From d00a1f6511e300dda308ab85b1b59a194c5b9e5a Mon Sep 17 00:00:00 2001 From: Boshen Date: Sun, 8 Sep 2024 13:21:48 +0800 Subject: [PATCH] chore: use dprint to format js, json and markdown --- .github/CODE_OF_CONDUCT.md | 25 +- .github/ISSUE_TEMPLATE/bug_report.md | 3 - .github/ISSUE_TEMPLATE/feature_request.md | 3 - .github/SECURITY.md | 2 +- .vscode/launch.json | 26 +- .vscode/tasks.json | 144 +++---- MAINTENANCE.md | 6 +- README.md | 18 +- crates/oxc_regular_expression/README.md | 1 - crates/oxc_transformer/README.md | 24 +- crates/oxc_traverse/scripts/build.mjs | 32 +- crates/oxc_traverse/scripts/lib/ancestor.mjs | 102 ++--- crates/oxc_traverse/scripts/lib/parse.mjs | 368 +++++++++--------- .../scripts/lib/scopes_collector.mjs | 16 +- crates/oxc_traverse/scripts/lib/traverse.mjs | 18 +- crates/oxc_traverse/scripts/lib/utils.mjs | 48 +-- crates/oxc_traverse/scripts/lib/walk.mjs | 274 ++++++------- dprint.json | 4 +- editors/vscode/client/extension.ts | 92 ++--- justfile | 1 + napi/parser/index.d.ts | 71 ++-- napi/parser/index.js | 349 ++++++++--------- napi/parser/parse.bench.mjs | 90 ++--- napi/parser/test.mjs | 8 +- napi/parser/test_module_lexer.mjs | 29 +- napi/transform/index.d.ts | 101 ++--- napi/transform/index.js | 343 ++++++++-------- napi/transform/test.mjs | 14 +- npm/oxc-parser/README.md | 6 +- npm/oxc-parser/scripts/generate-packages.mjs | 58 +-- npm/oxc-transform/README.md | 22 +- .../scripts/generate-packages.mjs | 58 +-- npm/oxlint/README.md | 6 +- npm/oxlint/configuration_schema.json | 2 +- npm/oxlint/package.json | 2 +- npm/oxlint/scripts/generate-packages.mjs | 64 +-- tasks/benchmark/codspeed/capture.mjs | 76 ++-- tasks/benchmark/codspeed/create_temp_dir.mjs | 2 +- tasks/benchmark/codspeed/upload.mjs | 118 +++--- tasks/coverage/README.md | 1 + tasks/coverage/src/runtime/package.json | 2 +- tasks/coverage/src/runtime/runtime.js | 125 +++--- tasks/lint_rules/src/eslint-rules.cjs | 94 +++-- tasks/lint_rules/src/main.cjs | 32 +- tasks/lint_rules/src/markdown-renderer.cjs | 59 ++- tasks/lint_rules/src/oxlint-rules.cjs | 44 +-- tasks/lint_rules/src/result-reporter.cjs | 4 +- wasm/parser/README.md | 20 +- wasm/parser/test-node.mjs | 8 +- 49 files changed, 1489 insertions(+), 1526 deletions(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 41dd9ebee5..60d8c9eec2 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -17,23 +17,23 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or +- The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities @@ -105,7 +105,7 @@ Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an +standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within @@ -117,8 +117,7 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 38f3a31a0a..e43f208a79 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -3,7 +3,4 @@ name: Bug report about: Create a report to help us improve. title: '' labels: C-bug - --- - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index a7fc69fbff..30bb7b4fcc 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -3,7 +3,4 @@ name: Feature request about: Suggest an idea for this project. title: '' labels: C-enhancement - --- - - diff --git a/.github/SECURITY.md b/.github/SECURITY.md index cafe2b15b3..63f5b072da 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -4,4 +4,4 @@ ## Reporting a Vulnerability -If you find any potential vulnerability, join our [discord channel](https://discord.gg/9uXCAwqQZW) and contact Boshen. +If you find any potential vulnerability, join our [discord channel](https://discord.gg/9uXCAwqQZW) and contact Boshen. diff --git a/.vscode/launch.json b/.vscode/launch.json index f98a979a51..8694caa094 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,19 +1,19 @@ // A launch configuration that compiles the extension and then opens it inside a new window { - "version": "0.2.0", - "configurations": [ - { - "type": "extensionHost", - "request": "launch", - "name": "Launch Client", - "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceFolder}/editors/vscode" ], - "sourceMaps": true, - "outFiles": ["${workspaceFolder}/editors/vscode/dist/*.js"], - "env": { + "version": "0.2.0", + "configurations": [ + { + "type": "extensionHost", + "request": "launch", + "name": "Launch Client", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceFolder}/editors/vscode"], + "sourceMaps": true, + "outFiles": ["${workspaceFolder}/editors/vscode/dist/*.js"], + "env": { "SERVER_PATH_DEV": "${workspaceRoot}/target/debug/oxc_language_server", "RUST_LOG": "debug" } - } - ] + } + ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 31fe43b413..08a64eb76f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,76 +1,76 @@ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format { - "version": "2.0.0", - "tasks": [ - // format code, then build tests (but do not run them). - { - "label": "rust: cargo test --no-run", - "type": "cargo", - "command": "test", - "args": [ - "--no-run" - ], - "problemMatcher": [ - "$rustc" - ], - "group": { - "kind": "build", - "isDefault": true - }, - "presentation": { - "echo": true, - "reveal": "silent", - "focus": false, - "panel": "shared", - "showReuseMessage": false, - "clear": true - }, - "dependsOn": [ - "rust: cargo fmt" - ] - }, - { - "type": "cargo", - "command": "fmt", - "problemMatcher": [ - "$rustc" - ], - "presentation": { - "echo": true, - "reveal": "silent", - "focus": false, - "panel": "shared", - "showReuseMessage": false, - "clear": false - }, - "label": "rust: cargo fmt" - }, - { - "type": "npm", - "script": "compile", - "group": "build", - "presentation": { - "panel": "dedicated", - "reveal": "never" - }, - "problemMatcher": [ - "$tsc" - ] - }, - { - "type": "shell", - "command": "cd ./editors/vscode && npm run watch", - "windows": { - "command": "cd ./editors/vscode; npm run watch" - }, - "label": "watch", - "isBackground": true, - "group": "build", - "presentation": { - "panel": "dedicated", - "reveal": "never" - } - }, - ], + "version": "2.0.0", + "tasks": [ + // format code, then build tests (but do not run them). + { + "label": "rust: cargo test --no-run", + "type": "cargo", + "command": "test", + "args": [ + "--no-run" + ], + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "echo": true, + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": true + }, + "dependsOn": [ + "rust: cargo fmt" + ] + }, + { + "type": "cargo", + "command": "fmt", + "problemMatcher": [ + "$rustc" + ], + "presentation": { + "echo": true, + "reveal": "silent", + "focus": false, + "panel": "shared", + "showReuseMessage": false, + "clear": false + }, + "label": "rust: cargo fmt" + }, + { + "type": "npm", + "script": "compile", + "group": "build", + "presentation": { + "panel": "dedicated", + "reveal": "never" + }, + "problemMatcher": [ + "$tsc" + ] + }, + { + "type": "shell", + "command": "cd ./editors/vscode && npm run watch", + "windows": { + "command": "cd ./editors/vscode; npm run watch" + }, + "label": "watch", + "isBackground": true, + "group": "build", + "presentation": { + "panel": "dedicated", + "reveal": "never" + } + } + ] } diff --git a/MAINTENANCE.md b/MAINTENANCE.md index 84d824e745..7290b01317 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -2,12 +2,12 @@ ### Release Oxlint -* Run [Prepare Release Oxlint] https://github.com/oxc-project/oxc/actions/workflows/prepare_release_oxlint.yml +- Run [Prepare Release Oxlint] https://github.com/oxc-project/oxc/actions/workflows/prepare_release_oxlint.yml ### E2E Testing -* Run [Oxlint Ecosystem CI](https://github.com/oxc-project/oxlint-ecosystem-ci/actions/workflows/ecosystem-ci.yml) +- Run [Oxlint Ecosystem CI](https://github.com/oxc-project/oxlint-ecosystem-ci/actions/workflows/ecosystem-ci.yml) ## Release Crates -* Run [Prepare Release Crates] https://github.com/oxc-project/oxc/actions/workflows/prepare_release_crates.yml +- Run [Prepare Release Crates] https://github.com/oxc-project/oxc/actions/workflows/prepare_release_crates.yml diff --git a/README.md b/README.md index f771ffac1f..caf3ae6054 100644 --- a/README.md +++ b/README.md @@ -213,13 +213,13 @@ We spend half of our time on strengthening the test infrastructure to prevent pr [Test Infrastructure](https://oxc.rs/docs/learn/architecture/test.html) documents our test procedures: -* Conformance suite on Test262, Babel, TypeScript -* Lots of fuzzing -* Linter snapshot diagnostics -* oxlint ecosystem ci -* Idempotency testing -* Code coverage -* End to end 3000 top npm packages +- Conformance suite on Test262, Babel, TypeScript +- Lots of fuzzing +- Linter snapshot diagnostics +- oxlint ecosystem ci +- Idempotency testing +- Code coverage +- End to end 3000 top npm packages --- @@ -252,8 +252,8 @@ This project was incubated with the assistance of these exceptional mentors and Special thanks go to -* [@domonji](https://github.com/domonji) for bootstrapping this project together, and also completing the TypeScript parser. -* [@tongtong-lu](https://github.com/tongtong-lu) and [@guan-wy](https://github.com/guan-wy) for designing the [project logo](https://github.com/oxc-project/oxc-assets). +- [@domonji](https://github.com/domonji) for bootstrapping this project together, and also completing the TypeScript parser. +- [@tongtong-lu](https://github.com/tongtong-lu) and [@guan-wy](https://github.com/guan-wy) for designing the [project logo](https://github.com/oxc-project/oxc-assets). ## ❤ Who's [Sponsoring Oxc](https://github.com/sponsors/Boshen)? diff --git a/crates/oxc_regular_expression/README.md b/crates/oxc_regular_expression/README.md index 48b705b854..b2e10ad668 100644 --- a/crates/oxc_regular_expression/README.md +++ b/crates/oxc_regular_expression/README.md @@ -5,4 +5,3 @@ Implements ECMAScript® 2024 Language Specification - https://tc39.es/ecma262/2024/multipage/ecmascript-language-lexical-grammar.html#sec-literals-regular-expression-literals - https://tc39.es/ecma262/2024/multipage/text-processing.html#sec-regexp-regular-expression-objects - https://tc39.es/ecma262/2024/multipage/additional-ecmascript-features-for-web-browsers.html#sec-regular-expressions-patterns - diff --git a/crates/oxc_transformer/README.md b/crates/oxc_transformer/README.md index eb51c07171..d8eaa8ec9a 100644 --- a/crates/oxc_transformer/README.md +++ b/crates/oxc_transformer/README.md @@ -41,10 +41,10 @@ For a maintainable and understandable codebase, please go big on code comments. Each transform should include a comment at top of file including: -* High level explanation of what transform does. -* One "before / after" example. -* Link to Babel plugin. -* Note of any ways in which our implementation diverges from Babel's, and why. +- High level explanation of what transform does. +- One "before / after" example. +- Link to Babel plugin. +- Note of any ways in which our implementation diverges from Babel's, and why. #### Methods @@ -88,17 +88,17 @@ So where we feel Babel's implementation is inefficient, but we have to follow it tests, make a `// TODO(improve-on-babel): Babel's impl is inefficient because X, we could do better by Y` comment, so we can return to it later. -### Clear "entry points" +### Clear "entry points" "Entry points" are where the visitor calls into the transform. -* Entry points of transform should be implemented as `impl Traverse for MyTransform`. -* Those methods have to be called `enter_*` and `exit_*`. -* Parent transform will only interface with child transform via these entry points. -* Only other method exposed externally should be `new`. That should be at top of the file. -* Entry points go directly below `new` method definition. -* Internal methods implemented lower down in an `impl MyTransform` block. -* Internal methods named descriptively - `add_id_to_function` not `transform_function`. +- Entry points of transform should be implemented as `impl Traverse for MyTransform`. +- Those methods have to be called `enter_*` and `exit_*`. +- Parent transform will only interface with child transform via these entry points. +- Only other method exposed externally should be `new`. That should be at top of the file. +- Entry points go directly below `new` method definition. +- Internal methods implemented lower down in an `impl MyTransform` block. +- Internal methods named descriptively - `add_id_to_function` not `transform_function`. i.e. File is laid out so logic flows from top of file to bottom. diff --git a/crates/oxc_traverse/scripts/build.mjs b/crates/oxc_traverse/scripts/build.mjs index d41510f6a7..0ad8d853e8 100644 --- a/crates/oxc_traverse/scripts/build.mjs +++ b/crates/oxc_traverse/scripts/build.mjs @@ -10,22 +10,22 @@ * We should do this properly with a Rust build script using `syn` etc. */ -import {writeFile} from 'fs/promises'; -import {exec} from 'child_process'; -import {join as pathJoin} from 'path'; -import {fileURLToPath} from 'url'; -import {promisify} from 'util'; -import getTypesFromCode from './lib/parse.mjs'; -import generateTraverseTraitCode from './lib/traverse.mjs'; +import { exec } from 'child_process'; +import { writeFile } from 'fs/promises'; +import { join as pathJoin } from 'path'; +import { fileURLToPath } from 'url'; +import { promisify } from 'util'; import generateAncestorsCode from './lib/ancestor.mjs'; -import generateWalkFunctionsCode from './lib/walk.mjs'; +import getTypesFromCode from './lib/parse.mjs'; import generateScopesCollectorCode from './lib/scopes_collector.mjs'; +import generateTraverseTraitCode from './lib/traverse.mjs'; +import generateWalkFunctionsCode from './lib/walk.mjs'; const execAsync = promisify(exec); -const PREAMBLE = '// Auto-generated code, DO NOT EDIT DIRECTLY!\n' - + '// Generated by `oxc_traverse/scripts/build.mjs`.\n' - + '// To alter this generated file you have to edit the codegen.\n\n'; +const PREAMBLE = '// Auto-generated code, DO NOT EDIT DIRECTLY!\n' + + '// Generated by `oxc_traverse/scripts/build.mjs`.\n' + + '// To alter this generated file you have to edit the codegen.\n\n'; const types = await getTypesFromCode(); @@ -36,9 +36,9 @@ await writeToFile('walk.rs', generateWalkFunctionsCode(types)); await writeToFile('scopes_collector.rs', generateScopesCollectorCode(types)); async function writeToFile(filename, code) { - code = `${PREAMBLE}${code}`; - const path = pathJoin(outputDirPath, filename); - console.log('Writing:', path); - await writeFile(path, code); - await execAsync(`rustfmt ${JSON.stringify(path)}`); + code = `${PREAMBLE}${code}`; + const path = pathJoin(outputDirPath, filename); + console.log('Writing:', path); + await writeFile(path, code); + await execAsync(`rustfmt ${JSON.stringify(path)}`); } diff --git a/crates/oxc_traverse/scripts/lib/ancestor.mjs b/crates/oxc_traverse/scripts/lib/ancestor.mjs index c6dab2480c..fb9929c56b 100644 --- a/crates/oxc_traverse/scripts/lib/ancestor.mjs +++ b/crates/oxc_traverse/scripts/lib/ancestor.mjs @@ -1,37 +1,37 @@ -import {camelToSnake, snakeToCamel} from './utils.mjs'; +import { camelToSnake, snakeToCamel } from './utils.mjs'; export default function generateAncestorsCode(types) { - const variantNamesForEnums = Object.create(null); - let ancestorTypeEnumVariants = '', - ancestorEnumVariants = '', - isFunctions = '', - ancestorTypes = '', - discriminant = 1; - for (const type of Object.values(types)) { - if (type.kind === 'enum') continue; + const variantNamesForEnums = Object.create(null); + let ancestorTypeEnumVariants = '', + ancestorEnumVariants = '', + isFunctions = '', + ancestorTypes = '', + discriminant = 1; + for (const type of Object.values(types)) { + if (type.kind === 'enum') continue; - const typeSnakeName = camelToSnake(type.name), - typeScreamingName = typeSnakeName.toUpperCase(); - let offsetCode = ''; - for (const field of type.fields) { - const offsetVarName = `OFFSET_${typeScreamingName}_${field.name.toUpperCase()}`; - field.offsetVarName = offsetVarName; - offsetCode += `pub(crate) const ${offsetVarName}: usize = ` - + `offset_of!(${type.name}, ${field.rawName});\n`; - } + const typeSnakeName = camelToSnake(type.name), + typeScreamingName = typeSnakeName.toUpperCase(); + let offsetCode = ''; + for (const field of type.fields) { + const offsetVarName = `OFFSET_${typeScreamingName}_${field.name.toUpperCase()}`; + field.offsetVarName = offsetVarName; + offsetCode += `pub(crate) const ${offsetVarName}: usize = ` + + `offset_of!(${type.name}, ${field.rawName});\n`; + } - const variantNames = []; - let thisAncestorTypes = ''; - for (const field of type.fields) { - const fieldTypeName = field.innerTypeName, - fieldType = types[fieldTypeName]; - if (!fieldType) continue; + const variantNames = []; + let thisAncestorTypes = ''; + for (const field of type.fields) { + const fieldTypeName = field.innerTypeName, + fieldType = types[fieldTypeName]; + if (!fieldType) continue; - let methodsCode = ''; - for (const otherField of type.fields) { - if (otherField === field) continue; + let methodsCode = ''; + for (const otherField of type.fields) { + if (otherField === field) continue; - methodsCode += ` + methodsCode += ` #[inline] pub fn ${otherField.rawName}(self) -> &'t ${otherField.rawTypeName} { unsafe { @@ -42,13 +42,13 @@ export default function generateAncestorsCode(types) { } } `; - } + } - const fieldNameCamel = snakeToCamel(field.name), - lifetimes = type.rawName.length > type.name.length ? `<'a, 't>` : "<'t>", - structName = `${type.name}Without${fieldNameCamel}${lifetimes}`; + const fieldNameCamel = snakeToCamel(field.name), + lifetimes = type.rawName.length > type.name.length ? `<'a, 't>` : "<'t>", + structName = `${type.name}Without${fieldNameCamel}${lifetimes}`; - thisAncestorTypes += ` + thisAncestorTypes += ` #[repr(transparent)] #[derive(Clone, Copy, Debug)] pub struct ${structName}( @@ -61,44 +61,44 @@ export default function generateAncestorsCode(types) { } `; - const variantName = `${type.name}${fieldNameCamel}`; - variantNames.push(variantName); + const variantName = `${type.name}${fieldNameCamel}`; + variantNames.push(variantName); - ancestorTypeEnumVariants += `${variantName} = ${discriminant},\n`; - ancestorEnumVariants += `${variantName}(${structName}) = AncestorType::${variantName} as u16,\n`; - discriminant++; + ancestorTypeEnumVariants += `${variantName} = ${discriminant},\n`; + ancestorEnumVariants += `${variantName}(${structName}) = AncestorType::${variantName} as u16,\n`; + discriminant++; - if (fieldType.kind === 'enum') { - (variantNamesForEnums[fieldTypeName] || (variantNamesForEnums[fieldTypeName] = [])) - .push(variantName); - } - } + if (fieldType.kind === 'enum') { + (variantNamesForEnums[fieldTypeName] || (variantNamesForEnums[fieldTypeName] = [])) + .push(variantName); + } + } - if (variantNames.length > 0) { - ancestorTypes += ` + if (variantNames.length > 0) { + ancestorTypes += ` ${offsetCode} ${thisAncestorTypes} `; - isFunctions += ` + isFunctions += ` #[inline] pub fn is_${typeSnakeName}(self) -> bool { matches!(self, ${variantNames.map(name => `Self::${name}(_)`).join(' | ')}) } `; - } } + } - for (const [typeName, variantNames] of Object.entries(variantNamesForEnums)) { - isFunctions += ` + for (const [typeName, variantNames] of Object.entries(variantNamesForEnums)) { + isFunctions += ` #[inline] pub fn is_via_${camelToSnake(typeName)}(self) -> bool { matches!(self, ${variantNames.map(name => `Self::${name}(_)`).join(' | ')}) } `; - } + } - return ` + return ` #![allow( unsafe_code, clippy::missing_safety_doc, diff --git a/crates/oxc_traverse/scripts/lib/parse.mjs b/crates/oxc_traverse/scripts/lib/parse.mjs index aead92dc2b..03b6ddc62c 100644 --- a/crates/oxc_traverse/scripts/lib/parse.mjs +++ b/crates/oxc_traverse/scripts/lib/parse.mjs @@ -1,7 +1,7 @@ -import {readFile} from 'fs/promises'; -import {join as pathJoin} from 'path'; -import {fileURLToPath} from 'url'; -import {typeAndWrappers} from './utils.mjs'; +import { readFile } from 'fs/promises'; +import { join as pathJoin } from 'path'; +import { fileURLToPath } from 'url'; +import { typeAndWrappers } from './utils.mjs'; const FILENAMES = ['js.rs', 'jsx.rs', 'literal.rs', 'ts.rs']; @@ -9,226 +9,226 @@ const FILENAMES = ['js.rs', 'jsx.rs', 'literal.rs', 'ts.rs']; * Parse type defs from Rust files. */ export default async function getTypesFromCode() { - const codeDirPath = pathJoin(fileURLToPath(import.meta.url), '../../../../oxc_ast/src/ast/'); + const codeDirPath = pathJoin(fileURLToPath(import.meta.url), '../../../../oxc_ast/src/ast/'); - const types = Object.create(null); - for (const filename of FILENAMES) { - const code = await readFile(`${codeDirPath}${filename}`, 'utf8'); - parseFile(code, filename, types); - } - return types; + const types = Object.create(null); + for (const filename of FILENAMES) { + const code = await readFile(`${codeDirPath}${filename}`, 'utf8'); + parseFile(code, filename, types); + } + return types; } class Position { - constructor(filename, index) { - this.filename = filename; - this.index = index; - } + constructor(filename, index) { + this.filename = filename; + this.index = index; + } - assert(condition, message) { - if (!condition) this.throw(message); - } - throw(message) { - throw new Error(`${message || 'Unknown error'} (at ${this.filename}:${this.index + 1})`); - } + assert(condition, message) { + if (!condition) this.throw(message); + } + throw(message) { + throw new Error(`${message || 'Unknown error'} (at ${this.filename}:${this.index + 1})`); + } } class Lines { - constructor(lines, filename, offset = 0) { - this.lines = lines; - this.filename = filename; - this.offset = offset; - this.index = 0; - } + constructor(lines, filename, offset = 0) { + this.lines = lines; + this.filename = filename; + this.offset = offset; + this.index = 0; + } - static fromCode(code, filename) { - const lines = code.split(/\r?\n/) - .map(line => line.replace(/\s+/g, ' ').replace(/ ?\/\/.*$/, '').replace(/ $/, '')); - return new Lines(lines, filename, 0); - } + static fromCode(code, filename) { + const lines = code.split(/\r?\n/) + .map(line => line.replace(/\s+/g, ' ').replace(/ ?\/\/.*$/, '').replace(/ $/, '')); + return new Lines(lines, filename, 0); + } - child() { - return new Lines([], this.filename, this.index); - } + child() { + return new Lines([], this.filename, this.index); + } - current() { - return this.lines[this.index]; - } - next() { - return this.lines[this.index++]; - } - isEnd() { - return this.index === this.lines.length; - } + current() { + return this.lines[this.index]; + } + next() { + return this.lines[this.index++]; + } + isEnd() { + return this.index === this.lines.length; + } - position() { - return new Position(this.filename, this.index + this.offset); - } - positionPrevious() { - return new Position(this.filename, this.index + this.offset - 1); - } + position() { + return new Position(this.filename, this.index + this.offset); + } + positionPrevious() { + return new Position(this.filename, this.index + this.offset - 1); + } } function parseFile(code, filename, types) { - const lines = Lines.fromCode(code, filename); - while (!lines.isEnd()) { - // if not #[ast(visit, ..)] - if (!/^#\[ast\(.*visit.*\)\]/.test(lines.current())) { - lines.next(); - continue; - } - - // Consume attrs and comments, parse `#[scope]` attr - let match, scopeArgs = null; - while (!lines.isEnd()) { - if (/^#\[scope[(\]]/.test(lines.current())) { - scopeArgs = parseScopeArgs(lines, scopeArgs); - continue; - } - match = lines.next().match(/^pub (enum|struct) ((.+?)(?:<'a>)?) \{/); - if (match) break; - } - lines.position().assert(match, `Could not find enum or struct after #[ast]`); - const [, kind, rawName, name] = match; - - // Find end of struct / enum - const itemLines = lines.child(); - while (!lines.isEnd()) { - const line = lines.next(); - if (line === '}') break; - itemLines.lines.push(line.trim()); - } - - if (kind === 'struct') { - types[name] = parseStruct(name, rawName, itemLines, scopeArgs); - } else { - types[name] = parseEnum(name, rawName, itemLines); - } + const lines = Lines.fromCode(code, filename); + while (!lines.isEnd()) { + // if not #[ast(visit, ..)] + if (!/^#\[ast\(.*visit.*\)\]/.test(lines.current())) { + lines.next(); + continue; } + + // Consume attrs and comments, parse `#[scope]` attr + let match, scopeArgs = null; + while (!lines.isEnd()) { + if (/^#\[scope[(\]]/.test(lines.current())) { + scopeArgs = parseScopeArgs(lines, scopeArgs); + continue; + } + match = lines.next().match(/^pub (enum|struct) ((.+?)(?:<'a>)?) \{/); + if (match) break; + } + lines.position().assert(match, `Could not find enum or struct after #[ast]`); + const [, kind, rawName, name] = match; + + // Find end of struct / enum + const itemLines = lines.child(); + while (!lines.isEnd()) { + const line = lines.next(); + if (line === '}') break; + itemLines.lines.push(line.trim()); + } + + if (kind === 'struct') { + types[name] = parseStruct(name, rawName, itemLines, scopeArgs); + } else { + types[name] = parseEnum(name, rawName, itemLines); + } + } } function parseStruct(name, rawName, lines, scopeArgs) { - const fields = []; + const fields = []; + while (!lines.isEnd()) { + let isScopeEntry = false, line; while (!lines.isEnd()) { - let isScopeEntry = false, line; - while (!lines.isEnd()) { - line = lines.next(); - if (line === '') continue; - if (line === '#[scope(enter_before)]') { - isScopeEntry = true; - } else if (line.startsWith('#[')) { - while (!line.endsWith(']')) { - line = lines.next(); - } - } else { - break; - } + line = lines.next(); + if (line === '') continue; + if (line === '#[scope(enter_before)]') { + isScopeEntry = true; + } else if (line.startsWith('#[')) { + while (!line.endsWith(']')) { + line = lines.next(); } - - const match = line.match(/^pub ((?:r#)?([a-z_]+)): (.+),$/); - lines.positionPrevious().assert(match, `Cannot parse line as struct field: '${line}'`); - const [, rawName, name, rawTypeName] = match, - typeName = rawTypeName.replace(/<'a>/g, '').replace(/<'a, ?/g, '<'), - {name: innerTypeName, wrappers} = typeAndWrappers(typeName); - - fields.push({name, typeName, rawName, rawTypeName, innerTypeName, wrappers}); - - if (isScopeEntry) scopeArgs.enterScopeBefore = name; + } else { + break; + } } - return {kind: 'struct', name, rawName, fields, scopeArgs}; + + const match = line.match(/^pub ((?:r#)?([a-z_]+)): (.+),$/); + lines.positionPrevious().assert(match, `Cannot parse line as struct field: '${line}'`); + const [, rawName, name, rawTypeName] = match, + typeName = rawTypeName.replace(/<'a>/g, '').replace(/<'a, ?/g, '<'), + { name: innerTypeName, wrappers } = typeAndWrappers(typeName); + + fields.push({ name, typeName, rawName, rawTypeName, innerTypeName, wrappers }); + + if (isScopeEntry) scopeArgs.enterScopeBefore = name; + } + return { kind: 'struct', name, rawName, fields, scopeArgs }; } function parseEnum(name, rawName, lines) { - const variants = [], - inherits = []; - while (!lines.isEnd()) { - let line = lines.next(); - if (line === '') continue; - if (line.startsWith('#[')) { - while (!line.endsWith(']')) { - line = lines.next(); - } - continue; - } - - const match = line.match(/^(.+?)\((.+?)\)(?: ?= ?(\d+))?,$/); - if (match) { - const [, name, rawTypeName, discriminantStr] = match, - typeName = rawTypeName.replace(/<'a>/g, '').replace(/<'a, ?/g, '<'), - {name: innerTypeName, wrappers} = typeAndWrappers(typeName), - discriminant = discriminantStr ? +discriminantStr : null; - variants.push({name, typeName, rawTypeName, innerTypeName, wrappers, discriminant}); - } else { - const match2 = line.match(/^@inherit ([A-Za-z]+)$/); - lines.positionPrevious().assert(match2, `Cannot parse line as enum variant: '${line}'`); - inherits.push(match2[1]); - } + const variants = [], + inherits = []; + while (!lines.isEnd()) { + let line = lines.next(); + if (line === '') continue; + if (line.startsWith('#[')) { + while (!line.endsWith(']')) { + line = lines.next(); + } + continue; } - return {kind: 'enum', name, rawName, variants, inherits}; + + const match = line.match(/^(.+?)\((.+?)\)(?: ?= ?(\d+))?,$/); + if (match) { + const [, name, rawTypeName, discriminantStr] = match, + typeName = rawTypeName.replace(/<'a>/g, '').replace(/<'a, ?/g, '<'), + { name: innerTypeName, wrappers } = typeAndWrappers(typeName), + discriminant = discriminantStr ? +discriminantStr : null; + variants.push({ name, typeName, rawTypeName, innerTypeName, wrappers, discriminant }); + } else { + const match2 = line.match(/^@inherit ([A-Za-z]+)$/); + lines.positionPrevious().assert(match2, `Cannot parse line as enum variant: '${line}'`); + inherits.push(match2[1]); + } + } + return { kind: 'enum', name, rawName, variants, inherits }; } function parseScopeArgs(lines, scopeArgs) { - const position = lines.position(); + const position = lines.position(); - // Get whole of `#[scope]` attr text as a single line string - let scopeArgsStr = ''; - let line = lines.next(); - if (line !== '#[scope]') { - line = line.slice('#[scope('.length); - while (!line.endsWith(')]')) { - scopeArgsStr += ` ${line}`; - line = lines.next(); - } - scopeArgsStr += ` ${line.slice(0, -2)}`; - scopeArgsStr = scopeArgsStr.trim().replace(/ +/g, ' ').replace(/,$/, ''); + // Get whole of `#[scope]` attr text as a single line string + let scopeArgsStr = ''; + let line = lines.next(); + if (line !== '#[scope]') { + line = line.slice('#[scope('.length); + while (!line.endsWith(')]')) { + scopeArgsStr += ` ${line}`; + line = lines.next(); } + scopeArgsStr += ` ${line.slice(0, -2)}`; + scopeArgsStr = scopeArgsStr.trim().replace(/ +/g, ' ').replace(/,$/, ''); + } - // Parse attr - return parseScopeArgsStr(scopeArgsStr, scopeArgs, position); + // Parse attr + return parseScopeArgsStr(scopeArgsStr, scopeArgs, position); } -const SCOPE_ARGS_KEYS = {flags: 'flags', strict_if: 'strictIf'}; +const SCOPE_ARGS_KEYS = { flags: 'flags', strict_if: 'strictIf' }; function parseScopeArgsStr(argsStr, args, position) { - if (!args) args = {flags: 'ScopeFlags::empty()', strictIf: null, enterScopeBefore: null}; + if (!args) args = { flags: 'ScopeFlags::empty()', strictIf: null, enterScopeBefore: null }; - if (!argsStr) return args; + if (!argsStr) return args; - const matchAndConsume = (regex) => { - const match = argsStr.match(regex); - position.assert(match); - argsStr = argsStr.slice(match[0].length); - return match.slice(1); - }; + const matchAndConsume = (regex) => { + const match = argsStr.match(regex); + position.assert(match); + argsStr = argsStr.slice(match[0].length); + return match.slice(1); + }; - try { - while (true) { - const [keyRaw] = matchAndConsume(/^([a-z_]+)\(/); - const key = SCOPE_ARGS_KEYS[keyRaw]; - position.assert(key, `Unexpected scope macro arg: ${key}`); + try { + while (true) { + const [keyRaw] = matchAndConsume(/^([a-z_]+)\(/); + const key = SCOPE_ARGS_KEYS[keyRaw]; + position.assert(key, `Unexpected scope macro arg: ${key}`); - let bracketCount = 1, - index = 0; - for (; index < argsStr.length; index++) { - const char = argsStr[index]; - if (char === '(') { - bracketCount++; - } else if (char === ')') { - bracketCount--; - if (bracketCount === 0) break; - } - } - position.assert(bracketCount === 0); - - args[key] = argsStr.slice(0, index).trim(); - argsStr = argsStr.slice(index + 1); - if (argsStr === '') break; - - matchAndConsume(/^ ?, ?/); + let bracketCount = 1, + index = 0; + for (; index < argsStr.length; index++) { + const char = argsStr[index]; + if (char === '(') { + bracketCount++; + } else if (char === ')') { + bracketCount--; + if (bracketCount === 0) break; } - } catch (err) { - position.throw(`Cannot parse scope args: '${argsStr}': ${err?.message || 'Unknown error'}`); - } + } + position.assert(bracketCount === 0); - return args; + args[key] = argsStr.slice(0, index).trim(); + argsStr = argsStr.slice(index + 1); + if (argsStr === '') break; + + matchAndConsume(/^ ?, ?/); + } + } catch (err) { + position.throw(`Cannot parse scope args: '${argsStr}': ${err?.message || 'Unknown error'}`); + } + + return args; } diff --git a/crates/oxc_traverse/scripts/lib/scopes_collector.mjs b/crates/oxc_traverse/scripts/lib/scopes_collector.mjs index 72a0a90dc6..8798e5cc97 100644 --- a/crates/oxc_traverse/scripts/lib/scopes_collector.mjs +++ b/crates/oxc_traverse/scripts/lib/scopes_collector.mjs @@ -1,20 +1,20 @@ -import {camelToSnake} from './utils.mjs'; +import { camelToSnake } from './utils.mjs'; export default function generateScopesCollectorCode(types) { - let methods = ''; - for (const type of Object.values(types)) { - if (type.kind === 'enum' || !type.scopeArgs) continue; + let methods = ''; + for (const type of Object.values(types)) { + if (type.kind === 'enum' || !type.scopeArgs) continue; - const extraParams = type.scopeArgs.flags === 'flags' ? ', _flags: ScopeFlags' : ''; - methods += ` + const extraParams = type.scopeArgs.flags === 'flags' ? ', _flags: ScopeFlags' : ''; + methods += ` #[inline] fn visit_${camelToSnake(type.name)}(&mut self, it: &${type.rawName}${extraParams}) { self.add_scope(&it.scope_id); } `; - } + } - return ` + return ` use std::cell::Cell; #[allow(clippy::wildcard_imports)] diff --git a/crates/oxc_traverse/scripts/lib/traverse.mjs b/crates/oxc_traverse/scripts/lib/traverse.mjs index f9b25acc0c..088846d5c5 100644 --- a/crates/oxc_traverse/scripts/lib/traverse.mjs +++ b/crates/oxc_traverse/scripts/lib/traverse.mjs @@ -1,21 +1,21 @@ -import {camelToSnake} from './utils.mjs'; +import { camelToSnake } from './utils.mjs'; export default function generateTraverseTraitCode(types) { - const typesArr = Object.values(types); - typesArr.push({name: 'Statements', rawName: "Vec<'a, Statement<'a>>"}); + const typesArr = Object.values(types); + typesArr.push({ name: 'Statements', rawName: "Vec<'a, Statement<'a>>" }); - let traverseMethods = ''; - for (const type of typesArr) { - const snakeName = camelToSnake(type.name); - traverseMethods += ` + let traverseMethods = ''; + for (const type of typesArr) { + const snakeName = camelToSnake(type.name); + traverseMethods += ` #[inline] fn enter_${snakeName}(&mut self, node: &mut ${type.rawName}, ctx: &mut TraverseCtx<'a>) {} #[inline] fn exit_${snakeName}(&mut self, node: &mut ${type.rawName}, ctx: &mut TraverseCtx<'a>) {} `; - } + } - return ` + return ` use oxc_allocator::Vec; #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; diff --git a/crates/oxc_traverse/scripts/lib/utils.mjs b/crates/oxc_traverse/scripts/lib/utils.mjs index b9a9463406..0f876d7a58 100644 --- a/crates/oxc_traverse/scripts/lib/utils.mjs +++ b/crates/oxc_traverse/scripts/lib/utils.mjs @@ -1,34 +1,34 @@ export function typeAndWrappers(name) { - const wrappers = []; - while (true) { - const match = name.match(/^(.+?)<(.+)>$/); - if (!match) break; - wrappers.push(match[1]); - name = match[2]; - } - return {name, wrappers}; + const wrappers = []; + while (true) { + const match = name.match(/^(.+?)<(.+)>$/); + if (!match) break; + wrappers.push(match[1]); + name = match[2]; + } + return { name, wrappers }; } export function camelToSnake(name) { - let prefixLen = 1; - for (const prefix of ['TS', 'JSX', 'JS']) { - if (name.startsWith(prefix)) { - prefixLen = prefix.length; - break; - } + let prefixLen = 1; + for (const prefix of ['TS', 'JSX', 'JS']) { + if (name.startsWith(prefix)) { + prefixLen = prefix.length; + break; } - return name.slice(0, prefixLen).toLowerCase() - + name.slice(prefixLen).replace(/[A-Z]/g, c => `_${c.toLowerCase()}`); + } + return name.slice(0, prefixLen).toLowerCase() + + name.slice(prefixLen).replace(/[A-Z]/g, c => `_${c.toLowerCase()}`); } export function snakeToCamel(name) { - let prefixLen = 0; - for (const prefix of ['TS', 'JSX', 'JS']) { - if (name.startsWith(`${prefix.toLowerCase()}_`)) { - prefixLen = prefix.length + 1; - break; - } + let prefixLen = 0; + for (const prefix of ['TS', 'JSX', 'JS']) { + if (name.startsWith(`${prefix.toLowerCase()}_`)) { + prefixLen = prefix.length + 1; + break; } - return name.slice(0, prefixLen + 1).toUpperCase() - + name.slice(prefixLen + 1).replace(/_([a-z])/g, (_, c) => c.toUpperCase()); + } + return name.slice(0, prefixLen + 1).toUpperCase() + + name.slice(prefixLen + 1).replace(/_([a-z])/g, (_, c) => c.toUpperCase()); } diff --git a/crates/oxc_traverse/scripts/lib/walk.mjs b/crates/oxc_traverse/scripts/lib/walk.mjs index 5dd83043c8..fadc0be144 100644 --- a/crates/oxc_traverse/scripts/lib/walk.mjs +++ b/crates/oxc_traverse/scripts/lib/walk.mjs @@ -1,17 +1,17 @@ import assert from 'assert'; -import {camelToSnake, snakeToCamel} from './utils.mjs'; +import { camelToSnake, snakeToCamel } from './utils.mjs'; export default function generateWalkFunctionsCode(types) { - let walkMethods = ''; - for (const type of Object.values(types)) { - if (type.kind === 'struct') { - walkMethods += generateWalkForStruct(type, types); - } else { - walkMethods += generateWalkForEnum(type, types); - } + let walkMethods = ''; + for (const type of Object.values(types)) { + if (type.kind === 'struct') { + walkMethods += generateWalkForStruct(type, types); + } else { + walkMethods += generateWalkForEnum(type, types); } + } - return ` + return ` #![allow( unsafe_code, clippy::missing_safety_doc, @@ -47,83 +47,83 @@ export default function generateWalkFunctionsCode(types) { } function generateWalkForStruct(type, types) { - let scopeIdField; - const visitedFields = type.fields.filter(field => { - if (field.name === 'scope_id' && field.typeName === `Cell>`) { - scopeIdField = field; - } - return field.innerTypeName in types; - }); + let scopeIdField; + const visitedFields = type.fields.filter(field => { + if (field.name === 'scope_id' && field.typeName === `Cell>`) { + scopeIdField = field; + } + return field.innerTypeName in types; + }); - const {scopeArgs} = type; - let scopeEnterField, enterScopeCode = '', exitScopeCode = ''; - if (scopeArgs && scopeIdField) { - // Get field to enter scope before - const enterFieldName = scopeArgs.enterScopeBefore; - if (enterFieldName) { - scopeEnterField = visitedFields.find(field => field.name === enterFieldName); - assert( - scopeEnterField, - `\`ast\` attr says to enter scope before field '${enterFieldName}' ` - + `in '${type.name}', but that field is not visited` - ); - } else { - scopeEnterField = visitedFields[0]; - } + const { scopeArgs } = type; + let scopeEnterField, enterScopeCode = '', exitScopeCode = ''; + if (scopeArgs && scopeIdField) { + // Get field to enter scope before + const enterFieldName = scopeArgs.enterScopeBefore; + if (enterFieldName) { + scopeEnterField = visitedFields.find(field => field.name === enterFieldName); + assert( + scopeEnterField, + `\`ast\` attr says to enter scope before field '${enterFieldName}' ` + + `in '${type.name}', but that field is not visited`, + ); + } else { + scopeEnterField = visitedFields[0]; + } - // TODO: Maybe this isn't quite right. `scope_id` fields are `Cell>`, - // so visitor is able to alter the `scope_id` of a node from higher up the tree, - // but we don't take that into account. - // Visitor should not do that though, so maybe it's OK. - // In final version, we should not make `scope_id` fields `Cell`s to prevent this. - enterScopeCode = ` + // TODO: Maybe this isn't quite right. `scope_id` fields are `Cell>`, + // so visitor is able to alter the `scope_id` of a node from higher up the tree, + // but we don't take that into account. + // Visitor should not do that though, so maybe it's OK. + // In final version, we should not make `scope_id` fields `Cell`s to prevent this. + enterScopeCode = ` let previous_scope_id = ctx.current_scope_id(); ctx.set_current_scope_id((*(${makeFieldCode(scopeIdField)})).get().unwrap()); `; - exitScopeCode = `ctx.set_current_scope_id(previous_scope_id);`; - } + exitScopeCode = `ctx.set_current_scope_id(previous_scope_id);`; + } - const fieldsCodes = visitedFields.map((field, index) => { - const fieldWalkName = `walk_${camelToSnake(field.innerTypeName)}`, - fieldCamelName = snakeToCamel(field.name); - const scopeCode = field === scopeEnterField ? enterScopeCode : ''; + const fieldsCodes = visitedFields.map((field, index) => { + const fieldWalkName = `walk_${camelToSnake(field.innerTypeName)}`, + fieldCamelName = snakeToCamel(field.name); + const scopeCode = field === scopeEnterField ? enterScopeCode : ''; - let tagCode = '', retagCode = ''; - if (index === 0) { - tagCode = ` + let tagCode = '', retagCode = ''; + if (index === 0) { + tagCode = ` let pop_token = ctx.push_stack( Ancestor::${type.name}${fieldCamelName}( ancestor::${type.name}Without${fieldCamelName}(node, PhantomData) ) ); `; + } else { + retagCode = `ctx.retag_stack(AncestorType::${type.name}${fieldCamelName});`; + } + + const fieldCode = makeFieldCode(field); + + if (field.wrappers[0] === 'Option') { + let walkCode; + if (field.wrappers.length === 2 && field.wrappers[1] === 'Vec') { + if (field.typeNameInner === 'Statement') { + // Special case for `Option>` + walkCode = `walk_statements(traverser, std::ptr::from_mut(field), ctx);`; } else { - retagCode = `ctx.retag_stack(AncestorType::${type.name}${fieldCamelName});`; - } - - const fieldCode = makeFieldCode(field); - - if (field.wrappers[0] === 'Option') { - let walkCode; - if (field.wrappers.length === 2 && field.wrappers[1] === 'Vec') { - if (field.typeNameInner === 'Statement') { - // Special case for `Option>` - walkCode = `walk_statements(traverser, std::ptr::from_mut(field), ctx);`; - } else { - walkCode = ` + walkCode = ` for item in field.iter_mut() { ${fieldWalkName}(traverser, std::ptr::from_mut(item), ctx); } `.trim(); - } - } else if (field.wrappers.length === 2 && field.wrappers[1] === 'Box') { - walkCode = `${fieldWalkName}(traverser, std::ptr::from_mut(&mut **field), ctx);`; - } else { - assert(field.wrappers.length === 1, `Cannot handle struct field with type ${field.typeName}`); - walkCode = `${fieldWalkName}(traverser, std::ptr::from_mut(field), ctx);`; - } + } + } else if (field.wrappers.length === 2 && field.wrappers[1] === 'Box') { + walkCode = `${fieldWalkName}(traverser, std::ptr::from_mut(&mut **field), ctx);`; + } else { + assert(field.wrappers.length === 1, `Cannot handle struct field with type ${field.typeName}`); + walkCode = `${fieldWalkName}(traverser, std::ptr::from_mut(field), ctx);`; + } - return ` + return ` ${scopeCode} ${tagCode} if let Some(field) = &mut *(${fieldCode}) { @@ -131,59 +131,59 @@ function generateWalkForStruct(type, types) { ${walkCode} } `; - } + } - if (field.wrappers[0] === 'Vec') { - let walkVecCode; - if (field.wrappers.length === 1 && field.innerTypeName === 'Statement') { - // Special case for `Vec` - walkVecCode = `walk_statements(traverser, ${fieldCode}, ctx);` - } else { - let walkCode = `${fieldWalkName}(traverser, std::ptr::from_mut(item), ctx);`, - iterModifier = ''; - if (field.wrappers.length === 2 && field.wrappers[1] === 'Option') { - iterModifier = '.flatten()'; - } else { - assert( - field.wrappers.length === 1, - `Cannot handle struct field with type ${field.type}` - ); - } - walkVecCode = ` + if (field.wrappers[0] === 'Vec') { + let walkVecCode; + if (field.wrappers.length === 1 && field.innerTypeName === 'Statement') { + // Special case for `Vec` + walkVecCode = `walk_statements(traverser, ${fieldCode}, ctx);`; + } else { + let walkCode = `${fieldWalkName}(traverser, std::ptr::from_mut(item), ctx);`, + iterModifier = ''; + if (field.wrappers.length === 2 && field.wrappers[1] === 'Option') { + iterModifier = '.flatten()'; + } else { + assert( + field.wrappers.length === 1, + `Cannot handle struct field with type ${field.type}`, + ); + } + walkVecCode = ` for item in (*(${fieldCode})).iter_mut()${iterModifier} { ${walkCode} } `.trim(); - } + } - return ` + return ` ${scopeCode} ${tagCode || retagCode} ${walkVecCode} `; - } + } - if (field.wrappers.length === 1 && field.wrappers[0] === 'Box') { - return ` + if (field.wrappers.length === 1 && field.wrappers[0] === 'Box') { + return ` ${scopeCode} ${tagCode || retagCode} ${fieldWalkName}(traverser, std::ptr::from_mut(&mut **(${fieldCode})), ctx); `; - } + } - assert(field.wrappers.length === 0, `Cannot handle struct field with type: ${field.type}`); + assert(field.wrappers.length === 0, `Cannot handle struct field with type: ${field.type}`); - return ` + return ` ${scopeCode} ${tagCode || retagCode} ${fieldWalkName}(traverser, ${fieldCode}, ctx); `; - }); + }); - if (visitedFields.length > 0) fieldsCodes.push('ctx.pop_stack(pop_token);'); + if (visitedFields.length > 0) fieldsCodes.push('ctx.pop_stack(pop_token);'); - const typeSnakeName = camelToSnake(type.name); - return ` + const typeSnakeName = camelToSnake(type.name); + return ` pub(crate) unsafe fn walk_${typeSnakeName}<'a, Tr: Traverse<'a>>( traverser: &mut Tr, node: *mut ${type.rawName}, @@ -198,53 +198,53 @@ function generateWalkForStruct(type, types) { } function makeFieldCode(field) { - return `node.cast::().add(ancestor::${field.offsetVarName}).cast::<${field.typeName}>()`; + return `node.cast::().add(ancestor::${field.offsetVarName}).cast::<${field.typeName}>()`; } function generateWalkForEnum(type, types) { - const variantCodes = type.variants.map((variant) => { - const variantType = types[variant.innerTypeName]; - assert(variantType, `Cannot handle enum variant with type: ${variant.type}`); + const variantCodes = type.variants.map((variant) => { + const variantType = types[variant.innerTypeName]; + assert(variantType, `Cannot handle enum variant with type: ${variant.type}`); - let nodeCode = '(node)'; - if (variant.wrappers.length === 1 && variant.wrappers[0] === 'Box') { - nodeCode = '(&mut **node)'; - } else { - assert(variant.wrappers.length === 0, `Cannot handle enum variant with type: ${variant.type}`); - } - - return `${type.name}::${variant.name}(node) => ` - + `walk_${camelToSnake(variant.innerTypeName)}(traverser, std::ptr::from_mut${nodeCode}, ctx),`; - }); - - const missingVariants = []; - for (const inheritedTypeName of type.inherits) { - // Recurse into nested inherited types - const variantMatches = [], - inheritedFrom = [inheritedTypeName]; - for (let i = 0; i < inheritedFrom.length; i++) { - const inheritedTypeName = inheritedFrom[i], - inheritedType = types[inheritedTypeName]; - if (!inheritedType || inheritedType.kind !== 'enum') { - missingVariants.push(inheritedTypeName); - } else { - variantMatches.push(...inheritedType.variants.map( - variant => `${type.name}::${variant.name}(_)` - )); - inheritedFrom.push(...inheritedType.inherits); - } - } - - variantCodes.push( - `${variantMatches.join(' | ')} => ` - + `walk_${camelToSnake(inheritedTypeName)}(traverser, node.cast(), ctx),` - ); + let nodeCode = '(node)'; + if (variant.wrappers.length === 1 && variant.wrappers[0] === 'Box') { + nodeCode = '(&mut **node)'; + } else { + assert(variant.wrappers.length === 0, `Cannot handle enum variant with type: ${variant.type}`); } - assert(missingVariants.length === 0, `Missing enum variants: ${missingVariants.join(', ')}`); + return `${type.name}::${variant.name}(node) => ` + + `walk_${camelToSnake(variant.innerTypeName)}(traverser, std::ptr::from_mut${nodeCode}, ctx),`; + }); - const typeSnakeName = camelToSnake(type.name); - return ` + const missingVariants = []; + for (const inheritedTypeName of type.inherits) { + // Recurse into nested inherited types + const variantMatches = [], + inheritedFrom = [inheritedTypeName]; + for (let i = 0; i < inheritedFrom.length; i++) { + const inheritedTypeName = inheritedFrom[i], + inheritedType = types[inheritedTypeName]; + if (!inheritedType || inheritedType.kind !== 'enum') { + missingVariants.push(inheritedTypeName); + } else { + variantMatches.push(...inheritedType.variants.map( + variant => `${type.name}::${variant.name}(_)`, + )); + inheritedFrom.push(...inheritedType.inherits); + } + } + + variantCodes.push( + `${variantMatches.join(' | ')} => ` + + `walk_${camelToSnake(inheritedTypeName)}(traverser, node.cast(), ctx),`, + ); + } + + assert(missingVariants.length === 0, `Missing enum variants: ${missingVariants.join(', ')}`); + + const typeSnakeName = camelToSnake(type.name); + return ` pub(crate) unsafe fn walk_${typeSnakeName}<'a, Tr: Traverse<'a>>( traverser: &mut Tr, node: *mut ${type.rawName}, diff --git a/dprint.json b/dprint.json index b9a7dc64cb..f95779e732 100644 --- a/dprint.json +++ b/dprint.json @@ -11,10 +11,8 @@ "tasks/coverage/misc", "**/tests/**", "**/fixtures/**", - "**/*.snap", "**/*.snap.*", - "**/CHANGELOG.md", - "~" + "**/CHANGELOG.md" ], "plugins": [ "https://plugins.dprint.dev/typescript-0.91.8.wasm", diff --git a/editors/vscode/client/extension.ts b/editors/vscode/client/extension.ts index d3f6d1b9f7..d8a554a051 100644 --- a/editors/vscode/client/extension.ts +++ b/editors/vscode/client/extension.ts @@ -1,34 +1,29 @@ import { - ExtensionContext, - window, commands, - workspace, - StatusBarItem, - StatusBarAlignment, ConfigurationTarget, + ExtensionContext, + StatusBarAlignment, + StatusBarItem, ThemeColor, -} from "vscode"; + window, + workspace, +} from 'vscode'; -import { - Executable, - LanguageClient, - LanguageClientOptions, - ServerOptions, -} from "vscode-languageclient/node"; +import { Executable, LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node'; -import { join } from "node:path"; +import { join } from 'node:path'; -const languageClientId = "oxc-vscode"; -const languageClientName = "oxc"; -const outputChannelName = "oxc_language_server"; -const traceOutputChannelName = "oxc_language_server.trace"; +const languageClientId = 'oxc-vscode'; +const languageClientName = 'oxc'; +const outputChannelName = 'oxc_language_server'; +const traceOutputChannelName = 'oxc_language_server.trace'; const enum OxcCommands { - RestartServer = "oxc.restartServer", - ApplyAllFixes = "oxc.applyAllFixes", - ShowOutputChannel = "oxc.showOutputChannel", - ShowTraceOutputChannel = "oxc.showTraceOutputChannel", - ToggleEnable = "oxc.toggleEnable", + RestartServer = 'oxc.restartServer', + ApplyAllFixes = 'oxc.applyAllFixes', + ShowOutputChannel = 'oxc.showOutputChannel', + ShowTraceOutputChannel = 'oxc.showTraceOutputChannel', + ToggleEnable = 'oxc.toggleEnable', } let client: LanguageClient; @@ -40,7 +35,7 @@ export async function activate(context: ExtensionContext) { OxcCommands.RestartServer, async () => { if (!client) { - window.showErrorMessage("oxc client not found"); + window.showErrorMessage('oxc client not found'); return; } @@ -48,12 +43,12 @@ export async function activate(context: ExtensionContext) { if (client.isRunning()) { await client.restart(); - window.showInformationMessage("oxc server restarted."); + window.showInformationMessage('oxc server restarted.'); } else { await client.start(); } } catch (err) { - client.error("Restarting client failed", err, "force"); + client.error('Restarting client failed', err, 'force'); } }, ); @@ -76,12 +71,12 @@ export async function activate(context: ExtensionContext) { OxcCommands.ToggleEnable, () => { let enabled = workspace - .getConfiguration("oxc_language_server") - .get("enable"); + .getConfiguration('oxc_language_server') + .get('enable'); let nextState = !enabled; workspace - .getConfiguration("oxc_language_server") - .update("enable", nextState, ConfigurationTarget.Global); + .getConfiguration('oxc_language_server') + .update('enable', nextState, ConfigurationTarget.Global); }, ); @@ -95,17 +90,16 @@ export async function activate(context: ExtensionContext) { const outputChannel = window.createOutputChannel(outputChannelName); const traceOutputChannel = window.createOutputChannel(traceOutputChannelName); - const ext = process.platform === "win32" ? ".exe" : ""; + const ext = process.platform === 'win32' ? '.exe' : ''; // NOTE: The `./target/release` path is aligned with the path defined in .github/workflows/release_vscode.yml - const command = - process.env.SERVER_PATH_DEV ?? + const command = process.env.SERVER_PATH_DEV ?? join(context.extensionPath, `./target/release/oxc_language_server${ext}`); const run: Executable = { command: command!, options: { env: { ...process.env, - RUST_LOG: process.env.RUST_LOG || "info", + RUST_LOG: process.env.RUST_LOG || 'info', }, }, }; @@ -117,24 +111,24 @@ export async function activate(context: ExtensionContext) { // Otherwise the run options are used // Options to control the language client let clientConfig: any = JSON.parse( - JSON.stringify(workspace.getConfiguration("oxc_language_server")), + JSON.stringify(workspace.getConfiguration('oxc_language_server')), ); let clientOptions: LanguageClientOptions = { // Register the server for plain text documents documentSelector: [ - "typescript", - "javascript", - "typescriptreact", - "javascriptreact", - "vue", - "svelte", + 'typescript', + 'javascript', + 'typescriptreact', + 'javascriptreact', + 'vue', + 'svelte', ].map((lang) => ({ language: lang, - scheme: "file", + scheme: 'file', })), synchronize: { // Notify the server about file changes to '.clientrc files contained in the workspace - fileEvents: workspace.createFileSystemWatcher("**/.clientrc"), + fileEvents: workspace.createFileSystemWatcher('**/.clientrc'), }, initializationOptions: { settings: clientConfig, @@ -151,15 +145,15 @@ export async function activate(context: ExtensionContext) { clientOptions, ); workspace.onDidChangeConfiguration((e) => { - let isAffected = e.affectsConfiguration("oxc_language_server"); + let isAffected = e.affectsConfiguration('oxc_language_server'); if (!isAffected) { return; } let settings: any = JSON.parse( - JSON.stringify(workspace.getConfiguration("oxc_language_server")), + JSON.stringify(workspace.getConfiguration('oxc_language_server')), ); updateStatsBar(settings.enable); - client.sendNotification("workspace/didChangeConfiguration", { settings }); + client.sendNotification('workspace/didChangeConfiguration', { settings }); }); function updateStatsBar(enable: boolean) { @@ -174,12 +168,10 @@ export async function activate(context: ExtensionContext) { } let bgColor = new ThemeColor( enable - ? "statusBarItem.activeBackground" - : "statusBarItem.errorBackground", + ? 'statusBarItem.activeBackground' + : 'statusBarItem.errorBackground', ); - myStatusBarItem.text = `oxc: ${ - enable ? "$(check-all)" : "$(circle-slash)" - }`; + myStatusBarItem.text = `oxc: ${enable ? '$(check-all)' : '$(circle-slash)'}`; myStatusBarItem.backgroundColor = bgColor; } diff --git a/justfile b/justfile index 0a36f8d18a..7a28f2f799 100755 --- a/justfile +++ b/justfile @@ -63,6 +63,7 @@ ast: fmt: cargo fmt --all taplo format + dprint fmt # Run cargo check check: diff --git a/napi/parser/index.d.ts b/napi/parser/index.d.ts index 33edf981a7..cf2345cd30 100644 --- a/napi/parser/index.d.ts +++ b/napi/parser/index.d.ts @@ -1,25 +1,25 @@ /* auto-generated by NAPI-RS */ /* eslint-disable */ export interface Comment { - type: 'Line' | 'Block' - value: string - start: number - end: number + type: 'Line' | 'Block'; + value: string; + start: number; + end: number; } export interface ExportSpecifier { /** Exported name */ - n: string + n: string; /** Local name, or undefined. */ - ln?: string + ln?: string; /** Start of exported name */ - s: number + s: number; /** End of exported name */ - e: number + e: number; /** Start of local name */ - ls?: number + ls?: number; /** End of local name */ - le?: number + le?: number; } export interface ImportSpecifier { @@ -30,40 +30,40 @@ export interface ImportSpecifier { * * For dynamic import expressions, this field will be empty if not a valid JS string. */ - n?: string + n?: string; /** Start of module specifier */ - s: number + s: number; /** End of module specifier */ - e: number + e: number; /** Start of import statement */ - ss: number + ss: number; /** End of import statement */ - se: number + se: number; /** * Import Type * * If this import keyword is a dynamic import, this is the start value. * * If this import keyword is a static import, this is -1. * * If this import keyword is an import.meta expression, this is -2. */ - d: number + d: number; /** * If this import has an import assertion, this is the start value * Otherwise this is `-1`. */ - a: number + a: number; } export interface ModuleLexer { - imports: Array - exports: Array + imports: Array; + exports: Array; /** * ESM syntax detection * * The use of ESM syntax: import / export statements and `import.meta` */ - hasModuleSyntax: boolean + hasModuleSyntax: boolean; /** Facade modules that only use import / export syntax */ - facade: boolean + facade: boolean; } /** @@ -71,7 +71,10 @@ export interface ModuleLexer { * * * Tokio crashes */ -export declare function moduleLexerAsync(sourceText: string, options?: ParserOptions | undefined | null): Promise +export declare function moduleLexerAsync( + sourceText: string, + options?: ParserOptions | undefined | null, +): Promise; /** * Outputs the list of exports and locations of import specifiers, @@ -81,19 +84,22 @@ export declare function moduleLexerAsync(sourceText: string, options?: ParserOpt * * * File extension is invalid */ -export declare function moduleLexerSync(sourceText: string, options?: ParserOptions | undefined | null): ModuleLexer +export declare function moduleLexerSync(sourceText: string, options?: ParserOptions | undefined | null): ModuleLexer; /** * # Panics * * * Tokio crashes */ -export declare function parseAsync(sourceText: string, options?: ParserOptions | undefined | null): Promise +export declare function parseAsync( + sourceText: string, + options?: ParserOptions | undefined | null, +): Promise; export interface ParseResult { - program: string - comments: Array - errors: Array + program: string; + comments: Array; + errors: Array; } /** @@ -102,8 +108,8 @@ export interface ParseResult { * */ export interface ParserOptions { - sourceType?: 'script' | 'module' | 'unambiguous' | undefined - sourceFilename?: string + sourceType?: 'script' | 'module' | 'unambiguous' | undefined; + sourceFilename?: string; /** * Emit `ParenthesizedExpression` in AST. * @@ -113,7 +119,7 @@ export interface ParserOptions { * * Default: true */ - preserveParens?: boolean + preserveParens?: boolean; } /** @@ -122,7 +128,7 @@ export interface ParserOptions { * * File extension is invalid * * Serde JSON serialization */ -export declare function parseSync(sourceText: string, options?: ParserOptions | undefined | null): ParseResult +export declare function parseSync(sourceText: string, options?: ParserOptions | undefined | null): ParseResult; /** * Parse without returning anything. @@ -133,5 +139,4 @@ export declare function parseSync(sourceText: string, options?: ParserOptions | * * File extension is invalid * * Serde JSON serialization */ -export declare function parseWithoutReturn(sourceText: string, options?: ParserOptions | undefined | null): void - +export declare function parseWithoutReturn(sourceText: string, options?: ParserOptions | undefined | null): void; diff --git a/napi/parser/index.js b/napi/parser/index.js index 2b09b39f8c..3aa5676c71 100644 --- a/napi/parser/index.js +++ b/napi/parser/index.js @@ -2,349 +2,330 @@ /* eslint-disable */ /* auto-generated by NAPI-RS */ -const { readFileSync } = require('fs') +const { readFileSync } = require('fs'); -let nativeBinding = null -const loadErrors = [] +let nativeBinding = null; +const loadErrors = []; const isMusl = () => { - let musl = false + let musl = false; if (process.platform === 'linux') { - musl = isMuslFromFilesystem() + musl = isMuslFromFilesystem(); if (musl === null) { - musl = isMuslFromReport() + musl = isMuslFromReport(); } if (musl === null) { - musl = isMuslFromChildProcess() + musl = isMuslFromChildProcess(); } } - return musl -} + return musl; +}; -const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-') +const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-'); const isMuslFromFilesystem = () => { try { - return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl') + return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl'); } catch { - return null + return null; } -} +}; const isMuslFromReport = () => { - const report = typeof process.report.getReport === 'function' ? process.report.getReport() : null + const report = typeof process.report.getReport === 'function' ? process.report.getReport() : null; if (!report) { - return null + return null; } if (report.header && report.header.glibcVersionRuntime) { - return false + return false; } if (Array.isArray(report.sharedObjects)) { if (report.sharedObjects.some(isFileMusl)) { - return true + return true; } } - return false -} + return false; +}; const isMuslFromChildProcess = () => { try { - return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl') + return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl'); } catch (e) { // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false - return false + return false; } -} +}; function requireNative() { if (process.platform === 'android') { if (process.arch === 'arm64') { try { - return require('./parser.android-arm64.node') + return require('./parser.android-arm64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-android-arm64') + return require('@oxc-parser/binding-android-arm64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'arm') { try { - return require('./parser.android-arm-eabi.node') + return require('./parser.android-arm-eabi.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-android-arm-eabi') + return require('@oxc-parser/binding-android-arm-eabi'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`)); } } else if (process.platform === 'win32') { if (process.arch === 'x64') { try { - return require('./parser.win32-x64-msvc.node') + return require('./parser.win32-x64-msvc.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-win32-x64-msvc') + return require('@oxc-parser/binding-win32-x64-msvc'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'ia32') { try { - return require('./parser.win32-ia32-msvc.node') + return require('./parser.win32-ia32-msvc.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-win32-ia32-msvc') + return require('@oxc-parser/binding-win32-ia32-msvc'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'arm64') { try { - return require('./parser.win32-arm64-msvc.node') + return require('./parser.win32-arm64-msvc.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-win32-arm64-msvc') + return require('@oxc-parser/binding-win32-arm64-msvc'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`)); } } else if (process.platform === 'darwin') { try { - return require('./parser.darwin-universal.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-parser/binding-darwin-universal') - } catch (e) { - loadErrors.push(e) - } + return require('./parser.darwin-universal.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-parser/binding-darwin-universal'); + } catch (e) { + loadErrors.push(e); + } if (process.arch === 'x64') { try { - return require('./parser.darwin-x64.node') + return require('./parser.darwin-x64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-darwin-x64') + return require('@oxc-parser/binding-darwin-x64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'arm64') { try { - return require('./parser.darwin-arm64.node') + return require('./parser.darwin-arm64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-darwin-arm64') + return require('@oxc-parser/binding-darwin-arm64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`)); } } else if (process.platform === 'freebsd') { if (process.arch === 'x64') { try { - return require('./parser.freebsd-x64.node') + return require('./parser.freebsd-x64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-freebsd-x64') + return require('@oxc-parser/binding-freebsd-x64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'arm64') { try { - return require('./parser.freebsd-arm64.node') + return require('./parser.freebsd-arm64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-freebsd-arm64') + return require('@oxc-parser/binding-freebsd-arm64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`)); } } else if (process.platform === 'linux') { if (process.arch === 'x64') { if (isMusl()) { try { - return require('./parser.linux-x64-musl.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-parser/binding-linux-x64-musl') - } catch (e) { - loadErrors.push(e) - } - + return require('./parser.linux-x64-musl.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-parser/binding-linux-x64-musl'); + } catch (e) { + loadErrors.push(e); + } } else { try { - return require('./parser.linux-x64-gnu.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-parser/binding-linux-x64-gnu') - } catch (e) { - loadErrors.push(e) - } - + return require('./parser.linux-x64-gnu.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-parser/binding-linux-x64-gnu'); + } catch (e) { + loadErrors.push(e); + } } } else if (process.arch === 'arm64') { if (isMusl()) { try { - return require('./parser.linux-arm64-musl.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-parser/binding-linux-arm64-musl') - } catch (e) { - loadErrors.push(e) - } - + return require('./parser.linux-arm64-musl.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-parser/binding-linux-arm64-musl'); + } catch (e) { + loadErrors.push(e); + } } else { try { - return require('./parser.linux-arm64-gnu.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-parser/binding-linux-arm64-gnu') - } catch (e) { - loadErrors.push(e) - } - + return require('./parser.linux-arm64-gnu.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-parser/binding-linux-arm64-gnu'); + } catch (e) { + loadErrors.push(e); + } } } else if (process.arch === 'arm') { if (isMusl()) { try { - return require('./parser.linux-arm-musleabihf.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-parser/binding-linux-arm-musleabihf') - } catch (e) { - loadErrors.push(e) - } - + return require('./parser.linux-arm-musleabihf.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-parser/binding-linux-arm-musleabihf'); + } catch (e) { + loadErrors.push(e); + } } else { try { - return require('./parser.linux-arm-gnueabihf.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-parser/binding-linux-arm-gnueabihf') - } catch (e) { - loadErrors.push(e) - } - + return require('./parser.linux-arm-gnueabihf.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-parser/binding-linux-arm-gnueabihf'); + } catch (e) { + loadErrors.push(e); + } } } else if (process.arch === 'riscv64') { if (isMusl()) { try { - return require('./parser.linux-riscv64-musl.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-parser/binding-linux-riscv64-musl') - } catch (e) { - loadErrors.push(e) - } - + return require('./parser.linux-riscv64-musl.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-parser/binding-linux-riscv64-musl'); + } catch (e) { + loadErrors.push(e); + } } else { try { - return require('./parser.linux-riscv64-gnu.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-parser/binding-linux-riscv64-gnu') - } catch (e) { - loadErrors.push(e) - } - + return require('./parser.linux-riscv64-gnu.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-parser/binding-linux-riscv64-gnu'); + } catch (e) { + loadErrors.push(e); + } } } else if (process.arch === 'ppc64') { try { - return require('./parser.linux-ppc64-gnu.node') + return require('./parser.linux-ppc64-gnu.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-linux-ppc64-gnu') + return require('@oxc-parser/binding-linux-ppc64-gnu'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 's390x') { try { - return require('./parser.linux-s390x-gnu.node') + return require('./parser.linux-s390x-gnu.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-parser/binding-linux-s390x-gnu') + return require('@oxc-parser/binding-linux-s390x-gnu'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`)); } } else { - loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`)); } } -nativeBinding = requireNative() +nativeBinding = requireNative(); if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { try { - nativeBinding = require('./parser.wasi.cjs') + nativeBinding = require('./parser.wasi.cjs'); } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { - console.error(err) + console.error(err); } } if (!nativeBinding) { try { - nativeBinding = require('@oxc-parser/binding-wasm32-wasi') + nativeBinding = require('@oxc-parser/binding-wasm32-wasi'); } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { - console.error(err) + console.error(err); } } } @@ -356,13 +337,13 @@ if (!nativeBinding) { // - The package owner could build/publish bindings for this arch // - The user may need to bundle the correct files // - The user may need to re-install node_modules to get new packages - throw new Error('Failed to load native binding', { cause: loadErrors }) + throw new Error('Failed to load native binding', { cause: loadErrors }); } - throw new Error(`Failed to load native binding`) + throw new Error(`Failed to load native binding`); } -module.exports.moduleLexerAsync = nativeBinding.moduleLexerAsync -module.exports.moduleLexerSync = nativeBinding.moduleLexerSync -module.exports.parseAsync = nativeBinding.parseAsync -module.exports.parseSync = nativeBinding.parseSync -module.exports.parseWithoutReturn = nativeBinding.parseWithoutReturn +module.exports.moduleLexerAsync = nativeBinding.moduleLexerAsync; +module.exports.moduleLexerSync = nativeBinding.moduleLexerSync; +module.exports.parseAsync = nativeBinding.parseAsync; +module.exports.parseSync = nativeBinding.parseSync; +module.exports.parseWithoutReturn = nativeBinding.parseWithoutReturn; diff --git a/napi/parser/parse.bench.mjs b/napi/parser/parse.bench.mjs index 3799d9b9f4..625651e6b1 100644 --- a/napi/parser/parse.bench.mjs +++ b/napi/parser/parse.bench.mjs @@ -1,61 +1,61 @@ -import {fileURLToPath} from 'url'; -import {join as pathJoin} from 'path'; -import {readFile, writeFile} from 'fs/promises'; -import {Bench} from 'tinybench'; -import {parseSync} from './index.js'; +import { readFile, writeFile } from 'fs/promises'; +import { join as pathJoin } from 'path'; +import { Bench } from 'tinybench'; +import { fileURLToPath } from 'url'; +import { parseSync } from './index.js'; const IS_CI = !!process.env.CI, - ACCURATE = IS_CI || process.env.ACCURATE; + ACCURATE = IS_CI || process.env.ACCURATE; const urls = [ - // TypeScript syntax (2.81MB) - 'https://raw.githubusercontent.com/microsoft/TypeScript/v5.3.3/src/compiler/checker.ts', - // Real world app tsx (1.0M) - 'https://raw.githubusercontent.com/oxc-project/benchmark-files/main/cal.com.tsx', - // Real world content-heavy app jsx (3K) - 'https://raw.githubusercontent.com/oxc-project/benchmark-files/main/RadixUIAdoptionSection.jsx', - // Heavy with classes (554K) - 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.269/build/pdf.mjs', - // ES5 (3.9M) - 'https://cdn.jsdelivr.net/npm/antd@5.12.5/dist/antd.js', + // TypeScript syntax (2.81MB) + 'https://raw.githubusercontent.com/microsoft/TypeScript/v5.3.3/src/compiler/checker.ts', + // Real world app tsx (1.0M) + 'https://raw.githubusercontent.com/oxc-project/benchmark-files/main/cal.com.tsx', + // Real world content-heavy app jsx (3K) + 'https://raw.githubusercontent.com/oxc-project/benchmark-files/main/RadixUIAdoptionSection.jsx', + // Heavy with classes (554K) + 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.269/build/pdf.mjs', + // ES5 (3.9M) + 'https://cdn.jsdelivr.net/npm/antd@5.12.5/dist/antd.js', ]; // Same directory as Rust benchmarks use for downloaded files const cacheDirPath = pathJoin(fileURLToPath(import.meta.url), '../../../target'); const files = await Promise.all(urls.map(async (url) => { - const filename = url.split('/').at(-1), - path = pathJoin(cacheDirPath, filename); + const filename = url.split('/').at(-1), + path = pathJoin(cacheDirPath, filename); - let code; - try { - code = await readFile(path, 'utf8'); - if (IS_CI) console.log('Found cached file:', filename); - } catch { - if (IS_CI) console.log('Downloading:', filename); - const res = await fetch(url); - code = await res.text(); - await writeFile(path, code); - } + let code; + try { + code = await readFile(path, 'utf8'); + if (IS_CI) console.log('Found cached file:', filename); + } catch { + if (IS_CI) console.log('Downloading:', filename); + const res = await fetch(url); + code = await res.text(); + await writeFile(path, code); + } - return {filename, code}; + return { filename, code }; })); const bench = new Bench( - ACCURATE + ACCURATE ? { - warmupIterations: 20, // Default is 5 - time: 5000, // 5 seconds, default is 500 ms - iterations: 100, // Default is 10 + warmupIterations: 20, // Default is 5 + time: 5000, // 5 seconds, default is 500 ms + iterations: 100, // Default is 10 } - : undefined + : undefined, ); -for (const {filename, code} of files) { - bench.add(`parser_napi[${filename}]`, () => { - const res = parseSync(code, {sourceFilename: filename}); - JSON.parse(res.program); - }); +for (const { filename, code } of files) { + bench.add(`parser_napi[${filename}]`, () => { + const res = parseSync(code, { sourceFilename: filename }); + JSON.parse(res.program); + }); } console.log('Warming up'); @@ -66,10 +66,10 @@ console.table(bench.table()); // If running on CI, save results to file if (IS_CI) { - const dataDir = process.env.DATA_DIR; - const results = bench.tasks.map(task => ({ - filename: task.name.match(/\[(.+)\]$/)[1], - duration: task.result.period / 1000, // In seconds - })); - await writeFile(pathJoin(dataDir, 'results.json'), JSON.stringify(results)); + const dataDir = process.env.DATA_DIR; + const results = bench.tasks.map(task => ({ + filename: task.name.match(/\[(.+)\]$/)[1], + duration: task.result.period / 1000, // In seconds + })); + await writeFile(pathJoin(dataDir, 'results.json'), JSON.stringify(results)); } diff --git a/napi/parser/test.mjs b/napi/parser/test.mjs index b7209b447d..8d24a8f38d 100644 --- a/napi/parser/test.mjs +++ b/napi/parser/test.mjs @@ -1,7 +1,7 @@ -import oxc from './index.js'; import assert from 'assert'; +import oxc from './index.js'; -console.log(`Testing on ${process.platform}-${process.arch}`) +console.log(`Testing on ${process.platform}-${process.arch}`); function test(ret) { console.log(ret); @@ -10,7 +10,7 @@ function test(ret) { assert(ret.comments.length == 1); } -const sourceText = "/* comment */ foo"; +const sourceText = '/* comment */ foo'; test(oxc.parseSync(sourceText)); @@ -18,4 +18,4 @@ async function main() { test(await oxc.parseAsync(sourceText)); } -main() +main(); diff --git a/napi/parser/test_module_lexer.mjs b/napi/parser/test_module_lexer.mjs index e208a3a3fb..3a2b3895e3 100644 --- a/napi/parser/test_module_lexer.mjs +++ b/napi/parser/test_module_lexer.mjs @@ -1,13 +1,13 @@ /* * Test and bench against `es-module-lexer` */ -import fs from "fs"; -import assert from "assert"; +import assert from 'assert'; +import fs from 'fs'; -import oxc from "./index.js"; -import * as esModuleLexer from "es-module-lexer"; +import * as esModuleLexer from 'es-module-lexer'; +import oxc from './index.js'; -const root = "/Users/boshen/github/es-module-lexer/test/samples"; +const root = '/Users/boshen/github/es-module-lexer/test/samples'; main(); @@ -16,7 +16,7 @@ async function main() { const files = fs .readdirSync(root) - .filter((x) => x.endsWith(".js")) + .filter((x) => x.endsWith('.js')) .map((file) => { const source = fs.readFileSync(`${root}/${file}`); return { @@ -27,8 +27,7 @@ async function main() { }); function test(source) { - const [imports, exports, facade, hasModuleSyntax] = - esModuleLexer.parse(source); + const [imports, exports, facade, hasModuleSyntax] = esModuleLexer.parse(source); const moduleLexer = oxc.moduleLexerSync(source); assert(moduleLexer.imports.length == imports.length); assert(moduleLexer.exports.length == exports.length); @@ -46,11 +45,11 @@ async function main() { const n = 25; - bench("es-module-lexer", esModuleLexer.parse); - bench("oxc", oxc.moduleLexerSync); + bench('es-module-lexer', esModuleLexer.parse); + bench('oxc', oxc.moduleLexerSync); function bench(name, fn) { - console.log("-----------"); + console.log('-----------'); console.log(name); doRun(); @@ -63,7 +62,7 @@ async function main() { } function doRun() { - console.log("Cold Run, All Samples"); + console.log('Cold Run, All Samples'); let totalSize = 0; { let total = 0; @@ -72,7 +71,7 @@ async function main() { total += timeRun(code); }); console.log(`test/samples/*.js (${Math.round(totalSize / 1e3)} KiB)`); - console.log(`> ${total + "ms"}`); + console.log(`> ${total + 'ms'}`); } console.log(`\nWarm Runs (average of ${n} runs)`); @@ -84,7 +83,7 @@ async function main() { total += timeRun(code); } - console.log(`> ${total / n + "ms"}`); + console.log(`> ${total / n + 'ms'}`); }); console.log(`\nWarm Runs, All Samples (average of ${n} runs)`); @@ -96,7 +95,7 @@ async function main() { }); } console.log(`test/samples/*.js (${Math.round(totalSize / 1e3)} KiB)`); - console.log(`> ${total / n + "ms"}`); + console.log(`> ${total / n + 'ms'}`); } } } diff --git a/napi/transform/index.d.ts b/napi/transform/index.d.ts index c7081c9d3f..2594fe46e7 100644 --- a/napi/transform/index.d.ts +++ b/napi/transform/index.d.ts @@ -9,25 +9,29 @@ export interface ArrowFunctionsBindingOptions { * * @default false */ - spec?: boolean + spec?: boolean; } export interface Es2015BindingOptions { /** Transform arrow functions into function expressions. */ - arrowFunction?: ArrowFunctionsBindingOptions + arrowFunction?: ArrowFunctionsBindingOptions; } /** TypeScript Isolated Declarations for Standalone DTS Emit */ -export declare function isolatedDeclaration(filename: string, sourceText: string, options: IsolatedDeclarationsOptions): IsolatedDeclarationsResult +export declare function isolatedDeclaration( + filename: string, + sourceText: string, + options: IsolatedDeclarationsOptions, +): IsolatedDeclarationsResult; export interface IsolatedDeclarationsOptions { - sourcemap: boolean + sourcemap: boolean; } export interface IsolatedDeclarationsResult { - code: string - map?: SourceMap - errors: Array + code: string; + map?: SourceMap; + errors: Array; } /** @@ -44,7 +48,7 @@ export interface ReactBindingOptions { * * @default 'automatic' */ - runtime?: 'classic' | 'automatic' + runtime?: 'classic' | 'automatic'; /** * Emit development-specific information, such as `__source` and `__self`. * @@ -52,7 +56,7 @@ export interface ReactBindingOptions { * * @see [@babel/plugin-transform-react-jsx-development](https://babeljs.io/docs/babel-plugin-transform-react-jsx-development) */ - development?: boolean + development?: boolean; /** * Toggles whether or not to throw an error if an XML namespaced tag name * is used. @@ -62,7 +66,7 @@ export interface ReactBindingOptions { * * @default true */ - throwIfNamespace?: boolean + throwIfNamespace?: boolean; /** * Enables [@babel/plugin-transform-react-pure-annotations](https://babeljs.io/docs/en/babel-plugin-transform-react-pure-annotations). * @@ -70,13 +74,13 @@ export interface ReactBindingOptions { * * @default true */ - pure?: boolean + pure?: boolean; /** * Replaces the import source when importing functions. * * @default 'react' */ - importSource?: string + importSource?: string; /** * Replace the function used when compiling JSX expressions. It should be a * qualified name (e.g. `React.createElement`) or an identifier (e.g. @@ -86,7 +90,7 @@ export interface ReactBindingOptions { * * @default 'React.createElement' */ - pragma?: string + pragma?: string; /** * Replace the component used when compiling JSX fragments. It should be a * valid JSX tag name. @@ -95,7 +99,7 @@ export interface ReactBindingOptions { * * @default 'React.Fragment' */ - pragmaFrag?: string + pragmaFrag?: string; /** * When spreading props, use `Object.assign` directly instead of an extend helper. * @@ -103,7 +107,7 @@ export interface ReactBindingOptions { * * @default false */ - useBuiltIns?: boolean + useBuiltIns?: boolean; /** * When spreading props, use inline object with spread elements directly * instead of an extend helper or Object.assign. @@ -112,9 +116,9 @@ export interface ReactBindingOptions { * * @default false */ - useSpread?: boolean + useSpread?: boolean; /** Enable react fast refresh transform */ - refresh?: ReactRefreshBindingOptions + refresh?: ReactRefreshBindingOptions; } export interface ReactRefreshBindingOptions { @@ -123,23 +127,23 @@ export interface ReactRefreshBindingOptions { * * @default `$RefreshReg$`. */ - refreshReg?: string + refreshReg?: string; /** * Specify the identifier of the refresh signature variable. * * @default `$RefreshSig$`. */ - refreshSig?: string - emitFullSignatures?: boolean + refreshSig?: string; + emitFullSignatures?: boolean; } export interface SourceMap { - file?: string - mappings?: string - sourceRoot?: string - sources?: Array - sourcesContent?: Array - names?: Array + file?: string; + mappings?: string; + sourceRoot?: string; + sources?: Array; + sourcesContent?: Array; + names?: Array; } /** @@ -154,7 +158,11 @@ export interface SourceMap { * @returns an object containing the transformed code, source maps, and any * errors that occurred during parsing or transformation. */ -export declare function transform(filename: string, sourceText: string, options?: TransformOptions | undefined | null): TransformResult +export declare function transform( + filename: string, + sourceText: string, + options?: TransformOptions | undefined | null, +): TransformResult; /** * Options for transforming a JavaScript or TypeScript file. @@ -162,24 +170,24 @@ export declare function transform(filename: string, sourceText: string, options? * @see {@link transform} */ export interface TransformOptions { - sourceType?: 'script' | 'module' | 'unambiguous' | undefined + sourceType?: 'script' | 'module' | 'unambiguous' | undefined; /** * The current working directory. Used to resolve relative paths in other * options. */ - cwd?: string + cwd?: string; /** * Force jsx parsing, * * @default false */ - jsx?: boolean + jsx?: boolean; /** Configure how TypeScript is transformed. */ - typescript?: TypeScriptBindingOptions + typescript?: TypeScriptBindingOptions; /** Configure how TSX and JSX are transformed. */ - react?: ReactBindingOptions + react?: ReactBindingOptions; /** Enable ES2015 transformations. */ - es2015?: Es2015BindingOptions + es2015?: Es2015BindingOptions; /** * Enable source map generation. * @@ -189,7 +197,7 @@ export interface TransformOptions { * * @see {@link SourceMap} */ - sourcemap?: boolean + sourcemap?: boolean; } export interface TransformResult { @@ -198,13 +206,13 @@ export interface TransformResult { * * If parsing failed, this will be an empty string. */ - code: string + code: string; /** * The source map for the transformed code. * * This will be set if {@link TransformOptions#sourcemap} is `true`. */ - map?: SourceMap + map?: SourceMap; /** * The `.d.ts` declaration file for the transformed code. Declarations are * only generated if `declaration` is set to `true` and a TypeScript file @@ -215,13 +223,13 @@ export interface TransformResult { * @see {@link TypeScriptBindingOptions#declaration} * @see [declaration tsconfig option](https://www.typescriptlang.org/tsconfig/#declaration) */ - declaration?: string + declaration?: string; /** * Declaration source map. Only generated if both * {@link TypeScriptBindingOptions#declaration declaration} and * {@link TransformOptions#sourcemap sourcemap} are set to `true`. */ - declarationMap?: SourceMap + declarationMap?: SourceMap; /** * Parse and transformation errors. * @@ -229,15 +237,15 @@ export interface TransformResult { * transformed code may still be available even if there are errors in this * list. */ - errors: Array + errors: Array; } export interface TypeScriptBindingOptions { - jsxPragma?: string - jsxPragmaFrag?: string - onlyRemoveTypeImports?: boolean - allowNamespaces?: boolean - allowDeclareFields?: boolean + jsxPragma?: string; + jsxPragmaFrag?: string; + onlyRemoveTypeImports?: boolean; + allowNamespaces?: boolean; + allowDeclareFields?: boolean; /** * Also generate a `.d.ts` declaration file for TypeScript files. * @@ -247,7 +255,7 @@ export interface TypeScriptBindingOptions { * * @default false */ - declaration?: boolean + declaration?: boolean; /** * Rewrite or remove TypeScript import/export declaration extensions. * @@ -258,6 +266,5 @@ export interface TypeScriptBindingOptions { * * @default false */ - rewriteImportExtensions?: 'rewrite' | 'remove' | boolean + rewriteImportExtensions?: 'rewrite' | 'remove' | boolean; } - diff --git a/napi/transform/index.js b/napi/transform/index.js index e1092b640a..b4268040ef 100644 --- a/napi/transform/index.js +++ b/napi/transform/index.js @@ -2,349 +2,330 @@ /* eslint-disable */ /* auto-generated by NAPI-RS */ -const { readFileSync } = require('fs') +const { readFileSync } = require('fs'); -let nativeBinding = null -const loadErrors = [] +let nativeBinding = null; +const loadErrors = []; const isMusl = () => { - let musl = false + let musl = false; if (process.platform === 'linux') { - musl = isMuslFromFilesystem() + musl = isMuslFromFilesystem(); if (musl === null) { - musl = isMuslFromReport() + musl = isMuslFromReport(); } if (musl === null) { - musl = isMuslFromChildProcess() + musl = isMuslFromChildProcess(); } } - return musl -} + return musl; +}; -const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-') +const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-'); const isMuslFromFilesystem = () => { try { - return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl') + return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl'); } catch { - return null + return null; } -} +}; const isMuslFromReport = () => { - const report = typeof process.report.getReport === 'function' ? process.report.getReport() : null + const report = typeof process.report.getReport === 'function' ? process.report.getReport() : null; if (!report) { - return null + return null; } if (report.header && report.header.glibcVersionRuntime) { - return false + return false; } if (Array.isArray(report.sharedObjects)) { if (report.sharedObjects.some(isFileMusl)) { - return true + return true; } } - return false -} + return false; +}; const isMuslFromChildProcess = () => { try { - return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl') + return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl'); } catch (e) { // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false - return false + return false; } -} +}; function requireNative() { if (process.platform === 'android') { if (process.arch === 'arm64') { try { - return require('./transform.android-arm64.node') + return require('./transform.android-arm64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-android-arm64') + return require('@oxc-transform/binding-android-arm64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'arm') { try { - return require('./transform.android-arm-eabi.node') + return require('./transform.android-arm-eabi.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-android-arm-eabi') + return require('@oxc-transform/binding-android-arm-eabi'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`)); } } else if (process.platform === 'win32') { if (process.arch === 'x64') { try { - return require('./transform.win32-x64-msvc.node') + return require('./transform.win32-x64-msvc.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-win32-x64-msvc') + return require('@oxc-transform/binding-win32-x64-msvc'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'ia32') { try { - return require('./transform.win32-ia32-msvc.node') + return require('./transform.win32-ia32-msvc.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-win32-ia32-msvc') + return require('@oxc-transform/binding-win32-ia32-msvc'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'arm64') { try { - return require('./transform.win32-arm64-msvc.node') + return require('./transform.win32-arm64-msvc.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-win32-arm64-msvc') + return require('@oxc-transform/binding-win32-arm64-msvc'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`)); } } else if (process.platform === 'darwin') { try { - return require('./transform.darwin-universal.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-transform/binding-darwin-universal') - } catch (e) { - loadErrors.push(e) - } + return require('./transform.darwin-universal.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-transform/binding-darwin-universal'); + } catch (e) { + loadErrors.push(e); + } if (process.arch === 'x64') { try { - return require('./transform.darwin-x64.node') + return require('./transform.darwin-x64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-darwin-x64') + return require('@oxc-transform/binding-darwin-x64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'arm64') { try { - return require('./transform.darwin-arm64.node') + return require('./transform.darwin-arm64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-darwin-arm64') + return require('@oxc-transform/binding-darwin-arm64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`)); } } else if (process.platform === 'freebsd') { if (process.arch === 'x64') { try { - return require('./transform.freebsd-x64.node') + return require('./transform.freebsd-x64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-freebsd-x64') + return require('@oxc-transform/binding-freebsd-x64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 'arm64') { try { - return require('./transform.freebsd-arm64.node') + return require('./transform.freebsd-arm64.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-freebsd-arm64') + return require('@oxc-transform/binding-freebsd-arm64'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`)); } } else if (process.platform === 'linux') { if (process.arch === 'x64') { if (isMusl()) { try { - return require('./transform.linux-x64-musl.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-transform/binding-linux-x64-musl') - } catch (e) { - loadErrors.push(e) - } - + return require('./transform.linux-x64-musl.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-transform/binding-linux-x64-musl'); + } catch (e) { + loadErrors.push(e); + } } else { try { - return require('./transform.linux-x64-gnu.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-transform/binding-linux-x64-gnu') - } catch (e) { - loadErrors.push(e) - } - + return require('./transform.linux-x64-gnu.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-transform/binding-linux-x64-gnu'); + } catch (e) { + loadErrors.push(e); + } } } else if (process.arch === 'arm64') { if (isMusl()) { try { - return require('./transform.linux-arm64-musl.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-transform/binding-linux-arm64-musl') - } catch (e) { - loadErrors.push(e) - } - + return require('./transform.linux-arm64-musl.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-transform/binding-linux-arm64-musl'); + } catch (e) { + loadErrors.push(e); + } } else { try { - return require('./transform.linux-arm64-gnu.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-transform/binding-linux-arm64-gnu') - } catch (e) { - loadErrors.push(e) - } - + return require('./transform.linux-arm64-gnu.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-transform/binding-linux-arm64-gnu'); + } catch (e) { + loadErrors.push(e); + } } } else if (process.arch === 'arm') { if (isMusl()) { try { - return require('./transform.linux-arm-musleabihf.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-transform/binding-linux-arm-musleabihf') - } catch (e) { - loadErrors.push(e) - } - + return require('./transform.linux-arm-musleabihf.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-transform/binding-linux-arm-musleabihf'); + } catch (e) { + loadErrors.push(e); + } } else { try { - return require('./transform.linux-arm-gnueabihf.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-transform/binding-linux-arm-gnueabihf') - } catch (e) { - loadErrors.push(e) - } - + return require('./transform.linux-arm-gnueabihf.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-transform/binding-linux-arm-gnueabihf'); + } catch (e) { + loadErrors.push(e); + } } } else if (process.arch === 'riscv64') { if (isMusl()) { try { - return require('./transform.linux-riscv64-musl.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-transform/binding-linux-riscv64-musl') - } catch (e) { - loadErrors.push(e) - } - + return require('./transform.linux-riscv64-musl.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-transform/binding-linux-riscv64-musl'); + } catch (e) { + loadErrors.push(e); + } } else { try { - return require('./transform.linux-riscv64-gnu.node') - } catch (e) { - loadErrors.push(e) - } - try { - return require('@oxc-transform/binding-linux-riscv64-gnu') - } catch (e) { - loadErrors.push(e) - } - + return require('./transform.linux-riscv64-gnu.node'); + } catch (e) { + loadErrors.push(e); + } + try { + return require('@oxc-transform/binding-linux-riscv64-gnu'); + } catch (e) { + loadErrors.push(e); + } } } else if (process.arch === 'ppc64') { try { - return require('./transform.linux-ppc64-gnu.node') + return require('./transform.linux-ppc64-gnu.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-linux-ppc64-gnu') + return require('@oxc-transform/binding-linux-ppc64-gnu'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else if (process.arch === 's390x') { try { - return require('./transform.linux-s390x-gnu.node') + return require('./transform.linux-s390x-gnu.node'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } try { - return require('@oxc-transform/binding-linux-s390x-gnu') + return require('@oxc-transform/binding-linux-s390x-gnu'); } catch (e) { - loadErrors.push(e) + loadErrors.push(e); } - } else { - loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`)); } } else { - loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`)) + loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`)); } } -nativeBinding = requireNative() +nativeBinding = requireNative(); if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { try { - nativeBinding = require('./transform.wasi.cjs') + nativeBinding = require('./transform.wasi.cjs'); } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { - console.error(err) + console.error(err); } } if (!nativeBinding) { try { - nativeBinding = require('@oxc-transform/binding-wasm32-wasi') + nativeBinding = require('@oxc-transform/binding-wasm32-wasi'); } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { - console.error(err) + console.error(err); } } } @@ -356,10 +337,10 @@ if (!nativeBinding) { // - The package owner could build/publish bindings for this arch // - The user may need to bundle the correct files // - The user may need to re-install node_modules to get new packages - throw new Error('Failed to load native binding', { cause: loadErrors }) + throw new Error('Failed to load native binding', { cause: loadErrors }); } - throw new Error(`Failed to load native binding`) + throw new Error(`Failed to load native binding`); } -module.exports.isolatedDeclaration = nativeBinding.isolatedDeclaration -module.exports.transform = nativeBinding.transform +module.exports.isolatedDeclaration = nativeBinding.isolatedDeclaration; +module.exports.transform = nativeBinding.transform; diff --git a/napi/transform/test.mjs b/napi/transform/test.mjs index 0bdc385602..ab127de27f 100644 --- a/napi/transform/test.mjs +++ b/napi/transform/test.mjs @@ -1,15 +1,15 @@ -import oxc from "./index.js"; -import assert from "assert"; +import assert from 'assert'; +import oxc from './index.js'; console.log(`Testing on ${process.platform}-${process.arch}`); -test(oxc.isolatedDeclaration("test.ts", "class A {}", { sourcemap: true }), { - code: "declare class A {}\n", +test(oxc.isolatedDeclaration('test.ts', 'class A {}', { sourcemap: true }), { + code: 'declare class A {}\n', map: { - mappings: "AAAA,cAAM,EAAE,CAAE", + mappings: 'AAAA,cAAM,EAAE,CAAE', names: [], - sources: ["test.ts"], - sourcesContent: ["class A {}"], + sources: ['test.ts'], + sourcesContent: ['class A {}'], }, }); diff --git a/npm/oxc-parser/README.md b/npm/oxc-parser/README.md index a9b3a4464d..7788d3d6f2 100644 --- a/npm/oxc-parser/README.md +++ b/npm/oxc-parser/README.md @@ -5,8 +5,8 @@ See index.d.ts for `parseSync` and `parseAsync` API. ## ESM ```javascript -import oxc from "oxc-parser"; -import assert from "assert"; +import assert from 'assert'; +import oxc from 'oxc-parser'; function test(ret) { const program = JSON.parse(ret.program); @@ -16,7 +16,7 @@ function test(ret) { const sourceText = "let foo: Foo = 'foo';"; const options = { - sourceFilename: "text.tsx", // the extension is used to determine which dialect to parse + sourceFilename: 'text.tsx', // the extension is used to determine which dialect to parse }; test(oxc.parseSync(sourceText, options)); diff --git a/npm/oxc-parser/scripts/generate-packages.mjs b/npm/oxc-parser/scripts/generate-packages.mjs index 296177560e..8ed558a1e9 100644 --- a/npm/oxc-parser/scripts/generate-packages.mjs +++ b/npm/oxc-parser/scripts/generate-packages.mjs @@ -1,13 +1,13 @@ // Code copied from [Rome](https://github.com/rome/tools/blob/main/npm/rome/scripts/generate-packages.mjs) -import { resolve } from "node:path"; -import { fileURLToPath } from "node:url"; -import * as fs from "node:fs"; +import * as fs from 'node:fs'; +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; -const OXC_ROOT = resolve(fileURLToPath(import.meta.url), "../.."); -const PACKAGES_ROOT = resolve(OXC_ROOT, ".."); -const BINARY_ROOT = resolve(OXC_ROOT, "../../napi/parser"); -const MANIFEST_PATH = resolve(OXC_ROOT, "package.json"); +const OXC_ROOT = resolve(fileURLToPath(import.meta.url), '../..'); +const PACKAGES_ROOT = resolve(OXC_ROOT, '..'); +const BINARY_ROOT = resolve(OXC_ROOT, '../../napi/parser'); +const MANIFEST_PATH = resolve(OXC_ROOT, 'package.json'); console.log('OXC_ROOT', OXC_ROOT); console.log('PACKAGES_ROOT', PACKAGES_ROOT); @@ -15,16 +15,16 @@ console.log('BINARY_ROOT', BINARY_ROOT); console.log('MANIFEST_PATH', MANIFEST_PATH); const LIBC_MAPPING = { - "gnu": "glibc", - "musl": "musl", -} + 'gnu': 'glibc', + 'musl': 'musl', +}; const rootManifest = JSON.parse( - fs.readFileSync(MANIFEST_PATH).toString("utf-8") + fs.readFileSync(MANIFEST_PATH).toString('utf-8'), ); function package_name(target) { - return `@oxc-parser/binding-${target}` + return `@oxc-parser/binding-${target}`; } function generateNativePackage(target) { const binaryName = `parser.${target}.node`; @@ -44,10 +44,10 @@ function generateNativePackage(target) { // Generate the package.json manifest const { version, author, license, homepage, bugs, repository } = rootManifest; - const triple = target.split("-"); + const triple = target.split('-'); const platform = triple[0]; const arch = triple[1]; - const libc = triple[2] && LIBC_MAPPING[triple[2]] && { libc: [LIBC_MAPPING[triple[2]]] } + const libc = triple[2] && LIBC_MAPPING[triple[2]] && { libc: [LIBC_MAPPING[triple[2]]] }; const manifest = { name: package_name(target), version, @@ -60,10 +60,10 @@ function generateNativePackage(target) { files: [binaryName], cpu: [arch], os: [platform], - ...libc + ...libc, }; - const manifestPath = resolve(packageRoot, "package.json"); + const manifestPath = resolve(packageRoot, 'package.json'); console.log(`Create manifest ${manifestPath}`); fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); @@ -73,12 +73,12 @@ function generateNativePackage(target) { function writeManifest() { const packageRoot = resolve(PACKAGES_ROOT, 'oxc-parser'); - const manifestPath = resolve(packageRoot, "package.json"); + const manifestPath = resolve(packageRoot, 'package.json'); console.log('packageRoot', packageRoot); const manifestData = JSON.parse( - fs.readFileSync(manifestPath).toString("utf-8") + fs.readFileSync(manifestPath).toString('utf-8'), ); const nativePackages = TARGETS.map((target) => [ @@ -86,8 +86,8 @@ function writeManifest() { rootManifest.version, ]); - manifestData["version"] = rootManifest.version; - manifestData["optionalDependencies"] = Object.fromEntries(nativePackages); + manifestData['version'] = rootManifest.version; + manifestData['optionalDependencies'] = Object.fromEntries(nativePackages); console.log('manifestPath', manifestPath); console.log('manifestData', manifestData); @@ -95,7 +95,7 @@ function writeManifest() { const content = JSON.stringify(manifestData, null, 2); fs.writeFileSync(manifestPath, content); - let files = ["index.js", "index.d.ts"]; + let files = ['index.js', 'index.d.ts']; for (const file of files) { fs.copyFileSync(resolve(BINARY_ROOT, file), resolve(packageRoot, file)); } @@ -103,14 +103,14 @@ function writeManifest() { // NOTE: Must update npm/oxc-parser/package.json const TARGETS = [ - "win32-x64-msvc", - "win32-arm64-msvc", - "linux-x64-gnu", - "linux-arm64-gnu", - "linux-x64-musl", - "linux-arm64-musl", - "darwin-x64", - "darwin-arm64", + 'win32-x64-msvc', + 'win32-arm64-msvc', + 'linux-x64-gnu', + 'linux-arm64-gnu', + 'linux-x64-musl', + 'linux-arm64-musl', + 'darwin-x64', + 'darwin-arm64', ]; for (const target of TARGETS) { diff --git a/npm/oxc-transform/README.md b/npm/oxc-transform/README.md index 71a8b1db9b..aebc29ce3b 100644 --- a/npm/oxc-transform/README.md +++ b/npm/oxc-transform/README.md @@ -12,14 +12,14 @@ This is still in alpha and may yield incorrect results, feel free to [submit a b import assert from 'assert'; import oxc from 'oxc-transform'; -const { sourceMap, sourceText, errors } = oxc.isolatedDeclaration("test.ts", "class A {}", { sourcemap: true }); +const { sourceMap, sourceText, errors } = oxc.isolatedDeclaration('test.ts', 'class A {}', { sourcemap: true }); -assert.equal(sourceText, "declare class A {}\n"); +assert.equal(sourceText, 'declare class A {}\n'); assert.deepEqual(ret.sourceMap, { - mappings: "AAAA,cAAM,EAAE,CAAE", + mappings: 'AAAA,cAAM,EAAE,CAAE', names: [], - sources: ["test.ts"], - sourcesContent: ["class A {}"], + sources: ['test.ts'], + sourcesContent: ['class A {}'], }); assert(errors.length == 0); ``` @@ -27,14 +27,18 @@ assert(errors.length == 0); ### API ```typescript -export function isolatedDeclaration(filename: string, sourceText: string, options: IsolatedDeclarationsOptions): IsolatedDeclarationsResult +export function isolatedDeclaration( + filename: string, + sourceText: string, + options: IsolatedDeclarationsOptions, +): IsolatedDeclarationsResult; export interface IsolatedDeclarationsOptions { - sourcemap: boolean + sourcemap: boolean; } export interface IsolatedDeclarationsResult { - sourceText: string - errors: Array + sourceText: string; + errors: Array; } ``` diff --git a/npm/oxc-transform/scripts/generate-packages.mjs b/npm/oxc-transform/scripts/generate-packages.mjs index a7435930e4..555ebc0492 100644 --- a/npm/oxc-transform/scripts/generate-packages.mjs +++ b/npm/oxc-transform/scripts/generate-packages.mjs @@ -1,13 +1,13 @@ // Code copied from [Rome](https://github.com/rome/tools/blob/main/npm/rome/scripts/generate-packages.mjs) -import { resolve } from "node:path"; -import { fileURLToPath } from "node:url"; -import * as fs from "node:fs"; +import * as fs from 'node:fs'; +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; -const OXC_ROOT = resolve(fileURLToPath(import.meta.url), "../.."); -const PACKAGES_ROOT = resolve(OXC_ROOT, ".."); -const BINARY_ROOT = resolve(OXC_ROOT, "../../napi/transform"); -const MANIFEST_PATH = resolve(OXC_ROOT, "package.json"); +const OXC_ROOT = resolve(fileURLToPath(import.meta.url), '../..'); +const PACKAGES_ROOT = resolve(OXC_ROOT, '..'); +const BINARY_ROOT = resolve(OXC_ROOT, '../../napi/transform'); +const MANIFEST_PATH = resolve(OXC_ROOT, 'package.json'); console.log('OXC_ROOT', OXC_ROOT); console.log('PACKAGES_ROOT', PACKAGES_ROOT); @@ -15,16 +15,16 @@ console.log('BINARY_ROOT', BINARY_ROOT); console.log('MANIFEST_PATH', MANIFEST_PATH); const LIBC_MAPPING = { - "gnu": "glibc", - "musl": "musl", -} + 'gnu': 'glibc', + 'musl': 'musl', +}; const rootManifest = JSON.parse( - fs.readFileSync(MANIFEST_PATH).toString("utf-8") + fs.readFileSync(MANIFEST_PATH).toString('utf-8'), ); function package_name(target) { - return `@oxc-transform/binding-${target}` + return `@oxc-transform/binding-${target}`; } function generateNativePackage(target) { const binaryName = `transform.${target}.node`; @@ -44,10 +44,10 @@ function generateNativePackage(target) { // Generate the package.json manifest const { version, author, license, homepage, bugs, repository } = rootManifest; - const triple = target.split("-"); + const triple = target.split('-'); const platform = triple[0]; const arch = triple[1]; - const libc = triple[2] && LIBC_MAPPING[triple[2]] && { libc: [LIBC_MAPPING[triple[2]]] } + const libc = triple[2] && LIBC_MAPPING[triple[2]] && { libc: [LIBC_MAPPING[triple[2]]] }; const manifest = { name: package_name(target), version, @@ -60,10 +60,10 @@ function generateNativePackage(target) { files: [binaryName], cpu: [arch], os: [platform], - ...libc + ...libc, }; - const manifestPath = resolve(packageRoot, "package.json"); + const manifestPath = resolve(packageRoot, 'package.json'); console.log(`Create manifest ${manifestPath}`); fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); @@ -73,12 +73,12 @@ function generateNativePackage(target) { function writeManifest() { const packageRoot = resolve(PACKAGES_ROOT, 'oxc-transform'); - const manifestPath = resolve(packageRoot, "package.json"); + const manifestPath = resolve(packageRoot, 'package.json'); console.log('packageRoot', packageRoot); const manifestData = JSON.parse( - fs.readFileSync(manifestPath).toString("utf-8") + fs.readFileSync(manifestPath).toString('utf-8'), ); const nativePackages = TARGETS.map((target) => [ @@ -86,8 +86,8 @@ function writeManifest() { rootManifest.version, ]); - manifestData["version"] = rootManifest.version; - manifestData["optionalDependencies"] = Object.fromEntries(nativePackages); + manifestData['version'] = rootManifest.version; + manifestData['optionalDependencies'] = Object.fromEntries(nativePackages); console.log('manifestPath', manifestPath); console.log('manifestData', manifestData); @@ -95,7 +95,7 @@ function writeManifest() { const content = JSON.stringify(manifestData, null, 2); fs.writeFileSync(manifestPath, content); - let files = ["index.js", "index.d.ts"]; + let files = ['index.js', 'index.d.ts']; for (const file of files) { fs.copyFileSync(resolve(BINARY_ROOT, file), resolve(packageRoot, file)); } @@ -103,14 +103,14 @@ function writeManifest() { // NOTE: Must update npm/oxc-transform/package.json const TARGETS = [ - "win32-x64-msvc", - "win32-arm64-msvc", - "linux-x64-gnu", - "linux-arm64-gnu", - "linux-x64-musl", - "linux-arm64-musl", - "darwin-x64", - "darwin-arm64", + 'win32-x64-msvc', + 'win32-arm64-msvc', + 'linux-x64-gnu', + 'linux-arm64-gnu', + 'linux-x64-musl', + 'linux-arm64-musl', + 'darwin-x64', + 'darwin-arm64', ]; for (const target of TARGETS) { diff --git a/npm/oxlint/README.md b/npm/oxlint/README.md index cc8b801911..7fc5c6105e 100644 --- a/npm/oxlint/README.md +++ b/npm/oxlint/README.md @@ -43,6 +43,6 @@ See [usage instructions](https://oxc.rs/docs/guide/usage/linter.html). Run -* `npx --yes oxlint@latest` in your JavaScript / TypeScript codebase and see it complete in milliseconds. No configurations are required. -* `npx oxlint@latest --help` for quick usage instructions. -* `npx oxlint@latest --rules` for the list of rules. +- `npx --yes oxlint@latest` in your JavaScript / TypeScript codebase and see it complete in milliseconds. No configurations are required. +- `npx oxlint@latest --help` for quick usage instructions. +- `npx oxlint@latest --rules` for the list of rules. diff --git a/npm/oxlint/configuration_schema.json b/npm/oxlint/configuration_schema.json index 9f06b0720e..0a8386fe27 100644 --- a/npm/oxlint/configuration_schema.json +++ b/npm/oxlint/configuration_schema.json @@ -295,4 +295,4 @@ ] } } -} \ No newline at end of file +} diff --git a/npm/oxlint/package.json b/npm/oxlint/package.json index 3c3405e9fa..ce7a34b993 100644 --- a/npm/oxlint/package.json +++ b/npm/oxlint/package.json @@ -25,4 +25,4 @@ "configuration_schema.json", "README.md" ] -} \ No newline at end of file +} diff --git a/npm/oxlint/scripts/generate-packages.mjs b/npm/oxlint/scripts/generate-packages.mjs index 7fe7a665b8..2bf6c1feb8 100644 --- a/npm/oxlint/scripts/generate-packages.mjs +++ b/npm/oxlint/scripts/generate-packages.mjs @@ -1,24 +1,24 @@ // Code copied from [Rome](https://github.com/rome/tools/blob/main/npm/rome/scripts/generate-packages.mjs) -import { resolve } from "node:path"; -import { fileURLToPath } from "node:url"; -import * as fs from "node:fs"; +import * as fs from 'node:fs'; +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; -const OXLINT_BIN_NAME = "oxlint"; -const OXLS_BIN_NAME = "oxc_language_server"; -const OXLINT_ROOT = resolve(fileURLToPath(import.meta.url), "../.."); -const PACKAGES_ROOT = resolve(OXLINT_ROOT, ".."); -const REPO_ROOT = resolve(PACKAGES_ROOT, ".."); -const MANIFEST_PATH = resolve(OXLINT_ROOT, "package.json"); +const OXLINT_BIN_NAME = 'oxlint'; +const OXLS_BIN_NAME = 'oxc_language_server'; +const OXLINT_ROOT = resolve(fileURLToPath(import.meta.url), '../..'); +const PACKAGES_ROOT = resolve(OXLINT_ROOT, '..'); +const REPO_ROOT = resolve(PACKAGES_ROOT, '..'); +const MANIFEST_PATH = resolve(OXLINT_ROOT, 'package.json'); const rootManifest = JSON.parse( - fs.readFileSync(MANIFEST_PATH).toString("utf-8") + fs.readFileSync(MANIFEST_PATH).toString('utf-8'), ); const LIBC_MAPPING = { - "gnu": "glibc", - "musl": "musl", -} + 'gnu': 'glibc', + 'musl': 'musl', +}; function generateNativePackage(target) { const packageName = `@${OXLINT_BIN_NAME}/${target}`; @@ -35,10 +35,10 @@ function generateNativePackage(target) { // Generate the package.json manifest const { version, author, license, homepage, bugs, repository } = rootManifest; - const triple = target.split("-"); + const triple = target.split('-'); const platform = triple[0]; const arch = triple[1]; - const libc = triple[2] && { libc: [LIBC_MAPPING[triple[2]]] } + const libc = triple[2] && { libc: [LIBC_MAPPING[triple[2]]] }; const manifest = { name: packageName, version, @@ -49,15 +49,15 @@ function generateNativePackage(target) { repository, os: [platform], cpu: [arch], - ...libc + ...libc, }; - const manifestPath = resolve(packageRoot, "package.json"); + const manifestPath = resolve(packageRoot, 'package.json'); console.log(`Create manifest ${manifestPath}`); fs.writeFileSync(manifestPath, JSON.stringify(manifest)); // Copy the binary - const ext = platform === "win32" ? ".exe" : ""; + const ext = platform === 'win32' ? '.exe' : ''; const oxlintBinSource = resolve(REPO_ROOT, `${OXLINT_BIN_NAME}-${target}${ext}`); const oxlintBinTarget = resolve(packageRoot, `${OXLINT_BIN_NAME}${ext}`); @@ -75,10 +75,10 @@ function generateNativePackage(target) { } function writeManifest() { - const manifestPath = resolve(PACKAGES_ROOT, OXLINT_BIN_NAME, "package.json"); + const manifestPath = resolve(PACKAGES_ROOT, OXLINT_BIN_NAME, 'package.json'); const manifestData = JSON.parse( - fs.readFileSync(manifestPath).toString("utf-8") + fs.readFileSync(manifestPath).toString('utf-8'), ); const nativePackages = TARGETS.map((target) => [ @@ -86,8 +86,8 @@ function writeManifest() { rootManifest.version, ]); - manifestData["version"] = rootManifest.version; - manifestData["optionalDependencies"] = Object.fromEntries(nativePackages); + manifestData['version'] = rootManifest.version; + manifestData['optionalDependencies'] = Object.fromEntries(nativePackages); console.log(`Update manifest ${manifestPath}`); const content = JSON.stringify(manifestData); @@ -97,18 +97,18 @@ function writeManifest() { // NOTE: Must update npm/oxlint/bin/oxlint // and npm/oxlint/bin/oxc_language_server const TARGETS = [ - "win32-x64", - "win32-arm64", - "linux-x64-gnu", - "linux-arm64-gnu", - "linux-x64-musl", - "linux-arm64-musl", - "darwin-x64", - "darwin-arm64", -] + 'win32-x64', + 'win32-arm64', + 'linux-x64-gnu', + 'linux-arm64-gnu', + 'linux-x64-musl', + 'linux-arm64-musl', + 'darwin-x64', + 'darwin-arm64', +]; for (const target of TARGETS) { - generateNativePackage(target); + generateNativePackage(target); } writeManifest(); diff --git a/tasks/benchmark/codspeed/capture.mjs b/tasks/benchmark/codspeed/capture.mjs index 509d1a130b..c468368322 100644 --- a/tasks/benchmark/codspeed/capture.mjs +++ b/tasks/benchmark/codspeed/capture.mjs @@ -9,19 +9,19 @@ * then shuts itself down. */ -import {createWriteStream} from 'fs'; -import fs from 'fs/promises'; -import {join as pathJoin} from 'path'; -import {pipeline} from 'stream/promises'; import express from 'express'; -import {extract} from 'tar'; +import { createWriteStream } from 'fs'; +import fs from 'fs/promises'; +import { join as pathJoin } from 'path'; +import { pipeline } from 'stream/promises'; +import { extract } from 'tar'; const DEFAULT_PORT = 3000, - LISTEN_ATTEMPTS = 10; + LISTEN_ATTEMPTS = 10; // Create directory for saving assets const rand = Math.round(Math.random() * 100000000000000).toString(16), - dataDir = `/tmp/oxc_bench_data_${rand}`; + dataDir = `/tmp/oxc_bench_data_${rand}`; await fs.mkdir(dataDir); let component = process.env.COMPONENT; @@ -29,61 +29,69 @@ if (process.env.FIXTURE) component += process.env.FIXTURE; const app = express(); -const wrapHandler = fn => (req, res, next) => { fn(req, res).catch(next); }; +const wrapHandler = fn => (req, res, next) => { + fn(req, res).catch(next); +}; const getFilePath = filename => pathJoin(dataDir, `${component}_${filename}`); -app.post('/upload', wrapHandler(async (req, res) => { +app.post( + '/upload', + wrapHandler(async (req, res) => { const stream = createWriteStream(getFilePath('metadata.json')); await pipeline(req, stream); res.json({ - status: 'success', - uploadUrl: `http://localhost:${port}/upload_archive`, - runId: 'dummy_value', + status: 'success', + uploadUrl: `http://localhost:${port}/upload_archive`, + runId: 'dummy_value', }); -})); + }), +); -app.put('/upload_archive', wrapHandler(async (req, res) => { +app.put( + '/upload_archive', + wrapHandler(async (req, res) => { // Stream uploaded tarball to file const path = getFilePath('archive.tar.gz'); const stream = createWriteStream(path); await pipeline(req, stream); // Untar contents + delete tarball - await extract({file: path, cwd: dataDir}); + await extract({ file: path, cwd: dataDir }); await fs.rm(path); // Rename `.out` files + delete `.log` files const filenames = await fs.readdir(dataDir); for (const filename of filenames) { - if (filename.endsWith('.log')) { - await fs.rm(pathJoin(dataDir, filename)); - } else if (filename.endsWith('.out')) { - await fs.rename(pathJoin(dataDir, filename), getFilePath(filename)); - } + if (filename.endsWith('.log')) { + await fs.rm(pathJoin(dataDir, filename)); + } else if (filename.endsWith('.out')) { + await fs.rename(pathJoin(dataDir, filename), getFilePath(filename)); + } } // Send response res.send(''); server.close(() => {}); -})); + }), +); // Open server on a port which is not already in use let server, - port = DEFAULT_PORT; + port = DEFAULT_PORT; for (let i = 0; i < LISTEN_ATTEMPTS; i++) { - console.log(`Starting server on port ${port}`); - try { - await new Promise((resolve, reject) => { - server = app.listen(port, resolve); - server.on('error', reject); - }); - break; - } catch (err) { - if (err?.code !== 'EADDRINUSE') throw err; - console.log(`Port ${port} in use. Trying again.`); - port = DEFAULT_PORT + Math.round(Math.random() * 5000); - } + console.log(`Starting server on port ${port}`); + try { + await new Promise((resolve, reject) => { + server = app.listen(port, resolve); + server.on('error', reject); + }); + break; + } catch (err) { + if (err?.code !== 'EADDRINUSE') throw err; + console.log(`Port ${port} in use. Trying again.`); + port = DEFAULT_PORT + Math.round(Math.random() * 5000); + } } console.log(`Server listening on port ${port}`); diff --git a/tasks/benchmark/codspeed/create_temp_dir.mjs b/tasks/benchmark/codspeed/create_temp_dir.mjs index f07559d8bf..f90c8e1942 100644 --- a/tasks/benchmark/codspeed/create_temp_dir.mjs +++ b/tasks/benchmark/codspeed/create_temp_dir.mjs @@ -6,7 +6,7 @@ import fs from 'fs'; // Create directory for saving assets const rand = Math.round(Math.random() * 1000000000000000000).toString(16), - dataDir = `/tmp/oxc_bench_data_${rand}`; + dataDir = `/tmp/oxc_bench_data_${rand}`; fs.mkdirSync(dataDir); // Output dir path to env var diff --git a/tasks/benchmark/codspeed/upload.mjs b/tasks/benchmark/codspeed/upload.mjs index 8a3cc90a67..dd438a1162 100644 --- a/tasks/benchmark/codspeed/upload.mjs +++ b/tasks/benchmark/codspeed/upload.mjs @@ -2,34 +2,34 @@ * Combine benchmark data from different jobs, and upload to Codspeed. */ -import {createReadStream} from 'fs'; -import fs from 'fs/promises'; -import {join as pathJoin} from 'path'; -import {createHash} from 'crypto'; import assert from 'assert'; -import {create as createTar} from 'tar'; import axios from 'axios'; +import { createHash } from 'crypto'; +import { createReadStream } from 'fs'; +import fs from 'fs/promises'; +import { join as pathJoin } from 'path'; +import { create as createTar } from 'tar'; const METADATA_SUFFIX = '_metadata.json', - CODSPEED_UPLOAD_URL = 'https://api.codspeed.io/upload'; + CODSPEED_UPLOAD_URL = 'https://api.codspeed.io/upload'; const dataDir = process.env.DATA_DIR, - token = process.env.CODSPEED_TOKEN; + token = process.env.CODSPEED_TOKEN; // Find profile files and first metadata file const profileFiles = []; let metadataPath; for (const filename of await fs.readdir(dataDir)) { - const path = pathJoin(dataDir, filename); - if (filename.endsWith(METADATA_SUFFIX)) { - if (!metadataPath) metadataPath = path; - } else { - const match = filename.match(/_(\d+)\.out$/); - assert(match, `Unexpected file: ${filename}`); + const path = pathJoin(dataDir, filename); + if (filename.endsWith(METADATA_SUFFIX)) { + if (!metadataPath) metadataPath = path; + } else { + const match = filename.match(/_(\d+)\.out$/); + assert(match, `Unexpected file: ${filename}`); - const pid = +match[1]; - profileFiles.push({pid, path}); - } + const pid = +match[1]; + profileFiles.push({ pid, path }); + } } // Move all `.out` files to one directory @@ -39,49 +39,49 @@ const outDir = pathJoin(dataDir, 'out'); await fs.mkdir(outDir); const pids = new Set(), - duplicates = []; + duplicates = []; let highestPid = -1; -for (const {pid, path} of profileFiles) { - if (pids.has(pid)) { - // Duplicate PID - duplicates.push({pid, path}); - } else { - pids.add(pid); - if (pid > highestPid) highestPid = pid; - await fs.rename(path, pathJoin(outDir, `${pid}.out`)); - } +for (const { pid, path } of profileFiles) { + if (pids.has(pid)) { + // Duplicate PID + duplicates.push({ pid, path }); + } else { + pids.add(pid); + if (pid > highestPid) highestPid = pid; + await fs.rename(path, pathJoin(outDir, `${pid}.out`)); + } } // Alter PIDs for `.out` files with duplicate filenames -for (let {pid, path} of duplicates) { - let content = await fs.readFile(path, 'utf8'); +for (let { pid, path } of duplicates) { + let content = await fs.readFile(path, 'utf8'); - const pidLine = `\npid: ${pid}\n`; - const index = content.indexOf(pidLine); - assert(index !== -1, `Could not locate PID in ${path}`); - const before = content.slice(0, index); - assert(before.split('\n').length === 3, `Unexpected formatting in ${path}`); + const pidLine = `\npid: ${pid}\n`; + const index = content.indexOf(pidLine); + assert(index !== -1, `Could not locate PID in ${path}`); + const before = content.slice(0, index); + assert(before.split('\n').length === 3, `Unexpected formatting in ${path}`); - pid = ++highestPid; - content = `${before}\npid: ${pid}\n${content.slice(index + pidLine.length)}`; + pid = ++highestPid; + content = `${before}\npid: ${pid}\n${content.slice(index + pidLine.length)}`; - await fs.writeFile(pathJoin(outDir, `${pid}.out`), content); - await fs.rm(path); + await fs.writeFile(pathJoin(outDir, `${pid}.out`), content); + await fs.rm(path); } // ZIP combined profile directory console.log('Zipping combined profile directory'); const archivePath = pathJoin(dataDir, 'archive.tar.gz'); -await createTar({file: archivePath, gzip: true, cwd: outDir}, ['./']); +await createTar({ file: archivePath, gzip: true, cwd: outDir }, ['./']); // Get size + MD5 hash of archive console.log('Hashing ZIP'); -const {size} = await fs.stat(archivePath); +const { size } = await fs.stat(archivePath); const hash = createHash('md5'); const inputStream = createReadStream(archivePath); for await (const chunk of inputStream) { - hash.update(chunk); + hash.update(chunk); } const md5 = hash.digest('base64'); @@ -97,33 +97,33 @@ metadata.profileMd5 = md5; if (!token) metadata.tokenless = true; const metadataJson = JSON.stringify(metadata); if (!token) { - const metadataHash = createHash('sha256').update(metadataJson).digest('hex'); - console.log(`CodSpeed Run Hash: "${metadataHash}"`); + const metadataHash = createHash('sha256').update(metadataJson).digest('hex'); + console.log(`CodSpeed Run Hash: "${metadataHash}"`); } // Upload metadata to CodSpeed console.log('Uploading metadata to CodSpeed'); -const {data} = await axios({ - method: 'post', - url: CODSPEED_UPLOAD_URL, - data: metadataJson, - headers: { - 'Content-Type': 'application/json', - ...(token ? {Authorization: token} : null), - }, +const { data } = await axios({ + method: 'post', + url: CODSPEED_UPLOAD_URL, + data: metadataJson, + headers: { + 'Content-Type': 'application/json', + ...(token ? { Authorization: token } : null), + }, }); assert(data?.status === 'success', 'Failed to upload metadata to Codspeed'); -const {uploadUrl} = data; +const { uploadUrl } = data; // Upload profile ZIP to Codspeed console.log('Uploading profile ZIP to CodSpeed'); await axios({ - method: 'put', - url: uploadUrl, - data: createReadStream(archivePath), - headers: { - 'Content-Type': 'application/gzip', - 'Content-Length': size, - 'Content-MD5': md5, - } + method: 'put', + url: uploadUrl, + data: createReadStream(archivePath), + headers: { + 'Content-Type': 'application/gzip', + 'Content-Length': size, + 'Content-MD5': md5, + }, }); diff --git a/tasks/coverage/README.md b/tasks/coverage/README.md index 2fc56e0392..647f8f7a1d 100644 --- a/tasks/coverage/README.md +++ b/tasks/coverage/README.md @@ -31,6 +31,7 @@ UPDATE_SNAPSHOT=1 just c ``` + [test262]: https://github.com/tc39/test262 [babel]: https://github.com/babel/babel [TypeScript]: https://github.com/microsoft/TypeScript diff --git a/tasks/coverage/src/runtime/package.json b/tasks/coverage/src/runtime/package.json index 472002573e..3dbc1ca591 100644 --- a/tasks/coverage/src/runtime/package.json +++ b/tasks/coverage/src/runtime/package.json @@ -1,3 +1,3 @@ { - "type": "module" + "type": "module" } diff --git a/tasks/coverage/src/runtime/runtime.js b/tasks/coverage/src/runtime/runtime.js index e8cf212611..d752aeabc5 100644 --- a/tasks/coverage/src/runtime/runtime.js +++ b/tasks/coverage/src/runtime/runtime.js @@ -1,115 +1,114 @@ -import vm from "node:vm" -import path from "node:path" -import fs from "node:fs" -import process from "node:process"; -import { createServer } from "node:http"; +import fs from 'node:fs'; +import { createServer } from 'node:http'; +import path from 'node:path'; +import process from 'node:process'; +import vm from 'node:vm'; const __dirname = path.dirname(new URL(import.meta.url).pathname); -const harnessDir = path.join(__dirname, '../..', 'test262', 'harness') +const harnessDir = path.join(__dirname, '../..', 'test262', 'harness'); - -const { Script, createContext, SourceTextModule, runInContext, SyntheticModule } = vm +const { Script, createContext, SourceTextModule, runInContext, SyntheticModule } = vm; async function runCodeInHarness(options = {}) { - const { code = "", includes = [], importDir = "", isAsync = false, isModule = true, isRaw = false } = options - const context = {} + const { code = '', includes = [], importDir = '', isAsync = false, isModule = true, isRaw = false } = options; + const context = {}; // See: https://github.com/nodejs/node/issues/36351 - const unique = () => '//' + Math.random() + const unique = () => '//' + Math.random(); const runCode = async () => { - const moduleCache = new Map - const dynamicImportCache = new Map + const moduleCache = new Map(); + const dynamicImportCache = new Map(); const findModule = (modulePath) => { - let module = moduleCache.get(modulePath) + let module = moduleCache.get(modulePath); if (!module) { - const code = fs.readFileSync(modulePath, 'utf8') + const code = fs.readFileSync(modulePath, 'utf8'); if (modulePath.endsWith('json')) { - const evaluate = function () { - this.setExport('default', runInContext('JSON.parse', context)(code)) - } - module = new SyntheticModule(['default'], evaluate, { context }) + const evaluate = function() { + this.setExport('default', runInContext('JSON.parse', context)(code)); + }; + module = new SyntheticModule(['default'], evaluate, { context }); } else { - module = new SourceTextModule(code + unique(), { context, importModuleDynamically }) + module = new SourceTextModule(code + unique(), { context, importModuleDynamically }); } - moduleCache.set(modulePath, module) + moduleCache.set(modulePath, module); } - return module - } + return module; + }; const linker = (specifier, referencingModule) => { - return findModule(path.join(importDir, specifier)) - } + return findModule(path.join(importDir, specifier)); + }; const importModuleDynamically = (specifier, script) => { - const where = path.join(importDir, specifier) - let promise = dynamicImportCache.get(where) + const where = path.join(importDir, specifier); + let promise = dynamicImportCache.get(where); if (!promise) { - const module = findModule(where) + const module = findModule(where); if (module.status === 'unlinked') { promise = module.link(linker) .then(() => module.evaluate()) - .then(() => module) + .then(() => module); } else { - promise = Promise.resolve(module) + promise = Promise.resolve(module); } - dynamicImportCache.set(where, promise) + dynamicImportCache.set(where, promise); } - return promise - } + return promise; + }; - createContext(context) - if (!isRaw) runInContext(createHarnessForTest(includes), context) + createContext(context); + if (!isRaw) runInContext(createHarnessForTest(includes), context); if (isModule) { - const module = new SourceTextModule(code + unique(), { context, importModuleDynamically }) - await module.link(linker) - await module.evaluate() + const module = new SourceTextModule(code + unique(), { context, importModuleDynamically }); + await module.link(linker); + await module.evaluate(); } else { - const script = new Script(code, { importModuleDynamically }) - script.runInContext(context) + const script = new Script(code, { importModuleDynamically }); + script.runInContext(context); } - } + }; if (isAsync) { await new Promise((resolve, reject) => { - context.$DONE = err => err ? reject(err) : resolve() - runCode().catch(reject) - }) + context.$DONE = err => err ? reject(err) : resolve(); + runCode().catch(reject); + }); } else { - await runCode() + await runCode(); } } -const harnessFiles = new Map -let defaultHarness = '' +const harnessFiles = new Map(); +let defaultHarness = ''; for (const entry of fs.readdirSync(harnessDir)) { if (entry.startsWith('.') || !entry.endsWith('.js')) { - continue + continue; } - const file = path.join(harnessDir, entry) - const content = fs.readFileSync(file, 'utf8') + const file = path.join(harnessDir, entry); + const content = fs.readFileSync(file, 'utf8'); if (entry === 'assert.js' || entry === 'sta.js') { - defaultHarness += content - continue + defaultHarness += content; + continue; } - harnessFiles.set(entry, content) + harnessFiles.set(entry, content); } function createHarnessForTest(includes) { - let harness = defaultHarness + let harness = defaultHarness; if (includes) { for (const include of includes) { - const content = harnessFiles.get(include) - if (!content) throw new Error(`Included file is missing: ${include}`) - harness += content + const content = harnessFiles.get(include); + if (!content) throw new Error(`Included file is missing: ${include}`); + harness += content; } } - return harness + return harness; } const server = createServer((req, res) => { @@ -119,16 +118,16 @@ const server = createServer((req, res) => { body += chunk.toString(); // convert Buffer to string }); req.on('end', async () => { - const options = JSON.parse(body) + const options = JSON.parse(body); try { await runCodeInHarness(options); } catch (err) { - if (parseInt(process.version.split('.')[0].replace("v", "")) < 20) { - return res.end('Please upgrade the Node.js version to 20 or later.') + if (parseInt(process.version.split('.')[0].replace('v', '')) < 20) { + return res.end('Please upgrade the Node.js version to 20 or later.'); } return res.end(err.toString()); } - + // res.setHeader('Content-Type', 'application/json'); res.end(); }); @@ -140,6 +139,6 @@ const server = createServer((req, res) => { process.on('unhandledRejection', () => { // Don't exit when a test does this -}) +}); server.listen(32055, () => {}); diff --git a/tasks/lint_rules/src/eslint-rules.cjs b/tasks/lint_rules/src/eslint-rules.cjs index 5e3ba84912..25030def8d 100644 --- a/tasks/lint_rules/src/eslint-rules.cjs +++ b/tasks/lint_rules/src/eslint-rules.cjs @@ -1,4 +1,4 @@ -const { Linter } = require("eslint"); +const { Linter } = require('eslint'); // NOTICE! // Plugins do not provide their type definitions, and also `@types/*` do not exist! @@ -13,76 +13,77 @@ const { Linter } = require("eslint"); const { rules: pluginTypeScriptAllRules, configs: pluginTypeScriptConfigs, -} = require("@typescript-eslint/eslint-plugin"); +} = require('@typescript-eslint/eslint-plugin'); // https://github.com/eslint-community/eslint-plugin-n/blob/master/lib/index.js -const { rules: pluginNAllRules } = require("eslint-plugin-n"); +const { rules: pluginNAllRules } = require('eslint-plugin-n'); // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/index.js const { rules: pluginUnicornAllRules, configs: pluginUnicornConfigs, -} = require("eslint-plugin-unicorn"); +} = require('eslint-plugin-unicorn'); // https://github.com/gajus/eslint-plugin-jsdoc/blob/main/src/index.js const { // @ts-expect-error: Module has no exported member rules: pluginJSDocAllRules, // @ts-expect-error: Module has no exported member configs: pluginJSDocConfigs, -} = require("eslint-plugin-jsdoc"); +} = require('eslint-plugin-jsdoc'); // https://github.com/import-js/eslint-plugin-import/blob/main/src/index.js const { rules: pluginImportAllRules, configs: pluginImportConfigs, -} = require("eslint-plugin-import"); +} = require('eslint-plugin-import'); // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/index.js const { rules: pluginJSXA11yAllRules, configs: pluginJSXA11yConfigs, -} = require("eslint-plugin-jsx-a11y"); +} = require('eslint-plugin-jsx-a11y'); // https://github.com/jest-community/eslint-plugin-jest/blob/main/src/index.ts const { rules: pluginJestAllRules, configs: pluginJestConfigs, -} = require("eslint-plugin-jest"); +} = require('eslint-plugin-jest'); // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/index.js -const { rules: pluginReactAllRules } = require("eslint-plugin-react"); +const { rules: pluginReactAllRules } = require('eslint-plugin-react'); // https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/src/index.js const { rules: pluginReactHooksAllRules, -} = require("eslint-plugin-react-hooks"); +} = require('eslint-plugin-react-hooks'); // https://github.com/cvazac/eslint-plugin-react-perf/blob/master/index.js const { rules: pluginReactPerfAllRules, configs: pluginReactPerfConfigs, -} = require("eslint-plugin-react-perf"); +} = require('eslint-plugin-react-perf'); // https://github.com/vercel/next.js/blob/canary/packages/eslint-plugin-next/src/index.ts -const { rules: pluginNextAllRules } = require("@next/eslint-plugin-next"); +const { rules: pluginNextAllRules } = require('@next/eslint-plugin-next'); // https://github.com/eslint-community/eslint-plugin-promise/blob/main/index.js const { rules: pluginPromiseRules, - configs: pluginPromiseConfigs -} = require("eslint-plugin-promise"); + configs: pluginPromiseConfigs, +} = require('eslint-plugin-promise'); // https://github.com/veritem/eslint-plugin-vitest/blob/main/src/index.ts const { rules: pluginVitestRules, - configs: pluginVitestConfigs -} = require("eslint-plugin-vitest"); + configs: pluginVitestConfigs, +} = require('eslint-plugin-vitest'); /** @param {import("eslint").Linter} linter */ const loadPluginTypeScriptRules = (linter) => { // We want to list all rules but not support type-checked rules const pluginTypeScriptDisableTypeCheckedRules = new Map( - Object.entries(pluginTypeScriptConfigs["disable-type-checked"].rules), + Object.entries(pluginTypeScriptConfigs['disable-type-checked'].rules), ); for (const [name, rule] of Object.entries(pluginTypeScriptAllRules)) { if ( pluginTypeScriptDisableTypeCheckedRules.has(`@typescript-eslint/${name}`) - ) + ) { continue; + } const prefixedName = `typescript/${name}`; // Presented but type is `string | false` - rule.meta.docs.recommended = typeof rule.meta.docs.recommended === "string"; + rule.meta.docs.recommended = typeof rule.meta.docs.recommended === 'string'; linter.defineRule(prefixedName, rule); } @@ -109,7 +110,7 @@ const loadPluginUnicornRules = (linter) => { // If name is presented and value is not "off", it is recommended const recommendedValue = pluginUnicornRecommendedRules.get(prefixedName); // @ts-expect-error: `rule.meta.docs` is possibly `undefined` - rule.meta.docs.recommended = recommendedValue && recommendedValue !== "off"; + rule.meta.docs.recommended = recommendedValue && recommendedValue !== 'off'; linter.defineRule(prefixedName, rule); } @@ -125,7 +126,7 @@ const loadPluginJSDocRules = (linter) => { // If name is presented and value is not "off", it is recommended const recommendedValue = pluginJSDocRecommendedRules.get(prefixedName); - rule.meta.docs.recommended = recommendedValue && recommendedValue !== "off"; + rule.meta.docs.recommended = recommendedValue && recommendedValue !== 'off'; linter.defineRule(prefixedName, rule); } @@ -157,11 +158,10 @@ const loadPluginJSXA11yRules = (linter) => { const prefixedName = `jsx-a11y/${name}`; const recommendedValue = pluginJSXA11yRecommendedRules.get(prefixedName); - rule.meta.docs.recommended = - recommendedValue && + rule.meta.docs.recommended = recommendedValue && // Type is `string | [string, opt]` - recommendedValue !== "off" && - recommendedValue[0] !== "off"; + recommendedValue !== 'off' && + recommendedValue[0] !== 'off'; linter.defineRule(prefixedName, rule); } @@ -178,7 +178,7 @@ const loadPluginJestRules = (linter) => { const recommendedValue = pluginJestRecommendedRules.get(prefixedName); // Presented but type is `string | undefined` - rule.meta.docs.recommended = typeof recommendedValue === "string"; + rule.meta.docs.recommended = typeof recommendedValue === 'string'; linter.defineRule(prefixedName, rule); } @@ -211,8 +211,7 @@ const loadPluginReactPerfRules = (linter) => { for (const [name, rule] of Object.entries(pluginReactPerfAllRules)) { const prefixedName = `react-perf/${name}`; - rule.meta.docs.recommended = - pluginReactPerfRecommendedRules.has(prefixedName); + rule.meta.docs.recommended = pluginReactPerfRecommendedRules.has(prefixedName); linter.defineRule(prefixedName, rule); } @@ -235,17 +234,16 @@ const loadPluginPromiseRules = (linter) => { for (const [name, rule] of Object.entries(pluginPromiseRules)) { const prefixedName = `promise/${name}`; - rule.meta.docs.recommended = - pluginPromiseRecommendedRules.has(prefixedName); + rule.meta.docs.recommended = pluginPromiseRecommendedRules.has(prefixedName); linter.defineRule(prefixedName, rule); } -} +}; /** @param {import("eslint").Linter} linter */ const loadPluginVitestRules = (linter) => { const pluginVitestRecommendedRules = new Map( - Object.entries(pluginVitestConfigs.recommended.rules) + Object.entries(pluginVitestConfigs.recommended.rules), ); for (const [name, rule] of Object.entries(pluginVitestRules)) { const prefixedName = `vitest/${name}`; @@ -254,7 +252,7 @@ const loadPluginVitestRules = (linter) => { linter.defineRule(prefixedName, rule); } -} +}; /** * @typedef {{ @@ -264,31 +262,31 @@ const loadPluginVitestRules = (linter) => { * @type {Map} */ exports.ALL_TARGET_PLUGINS = new Map([ - ["eslint", { npm: ["eslint"], issueNo: 479 }], - ["typescript", { npm: ["@typescript-eslint/eslint-plugin"], issueNo: 2180 }], - ["n", { npm: ["eslint-plugin-n"], issueNo: 493 }], - ["unicorn", { npm: ["eslint-plugin-unicorn"], issueNo: 684 }], - ["jsdoc", { npm: ["eslint-plugin-jsdoc"], issueNo: 1170 }], - ["import", { npm: ["eslint-plugin-import"], issueNo: 1117 }], - ["jsx-a11y", { npm: ["eslint-plugin-jsx-a11y"], issueNo: 1141 }], - ["jest", { npm: ["eslint-plugin-jest"], issueNo: 492 }], + ['eslint', { npm: ['eslint'], issueNo: 479 }], + ['typescript', { npm: ['@typescript-eslint/eslint-plugin'], issueNo: 2180 }], + ['n', { npm: ['eslint-plugin-n'], issueNo: 493 }], + ['unicorn', { npm: ['eslint-plugin-unicorn'], issueNo: 684 }], + ['jsdoc', { npm: ['eslint-plugin-jsdoc'], issueNo: 1170 }], + ['import', { npm: ['eslint-plugin-import'], issueNo: 1117 }], + ['jsx-a11y', { npm: ['eslint-plugin-jsx-a11y'], issueNo: 1141 }], + ['jest', { npm: ['eslint-plugin-jest'], issueNo: 492 }], [ - "react", + 'react', { - npm: ["eslint-plugin-react", "eslint-plugin-react-hooks"], + npm: ['eslint-plugin-react', 'eslint-plugin-react-hooks'], issueNo: 1022, }, ], - ["react-perf", { npm: ["eslint-plugin-react-perf"], issueNo: 2041 }], - ["nextjs", { npm: ["@next/eslint-plugin-next"], issueNo: 1929 }], - ["promise", { npm: ["eslint-plugin-promise"], issueNo: 4655 }], - ["vitest", { npm: ["eslint-plugin-vitest"], issueNo: 4656 }], + ['react-perf', { npm: ['eslint-plugin-react-perf'], issueNo: 2041 }], + ['nextjs', { npm: ['@next/eslint-plugin-next'], issueNo: 1929 }], + ['promise', { npm: ['eslint-plugin-promise'], issueNo: 4655 }], + ['vitest', { npm: ['eslint-plugin-vitest'], issueNo: 4656 }], ]); // All rules(including deprecated, recommended) are loaded initially. exports.createESLintLinter = () => new Linter({ - configType: "eslintrc", + configType: 'eslintrc', }); /** @param {import("eslint").Linter} linter */ diff --git a/tasks/lint_rules/src/main.cjs b/tasks/lint_rules/src/main.cjs index 0475ae9150..3d16c740ec 100644 --- a/tasks/lint_rules/src/main.cjs +++ b/tasks/lint_rules/src/main.cjs @@ -1,18 +1,17 @@ -const { parseArgs } = require("node:util"); +const { parseArgs } = require('node:util'); const { ALL_TARGET_PLUGINS, createESLintLinter, loadTargetPluginRules, -} = require("./eslint-rules.cjs"); +} = require('./eslint-rules.cjs'); const { createRuleEntries, updateNotSupportedStatus, updateImplementedStatus, - overrideTypeScriptPluginStatusWithEslintPluginStatus: - syncTypeScriptPluginStatusWithEslintPluginStatus, -} = require("./oxlint-rules.cjs"); -const { renderMarkdown } = require("./markdown-renderer.cjs"); -const { updateGitHubIssue } = require("./result-reporter.cjs"); + overrideTypeScriptPluginStatusWithEslintPluginStatus: syncTypeScriptPluginStatusWithEslintPluginStatus, +} = require('./oxlint-rules.cjs'); +const { renderMarkdown } = require('./markdown-renderer.cjs'); +const { updateGitHubIssue } = require('./result-reporter.cjs'); const HELP = ` Usage: @@ -23,7 +22,7 @@ Options: --update: Update the issue instead of printing to stdout --help, -h: Print this help message -Plugins: ${Array.from(ALL_TARGET_PLUGINS.keys()).join(", ")} +Plugins: ${Array.from(ALL_TARGET_PLUGINS.keys()).join(', ')} `; (async () => { @@ -33,9 +32,9 @@ Plugins: ${Array.from(ALL_TARGET_PLUGINS.keys()).join(", ")} const { values } = parseArgs({ options: { // Mainly for debugging - target: { type: "string", short: "t", multiple: true }, - update: { type: "boolean" }, - help: { type: "boolean", short: "h" }, + target: { type: 'string', short: 't', multiple: true }, + update: { type: 'boolean' }, + help: { type: 'boolean', short: 'h' }, }, }); @@ -68,10 +67,9 @@ Plugins: ${Array.from(ALL_TARGET_PLUGINS.keys()).join(", ")} // const results = await Promise.allSettled( Array.from(targetPluginNames).map((pluginName) => { - const pluginMeta = - /** @type {import("./eslint-rules.cjs").TargetPluginMeta} */ ( - ALL_TARGET_PLUGINS.get(pluginName) - ); + const pluginMeta = /** @type {import("./eslint-rules.cjs").TargetPluginMeta} */ ( + ALL_TARGET_PLUGINS.get(pluginName) + ); const content = renderMarkdown(pluginName, pluginMeta, ruleEntries); if (!values.update) return Promise.resolve(content); @@ -80,7 +78,7 @@ Plugins: ${Array.from(ALL_TARGET_PLUGINS.keys()).join(", ")} }), ); for (const result of results) { - if (result.status === "fulfilled") console.log(result.value); - if (result.status === "rejected") console.error(result.reason); + if (result.status === 'fulfilled') console.log(result.value); + if (result.status === 'rejected') console.error(result.reason); } })(); diff --git a/tasks/lint_rules/src/markdown-renderer.cjs b/tasks/lint_rules/src/markdown-renderer.cjs index e29b183187..e5c84e0b78 100644 --- a/tasks/lint_rules/src/markdown-renderer.cjs +++ b/tasks/lint_rules/src/markdown-renderer.cjs @@ -9,7 +9,7 @@ const renderIntroduction = ({ npm }) => ` > This comment is maintained by CI. Do not edit this comment directly. > To update comment template, see https://github.com/oxc-project/oxc/tree/main/tasks/lint_rules -This is tracking issue for ${npm.map((n) => "`" + n + "`").join(", ")}. +This is tracking issue for ${npm.map((n) => '`' + n + '`').join(', ')}. `; /** @@ -24,11 +24,9 @@ This is tracking issue for ${npm.map((n) => "`" + n + "`").join(", ")}. const renderCounters = ({ counters: { recommended, notRecommended, deprecated }, }) => { - const recommendedTodos = - recommended.total - + const recommendedTodos = recommended.total - (recommended.isImplemented + recommended.isNotSupported); - const notRecommendedTodos = - notRecommended.total - + const notRecommendedTodos = notRecommended.total - (notRecommended.isImplemented + notRecommended.isNotSupported); const countersList = [ @@ -38,7 +36,7 @@ const renderCounters = ({ notRecommendedTodos === 0 && ` - All done! 🎉`, ] .filter(Boolean) - .join("\n"); + .join('\n'); return ` There are ${recommended.total + notRecommended.total}(+ ${deprecated.total} deprecated) rules. @@ -68,19 +66,20 @@ Then register the rule in \`crates/oxc_linter/src/rules.rs\` and also \`declare_ const renderRulesList = ({ title, counters, views, defaultOpen = true }) => ` ## ${title} -
+
✨: ${counters.isImplemented}, 🚫: ${counters.isNotSupported} / total: ${counters.total} | Status | Name | Docs | | :----: | :--- | :--- | -${views - .map( - (v) => - `| ${v.isImplemented ? "✨" : ""}${v.isNotSupported ? "🚫" : ""} | ${v.name} | ${v.docsUrl} |`, - ) - .join("\n")} +${ + views + .map( + (v) => `| ${v.isImplemented ? '✨' : ''}${v.isNotSupported ? '🚫' : ''} | ${v.name} | ${v.docsUrl} |`, + ) + .join('\n') +} ✨ = Implemented, 🚫 = Not supported @@ -139,25 +138,25 @@ exports.renderMarkdown = (pluginName, pluginMeta, ruleEntries) => { renderCounters({ counters }), renderGettingStarted({ pluginName }), 0 < views.recommended.length && - renderRulesList({ - title: "Recommended rules", - counters: counters.recommended, - views: views.recommended, - }), + renderRulesList({ + title: 'Recommended rules', + counters: counters.recommended, + views: views.recommended, + }), 0 < views.notRecommended.length && - renderRulesList({ - title: "Not recommended rules", - counters: counters.notRecommended, - views: views.notRecommended, - }), + renderRulesList({ + title: 'Not recommended rules', + counters: counters.notRecommended, + views: views.notRecommended, + }), 0 < views.deprecated.length && - renderRulesList({ - title: "Deprecated rules", - counters: counters.deprecated, - views: views.deprecated, - defaultOpen: false, - }), + renderRulesList({ + title: 'Deprecated rules', + counters: counters.deprecated, + views: views.deprecated, + defaultOpen: false, + }), ] .filter(Boolean) - .join("\n"); + .join('\n'); }; diff --git a/tasks/lint_rules/src/oxlint-rules.cjs b/tasks/lint_rules/src/oxlint-rules.cjs index 046bbb2358..e609171277 100644 --- a/tasks/lint_rules/src/oxlint-rules.cjs +++ b/tasks/lint_rules/src/oxlint-rules.cjs @@ -1,52 +1,52 @@ -const { resolve } = require("node:path"); -const { readFile } = require("node:fs/promises"); +const { resolve } = require('node:path'); +const { readFile } = require('node:fs/promises'); const readAllImplementedRuleNames = async () => { const rulesFile = await readFile( - resolve("crates/oxc_linter/src/rules.rs"), - "utf8", + resolve('crates/oxc_linter/src/rules.rs'), + 'utf8', ); /** @type {Set} */ const rules = new Set(); let found = false; - for (let line of rulesFile.split("\n")) { + for (let line of rulesFile.split('\n')) { line = line.trim(); // Skip commented out rules - if (line.startsWith("//")) continue; + if (line.startsWith('//')) continue; - if (line === "oxc_macros::declare_all_lint_rules! {") { + if (line === 'oxc_macros::declare_all_lint_rules! {') { found = true; continue; } - if (found && line === "}") { + if (found && line === '}') { return rules; } if (found) { const prefixedName = line - .replaceAll(",", "") - .replaceAll("::", "/") - .replaceAll("_", "-"); + .replaceAll(',', '') + .replaceAll('::', '/') + .replaceAll('_', '-'); // Ignore no reference rules - if (prefixedName.startsWith("oxc/")) continue; + if (prefixedName.startsWith('oxc/')) continue; rules.add(prefixedName); } } - throw new Error("Failed to find the end of the rules list"); + throw new Error('Failed to find the end of the rules list'); }; const NOT_SUPPORTED_RULE_NAMES = new Set([ - "eslint/no-dupe-args", // superseded by strict mode - "eslint/no-octal", // superseded by strict mode - "eslint/no-with", // superseded by strict mode - "eslint/no-new-symbol", // Deprecated as of ESLint v9, but for a while disable manually - "import/no-unresolved", // Will always contain false positives due to module resolution complexity + 'eslint/no-dupe-args', // superseded by strict mode + 'eslint/no-octal', // superseded by strict mode + 'eslint/no-with', // superseded by strict mode + 'eslint/no-new-symbol', // Deprecated as of ESLint v9, but for a while disable manually + 'import/no-unresolved', // Will always contain false positives due to module resolution complexity ]); /** @@ -67,9 +67,9 @@ exports.createRuleEntries = (loadedAllRules) => { for (const [name, rule] of loadedAllRules) { // Default eslint rules are not prefixed - const prefixedName = name.includes("/") ? name : `eslint/${name}`; + const prefixedName = name.includes('/') ? name : `eslint/${name}`; - const docsUrl = rule.meta?.docs?.url ?? ""; + const docsUrl = rule.meta?.docs?.url ?? ''; const isDeprecated = rule.meta?.deprecated ?? false; const isRecommended = rule.meta?.docs?.recommended ?? false; @@ -117,10 +117,10 @@ exports.overrideTypeScriptPluginStatusWithEslintPluginStatus = ( ruleEntries, ) => { for (const [name, rule] of ruleEntries) { - if (!name.startsWith("typescript/")) continue; + if (!name.startsWith('typescript/')) continue; // This assumes that if the same name found, it implements the same rule. - const eslintRule = ruleEntries.get(name.replace("typescript/", "eslint/")); + const eslintRule = ruleEntries.get(name.replace('typescript/', 'eslint/')); if (!eslintRule) continue; rule.isImplemented = eslintRule.isImplemented; diff --git a/tasks/lint_rules/src/result-reporter.cjs b/tasks/lint_rules/src/result-reporter.cjs index 2e137f0cf3..7a6ff3d9e8 100644 --- a/tasks/lint_rules/src/result-reporter.cjs +++ b/tasks/lint_rules/src/result-reporter.cjs @@ -9,9 +9,9 @@ exports.updateGitHubIssue = async ({ issueNo }, markdown) => { const res = await fetch( `https://api.github.com/repos/oxc-project/oxc/issues/${issueNo}`, { - method: "PATCH", + method: 'PATCH', headers: { - Accept: "application/vnd.github+json", + Accept: 'application/vnd.github+json', Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, }, body: JSON.stringify({ body: markdown }), diff --git a/wasm/parser/README.md b/wasm/parser/README.md index 3f4d31ca79..df79941349 100644 --- a/wasm/parser/README.md +++ b/wasm/parser/README.md @@ -4,8 +4,8 @@ Experimental wasm package for the oxc parser, with full TypeScript typings suppo This package is built with different [wasm-pack's target](https://rustwasm.github.io/docs/wasm-bindgen/reference/deployment.html) builds: -* `wasm-pack build --target web` for bundler (webpack / vite) consumption. -* `wasm-pack build --target nodejs` for node.js +- `wasm-pack build --target web` for bundler (webpack / vite) consumption. +- `wasm-pack build --target nodejs` for node.js And exports the files as @@ -22,13 +22,13 @@ Source code: https://github.com/oxc-project/oxc/tree/main/wasm/parser ## Usage ```js -import initWasm, { parseSync } from "@oxc-parser/wasm"; +import initWasm, { parseSync } from '@oxc-parser/wasm'; async function main() { await initWasm(); - const code = "let foo"; - const result = parseSync(code, { sourceFilename: "test.ts" }); + const code = 'let foo'; + const result = parseSync(code, { sourceFilename: 'test.ts' }); console.log(result); } @@ -46,13 +46,13 @@ let sourceTextUtf8 = new TextEncoder().encode(sourceText); const convertToUtf8 = (sourceTextUtf8, d) => { return new TextDecoder().decode(sourceTextUtf8.slice(0, d)).length; -} +}; const diagnostics = result.errors.map((d) => ({ - from: convertToUtf8(sourceTextUtf8, d.start), - to: convertToUtf8(sourceTextUtf8, d.end), - severity: d.severity.toLowerCase(), - message: d.message, + from: convertToUtf8(sourceTextUtf8, d.start), + to: convertToUtf8(sourceTextUtf8, d.end), + severity: d.severity.toLowerCase(), + message: d.message, })); ``` diff --git a/wasm/parser/test-node.mjs b/wasm/parser/test-node.mjs index b4a66e6345..30d3c16e11 100644 --- a/wasm/parser/test-node.mjs +++ b/wasm/parser/test-node.mjs @@ -1,7 +1,7 @@ -import assert from 'assert' -import { parseSync } from "../../npm/parser-wasm/node/oxc_parser_wasm.js"; +import assert from 'assert'; +import { parseSync } from '../../npm/parser-wasm/node/oxc_parser_wasm.js'; -const code = "let foo"; -const result = parseSync(code, { sourceFilename: "test.ts" }); +const code = 'let foo'; +const result = parseSync(code, { sourceFilename: 'test.ts' }); assert(result.errors.length === 0); assert(result.program.body.length === 1);