mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
chore: use dprint to format js, json and markdown
This commit is contained in:
49 files changed
+1489
-1526
No files matched your search
+12
-13
@@ -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
|
||||
|
||||
|
||||
@@ -3,7 +3,4 @@ name: Bug report
|
||||
about: Create a report to help us improve.
|
||||
title: ''
|
||||
labels: C-bug
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -3,7 +3,4 @@ name: Feature request
|
||||
about: Suggest an idea for this project.
|
||||
title: ''
|
||||
labels: C-enhancement
|
||||
|
||||
---
|
||||
|
||||
|
||||
+1
-1
@@ -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.
|
||||
Vendored
+13
-13
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+72
-72
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+3
-3
@@ -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
|
||||
@@ -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)?
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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)}`);
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)]
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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<Option<ScopeId>>`) {
|
||||
scopeIdField = field;
|
||||
}
|
||||
return field.innerTypeName in types;
|
||||
});
|
||||
let scopeIdField;
|
||||
const visitedFields = type.fields.filter(field => {
|
||||
if (field.name === 'scope_id' && field.typeName === `Cell<Option<ScopeId>>`) {
|
||||
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<Option<ScopeId>>`,
|
||||
// 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<Option<ScopeId>>`,
|
||||
// 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<Vec<Statement>>`
|
||||
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<Vec<Statement>>`
|
||||
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<Statement>`
|
||||
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<Statement>`
|
||||
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::<u8>().add(ancestor::${field.offsetVarName}).cast::<${field.typeName}>()`;
|
||||
return `node.cast::<u8>().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},
|
||||
|
||||
+1
-3
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ ast:
|
||||
fmt:
|
||||
cargo fmt --all
|
||||
taplo format
|
||||
dprint fmt
|
||||
|
||||
# Run cargo check
|
||||
check:
|
||||
|
||||
Vendored
+38
-33
@@ -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<ImportSpecifier>
|
||||
exports: Array<ExportSpecifier>
|
||||
imports: Array<ImportSpecifier>;
|
||||
exports: Array<ExportSpecifier>;
|
||||
/**
|
||||
* 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<ModuleLexer>
|
||||
export declare function moduleLexerAsync(
|
||||
sourceText: string,
|
||||
options?: ParserOptions | undefined | null,
|
||||
): Promise<ModuleLexer>;
|
||||
|
||||
/**
|
||||
* 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<ParseResult>
|
||||
export declare function parseAsync(
|
||||
sourceText: string,
|
||||
options?: ParserOptions | undefined | null,
|
||||
): Promise<ParseResult>;
|
||||
|
||||
export interface ParseResult {
|
||||
program: string
|
||||
comments: Array<Comment>
|
||||
errors: Array<string>
|
||||
program: string;
|
||||
comments: Array<Comment>;
|
||||
errors: Array<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,8 +108,8 @@ export interface ParseResult {
|
||||
* <https://github.com/babel/babel/blob/main/packages/babel-parser/typings/babel-parser.d.ts>
|
||||
*/
|
||||
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;
|
||||
+165
-184
@@ -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;
|
||||
+45
-45
@@ -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));
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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'}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+54
-47
@@ -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<string>
|
||||
code: string;
|
||||
map?: SourceMap;
|
||||
errors: Array<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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<string | undefined | null>
|
||||
sourcesContent?: Array<string | undefined | null>
|
||||
names?: Array<string>
|
||||
file?: string;
|
||||
mappings?: string;
|
||||
sourceRoot?: string;
|
||||
sources?: Array<string | undefined | null>;
|
||||
sourcesContent?: Array<string | undefined | null>;
|
||||
names?: Array<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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<string>
|
||||
errors: Array<string>;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
+162
-181
@@ -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;
|
||||
@@ -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 {}'],
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<string>
|
||||
sourceText: string;
|
||||
errors: Array<string>;
|
||||
}
|
||||
```
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
@@ -295,4 +295,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,4 +25,4 @@
|
||||
"configuration_schema.json",
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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}`);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
});
|
||||
@@ -31,6 +31,7 @@ UPDATE_SNAPSHOT=1 just c
|
||||
```
|
||||
|
||||
<!-- Links -->
|
||||
|
||||
[test262]: https://github.com/tc39/test262
|
||||
[babel]: https://github.com/babel/babel
|
||||
[TypeScript]: https://github.com/microsoft/TypeScript
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
"type": "module"
|
||||
}
|
||||
@@ -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, () => {});
|
||||
@@ -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<string, TargetPluginMeta>}
|
||||
*/
|
||||
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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
})();
|
||||
@@ -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}
|
||||
|
||||
<details ${defaultOpen ? "open" : ""}>
|
||||
<details ${defaultOpen ? 'open' : ''}>
|
||||
<summary>
|
||||
✨: ${counters.isImplemented}, 🚫: ${counters.isNotSupported} / total: ${counters.total}
|
||||
</summary>
|
||||
|
||||
| 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');
|
||||
};
|
||||
@@ -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<string>} */
|
||||
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;
|
||||
|
||||
@@ -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 }),
|
||||
|
||||
+10
-10
@@ -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,
|
||||
}));
|
||||
```
|
||||
|
||||
|
||||
@@ -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);
|
||||
Reference in new issue
Block a user