Giter Club home page Giter Club logo

decaffeinate's Introduction

decaffeinate npm Join the chat at https://gitter.im/decaffeinate

Goodbye CoffeeScript, hello JavaScript!

JavaScript is the future, in part thanks to CoffeeScript. Now that it has served its purpose, it's time to move on. Convert your CoffeeScript source to modern JavaScript with decaffeinate.

Installation and usage

# via yarn
$ yarn global add decaffeinate
# via npm
$ npm install -g decaffeinate

$ decaffeinate input.coffee
input.coffee → input.js

# convert all files in directory and subdirectories
$ decaffeinate .
input.coffee → input.js
subfolder/input.coffee → subfolder/input.js

Alternatively, paste code into the online repl to immediately see the output.

For real-world use cases, you'll likely want to spend some time understanding the different options and nuances of the decaffeinate tool. You'll also likely want to run decaffeinate using the bulk-decaffeinate wrapper tool, or write your own wrapper script. See the Conversion Guide for more information and advice on running decaffeinate on real-world code, and see Cleanup suggestions after running decaffeinate for advice on cleaning up the converted JavaScript code and other things to keep in mind.

Questions and support

Feel free to join the gitter chat room to ask questions, or you can file an issue on the issues page:

Status

Complete. The project is stable enough for production use, and has been used to convert hundreds of thousands (probably millions) of lines of production code. The conversion process has been extensively tested and there are few or no known correctness bugs, although no guarantees are made.

Here are some popular open source CoffeeScript projects and their current status when run through decaffeinate. Each project has a decaffeinate-specific fork that is re-created from the original repo once per day.

Project Lines of CoffeeScript Conversion status Test status
chroma.js 3.3K chromajs-conversion-status chromajs-test-status
hubot [1] 3.7K hubot-conversion-status hubot-test-status
autoprefixer [1] 4.8K autoprefixer-conversion-status autoprefixer-test-status
coffeelint 8.8K coffeelint-conversion-status coffeelint-test-status
vimium [2] 11K vimium-conversion-status vimium-test-status
coffeescript [2] 17K coffeescript-conversion-status coffeescript-test-status
coffeescript2 [2] 17K coffeescript2-conversion-status coffeescript2-test-status
atom [1] 51K atom-conversion-status atom-test-status
atom-org 170K atom-org-conversion-status atom-org-test-status
codecombat 230K codecombat-conversion-status codecombat-test-status

Project builder status: Build Status

Notes:

  1. Hubot and Autoprefixer have fully moved to JavaScript using decaffeinate. This build runs on the last commit before the switch to JS. Atom has mostly moved to JavaScript using decaffeinate, so this build runs on an earlier revision that was primarily CoffeeScript.
  2. Some CoffeeScript tests are disabled because they are difficult to fix and test situations that do not seem to come up in real-world code. The Vimium test suite has also been modified slightly to work around a correctness issue. See How decaffeinate approaches correctness for full details.

To contribute to this list, send a pull request to the decaffeinate-examples project.

In addition, decaffeinate has been used on private codebases within various companies, such as Square, Benchling, Bugsnag, and DataFox.

Some blog posts on using decaffeinate:

If you run into crashes or correctness issues, or you have suggestions on how decaffeinate could be improved, feel free to file an issue on the issues page.

Goals

  • Fully automated conversion of the CoffeeScript language to modern JavaScript.
  • Preserve whitespace, formatting, and comments as much as possible to allow a full one-time conversion of your CoffeeScript source code.
  • Focus on correctness as the first priority, with some options to generate nicer code at the expense of 100% correctness.
  • Provide helpful error messages when it encounters an unsupported language construct.

Common options

  • --use-cs2: Treat the input as CoffeeScript 2 code. CoffeeScript 2 has some small breaking changes and differences in behavior compared with CS1, so decaffeinate assumes CS1 by default and allows CS2 via this flag.
  • --use-js-modules: Convert require and module.exports to import and export. Note that this may result in incorrect import statements because decaffeinate does not know the export style used by the other file. To generate correct imports, use bulk-decaffeinate and enable the useJSModules option.

Other options

  • --modernize-js: Treat the input as JavaScript and only run the JavaScript-to-JavaScript transforms, modifying the file(s) in-place.
  • --literate: Treat the input file as Literate CoffeeScript.
  • --disable-suggestion-comment: Do not include a comment with followup suggestions at the top of the output file.
  • --no-array-includes: Do not use Array.prototype.includes in generated code.
  • --safe-import-function-identifiers: Comma-separated list of function names that may safely be in the import/require section of the file. All other function calls will disqualify later requires from being converted to imports.
  • --prefer-let: Use let instead of const for most variables in output code.
  • --loose: Enable all --loose... options.
  • --loose-default-params: Convert CS default params to JS default params.
  • --loose-for-expressions: Do not wrap expression loop targets in Array.from.
  • --loose-for-of: Do not wrap JS for...of loop targets in Array.from.
  • --loose-includes: Do not wrap in Array.from when converting in to includes.
  • --loose-comparison-negation: Allow unsafe simplifications like !(a > b) to a <= b.
  • --loose-js-modules: Allow named exports when converting to JS modules.
  • --disallow-invalid-constructors: Give an error when constructors use this before super or omit the super call in a subclass.
  • --optional-chaining: Target JavaScript optional chaining. Note the semantics may not match exactly.
  • --nullish-coalescing: Target JavaScript nullish coalescing. Note the semantics may not match exactly.
  • --logical-assignment: Use the ES2021 logical assignment operators &&=, ||=, and ??=.

