Skip to content

Instantly share code, notes, and snippets.

@leaysgur
Last active September 2, 2024 01:52
Show Gist options
  • Save leaysgur/f4ac50a45645967a0f4bdb38112c3212 to your computer and use it in GitHub Desktop.
Save leaysgur/f4ac50a45645967a0f4bdb38112c3212 to your computer and use it in GitHub Desktop.
Try to use `oxc-parser` as Prettier parser for `estree` printer
import { format, __debug } from "./standalone.js";
import * as meriyahPlugin from "./src/plugins/meriyah.js";
import * as oxcPlugin from "./src/plugins/oxc.js";
import * as estreePlugin from "./src/plugins/estree.js";
const plugins = [estreePlugin, meriyahPlugin, oxcPlugin];
const source = `
// 1
let a
= 42 // 2
`.trim();
for (const parser of ["meriyah", "oxc"]) {
console.log(`🦄 ${parser}`);
const ast = await __debug.parse(source, { parser, plugins });
console.log(JSON.stringify(ast, null, 2));
const doc = await __debug.printToDoc(source, { parser, plugins });
console.log(JSON.stringify(doc, null, 2));
const formatted = await format(source, { parser, plugins });
console.log(["```", formatted, "```"].join("\n"));
}
diff --git a/src/language-js/parse/oxc.js b/src/language-js/parse/oxc.js
new file mode 100644
index 000000000..fbfada4ee
--- /dev/null
+++ b/src/language-js/parse/oxc.js
@@ -0,0 +1,71 @@
+import { parseSync as oxcParse } from "oxc-parser";
+
+import createError from "../../common/parser-create-error.js";
+import postprocess from "./postprocess/index.js";
+import createParser from "./utils/create-parser.js";
+import getSourceType from "./utils/get-source-type.js";
+
+const parseOptions = {
+ preserveParens: true,
+};
+
+function parseWithOptions(text, sourceType) {
+ const { program, comments, errors } = oxcParse(text, {
+ sourceType,
+ ...parseOptions,
+ });
+
+ if (errors.length !== 0) throw new Error(errors[0]);
+
+ const ast = JSON.parse(program);
+ ast.comments = comments.map((comment) => ({
+ ...comment,
+ start: comment.start - 2,
+ }));
+
+ return ast;
+}
+
+// TODO: Not sure
+function createParseError(error) {
+ let { message, line, column } = error;
+
+ const matches = message.match(
+ /^\[(?<line>\d+):(?<column>\d+)\]: (?<message>.*)$/u,
+ )?.groups;
+
+ if (matches) {
+ message = matches.message;
+
+ /* c8 ignore next 4 */
+ if (typeof line !== "number") {
+ line = Number(matches.line);
+ column = Number(matches.column);
+ }
+ }
+
+ /* c8 ignore next 3 */
+ if (typeof line !== "number") {
+ return error;
+ }
+
+ return createError(message, {
+ loc: { start: { line, column } },
+ cause: error,
+ });
+}
+
+function parse(text, options = {}) {
+ const sourceType = getSourceType(options);
+
+ let ast;
+ try {
+ ast = parseWithOptions(text, sourceType);
+ } catch (/** @type {any} */ { errors: [error] }) {
+ throw createParseError(error);
+ }
+
+ return postprocess(ast, { parser: "oxc", text });
+}
+
+export const oxc = createParser(parse);
diff --git a/src/language-js/parse/postprocess/index.js b/src/language-js/parse/postprocess/index.js
index f148bc8b3..5bbdb56aa 100644
--- a/src/language-js/parse/postprocess/index.js
+++ b/src/language-js/parse/postprocess/index.js
@@ -59,6 +59,18 @@ function postprocess(ast, options) {
});
}
+ if (parser === "oxc") {
+ ast = visitNode(ast, (node) => {
+ // TODO: Other literals may need to be fixed too
+ if (node.type === "StringLiteral") {
+ node.extra = { raw: node.value };
+ }
+ if (node.type === "NumericLiteral") {
+ node.extra = { raw: node.raw };
+ }
+ });
+ }
+
ast = visitNode(ast, (node) => {
switch (node.type) {
case "LogicalExpression":
diff --git a/src/plugins/oxc.js b/src/plugins/oxc.js
new file mode 100644
index 000000000..dfda20300
--- /dev/null
+++ b/src/plugins/oxc.js
@@ -0,0 +1 @@
+export * as parsers from "../language-js/parse/oxc.js";
@leaysgur
Copy link
Author

leaysgur commented Sep 2, 2024

Not practical at all.

It works with let a = 42; but for other case, many AST modifications are still required...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment