benjamn / recast

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

🎩 `SequenceExpression` printed incorrectly when used as part of `MemberExpression` #1061

Open coderaiser opened 2 years ago

coderaiser commented 2 years ago

I got case that may be relevant to https://github.com/benjamn/recast/pull/1057, since it's about SequenceExpressions. For such code:

const name = (FIRST || SECOND).VALUE || HELLO;

After instrumenting by coverage tool 🎩ESCover I receive next results.

βœ… @babel/generate produces correct result:

const name = (__c4['🧨'](1, 13), ((__c4['🧨'](1, 14), FIRST) || (__c4['🧨'](1, 23), SECOND)).VALUE) || (__c4['🧨'](1, 40), HELLO);
//                               ^ opening round bracket            closing round bracket ^

❌ recast produces incorrect result:

 const name = (__c4['🧨'](1, 13), (__c4['🧨'](1, 14), FIRST) || (__c4['🧨'](1, 23), SECOND).VALUE) || (__c4['🧨'](1, 40), HELLO);
//                               ^ missing                                       missing ^                                                                 

Because if __c4['🧨'] calls are removed, code looks like this:

 const name = (FIRST || SECOND.VALUE) || HELLO;

Which is absolutely wrong. Here is code (+ what inslide a fix function) of 🐊Putout plugin that does transforms with Babel API.

Here is test example:

it("sequence", async function() {
    const source = 'const name = (a || b).value || value';
    const expected = `const name = (__c4['🧨'](1, 13), ((__c4['🧨'](1, 14), a) || (__c4['🧨'](1, 19), b).value)) || (__c4['🧨'](1, 31), value)`;

    // @ts-ignore
    const plugin = await eval('import("escover/plugin")') as any;
    // @ts-ignore
    const {transform, parse, print} = await eval('import("putout")') as any;

    const ast = parse(source);

    transform(ast, source, {
        plugins: [
            ['escover', plugin],
        ],
    });

    assert.strictEqual(
      print(ast),
      expected,
    );
});

Only transformed made by 🐊Putout, parse and print it's recast.

Looks like it is related to

gnprice commented 2 years ago

Thanks for the report!

One thing that would help a lot in debugging this would be to have a way to reproduce it without needing to install any additional libraries (like escover/plugin or putout.)

Can you make a version of your test example that replaces the transform call with some explicit modifications to the AST? Like in the style seen here: https://github.com/benjamn/recast#usage . Or if you search through test/printer.ts for the string "ast.program", you'll find a number of examples of test cases that take some AST and then print it.