benjamn / recast

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

How do you parse #privateFields? #1381

Closed NullVoxPopuli closed 7 months ago

NullVoxPopuli commented 7 months ago

I have a reproduction here: https://stackblitz.com/edit/stackblitz-starters-wetowk

code ```js import recast from 'recast'; import babelParser from '@babel/parser'; const source = `import './with-a-class.css'; import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import TEMPLATE from "./with-a-class.hbs"; import { f, i } from "decorator-transforms/runtime"; import { setComponentTemplate } from "@ember/component"; export default class WithAClass extends Component { static { f(this, "greeting", [tracked], function () { return 'hello there'; }); } #greeting = (i(this, "greeting"), void 0); } setComponentTemplate(TEMPLATE, WithAClass);`; try { const ast = recast.parse(source, { parser: babelParser, }); console.log('success'); console.log(ast); } catch (e) { console.error(e.message); console.error(e.stack); } ```

Error:

Error: Line 14: Unexpected token ILLEGAL
    at ErrorHandler</ErrorHandler.prototype.constructError (/home/projects/stackblitz-starters-wetowk/node_modules/.pnpm/esprima@4.0.1/node_modules/esprima/dist/esprima.js:5012:22)

couple things of note:


past iterations on this issue:

accidentally using runkit I have a reproduction here, and I'm getting an error: https://runkit.com/nullvoxpopuli/recast-and-private-fields
code ```js const { parse } = require('recast'); const babel = require('@babel/parser'); const source = `import './with-a-class.css'; import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import TEMPLATE from "./with-a-class.hbs"; import { f, i } from "decorator-transforms/runtime"; import { setComponentTemplate } from "@ember/component"; export default class WithAClass extends Component { static { f(this, "greeting", [tracked], function () { return 'hello there'; }); } #greeting = (i(this, "greeting"), void 0); } setComponentTemplate(TEMPLATE, WithAClass);` try { const ast = parse(source, { parser: babel }); console.log(ast); } catch (e) { console.error(e.message); console.error(e.stack); } ```
Error: ``` Error: Line 14: Unexpected token ILLEGAL at ErrorHandler.constructError (/app/available_modules/1702066257000/recast/node_modules/esprima/dist/esprima.js:5012:22) ``` Line 14 has the `#` on it. ---- Update: - it appears that runkit doesn't even support private fields, even though they are very widely supported by all browsers: https://caniuse.com/mdn-javascript_classes_private_class_fields ![image](https://github.com/benjamn/recast/assets/199018/95ac0fb5-f841-44a0-8214-e0e939c76180) I need to make a different repro
NullVoxPopuli commented 7 months ago

Figured it out, this is what I ultimately ended up using (also the latest code at the reproduction):

const source = `import './with-a-class.css';

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import TEMPLATE from "./with-a-class.hbs";
import { f, i } from "decorator-transforms/runtime";
import { setComponentTemplate } from "@ember/component";
export default class WithAClass extends Component {
  static {
    f(this, "greeting", [tracked], function () {
      return 'hello there';
    });
  }
  #greeting = (i(this, "greeting"), void 0);
}
setComponentTemplate(TEMPLATE, WithAClass);`;

import recast from 'recast';
import * as acorn from 'acorn';
import babelParser from '@babel/parser';

try {
  const ast = recast.parse(source, {
    // The default parser doesn't support:
    // - static initialization blocks
    // - private fields
    parser: {
      parse(source) {
        return babelParser.parse(source, {
          sourceType: 'module',
          allowImportExportEverywhere: true,
          tokens: true,
        });
      },
    },
  });
  console.log('success');
  console.log(ast);
} catch (e) {
  console.error(e.message);
  console.error(e.stack);
}

It seems the acorns and espreema parsers are fairly incomplete.