millermedeiros / esformatter

ECMAScript code beautifier/formatter
MIT License
970 stars 91 forks source link

Incorrect startToken for arrow function body #463

Open Gozala opened 8 years ago

Gozala commented 8 years ago

Here is an example code:

const Closed = result =>
  ( { type: 'Closed'
    , result
    }
  )

I'm trying to write plugin that would reformat such function as follows:

const Closed =
  result =>
  ({ type: "Closed", result })

But when attempting to do something along these lines:

var tk = require('rocambole-token');

var options = {}

exports.setOptions = function(config) {
  options = config
}

exports.nodeAfter = function(node) {
  if (node.type === 'VariableDeclarator') {
    if (node.init.type === 'ArrowFunctionExpression') {
      // insert a line break before the init
      tk.before(node.init.startToken, {
        type: 'LineBreak',
        value: options.lineBreak.value + options.indent.value
      });

      console.warn(node.init.body.startToken.type, node.init.body.startToken.value)

      tk.before(node.init.body.startToken, {
        type: 'LineBreak',
        value: options.lineBreak.value + options.indent.value
      });
    }
  }
};

I get following result:

const Closed =
  result => (
  {
  type: 'Closed',
result}
)

And more importantly following thing is being logged:

Punctuator {

It seems that startToken of the function body is { instead of expected (.

Gozala commented 8 years ago

I guess easier way to see this issue is by looking at https://astexplorer.net/#/8hK2Y2BwqI

millermedeiros commented 8 years ago

the "fun" thing here is that the startToken of the body is really the { because the body is marked as an ObjectExpression... - AST ignores parenthesis in most cases...

this is one of the main reasons why I really wanted to have a REAL concrete syntax tree, where the parenthesis would create groups and have an easy way to capture the start/end of the group... but it would be too much work and I went with the easy way...

see getParentheses method inside https://github.com/millermedeiros/esformatter/blob/master/lib/hooks/expressionParentheses.js#L19 - maybe we should export this function on the esformatter object to make it easier for plugins to reuse it (esformatter is passed as second argument on plugin.setOptions)