From e0500d1079cd845ef34e86e609474e1a1ac2a03a Mon Sep 17 00:00:00 2001 From: Ferdinand Prantl Date: Sat, 7 May 2022 17:07:18 +0200 Subject: [PATCH] Add support for the Meriyah parser Meriyah is a fast and modern implementation of ECMAScript parser --- README.md | 2 +- lib/parser.ts | 4 ++-- package-lock.json | 16 ++++++++++++++++ package.json | 1 + parsers/meriyah.ts | 36 ++++++++++++++++++++++++++++++++++++ test/comments.ts | 2 ++ test/parser.ts | 2 ++ test/printer.ts | 1 + 8 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 parsers/meriyah.ts diff --git a/README.md b/README.md index d55db99f1..5c8124456 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ const tsAst = recast.parse(source, { }); ``` -**Note:** Some of these parsers import npm packages that Recast does not directly depend upon, so please be aware you may have to run `npm install babylon@next` to use the `typescript`, `flow`, or `babylon` parsers, or `npm install acorn` to use the `acorn` parser. Only Esprima is installed by default when Recast is installed. +**Note:** Some of these parsers import npm packages that Recast does not directly depend upon, so please be aware you may have to run `npm install babylon@next` to use the `typescript`, `flow`, or `babylon` parsers, or `npm install acorn` to use the `acorn` parser, or `npm install meriyah` to use the `meriyah` parser. Only Esprima is installed by default when Recast is installed. After calling `recast.parse`, if you're going to transform the AST, make sure that the `.original` property is preserved. With Babel, for instance, if you call `transformFromAST`, you must pass `cloneInputAst: false` in its options. ([More detail](https://github.com/babel/babel/issues/12882). diff --git a/lib/parser.ts b/lib/parser.ts index ca48b56bd..b7ab65ef3 100644 --- a/lib/parser.ts +++ b/lib/parser.ts @@ -78,8 +78,8 @@ export function parse(source: string, options?: Partial) { program = ast; // In order to ensure we reprint leading and trailing program // comments, wrap the original Program node with a File node. Only - // ESTree parsers (Acorn and Esprima) return a Program as the root AST - // node. Most other (Babylon-like) parsers return a File. + // ESTree parsers (Acorn, Esprima, Meriyah) return a Program as the root + // AST node. Most other (Babylon-like) parsers return a File. file = b.file(ast, options.sourceFileName || null); file.loc = { start: lines.firstPos(), diff --git a/package-lock.json b/package-lock.json index f72bf2d62..08e8b6661 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "flow-parser": "0.156.0", "glob": "7.2.0", "lint-staged": "^12.4.1", + "meriyah": "^4.2.1", "mocha": "9.0.2", "prettier": "^2.6.2", "reify": "0.20.12", @@ -4074,6 +4075,15 @@ "node": ">= 8" } }, + "node_modules/meriyah": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-4.2.1.tgz", + "integrity": "sha512-Uv5sWsmjFNC6IszEmHo5bzJLL+kqjQ/VrEj9Agqsqtx7B6dcxHnHLew1ioJD19HNXrxrRZltPi+NVh12I8RLXA==", + "dev": true, + "engines": { + "node": ">=10.4.0" + } + }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -8506,6 +8516,12 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, + "meriyah": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-4.2.1.tgz", + "integrity": "sha512-Uv5sWsmjFNC6IszEmHo5bzJLL+kqjQ/VrEj9Agqsqtx7B6dcxHnHLew1ioJD19HNXrxrRZltPi+NVh12I8RLXA==", + "dev": true + }, "micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", diff --git a/package.json b/package.json index 94e9134d8..00c2745d7 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "flow-parser": "0.156.0", "glob": "7.2.0", "lint-staged": "^12.4.1", + "meriyah": "^4.2.1", "mocha": "9.0.2", "prettier": "^2.6.2", "reify": "0.20.12", diff --git a/parsers/meriyah.ts b/parsers/meriyah.ts new file mode 100644 index 000000000..ddce0da9d --- /dev/null +++ b/parsers/meriyah.ts @@ -0,0 +1,36 @@ +// This module is suitable for passing as options.parser when calling +// recast.parse to process JavaScript code with Meriyah: +// +// const ast = recast.parse(source, { +// parser: require("recast/parsers/meriyah") +// }); +// +import { getOption } from "../lib/util"; + +function convertComment(comment: any): any { + let { type } = comment; + type = type[0] === 'S' ? 'Line' : 'Block'; // SingleLine/MultiLine + return { ...comment, type }; +} + +export function parse(source: string, options?: any) { + const comments: any[] = []; + const tokens: any[] = []; + const ast = require("meriyah").parse(source, { + module: getOption(options, "sourceType", "module") === "module", + specDeviation: getOption(options, "tolerant", true), + jsx: getOption(options, "jsx", false), + ranges: getOption(options, "range", false), + loc: true, + raw: true, + next: true, + globalReturn: true, + onComment: comments, + onToken: tokens, + }); + + ast.comments = comments.map(convertComment); + ast.tokens = tokens; + + return ast; +} diff --git a/test/comments.ts b/test/comments.ts index 4029c036a..ff9aecddd 100644 --- a/test/comments.ts +++ b/test/comments.ts @@ -23,6 +23,7 @@ const nodeMajorVersion = parseInt(process.versions.node, 10); describe("comments", function () { [ "../parsers/acorn", + "../parsers/meriyah", "../parsers/babel", "../parsers/esprima", "../parsers/flow", @@ -180,6 +181,7 @@ function runTestsForParser(parserId: any) { const info = ( { acorn: esprimaInfo, + meriyah: esprimaInfo, babel: babelInfo, esprima: esprimaInfo, flow: babelInfo, diff --git a/test/parser.ts b/test/parser.ts index c044146d4..0e5b97998 100644 --- a/test/parser.ts +++ b/test/parser.ts @@ -15,6 +15,7 @@ const nodeMajorVersion = parseInt(process.versions.node, 10); describe("parser", function () { [ "../parsers/acorn", + "../parsers/meriyah", "../parsers/babel", "../parsers/esprima", "../parsers/flow", @@ -84,6 +85,7 @@ function runTestsForParser(parserId: string) { const lineCommentTypes: { [name: string]: string } = { acorn: "Line", + meriyah: "Line", babel: "CommentLine", esprima: "Line", flow: "CommentLine", diff --git a/test/printer.ts b/test/printer.ts index a2934dde4..f78983913 100644 --- a/test/printer.ts +++ b/test/printer.ts @@ -1692,6 +1692,7 @@ describe("printer", function () { checkWith(require("../parsers/esprima")); checkWith(require("../parsers/acorn")); + checkWith(require("../parsers/meriyah")); if (nodeMajorVersion >= 6) { checkWith(require("../parsers/babel"));