For more usage details, see the output of decaffeinate --help.

decaffeinate's People

Contributors

alangpierce avatar bhvaleri avatar dependabot-preview[bot] avatar dependabot[bot] avatar dgoldstein0 avatar dolzenko avatar eden-sun avatar edi9999 avatar ef4 avatar eventualbuddha avatar flying-sheep avatar greenkeeper[bot] avatar greenkeeperio-bot avatar hilts-vaughan avatar hneiva avatar iainb avatar isayme avatar madskonradsen avatar marcmenn avatar mattms avatar netei avatar norepercussions avatar qnighy avatar readmecritic avatar refack avatar sandstrom avatar shaylew avatar tatsuyafw avatar tbonemalone avatar willroberts avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

decaffeinate's Issues

Error: cannot traverse unknown node type: JavaScript

When the coffescript contain javascript expression xxxxxx, decaffeinate throw the error "cannot traverse unknown node type: JavaScript"

Example code:

`import Ember from 'ember'`
`import Resolver from 'ember/resolver'`
`import loadInitializers from 'ember/load-initializers'`
`import config from './config/environment'`
Ember.MODEL_FACTORY_INJECTIONS = true

App = Ember.Application.extend 
  modulePrefix: config.modulePrefix,
  podModulePrefix: config.podModulePrefix,
  Resolver: Resolver


loadInitializers(App, config.modulePrefix)

`export default App`


TypeError: Object prototype may only be an Object or null: utf8

Getting this error on bevry/taskgroup:

$ decaffeinate src/lib/taskgroup.coffee
fs.js:1613
  options = Object.create(options || {});
                   ^
TypeError: Object prototype may only be an Object or null: utf8
    at Function.create (native)
    at new ReadStream (fs.js:1613:20)
    at fs.createReadStream (fs.js:1602:10)
    at processPath (/Users/balupton/.nvm/versions/io.js/v1.6.1/lib/node_modules/decaffeinate/lib/cli.js:72:19)
    at processNext (/Users/balupton/.nvm/versions/io.js/v1.6.1/lib/node_modules/decaffeinate/lib/cli.js:82:7)
    at runWithPaths (/Users/balupton/.nvm/versions/io.js/v1.6.1/lib/node_modules/decaffeinate/lib/cli.js:88:3)
    at run (/Users/balupton/.nvm/versions/io.js/v1.6.1/lib/node_modules/decaffeinate/lib/cli.js:29:5)
    at Object.<anonymous> (/Users/balupton/.nvm/versions/io.js/v1.6.1/lib/node_modules/decaffeinate/bin/decaffeinate:3:22)
    at Module._compile (module.js:410:26)
    at Object.Module._extensions..js (module.js:428:10)

Chained function invocation on next line does not allow extra indent

I'm not sure if this is legit way to chain a method call, but it's all over my code base.

$stateProvider
  .state 'foo'
  .state 'bar'

leads to:

Error: Syntax error on line 2, column 9: unexpected '\'' (\u0027)
1 : $stateProvider
2 :   .state 'foo'
^ :        ^
3 :   .state 'bar'
4 :

The function call is chained if the indent level is the same

$stateProvider
.state 'foo'

leads to:

$stateProvider
.state( 'foo'
);

