tree-sitter / tree-sitter-javascript

Javascript grammar for tree-sitter
MIT License
329 stars 110 forks source link

Default export of anonymous function declaration is misclassified as function expression #323

Open jackschu opened 4 weeks ago

jackschu commented 4 weeks ago

The following piece of code is valid but it is parsed incorrectly:

export default function() {}

Here's a link to the TypeScript Playground showing that the snippet above is valid JavaScript or TypeScript

The output of tree-sitter parse is the following:

(program [0, 0] - [1, 0]
  (export_statement [0, 0] - [0, 28]
    value: (function_expression [0, 15] - [0, 28]
      parameters: (formal_parameters [0, 23] - [0, 25])
      body: (statement_block [0, 26] - [0, 28]))))

This example shows treesitter classifying this as a 'function_expression' when i think it should be classified as a 'function_declaration'.

This is because function declaration requires a name.

MDN mentions

As a special case, functions and classes are exported as declarations, not expressions, and these declarations can be anonymous. This means functions will be hoisted.

I havent dug through the spec but vaguely trust MDN, also Acorn parses this as a function declaration. Misclassifying it as a function expression can leave autoformatters wanting to parenthesize this expression and likely can leave highlighters to use the wrong color.

jackschu commented 4 weeks ago

I'm not really sure if the right thing to do here is to

  1. Spawn another syntax node for 'function declaration that is part of a default export and therefore may be anonymous'
  2. Alias function_expression to function_declaration in the export_statement node
  3. Allow function_declaration to only optionally have a name

Happy to put up a PR but not sure on the direction