From c26d23c95561742ad51a79c79ef96887a21be8bc Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 27 May 2025 09:35:31 +0800 Subject: [PATCH] Add `oxc` parser (#17472) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .github/workflows/prod-test.yml | 5 +- CONTRIBUTING.md | 2 +- eslint.config.js | 1 + knip.config.js | 1 + package.json | 4 +- packages/plugin-oxc/README.md | 31 +++ packages/plugin-oxc/index.js | 3 + packages/plugin-oxc/package.json | 22 ++ scripts/build-website.js | 2 +- scripts/build/README.md | 10 + scripts/build/build-dependencies-license.js | 10 +- scripts/build/build-javascript-module.js | 9 +- scripts/build/build-package-json.js | 43 +++- scripts/build/build-types.js | 2 +- scripts/build/build.js | 55 ++++- scripts/build/config.js | 88 +++++++- scripts/build/parse-arguments.js | 18 +- scripts/release/steps/generate-bundles.js | 8 +- scripts/utils/index.js | 2 + src/language-js/comments/printer-methods.js | 1 + src/language-js/parse/oxc.js | 84 ++++++++ src/language-js/print/property.js | 1 + src/main/range-util.js | 1 + src/utils/try-combinations.js | 21 ++ tests/config/run-format-test.js | 71 +++++- tests/config/utils/check-parsers.js | 3 +- .../__snapshots__/format.test.js.snap | 9 + tests/format/js/arrows-bind/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 8 + .../newline-before-arrow/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 9 + .../js/async-do-expressions/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 160 ++++++++++++++ tests/format/js/babel-plugins/format.test.js | 18 ++ .../__snapshots__/format.test.js.snap | 122 +++++++++++ .../format/js/bind-expressions/format.test.js | 4 +- .../invalid/__snapshots__/format.test.js.snap | 9 + tests/format/js/call/invalid/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 11 + .../comments-pipeline-own-line/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 14 ++ .../deferred-import-evaluation/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 75 +++++++ .../format.test.js | 2 +- .../js/do/__snapshots__/format.test.js.snap | 22 ++ tests/format/js/do/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 28 +++ .../format.test.js | 8 + .../escaped/__snapshots__/format.test.js.snap | 7 + .../js/export-default/escaped/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 10 + .../export-default-from/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 36 ++++ tests/format/js/module-blocks/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 11 + .../js/multiparser-invalid/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 20 ++ .../no-semi-babylon-extensions/format.test.js | 4 +- .../objects/__snapshots__/format.test.js.snap | 11 + tests/format/js/objects/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 99 +++++++++ .../format.test.js | 1 + .../__snapshots__/format.test.js.snap | 9 + .../js/partial-application/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 38 ++++ .../js/pipeline-operator/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 14 ++ .../js/source-phase-imports/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 9 + .../js/throw_expressions/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 18 ++ tests/format/js/v8_intrinsic/format.test.js | 2 +- .../jsx/do/__snapshots__/format.test.js.snap | 10 + tests/format/jsx/do/format.test.js | 1 + yarn.lock | 203 +++++++++++++++++- 75 files changed, 1458 insertions(+), 67 deletions(-) create mode 100644 packages/plugin-oxc/README.md create mode 100644 packages/plugin-oxc/index.js create mode 100644 packages/plugin-oxc/package.json create mode 100644 src/language-js/parse/oxc.js diff --git a/.github/workflows/prod-test.yml b/.github/workflows/prod-test.yml index ce83197f6..494aceeab 100644 --- a/.github/workflows/prod-test.yml +++ b/.github/workflows/prod-test.yml @@ -176,5 +176,8 @@ jobs: path: dist - name: Release + # Use `--compact` after we publish `@prettier/plugin-oxc` + # run: | + # npx pkg-pr-new publish "./dist/*" --compact --packageManager=yarn run: | - npx pkg-pr-new publish "./dist/*" --compact --packageManager=yarn + npx pkg-pr-new publish "./dist/*" --packageManager=yarn diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c3fecae10..762dc818b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ function runFormatTest( Parameters: - **`fixtures`**: Must be set to `import.meta` or to an object of the shape `{ importMeta: import.meta, ... }`. The object may have the `snippets` property to specify an array of extra input entries in addition to the files in the current directory. For each input entry (a file or a snippet), `runFormatTest` configures and runs a number of tests. The main check is that for a given input the output should match the snapshot (for snippets, the expected output can also be specified directly). [Additional checks](#deeper-testing) are controlled by options and environment variables. -- **`parsers`**: A list of parser names. The tests verify that the parsers in this list produce the same output. If the list includes `typescript`, then `babel-ts` is included implicitly. If the list includes `flow`, then `babel-flow` is included implicitly. If the list includes `babel`, and the current directory is inside `tests/format/js` or `tests/format/jsx`, then `acorn`, `espree`, and `meriyah` are included implicitly. +- **`parsers`**: A list of parser names. The tests verify that the parsers in this list produce the same output. If the list includes `typescript`, then `babel-ts` is included implicitly. If the list includes `flow`, then `babel-flow` is included implicitly. If the list includes `babel`, and the current directory is inside `tests/format/js` or `tests/format/jsx`, then `acorn`, `espree`, `meriyah`, and `oxc` are included implicitly. - **`options`**: In addition to Prettier's formatting options, can contain the `errors` property to specify that it's expected that the formatting shouldn't be successful and an error should be thrown for all (`errors: true`) or some combinations of input entries and parsers. The implementation of `runFormatTest` can be found in [`tests/config/run-format-test.js`](tests/config/run-format-test.js). diff --git a/eslint.config.js b/eslint.config.js index 8a22cc627..6dfd1eac3 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -431,6 +431,7 @@ export default [ "src/language-js/parse/meriyah.js", "src/language-js/parse/json.js", "src/language-js/parse/acorn.js", + "src/language-js/parse/oxc.js", "src/language-js/parse/utils/wrap-babel-expression.js", ], "prettier-internal-rules/prefer-create-type-check-function": [ diff --git a/knip.config.js b/knip.config.js index a768c7d40..6850346b7 100644 --- a/knip.config.js +++ b/knip.config.js @@ -8,6 +8,7 @@ export default { // so there is no actual use of the CLI files "src/cli/index.js", "src/experimental-cli/index.js", + "packages/plugin-oxc/index.js", ], project: ["src/**", "scripts/**"], ignore: [ diff --git a/package.json b/package.json index 6f830e831..9d35f492d 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "html-ua-styles": "0.0.8", "ignore": "7.0.4", "import-meta-resolve": "4.1.0", + "index-to-position": "1.1.0", "is-es5-identifier-name": "1.0.0", "jest-docblock": "30.0.0-alpha.7", "json5": "2.2.3", @@ -81,6 +82,7 @@ "minimist": "1.2.8", "n-readlines": "1.0.1", "outdent": "0.8.0", + "oxc-parser": "0.69.0", "parse-json": "8.3.0", "picocolors": "1.1.1", "please-upgrade-node": "3.2.0", @@ -137,7 +139,6 @@ "eslint-plugin-unicorn": "59.0.1", "esm-utils": "4.4.2", "globals": "16.1.0", - "index-to-position": "1.1.0", "jest": "30.0.0-alpha.7", "jest-light-runner": "0.7.8", "jest-snapshot-serializer-ansi": "2.2.1", @@ -150,6 +151,7 @@ "npm-run-all2": "8.0.3", "prettier": "3.5.3", "pretty-bytes": "7.0.0", + "pretty-ms": "9.2.0", "rollup-plugin-license": "3.6.0", "semver": "7.7.2", "serialize-javascript": "6.0.2", diff --git a/packages/plugin-oxc/README.md b/packages/plugin-oxc/README.md new file mode 100644 index 000000000..f7cec954d --- /dev/null +++ b/packages/plugin-oxc/README.md @@ -0,0 +1,31 @@ +# @prettier/plugin-oxc + +> Prettier Oxc plugin. + +## Install + +```bash +yarn add --dev prettier @prettier/plugin-oxc +``` + +## Usage + +Create or modify your [prettier configuration file](https://prettier.io/docs/en/configuration) to use the plugin: + +```json +{ + "overrides": [ + { + "files": ["**/*.{js,mjs,cjs}"], + "options": { + "plugins": ["@prettier/plugin-oxc"], + "parser": "oxc" + } + } + ] +} +``` + +## Related + +- [Oxc](https://oxc.rs/) - The JavaScript Oxidation Compiler diff --git a/packages/plugin-oxc/index.js b/packages/plugin-oxc/index.js new file mode 100644 index 000000000..d81d6defb --- /dev/null +++ b/packages/plugin-oxc/index.js @@ -0,0 +1,3 @@ +import { oxc } from "../../src/language-js/parse/oxc.js"; + +export const parsers = { oxc }; diff --git a/packages/plugin-oxc/package.json b/packages/plugin-oxc/package.json new file mode 100644 index 000000000..3d256d741 --- /dev/null +++ b/packages/plugin-oxc/package.json @@ -0,0 +1,22 @@ +{ + "name": "@prettier/plugin-oxc", + "version": "0.0.1", + "description": "Prettier Oxc plugin.", + "type": "module", + "exports": { + ".": { + "types": "./index.d.js", + "default": "./index.mjs" + }, + "./*": "./*" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/prettier/prettier.git", + "directory": "packages/plugin-oxc" + }, + "funding": "https://github.com/prettier/prettier?sponsor=1", + "homepage": "https://github.com/prettier/prettier/packages/plugin-oxc", + "author": "fisker Cheung ", + "license": "MIT" +} diff --git a/scripts/build-website.js b/scripts/build-website.js index 95d913f60..2cd011d42 100644 --- a/scripts/build-website.js +++ b/scripts/build-website.js @@ -43,7 +43,7 @@ async function buildPrettier() { }); try { - await runYarn("build", ["--playground", "--clean"], { + await runYarn("build", ["--package=prettier", "--clean", "--playground"], { cwd: PROJECT_ROOT, }); } finally { diff --git a/scripts/build/README.md b/scripts/build/README.md index 1da91e8b8..67a3d5401 100644 --- a/scripts/build/README.md +++ b/scripts/build/README.md @@ -12,6 +12,16 @@ yarn build ## Flags +### `--package` + +What package to build, will build all packages if omitted. + +``` +yarn build +yarn build --package prettier +yarn build --package prettier --package @prettier/plugin-oxc +``` + ### `--clean` Remove `dist` directory before bundle files. diff --git a/scripts/build/build-dependencies-license.js b/scripts/build/build-dependencies-license.js index a1d5bd69f..b297f3d31 100644 --- a/scripts/build/build-dependencies-license.js +++ b/scripts/build/build-dependencies-license.js @@ -42,11 +42,11 @@ function getDependencies(results) { return dependencies; } -function getLicenseText(dependencies) { +function getLicenseText(packageConfig, dependencies) { dependencies = dependencies.filter( (dependency, index) => - // Exclude ourself - dependency.name !== "prettier" && + // Exclude self + dependency.name !== packageConfig.packageName && // Unique by `name` and `version` index === dependencies.findIndex( @@ -72,7 +72,7 @@ function getLicenseText(dependencies) { const head = outdent` # Licenses of bundled dependencies - The published Prettier artifact additionally contains code with the following licenses: + The published ${packageConfig.packageDisplayName ?? packageConfig.packageName} artifact additionally contains code with the following licenses: ${new Intl.ListFormat("en-US", { type: "conjunction" }).format(licenses)}. `; @@ -149,7 +149,7 @@ async function buildDependenciesLicense({ throw new Error("Fail to collect dependencies."); } - const text = getLicenseText(dependencies); + const text = getLicenseText(packageConfig, dependencies); await fs.writeFile(path.join(distDirectory, fileName), text); } diff --git a/scripts/build/build-javascript-module.js b/scripts/build/build-javascript-module.js index 8ac8a1272..4bed8dcb6 100644 --- a/scripts/build/build-javascript-module.js +++ b/scripts/build/build-javascript-module.js @@ -4,7 +4,10 @@ import browserslistToEsbuild from "browserslist-to-esbuild"; import esbuild from "esbuild"; import { nodeModulesPolyfillPlugin as esbuildPluginNodeModulePolyfills } from "esbuild-plugins-node-modules-polyfill"; import createEsmUtils from "esm-utils"; -import { PROJECT_ROOT } from "../utils/index.js"; +import { + PRODUCTION_MINIMAL_NODE_JS_VERSION, + PROJECT_ROOT, +} from "../utils/index.js"; import esbuildPluginAddDefaultExport from "./esbuild-plugins/add-default-export.js"; import esbuildPluginEvaluate from "./esbuild-plugins/evaluate.js"; import esbuildPluginPrimitiveDefine from "./esbuild-plugins/primitive-define.js"; @@ -241,7 +244,9 @@ function getEsbuildOptions({ packageConfig, file, cliOptions }) { external: ["pnpapi", ...(buildOptions.external ?? [])], // Disable esbuild auto discover `tsconfig.json` file tsconfigRaw: JSON.stringify({}), - target: [...(buildOptions.target ?? ["node14"])], + target: [ + ...(buildOptions.target ?? [`node${PRODUCTION_MINIMAL_NODE_JS_VERSION}`]), + ], logLevel: "error", format: file.output.format, outfile: path.join(distDirectory, cliOptions.saveAs ?? file.output.file), diff --git a/scripts/build/build-package-json.js b/scripts/build/build-package-json.js index 10561ad77..0793033c2 100644 --- a/scripts/build/build-package-json.js +++ b/scripts/build/build-package-json.js @@ -1,5 +1,10 @@ import path from "node:path"; -import { PROJECT_ROOT, readJson, writeJson } from "../utils/index.js"; +import { + PRODUCTION_MINIMAL_NODE_JS_VERSION, + PROJECT_ROOT, + readJson, + writeJson, +} from "../utils/index.js"; const keysToKeep = [ "name", @@ -20,7 +25,7 @@ const keysToKeep = [ "preferUnplugged", ]; -async function buildPackageJson({ packageConfig, file }) { +async function buildPrettierPackageJson({ packageConfig, file }) { const { distDirectory, files } = packageConfig; const packageJson = await readJson(path.join(PROJECT_ROOT, file.input)); @@ -36,8 +41,8 @@ async function buildPackageJson({ packageConfig, file }) { engines: { ...packageJson.engines, // https://github.com/prettier/prettier/pull/13118#discussion_r922708068 - // Don't delete, comment out if we don't want override - node: ">=14", + // Don't delete, event it's the same in package.json + node: `>=${PRODUCTION_MINIMAL_NODE_JS_VERSION}`, }, type: "commonjs", exports: { @@ -108,6 +113,34 @@ async function buildPackageJson({ packageConfig, file }) { ); } +async function buildPluginOxcPackageJson({ packageConfig, file }) { + const { distDirectory, files } = packageConfig; + const packageJson = await readJson(path.join(PROJECT_ROOT, file.input)); + const projectPackageJson = await readJson( + path.join(PROJECT_ROOT, "package.json"), + ); + + const overrides = { + engines: { + ...packageJson.engines, + // https://github.com/prettier/prettier/pull/13118#discussion_r922708068 + // Don't delete, event it's the same in package.json + node: `>=${PRODUCTION_MINIMAL_NODE_JS_VERSION}`, + }, + // Use `commonjs` since we may provide browser build in future. + type: "commonjs", + files: files.map(({ output: { file } }) => file).sort(), + dependencies: { + "oxc-parser": projectPackageJson.dependencies["oxc-parser"], + }, + }; + + await writeJson( + path.join(distDirectory, file.output.file), + Object.assign(pick(packageJson, keysToKeep), overrides), + ); +} + function pick(object, keys) { keys = new Set(keys); return Object.fromEntries( @@ -115,4 +148,4 @@ function pick(object, keys) { ); } -export default buildPackageJson; +export { buildPluginOxcPackageJson, buildPrettierPackageJson }; diff --git a/scripts/build/build-types.js b/scripts/build/build-types.js index 1e65175c0..358b25469 100644 --- a/scripts/build/build-types.js +++ b/scripts/build/build-types.js @@ -43,7 +43,7 @@ async function buildPluginTypes({ packageConfig, file: { input, output } }) { parserNames.length === 0 ? "export {};" : outdent` - import { Parser } from "../index.js"; + import { Parser } from "${packageConfig.packageName === "prettier" ? "../index.js" : "prettier"}"; export declare const parsers: { ${parserNames diff --git a/scripts/build/build.js b/scripts/build/build.js index 61a93aaef..d563bc477 100644 --- a/scripts/build/build.js +++ b/scripts/build/build.js @@ -6,8 +6,9 @@ import readline from "node:readline"; import createEsmUtils from "esm-utils"; import styleText from "node-style-text"; import prettyBytes from "pretty-bytes"; +import prettyMilliseconds from "pretty-ms"; import { DIST_DIR } from "../utils/index.js"; -import packageConfig from "./config.js"; +import packageConfigs from "./config.js"; import parseArguments from "./parse-arguments.js"; const { require } = createEsmUtils(import.meta); @@ -132,6 +133,24 @@ async function buildFile({ packageConfig, file, cliOptions, results }) { async function run() { const cliOptions = parseArguments(); + let packagesToBuild = []; + if (cliOptions.packages) { + for (const packageName of cliOptions.packages) { + const packageConfig = packageConfigs.find( + (packageConfig) => packageConfig.packageName === packageName, + ); + + if (!packageConfig) { + throw new Error(`Unknown package "${packageName}"`); + } + + packagesToBuild.push(packageConfig); + } + } else { + packagesToBuild = packageConfigs; + } + + // TODO: Clear package dist directory instead if (cliOptions.clean) { let stat; try { @@ -149,17 +168,31 @@ async function run() { } } - console.log(styleText.inverse(" Building packages ")); + for (const [index, packageConfig] of packagesToBuild.entries()) { + if (index > 0) { + console.log(); + } - const results = []; - for (const file of packageConfig.files) { - const result = await buildFile({ - packageConfig, - file, - cliOptions, - results, - }); - results.push(result); + console.log( + styleText.inverse( + `[${index + 1}/${packagesToBuild.length}] Building package '${packageConfig.packageName}'`, + ), + ); + + const startTime = performance.now(); + const results = []; + for (const file of packageConfig.files) { + const result = await buildFile({ + packageConfig, + file, + cliOptions, + results, + }); + results.push(result); + } + console.log( + `Build package '${packageConfig.packageName}' success in ${prettyMilliseconds(performance.now() - startTime)}`, + ); } } diff --git a/scripts/build/config.js b/scripts/build/config.js index 0e421551a..f398c3185 100644 --- a/scripts/build/config.js +++ b/scripts/build/config.js @@ -6,7 +6,10 @@ import { outdent } from "outdent"; import { copyFile, DIST_DIR, PROJECT_ROOT } from "../utils/index.js"; import buildDependenciesLicense from "./build-dependencies-license.js"; import buildJavascriptModule from "./build-javascript-module.js"; -import buildPackageJson from "./build-package-json.js"; +import { + buildPluginOxcPackageJson, + buildPrettierPackageJson, +} from "./build-package-json.js"; import buildTypes from "./build-types.js"; import esmifyTypescriptEslint from "./esmify-typescript-eslint.js"; import modifyTypescriptModule from "./modify-typescript-module.js"; @@ -895,7 +898,7 @@ const metaFiles = [ output: { format: "json", }, - build: buildPackageJson, + build: buildPrettierPackageJson, }, { input: "README.md", @@ -919,8 +922,79 @@ const metaFiles = [ /** @type {Files[]} */ const files = [...nodejsFiles, ...universalFiles, ...metaFiles].filter(Boolean); -export default { - packageName: "prettier", - distDirectory: path.join(DIST_DIR, "prettier"), - files, -}; +export default [ + { + packageName: "prettier", + // Used in THIRD-PARTY-NOTICES.md + packageDisplayName: "Prettier", + distDirectory: path.join(DIST_DIR, "prettier"), + files, + }, + { + packageName: "@prettier/plugin-oxc", + distDirectory: path.join(DIST_DIR, "plugin-oxc"), + files: [ + ...[ + { + input: "packages/plugin-oxc/index.js", + addDefaultExport: true, + external: ["oxc-parser"], + }, + ].flatMap((file) => { + let { input, output, outputBaseName, ...buildOptions } = file; + + const format = input.endsWith(".cjs") ? "cjs" : "esm"; + outputBaseName ??= path.basename(input, path.extname(input)); + + return [ + { + input, + output: { + format, + file: `${outputBaseName}${extensions[format]}`, + }, + platform: "node", + buildOptions, + build: buildJavascriptModule, + kind: "javascript", + }, + getTypesFileConfig({ input, outputBaseName, isPlugin: true }), + ]; + }), + ...[ + { + input: "packages/plugin-oxc/package.json", + output: { + file: "package.json", + format: "json", + }, + build: buildPluginOxcPackageJson, + }, + { + input: "packages/plugin-oxc/README.md", + output: { + file: "README.md", + }, + build: copyFileBuilder, + }, + { + input: "LICENSE", + output: { + file: "LICENSE", + }, + build: copyFileBuilder, + }, + { + output: { + file: "THIRD-PARTY-NOTICES.md", + }, + build: buildDependenciesLicense, + }, + ].map((file) => ({ + ...file, + output: { file: file.input, ...file.output }, + kind: "meta", + })), + ], + }, +]; diff --git a/scripts/build/parse-arguments.js b/scripts/build/parse-arguments.js index b6e39d790..25c0743c7 100644 --- a/scripts/build/parse-arguments.js +++ b/scripts/build/parse-arguments.js @@ -2,9 +2,12 @@ import path from "node:path"; import { parseArgs } from "node:util"; import { DIST_DIR } from "../utils/index.js"; +const isUnique = (array) => new Set(array).size === array.length; + function parseArguments() { const { values } = parseArgs({ options: { + package: { type: "string", multiple: true }, playground: { type: "boolean", default: false }, "print-size": { type: "boolean", default: false }, "compare-size": { type: "boolean", default: false }, @@ -30,32 +33,37 @@ function parseArguments() { clean: values.clean, saveAs: values["save-as"], reports: values.report, + packages: values.package, }; + if (Array.isArray(result.packages) && !isUnique(result.packages)) { + throw new Error("'--package' should be unique."); + } + if (result.saveAs) { if (result.files?.size !== 1) { throw new Error( - "'--save-as' can only use together with one '--file' flag", + "'--save-as' can only use together with one '--file' flag.", ); } // TODO: Support package name const distDirectory = path.join(DIST_DIR, "prettier"); if (!path.join(distDirectory, result.saveAs).startsWith(distDirectory)) { - throw new Error("'--save-as' can only relative path"); + throw new Error("'--save-as' can only relative path."); } } if (result.compareSize) { if (result.minify === false) { throw new Error( - "'--compare-size' can not use together with '--no-minify' flag", + "'--compare-size' can not use together with '--no-minify' flag.", ); } if (result.saveAs) { throw new Error( - "'--compare-size' can not use together with '--save-as' flag", + "'--compare-size' can not use together with '--save-as' flag.", ); } } @@ -63,7 +71,7 @@ function parseArguments() { if (Array.isArray(result.reports) && result.reports.includes("all")) { if (result.reports.length !== 1) { throw new Error( - "'--report=all' can not use with another '--report' flag", + "'--report=all' can not use with another '--report' flag.", ); } diff --git a/scripts/release/steps/generate-bundles.js b/scripts/release/steps/generate-bundles.js index ba5a4eb91..dbc612b9a 100644 --- a/scripts/release/steps/generate-bundles.js +++ b/scripts/release/steps/generate-bundles.js @@ -8,7 +8,13 @@ export default async function generateBundles({ dry, version, manual }) { await logPromise( "Generating bundles", - runYarn(["build", "--clean", "--print-size", "--compare-size"]), + runYarn([ + "build", + "--package=prettier", + "--clean", + "--print-size", + "--compare-size", + ]), ); const builtPkg = await readJson("dist/prettier/package.json"); diff --git a/scripts/utils/index.js b/scripts/utils/index.js index 398e572cc..386889472 100644 --- a/scripts/utils/index.js +++ b/scripts/utils/index.js @@ -36,10 +36,12 @@ const PROJECT_ROOT = url.fileURLToPath(new URL("../../", import.meta.url)); const DIST_DIR = path.join(PROJECT_ROOT, "dist"); const WEBSITE_DIR = path.join(PROJECT_ROOT, "website"); const SOURCE_DIR = path.join(PROJECT_ROOT, "src"); +const PRODUCTION_MINIMAL_NODE_JS_VERSION = "14"; export { copyFile, DIST_DIR, + PRODUCTION_MINIMAL_NODE_JS_VERSION, PROJECT_ROOT, readJson, SOURCE_DIR, diff --git a/src/language-js/comments/printer-methods.js b/src/language-js/comments/printer-methods.js index afae8fca2..ed8d74880 100644 --- a/src/language-js/comments/printer-methods.js +++ b/src/language-js/comments/printer-methods.js @@ -45,6 +45,7 @@ function getCommentChildNodes(node, options) { (options.parser === "typescript" || options.parser === "flow" || options.parser === "acorn" || + options.parser === "oxc" || options.parser === "espree" || options.parser === "meriyah" || options.parser === "__babel_estree") && diff --git a/src/language-js/parse/oxc.js b/src/language-js/parse/oxc.js new file mode 100644 index 000000000..9db135d24 --- /dev/null +++ b/src/language-js/parse/oxc.js @@ -0,0 +1,84 @@ +import indexToPosition from "index-to-position"; +import { parseAsync as oxcParse, rawTransferSupported } from "oxc-parser"; +import createError from "../../common/parser-create-error.js"; +import { tryCombinationsAsync } from "../../utils/try-combinations.js"; +import postprocess from "./postprocess/index.js"; +import createParser from "./utils/create-parser.js"; +import getSourceType from "./utils/get-source-type.js"; + +function createParseError(error, { text }) { + const { + message, + labels: [{ start: startIndex, end: endIndex }], + } = error; + + const [start, end] = [startIndex, endIndex].map((index) => + indexToPosition(text, index, { oneBased: true }), + ); + + return createError(message, { + loc: { + start, + end, + }, + cause: error, + }); +} + +let cachedIsRawTransferSupported; +const isRawTransferSupported = () => { + cachedIsRawTransferSupported ??= rawTransferSupported(); + return cachedIsRawTransferSupported; +}; + +async function parseWithOptions(filename, text, sourceType) { + const result = await oxcParse(filename, text, { + sourceType, + lang: "jsx", + preserveParens: false, + // @ts-expect-error -- missing + experimentalRawTransfer: isRawTransferSupported(), + }); + + const { errors } = result; + for (const error of errors) { + if ( + error.severity === "Error" && + (error.message === + "A 'return' statement can only be used within a function body." || + /^Identifier `.*` has already been declared$/u.test(error.message)) + ) { + continue; + } + throw createParseError(error, { text }); + } + + return result; +} + +async function parse(text, options = {}) { + const sourceType = getSourceType(options); + let { filepath } = options; + if (typeof filepath !== "string") { + filepath = "prettier.jsx"; + } + + const combinations = (sourceType ? [sourceType] : ["module", "script"]).map( + (sourceType) => () => parseWithOptions(filepath, text, sourceType), + ); + + let result; + try { + result = await tryCombinationsAsync(combinations); + } catch (/** @type {any} */ { errors: [error] }) { + throw error; + } + + const { program: ast, comments } = result; + // @ts-expect-error -- expected + ast.comments = comments; + + return postprocess(ast, { text, parser: "oxc" }); +} + +export const oxc = createParser(parse); diff --git a/src/language-js/print/property.js b/src/language-js/print/property.js index 9556833d1..7d972946e 100644 --- a/src/language-js/print/property.js +++ b/src/language-js/print/property.js @@ -69,6 +69,7 @@ function isStringKeySafeToUnquote(node, options) { node.type !== "ImportAttribute" && (options.parser === "babel" || options.parser === "acorn" || + options.parser === "oxc" || options.parser === "espree" || options.parser === "meriyah" || options.parser === "__babel_estree") diff --git a/src/main/range-util.js b/src/main/range-util.js index 97c9ae8f4..b2e2906a3 100644 --- a/src/main/range-util.js +++ b/src/main/range-util.js @@ -177,6 +177,7 @@ function isSourceElement(opts, node, parentNode) { case "acorn": case "espree": case "meriyah": + case "oxc": case "__babel_estree": return isJsSourceElement(node.type, parentNode?.type); case "json": diff --git a/src/utils/try-combinations.js b/src/utils/try-combinations.js index 51709a1e1..5ba940306 100644 --- a/src/utils/try-combinations.js +++ b/src/utils/try-combinations.js @@ -18,4 +18,25 @@ function tryCombinations(combinations) { throw Object.assign(new Error("All combinations failed"), { errors }); } +/** + * @template {function} T + * @param {T[]} combinations + * @returns {Promise>} + */ +async function tryCombinationsAsync(combinations) { + const errors = []; + for (const fn of combinations) { + try { + return await fn(); + } catch (error) { + errors.push(error); + } + } + + // TODO: Use `AggregateError` when we drop Node.js v14 + // throw new AggregateError(errors, "All combinations failed"); + throw Object.assign(new Error("All combinations failed"), { errors }); +} + export default tryCombinations; +export { tryCombinationsAsync }; diff --git a/tests/config/run-format-test.js b/tests/config/run-format-test.js index 0379bda7b..068092ee5 100644 --- a/tests/config/run-format-test.js +++ b/tests/config/run-format-test.js @@ -11,7 +11,8 @@ import visualizeEndOfLine from "./utils/visualize-end-of-line.js"; const { __dirname } = createEsmUtils(import.meta); -const { FULL_TEST, TEST_STANDALONE } = process.env; +const { FULL_TEST, TEST_STANDALONE, NODE_ENV } = process.env; +const isProduction = NODE_ENV === "production"; const BOM = "\uFEFF"; const CURSOR_PLACEHOLDER = "<|>"; @@ -56,16 +57,17 @@ const unstableTests = new Map( ); const unstableAstTests = new Map(); - -const espreeDisabledTests = new Set( +const commentClosureTypecaseTests = new Set( [ // These tests only work for `babel` "comments-closure-typecast", ].map((directory) => path.join(__dirname, "../format/js", directory)), ); + +const espreeDisabledTests = commentClosureTypecaseTests; const acornDisabledTests = new Set(); const meriyahDisabledTests = new Set([ - ...espreeDisabledTests, + ...commentClosureTypecaseTests, ...[ // Parsing to different ASTs "js/decorators/member-expression.js", @@ -78,11 +80,43 @@ const meriyahDisabledTests = new Set([ "js/regex/regexp-modifiers.js", ].map((file) => path.join(__dirname, "../format", file)), ]); -const babelTsDisabledTest = new Set( +const babelTsDisabledTests = new Set( ["conformance/types/moduleDeclaration/kind-detection.ts"].map((file) => path.join(__dirname, "../format/typescript", file), ), ); +const oxcDisabledTests = new Set([ + ...commentClosureTypecaseTests, + ...[ + // Missing `.phase` + // https://github.com/oxc-project/oxc/issues/10978 + "js/babel-plugins/deferred-import-evaluation.js", + "js/babel-plugins/source-phase-imports.js", + "js/deferred-import-evaluation/dynamic-import-attributes-expression.js", + "js/deferred-import-evaluation/dynamic-import.js", + "js/deferred-import-evaluation/import-defer-attributes-declaration.js", + "js/deferred-import-evaluation/import-defer.js", + "js/dynamic-import/import-phase.js", + "js/source-phase-imports/import-source-attributes-expression.js", + "js/source-phase-imports/import-source-dynamic-import.js", + "js/source-phase-imports/import-source-attributes-declaration.js", + "js/source-phase-imports/import-source-binding-from.js", + "js/source-phase-imports/import-source-binding-source.js", + "js/source-phase-imports/import-source.js", + + // Missing `.decorators` + // https://github.com/oxc-project/oxc/issues/10921 + "js/babel-plugins/decorators.js", + "js/decorators", + "js/decorators/class-expression", + "js/decorators-export", + "js/decorator-auto-accessors", + "js/ignore/class-expression-decorator.js", + + // https://github.com/oxc-project/oxc/issues/10980 + "js/top-level-await/test.cjs", // Parses as `module` even I already told it's `script` + ].map((file) => path.join(__dirname, "../format", file)), +]); const isUnstable = (filename, options) => { const testFunction = unstableTests.get(filename); @@ -236,6 +270,9 @@ function runFormatTest(fixtures, parsers, options) { if (!parsers.includes("meriyah") && !meriyahDisabledTests.has(dirname)) { allParsers.push("meriyah"); } + if (!parsers.includes("acorn") && !oxcDisabledTests.has(dirname)) { + allParsers.push("oxc"); + } } if ( @@ -285,10 +322,11 @@ function runFormatTest(fixtures, parsers, options) { for (const currentParser of allParsers) { if ( + (currentParser === "acorn" && acornDisabledTests.has(filename)) || (currentParser === "espree" && espreeDisabledTests.has(filename)) || (currentParser === "meriyah" && meriyahDisabledTests.has(filename)) || - (currentParser === "acorn" && acornDisabledTests.has(filename)) || - (currentParser === "babel-ts" && babelTsDisabledTest.has(filename)) + (currentParser === "oxc" && oxcDisabledTests.has(filename)) || + (currentParser === "babel-ts" && babelTsDisabledTests.has(filename)) ) { continue; } @@ -508,10 +546,11 @@ const insertCursor = (text, cursorOffset) => text.slice(cursorOffset) : text; async function format(originalText, originalOptions) { - const { text: input, options } = replacePlaceholders( + let { text: input, options } = replacePlaceholders( originalText, originalOptions, ); + options = await loadPlugins(options); const inputWithCursor = insertCursor(input, options.cursorOffset); const prettier = await getPrettier(); @@ -534,4 +573,20 @@ async function format(originalText, originalOptions) { }; } +async function loadPlugins(options) { + if (options.parser === "oxc") { + const plugins = options.plugins ?? []; + const url = new URL( + isProduction + ? "../../dist/plugin-oxc/index.mjs" + : "../../packages/plugin-oxc/index.js", + import.meta.url, + ); + plugins.push(TEST_STANDALONE ? await import(url) : url); + return { ...options, plugins }; + } + + return options; +} + export default runFormatTest; diff --git a/tests/config/utils/check-parsers.js b/tests/config/utils/check-parsers.js index ede5d8c98..19dafab8f 100644 --- a/tests/config/utils/check-parsers.js +++ b/tests/config/utils/check-parsers.js @@ -57,12 +57,13 @@ const categoryParsers = new Map([ [ "js", { - parsers: ["babel", "acorn", "espree", "meriyah"], + parsers: ["babel", "acorn", "espree", "meriyah", "oxc"], verifyParsers: [ "babel", "acorn", "espree", "meriyah", + "oxc", "flow", "babel-flow", "typescript", diff --git a/tests/format/js/arrows-bind/__snapshots__/format.test.js.snap b/tests/format/js/arrows-bind/__snapshots__/format.test.js.snap index cbaef4ad2..527f05812 100644 --- a/tests/format/js/arrows-bind/__snapshots__/format.test.js.snap +++ b/tests/format/js/arrows-bind/__snapshots__/format.test.js.snap @@ -30,6 +30,15 @@ exports[`arrows-bind.js [meriyah] format 1`] = ` Cause: [1:8-1:9]: Expected ')'" `; +exports[`arrows-bind.js [oxc] format 1`] = ` +"Expected \`,\` but found \`:\` (1:9) +> 1 | a => ({}::b()\`\`[''].c++ && 0 ? 0 : 0); + | ^ + 2 | (a => b)::c; + 3 | a::(b => c); + 4 |" +`; + exports[`arrows-bind.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/arrows-bind/format.test.js b/tests/format/js/arrows-bind/format.test.js index e59778563..6e1f44b04 100644 --- a/tests/format/js/arrows-bind/format.test.js +++ b/tests/format/js/arrows-bind/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/arrows/newline-before-arrow/__snapshots__/format.test.js.snap b/tests/format/js/arrows/newline-before-arrow/__snapshots__/format.test.js.snap index 308ed7311..a9553bd32 100644 --- a/tests/format/js/arrows/newline-before-arrow/__snapshots__/format.test.js.snap +++ b/tests/format/js/arrows/newline-before-arrow/__snapshots__/format.test.js.snap @@ -27,6 +27,14 @@ exports[`newline-before-arrow.js [meriyah] format 1`] = ` Cause: [2:0-2:2]: No line break is allowed after '=>'" `; +exports[`newline-before-arrow.js [oxc] format 1`] = ` +"Line terminator not permitted before arrow (2:1) + 1 | async x +> 2 | => x + | ^^ + 3 |" +`; + exports[`newline-before-arrow.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/arrows/newline-before-arrow/format.test.js b/tests/format/js/arrows/newline-before-arrow/format.test.js index da90808c6..ac9301599 100644 --- a/tests/format/js/arrows/newline-before-arrow/format.test.js +++ b/tests/format/js/arrows/newline-before-arrow/format.test.js @@ -3,5 +3,6 @@ runFormatTest(import.meta, ["babel"], { acorn: ["newline-before-arrow.js"], espree: ["newline-before-arrow.js"], meriyah: ["newline-before-arrow.js"], + oxc: ["newline-before-arrow.js"], }, }); diff --git a/tests/format/js/async-do-expressions/__snapshots__/format.test.js.snap b/tests/format/js/async-do-expressions/__snapshots__/format.test.js.snap index 6789d9e51..8ac16136d 100644 --- a/tests/format/js/async-do-expressions/__snapshots__/format.test.js.snap +++ b/tests/format/js/async-do-expressions/__snapshots__/format.test.js.snap @@ -30,6 +30,15 @@ exports[`async-do-expressions.js [meriyah] format 1`] = ` Cause: [1:6-1:8]: Unexpected token: 'do'" `; +exports[`async-do-expressions.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:6) +> 1 | async do { + | ^ + 2 | 1; + 3 | }; + 4 |" +`; + exports[`async-do-expressions.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/async-do-expressions/format.test.js b/tests/format/js/async-do-expressions/format.test.js index e59778563..6e1f44b04 100644 --- a/tests/format/js/async-do-expressions/format.test.js +++ b/tests/format/js/async-do-expressions/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/babel-plugins/__snapshots__/format.test.js.snap b/tests/format/js/babel-plugins/__snapshots__/format.test.js.snap index b3b5e40b7..e1a88eeb2 100644 --- a/tests/format/js/babel-plugins/__snapshots__/format.test.js.snap +++ b/tests/format/js/babel-plugins/__snapshots__/format.test.js.snap @@ -24,6 +24,13 @@ exports[`async-do-expressions.js [meriyah] format 1`] = ` Cause: [1:6-1:8]: Unexpected token: 'do'" `; +exports[`async-do-expressions.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:6) +> 1 | async do { await requestAPI().json() }; + | ^ + 2 |" +`; + exports[`async-do-expressions.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -636,6 +643,17 @@ exports[`destructuring-private.js [meriyah] format 1`] = ` Cause: [5:12-5:13]: Unexpected token: 'PrivateField'" `; +exports[`destructuring-private.js [oxc] format 1`] = ` +"Unexpected token (5:13) + 3 | constructor() { + 4 | console.log(this.#x); // => 1 +> 5 | const { #x: x } = this; + | ^^ + 6 | console.log(x); // => 1 + 7 | } + 8 | equals({ #x: otherX }) {" +`; + exports[`destructuring-private.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -708,6 +726,17 @@ exports[`do-expressions.js [meriyah] format 1`] = ` Cause: [3:8-3:10]: Unexpected token: 'do'" `; +exports[`do-expressions.js [oxc] format 1`] = ` +"Unexpected token (3:9) + 1 | // https://babeljs.io/docs/babel-plugin-proposal-do-expressions + 2 | +> 3 | let a = do { + | ^^ + 4 | if(x > 10) { + 5 | 'big'; + 6 | } else {" +`; + exports[`do-expressions.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -869,6 +898,15 @@ exports[`export-default-from.js [meriyah] format 1`] = ` Cause: [4:7-4:8]: Unexpected token: 'identifier'" `; +exports[`export-default-from.js [oxc] format 1`] = ` +"Unexpected token (4:8) + 2 | + 3 | +> 4 | export v from 'mod'; + | ^ + 5 |" +`; + exports[`export-default-from.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -992,6 +1030,15 @@ exports[`flow.js [meriyah] format 1`] = ` Cause: [3:16-3:17]: Expected ')'" `; +exports[`flow.js [oxc] format 1`] = ` +"Expected \`,\` but found \`:\` (3:17) + 1 | // https://babeljs.io/docs/babel-preset-flow + 2 | +> 3 | function foo(one: any, two: number, three?): string {} + | ^ + 4 |" +`; + exports[`function-bind.js [acorn] format 1`] = ` "Unexpected token (3:5) 1 | // https://babeljs.io/docs/babel-plugin-proposal-function-bind @@ -1028,6 +1075,17 @@ exports[`function-bind.js [meriyah] format 1`] = ` Cause: [3:4-3:5]: Unexpected token: ':'" `; +exports[`function-bind.js [oxc] format 1`] = ` +"Unexpected token (3:5) + 1 | // https://babeljs.io/docs/babel-plugin-proposal-function-bind + 2 | +> 3 | obj::func + | ^ + 4 | // is equivalent to: + 5 | func.bind(obj) + 6 |" +`; + exports[`function-bind.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1109,6 +1167,17 @@ exports[`function-sent.js [meriyah] format 1`] = ` Cause: [4:32-4:33]: Expected '('" `; +exports[`function-sent.js [oxc] format 1`] = ` +"Expected \`(\` but found \`.\` (4:33) + 2 | + 3 | function* generator() { +> 4 | console.log("Sent", function.sent); + | ^ + 5 | console.log("Yield", yield); + 6 | } + 7 |" +`; + exports[`function-sent.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1351,6 +1420,15 @@ exports[`module-blocks.js [meriyah] format 1`] = ` Cause: [1:15-1:16]: Unexpected token: '{'" `; +exports[`module-blocks.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:15) +> 1 | let m = module { + | ^ + 2 | export let m = 2; + 3 | export let n = 3; + 4 | };" +`; + exports[`module-blocks.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1720,6 +1798,13 @@ exports[`optional-chaining-assignment.js [meriyah] format 1`] = ` Cause: [1:17-1:18]: Invalid left-hand side in assignment" `; +exports[`optional-chaining-assignment.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:1) +> 1 | maybeAnObj?.prop = theValue; + | ^^^^^^^^^^^^^^^^ + 2 |" +`; + exports[`optional-chaining-assignment.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1770,6 +1855,17 @@ exports[`partial-application.js [meriyah] format 1`] = ` Cause: [5:22-5:23]: Unexpected token: '?'" `; +exports[`partial-application.js [oxc] format 1`] = ` +"Unexpected token (5:23) + 3 | function add(x, y) { return x + y; } + 4 | +> 5 | const addOne = add(1, ?); // apply from the left + | ^ + 6 | addOne(2); // 3 + 7 | + 8 | const addTen = add(?, 10); // apply from the right" +`; + exports[`partial-application.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1860,6 +1956,17 @@ exports[`pipeline-operator-fsharp.js [meriyah] format 1`] = ` Cause: [5:3-5:4]: Unexpected token: '>'" `; +exports[`pipeline-operator-fsharp.js [oxc] format 1`] = ` +"Unexpected token (5:4) + 3 | + 4 | promise +> 5 | |> await + | ^ + 6 | |> x => doubleSay(x, ', ') + 7 | |> capitalize + 8 | |> x => x + '!'" +`; + exports[`pipeline-operator-fsharp.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1971,6 +2078,17 @@ exports[`pipeline-operator-hack.js [meriyah] format 1`] = ` Cause: [5:2-5:3]: Unexpected token: '>'" `; +exports[`pipeline-operator-hack.js [oxc] format 1`] = ` +"Unexpected token (5:3) + 3 | + 4 | return list +> 5 | |> take(prefix.length, %) + | ^ + 6 | |> equals(%, prefix); + 7 | + 8 | // (The % token isn't final; it might instead be @ or ? or #.)" +`; + exports[`pipeline-operator-hack.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -2033,6 +2151,17 @@ exports[`pipeline-operator-minimal.js [meriyah] format 1`] = ` Cause: [8:3-8:4]: Unexpected token: '>'" `; +exports[`pipeline-operator-minimal.js [oxc] format 1`] = ` +"Unexpected token (8:4) + 6 | + 7 | let result = "hello" +> 8 | |> doubleSay + | ^ + 9 | |> capitalize + 10 | |> exclaim; + 11 |" +`; + exports[`pipeline-operator-minimal.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -2346,6 +2475,17 @@ exports[`throw-expressions.js [meriyah] format 1`] = ` Cause: [3:22-3:27]: Unexpected token: 'throw'" `; +exports[`throw-expressions.js [oxc] format 1`] = ` +"Unexpected token (3:23) + 1 | // https://babeljs.io/docs/babel-plugin-proposal-throw-expressions + 2 | +> 3 | function test(param = throw new Error('required!')) { + | ^^^^^ + 4 | const test = param === true || throw new Error('Falsy!'); + 5 | } + 6 |" +`; + exports[`throw-expressions.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -2454,6 +2594,15 @@ exports[`typescript.js [meriyah] format 1`] = ` Cause: [3:7-3:8]: Missing initializer in const declaration" `; +exports[`typescript.js [oxc] format 1`] = ` +"Missing initializer in const declaration (3:7) + 1 | // https://babeljs.io/docs/babel-preset-typescript + 2 | +> 3 | const x: number = 0; + | ^ + 4 |" +`; + exports[`v8intrinsic.js [acorn] format 1`] = ` "Unexpected token (3:1) 1 | // https://github.com/babel/babel/pull/10148 @@ -2490,6 +2639,17 @@ exports[`v8intrinsic.js [meriyah] format 1`] = ` Cause: [3:0-3:1]: Unexpected token: '%'" `; +exports[`v8intrinsic.js [oxc] format 1`] = ` +"Unexpected token (3:1) + 1 | // https://github.com/babel/babel/pull/10148 + 2 | +> 3 | %DebugPrint(foo); + | ^ + 4 | + 5 | + 6 | // Invalid code https://github.com/JLHwung/babel/blob/c1a3cbfd65e08b7013fd6f8c62add8cb10b4b169/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-bind-expression/options.json" +`; + exports[`v8intrinsic.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] diff --git a/tests/format/js/babel-plugins/format.test.js b/tests/format/js/babel-plugins/format.test.js index c9b3dca66..45f46217f 100644 --- a/tests/format/js/babel-plugins/format.test.js +++ b/tests/format/js/babel-plugins/format.test.js @@ -76,6 +76,24 @@ runFormatTest(import.meta, ["babel", "babel-ts", "babel-flow"], { "deferred-import-evaluation.js", "optional-chaining-assignment.js", ], + oxc: [ + "async-do-expressions.js", + "destructuring-private.js", + "do-expressions.js", + "export-default-from.js", + "flow.js", + "function-bind.js", + "function-sent.js", + "module-blocks.js", + "optional-chaining-assignment.js", + "partial-application.js", + "pipeline-operator-fsharp.js", + "pipeline-operator-hack.js", + "pipeline-operator-minimal.js", + "throw-expressions.js", + "typescript.js", + "v8intrinsic.js", + ], babel: ["flow.js", "typescript.js"], __babel_estree: ["flow.js", "typescript.js"], }, diff --git a/tests/format/js/bind-expressions/__snapshots__/format.test.js.snap b/tests/format/js/bind-expressions/__snapshots__/format.test.js.snap index a648eb95b..02da7a260 100644 --- a/tests/format/js/bind-expressions/__snapshots__/format.test.js.snap +++ b/tests/format/js/bind-expressions/__snapshots__/format.test.js.snap @@ -33,6 +33,16 @@ exports[`await.js [meriyah] format 1`] = ` Cause: [3:26-3:27]: Unexpected token: ':'" `; +exports[`await.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (3:27) + 1 | const doBothThings = async () => { + 2 | const request = doAsyncThing(); +> 3 | return (await request)::doSyncThing(); + | ^ + 4 | }; + 5 |" +`; + exports[`await.js - {"semi":false} [acorn] format 1`] = ` "Unexpected token (3:27) 1 | const doBothThings = async () => { @@ -66,6 +76,16 @@ exports[`await.js - {"semi":false} [meriyah] format 1`] = ` Cause: [3:26-3:27]: Unexpected token: ':'" `; +exports[`await.js - {"semi":false} [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (3:27) + 1 | const doBothThings = async () => { + 2 | const request = doAsyncThing(); +> 3 | return (await request)::doSyncThing(); + | ^ + 4 | }; + 5 |" +`; + exports[`await.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -137,6 +157,15 @@ exports[`bind_parens.js [meriyah] format 1`] = ` Cause: [1:8-1:9]: Unexpected token: ':'" `; +exports[`bind_parens.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:9) +> 1 | (a || b)::c; + | ^ + 2 | a || (b::c); + 3 | ::obj.prop; + 4 | (void 0)::func();" +`; + exports[`bind_parens.js - {"semi":false} [acorn] format 1`] = ` "Unexpected token (1:9) > 1 | (a || b)::c; @@ -167,6 +196,15 @@ exports[`bind_parens.js - {"semi":false} [meriyah] format 1`] = ` Cause: [1:8-1:9]: Unexpected token: ':'" `; +exports[`bind_parens.js - {"semi":false} [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:9) +> 1 | (a || b)::c; + | ^ + 2 | a || (b::c); + 3 | ::obj.prop; + 4 | (void 0)::func();" +`; + exports[`bind_parens.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -364,6 +402,17 @@ exports[`long_name_method.js [meriyah] format 1`] = ` Cause: [3:53-3:54]: Unexpected token: ':'" `; +exports[`long_name_method.js [oxc] format 1`] = ` +"Unexpected token (3:54) + 1 | class X { + 2 | constructor() { +> 3 | this.testLongNameMethodAndSomethingElseLallala = ::this.testLongNameMethodAndSomethingElseLallala; + | ^ + 4 | } + 5 | + 6 | testLongNameMethodAndSomethingElseLallala() {" +`; + exports[`long_name_method.js - {"semi":false} [acorn] format 1`] = ` "Unexpected token (3:54) 1 | class X { @@ -400,6 +449,17 @@ exports[`long_name_method.js - {"semi":false} [meriyah] format 1`] = ` Cause: [3:53-3:54]: Unexpected token: ':'" `; +exports[`long_name_method.js - {"semi":false} [oxc] format 1`] = ` +"Unexpected token (3:54) + 1 | class X { + 2 | constructor() { +> 3 | this.testLongNameMethodAndSomethingElseLallala = ::this.testLongNameMethodAndSomethingElseLallala; + | ^ + 4 | } + 5 | + 6 | testLongNameMethodAndSomethingElseLallala() {" +`; + exports[`long_name_method.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -497,6 +557,17 @@ exports[`method_chain.js [meriyah] format 1`] = ` Cause: [10:8-10:9]: Unexpected token: ':'" `; +exports[`method_chain.js [oxc] format 1`] = ` +"Unexpected token (10:9) + 8 | function test(observable) { + 9 | return observable +> 10 | ::filter(data => data.someTest) + | ^ + 11 | ::throttle(() => + 12 | interval(10) + 13 | ::take(1)" +`; + exports[`method_chain.js - {"semi":false} [acorn] format 1`] = ` "Unexpected token (10:9) 8 | function test(observable) { @@ -533,6 +604,17 @@ exports[`method_chain.js - {"semi":false} [meriyah] format 1`] = ` Cause: [10:8-10:9]: Unexpected token: ':'" `; +exports[`method_chain.js - {"semi":false} [oxc] format 1`] = ` +"Unexpected token (10:9) + 8 | function test(observable) { + 9 | return observable +> 10 | ::filter(data => data.someTest) + | ^ + 11 | ::throttle(() => + 12 | interval(10) + 13 | ::take(1)" +`; + exports[`method_chain.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -662,6 +744,17 @@ exports[`short_name_method.js [meriyah] format 1`] = ` Cause: [3:23-3:24]: Unexpected token: ':'" `; +exports[`short_name_method.js [oxc] format 1`] = ` +"Unexpected token (3:24) + 1 | class X { + 2 | constructor() { +> 3 | this.shortMethod = ::this.shortMethod; + | ^ + 4 | } + 5 | + 6 | shortMethod() {" +`; + exports[`short_name_method.js - {"semi":false} [acorn] format 1`] = ` "Unexpected token (3:24) 1 | class X { @@ -698,6 +791,17 @@ exports[`short_name_method.js - {"semi":false} [meriyah] format 1`] = ` Cause: [3:23-3:24]: Unexpected token: ':'" `; +exports[`short_name_method.js - {"semi":false} [oxc] format 1`] = ` +"Unexpected token (3:24) + 1 | class X { + 2 | constructor() { +> 3 | this.shortMethod = ::this.shortMethod; + | ^ + 4 | } + 5 | + 6 | shortMethod() {" +`; + exports[`short_name_method.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -787,6 +891,15 @@ exports[`unary.js [meriyah] format 1`] = ` Cause: [1:2-1:3]: Unexpected token: ':'" `; +exports[`unary.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:3) +> 1 | !x::y; + | ^ + 2 | !(x::y /* foo */); + 3 | !(/* foo */ x::y); + 4 | !(" +`; + exports[`unary.js - {"semi":false} [acorn] format 1`] = ` "Unexpected token (1:3) > 1 | !x::y; @@ -817,6 +930,15 @@ exports[`unary.js - {"semi":false} [meriyah] format 1`] = ` Cause: [1:2-1:3]: Unexpected token: ':'" `; +exports[`unary.js - {"semi":false} [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:3) +> 1 | !x::y; + | ^ + 2 | !(x::y /* foo */); + 3 | !(/* foo */ x::y); + 4 | !(" +`; + exports[`unary.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/bind-expressions/format.test.js b/tests/format/js/bind-expressions/format.test.js index 527ee9a76..d2a87850b 100644 --- a/tests/format/js/bind-expressions/format.test.js +++ b/tests/format/js/bind-expressions/format.test.js @@ -1,7 +1,7 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); runFormatTest(import.meta, ["babel"], { semi: false, - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/call/invalid/__snapshots__/format.test.js.snap b/tests/format/js/call/invalid/__snapshots__/format.test.js.snap index 8f81c90fe..94d714d58 100644 --- a/tests/format/js/call/invalid/__snapshots__/format.test.js.snap +++ b/tests/format/js/call/invalid/__snapshots__/format.test.js.snap @@ -49,3 +49,12 @@ exports[`null-arguments-item.js [meriyah] format 1`] = ` 4 | //1 Cause: [1:10-1:11]: Unexpected token: ','" `; + +exports[`null-arguments-item.js [oxc] format 1`] = ` +"Unexpected token (1:11) +> 1 | foor('a', , 'b'); + | ^ + 2 | foo('looooooooooooooooooooooooooooooooooooooooooooooong', , 'looooooooooooooooooooooooooooooooooooooooooooooong'); + 3 | foo("a", + 4 | //1" +`; diff --git a/tests/format/js/call/invalid/format.test.js b/tests/format/js/call/invalid/format.test.js index 60815cda9..3e782ee1c 100644 --- a/tests/format/js/call/invalid/format.test.js +++ b/tests/format/js/call/invalid/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { acorn: true, espree: true, meriyah: true, + oxc: true, }, }); diff --git a/tests/format/js/comments-pipeline-own-line/__snapshots__/format.test.js.snap b/tests/format/js/comments-pipeline-own-line/__snapshots__/format.test.js.snap index 549d61af6..0746fc55c 100644 --- a/tests/format/js/comments-pipeline-own-line/__snapshots__/format.test.js.snap +++ b/tests/format/js/comments-pipeline-own-line/__snapshots__/format.test.js.snap @@ -36,6 +36,17 @@ exports[`pipeline_own_line.js [meriyah] format 1`] = ` Cause: [4:2-4:3]: Unexpected token: '>'" `; +exports[`pipeline_own_line.js [oxc] format 1`] = ` +"Unexpected token (4:3) + 2 | 0 + 3 | // Comment +> 4 | |> x + | ^ + 5 | } + 6 | + 7 | bifornCringerMoshedPerplexSawder(" +`; + exports[`pipeline_own_line.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/comments-pipeline-own-line/format.test.js b/tests/format/js/comments-pipeline-own-line/format.test.js index e59778563..6e1f44b04 100644 --- a/tests/format/js/comments-pipeline-own-line/format.test.js +++ b/tests/format/js/comments-pipeline-own-line/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/deferred-import-evaluation/__snapshots__/format.test.js.snap b/tests/format/js/deferred-import-evaluation/__snapshots__/format.test.js.snap index 6b13f6eac..af97d294d 100644 --- a/tests/format/js/deferred-import-evaluation/__snapshots__/format.test.js.snap +++ b/tests/format/js/deferred-import-evaluation/__snapshots__/format.test.js.snap @@ -192,6 +192,13 @@ exports[`no-default.js [meriyah] format 1`] = ` Cause: [1:13-1:14]: Expected 'from'" `; +exports[`no-default.js [oxc] format 1`] = ` +"Expected \`from\` but found \`Identifier\` (1:14) +> 1 | import defer x from "x"; + | ^ + 2 |" +`; + exports[`no-named.js [__babel_estree] format 1`] = ` "Only \`import defer * as x from "./module"\` is valid. (1:16) > 1 | import defer { x } from "x"; @@ -231,3 +238,10 @@ exports[`no-named.js [meriyah] format 1`] = ` 2 | Cause: [1:13-1:14]: Expected 'from'" `; + +exports[`no-named.js [oxc] format 1`] = ` +"Expected \`from\` but found \`{\` (1:14) +> 1 | import defer { x } from "x"; + | ^ + 2 |" +`; diff --git a/tests/format/js/deferred-import-evaluation/format.test.js b/tests/format/js/deferred-import-evaluation/format.test.js index ae71ea629..b785d5d78 100644 --- a/tests/format/js/deferred-import-evaluation/format.test.js +++ b/tests/format/js/deferred-import-evaluation/format.test.js @@ -11,6 +11,7 @@ runFormatTest(import.meta, ["babel"], { acorn: [...importDeferTests, ...invalidSyntaxTests], espree: [...importDeferTests, ...invalidSyntaxTests], meriyah: [...importDeferTests, ...invalidSyntaxTests], + oxc: invalidSyntaxTests, babel: invalidSyntaxTests, __babel_estree: invalidSyntaxTests, }, diff --git a/tests/format/js/destructuring-private-fields/__snapshots__/format.test.js.snap b/tests/format/js/destructuring-private-fields/__snapshots__/format.test.js.snap index 1981c93e8..4cacd4191 100644 --- a/tests/format/js/destructuring-private-fields/__snapshots__/format.test.js.snap +++ b/tests/format/js/destructuring-private-fields/__snapshots__/format.test.js.snap @@ -33,6 +33,16 @@ exports[`arrow-params.js [meriyah] format 1`] = ` Cause: [3:10-3:11]: Unexpected token: 'PrivateField'" `; +exports[`arrow-params.js [oxc] format 1`] = ` +"Unexpected token (3:11) + 1 | class C { + 2 | #x = 1; +> 3 | #p = ({ #x: x }) => {} + | ^^ + 4 | } + 5 |" +`; + exports[`arrow-params.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -89,6 +99,17 @@ exports[`assignment.js [meriyah] format 1`] = ` Cause: [5:7-5:8]: Unexpected token: 'PrivateField'" `; +exports[`assignment.js [oxc] format 1`] = ` +"Unexpected token (5:8) + 3 | m() { + 4 | let x; +> 5 | ({ #x: x } = this); + | ^^ + 6 | } + 7 | } + 8 |" +`; + exports[`assignment.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -148,6 +169,16 @@ exports[`async-arrow-params.js [meriyah] format 1`] = ` Cause: [3:16-3:17]: Unexpected token: 'PrivateField'" `; +exports[`async-arrow-params.js [oxc] format 1`] = ` +"Unexpected token (3:17) + 1 | class C { + 2 | #x = 1; +> 3 | #p = async ({ #x: x }) => {} + | ^^ + 4 | } + 5 |" +`; + exports[`async-arrow-params.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -204,6 +235,17 @@ exports[`bindings.js [meriyah] format 1`] = ` Cause: [4:11-4:12]: Unexpected token: 'PrivateField'" `; +exports[`bindings.js [oxc] format 1`] = ` +"Unexpected token (4:12) + 2 | #x = 1; + 3 | m() { +> 4 | const {#x: x} = this; + | ^^ + 5 | } + 6 | } + 7 |" +`; + exports[`bindings.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -264,6 +306,17 @@ exports[`for-lhs.js [meriyah] format 1`] = ` Cause: [5:10-5:11]: Unexpected token: 'PrivateField'" `; +exports[`for-lhs.js [oxc] format 1`] = ` +"Unexpected token (5:11) + 3 | m() { + 4 | let x; +> 5 | for ({#x: x} of [this]); + | ^^ + 6 | } + 7 | } + 8 |" +`; + exports[`for-lhs.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -326,6 +379,17 @@ exports[`nested-bindings.js [meriyah] format 1`] = ` Cause: [4:16-4:17]: Unexpected token: 'PrivateField'" `; +exports[`nested-bindings.js [oxc] format 1`] = ` +"Unexpected token (4:17) + 2 | #x = 1; + 3 | m() { +> 4 | const {x: { #x: [x] }, y: [...{ #x: y }]} = this; + | ^^ + 5 | } + 6 | } + 7 |" +`; + exports[`nested-bindings.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -391,6 +455,17 @@ exports[`valid-multiple-bindings.js [meriyah] format 1`] = ` Cause: [4:11-4:12]: Unexpected token: 'PrivateField'" `; +exports[`valid-multiple-bindings.js [oxc] format 1`] = ` +"Unexpected token (4:12) + 2 | #x = 1; + 3 | m() { +> 4 | const {#x: x1, #x: x2 = x1 } = this; + | ^^ + 5 | } + 6 | } + 7 |" +`; + exports[`valid-multiple-bindings.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] diff --git a/tests/format/js/destructuring-private-fields/format.test.js b/tests/format/js/destructuring-private-fields/format.test.js index f7d424cd9..0d936213d 100644 --- a/tests/format/js/destructuring-private-fields/format.test.js +++ b/tests/format/js/destructuring-private-fields/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel", "babel-flow", "babel-ts"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/do/__snapshots__/format.test.js.snap b/tests/format/js/do/__snapshots__/format.test.js.snap index f4dcf6cb2..8d98614ba 100644 --- a/tests/format/js/do/__snapshots__/format.test.js.snap +++ b/tests/format/js/do/__snapshots__/format.test.js.snap @@ -36,6 +36,17 @@ exports[`call-arguments.js [meriyah] format 1`] = ` Cause: [3:2-3:4]: Unexpected token: 'do'" `; +exports[`call-arguments.js [oxc] format 1`] = ` +"Unexpected token (3:3) + 1 | // from https://github.com/babel/babel/pull/13122/ + 2 | expect( +> 3 | do { + | ^^ + 4 | var bar = "foo"; + 5 | if (!bar) throw new Error( + 6 | "unreachable"" +`; + exports[`call-arguments.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -158,6 +169,17 @@ exports[`do.js [meriyah] format 1`] = ` Cause: [3:4-3:6]: Unexpected token: 'do'" `; +exports[`do.js [oxc] format 1`] = ` +"Unexpected token (3:5) + 1 | const envSpecific = { + 2 | domain: +> 3 | do { + | ^^ + 4 | if(env === 'production') 'https://abc.mno.com/'; + 5 | else if(env === 'development') 'http://localhost:4000'; + 6 | }" +`; + exports[`do.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/do/format.test.js b/tests/format/js/do/format.test.js index e59778563..6e1f44b04 100644 --- a/tests/format/js/do/format.test.js +++ b/tests/format/js/do/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/explicit-resource-management/__snapshots__/format.test.js.snap b/tests/format/js/explicit-resource-management/__snapshots__/format.test.js.snap index dcfdd3133..3ca3e8556 100644 --- a/tests/format/js/explicit-resource-management/__snapshots__/format.test.js.snap +++ b/tests/format/js/explicit-resource-management/__snapshots__/format.test.js.snap @@ -857,6 +857,15 @@ exports[`valid-module-block-top-level-await-using-binding.js [meriyah] format 1` Cause: [1:17-1:18]: Unexpected token: '{'" `; +exports[`valid-module-block-top-level-await-using-binding.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:17) +> 1 | const m = module { + | ^ + 2 | await using foo = bar(); + 3 | } + 4 |" +`; + exports[`valid-module-block-top-level-await-using-binding.js [typescript] format 1`] = ` "',' expected. (1:18) > 1 | const m = module { @@ -924,6 +933,15 @@ exports[`valid-module-block-top-level-using-binding.js [meriyah] format 1`] = ` Cause: [1:7-1:8]: Unexpected token: '{'" `; +exports[`valid-module-block-top-level-using-binding.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:7) +> 1 | module { + | ^ + 2 | using foo = bar(); + 3 | } + 4 |" +`; + exports[`valid-module-block-top-level-using-binding.js [typescript] format 1`] = ` "Namespace must be given a name. (1:8) > 1 | module { @@ -1269,6 +1287,16 @@ exports[`valid-using-binding-using.js [meriyah] format 1`] = ` Cause: [2:8-2:13]: Unexpected token: 'identifier'" `; +exports[`valid-using-binding-using.js [oxc] format 1`] = ` +"Expected \`;\` but found \`using\` (3:14) + 1 | { + 2 | using using = of; +> 3 | for (using using of of); + | ^^^^^ + 4 | } + 5 |" +`; + exports[`valid-using-binding-using.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] diff --git a/tests/format/js/explicit-resource-management/format.test.js b/tests/format/js/explicit-resource-management/format.test.js index 1eb54cb79..a8efc9848 100644 --- a/tests/format/js/explicit-resource-management/format.test.js +++ b/tests/format/js/explicit-resource-management/format.test.js @@ -103,5 +103,13 @@ runFormatTest(import.meta, ["babel", "flow", "typescript"], { "valid-for-using-declaration.js", "valid-module-block-top-level-await-using-binding.js", ], + oxc: [ + // "invalid-duplicate-using-bindings.js", + // "invalid-script-top-level-using-binding.js", + "valid-module-block-top-level-using-binding.js", + "valid-module-block-top-level-await-using-binding.js", + + "valid-using-binding-using.js", + ], }, }); diff --git a/tests/format/js/export-default/escaped/__snapshots__/format.test.js.snap b/tests/format/js/export-default/escaped/__snapshots__/format.test.js.snap index 6a0b488ba..80575a568 100644 --- a/tests/format/js/export-default/escaped/__snapshots__/format.test.js.snap +++ b/tests/format/js/export-default/escaped/__snapshots__/format.test.js.snap @@ -31,6 +31,13 @@ exports[`default-escaped.js [meriyah] format 1`] = ` Cause: [2:7-2:12]: Unexpected token: 'identifier'" `; +exports[`default-escaped.js [oxc] format 1`] = ` +"Unexpected token (2:8) + 1 | // export asyn\\u{63} from "async"; +> 2 | export n\\u{63} from "async"; + | ^^^^^^^" +`; + exports[`default-escaped.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow"] diff --git a/tests/format/js/export-default/escaped/format.test.js b/tests/format/js/export-default/escaped/format.test.js index 769aa912d..578b9300a 100644 --- a/tests/format/js/export-default/escaped/format.test.js +++ b/tests/format/js/export-default/escaped/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel", "flow"], { - errors: { acorn: true, espree: true, meriyah: true, flow: true }, + errors: { acorn: true, espree: true, meriyah: true, flow: true, oxc: true }, }); diff --git a/tests/format/js/export-default/export-default-from/__snapshots__/format.test.js.snap b/tests/format/js/export-default/export-default-from/__snapshots__/format.test.js.snap index 723aed7bc..7841a6ffa 100644 --- a/tests/format/js/export-default/export-default-from/__snapshots__/format.test.js.snap +++ b/tests/format/js/export-default/export-default-from/__snapshots__/format.test.js.snap @@ -33,6 +33,16 @@ exports[`export.js [meriyah] format 1`] = ` Cause: [2:7-2:8]: Unexpected token: 'identifier'" `; +exports[`export.js [oxc] format 1`] = ` +"Unexpected token (2:8) + 1 | export * as ns from 'mod'; +> 2 | export v from 'mod'; + | ^ + 3 | export a, * as b from 'mod'; + 4 | export c, { foo } from 'mod'; + 5 | export * as d from 'mod';" +`; + exports[`export.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/export-default/export-default-from/format.test.js b/tests/format/js/export-default/export-default-from/format.test.js index e59778563..6e1f44b04 100644 --- a/tests/format/js/export-default/export-default-from/format.test.js +++ b/tests/format/js/export-default/export-default-from/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/module-blocks/__snapshots__/format.test.js.snap b/tests/format/js/module-blocks/__snapshots__/format.test.js.snap index edd263632..5b5963e50 100644 --- a/tests/format/js/module-blocks/__snapshots__/format.test.js.snap +++ b/tests/format/js/module-blocks/__snapshots__/format.test.js.snap @@ -30,6 +30,15 @@ exports[`comments.js [meriyah] format 1`] = ` Cause: [1:31-1:32]: Unexpected token: '{'" `; +exports[`comments.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:24) +> 1 | const m = /*A1*/ module /*A2*/ { /*A3*/ + | ^ + 2 | /*A4*/ + 3 | export const foo = "foo"; + 4 | export { foo }; /*A5*/" +`; + exports[`comments.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -93,6 +102,15 @@ exports[`module-blocks.js [meriyah] format 1`] = ` Cause: [1:7-1:8]: Unexpected token: '{'" `; +exports[`module-blocks.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:7) +> 1 | module { await 3 }; + | ^ + 2 | + 3 | class B { + 4 | #p() {" +`; + exports[`module-blocks.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -240,6 +258,15 @@ exports[`range.js [meriyah] format 1`] = ` Cause: [1:25-1:26]: Unexpected token: '{'" `; +exports[`range.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:25) +> 1 | let moduleBlock = module { export let y = 1; + | ^ + 2 | }; + 3 | + 4 | foo(module { export let foo = "foo"; })" +`; + exports[`range.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -299,6 +326,15 @@ exports[`worker.js [meriyah] format 1`] = ` Cause: [1:31-1:32]: Expected ')'" `; +exports[`worker.js [oxc] format 1`] = ` +"Expected \`,\` but found \`{\` (1:32) +> 1 | let worker = new Worker(module { + | ^ + 2 | onmessage = function({data}) { + 3 | let mod = import(data); + 4 | postMessage(mod.fn());" +`; + exports[`worker.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/module-blocks/format.test.js b/tests/format/js/module-blocks/format.test.js index 0914dc9aa..fadaccdf8 100644 --- a/tests/format/js/module-blocks/format.test.js +++ b/tests/format/js/module-blocks/format.test.js @@ -3,5 +3,6 @@ runFormatTest(import.meta, ["babel"], { acorn: ["module-blocks.js", "range.js", "comments.js", "worker.js"], espree: ["module-blocks.js", "range.js", "comments.js", "worker.js"], meriyah: ["module-blocks.js", "range.js", "comments.js", "worker.js"], + oxc: ["module-blocks.js", "range.js", "comments.js", "worker.js"], }, }); diff --git a/tests/format/js/multiparser-invalid/__snapshots__/format.test.js.snap b/tests/format/js/multiparser-invalid/__snapshots__/format.test.js.snap index 039e53fa7..85c29a5cc 100644 --- a/tests/format/js/multiparser-invalid/__snapshots__/format.test.js.snap +++ b/tests/format/js/multiparser-invalid/__snapshots__/format.test.js.snap @@ -45,6 +45,17 @@ exports[`text.js [meriyah] format 1`] = ` Cause: [6:16-6:20]: Invalid hexadecimal escape sequence" `; +exports[`text.js [oxc] format 1`] = ` +"Bad escape sequence in untagged template literal (6:18) + 4 | foo = markdown\`\\u{prettier}\\u{0065}\`; + 5 | foo = css\`\\u{prettier}\\u{0065}\`; +> 6 | foo = /* HTML */\`\\u{prettier}\\u{0065}\`; + | ^^^^^^^^^^^^^^^^^^^^ + 7 | foo = /* GraphQL */\`\\u{prettier}\\u{0065}\`; + 8 | + 9 | foo = foo\`\\u{prettier}\${foo}pr\\u{0065}ttier\`;" +`; + exports[`text.js [typescript] format 1`] = ` "Hexadecimal digit expected. (6:21) 4 | foo = markdown\`\\u{prettier}\\u{0065}\`; diff --git a/tests/format/js/multiparser-invalid/format.test.js b/tests/format/js/multiparser-invalid/format.test.js index e2d1c08e8..07531592d 100644 --- a/tests/format/js/multiparser-invalid/format.test.js +++ b/tests/format/js/multiparser-invalid/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel", "flow", "typescript"], { flow: true, typescript: true, meriyah: true, + oxc: true, }, }); diff --git a/tests/format/js/no-semi-babylon-extensions/__snapshots__/format.test.js.snap b/tests/format/js/no-semi-babylon-extensions/__snapshots__/format.test.js.snap index a3f87b20e..697933a95 100644 --- a/tests/format/js/no-semi-babylon-extensions/__snapshots__/format.test.js.snap +++ b/tests/format/js/no-semi-babylon-extensions/__snapshots__/format.test.js.snap @@ -33,6 +33,16 @@ exports[`no-semi.js [meriyah] format 1`] = ` Cause: [2:1-2:2]: Unexpected token: ':'" `; +exports[`no-semi.js [oxc] format 1`] = ` +"Unexpected token (2:2) + 1 | a +> 2 | ;::b.c + | ^ + 3 | + 4 | class A { + 5 | a = b;" +`; + exports[`no-semi.js - {"semi":false} [acorn] format 1`] = ` "Unexpected token (2:2) 1 | a @@ -66,6 +76,16 @@ exports[`no-semi.js - {"semi":false} [meriyah] format 1`] = ` Cause: [2:1-2:2]: Unexpected token: ':'" `; +exports[`no-semi.js - {"semi":false} [oxc] format 1`] = ` +"Unexpected token (2:2) + 1 | a +> 2 | ;::b.c + | ^ + 3 | + 4 | class A { + 5 | a = b;" +`; + exports[`no-semi.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/no-semi-babylon-extensions/format.test.js b/tests/format/js/no-semi-babylon-extensions/format.test.js index 527ee9a76..d2a87850b 100644 --- a/tests/format/js/no-semi-babylon-extensions/format.test.js +++ b/tests/format/js/no-semi-babylon-extensions/format.test.js @@ -1,7 +1,7 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); runFormatTest(import.meta, ["babel"], { semi: false, - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/objects/__snapshots__/format.test.js.snap b/tests/format/js/objects/__snapshots__/format.test.js.snap index 89f212811..d021a3ff4 100644 --- a/tests/format/js/objects/__snapshots__/format.test.js.snap +++ b/tests/format/js/objects/__snapshots__/format.test.js.snap @@ -117,6 +117,17 @@ exports[`expression.js [meriyah] format 1`] = ` Cause: [5:3-5:4]: Expected ')'" `; +exports[`expression.js [oxc] format 1`] = ` +"Expected \`,\` but found \`:\` (5:4) + 3 | a = () => ({}).x; + 4 | ({} && a, b); +> 5 | ({}::b, 0); + | ^ + 6 | ({}::b()\`\`[''].c++ && 0 ? 0 : 0, 0); + 7 | ({}(), 0); + 8 | ({} = 0);" +`; + exports[`expression.js [typescript] format 1`] = ` "')' expected. (5:4) 3 | a = () => ({}).x; diff --git a/tests/format/js/objects/format.test.js b/tests/format/js/objects/format.test.js index 76f97b8c7..c32eeca47 100644 --- a/tests/format/js/objects/format.test.js +++ b/tests/format/js/objects/format.test.js @@ -4,6 +4,7 @@ runFormatTest(import.meta, ["babel", "typescript", "flow"], { espree: ["expression.js"], typescript: ["expression.js"], meriyah: ["expression.js"], + oxc: ["expression.js"], flow: ["expression.js"], }, }); diff --git a/tests/format/js/optional-chaining-assignment/__snapshots__/format.test.js.snap b/tests/format/js/optional-chaining-assignment/__snapshots__/format.test.js.snap index 3d2d45c7a..c3682891d 100644 --- a/tests/format/js/optional-chaining-assignment/__snapshots__/format.test.js.snap +++ b/tests/format/js/optional-chaining-assignment/__snapshots__/format.test.js.snap @@ -40,6 +40,13 @@ exports[`invalid-destructuring-arr.js [meriyah] format 1`] = ` Cause: [1:9-1:10]: Invalid left-hand side in assignment" `; +exports[`invalid-destructuring-arr.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:2) +> 1 | [a?.b] = []; + | ^^^^ + 2 |" +`; + exports[`invalid-destructuring-obj.js [__babel_estree] format 1`] = ` "Invalid optional chaining in the left-hand side of object destructuring pattern. (1:10) > 1 | ({ prop: a?.b } = {}); @@ -80,6 +87,13 @@ exports[`invalid-destructuring-obj.js [meriyah] format 1`] = ` Cause: [1:18-1:19]: Invalid left-hand side in assignment" `; +exports[`invalid-destructuring-obj.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:10) +> 1 | ({ prop: a?.b } = {}); + | ^^^^ + 2 |" +`; + exports[`invalid-fn-param.js [__babel_estree] format 1`] = ` "Unexpected token, expected "," (1:13) > 1 | function f(a?.b) {} @@ -120,6 +134,13 @@ exports[`invalid-fn-param.js [meriyah] format 1`] = ` Cause: [1:12-1:14]: Expected ')'" `; +exports[`invalid-fn-param.js [oxc] format 1`] = ` +"Expected \`,\` but found \`?.\` (1:13) +> 1 | function f(a?.b) {} + | ^^ + 2 |" +`; + exports[`invalid-fn-param-arrow.js [__babel_estree] format 1`] = ` "Invalid optional chaining in the left-hand side of function parameter list. (1:2) > 1 | (a?.b) => {} @@ -160,6 +181,13 @@ exports[`invalid-fn-param-arrow.js [meriyah] format 1`] = ` Cause: [1:7-1:9]: The left-hand side of the arrow can only be destructed through assignment" `; +exports[`invalid-fn-param-arrow.js [oxc] format 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found none (1:7) +> 1 | (a?.b) => {} + | ^ + 2 |" +`; + exports[`invalid-fn-param-assign.js [__babel_estree] format 1`] = ` "Unexpected token, expected "," (1:13) > 1 | function f(a?.b = c) {} @@ -200,6 +228,13 @@ exports[`invalid-fn-param-assign.js [meriyah] format 1`] = ` Cause: [1:12-1:14]: Expected ')'" `; +exports[`invalid-fn-param-assign.js [oxc] format 1`] = ` +"Expected \`,\` but found \`?.\` (1:13) +> 1 | function f(a?.b = c) {} + | ^^ + 2 |" +`; + exports[`invalid-for-await-of.js [__babel_estree] format 1`] = ` "Invalid optional chaining in the left-hand side of for-of statement. (1:6) > 1 | for (a?.b of x); @@ -240,6 +275,13 @@ exports[`invalid-for-await-of.js [meriyah] format 1`] = ` Cause: [1:10-1:12]: Invalid left-hand side in for-of" `; +exports[`invalid-for-await-of.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:6) +> 1 | for (a?.b of x); + | ^^^^ + 2 |" +`; + exports[`invalid-for-in.js [__babel_estree] format 1`] = ` "Invalid optional chaining in the left-hand side of for-in statement. (1:6) > 1 | for (a?.b in x); @@ -280,6 +322,13 @@ exports[`invalid-for-in.js [meriyah] format 1`] = ` Cause: [1:10-1:12]: Invalid left-hand side in for-in" `; +exports[`invalid-for-in.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:6) +> 1 | for (a?.b in x); + | ^^^^ + 2 |" +`; + exports[`invalid-for-of.js [__babel_estree] format 1`] = ` "Invalid optional chaining in the left-hand side of for-of statement. (1:6) > 1 | for (a?.b of x); @@ -320,6 +369,13 @@ exports[`invalid-for-of.js [meriyah] format 1`] = ` Cause: [1:10-1:12]: Invalid left-hand side in for-of" `; +exports[`invalid-for-of.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:6) +> 1 | for (a?.b of x); + | ^^^^ + 2 |" +`; + exports[`invalid-inc-postfix.js [__babel_estree] format 1`] = ` "Invalid optional chaining in the left-hand side of postfix operation. (1:1) > 1 | a?.b++; @@ -360,6 +416,13 @@ exports[`invalid-inc-postfix.js [meriyah] format 1`] = ` Cause: [1:4-1:6]: Invalid increment/decrement operand" `; +exports[`invalid-inc-postfix.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:1) +> 1 | a?.b++; + | ^^^^ + 2 |" +`; + exports[`invalid-inc-prefix.js [__babel_estree] format 1`] = ` "Invalid optional chaining in the left-hand side of prefix operation. (1:3) > 1 | ++a?.b; @@ -400,6 +463,13 @@ exports[`invalid-inc-prefix.js [meriyah] format 1`] = ` Cause: [1:6-1:7]: Invalid increment/decrement operand" `; +exports[`invalid-inc-prefix.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:3) +> 1 | ++a?.b; + | ^^^^ + 2 |" +`; + exports[`valid-complex-case.js [acorn] format 1`] = ` "The keyword 'let' is reserved (1:1) > 1 | let?.()[a] =1; @@ -427,6 +497,14 @@ exports[`valid-complex-case.js [meriyah] format 1`] = ` Cause: [1:3-1:5]: \`let\` declaration not allowed here and \`let\` cannot be a regular var name in strict mode" `; +exports[`valid-complex-case.js [oxc] format 1`] = ` +"Unexpected token (1:4) +> 1 | let?.()[a] =1; + | ^^ + 2 | let?.[a] = 1; + 3 |" +`; + exports[`valid-complex-case.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -459,6 +537,13 @@ exports[`valid-lhs-eq.js [espree] format 1`] = ` Cause: Optional chaining cannot appear in left-hand side" `; +exports[`valid-lhs-eq.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:1) +> 1 | a?.b.c = d; + | ^^^^^^ + 2 |" +`; + exports[`valid-lhs-eq.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -489,6 +574,13 @@ exports[`valid-lhs-plus-eq.js [espree] format 1`] = ` Cause: Optional chaining cannot appear in left-hand side" `; +exports[`valid-lhs-plus-eq.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:1) +> 1 | a?.b.c += d; + | ^^^^^^ + 2 |" +`; + exports[`valid-lhs-plus-eq.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -527,6 +619,13 @@ exports[`valid-parenthesized.js [meriyah] format 1`] = ` Cause: [1:7-1:8]: Invalid left-hand side in assignment" `; +exports[`valid-parenthesized.js [oxc] format 1`] = ` +"Cannot assign to this expression (1:2) +> 1 | (a?.b) = c; + | ^^^^ + 2 |" +`; + exports[`valid-parenthesized.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/optional-chaining-assignment/format.test.js b/tests/format/js/optional-chaining-assignment/format.test.js index 2820f6f5d..482d909d6 100644 --- a/tests/format/js/optional-chaining-assignment/format.test.js +++ b/tests/format/js/optional-chaining-assignment/format.test.js @@ -31,6 +31,7 @@ runFormatTest(import.meta, ["babel"], { ), ...invalidSyntaxTests, ], + oxc: [...optionalChainingAssignTests, ...invalidSyntaxTests], babel: invalidSyntaxTests, __babel_estree: invalidSyntaxTests, }, diff --git a/tests/format/js/partial-application/__snapshots__/format.test.js.snap b/tests/format/js/partial-application/__snapshots__/format.test.js.snap index 54c068119..45211b452 100644 --- a/tests/format/js/partial-application/__snapshots__/format.test.js.snap +++ b/tests/format/js/partial-application/__snapshots__/format.test.js.snap @@ -30,6 +30,15 @@ exports[`test.js [meriyah] format 1`] = ` Cause: [1:22-1:23]: Unexpected token: '?'" `; +exports[`test.js [oxc] format 1`] = ` +"Unexpected token (1:23) +> 1 | const addOne = add(1, ?); // apply from the left + | ^ + 2 | addOne(2); // 3 + 3 | + 4 | const addTen = add(?, 10); // apply from the right" +`; + exports[`test.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/partial-application/format.test.js b/tests/format/js/partial-application/format.test.js index e59778563..6e1f44b04 100644 --- a/tests/format/js/partial-application/format.test.js +++ b/tests/format/js/partial-application/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/pipeline-operator/__snapshots__/format.test.js.snap b/tests/format/js/pipeline-operator/__snapshots__/format.test.js.snap index 5e8cf580c..4f8240a37 100644 --- a/tests/format/js/pipeline-operator/__snapshots__/format.test.js.snap +++ b/tests/format/js/pipeline-operator/__snapshots__/format.test.js.snap @@ -33,6 +33,16 @@ exports[`block-comments.js [meriyah] format 1`] = ` Cause: [2:1-2:2]: Unexpected token: '>'" `; +exports[`block-comments.js [oxc] format 1`] = ` +"Unexpected token (2:2) + 1 | bifornCringerMoshedPerplexSawder +> 2 | |> foo1 + | ^ + 3 | |> foo2 /* comment1 */ + 4 | |> foo3 /* comment2 */ + 5 | |> kochabCooieGameOnOboleUnweave" +`; + exports[`block-comments.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -90,6 +100,16 @@ exports[`fsharp_style_pipeline_operator.js [meriyah] format 1`] = ` Cause: [2:3-2:4]: Unexpected token: '>'" `; +exports[`fsharp_style_pipeline_operator.js [oxc] format 1`] = ` +"Unexpected token (2:4) + 1 | promise +> 2 | |> await + | ^ + 3 | |> x => doubleSay(x, ', ') + 4 | |> capitalize + 5 | |> x => x + '!'" +`; + exports[`fsharp_style_pipeline_operator.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -215,6 +235,15 @@ exports[`hack_pipeline_operator.js [meriyah] format 1`] = ` Cause: [1:3-1:4]: Unexpected token: '>'" `; +exports[`hack_pipeline_operator.js [oxc] format 1`] = ` +"Unexpected token (1:4) +> 1 | a |> await % |> % * 3; + | ^ + 2 | + 3 | foo + 4 | |> await %" +`; + exports[`hack_pipeline_operator.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -359,6 +388,15 @@ exports[`minimal_pipeline_operator.js [meriyah] format 1`] = ` Cause: [1:3-1:4]: Unexpected token: '>'" `; +exports[`minimal_pipeline_operator.js [oxc] format 1`] = ` +"Unexpected token (1:4) +> 1 | a |> b |> c; + | ^ + 2 | + 3 | a |> (b |> c); + 4 |" +`; + exports[`minimal_pipeline_operator.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/pipeline-operator/format.test.js b/tests/format/js/pipeline-operator/format.test.js index e59778563..6e1f44b04 100644 --- a/tests/format/js/pipeline-operator/format.test.js +++ b/tests/format/js/pipeline-operator/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/source-phase-imports/__snapshots__/format.test.js.snap b/tests/format/js/source-phase-imports/__snapshots__/format.test.js.snap index 6907e1c75..18b7ac2c4 100644 --- a/tests/format/js/source-phase-imports/__snapshots__/format.test.js.snap +++ b/tests/format/js/source-phase-imports/__snapshots__/format.test.js.snap @@ -282,6 +282,13 @@ exports[`no-named.js [meriyah] format 1`] = ` Cause: [1:14-1:15]: Expected 'from'" `; +exports[`no-named.js [oxc] format 1`] = ` +"Expected \`from\` but found \`{\` (1:15) +> 1 | import source { x } from "x"; + | ^ + 2 |" +`; + exports[`no-namespace.js [__babel_estree] format 1`] = ` "Only \`import source x from "./module"\` is valid. (1:15) > 1 | import source * as x from "x"; @@ -321,3 +328,10 @@ exports[`no-namespace.js [meriyah] format 1`] = ` 2 | Cause: [1:14-1:15]: Expected 'from'" `; + +exports[`no-namespace.js [oxc] format 1`] = ` +"Expected \`from\` but found \`*\` (1:15) +> 1 | import source * as x from "x"; + | ^ + 2 |" +`; diff --git a/tests/format/js/source-phase-imports/format.test.js b/tests/format/js/source-phase-imports/format.test.js index 16289150f..512abb2ad 100644 --- a/tests/format/js/source-phase-imports/format.test.js +++ b/tests/format/js/source-phase-imports/format.test.js @@ -13,6 +13,7 @@ runFormatTest(import.meta, ["babel"], { acorn: [...importSourceTests, ...invalidSyntaxTests], espree: [...importSourceTests, ...invalidSyntaxTests], meriyah: [...importSourceTests, ...invalidSyntaxTests], + oxc: invalidSyntaxTests, babel: invalidSyntaxTests, __babel_estree: invalidSyntaxTests, }, diff --git a/tests/format/js/throw_expressions/__snapshots__/format.test.js.snap b/tests/format/js/throw_expressions/__snapshots__/format.test.js.snap index 61a64af90..5a488bf1f 100644 --- a/tests/format/js/throw_expressions/__snapshots__/format.test.js.snap +++ b/tests/format/js/throw_expressions/__snapshots__/format.test.js.snap @@ -30,6 +30,15 @@ exports[`throw_expression.js [meriyah] format 1`] = ` Cause: [1:25-1:30]: Unexpected token: 'throw'" `; +exports[`throw_expression.js [oxc] format 1`] = ` +"Unexpected token (1:26) +> 1 | function save(filename = throw new TypeError("Argument required")) {} + | ^^^^^ + 2 | + 3 | lint(ast, { + 4 | with: () => throw new Error("avoid using 'with' statements.")" +`; + exports[`throw_expression.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/throw_expressions/format.test.js b/tests/format/js/throw_expressions/format.test.js index e59778563..6e1f44b04 100644 --- a/tests/format/js/throw_expressions/format.test.js +++ b/tests/format/js/throw_expressions/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/js/v8_intrinsic/__snapshots__/format.test.js.snap b/tests/format/js/v8_intrinsic/__snapshots__/format.test.js.snap index 9cf17e690..715db4f46 100644 --- a/tests/format/js/v8_intrinsic/__snapshots__/format.test.js.snap +++ b/tests/format/js/v8_intrinsic/__snapshots__/format.test.js.snap @@ -27,6 +27,14 @@ exports[`avoid-conflicts-to-pipeline.js [meriyah] format 1`] = ` Cause: [2:15-2:16]: Unexpected token: '%'" `; +exports[`avoid-conflicts-to-pipeline.js [oxc] format 1`] = ` +"Unexpected token (2:16) + 1 | // |> +> 2 | const status = %GetOptimizationStatus(fn); + | ^ + 3 |" +`; + exports[`avoid-conflicts-to-pipeline.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -76,6 +84,16 @@ exports[`intrinsic_call.js [meriyah] format 1`] = ` Cause: [2:12-2:13]: Unexpected token: '%'" `; +exports[`intrinsic_call.js [oxc] format 1`] = ` +"Unexpected token (2:13) + 1 | function doSmth() { +> 2 | %DebugPrint + | ^ + 3 | ( + 4 | foo ) + 5 | }" +`; + exports[`intrinsic_call.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/js/v8_intrinsic/format.test.js b/tests/format/js/v8_intrinsic/format.test.js index e59778563..6e1f44b04 100644 --- a/tests/format/js/v8_intrinsic/format.test.js +++ b/tests/format/js/v8_intrinsic/format.test.js @@ -1,3 +1,3 @@ runFormatTest(import.meta, ["babel"], { - errors: { acorn: true, espree: true, meriyah: true }, + errors: { acorn: true, espree: true, meriyah: true, oxc: true }, }); diff --git a/tests/format/jsx/do/__snapshots__/format.test.js.snap b/tests/format/jsx/do/__snapshots__/format.test.js.snap index 38647183a..f8df2a2aa 100644 --- a/tests/format/jsx/do/__snapshots__/format.test.js.snap +++ b/tests/format/jsx/do/__snapshots__/format.test.js.snap @@ -33,6 +33,16 @@ exports[`do.js [meriyah] format 1`] = ` Cause: [2:3-2:5]: Unexpected token: 'do'" `; +exports[`do.js [oxc] format 1`] = ` +"Unexpected token (2:4) + 1 |
+> 2 | {do { + | ^^ + 3 | 1 + 4 | }} + 5 |
" +`; + exports[`do.js format 1`] = ` ====================================options===================================== parsers: ["babel"] diff --git a/tests/format/jsx/do/format.test.js b/tests/format/jsx/do/format.test.js index ec5f56871..f1e1a4294 100644 --- a/tests/format/jsx/do/format.test.js +++ b/tests/format/jsx/do/format.test.js @@ -3,5 +3,6 @@ runFormatTest(import.meta, ["babel"], { acorn: ["do.js"], espree: ["do.js"], meriyah: ["do.js"], + oxc: ["do.js"], }, }); diff --git a/yarn.lock b/yarn.lock index 0f33c9aa4..d20633d82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -972,6 +972,34 @@ __metadata: languageName: node linkType: hard +"@emnapi/core@npm:^1.4.3": + version: 1.4.3 + resolution: "@emnapi/core@npm:1.4.3" + dependencies: + "@emnapi/wasi-threads": "npm:1.0.2" + tslib: "npm:^2.4.0" + checksum: 10/b511f66b897d2019835391544fdf11f4fa0ce06cc1181abfa17c7d4cf03aaaa4fc8a64fcd30bb3f901de488d0a6f370b53a8de2215a898f5a4ac98015265b3b7 + languageName: node + linkType: hard + +"@emnapi/runtime@npm:^1.4.3": + version: 1.4.3 + resolution: "@emnapi/runtime@npm:1.4.3" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/4f90852a1a5912982cc4e176b6420556971bcf6a85ee23e379e2455066d616219751367dcf43e6a6eaf41ea7e95ba9dc830665a52b5d979dfe074237d19578f8 + languageName: node + linkType: hard + +"@emnapi/wasi-threads@npm:1.0.2": + version: 1.0.2 + resolution: "@emnapi/wasi-threads@npm:1.0.2" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/e82941776665eb958c2084728191d6b15a94383449975c4621b67a1c8217e1c0ec11056a693906c76863cb96f782f8be500510ecec6874e3f5da35a8e7968cfd + languageName: node + linkType: hard + "@esbuild/aix-ppc64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/aix-ppc64@npm:0.25.4" @@ -1890,6 +1918,17 @@ __metadata: languageName: node linkType: hard +"@napi-rs/wasm-runtime@npm:^0.2.9": + version: 0.2.10 + resolution: "@napi-rs/wasm-runtime@npm:0.2.10" + dependencies: + "@emnapi/core": "npm:^1.4.3" + "@emnapi/runtime": "npm:^1.4.3" + "@tybys/wasm-util": "npm:^0.9.0" + checksum: 10/1e4cf77891390825b1756eb5e302035b80c9dd21959417c4e4ed063eacfb6df9f42dfc001bf0fa9c9dbd0a7374342502feaa0a59103e7ea9aa5b318732280a49 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -1939,6 +1978,106 @@ __metadata: languageName: node linkType: hard +"@oxc-parser/binding-darwin-arm64@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-darwin-arm64@npm:0.69.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@oxc-parser/binding-darwin-x64@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-darwin-x64@npm:0.69.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@oxc-parser/binding-freebsd-x64@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-freebsd-x64@npm:0.69.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@oxc-parser/binding-linux-arm-gnueabihf@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-linux-arm-gnueabihf@npm:0.69.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@oxc-parser/binding-linux-arm64-gnu@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-linux-arm64-gnu@npm:0.69.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@oxc-parser/binding-linux-arm64-musl@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-linux-arm64-musl@npm:0.69.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@oxc-parser/binding-linux-riscv64-gnu@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-linux-riscv64-gnu@npm:0.69.0" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@oxc-parser/binding-linux-s390x-gnu@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-linux-s390x-gnu@npm:0.69.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@oxc-parser/binding-linux-x64-gnu@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-linux-x64-gnu@npm:0.69.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@oxc-parser/binding-linux-x64-musl@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-linux-x64-musl@npm:0.69.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@oxc-parser/binding-wasm32-wasi@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-wasm32-wasi@npm:0.69.0" + dependencies: + "@napi-rs/wasm-runtime": "npm:^0.2.9" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@oxc-parser/binding-win32-arm64-msvc@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-win32-arm64-msvc@npm:0.69.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@oxc-parser/binding-win32-x64-msvc@npm:0.69.0": + version: 0.69.0 + resolution: "@oxc-parser/binding-win32-x64-msvc@npm:0.69.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@oxc-project/types@npm:^0.69.0": + version: 0.69.0 + resolution: "@oxc-project/types@npm:0.69.0" + checksum: 10/fed6ca8401b7b9ba29fdf271a933093ef84b24c8f88077b0edbaeca4d2084bde0f157acd7fc8e3a5957041966bd106e5c61fab5818ad68d06cd8eca60269c8f9 + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -2053,6 +2192,15 @@ __metadata: languageName: node linkType: hard +"@tybys/wasm-util@npm:^0.9.0": + version: 0.9.0 + resolution: "@tybys/wasm-util@npm:0.9.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/aa58e64753a420ad1eefaf7bacef3dda61d74f9336925943d9244132d5b48d9242f734f1e707fd5ccfa6dd1d8ec8e6debc234b4dedb3a5b0d8486d1f373350b2 + languageName: node + linkType: hard + "@types/babel__core@npm:^7.1.14": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" @@ -6633,6 +6781,55 @@ __metadata: languageName: node linkType: hard +"oxc-parser@npm:0.69.0": + version: 0.69.0 + resolution: "oxc-parser@npm:0.69.0" + dependencies: + "@oxc-parser/binding-darwin-arm64": "npm:0.69.0" + "@oxc-parser/binding-darwin-x64": "npm:0.69.0" + "@oxc-parser/binding-freebsd-x64": "npm:0.69.0" + "@oxc-parser/binding-linux-arm-gnueabihf": "npm:0.69.0" + "@oxc-parser/binding-linux-arm64-gnu": "npm:0.69.0" + "@oxc-parser/binding-linux-arm64-musl": "npm:0.69.0" + "@oxc-parser/binding-linux-riscv64-gnu": "npm:0.69.0" + "@oxc-parser/binding-linux-s390x-gnu": "npm:0.69.0" + "@oxc-parser/binding-linux-x64-gnu": "npm:0.69.0" + "@oxc-parser/binding-linux-x64-musl": "npm:0.69.0" + "@oxc-parser/binding-wasm32-wasi": "npm:0.69.0" + "@oxc-parser/binding-win32-arm64-msvc": "npm:0.69.0" + "@oxc-parser/binding-win32-x64-msvc": "npm:0.69.0" + "@oxc-project/types": "npm:^0.69.0" + dependenciesMeta: + "@oxc-parser/binding-darwin-arm64": + optional: true + "@oxc-parser/binding-darwin-x64": + optional: true + "@oxc-parser/binding-freebsd-x64": + optional: true + "@oxc-parser/binding-linux-arm-gnueabihf": + optional: true + "@oxc-parser/binding-linux-arm64-gnu": + optional: true + "@oxc-parser/binding-linux-arm64-musl": + optional: true + "@oxc-parser/binding-linux-riscv64-gnu": + optional: true + "@oxc-parser/binding-linux-s390x-gnu": + optional: true + "@oxc-parser/binding-linux-x64-gnu": + optional: true + "@oxc-parser/binding-linux-x64-musl": + optional: true + "@oxc-parser/binding-wasm32-wasi": + optional: true + "@oxc-parser/binding-win32-arm64-msvc": + optional: true + "@oxc-parser/binding-win32-x64-msvc": + optional: true + checksum: 10/9908d21ec5ad4661a2f52b7a036d0dafad1354cd61f5796d097914b71db972e7b12d47696b4047d46ffacf5fa02b874699ff3a51b784bf840741a2015f6484c9 + languageName: node + linkType: hard + "p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -7081,6 +7278,7 @@ __metadata: node-style-text: "npm:0.0.8" npm-run-all2: "npm:8.0.3" outdent: "npm:0.8.0" + oxc-parser: "npm:0.69.0" parse-json: "npm:8.3.0" picocolors: "npm:1.1.1" please-upgrade-node: "npm:3.2.0" @@ -7092,6 +7290,7 @@ __metadata: postcss-values-parser: "npm:2.0.1" prettier: "npm:3.5.3" pretty-bytes: "npm:7.0.0" + pretty-ms: "npm:9.2.0" regexp-util: "npm:2.0.3" remark-footnotes: "npm:2.0.0" remark-math: "npm:3.0.1" @@ -7151,7 +7350,7 @@ __metadata: languageName: node linkType: hard -"pretty-ms@npm:^9.0.0": +"pretty-ms@npm:9.2.0, pretty-ms@npm:^9.0.0": version: 9.2.0 resolution: "pretty-ms@npm:9.2.0" dependencies: @@ -8277,7 +8476,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.3.0, tslib@npm:^2.6.2": +"tslib@npm:^2.3.0, tslib@npm:^2.4.0, tslib@npm:^2.6.2": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7