which is OK. However, chaining an additional function call is broken (see #63)

Support nested ternary expressions

This:

# `if` expression with multiple alternates
a(if b then c else if d then e else f)

Should become:

// `if` expression with multiple alternates
a(b ? c : d ? e : f);

Or perhaps:

// `if` expression with multiple alternates
a(b ? c : (d ? e : f));

This is follow-up from #23.

Add support for default values in functions

The following file :

class Test
  constructor:()->
  testFn:(a,b=2)->

triggers error :

    throw new Error('cannot traverse unknown node type: ' + node.type);
          ^
Error: cannot traverse unknown node type: DefaultParam
    at childPropertyNames (C:\ProgramData\chocolatey\lib\nodejs.commandline.0.10.35\tools\node_modules\decaffeinate\lib\utils\traverse.js:70:11)
    at traverse (C:\ProgramData\chocolatey\lib\nodejs.commandline.0.10.35\tools\node_modules\decaffeinate\lib\utils\traverse.js:36:47)
    at C:\ProgramData\chocolatey\lib\nodejs.commandline.0.10.35\tools\node_modules\decaffeinate\lib\utils\traverse.js:27:11
    at Array.forEach (native)
    at C:\ProgramData\chocolatey\lib\nodejs.commandline.0.10.35\tools\node_modules\decaffeinate\lib\utils\traverse.js:25:15
    at Array.forEach (native)
    at descend (C:\ProgramData\chocolatey\lib\nodejs.commandline.0.10.35\tools\node_modules\decaffeinate\lib\utils\traverse.js:22:30)
    at traverse (C:\ProgramData\chocolatey\lib\nodejs.commandline.0.10.35\tools\node_modules\decaffeinate\lib\utils\traverse.js:39:5)
    at C:\ProgramData\chocolatey\lib\nodejs.commandline.0.10.35\tools\node_modules\decaffeinate\lib\utils\traverse.js:31:9
    at Array.forEach (native)

Add support for `throw` expressions

These should pretty much transfer over unchanged, with the exception that in in CoffeeScript throw may be used in expression contexts, like this:

doSomething() or throw new Error('NOPE')

This should probably turn into something like this:

doSomething() || (() => { throw new Error('NOPE'); })();

Errors on `continue`

The following compiles in CoffeeScript Redux but errors in decaffeinate:

for foo in bar
  continue

Support binary existence operators

a ? b      # simple identifiers
a ? b.c    # complex RHS with identifier LHS
a.b ? c    # complex LHS with identifier RHS
a.b ? c.d  # complex LHS & RHS
a(b ? c)   # simple identifiers in an expression context
a(b.c ? d) # complex LHS with identifier RHS
// simple identifiers
if (typeof a !== "undefined" && a !== null) {
  a;
} else {
  b;
}

// complex RHS with identifier LHS
if (typeof a !== "undefined" && a !== null) {
  a;
} else {
  b.c;
}

// complex LHS with identifier RHS
if ((ref = a.b) != null) {
  ref;
} else {
  c;
}

// complex LHS & RHS
if ((ref = a.b) != null) {
  ref;
} else {
  c.d;
}

// simple identifiers in an expression context
a(b != null ? b : c);

// complex LHS with identifier RHS
a((ref = b.c) != null ? ref : d);

Any non-identifier LHS requires a temporary variable, which will need a declaration somewhere at the top of the block. We can take advantage of the existing infrastructure for variable declarations, unary existential operators, and if statements by pre-processing into this:

if a? then a else b                # simple identifiers
if a? then a else b.c              # complex RHS with identifier LHS
if (ref = a.b)? then ref else c    # complex LHS with identifier RHS
if (ref = a.b)? then ref else c.d  # complex LHS & RHS
a(if b? then b else c)             # simple identifiers in an expression context
a(if (ref = b.c)? then ref else d) # complex LHS with identifier RHS

This will require #23 to work.

chokes on line continuation

Very useful project. I was just experimenting with converting rivescript,js (https://github.com/aichaos/rivescript-js/) and ran into this issue. decaffeinate chokes on the line continuation for multi-line text (likely anything using the line continuation)

rs.say "Collecting trigger list for topic #{topic} (depth=#{depth}; " \
    + "inheritance=#{inheritance}; inherited=#{inherited})"

The problem is resolved when I eliminate the line continuation and put everything on one line.

Support chain syntax

I'm exporting my controllers via angular using

angular
  .module('app')
  .controller('MyCtrl', MyCtrl)

decaffeinate doesn't support this syntax. I'm getting the error:

Error: BUG! Could not fix range for FunctionApplication at line 8, column 1
    at fixRange (/opt/boxen/nodenv/versions/v0.12.7/lib/node_modules/decaffeinate/lib/utils/parse.js:127:11)
    at /opt/boxen/nodenv/versions/v0.12.7/lib/node_modules/decaffeinate/lib/utils/parse.js:41:5
    at traverse (/opt/boxen/nodenv/versions/v0.12.7/lib/node_modules/decaffeinate/lib/utils/traverse.js:36:23)
    at /opt/boxen/nodenv/versions/v0.12.7/lib/node_modules/decaffeinate/lib/utils/traverse.js:31:9
    at Array.forEach (native)
    at descend (/opt/boxen/nodenv/versions/v0.12.7/lib/node_modules/decaffeinate/lib/utils/traverse.js:22:32)
    at traverse (/opt/boxen/nodenv/versions/v0.12.7/lib/node_modules/decaffeinate/lib/utils/traverse.js:39:5)
    at /opt/boxen/nodenv/versions/v0.12.7/lib/node_modules/decaffeinate/lib/utils/traverse.js:31:9
    at Array.forEach (native)
    at descend (/opt/boxen/nodenv/versions/v0.12.7/lib/node_modules/decaffeinate/lib/utils/traverse.js:22:32)

If I change it and put everything in the same line, it successfully converts this chunk of code.

Support `switch` statements

Trying out decaffeinate, unfortunately not getting very far with it. Didn't notice an existing issue for the lack of switch support, which I bumped into quickly, so figured I'd open one.

λ decaffeinate src/test.coffee
[path-to]/decaffeinate/lib/utils/traverse.js:142
    throw new Error('cannot traverse unknown node type: ' + node.type);
          ^
Error: cannot traverse unknown node type: Switch

Support for Inheritance

class B
  constructor: ->

generates

class B {
  constructor() {}
}

inheritance sets { at the wrong position

B = require './B'
class A extends B
  constructor: ->

generates

var B = require('./B');
class A { extends B
  constructor() {}
}

Thanks!

Add support for function expressions

In CoffeeScript every function is a function expression. Here are some examples of transforming them:

# single-line function
a = -> 1

# single-line function containing this
a = -> this

# multi-line function
a = ->
  b + c

# single-line bound function
a = => 1

# multi-statement bound function
a = => 1; 2

# bound function referencing arguments
a = => arguments
// single-line function
var a = () => 1;

// single-line function containing this
var a = function() { return this; };

// multi-line function
var a = function() {
  return b + c;
};

// single-line bound function
var a = () => 1;

// multi-statement bound function
var a = () => (1, 2);

// bound function referencing arguments
var a = function() { return arguments; }.bind(this);

Note that the full transformation to JavaScript is shown, but this transform should only concern itself with transforming arrows into either function(){} or ()=>{} as appropriate.

Insert semi-colons at the end of most statements

Most statements should be followed by semi-colons. We should be careful to insert them only where one is not already present. Here are some examples:

# bare identifier
a
# function application
b c: d
# already ends in semi-colon
x + y;
# if statement
if a
  b
# for loop
for i in [0...5]
  a += i
// bare identifier
a;
// function application
b({c: d});
// already ends in semi-colon
x + y;
// if statement
if (a) {
  b;
}
// for loop
for (var i = 0; i < 5; i++) {
  a += i;
}

Add support for `||=` and `&&=`.

For example:

a ||= b
a.b ||= c
a[b] ||= c
a[b()] ||= c
a[b][c] ||= d
a[b][c()] ||= d
a(b[c][d] ||= e)

Should become:

a || (a = b);
a.b || (a.b = c);
a[b] || (a[b] = c);
a[name = b()] || (a[name] = c);
(base = a[b])[c] || (base[c] = d);
(base = a[b])[name = c()] || (base[name] = d);
a((base = b[c])[d] || (base[d] = e));

Error: "Cannot use replaced characters as slice anchors" with `if a then throw Error`

Hi, with the following source :

if a then throw new Error "Error"

I get the following error :

     Error: Cannot use replaced characters as slice anchors
      at patchThrowStart (src/patchers/patchThrow.js:14:17)
      at src/index.js:30:25
      at traverse (src/utils/traverse.js:28:25)
      at src/utils/traverse.js:23:9
      at Array.forEach (native)
      at descend (src/utils/traverse.js:14:30)
      at src/index.js:81:5
      at traverse (src/utils/traverse.js:28:25)
      at src/utils/traverse.js:19:11
      at Array.forEach (native)
      at src/utils/traverse.js:17:15
      at Array.forEach (native)
      at descend (src/utils/traverse.js:14:30)
      at src/index.js:81:5
      at traverse (src/utils/traverse.js:28:25)
      at src/utils/traverse.js:23:9
      at Array.forEach (native)
      at descend (src/utils/traverse.js:14:30)
      at src/index.js:81:5
      at traverse (src/utils/traverse.js:28:25)
      at convert (src/index.js:60:3)
      at check (test/support/check.js:1:17)
      at Context.<anonymous> (test/decaffeinate_test.js:399:7)

It should work with multiple pluses

Input:

a="b"+"c"+"d"

Error:

 Error: BUG! Could not fix range for PlusOp because it has no raw value
  at fixRange (src/utils/parse.js:71:13)
  at src/utils/parse.js:19:5
  at traverse (src/utils/traverse.js:28:25)
  at src/utils/traverse.js:23:9
  at Array.forEach (native)
  at descend (src/utils/traverse.js:14:30)
  at traverse (src/utils/traverse.js:35:5)
  at src/utils/traverse.js:23:9
  at Array.forEach (native)
  at descend (src/utils/traverse.js:14:30)
  at traverse (src/utils/traverse.js:35:5)
  at src/utils/traverse.js:19:11
  at Array.forEach (native)
  at src/utils/traverse.js:17:15
  at Array.forEach (native)
  at descend (src/utils/traverse.js:14:30)
  at traverse (src/utils/traverse.js:35:5)
  at src/utils/traverse.js:23:9
  at Array.forEach (native)
  at descend (src/utils/traverse.js:14:30)
  at traverse (src/utils/traverse.js:35:5)
  at parse (src/utils/parse.js:17:3)
  at convert (src/index.js:40:15)
  at check (test/support/check.js:1:17)
  at Context.<anonymous> (test/decaffeinate_test.js:407:7)

Add support for Classes

CoffeeScript classes are similar to ES6 classes, but have some subtle differences. We should not attempt to transform anything that cannot retain the same semantics. Here's some example transformations:

# named classes
class Foo

# anonymous classes
a(class)

# classes with methods
class Bar
  baz: ->

# class extends
class Square extends Rectangle

# instance properties
class Bat
  x: 1

# static properties
class Baz
  @a: 1

# bound methods
class Cookie
  eat: =>
// named classes
class Foo {}

// anonymous classes
a(class {});

// classes with methods
class Bar {
  baz() {}
}

// class extends
class Square extends Rectangle {}

// instance properties
// disallowed, should error with "assign `Bat::x = 1` after class body"

// static properties
// disallowed, should error with "assign `Baz.a = 1` after class body"

// bound methods
// disallowed, should error with "bind `eat` in constructor: `@eat = @eat.bind(this)`"

Note that this example shows the code transformed fully to JavaScript, but this transform should only worry about the class and the class body.

Add support for For loops

As noted in #1, decaffeinate does not yet support transforming for loops. I think there are really only three kinds of loops we can translate easily:

for-of -> for-in

for a of b
  #

Should turn into this:

for (var a in b) {
  // …
}

for-in -> for-of

for a in b
  #

Should turn into this:

for (var a of b) {
  // …
}

for-in [a..b] -> traditional for loop

for a in [0...5]
  #

Should turn into this:

for (var a = 0; a < 5; a++) {
  // …
}

If the range is not exclusive, e.g. 0..5, <= should be used instead of <. If either of the bounds of the range are not literal numbers, e.g. [m...n], then we'll have to check which direction it's going:

for (var a = m; m <= n ? a < n : a > n; m <= n ? a++ : a--) {
  // …
}

This is essentially what the actual CoffeeScript compiler does.

Other types of for loop

We should print a message indicating that we cannot convert anything that does not match the above.

Why Redux

I'm curious why you chose Redux. It doesn't support line continuations, so this is a syntax error:

if foo and
        bar
    doSomething

Add support for string interpolation

Double-quoted strings may contain string interpolation and, if so, should turn into template strings:

"a#{b}c"
"""a#{b}c"""

Should become:

`a${b}c`
`a${b}c`

Strategy

CoffeeScriptRedux parses string interpolation into a ConcatOp node, which may itself contain more ConcatOp nodes. For example, "a#{b}c" parses as:

{ type: 'ConcatOp',
  line: 1,
  column: 1,
  raw: '"a#{b}c"',
  range: [ 0, 8 ],
  left:
   { type: 'ConcatOp',
     left:
      { type: 'String',
        line: 1,
        column: 2,
        data: 'a' },
     right:
      { type: 'Identifier',
        line: 1,
        column: 5,
        raw: 'b',
        range: [ 4, 5 ],
        data: 'b' } },
  right:
   { type: 'String',
     line: 1,
     column: 7,
     raw: 'c',
     range: [ 6, 7 ],
     data: 'c' } }

We need to walk this structure to find where the string interpolation token starts to replace #{ with ${, and to replace the double-quote delimiters with backticks. This wouldn't be hard with complete location information. Unfortunately CSR has known issues with its node range information, so we have to fix the ranges ourselves. This range fixing is not yet complete. Some nodes, like the a string above, do not have a range property at all. Thus we need more robust range fixing that checks the line and column properties, or perhaps completely replaces the range info by re-scanning the string ourselves.

Support `if` expressions

# `if` expression without alternate
a(if b then c)

# `if` expression with alternate
a(if b then c else d)

# `if` expression with multiple alternates
a(if b then c else if d then e else f)

# `if` expression with block consequent
a(
  if b
    c
    d
)

# `if` expression with block alternate
a(
  if b
    c
  else
    d
    e
)
// `if` expression without alternate
a(b ? c : undefined);

// `if` expression with alternate
a(b ? c : d);

// `if` expression with multiple alternates
a(b ? c : d ? e : f);

// `if` expression with block consequent
a(
  (() => {
    if (b) {
      c;
      return d;
    }
  })()
);

// `if` expression with block alternate
a(
  (() => {
    if (b) {
      c;
    } else {
      d;
      return e;
    }
  })()
);

For if expressions with block consequent or alternate, they should be pre-processed as below, which will allow the normal function, if statement, & implicit return handling.

# `if` expression with block consequent
a(
  (=>
    if b
      c
      d
  )()
)

# `if` expression with block alternate
a(
  (=>
    if b
      c
    else
      d
      e
  )()
)

Comparison operators don't work?

All the basic comparison operators appear to be unsupported.

For instance, if I run this:

echo "a == b" | decaffeinate

traverse.js complains like so:

Error: cannot traverse unknown node type: EQOp

I get the same results for any other comparison operators, as well.

Here's a list of all I tried and their associated AST node names (I may be missing some operators):

  • EQOp (==, is)
  • NEQOp (!=, isnt)
  • GTOp (>)
  • GTEOp (>=)
  • LTOp (<)
  • LTEOp (<=)
  • UrnaryExistsOp (<expr>?)
  • BitAndOp (&)
  • BitOrOp (|)
  • BitXorOp (^)

Fails to parse trailing comment after JS object literal open curly brace

Failing test case:

RestangularProvider.setRestangularFields({ # comment
  route: "restangularRoute"
})

error:

Error: Syntax error on line 6, column 3: unexpected 'r' (\u0072)
3 :   route: "restangularRoute"
4 : # Fails
5 : RestangularProvider.setRestangularFields({ # comment
6 :   route: "restangularRoute"
^ :   ^
7 : })

I suspect this might be a Redux problem


Side note: Switching the JS object literal to a coffee literal, or moving the comment to the next line works:

# These work fine
RestangularProvider.setRestangularFields # comment
  route: "restangularRoute"

RestangularProvider.setRestangularFields({
  # comment
  route: "restangularRoute" # comment
})

Support functions wrapped in parens

This snippet fails on decaffeinate with the error

Error: BUG! Could not fix range for MemberAccessOp at line 4, column 16
    at fixRange (/Users/user/.nvm/v0.10.38/lib/node_modules/decaffeinate/lib/utils/parse.js:106:11)
    at /Users/user/.nvm/v0.10.38/lib/node_modules/decaffeinate/lib/utils/parse.js:37:5
    at traverse (/Users/user/.nvm/v0.10.38/lib/node_modules/decaffeinate/lib/utils/traverse.js:44:23)
    at /Users/user/.nvm/v0.10.38/lib/node_modules/decaffeinate/lib/utils/traverse.js:39:9
    at Array.forEach (native)
    at descend (/Users/user/.nvm/v0.10.38/lib/node_modules/decaffeinate/lib/utils/traverse.js:30:30)
    at traverse (/Users/user/.nvm/v0.10.38/lib/node_modules/decaffeinate/lib/utils/traverse.js:47:5)
    at /Users/user/.nvm/v0.10.38/lib/node_modules/decaffeinate/lib/utils/traverse.js:39:9
    at Array.forEach (native)
    at descend (/Users/user/.nvm/v0.10.38/lib/node_modules/decaffeinate/lib/utils/traverse.js:30:30)
`import Ember from "ember"`;

MyObject = Em.Object.extend
  myProperty: (() ->
    return 'thing'
  ).property()

`export default MyObject`

It seems like valid CS code, any reason that this is failing?

Rewrite comments from '#' to '//'

We need to rewrite comments. Here are some examples:

# line comment by itself

foo()  # line comment following an expression

###
block comment
###

###
# doc comment
###

Should become:

// line comment by itself

foo(); // line comment following an expression

/*
block comment
*/

/**
 * doc comment
 */

Error: cannot traverse unknown node type: InOp

To repro, run:

curl -s https://raw.githubusercontent.com/atom/atom/b682658427eb9edb5cf9b152652817a8305bf43e/src/package-manager.coffee | decaffeinate | less

/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:148
    throw new Error('cannot traverse unknown node type: ' + node.type);
          ^
Error: cannot traverse unknown node type: InOp
    at childPropertyNames (/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:148:11)
    at traverse (/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:36:47)
    at /usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:31:9
    at Array.forEach (native)
    at descend (/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:22:32)
    at traverse (/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:39:5)
    at /usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:27:11
    at Array.forEach (native)
    at /usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:25:15
    at Array.forEach (native)

Version: [email protected]

Cmd-L key binding is overloaded on Chrome and Firefox for Mac

On Firefox and Chrome for Mac (and probably other browsers), Cmd-L selects the search and URL field of the browser. Decaffeinate overrides this with the "go to line number" functionality. Not a huge priority, obviously, but it was a surprise.

It may be worthwhile to remove this binding or change the shortcut (or perhaps allow the user to create their own key bindings, or choose a set of key bindings). If we do decide to change, then Ctl-G is a good candidate - it's the default key binding for "go to line number" in Sublime Text.

Should be able to parse RegExp

Running echo "foo = /someregex/i" | decaffeinate gives the following error:

/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:70
    throw new Error('cannot traverse unknown node type: ' + node.type);
          ^
Error: cannot traverse unknown node type: RegExp
    at childPropertyNames (/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:70:11)
    at traverse (/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:44:47)
    at /usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:39:9
    at Array.forEach (native)
    at descend (/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:30:30)
    at traverse (/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:47:5)
    at /usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:35:11
    at Array.forEach (native)
    at /usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:33:15
    at Array.forEach (native)

As far as I know, regexes in CoffeeScript need no modification to be translated to ES6.

Add support for If statements

if statements take a variety of forms in CoffeeScript. Here's how I think they should map:

# simple, multi-line
if a
  b

# single-line
b if a

# if-then-else single-line
if a then b else c

# if-then-else multi-line
if a then b
else c

# if-else multi-line
if a
  b
else
  c

# unless
unless a
  b
// simple, multi-line
if (a) {
  b;
}

// single-line
if (a) { b; }

// if-then-else single-line
if (a) { b; } else { c; }

// if-then-else multi-line
if (a) { b; }
else { c; }

// if-else multi-line
if (a) {
  b;
} else {
  c;
}

// unless
if (!a) {
  b;
}

Note that the fully transformed JavaScript is shown, but this transform should only concern itself with adding parentheses, braces, and transforming unless to if. I anticipate there may be issues with this one, especially changing post-if to regular if, due to the MagicString limitation of only allowing modifying a given location once.

Next-Line Fat arrow inside object literal generates misplaced semicolon

foo =
  bar: (svc) =>
    svc.blarg()
  baz: (svc) =>
    svc.bloop()

generates:

var foo =
  {bar: (svc) => {
    return svc.blarg();
  },
  baz: (svc) => {
    return svc.bloop();
  };
} 

Note that single-line fat-arrows in object literals work fine. Also, only the last element of the literal seems to matter. This coffee src is transpiled OK:

foo =
  bar: (svc) => 
    svc.blarg()
  baz: (svc) => svc.bloop()

Add support for `?=`.

For example:

a ?= b
a.b ?= c
a[b] ?= c
a[b()] ?= c
a[b][c] ?= d
a[b][c()] ?= d
a(b[c][d()] ?= e)

should become:

if (a == null) { a = b; }
if (a.b == null) { a.b = c; }
if (a[b] == null) { a[b] = c; }
if (a[name = b()] == null) { a[name] = c; }
if ((base = a[b])[c] == null) { base[c] = d; }
if ((base = a[b])[name = c()] == null) { base[name] = d; }
a((value = (base = b[c])[name = d()]) == null ? base[name] = e : value);

Insert braces for implicit object literals

CoffeeScript allows implicit object literals that are not surrounded by braces. We need to insert them to convert to JavaScript. Here are a few examples that we should support:

# single line
a b: c
a(b: c)

# multiple lines
a
  b: c
a(
  b: c
)

# indented, multiple lines
a = ->
  b
    c: d
// both single lines look like this
a({b: c});

// both multiple lines look like this
a({
  b: c
});

// indented, multiple lines
var a = function() {
  b({
    c: d
  });
};

Note that the full transformation to JavaScript is shown, but this transformation need only worry about the object braces { and }.

formatParserError

Hi!

I was expecting to have some manual work to do to completely convert, but so far, I'm getting error on the first character of most of my file. Here is an example :

If I can help debug that problem, do not hesitate :)

~$ decaffeinate coffee.coffee

/usr/local/lib/node_modules/decaffeinate/node_modules/coffee-script-redux/lib/module.js:61
      throw new Error(formatParserError(preprocessed, e));
            ^
Error: Syntax error on line 1, column 1: unexpected '"' (\u0022)
1 : angular.module("driverLogs")
^ : ^

Can't install decaffeinate properly

OS X Yosemite / node v0.10.35
After npm install -g decaffeinate I didn't get decaffeinate command:

$ which decaffeinate
decaffeinate not found

I tried to run it like this /usr/local/lib/node_modules/decaffeinate/bin/decaffeinate script.coffee but got an error:

/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:114
        throw new Error("unknown node type: " + node.type);
              ^
Error: unknown node type: ForOf
    at traverse (/usr/local/lib/node_modules/decaffeinate/lib/utils/traverse.js:114:15)
    at parse (/usr/local/lib/node_modules/decaffeinate/lib/utils/parse.js:21:3)
    at convert (/usr/local/lib/node_modules/decaffeinate/lib/index.js:53:13)
    at ReadStream.<anonymous> (/usr/local/lib/node_modules/decaffeinate/lib/cli.js:145:16)
    at ReadStream.emit (events.js:117:20)
    at _stream_readable.js:944:16
    at process._tickCallback (node.js:442:13)

Omit `return` insertion for `throw` statements

Repro

foo = ->
    throw new Error 'Not implemented'

Expected

var foo = function() {
  throw new Error('Not implemented');
};

Actual

var foo = function() {
    return throw new Error('Not implemented');
//  ^^^^^^ Invalid
};

Simple if condition with `and` fails

if (a? and a!="") then 1

fails with

     Error: BUG! Could not fix range for NEQOp because it has no raw value
      at fixRange (src/utils/parse.js:70:13)
      at src/utils/parse.js:19:5
      at traverse (src/utils/traverse.js:28:25)
      at src/utils/traverse.js:23:9
      at Array.forEach (native)
      at descend (src/utils/traverse.js:14:30)
      at traverse (src/utils/traverse.js:35:5)
      at src/utils/traverse.js:23:9
      at Array.forEach (native)
      at descend (src/utils/traverse.js:14:30)
      at traverse (src/utils/traverse.js:35:5)
      at src/utils/traverse.js:19:11
      at Array.forEach (native)
      at src/utils/traverse.js:17:15
      at Array.forEach (native)
      at descend (src/utils/traverse.js:14:30)
      at traverse (src/utils/traverse.js:35:5)
      at src/utils/traverse.js:23:9
      at Array.forEach (native)
      at descend (src/utils/traverse.js:14:30)
      at traverse (src/utils/traverse.js:35:5)
      at parse (src/utils/parse.js:17:3)
      at convert (src/index.js:40:15)
      at check (test/support/check.js:1:17)
      at Context.<anonymous> (test/decaffeinate_test.js:403:7)

decaffeination attempt failure due to ambigous indentation

it's possible its an issue on my end, but i figure I would open an issue incase :)

± % cat test/app/lib/data_access/caching_api_clients/crowd_pics_images_spec.coffee|  ./node_modules/.bin/decaffeinate           !10094

/Users/stefan/src/yapp/projects/yapp-mobile/node_modules/decaffeinate/node_modules/coffee-script-redux/lib/module.js:60
        throw e;
              ^
Error: Syntax error on line 24: indentation is ambiguous
21 :     }
22 :
23 :     fakeServer = null
24 :     before async(->
^^ :    ^
25 :       fakeServer = sinon.fakeServer.create()
26 :       fakeServer.autoRespond = true
27 :       YB.clientStorage.done ->
    at Preprocessor.Preprocessor.consumeIndentation (/Users/stefan/src/yapp/projects/yapp-mobile/node_modules/decaffeinate/node_modules
/coffee-script-redux/lib/preprocessor.js:155:17)
    at Preprocessor.Preprocessor.process (/Users/stefan/src/yapp/projects/yapp-mobile/node_modules/decaffeinate/node_modules/coffee-scr
ipt-redux/lib/preprocessor.js:190:14)
    at Function.Preprocessor.Preprocessor.process (/Users/stefan/src/yapp/projects/yapp-mobile/node_modules/decaffeinate/node_modules/c
offee-script-redux/lib/preprocessor.js:22:38)
    at CoffeeScript.parse (/Users/stefan/src/yapp/projects/yapp-mobile/node_modules/decaffeinate/node_modules/coffee-script-redux/lib/m
odule.js:47:35)
    at parse (/Users/stefan/src/yapp/projects/yapp-mobile/node_modules/decaffeinate/lib/utils/parse.js:22:13)
    at convert (/Users/stefan/src/yapp/projects/yapp-mobile/node_modules/decaffeinate/lib/index.js:59:13)
    at Socket.<anonymous> (/Users/stefan/src/yapp/projects/yapp-mobile/node_modules/decaffeinate/lib/cli.js:150:16)
    at Socket.emit (events.js:117:20)
    at _stream_readable.js:944:16

Error always reports line 1

It would be nice if the parser reported the line that it choked on. For instance, given this file

# random comment

foo = func('param',
  bar: 'baz'
  qux: 'im out of things'
)

it doesn't match CoffeeScript redux format, so it bails with this message:

› decaffeinate test.coffee
/Users/blimmer/.nvm/versions/node/v0.12.5/lib/node_modules/decaffeinate/node_modules/coffee-script-redux/lib/module.js:61
      throw new Error(formatParserError(preprocessed, e));
            ^
Error: Syntax error on line 1, column 1: unexpected '\n' (\u000A)
1 : # random comment
^ : ^
2 :
3 : foo = func('param',
4 :   bar: 'baz'
    at CoffeeScript.parse (/Users/blimmer/.nvm/versions/node/v0.12.5/lib/node_modules/decaffeinate/node_modules/coffee-script-redux/lib/module.js:61:13)
    at parse (/Users/blimmer/.nvm/versions/node/v0.12.5/lib/node_modules/decaffeinate/lib/utils/parse.js:36:42)
    at convert (/Users/blimmer/.nvm/versions/node/v0.12.5/lib/node_modules/decaffeinate/lib/index.js:177:43)
    at ReadStream.<anonymous> (/Users/blimmer/.nvm/versions/node/v0.12.5/lib/node_modules/decaffeinate/lib/cli.js:106:35)
    at ReadStream.emit (events.js:129:20)
    at _stream_readable.js:908:16
    at process._tickCallback (node.js:355:11)

which makes it hard to figure out what I need to change to make decaffeinate work. With large files, I like to correct to CoffeeScript redux format and let decaffeinate do the heavy lifting.

It seems like this would be possible, because the CoffeeScript Redux web parser is able to identify the place where the parsing problem exists:

screen shot 2015-09-10 at 4 28 47 pm

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.