benjamn / recast

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

Add parser support for esprima-next #1393

Open btiernay opened 4 months ago

btiernay commented 4 months ago

esprima-next is a modern replacements for esprima and fixes many of the issues with current versions ECMAScript support.

JakeCigar commented 4 months ago

Thanks to your issue, my issue was solved by using esprima-next!

I just did npm install esprima-next and coded recast.parse(code,{ parser: require("esprima-next") })

btiernay commented 4 months ago

It's definitely much better, but still fails for certain things like private class fields. This is more of a failing of ast-types than Recast, but Recast needs to change in a few areas:

  1. The parser is hard coded to esprima in certain parts of the code
    // Use ast.tokens if possible, and otherwise fall back to the Esprima
    // tokenizer. All the preconfigured ../parsers/* expose ast.tokens
    // automatically, but custom parsers might need additional configuration
    // to avoid this fallback.
    var tokens = Array.isArray(ast.tokens)
        ? ast.tokens
        : require("esprima").tokenize(sourceWithoutTabs, {
            loc: true,
        });

The above would need to be updated to support esprima-next.

  1. ast-types needs to be extended by so-called "forks" to support then new syntax elements: https://github.com/benjamn/recast/issues/1283
eventualbuddha commented 4 months ago

Out of curiosity: why not use @babel/parser? Also, what specifically fails when using esprima-next? Do you have a code sample? This works fine for me and has ast.tokens, so it shouldn't be falling back to esprima's tokenizer:

import { parse } from "recast";
import * as esprima from "esprima-next";

const code = `ITEM?.getAsEntry?.() ?? ITEM?.webkitGetAsEntry?.()`;

console.log(parse(code, { parser: esprima }));
btiernay commented 4 months ago

Out of curiosity: why not use @babel/parser?

Originally it was because I needed something that could be bundled small enough to fit within Snowflake's constraints. I tried with Babel and it was too large, but I have since taken a different approach.

Also, what specifically fails when using esprima-next? Do you have a code sample? This works fine for me and has ast.tokens, so it shouldn't be falling back to esprima's tokenizer:


import { parse } from "recast";

import * as esprima from "esprima-next";

const code = `ITEM?.getAsEntry?.() ?? ITEM?.webkitGetAsEntry?.()`;

console.log(parse(code, { parser: esprima }));

It was the PrivateName it was returning instead of PrivateIdentifier for class private fields. I've opened an issue against esprima-next since.