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