davidbonnet / astring

🌳 Tiny and fast JavaScript code generator from an ESTree-compliant AST.

Home Page:https://david.bonnet.cc/astring/demo/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

LogicalExpression with nullish coalescing on the left side produces invalid syntax

bpstrngr opened this issue · comments

Motivation

I'm building a loader module that performs transformations on AST-s and re-serializes them with Astring.

Expected behavior

A function declaration in Rollup's src/utils/options/normalizeOutputOptions.js file reading

const getInlineDynamicImports = (config, inputOptions) => {
  const inlineDynamicImports = (config.inlineDynamicImports ?? inputOptions.inlineDynamicImports) || false;
  // ...further statements. 
};
//  source: https://github.com/rollup/rollup/blob/master/src/utils/options/normalizeOutputOptions.ts#L192C15-L192C15

contains a LogicalExpression node that Acorn parses as the following:

Node {
    type: 'LogicalExpression',
    start: 5340,
    end: 5415,
    loc: SourceLocation { start: [Position], end: [Position] },
    left: Node {
      type: 'LogicalExpression',
      start: 5341,
      end: 5405,
      loc: [SourceLocation],
      left: [Node],
      operator: '??',
      right: [Node]
    },
    operator: '||',
    right: Node {
      type: 'Literal',
      start: 5410,
      end: 5415,
      loc: [SourceLocation],
      value: false,
      raw: 'false'
    }
  }

which should be reversible to the valid expression with Astring.

Actual behavior

Passing the unmodified AST back to Astring produces the following string:

const getInlineDynamicImports = (config, inputOptions) => {
  const inlineDynamicImports = config.inlineDynamicImports ?? inputOptions.inlineDynamicImports || false;
  // ...further statements. 
};

which, passed further in my loader hook fails with this error:

file:///mnt/chromeos/GoogleDrive/MyDrive/function/rollup_2022_rollup/0/src/utils/options/normalizeOutputOptions.ts:116
  const inlineDynamicImports = config.inlineDynamicImports ?? inputOptions.inlineDynamicImports || false;
                                                                                                ^^

SyntaxError: Unexpected token '||'
    at ESMLoader.moduleStrategy (node:internal/modules/esm/translators:117:18)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:460:14)

Node.js v19.6.0

I was surprised that this is an invalid syntax, but as i confirmed in repl it's only valid with brackets around the left side:
image

Is this a problem with Acorn (its plugins can interfere with the produced AST), or the serializer?

Either Acorn should preserve some "bracket" parent node above the left side (being in the business of transforming AST-s i could handle that, but I never know where exactly to look up how that Node would look like form Acorn-adjacent docs), or Astring should detect the need for brackets in this situation.

I'm using Astring v1.8.6.

small update: found Acorn has a "preserveParens" option, but that just inserts Nodes that Astring doesn't recognise to begin with. Also found a related pack of issues, but those produce runtime bugs, not syntactic errors: estree/estree#194

Thanks for raising this @bpstrngr. Will fix it this week unless someone else does sooner.

Hi @bpstrngr, unless I'm missing something, this issue couldn't be reproduced. It's actually covered by tests here:

Could be that your project isn't using the latest version of astring.

@davidbonnet i moved past this since, i'm not sure what dissipated the problem. Could be that i didn't check my version, sorry. Thank you for looking into it!