From 1b246f896d1e47935d5d66c99a65472ab1781235 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Wed, 15 Jul 2026 01:53:00 +0800 Subject: [PATCH] Add `yuku` parser (#19628) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> # Conflicts: # tests/format/js/deferred-import-evaluation/__snapshots__/format.test.js.snap --- .github/renovate.json5 | 4 + CONTRIBUTING.md | 2 +- cspell.json | 1 + eslint.config.js | 1 + knip.config.js | 3 +- package.json | 4 +- packages/plugin-yuku/README.md | 56 ++++++ packages/plugin-yuku/index.js | 18 ++ packages/plugin-yuku/languages.evaluate.js | 15 ++ packages/plugin-yuku/package.json | 24 +++ scripts/build-website.js | 2 +- scripts/build/packages/index.js | 2 + scripts/build/packages/plugin-yuku.js | 104 +++++++++++ scripts/production-eslint-config.js | 1 + src/language-js/parse/index.js | 1 + src/language-js/parse/oxc.js | 2 +- src/language-js/parse/postprocess/index.js | 12 +- src/language-js/parse/yuku.js | 89 ++++++++++ src/language-js/print/key.js | 1 + .../builtin-plugins/development-plugins.js | 1 + src/main/range.js | 1 + tests/config/browser-prettier/main.js | 4 +- .../config/format-test/failed-format-tests.js | 1 + tests/config/format-test/get-parsers.js | 2 +- tests/config/format-test/verify-fixtures.js | 5 +- .../__snapshots__/format.test.js.snap | 48 +++++ .../format.test.js | 1 + .../__snapshots__/format.test.js.snap | 154 ++++++++++++++++ .../_errors_/discard-binding/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 24 +++ .../js/_errors_/export-name/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 8 + .../newline-before-arrow/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 6 + .../js/_errors_/reserved-word/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 9 + tests/format/js/arrows-bind/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 9 + .../js/async-do-expressions/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 167 ++++++++++++++++++ tests/format/js/babel-plugins/format.test.js | 19 ++ .../__snapshots__/format.test.js.snap | 122 +++++++++++++ .../format/js/bind-expressions/format.test.js | 1 + .../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 | 1 + .../__snapshots__/format.test.js.snap | 14 ++ .../deferred-import-evaluation/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 75 ++++++++ .../format.test.js | 1 + .../__snapshots__/format.test.js.snap | 134 ++++++++++++++ .../format/js/discard-binding/format.test.js | 1 + .../js/do/__snapshots__/format.test.js.snap | 22 +++ tests/format/js/do/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 80 +++++++++ .../format.test.js | 13 ++ .../escaped/__snapshots__/format.test.js.snap | 7 + .../js/export-default/escaped/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 10 ++ .../export-default-from/format.test.js | 1 + .../js/for/__snapshots__/format.test.js.snap | 11 ++ tests/format/js/for/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 18 ++ .../js/identifier/parentheses/format.test.js | 18 +- .../__snapshots__/format.test.js.snap | 18 +- .../js/import-assertions/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 27 +++ tests/format/js/module-blocks/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 9 + .../module-blocks/quote-props/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 | 1 + .../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 | 1 + .../__snapshots__/format.test.js.snap | 38 ++++ .../js/pipeline-operator/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 10 ++ tests/format/js/reserved-word/format.test.js | 4 +- .../__snapshots__/format.test.js.snap | 28 +++ .../js/source-phase-imports/format.test.js | 5 + .../__snapshots__/format.test.js.snap | 9 + .../js/throw_expressions/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 18 ++ tests/format/js/v8_intrinsic/format.test.js | 1 + .../jsx/do/__snapshots__/format.test.js.snap | 10 ++ tests/format/jsx/do/format.test.js | 1 + tests/unit/builtin-plugins.js | 1 + website/playground/codeSamples.mjs | 1 + website/playground/panel/language.js | 1 + yarn.lock | 138 +++++++++++++++ 97 files changed, 1814 insertions(+), 27 deletions(-) create mode 100644 packages/plugin-yuku/README.md create mode 100644 packages/plugin-yuku/index.js create mode 100644 packages/plugin-yuku/languages.evaluate.js create mode 100644 packages/plugin-yuku/package.json create mode 100644 scripts/build/packages/plugin-yuku.js create mode 100644 src/language-js/parse/yuku.js diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 8ec57fa8f..1e9c239ce 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -60,6 +60,10 @@ groupName: "Acorn and Espree", matchPackageNames: ["acorn", "acorn-jsx", "espree"], }, + { + groupName: "Yuku parser", + matchPackageNames: ["yuku-parser", "@yuku-parser/*"], + }, { groupName: "Regex related dependencies", matchPackageNames: ["regexp-util", "unicode-regex", "cjk-regex"], diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca4b6ca9c..26f4d91dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,7 +67,7 @@ If the list includes `typescript`, then `babel-ts`, and `oxc-ts` are included im If the list includes `flow`, then `hermes` 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. +If the list includes `babel`, and the current directory is inside `tests/format/js` or `tests/format/jsx`, then `acorn`, `espree`, `meriyah`, `oxc`, and `yuku` are included implicitly. ### **`options`** diff --git a/cspell.json b/cspell.json index 2b1e17847..ca817645e 100644 --- a/cspell.json +++ b/cspell.json @@ -306,6 +306,7 @@ "xtest", "yamafaktory", "Yatharth", + "yuku", "Zatorski" ], "ignoreRegExpList": [ diff --git a/eslint.config.js b/eslint.config.js index 28e594fd5..8148a1331 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -515,6 +515,7 @@ const configs = [ "src/language-js/parse/json.js", "src/language-js/parse/acorn.js", "src/language-js/parse/oxc.js", + "src/language-js/parse/yuku.js", "src/language-js/parse/utilities/wrap-expression.js", ], "prettier-internal-rules/prefer-create-type-check-function": [ diff --git a/knip.config.js b/knip.config.js index c54151ade..10464ef4b 100644 --- a/knip.config.js +++ b/knip.config.js @@ -35,8 +35,9 @@ const config = { "buffer", "base64-arraybuffer-es6", "flow-estree", + "@yuku-parser/wasm", ], - ignoreBinaries: ["test-coverage"], + ignoreBinaries: [], }, website: { entry: [ diff --git a/package.json b/package.json index bbdf9d672..77f6c6f57 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,8 @@ "vnopts": "2.0.5", "wcwidth.js": "2.0.0", "yaml": "2.9.0", - "yaml-unist-parser": "3.2.0" + "yaml-unist-parser": "3.2.0", + "yuku-parser": "0.6.2" }, "devDependencies": { "@babel/generator": "8.0.0", @@ -140,6 +141,7 @@ "@types/jsesc": "3.0.3", "@typescript-eslint/eslint-plugin": "8.64.0", "@typescript-eslint/parser": "8.64.0", + "@yuku-parser/wasm": "0.6.2", "base64-arraybuffer-es6": "3.1.0", "browserslist": "4.28.5", "browserslist-to-esbuild": "2.1.1", diff --git a/packages/plugin-yuku/README.md b/packages/plugin-yuku/README.md new file mode 100644 index 000000000..a3f75fb00 --- /dev/null +++ b/packages/plugin-yuku/README.md @@ -0,0 +1,56 @@ +# @prettier/plugin-yuku + +[![Npm Version](https://img.shields.io/npm/v/@prettier/plugin-yuku.svg?style=flat-square)](https://www.npmjs.com/package/@prettier/plugin-yuku) +[![MIT License](https://img.shields.io/npm/l/@prettier/plugin-yuku.svg?style=flat-square)](https://github.com/prettier/prettier/blob/main/license) + +> Prettier [yuku](https://yuku.fyi/) plugin. + +## Install + +```bash +yarn add --dev --exact prettier @prettier/plugin-yuku +``` + +## Usage + +Create or modify your [prettier configuration file](https://prettier.io/docs/en/configuration) to use the plugin: + +```js +// prettier.config.mjs +import * as prettierPluginYuku from "@prettier/plugin-yuku"; + +/** + * @see https://prettier.io/docs/configuration + * @type {import("prettier").Config} + */ +const config = { + plugins: [prettierPluginYuku], +}; + +export default config; +``` + +**Requires prettier>=3.6.0** + +Or config explicitly + +```js +// prettier.config.mjs +import * as prettierPluginYuku from "@prettier/plugin-yuku"; + +/** + * @see https://prettier.io/docs/configuration + * @type {import("prettier").Config} + */ +const config = { + overrides: [ + { + files: ["**/*.{js,mjs,cjs,jsx}"], + parser: "yuku", + plugins: [prettierPluginYuku], + }, + ], +}; + +export default config; +``` diff --git a/packages/plugin-yuku/index.js b/packages/plugin-yuku/index.js new file mode 100644 index 000000000..0cca1ae25 --- /dev/null +++ b/packages/plugin-yuku/index.js @@ -0,0 +1,18 @@ +import * as yukuParsers from "../../src/language-js/parse/yuku.js"; +import { estree as estreePrinter } from "../../src/language-js/printers.js"; + +const AST_FORMAT = "estree-yuku"; + +export const parsers = Object.fromEntries( + Object.entries(yukuParsers).map(([name, parser]) => [ + name, + { ...parser, astFormat: AST_FORMAT }, + ]), +); + +export const printers = { + [AST_FORMAT]: estreePrinter, +}; + +export { default as options } from "../../src/language-js/options.js"; +export { default as languages } from "./languages.evaluate.js"; diff --git a/packages/plugin-yuku/languages.evaluate.js b/packages/plugin-yuku/languages.evaluate.js new file mode 100644 index 000000000..ce83af0bb --- /dev/null +++ b/packages/plugin-yuku/languages.evaluate.js @@ -0,0 +1,15 @@ +import builtinJsLanguages from "../../src/language-js/languages.evaluate.js"; + +const replacements = new Map([["babel", "yuku"]]); + +const languages = builtinJsLanguages + .map((language) => { + const parsers = language.parsers + .map((parser) => replacements.get(parser)) + .filter(Boolean); + + return parsers.length > 0 ? { ...language, parsers } : undefined; + }) + .filter(Boolean); + +export default languages; diff --git a/packages/plugin-yuku/package.json b/packages/plugin-yuku/package.json new file mode 100644 index 000000000..e91966f27 --- /dev/null +++ b/packages/plugin-yuku/package.json @@ -0,0 +1,24 @@ +{ + "name": "@prettier/plugin-yuku", + "version": "0.0.0", + "description": "Prettier yuku plugin.", + "type": "module", + "exports": { + ".": { + "types": "./index.d.ts", + "browser": "./index.browser.mjs", + "default": "./index.mjs" + }, + "./*": "./*" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/prettier/prettier.git", + "directory": "packages/plugin-yuku" + }, + "funding": "https://github.com/prettier/prettier?sponsor=1", + "homepage": "https://github.com/prettier/prettier/tree/main/packages/plugin-yuku", + "author": "fisker Cheung ", + "license": "MIT", + "sideEffects": false +} diff --git a/scripts/build-website.js b/scripts/build-website.js index c4d872684..056c4415b 100644 --- a/scripts/build-website.js +++ b/scripts/build-website.js @@ -68,7 +68,7 @@ async function buildPlaygroundFiles(version) { for (const pluginName of ["plugin-hermes"]) { pluginFiles.push(`${pluginName}/index.mjs`); } - for (const pluginName of ["plugin-oxc"]) { + for (const pluginName of ["plugin-oxc", "plugin-yuku"]) { pluginFiles.push(`${pluginName}/index.browser.mjs`); } } diff --git a/scripts/build/packages/index.js b/scripts/build/packages/index.js index 78e0dee34..d9e39fa4f 100644 --- a/scripts/build/packages/index.js +++ b/scripts/build/packages/index.js @@ -1,9 +1,11 @@ import pluginHermesBuildConfig from "./plugin-hermes.js"; import pluginOxcBuildConfig from "./plugin-oxc.js"; +import pluginYukuBuildConfig from "./plugin-yuku.js"; import prettierBuildConfig from "./prettier.js"; export default [ prettierBuildConfig, pluginHermesBuildConfig, pluginOxcBuildConfig, + pluginYukuBuildConfig, ]; diff --git a/scripts/build/packages/plugin-yuku.js b/scripts/build/packages/plugin-yuku.js new file mode 100644 index 000000000..6c7c3c040 --- /dev/null +++ b/scripts/build/packages/plugin-yuku.js @@ -0,0 +1,104 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { outdent } from "outdent"; +import { DIST_DIR, PACKAGES_DIRECTORY } from "../../utilities/index.js"; +import { createJavascriptModuleBuilder } from "../builders/javascript-module.js"; +import { getPackageFile } from "../utilities.js"; +import { + createPackageMetaFilesConfig, + createTypesConfig, +} from "./config-helpers.js"; + +const packageConfig = { + packageName: "@prettier/plugin-yuku", + sourceDirectory: path.join(PACKAGES_DIRECTORY, "plugin-yuku"), + distDirectory: path.join(DIST_DIR, "plugin-yuku"), + modules: [], +}; + +const mainModule = { + name: "Entries", + files: [ + { + input: "index.js", + output: "index.mjs", + build: createJavascriptModuleBuilder({ + input: "index.js", + output: "index.mjs", + format: "esm", + platform: "node", + external: ["yuku-parser"], + addDefaultExport: true, + }), + }, + { + input: "index.js", + output: "index.browser.mjs", + build: createJavascriptModuleBuilder({ + format: "esm", + platform: "universal", + addDefaultExport: true, + replaceModule: [ + { + module: getPackageFile("yuku-parser"), + path: getPackageFile("@yuku-parser/wasm"), + }, + { + module: getPackageFile("@yuku-parser/wasm"), + async process(text) { + const wasmUrlPattern = + /const wasmUrl = new URL\("(?.\/.+\.wasm)", import\.meta\.url\);/; + const { wasmFile } = text.match(wasmUrlPattern).groups; + const wasmBase64String = await fs.readFile( + getPackageFile(`@yuku-parser/wasm/${wasmFile}`), + "base64", + ); + + text = text.replace('import("node:fs/promises")', "whatever"); + text = text.replace(wasmUrlPattern, ""); + + text = text.replace( + "const { memory, alloc, free, parse: wasmParse } = (await instantiate()).exports;", + outdent` + const module = new WebAssembly.Module((wasmBinary)); + const instance = new WebAssembly.Instance(module); + const { memory, alloc, free, parse: wasmParse } = instance.exports; + `, + ); + + text = outdent` + import { decode as __decode } from "base64-arraybuffer-es6"; + const __base64ToArrayBuffer = Uint8Array.fromBase64 + ? (string) => Uint8Array.fromBase64(string).buffer + : __decode; + const wasmBinary = /* "${wasmFile}" */ __base64ToArrayBuffer(${JSON.stringify(wasmBase64String)}); + + ${text} + `; + + return text; + }, + }, + ], + }), + playground: true, + }, + ...createTypesConfig({ input: "index.js", isPlugin: true }), + ], +}; + +packageConfig.modules.push( + mainModule, + createPackageMetaFilesConfig({ + "package.json"(packageJson, { projectPackageJson }) { + return { + ...packageJson, + dependencies: { + "yuku-parser": projectPackageJson.dependencies["yuku-parser"], + }, + }; + }, + }), +); + +export default packageConfig; diff --git a/scripts/production-eslint-config.js b/scripts/production-eslint-config.js index c5f76b58c..a87c37c9d 100644 --- a/scripts/production-eslint-config.js +++ b/scripts/production-eslint-config.js @@ -28,6 +28,7 @@ const nodejsFiles = jsFiles.filter( "dist/prettier/internal/experimental-cli.mjs", "dist/prettier/internal/experimental-cli-worker.mjs", "dist/plugin-oxc/index.mjs", + "dist/plugin-yuku/index.mjs", ].includes(file), ); diff --git a/src/language-js/parse/index.js b/src/language-js/parse/index.js index e2b938d1e..ead74fa4a 100644 --- a/src/language-js/parse/index.js +++ b/src/language-js/parse/index.js @@ -7,3 +7,4 @@ export * from "./hermes.js"; export * from "./meriyah.js"; export * from "./oxc.js"; export * from "./typescript.js"; +export * from "./yuku.js"; diff --git a/src/language-js/parse/oxc.js b/src/language-js/parse/oxc.js index 46998b046..daad95f6b 100644 --- a/src/language-js/parse/oxc.js +++ b/src/language-js/parse/oxc.js @@ -69,7 +69,7 @@ function parseJs(text, options) { const sourceType = getSourceType(filepath); if (typeof filepath !== "string") { - filepath = "prettier.tsx"; + filepath = "prettier.jsx"; } const combinations = ( sourceType ? [sourceType] : SOURCE_TYPE_COMBINATIONS diff --git a/src/language-js/parse/postprocess/index.js b/src/language-js/parse/postprocess/index.js index 226bb95eb..b1c60c7df 100644 --- a/src/language-js/parse/postprocess/index.js +++ b/src/language-js/parse/postprocess/index.js @@ -45,7 +45,15 @@ const isNodeWithRaw = createTypeCheckFunction([ /** @param {{ text: string, - astType?: "espree" | "flow" | "hermes" | "meriyah" | "oxc-js" | "oxc-ts" | "typescript", + astType?: + | "espree" + | "flow" + | "hermes" + | "meriyah" + | "oxc-js" + | "oxc-ts" + | "typescript" + | "yuku-js", }} options */ function postprocess(ast, options) { @@ -65,7 +73,7 @@ function postprocess(ast, options) { } if (ast.hashbang) { - if (isOxcTs) { + if (isOxcTs || astType === "yuku-js") { comments.unshift(ast.hashbang); } delete ast.hashbang; diff --git a/src/language-js/parse/yuku.js b/src/language-js/parse/yuku.js new file mode 100644 index 000000000..052335e63 --- /dev/null +++ b/src/language-js/parse/yuku.js @@ -0,0 +1,89 @@ +import indexToPosition from "index-to-position"; +import { parse as yukuParse } from "yuku-parser"; +import createError from "../../common/parser-create-error.js"; +import { tryCombinationsSync } from "../../utilities/try-combinations.js"; +import postprocess from "./postprocess/index.js"; +import createParser from "./utilities/create-parser.js"; +import { + getSourceType, + SOURCE_TYPE_COMBINATIONS, +} from "./utilities/source-types.js"; + +/** @import {ParseOptions} from "yuku-parser" */ + +function createParseError(error, { text }) { + if (typeof error?.start !== "number" || typeof error?.end !== "number") { + return error; + } + + const { message, 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, + }); +} + +/** +@param {string} text +@param {ParseOptions} options +*/ +function parseWithOptions(text, options) { + const result = yukuParse(text, { + preserveParens: true, + allowReturnOutsideFunction: true, + semanticErrors: false, + attachComments: false, + ...options, + }); + + const { diagnostics: errors } = result; + for (const error of errors) { + throw createParseError(error, { text }); + } + + return result; +} + +function parseJs(text, options) { + const filepath = options?.filepath; + const sourceType = getSourceType(filepath); + + const combinations = ( + sourceType ? [sourceType] : SOURCE_TYPE_COMBINATIONS + ).map( + (sourceType) => () => + parseWithOptions(text, { + sourceType: sourceType === "commonjs" ? "script" : sourceType, + lang: "jsx", + }), + ); + + let result; + try { + result = tryCombinationsSync(combinations); + } catch ({ + // @ts-expect-error -- expected + errors: [error], + }) { + throw error; + } + + const { program: ast, comments } = result; + + // @ts-expect-error -- expected + ast.comments = comments; + + return postprocess(ast, { text, astType: "yuku-js" }); +} + +const yuku = /* @__PURE__ */ createParser(parseJs); + +export { yuku }; diff --git a/src/language-js/print/key.js b/src/language-js/print/key.js index cabfe3970..c51f74bf9 100644 --- a/src/language-js/print/key.js +++ b/src/language-js/print/key.js @@ -118,6 +118,7 @@ function isKeySafeToUnquote(node, options) { (parser === "babel" || parser === "acorn" || parser === "oxc" || + parser === "yuku" || parser === "espree" || parser === "meriyah" || parser === "__babel_estree") && diff --git a/src/main/plugins/builtin-plugins/development-plugins.js b/src/main/plugins/builtin-plugins/development-plugins.js index 683c979d7..ad4493a22 100644 --- a/src/main/plugins/builtin-plugins/development-plugins.js +++ b/src/main/plugins/builtin-plugins/development-plugins.js @@ -79,6 +79,7 @@ export const plugins = /* @__PURE__ */ toLazyLoadPlugins( "oxc", "oxc-ts", "typescript", + "yuku", ], }, { diff --git a/src/main/range.js b/src/main/range.js index 623524a97..6a5030b6b 100644 --- a/src/main/range.js +++ b/src/main/range.js @@ -171,6 +171,7 @@ function isSourceElement(opts, node, parentNode) { case "meriyah": case "oxc": case "oxc-ts": + case "yuku": case "__babel_estree": return isJsSourceElement(node.type, parentNode?.type); case "json": diff --git a/tests/config/browser-prettier/main.js b/tests/config/browser-prettier/main.js index 6e8eb8b38..a0be78684 100644 --- a/tests/config/browser-prettier/main.js +++ b/tests/config/browser-prettier/main.js @@ -20,6 +20,7 @@ const esmFiles = { "prettier/plugins/meriyah.mjs", "plugin-hermes/index.mjs", "plugin-oxc/index.browser.mjs", + "plugin-yuku/index.browser.mjs", ], }; const umdFiles = { @@ -38,9 +39,10 @@ const umdFiles = { "prettier/plugins/yaml.js", "prettier/plugins/flow.js", "prettier/plugins/meriyah.js", - // These two plugins don't have UMD version + // These plugins don't have UMD version "plugin-hermes/index.mjs", "plugin-oxc/index.browser.mjs", + "plugin-yuku/index.browser.mjs", ], }; diff --git a/tests/config/format-test/failed-format-tests.js b/tests/config/format-test/failed-format-tests.js index 816bef1bc..d5c000a9b 100644 --- a/tests/config/format-test/failed-format-tests.js +++ b/tests/config/format-test/failed-format-tests.js @@ -89,6 +89,7 @@ const disabledTests = new Map( ], oxc: [], "oxc-ts": ["typescript/typescript-only/"], + yuku: [], hermes: [ ...commentClosureTypecaseTests, diff --git a/tests/config/format-test/get-parsers.js b/tests/config/format-test/get-parsers.js index 2329cabd7..294a57b36 100644 --- a/tests/config/format-test/get-parsers.js +++ b/tests/config/format-test/get-parsers.js @@ -17,7 +17,7 @@ function getParsers(dirname, parsers) { parsers.includes("babel") && (isLanguage(dirname, "js") || isLanguage(dirname, "jsx")) ) { - addParsers("acorn", "espree", "meriyah", "oxc"); + addParsers("acorn", "espree", "meriyah", "oxc", "yuku"); } if (parsers.includes("typescript")) { diff --git a/tests/config/format-test/verify-fixtures.js b/tests/config/format-test/verify-fixtures.js index bf7a5dbdd..86dee4ecc 100644 --- a/tests/config/format-test/verify-fixtures.js +++ b/tests/config/format-test/verify-fixtures.js @@ -59,7 +59,7 @@ const categoryParsers = new Map([ [ "js", { - parsers: ["babel", "acorn", "espree", "meriyah", "oxc"], + parsers: ["babel", "acorn", "espree", "meriyah", "oxc", "yuku"], verifyParsers: [ "babel", "acorn", @@ -67,6 +67,7 @@ const categoryParsers = new Map([ "meriyah", "oxc", "oxc-ts", + "yuku", "flow", "babel-flow", "typescript", @@ -102,6 +103,7 @@ const categoryParsers = new Map([ "hermes", "oxc", "oxc-ts", + "yuku", ], verifyParsers: [ "babel", @@ -117,6 +119,7 @@ const categoryParsers = new Map([ "hermes", "oxc", "oxc-ts", + "yuku", ], extensions: [".js", ".jsx"], }, diff --git a/tests/format/js/_errors_/class-property-named-constructor/__snapshots__/format.test.js.snap b/tests/format/js/_errors_/class-property-named-constructor/__snapshots__/format.test.js.snap index 46a896daa..3428c4919 100644 --- a/tests/format/js/_errors_/class-property-named-constructor/__snapshots__/format.test.js.snap +++ b/tests/format/js/_errors_/class-property-named-constructor/__snapshots__/format.test.js.snap @@ -90,6 +90,14 @@ exports[`snippet: #0 format[typescript] 1`] = ` Cause: '(' expected." `; +exports[`snippet: #0 format[yuku] 1`] = ` +"Expected '(' for getter/setter definition, but found '}' (3:1) + 1 | class Foo { + 2 | constructor +> 3 | } + | ^" +`; + exports[`snippet: #1 format[acorn] 1`] = ` "Classes can't have a field named 'constructor' (2:3) 1 | class Foo { @@ -180,6 +188,14 @@ exports[`snippet: #1 format[typescript] 1`] = ` Cause: Classes may not have a field named 'constructor'." `; +exports[`snippet: #1 format[yuku] 1`] = ` +"Expected '(' for getter/setter definition, but found '}' (3:1) + 1 | class Foo { + 2 | 'constructor' +> 3 | } + | ^" +`; + exports[`snippet: #2 format[acorn] 1`] = ` "Classes can't have a field named 'constructor' (2:3) 1 | class Foo { @@ -270,6 +286,14 @@ exports[`snippet: #2 format[typescript] 1`] = ` Cause: Classes may not have a field named 'constructor'." `; +exports[`snippet: #2 format[yuku] 1`] = ` +"Expected '(' for getter/setter definition, but found '}' (3:1) + 1 | class Foo { + 2 | 'constructor' +> 3 | } + | ^" +`; + exports[`snippet: #3 format[acorn] 1`] = ` "Unexpected token (2:12) 1 | class Foo { @@ -360,6 +384,14 @@ exports[`snippet: #3 format[typescript] 1`] = ` Cause: Classes may not have a field named 'constructor'." `; +exports[`snippet: #3 format[yuku] 1`] = ` +"Expected '(' for getter/setter definition, but found '}' (3:1) + 1 | class Foo { + 2 | accessor 'constructor' +> 3 | } + | ^" +`; + exports[`snippet: #4 format[acorn] 1`] = ` "Unexpected token (2:12) 1 | class Foo { @@ -450,6 +482,14 @@ exports[`snippet: #4 format[typescript] 1`] = ` Cause: Classes may not have a field named 'constructor'." `; +exports[`snippet: #4 format[yuku] 1`] = ` +"Expected '(' for getter/setter definition, but found '}' (3:1) + 1 | class Foo { + 2 | accessor 'constructor' +> 3 | } + | ^" +`; + exports[`snippet: #5 format[acorn] 1`] = ` "Unexpected token (2:12) 1 | class Foo { @@ -539,3 +579,11 @@ exports[`snippet: #5 format[typescript] 1`] = ` | ^ Cause: '(' expected." `; + +exports[`snippet: #5 format[yuku] 1`] = ` +"Expected '(' for getter/setter definition, but found '}' (3:1) + 1 | class Foo { + 2 | accessor constructor +> 3 | } + | ^" +`; diff --git a/tests/format/js/_errors_/class-property-named-constructor/format.test.js b/tests/format/js/_errors_/class-property-named-constructor/format.test.js index 25c0a0dda..5363c5f31 100644 --- a/tests/format/js/_errors_/class-property-named-constructor/format.test.js +++ b/tests/format/js/_errors_/class-property-named-constructor/format.test.js @@ -14,6 +14,7 @@ runFormatTest( "babel-ts", "oxc", "oxc-ts", + "yuku", "flow", "hermes", ], diff --git a/tests/format/js/_errors_/discard-binding/__snapshots__/format.test.js.snap b/tests/format/js/_errors_/discard-binding/__snapshots__/format.test.js.snap index 1b98c2a07..6ee962dc7 100644 --- a/tests/format/js/_errors_/discard-binding/__snapshots__/format.test.js.snap +++ b/tests/format/js/_errors_/discard-binding/__snapshots__/format.test.js.snap @@ -80,6 +80,15 @@ exports[`invalid-array-expression.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`invalid-array-expression.js format[yuku] 1`] = ` +"Unexpected token ']' (1:9) +> 1 | ([[[void], x, ], y]); + | ^ + 2 | + 3 | ([[[x], void, ], y]); + 4 |" +`; + exports[`invalid-assignment-expression.js format[acorn] 1`] = ` "Unexpected token (1:6) > 1 | void = 0; @@ -144,6 +153,13 @@ exports[`invalid-assignment-expression.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`invalid-assignment-expression.js format[yuku] 1`] = ` +"Unexpected token '=' (1:6) +> 1 | void = 0; + | ^ + 2 |" +`; + exports[`invalid-assignment-for.js format[acorn] 1`] = ` "Unexpected token (1:15) > 1 | for (void of []); @@ -208,6 +224,13 @@ exports[`invalid-assignment-for.js format[typescript] 1`] = ` Cause: An element access expression should take an argument." `; +exports[`invalid-assignment-for.js format[yuku] 1`] = ` +"Unexpected token ']' (1:15) +> 1 | for (void of []); + | ^ + 2 |" +`; + exports[`invalid-assignment-pattern.js format[acorn] 1`] = ` "Unexpected keyword 'void' (3:14) 1 | { @@ -304,6 +327,17 @@ exports[`invalid-assignment-pattern.js format[typescript] 1`] = ` Cause: Identifier expected. 'void' is a reserved word that cannot be used here." `; +exports[`invalid-assignment-pattern.js format[yuku] 1`] = ` +"'void' is reserved and cannot be used as a binding identifier (3:14) + 1 | { + 2 | // function parameter +> 3 | function f(void = 0) {} + | ^^^^ + 4 | } + 5 | { + 6 | // arrow function parameter" +`; + exports[`invalid-async-call-argument.js format[acorn] 1`] = ` "Unexpected token (1:11) > 1 | async(void, x); @@ -384,6 +418,15 @@ exports[`invalid-async-call-argument.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`invalid-async-call-argument.js format[yuku] 1`] = ` +"Unexpected token ',' (1:11) +> 1 | async(void, x); + | ^ + 2 | + 3 | async(x, void); + 4 |" +`; + exports[`invalid-catch-parameter.js format[acorn] 1`] = ` "Unexpected keyword 'void' (1:15) > 1 | try {} catch (void) {} @@ -448,6 +491,13 @@ exports[`invalid-catch-parameter.js format[typescript] 1`] = ` Cause: Identifier expected. 'void' is a reserved word that cannot be used here." `; +exports[`invalid-catch-parameter.js format[yuku] 1`] = ` +"'void' is reserved and cannot be used as a binding identifier (1:15) +> 1 | try {} catch (void) {} + | ^^^^ + 2 |" +`; + exports[`invalid-lone-arrow-function-parameter.js format[acorn] 1`] = ` "Unexpected token (1:6) > 1 | void => {} @@ -512,6 +562,13 @@ exports[`invalid-lone-arrow-function-parameter.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`invalid-lone-arrow-function-parameter.js format[yuku] 1`] = ` +"Unexpected token '=>' (1:6) +> 1 | void => {} + | ^^ + 2 |" +`; + exports[`invalid-lone-async-arrow-function-parameter.js format[acorn] 1`] = ` "Unexpected token (1:7) > 1 | async void => {} @@ -576,6 +633,13 @@ exports[`invalid-lone-async-arrow-function-parameter.js format[typescript] 1`] = Cause: Unexpected keyword or identifier." `; +exports[`invalid-lone-async-arrow-function-parameter.js format[yuku] 1`] = ` +"'void' is reserved and cannot be used as an identifier (1:7) +> 1 | async void => {} + | ^^^^ + 2 |" +`; + exports[`invalid-object-expression.js format[acorn] 1`] = ` "Unexpected token (1:22) > 1 | ({ p: { p: { p: void }, x, }, y}); @@ -656,6 +720,15 @@ exports[`invalid-object-expression.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`invalid-object-expression.js format[yuku] 1`] = ` +"Unexpected token '}' (1:22) +> 1 | ({ p: { p: { p: void }, x, }, y}); + | ^ + 2 | + 3 | ({ p: { x: { x }, p: void, }, y}); + 4 |" +`; + exports[`invalid-parenthesized-assignment.js format[acorn] 1`] = ` "Unexpected token (1:7) > 1 | [(void)] = []; @@ -720,6 +793,13 @@ exports[`invalid-parenthesized-assignment.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`invalid-parenthesized-assignment.js format[yuku] 1`] = ` +"Unexpected token ')' (1:7) +> 1 | [(void)] = []; + | ^ + 2 |" +`; + exports[`invalid-parenthesized-binding.js format[acorn] 1`] = ` "Unexpected token (1:10) > 1 | const [, (void), ] = value; @@ -784,6 +864,13 @@ exports[`invalid-parenthesized-binding.js format[typescript] 1`] = ` Cause: Array element destructuring pattern expected." `; +exports[`invalid-parenthesized-binding.js format[yuku] 1`] = ` +"Unexpected token ')' (1:15) +> 1 | const [, (void), ] = value; + | ^ + 2 |" +`; + exports[`invalid-rest-element-array-pattern.js format[acorn] 1`] = ` "Unexpected keyword 'void' (2:12) 1 | { @@ -872,6 +959,16 @@ exports[`invalid-rest-element-array-pattern.js format[typescript] 1`] = ` Cause: Identifier expected. 'void' is a reserved word that cannot be used here." `; +exports[`invalid-rest-element-array-pattern.js format[yuku] 1`] = ` +"Unexpected token ']' (2:17) + 1 | { +> 2 | var [ ...void ] = []; + | ^ + 3 | } + 4 | { + 5 | for (var [...void] of [[]]);" +`; + exports[`invalid-rest-element-array-pattern-for-lhs.js format[acorn] 1`] = ` "Unexpected token (1:16) > 1 | for ([ ...void ] of []); @@ -936,6 +1033,13 @@ exports[`invalid-rest-element-array-pattern-for-lhs.js format[typescript] 1`] = Cause: Expression expected." `; +exports[`invalid-rest-element-array-pattern-for-lhs.js format[yuku] 1`] = ` +"Unexpected token ']' (1:16) +> 1 | for ([ ...void ] of []); + | ^ + 2 |" +`; + exports[`invalid-rest-element-array-pattern-lhs.js format[acorn] 1`] = ` "Unexpected token (1:12) > 1 | ([ ...void ] = []); @@ -1000,6 +1104,13 @@ exports[`invalid-rest-element-array-pattern-lhs.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`invalid-rest-element-array-pattern-lhs.js format[yuku] 1`] = ` +"Unexpected token ']' (1:12) +> 1 | ([ ...void ] = []); + | ^ + 2 |" +`; + exports[`invalid-rest-element-object-pattern.js format[acorn] 1`] = ` "Unexpected keyword 'void' (2:12) 1 | { @@ -1088,6 +1199,16 @@ exports[`invalid-rest-element-object-pattern.js format[typescript] 1`] = ` Cause: ':' expected." `; +exports[`invalid-rest-element-object-pattern.js format[yuku] 1`] = ` +"Unexpected token '}' (2:17) + 1 | { +> 2 | var { ...void } = {}; + | ^ + 3 | } + 4 | { + 5 | for (var { ...void } of [{}]);" +`; + exports[`invalid-rest-element-object-pattern-for-lhs.js format[acorn] 1`] = ` "Unexpected token (1:16) > 1 | for ({ ...void } of []); @@ -1152,6 +1273,13 @@ exports[`invalid-rest-element-object-pattern-for-lhs.js format[typescript] 1`] = Cause: Expression expected." `; +exports[`invalid-rest-element-object-pattern-for-lhs.js format[yuku] 1`] = ` +"Unexpected token '}' (1:16) +> 1 | for ({ ...void } of []); + | ^ + 2 |" +`; + exports[`invalid-rest-element-object-pattern-lhs.js format[acorn] 1`] = ` "Unexpected token (1:12) > 1 | ({ ...void } = {}); @@ -1216,6 +1344,13 @@ exports[`invalid-rest-element-object-pattern-lhs.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`invalid-rest-element-object-pattern-lhs.js format[yuku] 1`] = ` +"Unexpected token '}' (1:12) +> 1 | ({ ...void } = {}); + | ^ + 2 |" +`; + exports[`invalid-sequence-expression.js format[acorn] 1`] = ` "Unexpected token (1:6) > 1 | (void, x); @@ -1296,6 +1431,15 @@ exports[`invalid-sequence-expression.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`invalid-sequence-expression.js format[yuku] 1`] = ` +"Unexpected token ',' (1:6) +> 1 | (void, x); + | ^ + 2 | + 3 | (x, void); + 4 |" +`; + exports[`invalid-variable-declarator.js format[acorn] 1`] = ` "Unexpected keyword 'void' (2:7) 1 | { @@ -1383,3 +1527,13 @@ exports[`invalid-variable-declarator.js format[typescript] 1`] = ` 5 | let void = f(), void = g(); Cause: 'void' is not allowed as a variable declaration name." `; + +exports[`invalid-variable-declarator.js format[yuku] 1`] = ` +"'void' is reserved and cannot be used as a binding identifier (2:7) + 1 | { +> 2 | var void = f(); + | ^^^^ + 3 | } + 4 | { + 5 | let void = f(), void = g();" +`; diff --git a/tests/format/js/_errors_/discard-binding/format.test.js b/tests/format/js/_errors_/discard-binding/format.test.js index 909e2769f..e611b8aa0 100644 --- a/tests/format/js/_errors_/discard-binding/format.test.js +++ b/tests/format/js/_errors_/discard-binding/format.test.js @@ -6,5 +6,6 @@ runFormatTest(import.meta, [ "meriyah", "oxc", "oxc-ts", + "yuku", "hermes", ]); diff --git a/tests/format/js/_errors_/export-name/__snapshots__/format.test.js.snap b/tests/format/js/_errors_/export-name/__snapshots__/format.test.js.snap index 8f10b2802..f6dfcff32 100644 --- a/tests/format/js/_errors_/export-name/__snapshots__/format.test.js.snap +++ b/tests/format/js/_errors_/export-name/__snapshots__/format.test.js.snap @@ -84,6 +84,12 @@ exports[`snippet: #0 format[oxc-ts] 1`] = ` | ^^^^^^^^" `; +exports[`snippet: #0 format[yuku] 1`] = ` +"An export name cannot include a unicode lone surrogate (1:10) +> 1 | import { "\\uD83C" as b } from "./foo"; + | ^^^^^^^^" +`; + exports[`snippet: #1 format[__babel_estree] 1`] = ` "An export name cannot include a lone surrogate, found '\\ud83c'. (1:10) > 1 | export { "\\uD83C" } from "./foo"; @@ -168,6 +174,12 @@ exports[`snippet: #1 format[oxc-ts] 1`] = ` | ^^^^^^^^" `; +exports[`snippet: #1 format[yuku] 1`] = ` +"An export name cannot include a unicode lone surrogate (1:10) +> 1 | export { "\\uD83C" } from "./foo"; + | ^^^^^^^^" +`; + exports[`snippet: #2 format[__babel_estree] 1`] = ` "An export name cannot include a lone surrogate, found '\\ud83c'. (1:10) > 1 | export { "\\uD83C" as b } from "./foo"; @@ -252,6 +264,12 @@ exports[`snippet: #2 format[oxc-ts] 1`] = ` | ^^^^^^^^" `; +exports[`snippet: #2 format[yuku] 1`] = ` +"An export name cannot include a unicode lone surrogate (1:10) +> 1 | export { "\\uD83C" as b } from "./foo"; + | ^^^^^^^^" +`; + exports[`snippet: #3 format[__babel_estree] 1`] = ` "An export name cannot include a lone surrogate, found '\\ud83c'. (1:15) > 1 | export { b as "\\uD83C" } from "./foo"; @@ -335,3 +353,9 @@ exports[`snippet: #3 format[oxc-ts] 1`] = ` > 1 | export { b as "\\uD83C" } from "./foo"; | ^^^^^^^^" `; + +exports[`snippet: #3 format[yuku] 1`] = ` +"An export name cannot include a unicode lone surrogate (1:15) +> 1 | export { b as "\\uD83C" } from "./foo"; + | ^^^^^^^^" +`; diff --git a/tests/format/js/_errors_/export-name/format.test.js b/tests/format/js/_errors_/export-name/format.test.js index 23e2554a5..ba2a214c9 100644 --- a/tests/format/js/_errors_/export-name/format.test.js +++ b/tests/format/js/_errors_/export-name/format.test.js @@ -22,5 +22,6 @@ runFormatTest( "hermes", "oxc", "oxc-ts", + "yuku", ], ); diff --git a/tests/format/js/_errors_/newline-before-arrow/__snapshots__/format.test.js.snap b/tests/format/js/_errors_/newline-before-arrow/__snapshots__/format.test.js.snap index 3211fb430..7257e179a 100644 --- a/tests/format/js/_errors_/newline-before-arrow/__snapshots__/format.test.js.snap +++ b/tests/format/js/_errors_/newline-before-arrow/__snapshots__/format.test.js.snap @@ -79,3 +79,11 @@ exports[`newline-before-arrow.js format[typescript] 1`] = ` 3 | Cause: Unexpected keyword or identifier." `; + +exports[`newline-before-arrow.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found 'x' (1:7) +> 1 | async x + | ^ + 2 | => x + 3 |" +`; diff --git a/tests/format/js/_errors_/newline-before-arrow/format.test.js b/tests/format/js/_errors_/newline-before-arrow/format.test.js index c72ea76ae..acaca2d09 100644 --- a/tests/format/js/_errors_/newline-before-arrow/format.test.js +++ b/tests/format/js/_errors_/newline-before-arrow/format.test.js @@ -8,4 +8,5 @@ runFormatTest(import.meta, [ "meriyah", "babel-ts", "oxc", + "yuku", ]); diff --git a/tests/format/js/_errors_/reserved-word/__snapshots__/format.test.js.snap b/tests/format/js/_errors_/reserved-word/__snapshots__/format.test.js.snap index c36629144..716a50fea 100644 --- a/tests/format/js/_errors_/reserved-word/__snapshots__/format.test.js.snap +++ b/tests/format/js/_errors_/reserved-word/__snapshots__/format.test.js.snap @@ -84,6 +84,12 @@ exports[`snippet: #0 format[typescript] 1`] = ` Cause: Declaration or statement expected." `; +exports[`snippet: #0 format[yuku] 1`] = ` +"Keywords cannot contain escape characters (1:8) +> 1 | export asyn\\u{63} from "async"; + | ^^^^^^^^^^" +`; + exports[`snippet: #1 format[acorn] 1`] = ` "The keyword 'interface' is reserved (1:8) > 1 | import interface from "foo"; diff --git a/tests/format/js/_errors_/reserved-word/format.test.js b/tests/format/js/_errors_/reserved-word/format.test.js index 17103d170..6470110d0 100644 --- a/tests/format/js/_errors_/reserved-word/format.test.js +++ b/tests/format/js/_errors_/reserved-word/format.test.js @@ -36,5 +36,6 @@ runFormatTest( "hermes", "oxc", "oxc-ts", + "yuku", ], ); 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 3b1d5b90c..e0d8efced 100644 --- a/tests/format/js/arrows-bind/__snapshots__/format.test.js.snap +++ b/tests/format/js/arrows-bind/__snapshots__/format.test.js.snap @@ -55,3 +55,12 @@ exports[`arrows-bind.js format[oxc] 1`] = ` 3 | a::(b => c); 4 |" `; + +exports[`arrows-bind.js format[yuku] 1`] = ` +"Expected ',' or ')' in parenthesized expression, but found ':' (1:9) +> 1 | a => ({}::b()\`\`[''].c++ && 0 ? 0 : 0); + | ^ + 2 | (a => b)::c; + 3 | a::(b => c); + 4 |" +`; diff --git a/tests/format/js/arrows-bind/format.test.js b/tests/format/js/arrows-bind/format.test.js index c0a7f0191..524093664 100644 --- a/tests/format/js/arrows-bind/format.test.js +++ b/tests/format/js/arrows-bind/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: true, }, }); 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 90867e060..d1019081c 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 @@ -93,3 +93,12 @@ exports[`async-do-expressions.js format[oxc] 1`] = ` 3 | }; 4 |" `; + +exports[`async-do-expressions.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found 'do' (1:7) +> 1 | async do { + | ^^ + 2 | 1; + 3 | }; + 4 |" +`; diff --git a/tests/format/js/async-do-expressions/format.test.js b/tests/format/js/async-do-expressions/format.test.js index c0a7f0191..524093664 100644 --- a/tests/format/js/async-do-expressions/format.test.js +++ b/tests/format/js/async-do-expressions/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: 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 fa6c2a7b5..150f09c2a 100644 --- a/tests/format/js/babel-plugins/__snapshots__/format.test.js.snap +++ b/tests/format/js/babel-plugins/__snapshots__/format.test.js.snap @@ -46,6 +46,13 @@ exports[`async-do-expressions.js format[oxc] 1`] = ` 2 |" `; +exports[`async-do-expressions.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found 'do' (1:7) +> 1 | async do { await requestAPI().json() }; + | ^^ + 2 |" +`; + exports[`async-generators.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -681,6 +688,17 @@ exports[`destructuring-private.js format[oxc] 1`] = ` 8 | equals({ #x: otherX }) {" `; +exports[`destructuring-private.js format[yuku] 1`] = ` +"Unexpected token '#x' as property key (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[`discard-binding.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -725,6 +743,13 @@ exports[`discard-binding.js format[oxc] 1`] = ` 2 |" `; +exports[`discard-binding.js format[yuku] 1`] = ` +"Unexpected token ']' (1:15) +> 1 | const [a, void] = iter; + | ^ + 2 |" +`; + exports[`do-expressions.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -805,6 +830,17 @@ exports[`do-expressions.js format[oxc] 1`] = ` 6 | } else {" `; +exports[`do-expressions.js format[yuku] 1`] = ` +"'do' is reserved and cannot be used as an identifier (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[`dynamic-import.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -935,6 +971,15 @@ exports[`export-default-from.js format[oxc] 1`] = ` 5 |" `; +exports[`export-default-from.js format[yuku] 1`] = ` +"Expected declaration after 'export', but found 'v' (4:8) + 2 | + 3 | +> 4 | export v from 'mod'; + | ^ + 5 |" +`; + exports[`export-namespace-from.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1028,6 +1073,15 @@ exports[`flow.js format[oxc] 1`] = ` 4 |" `; +exports[`flow.js format[yuku] 1`] = ` +"Expected ')' to close parameter list, 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 format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1119,6 +1173,17 @@ exports[`function-bind.js format[oxc] 1`] = ` 6 |" `; +exports[`function-bind.js format[yuku] 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-sent.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1197,6 +1262,17 @@ exports[`function-sent.js format[oxc] 1`] = ` 7 |" `; +exports[`function-sent.js format[yuku] 1`] = ` +"Expected '(' to start parameter list, but found '.' (4:33) + 2 | + 3 | function* generator() { +> 4 | console.log("Sent", function.sent); + | ^ + 5 | console.log("Yield", yield); + 6 | } + 7 |" +`; + exports[`import-assertions-dynamic.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1391,6 +1467,15 @@ exports[`module-blocks.js format[oxc] 1`] = ` 4 | };" `; +exports[`module-blocks.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found '{' (1:16) +> 1 | let m = module { + | ^ + 2 | export let m = 2; + 3 | export let n = 3; + 4 | };" +`; + exports[`module-string-names.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1754,6 +1839,13 @@ exports[`optional-chaining-assignment.js format[oxc] 1`] = ` 2 |" `; +exports[`optional-chaining-assignment.js format[yuku] 1`] = ` +"Optional chaining is not allowed in assignment pattern (1:1) +> 1 | maybeAnObj?.prop = theValue; + | ^^^^^^^^^^^^^^^^ + 2 |" +`; + exports[`partial-application.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1854,6 +1946,17 @@ exports[`partial-application.js format[oxc] 1`] = ` 8 | const addTen = add(?, 10); // apply from the right" `; +exports[`partial-application.js format[yuku] 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[`pipeline-operator-fsharp.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -1975,6 +2078,17 @@ exports[`pipeline-operator-fsharp.js format[oxc] 1`] = ` 8 | |> x => x + '!'" `; +exports[`pipeline-operator-fsharp.js format[yuku] 1`] = ` +"Unexpected token '>' (5:4) + 3 | + 4 | promise +> 5 | |> await + | ^ + 6 | |> x => doubleSay(x, ', ') + 7 | |> capitalize + 8 | |> x => x + '!'" +`; + exports[`pipeline-operator-hack.cjs format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -2047,6 +2161,17 @@ exports[`pipeline-operator-hack.cjs format[oxc] 1`] = ` 8 | // (The % token isn't final; it might instead be @ or ? or #.)" `; +exports[`pipeline-operator-hack.cjs format[yuku] 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-minimal.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -2126,6 +2251,17 @@ exports[`pipeline-operator-minimal.js format[oxc] 1`] = ` 11 |" `; +exports[`pipeline-operator-minimal.js format[yuku] 1`] = ` +"Unexpected token '>' (8:4) + 6 | + 7 | let result = "hello" +> 8 | |> doubleSay + | ^ + 9 | |> capitalize + 10 | |> exclaim; + 11 |" +`; + exports[`private-fields-in-in.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -2433,6 +2569,17 @@ exports[`throw-expressions.js format[oxc] 1`] = ` 6 |" `; +exports[`throw-expressions.js format[yuku] 1`] = ` +"'throw' is reserved and cannot be used as an identifier (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[`typescript.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -2509,6 +2656,15 @@ exports[`typescript.js format[oxc] 1`] = ` 4 |" `; +exports[`typescript.js format[yuku] 1`] = ` +"'const' declarations must be initialized (3:7) + 1 | // https://babeljs.io/docs/babel-preset-typescript + 2 | +> 3 | const x: number = 0; + | ^ + 4 |" +`; + exports[`v8intrinsic.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-ts", "babel-flow"] @@ -2615,3 +2771,14 @@ exports[`v8intrinsic.js format[oxc] 1`] = ` 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[yuku] 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" +`; diff --git a/tests/format/js/babel-plugins/format.test.js b/tests/format/js/babel-plugins/format.test.js index 15206ad89..9a82e74ae 100644 --- a/tests/format/js/babel-plugins/format.test.js +++ b/tests/format/js/babel-plugins/format.test.js @@ -111,6 +111,25 @@ runFormatTest(import.meta, ["babel", "babel-ts", "babel-flow"], { "v8intrinsic.js", "discard-binding.js", ], + yuku: [ + "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.cjs", + "pipeline-operator-minimal.js", + "throw-expressions.js", + "typescript.js", + "v8intrinsic.js", + "discard-binding.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 2ab81eaed..57634a6bc 100644 --- a/tests/format/js/bind-expressions/__snapshots__/format.test.js.snap +++ b/tests/format/js/bind-expressions/__snapshots__/format.test.js.snap @@ -63,6 +63,16 @@ exports[`await.js - {"semi":false} format[oxc] 1`] = ` 5 |" `; +exports[`await.js - {"semi":false} format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found ':' (3:27) + 1 | const doBothThings = async () => { + 2 | const request = doAsyncThing(); +> 3 | return (await request)::doSyncThing(); + | ^ + 4 | }; + 5 |" +`; + exports[`await.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -125,6 +135,16 @@ exports[`await.js format[oxc] 1`] = ` 5 |" `; +exports[`await.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found ':' (3:27) + 1 | const doBothThings = async () => { + 2 | const request = doAsyncThing(); +> 3 | return (await request)::doSyncThing(); + | ^ + 4 | }; + 5 |" +`; + exports[`bind_parens.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -252,6 +272,15 @@ exports[`bind_parens.js - {"semi":false} format[oxc] 1`] = ` 4 | (void 0)::func();" `; +exports[`bind_parens.js - {"semi":false} format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found ':' (1:9) +> 1 | (a || b)::c; + | ^ + 2 | a || (b::c); + 3 | ::obj.prop; + 4 | (void 0)::func();" +`; + exports[`bind_parens.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -378,6 +407,15 @@ exports[`bind_parens.js format[oxc] 1`] = ` 4 | (void 0)::func();" `; +exports[`bind_parens.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found ':' (1:9) +> 1 | (a || b)::c; + | ^ + 2 | a || (b::c); + 3 | ::obj.prop; + 4 | (void 0)::func();" +`; + exports[`long_name_method.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -455,6 +493,17 @@ exports[`long_name_method.js - {"semi":false} format[oxc] 1`] = ` 6 | testLongNameMethodAndSomethingElseLallala() {" `; +exports[`long_name_method.js - {"semi":false} format[yuku] 1`] = ` +"Unexpected token ':' (3:54) + 1 | class X { + 2 | constructor() { +> 3 | this.testLongNameMethodAndSomethingElseLallala = ::this.testLongNameMethodAndSomethingElseLallala; + | ^ + 4 | } + 5 | + 6 | testLongNameMethodAndSomethingElseLallala() {" +`; + exports[`long_name_method.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -531,6 +580,17 @@ exports[`long_name_method.js format[oxc] 1`] = ` 6 | testLongNameMethodAndSomethingElseLallala() {" `; +exports[`long_name_method.js format[yuku] 1`] = ` +"Unexpected token ':' (3:54) + 1 | class X { + 2 | constructor() { +> 3 | this.testLongNameMethodAndSomethingElseLallala = ::this.testLongNameMethodAndSomethingElseLallala; + | ^ + 4 | } + 5 | + 6 | testLongNameMethodAndSomethingElseLallala() {" +`; + exports[`method_chain.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -624,6 +684,17 @@ exports[`method_chain.js - {"semi":false} format[oxc] 1`] = ` 13 | ::take(1)" `; +exports[`method_chain.js - {"semi":false} format[yuku] 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 format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -716,6 +787,17 @@ exports[`method_chain.js format[oxc] 1`] = ` 13 | ::take(1)" `; +exports[`method_chain.js format[yuku] 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[`short_name_method.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -792,6 +874,17 @@ exports[`short_name_method.js - {"semi":false} format[oxc] 1`] = ` 6 | shortMethod() {" `; +exports[`short_name_method.js - {"semi":false} format[yuku] 1`] = ` +"Unexpected token ':' (3:24) + 1 | class X { + 2 | constructor() { +> 3 | this.shortMethod = ::this.shortMethod; + | ^ + 4 | } + 5 | + 6 | shortMethod() {" +`; + exports[`short_name_method.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -867,6 +960,17 @@ exports[`short_name_method.js format[oxc] 1`] = ` 6 | shortMethod() {" `; +exports[`short_name_method.js format[yuku] 1`] = ` +"Unexpected token ':' (3:24) + 1 | class X { + 2 | constructor() { +> 3 | this.shortMethod = ::this.shortMethod; + | ^ + 4 | } + 5 | + 6 | shortMethod() {" +`; + exports[`unary.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -946,6 +1050,15 @@ exports[`unary.js - {"semi":false} format[oxc] 1`] = ` 4 | !(" `; +exports[`unary.js - {"semi":false} format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found ':' (1:3) +> 1 | !x::y; + | ^ + 2 | !(x::y /* foo */); + 3 | !(/* foo */ x::y); + 4 | !(" +`; + exports[`unary.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -1023,3 +1136,12 @@ exports[`unary.js format[oxc] 1`] = ` 3 | !(/* foo */ x::y); 4 | !(" `; + +exports[`unary.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found ':' (1:3) +> 1 | !x::y; + | ^ + 2 | !(x::y /* foo */); + 3 | !(/* foo */ x::y); + 4 | !(" +`; diff --git a/tests/format/js/bind-expressions/format.test.js b/tests/format/js/bind-expressions/format.test.js index ab36700a0..c3db9dce6 100644 --- a/tests/format/js/bind-expressions/format.test.js +++ b/tests/format/js/bind-expressions/format.test.js @@ -4,6 +4,7 @@ const errors = { meriyah: true, oxc: true, "oxc-ts": true, + yuku: true, }; runFormatTest(import.meta, ["babel"], { errors }); 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 0c8b4d186..e0c704788 100644 --- a/tests/format/js/call/invalid/__snapshots__/format.test.js.snap +++ b/tests/format/js/call/invalid/__snapshots__/format.test.js.snap @@ -58,3 +58,12 @@ exports[`null-arguments-item.js format[oxc] 1`] = ` 3 | foo("a", 4 | //1" `; + +exports[`null-arguments-item.js format[yuku] 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 e3c45792c..ecb097c05 100644 --- a/tests/format/js/call/invalid/format.test.js +++ b/tests/format/js/call/invalid/format.test.js @@ -7,5 +7,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: 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 4624ffd56..7e714e1b3 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 @@ -133,3 +133,14 @@ exports[`pipeline_own_line.js format[oxc] 1`] = ` 6 | 7 | bifornCringerMoshedPerplexSawder(" `; + +exports[`pipeline_own_line.js format[yuku] 1`] = ` +"Unexpected token '>' (4:3) + 2 | 0 + 3 | // Comment +> 4 | |> x + | ^ + 5 | } + 6 | + 7 | bifornCringerMoshedPerplexSawder(" +`; 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 c0a7f0191..524093664 100644 --- a/tests/format/js/comments-pipeline-own-line/format.test.js +++ b/tests/format/js/comments-pipeline-own-line/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: 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 03f0cfec8..737bca20e 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 @@ -195,6 +195,13 @@ exports[`no-default.js format[oxc] 1`] = ` 2 |" `; +exports[`no-default.js format[yuku] 1`] = ` +"'import defer' only supports a namespace import (1:8) +> 1 | import defer x from "x"; + | ^^^^^ + 2 |" +`; + exports[`no-named.js format[__babel_estree] 1`] = ` "Only \`import defer * as x from "./module"\` is valid. (1:16) > 1 | import defer { x } from "x"; @@ -241,3 +248,10 @@ exports[`no-named.js format[oxc] 1`] = ` | ^^^^^ 2 |" `; + +exports[`no-named.js format[yuku] 1`] = ` +"Expected 'from' after import clause, 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 d3fc06873..e68d54a52 100644 --- a/tests/format/js/deferred-import-evaluation/format.test.js +++ b/tests/format/js/deferred-import-evaluation/format.test.js @@ -13,6 +13,7 @@ runFormatTest(import.meta, ["babel"], { meriyah: [...importDeferTests, ...invalidSyntaxTests], oxc: invalidSyntaxTests, "oxc-ts": invalidSyntaxTests, + yuku: ["dynamic-import-attributes-expression.js", ...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 21b406e0e..ce8e54592 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 @@ -62,6 +62,16 @@ exports[`arrow-params.js format[oxc] 1`] = ` 5 |" `; +exports[`arrow-params.js format[yuku] 1`] = ` +"Unexpected token '#x' as property key (3:11) + 1 | class C { + 2 | #x = 1; +> 3 | #p = ({ #x: x }) => {} + | ^^ + 4 | } + 5 |" +`; + exports[`assignment.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -134,6 +144,17 @@ exports[`assignment.js format[oxc] 1`] = ` 8 |" `; +exports[`assignment.js format[yuku] 1`] = ` +"Unexpected token '#x' as property key (5:8) + 3 | m() { + 4 | let x; +> 5 | ({ #x: x } = this); + | ^^ + 6 | } + 7 | } + 8 |" +`; + exports[`async-arrow-params.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -196,6 +217,16 @@ exports[`async-arrow-params.js format[oxc] 1`] = ` 5 |" `; +exports[`async-arrow-params.js format[yuku] 1`] = ` +"Unexpected token '#x' as property key (3:17) + 1 | class C { + 2 | #x = 1; +> 3 | #p = async ({ #x: x }) => {} + | ^^ + 4 | } + 5 |" +`; + exports[`bindings.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -266,6 +297,17 @@ exports[`bindings.js format[oxc] 1`] = ` 7 |" `; +exports[`bindings.js format[yuku] 1`] = ` +"Unexpected token '#x' as property key (4:12) + 2 | #x = 1; + 3 | m() { +> 4 | const {#x: x} = this; + | ^^ + 5 | } + 6 | } + 7 |" +`; + exports[`for-lhs.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -338,6 +380,17 @@ exports[`for-lhs.js format[oxc] 1`] = ` 8 |" `; +exports[`for-lhs.js format[yuku] 1`] = ` +"Unexpected token '#x' as property key (5:11) + 3 | m() { + 4 | let x; +> 5 | for ({#x: x} of [this]); + | ^^ + 6 | } + 7 | } + 8 |" +`; + exports[`nested-bindings.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -413,6 +466,17 @@ exports[`nested-bindings.js format[oxc] 1`] = ` 7 |" `; +exports[`nested-bindings.js format[yuku] 1`] = ` +"Unexpected token '#x' as property key (4:17) + 2 | #x = 1; + 3 | m() { +> 4 | const {x: { #x: [x] }, y: [...{ #x: y }]} = this; + | ^^ + 5 | } + 6 | } + 7 |" +`; + exports[`valid-multiple-bindings.js format 1`] = ` ====================================options===================================== parsers: ["babel", "babel-flow", "babel-ts"] @@ -482,3 +546,14 @@ exports[`valid-multiple-bindings.js format[oxc] 1`] = ` 6 | } 7 |" `; + +exports[`valid-multiple-bindings.js format[yuku] 1`] = ` +"Unexpected token '#x' as property key (4:12) + 2 | #x = 1; + 3 | m() { +> 4 | const {#x: x1, #x: x2 = x1 } = this; + | ^^ + 5 | } + 6 | } + 7 |" +`; diff --git a/tests/format/js/destructuring-private-fields/format.test.js b/tests/format/js/destructuring-private-fields/format.test.js index 9ba1253eb..f24a80b3b 100644 --- a/tests/format/js/destructuring-private-fields/format.test.js +++ b/tests/format/js/destructuring-private-fields/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel", "babel-flow", "babel-ts"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: true, }, }); diff --git a/tests/format/js/discard-binding/__snapshots__/format.test.js.snap b/tests/format/js/discard-binding/__snapshots__/format.test.js.snap index 0a6bc8d9a..a08ec17c2 100644 --- a/tests/format/js/discard-binding/__snapshots__/format.test.js.snap +++ b/tests/format/js/discard-binding/__snapshots__/format.test.js.snap @@ -180,6 +180,17 @@ exports[`array-pattern.js format[typescript] 1`] = ` Cause: Array element destructuring pattern expected." `; +exports[`array-pattern.js format[yuku] 1`] = ` +"Unexpected token ',' (3:16) + 1 | { + 2 | // destructuring binding +> 3 | const [, void, ] = value; + | ^ + 4 | } + 5 | { + 6 | // for-of destructuring binding" +`; + exports[`basic.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -285,6 +296,15 @@ exports[`basic.js format[typescript] 1`] = ` Cause: Array element destructuring pattern expected." `; +exports[`basic.js format[yuku] 1`] = ` +"Unexpected token ']' (1:12) +> 1 | const [void] = [,void] = [void,] = []; + | ^ + 2 | + 3 | function f(void, { p: void }, [ void ]) {} + 4 |" +`; + exports[`discard-binding-arrow-params.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -362,6 +382,13 @@ exports[`discard-binding-arrow-params.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`discard-binding-arrow-params.js format[yuku] 1`] = ` +"Unexpected token ')' (1:6) +> 1 | (void) => {} + | ^ + 2 |" +`; + exports[`discard-binding-assignment.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -439,6 +466,13 @@ exports[`discard-binding-assignment.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`discard-binding-assignment.js format[yuku] 1`] = ` +"Unexpected token ']' (1:7) +> 1 | ([void] = []); + | ^ + 2 |" +`; + exports[`discard-binding-async-arrow-params.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -516,6 +550,13 @@ exports[`discard-binding-async-arrow-params.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`discard-binding-async-arrow-params.js format[yuku] 1`] = ` +"Unexpected token ')' (1:12) +> 1 | async (void) => {} + | ^ + 2 |" +`; + exports[`discard-binding-bindings.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -593,6 +634,13 @@ exports[`discard-binding-bindings.js format[typescript] 1`] = ` Cause: Identifier expected. 'void' is a reserved word that cannot be used here." `; +exports[`discard-binding-bindings.js format[yuku] 1`] = ` +"Unexpected token '}' (1:17) +> 1 | const { p: void } = {}; + | ^ + 2 |" +`; + exports[`discard-binding-for-await-using-binding.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -690,6 +738,15 @@ exports[`discard-binding-for-await-using-binding.js format[typescript] 1`] = ` Cause: ';' expected." `; +exports[`discard-binding-for-await-using-binding.js format[yuku] 1`] = ` +"'void' is reserved and cannot be used as a binding identifier (2:19) + 1 | async () => { +> 2 | for(await using void of []); + | ^^^^ + 3 | } + 4 |" +`; + exports[`discard-binding-for-bindings.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -767,6 +824,13 @@ exports[`discard-binding-for-bindings.js format[typescript] 1`] = ` Cause: Identifier expected. 'void' is a reserved word that cannot be used here." `; +exports[`discard-binding-for-bindings.js format[yuku] 1`] = ` +"Unexpected token '}' (1:21) +> 1 | for(const { p: void } of []); + | ^ + 2 |" +`; + exports[`discard-binding-for-lhs.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -844,6 +908,13 @@ exports[`discard-binding-for-lhs.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`discard-binding-for-lhs.js format[yuku] 1`] = ` +"Unexpected token '}' (1:15) +> 1 | for({ p: void } of []); + | ^ + 2 |" +`; + exports[`discard-binding-for-using-binding.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -937,6 +1008,15 @@ exports[`discard-binding-for-using-binding.js format[typescript] 1`] = ` Cause: ';' expected." `; +exports[`discard-binding-for-using-binding.js format[yuku] 1`] = ` +"'void' is reserved and cannot be used as a binding identifier (2:13) + 1 | { +> 2 | for(using void of []); + | ^^^^ + 3 | } + 4 |" +`; + exports[`function-parameter.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1086,6 +1166,17 @@ exports[`function-parameter.js format[typescript] 1`] = ` Cause: Identifier expected. 'void' is a reserved word that cannot be used here." `; +exports[`function-parameter.js format[yuku] 1`] = ` +"'void' is reserved and cannot be used as a binding identifier (3:14) + 1 | { + 2 | // function parameter +> 3 | function f(void) {} + | ^^^^ + 4 | } + 5 | { + 6 | // arrow function parameter" +`; + exports[`object-pattern.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1284,6 +1375,17 @@ exports[`object-pattern.js format[typescript] 1`] = ` Cause: Identifier expected. 'void' is a reserved word that cannot be used here." `; +exports[`object-pattern.js format[yuku] 1`] = ` +"Unexpected token '}' (3:22) + 1 | { + 2 | // destructuring binding +> 3 | const { void: void } = value; + | ^ + 4 | } + 5 | { + 6 | // for-of destructuring binding" +`; + exports[`unary-expression-void.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1425,6 +1527,17 @@ exports[`unary-expression-void.js format[typescript] 1`] = ` Cause: Expression expected." `; +exports[`unary-expression-void.js format[yuku] 1`] = ` +"Unexpected token ']' (4:10) + 2 | void [ + 3 | // pattern +> 4 | [ void ] = [{ + | ^ + 5 | // expr + 6 | [ void [] ]: + 7 | // pattern" +`; + exports[`using.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1536,6 +1649,16 @@ exports[`using.js format[typescript] 1`] = ` Cause: Unexpected keyword or identifier." `; +exports[`using.js format[yuku] 1`] = ` +"'void' is reserved and cannot be used as a binding identifier (2:9) + 1 | { +> 2 | using void = f(); + | ^^^^ + 3 | } + 4 | async (void) => { + 5 | await using void = f();" +`; + exports[`using-variable-declarator.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1714,3 +1837,14 @@ exports[`using-variable-declarator.js format[typescript] 1`] = ` 6 | // using 2 declarators Cause: Unexpected keyword or identifier." `; + +exports[`using-variable-declarator.js format[yuku] 1`] = ` +"'void' is reserved and cannot be used as a binding identifier (3:9) + 1 | { + 2 | // using 1 declarator +> 3 | using void = f(); + | ^^^^ + 4 | } + 5 | { + 6 | // using 2 declarators" +`; diff --git a/tests/format/js/discard-binding/format.test.js b/tests/format/js/discard-binding/format.test.js index 30ab92f0a..bf56b0c11 100644 --- a/tests/format/js/discard-binding/format.test.js +++ b/tests/format/js/discard-binding/format.test.js @@ -7,6 +7,7 @@ runFormatTest(import.meta, ["babel", "flow", "typescript"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: true, hermes: true, }, }); diff --git a/tests/format/js/do/__snapshots__/format.test.js.snap b/tests/format/js/do/__snapshots__/format.test.js.snap index ec3658cc3..2e8132a43 100644 --- a/tests/format/js/do/__snapshots__/format.test.js.snap +++ b/tests/format/js/do/__snapshots__/format.test.js.snap @@ -132,6 +132,17 @@ exports[`call-arguments.js format[oxc] 1`] = ` 6 | "unreachable"" `; +exports[`call-arguments.js format[yuku] 1`] = ` +"'do' is reserved and cannot be used as an identifier (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[`do.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -328,3 +339,14 @@ exports[`do.js format[oxc] 1`] = ` 5 | else if(env === 'development') 'http://localhost:4000'; 6 | }" `; + +exports[`do.js format[yuku] 1`] = ` +"'do' is reserved and cannot be used as an identifier (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 | }" +`; diff --git a/tests/format/js/do/format.test.js b/tests/format/js/do/format.test.js index c0a7f0191..524093664 100644 --- a/tests/format/js/do/format.test.js +++ b/tests/format/js/do/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: 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 32313b843..cb6ace946 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 @@ -235,6 +235,16 @@ async function f() { ================================================================================ `; +exports[`valid-await-expr-using.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found '+' (3:17) + 1 | async function f() { + 2 | await using[x]; +> 3 | await using.x + await using(x) ? await using?.x : await using\`x\`; + | ^ + 4 | } + 5 |" +`; + exports[`valid-await-expr-using-in.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -264,6 +274,15 @@ Cause: 'identifier' expected in declaration (2:14) ~~~~~~~~~~~~^" `; +exports[`valid-await-expr-using-in.js format[yuku] 1`] = ` +"'in' is reserved and cannot be used as a binding identifier (2:15) + 1 | async function f() { +> 2 | await using in foo; + | ^^ + 3 | } + 4 |" +`; + exports[`valid-await-expr-using-instanceof.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -293,6 +312,15 @@ Cause: 'identifier' expected in declaration (2:14) ~~~~~~~~~~~~^" `; +exports[`valid-await-expr-using-instanceof.js format[yuku] 1`] = ` +"'instanceof' is reserved and cannot be used as a binding identifier (2:15) + 1 | async function f() { +> 2 | await using instanceof foo; + | ^^^^^^^^^^ + 3 | } + 4 |" +`; + exports[`valid-await-using-asi-assignment.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -761,6 +789,15 @@ exports[`valid-module-block-top-level-await-using-binding.js format[typescript] Cause: ',' expected." `; +exports[`valid-module-block-top-level-await-using-binding.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found '{' (1:18) +> 1 | const m = module { + | ^ + 2 | await using foo = bar(); + 3 | } + 4 |" +`; + exports[`valid-module-block-top-level-using-binding.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -858,6 +895,15 @@ exports[`valid-module-block-top-level-using-binding.js format[typescript] 1`] = Cause: Namespace must be given a name." `; +exports[`valid-module-block-top-level-using-binding.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found '{' (1:8) +> 1 | module { + | ^ + 2 | using foo = bar(); + 3 | } + 4 |" +`; + exports[`valid-using-as-identifier-computed-member.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -946,6 +992,15 @@ exports[`valid-using-as-identifier-for-in.js format[hermes] 1`] = ` Cause: Failed to parse source" `; +exports[`valid-using-as-identifier-for-in.js format[yuku] 1`] = ` +"Unexpected token '\`\`' in binding pattern (4:11) + 2 | for (using.foo in []); + 3 | for (using().foo in []); +> 4 | for (using\`\`.foo in []); + | ^^ + 5 |" +`; + exports[`valid-using-as-identifier-for-init.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -961,6 +1016,15 @@ for (using; (reader = getReader());); ================================================================================ `; +exports[`valid-using-as-identifier-for-init.js format[yuku] 1`] = ` +"Unexpected token ';' in binding pattern (2:8) + 1 | for ( +> 2 | using; + | ^ + 3 | reader = getReader();); + 4 |" +`; + exports[`valid-using-as-identifier-for-of.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -980,6 +1044,15 @@ for (using\`\`.foo of of); ================================================================================ `; +exports[`valid-using-as-identifier-for-of.js format[yuku] 1`] = ` +"Unexpected token '\`\`' in binding pattern (4:11) + 2 | for (using.foo of of); + 3 | for (using().foo of of); +> 4 | for (using\`\`.foo of of); + | ^^ + 5 |" +`; + exports[`valid-using-as-identifier-in.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -1003,6 +1076,13 @@ using in using instanceof using; ~~~~~~^" `; +exports[`valid-using-as-identifier-in.js format[yuku] 1`] = ` +"'in' is reserved and cannot be used as a binding identifier (1:7) +> 1 | using in using instanceof using; + | ^^ + 2 |" +`; + exports[`valid-using-binding-basic.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 f82a6d56c..e6eb3596d 100644 --- a/tests/format/js/explicit-resource-management/format.test.js +++ b/tests/format/js/explicit-resource-management/format.test.js @@ -94,5 +94,18 @@ runFormatTest(import.meta, ["babel", "flow", "typescript"], { "valid-module-block-top-level-using-binding.js", "valid-module-block-top-level-await-using-binding.js", ], + yuku: [ + // "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-await-expr-using-in.js", + "valid-await-expr-using-instanceof.js", + "valid-await-expr-using.js", + "valid-using-as-identifier-for-in.js", + "valid-using-as-identifier-for-init.js", + "valid-using-as-identifier-for-of.js", + "valid-using-as-identifier-in.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 e7a8436a5..0429f6d08 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 @@ -62,3 +62,10 @@ exports[`default-escaped.js format[oxc] 1`] = ` > 2 | export n\\u{63} from "async"; | ^^^^^^^" `; + +exports[`default-escaped.js format[yuku] 1`] = ` +"Expected declaration after 'export', but found 'n\\u{63}' (2:8) + 1 | // export asyn\\u{63} from "async"; +> 2 | export n\\u{63} from "async"; + | ^^^^^^^" +`; diff --git a/tests/format/js/export-default/escaped/format.test.js b/tests/format/js/export-default/escaped/format.test.js index 8461922b9..235b0635f 100644 --- a/tests/format/js/export-default/escaped/format.test.js +++ b/tests/format/js/export-default/escaped/format.test.js @@ -7,5 +7,6 @@ runFormatTest(import.meta, ["babel", "flow"], { hermes: true, oxc: true, "oxc-ts": true, + yuku: 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 0f4433352..0abe00ddc 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 @@ -72,3 +72,13 @@ exports[`export.js format[oxc] 1`] = ` 4 | export c, { foo } from 'mod'; 5 | export * as d from 'mod';" `; + +exports[`export.js format[yuku] 1`] = ` +"Expected declaration after 'export', but found 'v' (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';" +`; 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 c0a7f0191..524093664 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 @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: true, }, }); diff --git a/tests/format/js/for/__snapshots__/format.test.js.snap b/tests/format/js/for/__snapshots__/format.test.js.snap index e02440793..a03a15e6f 100644 --- a/tests/format/js/for/__snapshots__/format.test.js.snap +++ b/tests/format/js/for/__snapshots__/format.test.js.snap @@ -917,6 +917,17 @@ exports[`for-in-with-initializer.js format[typescript] 1`] = ` Cause: ',' expected." `; +exports[`for-in-with-initializer.js format[yuku] 1`] = ` +"Expected ';' after for-loop init, but found ')' (4:33) + 2 | + 3 | for (var a = (b in c) in {}); +> 4 | for (var a = 1 || (b in c) in {}); + | ^ + 5 | for (var a = 1 + (2 || (b in c)) in {}); + 6 | for (var a = (() => b in c) in {}); + 7 | for (var a = 1 || (() => b in c) in {});" +`; + exports[`in.js format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] diff --git a/tests/format/js/for/format.test.js b/tests/format/js/for/format.test.js index 441b72f6d..83397493d 100644 --- a/tests/format/js/for/format.test.js +++ b/tests/format/js/for/format.test.js @@ -2,5 +2,6 @@ runFormatTest(import.meta, ["babel", "flow", "typescript"], { errors: { flow: ["parentheses.js", "for-in-with-initializer.js"], typescript: ["parentheses.js", "for-in-with-initializer.js"], + yuku: ["for-in-with-initializer.js"], }, }); diff --git a/tests/format/js/identifier/parentheses/__snapshots__/format.test.js.snap b/tests/format/js/identifier/parentheses/__snapshots__/format.test.js.snap index b20bf4868..cb3366211 100644 --- a/tests/format/js/identifier/parentheses/__snapshots__/format.test.js.snap +++ b/tests/format/js/identifier/parentheses/__snapshots__/format.test.js.snap @@ -252,6 +252,15 @@ a[1] + (let[2] = 2) ================================================================================ `; +exports[`let.js - {"semi":false} format[yuku] 1`] = ` +"Unexpected token '.' in binding pattern (1:4) +> 1 | let.a = 1; + | ^ + 2 | + 3 | let.a[0] = 1; + 4 |" +`; + exports[`let.js format 1`] = ` ====================================options===================================== parsers: ["babel", "typescript"] @@ -475,3 +484,12 @@ a[1] + (let[2] = 2); ================================================================================ `; + +exports[`let.js format[yuku] 1`] = ` +"Unexpected token '.' in binding pattern (1:4) +> 1 | let.a = 1; + | ^ + 2 | + 3 | let.a[0] = 1; + 4 |" +`; diff --git a/tests/format/js/identifier/parentheses/format.test.js b/tests/format/js/identifier/parentheses/format.test.js index ed93e5ed0..9c7fe1d55 100644 --- a/tests/format/js/identifier/parentheses/format.test.js +++ b/tests/format/js/identifier/parentheses/format.test.js @@ -1,8 +1,14 @@ -runFormatTest(import.meta, [ - "babel", - // "flow", - "typescript", -]); +const errors = { yuku: ["let.js"] }; + +runFormatTest( + import.meta, + [ + "babel", + // "flow", + "typescript", + ], + { errors }, +); runFormatTest( import.meta, [ @@ -10,5 +16,5 @@ runFormatTest( // "flow", "typescript", ], - { semi: false }, + { semi: false, errors }, ); diff --git a/tests/format/js/import-assertions/__snapshots__/format.test.js.snap b/tests/format/js/import-assertions/__snapshots__/format.test.js.snap index a2c7c8efa..964a79d3f 100644 --- a/tests/format/js/import-assertions/__snapshots__/format.test.js.snap +++ b/tests/format/js/import-assertions/__snapshots__/format.test.js.snap @@ -2,7 +2,7 @@ exports[`dynamic-import.js format 1`] = ` ====================================options===================================== -parsers: ["oxc", "typescript", "hermes"] +parsers: ["oxc", "yuku", "typescript", "hermes"] printWidth: 80 (default) | =====================================input====================================== import("./foo.json", { assert: { type: "json" } }); @@ -15,7 +15,7 @@ import("./foo.json", { assert: { type: "json" } }); exports[`empty.js format 1`] = ` ====================================options===================================== -parsers: ["oxc", "typescript", "hermes"] +parsers: ["oxc", "yuku", "typescript", "hermes"] printWidth: 80 (default) | =====================================input====================================== export * as foo from "foo.json" @@ -63,7 +63,7 @@ export * as bar from "bar.json" assert { } exports[`keyword-detect.js format 1`] = ` ====================================options===================================== -parsers: ["oxc", "typescript", "hermes"] +parsers: ["oxc", "yuku", "typescript", "hermes"] printWidth: 80 (default) | =====================================input====================================== import "./test.json" /* with */ assert /* with */ { type: "json" } @@ -108,7 +108,7 @@ import "./test.json" /* with */ assert /* with */ { type: "json" } exports[`multi-types.js format 1`] = ` ====================================options===================================== -parsers: ["oxc", "typescript", "hermes"] +parsers: ["oxc", "yuku", "typescript", "hermes"] printWidth: 80 (default) | =====================================input====================================== import json from "./foo.json" assert { type: "json", type: "bar" }; @@ -139,7 +139,7 @@ import json from "./foo.json" assert { type: "json", type: "bar" }; exports[`non-type.js format 1`] = ` ====================================options===================================== -parsers: ["oxc", "typescript", "hermes"] +parsers: ["oxc", "yuku", "typescript", "hermes"] printWidth: 80 (default) | =====================================input====================================== import foo from "foo.json" assert { lazy: "true" }; @@ -170,7 +170,7 @@ import foo from "foo.json" assert { lazy: "true" }; exports[`not-import-assertions.js format 1`] = ` ====================================options===================================== -parsers: ["oxc", "typescript", "hermes"] +parsers: ["oxc", "yuku", "typescript", "hermes"] printWidth: 80 (default) | =====================================input====================================== import "x" @@ -185,7 +185,7 @@ assert({ type: "json" }); exports[`re-export.js format 1`] = ` ====================================options===================================== -parsers: ["oxc", "typescript", "hermes"] +parsers: ["oxc", "yuku", "typescript", "hermes"] printWidth: 80 (default) | =====================================input====================================== export { default as foo2 } from "foo.json" assert { type: "json" }; @@ -224,7 +224,7 @@ export { default as foo2 } from "foo.json" assert { type: "json" }; exports[`static-import.js format 1`] = ` ====================================options===================================== -parsers: ["oxc", "typescript", "hermes"] +parsers: ["oxc", "yuku", "typescript", "hermes"] printWidth: 80 (default) | =====================================input====================================== import json from "./foo.json" assert { type: "json" }; @@ -255,7 +255,7 @@ import json from "./foo.json" assert { type: "json" }; exports[`without-from.js format 1`] = ` ====================================options===================================== -parsers: ["oxc", "typescript", "hermes"] +parsers: ["oxc", "yuku", "typescript", "hermes"] printWidth: 80 (default) | =====================================input====================================== import "foo" assert { type: "json" } diff --git a/tests/format/js/import-assertions/format.test.js b/tests/format/js/import-assertions/format.test.js index 78b016bd8..af5ef50cd 100644 --- a/tests/format/js/import-assertions/format.test.js +++ b/tests/format/js/import-assertions/format.test.js @@ -1,4 +1,4 @@ -runFormatTest(import.meta, ["oxc", "typescript", "hermes"], { +runFormatTest(import.meta, ["oxc", "yuku", "typescript", "hermes"], { errors: { "babel-ts": [ "empty.js", 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 1282bd018..6963e1470 100644 --- a/tests/format/js/module-blocks/__snapshots__/format.test.js.snap +++ b/tests/format/js/module-blocks/__snapshots__/format.test.js.snap @@ -71,6 +71,15 @@ exports[`comments.js format[oxc] 1`] = ` 4 | export { foo }; /*A5*/" `; +exports[`comments.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found '{' (1:32) +> 1 | const m = /*A1*/ module /*A2*/ { /*A3*/ + | ^ + 2 | /*A4*/ + 3 | export const foo = "foo"; + 4 | export { foo }; /*A5*/" +`; + exports[`module-blocks.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -209,6 +218,15 @@ exports[`module-blocks.js format[oxc] 1`] = ` 4 | #p() {" `; +exports[`module-blocks.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found '{' (1:8) +> 1 | module { await 3 }; + | ^ + 2 | + 3 | class B { + 4 | #p() {" +`; + exports[`non-module-blocks.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -291,3 +309,12 @@ exports[`range.js format[oxc] 1`] = ` 3 | 4 | foo(module { export let foo = "foo"; })" `; + +exports[`range.js format[yuku] 1`] = ` +"Expected a semicolon or an implicit semicolon after a statement, but found '{' (1:26) +> 1 | let moduleBlock = module { export let y = 1; + | ^ + 2 | }; + 3 | + 4 | foo(module { export let foo = "foo"; })" +`; diff --git a/tests/format/js/module-blocks/format.test.js b/tests/format/js/module-blocks/format.test.js index 25579dd12..4e7e87e56 100644 --- a/tests/format/js/module-blocks/format.test.js +++ b/tests/format/js/module-blocks/format.test.js @@ -4,6 +4,7 @@ const errors = { meriyah: ["module-blocks.js", "range.js", "comments.js"], oxc: ["module-blocks.js", "range.js", "comments.js"], "oxc-ts": ["module-blocks.js", "range.js", "comments.js"], + yuku: ["module-blocks.js", "range.js", "comments.js"], }; runFormatTest(import.meta, ["babel"], { errors }); diff --git a/tests/format/js/module-blocks/quote-props/__snapshots__/format.test.js.snap b/tests/format/js/module-blocks/quote-props/__snapshots__/format.test.js.snap index 8b0f9f7de..32f59818b 100644 --- a/tests/format/js/module-blocks/quote-props/__snapshots__/format.test.js.snap +++ b/tests/format/js/module-blocks/quote-props/__snapshots__/format.test.js.snap @@ -134,3 +134,12 @@ exports[`worker.js format[oxc] 1`] = ` 3 | let mod = import(data); 4 | postMessage(mod.fn());" `; + +exports[`worker.js format[yuku] 1`] = ` +"Expected ')' after constructor arguments, but found '{' (1:28) +> 1 | worker = new Worker(module { + | ^ + 2 | onmessage = function({data}) { + 3 | let mod = import(data); + 4 | postMessage(mod.fn());" +`; diff --git a/tests/format/js/module-blocks/quote-props/format.test.js b/tests/format/js/module-blocks/quote-props/format.test.js index 67806e922..d801b8e10 100644 --- a/tests/format/js/module-blocks/quote-props/format.test.js +++ b/tests/format/js/module-blocks/quote-props/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: ["worker.js"], oxc: ["worker.js"], "oxc-ts": ["worker.js"], + yuku: ["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 62b5bcd4e..c2dd4af4f 100644 --- a/tests/format/js/multiparser-invalid/__snapshots__/format.test.js.snap +++ b/tests/format/js/multiparser-invalid/__snapshots__/format.test.js.snap @@ -166,3 +166,14 @@ exports[`text.js format[typescript] 1`] = ` 9 | foo = foo\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; Cause: Hexadecimal digit expected." `; + +exports[`text.js format[yuku] 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\`;" +`; diff --git a/tests/format/js/multiparser-invalid/format.test.js b/tests/format/js/multiparser-invalid/format.test.js index 952dda85b..8b61b8bb5 100644 --- a/tests/format/js/multiparser-invalid/format.test.js +++ b/tests/format/js/multiparser-invalid/format.test.js @@ -8,5 +8,6 @@ runFormatTest(import.meta, ["babel", "flow", "typescript"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: 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 56784ead4..6ff65b1dd 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 @@ -77,6 +77,16 @@ exports[`no-semi.js - {"semi":false} format[oxc] 1`] = ` 5 | a = b;" `; +exports[`no-semi.js - {"semi":false} format[yuku] 1`] = ` +"Unexpected token ':' (2:2) + 1 | a +> 2 | ;::b.c + | ^ + 3 | + 4 | class A { + 5 | a = b;" +`; + exports[`no-semi.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -152,3 +162,13 @@ exports[`no-semi.js format[oxc] 1`] = ` 4 | class A { 5 | a = b;" `; + +exports[`no-semi.js format[yuku] 1`] = ` +"Unexpected token ':' (2:2) + 1 | a +> 2 | ;::b.c + | ^ + 3 | + 4 | class A { + 5 | a = b;" +`; 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 ad763c739..afc2ac877 100644 --- a/tests/format/js/no-semi-babylon-extensions/format.test.js +++ b/tests/format/js/no-semi-babylon-extensions/format.test.js @@ -4,6 +4,7 @@ const errors = { meriyah: true, oxc: true, "oxc-ts": true, + yuku: true, }; runFormatTest(import.meta, ["babel"], { errors }); runFormatTest(import.meta, ["babel"], { semi: false, errors }); diff --git a/tests/format/js/objects/__snapshots__/format.test.js.snap b/tests/format/js/objects/__snapshots__/format.test.js.snap index f97f22a68..aba2b8696 100644 --- a/tests/format/js/objects/__snapshots__/format.test.js.snap +++ b/tests/format/js/objects/__snapshots__/format.test.js.snap @@ -223,6 +223,17 @@ exports[`expression.js format[typescript] 1`] = ` Cause: ')' expected." `; +exports[`expression.js format[yuku] 1`] = ` +"Expected ',' or ')' in parenthesized expression, 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[`getter-setter.js format 1`] = ` ====================================options===================================== parsers: ["babel", "typescript", "flow"] diff --git a/tests/format/js/objects/format.test.js b/tests/format/js/objects/format.test.js index ffe8bd411..75ee1c077 100644 --- a/tests/format/js/objects/format.test.js +++ b/tests/format/js/objects/format.test.js @@ -6,6 +6,7 @@ runFormatTest(import.meta, ["babel", "typescript", "flow"], { meriyah: ["expression.js"], oxc: ["expression.js"], "oxc-ts": ["expression.js"], + yuku: ["expression.js"], flow: ["expression.js"], hermes: ["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 24caadf30..29d6ef3ed 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 @@ -47,6 +47,13 @@ exports[`invalid-destructuring-arr.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-destructuring-arr.js format[yuku] 1`] = ` +"Optional chaining is not allowed in assignment pattern (1:2) +> 1 | [a?.b] = []; + | ^^^^ + 2 |" +`; + exports[`invalid-destructuring-obj.js format[__babel_estree] 1`] = ` "Invalid optional chaining in the left-hand side of object destructuring pattern. (1:10) > 1 | ({ prop: a?.b } = {}); @@ -94,6 +101,13 @@ exports[`invalid-destructuring-obj.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-destructuring-obj.js format[yuku] 1`] = ` +"Optional chaining is not allowed in assignment pattern (1:10) +> 1 | ({ prop: a?.b } = {}); + | ^^^^ + 2 |" +`; + exports[`invalid-fn-param.js format[__babel_estree] 1`] = ` "Unexpected token, expected "," (1:13) > 1 | function f(a?.b) {} @@ -141,6 +155,13 @@ exports[`invalid-fn-param.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-fn-param.js format[yuku] 1`] = ` +"Expected ')' to close parameter list, but found '?.' (1:13) +> 1 | function f(a?.b) {} + | ^^ + 2 |" +`; + exports[`invalid-fn-param-arrow.js format[__babel_estree] 1`] = ` "Invalid optional chaining in the left-hand side of function parameter list. (1:2) > 1 | (a?.b) => {} @@ -188,6 +209,13 @@ exports[`invalid-fn-param-arrow.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-fn-param-arrow.js format[yuku] 1`] = ` +"Optional chaining is not allowed in binding pattern (1:2) +> 1 | (a?.b) => {} + | ^^^^ + 2 |" +`; + exports[`invalid-fn-param-assign.js format[__babel_estree] 1`] = ` "Unexpected token, expected "," (1:13) > 1 | function f(a?.b = c) {} @@ -235,6 +263,13 @@ exports[`invalid-fn-param-assign.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-fn-param-assign.js format[yuku] 1`] = ` +"Expected ')' to close parameter list, but found '?.' (1:13) +> 1 | function f(a?.b = c) {} + | ^^ + 2 |" +`; + exports[`invalid-for-await-of.js format[__babel_estree] 1`] = ` "Invalid optional chaining in the left-hand side of for-of statement. (1:6) > 1 | for (a?.b of x); @@ -282,6 +317,13 @@ exports[`invalid-for-await-of.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-for-await-of.js format[yuku] 1`] = ` +"Optional chaining is not allowed in assignment pattern (1:6) +> 1 | for (a?.b of x); + | ^^^^ + 2 |" +`; + exports[`invalid-for-in.js format[__babel_estree] 1`] = ` "Invalid optional chaining in the left-hand side of for-in statement. (1:6) > 1 | for (a?.b in x); @@ -329,6 +371,13 @@ exports[`invalid-for-in.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-for-in.js format[yuku] 1`] = ` +"Optional chaining is not allowed in assignment pattern (1:6) +> 1 | for (a?.b in x); + | ^^^^ + 2 |" +`; + exports[`invalid-for-of.js format[__babel_estree] 1`] = ` "Invalid optional chaining in the left-hand side of for-of statement. (1:6) > 1 | for (a?.b of x); @@ -376,6 +425,13 @@ exports[`invalid-for-of.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-for-of.js format[yuku] 1`] = ` +"Optional chaining is not allowed in assignment pattern (1:6) +> 1 | for (a?.b of x); + | ^^^^ + 2 |" +`; + exports[`invalid-inc-postfix.js format[__babel_estree] 1`] = ` "Invalid optional chaining in the left-hand side of postfix operation. (1:1) > 1 | a?.b++; @@ -423,6 +479,13 @@ exports[`invalid-inc-postfix.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-inc-postfix.js format[yuku] 1`] = ` +"Invalid operand for increment/decrement operator (1:1) +> 1 | a?.b++; + | ^^^^ + 2 |" +`; + exports[`invalid-inc-prefix.js format[__babel_estree] 1`] = ` "Invalid optional chaining in the left-hand side of prefix operation. (1:3) > 1 | ++a?.b; @@ -470,6 +533,13 @@ exports[`invalid-inc-prefix.js format[oxc] 1`] = ` 2 |" `; +exports[`invalid-inc-prefix.js format[yuku] 1`] = ` +"Invalid operand for increment/decrement operator (1:3) +> 1 | ++a?.b; + | ^^^^ + 2 |" +`; + exports[`valid-complex-case.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -520,6 +590,14 @@ exports[`valid-complex-case.js format[oxc] 1`] = ` 3 |" `; +exports[`valid-complex-case.js format[yuku] 1`] = ` +"Unexpected token '?.' in binding pattern (1:4) +> 1 | let?.()[a] =1; + | ^^ + 2 | let?.[a] = 1; + 3 |" +`; + exports[`valid-lhs-eq.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -556,6 +634,13 @@ exports[`valid-lhs-eq.js format[oxc] 1`] = ` 2 |" `; +exports[`valid-lhs-eq.js format[yuku] 1`] = ` +"Optional chaining is not allowed in assignment pattern (1:1) +> 1 | a?.b.c = d; + | ^^^^^^ + 2 |" +`; + exports[`valid-lhs-plus-eq.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -592,6 +677,13 @@ exports[`valid-lhs-plus-eq.js format[oxc] 1`] = ` 2 |" `; +exports[`valid-lhs-plus-eq.js format[yuku] 1`] = ` +"Invalid assignment target (1:1) +> 1 | a?.b.c += d; + | ^^^^^^ + 2 |" +`; + exports[`valid-parenthesized.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -635,3 +727,10 @@ exports[`valid-parenthesized.js format[oxc] 1`] = ` | ^^^^ 2 |" `; + +exports[`valid-parenthesized.js format[yuku] 1`] = ` +"Parenthesized expression in assignment pattern must be a simple assignment target (1:2) +> 1 | (a?.b) = c; + | ^^^^ + 2 |" +`; diff --git a/tests/format/js/optional-chaining-assignment/format.test.js b/tests/format/js/optional-chaining-assignment/format.test.js index fd1452eb2..99ed28cc5 100644 --- a/tests/format/js/optional-chaining-assignment/format.test.js +++ b/tests/format/js/optional-chaining-assignment/format.test.js @@ -33,6 +33,7 @@ runFormatTest(import.meta, ["babel"], { ], oxc: [...optionalChainingAssignTests, ...invalidSyntaxTests], "oxc-ts": [...optionalChainingAssignTests, ...invalidSyntaxTests], + yuku: [...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 0e115c5f2..66dad5919 100644 --- a/tests/format/js/partial-application/__snapshots__/format.test.js.snap +++ b/tests/format/js/partial-application/__snapshots__/format.test.js.snap @@ -67,3 +67,12 @@ exports[`test.js format[oxc] 1`] = ` 3 | 4 | const addTen = add(?, 10); // apply from the right" `; + +exports[`test.js format[yuku] 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" +`; diff --git a/tests/format/js/partial-application/format.test.js b/tests/format/js/partial-application/format.test.js index c0a7f0191..524093664 100644 --- a/tests/format/js/partial-application/format.test.js +++ b/tests/format/js/partial-application/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: 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 74f9cd80a..d495661a4 100644 --- a/tests/format/js/pipeline-operator/__snapshots__/format.test.js.snap +++ b/tests/format/js/pipeline-operator/__snapshots__/format.test.js.snap @@ -66,6 +66,16 @@ exports[`block-comments.js format[oxc] 1`] = ` 5 | |> kochabCooieGameOnOboleUnweave" `; +exports[`block-comments.js format[yuku] 1`] = ` +"Unexpected token '>' (2:2) + 1 | bifornCringerMoshedPerplexSawder +> 2 | |> foo1 + | ^ + 3 | |> foo2 /* comment1 */ + 4 | |> foo3 /* comment2 */ + 5 | |> kochabCooieGameOnOboleUnweave" +`; + exports[`fsharp_style_pipeline_operator.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -203,6 +213,16 @@ exports[`fsharp_style_pipeline_operator.js format[oxc] 1`] = ` 5 | |> x => x + '!'" `; +exports[`fsharp_style_pipeline_operator.js format[yuku] 1`] = ` +"Unexpected token '>' (2:4) + 1 | promise +> 2 | |> await + | ^ + 3 | |> x => doubleSay(x, ', ') + 4 | |> capitalize + 5 | |> x => x + '!'" +`; + exports[`hack_pipeline_operator.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -355,6 +375,15 @@ exports[`hack_pipeline_operator.js format[oxc] 1`] = ` 4 | |> await %" `; +exports[`hack_pipeline_operator.js format[yuku] 1`] = ` +"Unexpected token '>' (1:4) +> 1 | a |> await % |> % * 3; + | ^ + 2 | + 3 | foo + 4 | |> await %" +`; + exports[`minimal_pipeline_operator.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -503,3 +532,12 @@ exports[`minimal_pipeline_operator.js format[oxc] 1`] = ` 3 | a |> (b |> c); 4 |" `; + +exports[`minimal_pipeline_operator.js format[yuku] 1`] = ` +"Unexpected token '>' (1:4) +> 1 | a |> b |> c; + | ^ + 2 | + 3 | a |> (b |> c); + 4 |" +`; diff --git a/tests/format/js/pipeline-operator/format.test.js b/tests/format/js/pipeline-operator/format.test.js index c0a7f0191..524093664 100644 --- a/tests/format/js/pipeline-operator/format.test.js +++ b/tests/format/js/pipeline-operator/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: true, }, }); diff --git a/tests/format/js/reserved-word/__snapshots__/format.test.js.snap b/tests/format/js/reserved-word/__snapshots__/format.test.js.snap index e8a803171..423a01de2 100644 --- a/tests/format/js/reserved-word/__snapshots__/format.test.js.snap +++ b/tests/format/js/reserved-word/__snapshots__/format.test.js.snap @@ -50,6 +50,16 @@ var let = "foo"; ================================================================================ `; +exports[`let.js format[yuku] 1`] = ` +"Unexpected token '.' in binding pattern (2:4) + 1 | foo.let; +> 2 | let.foo; + | ^ + 3 | new let(); + 4 | ({ let: "foo" }); + 5 | (let, "foo");" +`; + exports[`yield.js format 1`] = ` ====================================options===================================== parsers: ["acorn", "espree", "meriyah", "babel"] diff --git a/tests/format/js/reserved-word/format.test.js b/tests/format/js/reserved-word/format.test.js index 0592a869d..ae904d11b 100644 --- a/tests/format/js/reserved-word/format.test.js +++ b/tests/format/js/reserved-word/format.test.js @@ -1 +1,3 @@ -runFormatTest(import.meta, ["acorn", "espree", "meriyah", "babel"]); +runFormatTest(import.meta, ["acorn", "espree", "meriyah", "babel"], { + errors: { yuku: ["let.js"] }, +}); 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 51680b574..59a657f59 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 @@ -124,6 +124,13 @@ exports[`import-source-attributes-expression.js format[meriyah] 1`] = ` Cause: [1:7-1:13]: The only valid meta property for import is 'import.meta'" `; +exports[`import-source-attributes-expression.js format[yuku] 1`] = ` +"Expected ')' after import(), but found ',' (1:18) +> 1 | import.source("x", { with: { attr: "val" } }); + | ^ + 2 |" +`; + exports[`import-source-binding-from.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -161,6 +168,13 @@ exports[`import-source-binding-from.js format[meriyah] 1`] = ` Cause: [1:19-1:23]: Import source must be string" `; +exports[`import-source-binding-from.js format[yuku] 1`] = ` +"Expected module specifier, but found 'from' (1:20) +> 1 | import source from from "x"; + | ^^^^ + 2 |" +`; + exports[`import-source-binding-source.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -282,6 +296,13 @@ exports[`no-named.js format[oxc] 1`] = ` 2 |" `; +exports[`no-named.js format[yuku] 1`] = ` +"Expected 'from' after import clause, but found '{' (1:15) +> 1 | import source { x } from "x"; + | ^ + 2 |" +`; + exports[`no-namespace.js format[__babel_estree] 1`] = ` "Only \`import source x from "./module"\` is valid. (1:15) > 1 | import source * as x from "x"; @@ -328,3 +349,10 @@ exports[`no-namespace.js format[oxc] 1`] = ` | ^^^^^^ 2 |" `; + +exports[`no-namespace.js format[yuku] 1`] = ` +"Expected 'from' after import clause, 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 a02532b70..13757ad5a 100644 --- a/tests/format/js/source-phase-imports/format.test.js +++ b/tests/format/js/source-phase-imports/format.test.js @@ -15,6 +15,11 @@ runFormatTest(import.meta, ["babel"], { meriyah: [...importSourceTests, ...invalidSyntaxTests], oxc: invalidSyntaxTests, "oxc-ts": invalidSyntaxTests, + yuku: [ + "import-source-attributes-expression.js", + "import-source-binding-from.js", + ...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 671f37f00..e92d70c83 100644 --- a/tests/format/js/throw_expressions/__snapshots__/format.test.js.snap +++ b/tests/format/js/throw_expressions/__snapshots__/format.test.js.snap @@ -91,3 +91,12 @@ exports[`throw_expression.js format[oxc] 1`] = ` 3 | lint(ast, { 4 | with: () => throw new Error("avoid using 'with' statements.")" `; + +exports[`throw_expression.js format[yuku] 1`] = ` +"'throw' is reserved and cannot be used as an identifier (1:26) +> 1 | function save(filename = throw new TypeError("Argument required")) {} + | ^^^^^ + 2 | + 3 | lint(ast, { + 4 | with: () => throw new Error("avoid using 'with' statements.")" +`; diff --git a/tests/format/js/throw_expressions/format.test.js b/tests/format/js/throw_expressions/format.test.js index c0a7f0191..524093664 100644 --- a/tests/format/js/throw_expressions/format.test.js +++ b/tests/format/js/throw_expressions/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: 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 9c32aa5a2..663eaa08b 100644 --- a/tests/format/js/v8_intrinsic/__snapshots__/format.test.js.snap +++ b/tests/format/js/v8_intrinsic/__snapshots__/format.test.js.snap @@ -50,6 +50,14 @@ exports[`avoid-conflicts-to-pipeline.js format[oxc] 1`] = ` 3 |" `; +exports[`avoid-conflicts-to-pipeline.js format[yuku] 1`] = ` +"Unexpected token '%' (2:16) + 1 | // |> +> 2 | const status = %GetOptimizationStatus(fn); + | ^ + 3 |" +`; + exports[`intrinsic_call.js format 1`] = ` ====================================options===================================== parsers: ["babel"] @@ -137,3 +145,13 @@ exports[`intrinsic_call.js format[oxc] 1`] = ` 4 | foo ) 5 | }" `; + +exports[`intrinsic_call.js format[yuku] 1`] = ` +"Unexpected token '%' (2:13) + 1 | function doSmth() { +> 2 | %DebugPrint + | ^ + 3 | ( + 4 | foo ) + 5 | }" +`; diff --git a/tests/format/js/v8_intrinsic/format.test.js b/tests/format/js/v8_intrinsic/format.test.js index c0a7f0191..524093664 100644 --- a/tests/format/js/v8_intrinsic/format.test.js +++ b/tests/format/js/v8_intrinsic/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: true, oxc: true, "oxc-ts": true, + yuku: true, }, }); diff --git a/tests/format/jsx/do/__snapshots__/format.test.js.snap b/tests/format/jsx/do/__snapshots__/format.test.js.snap index 5e6adf1b6..18d06635d 100644 --- a/tests/format/jsx/do/__snapshots__/format.test.js.snap +++ b/tests/format/jsx/do/__snapshots__/format.test.js.snap @@ -63,3 +63,13 @@ exports[`do.js format[oxc] 1`] = ` 4 | }} 5 | " `; + +exports[`do.js format[yuku] 1`] = ` +"'do' is reserved and cannot be used as an identifier (2:4) + 1 |
+> 2 | {do { + | ^^ + 3 | 1 + 4 | }} + 5 |
" +`; diff --git a/tests/format/jsx/do/format.test.js b/tests/format/jsx/do/format.test.js index ef7bd3702..5b805a8d4 100644 --- a/tests/format/jsx/do/format.test.js +++ b/tests/format/jsx/do/format.test.js @@ -5,5 +5,6 @@ runFormatTest(import.meta, ["babel"], { meriyah: ["do.js"], oxc: ["do.js"], "oxc-ts": ["do.js"], + yuku: ["do.js"], }, }); diff --git a/tests/unit/builtin-plugins.js b/tests/unit/builtin-plugins.js index 1752cb5b7..9d8b0c511 100644 --- a/tests/unit/builtin-plugins.js +++ b/tests/unit/builtin-plugins.js @@ -48,6 +48,7 @@ test("builtin parsers", async () => { "typescript", "vue", "yaml", + "yuku", ] `); }); diff --git a/website/playground/codeSamples.mjs b/website/playground/codeSamples.mjs index 0387c7401..28404c6b5 100644 --- a/website/playground/codeSamples.mjs +++ b/website/playground/codeSamples.mjs @@ -5,6 +5,7 @@ export default function getCodeSamples(parser) { case "espree": case "meriyah": case "oxc": + case "yuku": return [ 'function HelloWorld({greeting = "hello", greeted = \'"World"\', silent = false, onMouseOver,}) {', "", diff --git a/website/playground/panel/language.js b/website/playground/panel/language.js index 27b2363e9..d05fe55a7 100644 --- a/website/playground/panel/language.js +++ b/website/playground/panel/language.js @@ -15,6 +15,7 @@ function getCodemirrorMode(parser) { case "espree": case "meriyah": case "oxc": + case "yuku": return "JSX"; case "doc-explorer": diff --git a/yarn.lock b/yarn.lock index 1067afab7..572e479ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3042,6 +3042,99 @@ __metadata: languageName: node linkType: hard +"@yuku-parser/binding-darwin-arm64@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-darwin-arm64@npm:0.6.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@yuku-parser/binding-darwin-x64@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-darwin-x64@npm:0.6.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@yuku-parser/binding-freebsd-x64@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-freebsd-x64@npm:0.6.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@yuku-parser/binding-linux-arm-gnu@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-linux-arm-gnu@npm:0.6.2" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@yuku-parser/binding-linux-arm-musl@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-linux-arm-musl@npm:0.6.2" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@yuku-parser/binding-linux-arm64-gnu@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-linux-arm64-gnu@npm:0.6.2" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@yuku-parser/binding-linux-arm64-musl@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-linux-arm64-musl@npm:0.6.2" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@yuku-parser/binding-linux-x64-gnu@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-linux-x64-gnu@npm:0.6.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@yuku-parser/binding-linux-x64-musl@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-linux-x64-musl@npm:0.6.2" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@yuku-parser/binding-win32-arm64@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-win32-arm64@npm:0.6.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@yuku-parser/binding-win32-x64@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/binding-win32-x64@npm:0.6.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@yuku-parser/wasm@npm:0.6.2": + version: 0.6.2 + resolution: "@yuku-parser/wasm@npm:0.6.2" + dependencies: + "@yuku-toolchain/types": "npm:0.5.43" + checksum: 10/95b8aed6a90feb7da5fe7697d68877630306fc5656270d4f47ed739e1cb7ed85a165d0aaa7efd89e6c77fb1339689744281149afa97e663b4ff3a05acd33f2fa + languageName: node + linkType: hard + +"@yuku-toolchain/types@npm:0.5.43": + version: 0.5.43 + resolution: "@yuku-toolchain/types@npm:0.5.43" + checksum: 10/ee3d3ac6622aba378c69c7a3e1164adbdd11b977dcb32d410e0e565733bdc1ff4c066d44f7b9d9442713ecc778bc53a191ddea518eb63d1635c034334f43517d + languageName: node + linkType: hard + "abbrev@npm:^5.0.0": version: 5.0.0 resolution: "abbrev@npm:5.0.0" @@ -8209,6 +8302,7 @@ __metadata: "@typescript-eslint/parser": "npm:8.64.0" "@typescript-eslint/typescript-estree": "npm:8.64.0" "@typescript-eslint/visitor-keys": "npm:8.64.0" + "@yuku-parser/wasm": "npm:0.6.2" acorn: "npm:8.17.0" acorn-jsx: "npm:5.3.2" angular-estree-parser: "npm:15.5.0" @@ -8339,6 +8433,7 @@ __metadata: yaml: "npm:2.9.0" yaml-test-suite: "npm:0.1.0" yaml-unist-parser: "npm:3.2.0" + yuku-parser: "npm:0.6.2" bin: prettier: ./bin/prettier.cjs languageName: unknown @@ -10093,6 +10188,49 @@ __metadata: languageName: node linkType: hard +"yuku-parser@npm:0.6.2": + version: 0.6.2 + resolution: "yuku-parser@npm:0.6.2" + dependencies: + "@yuku-parser/binding-darwin-arm64": "npm:0.6.2" + "@yuku-parser/binding-darwin-x64": "npm:0.6.2" + "@yuku-parser/binding-freebsd-x64": "npm:0.6.2" + "@yuku-parser/binding-linux-arm-gnu": "npm:0.6.2" + "@yuku-parser/binding-linux-arm-musl": "npm:0.6.2" + "@yuku-parser/binding-linux-arm64-gnu": "npm:0.6.2" + "@yuku-parser/binding-linux-arm64-musl": "npm:0.6.2" + "@yuku-parser/binding-linux-x64-gnu": "npm:0.6.2" + "@yuku-parser/binding-linux-x64-musl": "npm:0.6.2" + "@yuku-parser/binding-win32-arm64": "npm:0.6.2" + "@yuku-parser/binding-win32-x64": "npm:0.6.2" + "@yuku-toolchain/types": "npm:0.5.43" + dependenciesMeta: + "@yuku-parser/binding-darwin-arm64": + optional: true + "@yuku-parser/binding-darwin-x64": + optional: true + "@yuku-parser/binding-freebsd-x64": + optional: true + "@yuku-parser/binding-linux-arm-gnu": + optional: true + "@yuku-parser/binding-linux-arm-musl": + optional: true + "@yuku-parser/binding-linux-arm64-gnu": + optional: true + "@yuku-parser/binding-linux-arm64-musl": + optional: true + "@yuku-parser/binding-linux-x64-gnu": + optional: true + "@yuku-parser/binding-linux-x64-musl": + optional: true + "@yuku-parser/binding-win32-arm64": + optional: true + "@yuku-parser/binding-win32-x64": + optional: true + checksum: 10/331c1cc68f4aed45cb7c914c12693b42cb5a2bfbd9f20663a1fa00bf6d2991e85982b0fcd5c7dc6c5077ce3d9b6a32c102155d85797e874d89b753182310bb1a + languageName: node + linkType: hard + "zeptomatch-escape@npm:^1.0.1": version: 1.0.1 resolution: "zeptomatch-escape@npm:1.0.1"