benjamn / recast

JavaScript syntax tree transformer, nondestructive pretty-printer, and automatic source map generator
MIT License
5.01k stars 350 forks source link

Parens are dropped, changing program semantics / introducing syntax error #985

Open NickHeiner opened 3 years ago

NickHeiner commented 3 years ago

I'm using Babel and Recast in conjunction to transform my AST. When I use Babel alone, the output is fine (although not formatted correctly.) When I introduce Recast, it drops parens, changing the program semantics (or introducing a syntax error).

Input code:

jest.mock('./my-module', () => () => ({
  mockedFn: jest.fn()
}));

Babel plugin:

const plugin = ({ types: t }) => ({
  visitor: {
    ArrowFunctionExpression(astPath) {
      const getWrappedValue = (originalValue) =>
        t.callExpression(t.identifier("wrapped"), [
          originalValue
        ]);

      const bodyPath = astPath.get("body");
      bodyPath.replaceWith(getWrappedValue(bodyPath.node));
      astPath.skip();
    }
  }
});

Transformed results:

// Babel result
jest.mock('./my-module', () => wrapped(() => ({
  mockedFn: jest.fn()
})));

// Recast result
jest.mock('./my-module', () => wrapped(() => {
  mockedFn: jest.fn()
}));

Full runnable repro.

We can see that the () around the arrow function return expression are dropped. When there are multiple members of the object, this results in a syntax error:

() => ({a: true, b: false})

// Syntax error
() => {a: true, b: false}

Possibly related: #914, #327, #533, #81 Versions:

gnprice commented 2 years ago

This issue no longer reproduces :tada:

With recast@0.21.1, I get:

Babel result
jest.mock('./my-module', () => wrapped(() => ({
  mockedFn: jest.fn()
})));
Recast result
jest.mock('./my-module', () => wrapped(() => ({
  mockedFn: jest.fn()
})));

i.e., the Recast result has that necessary pair of parens, just like the Babel result.

The issue does still reproduce if I go back to Recast 0.21.0. So most likely it was fixed by #1068, which was a parenthesization fix that happened between those versions.