Skip to content

Commit 53d04dd

Browse files
committed
feat(linter): convert oxlint to NAPI app (#13723)
Convert `oxlint` to a NAPI package. This PR: 1. Moves files from `napi/oxlint` into `apps/oxlint`. 2. Converts `oxlint` into a NAPI package. 3. Alters the [release workflow](https://github.com/oxc-project/oxc/pull/13723/files#diff-80cb497c859bbaf7756da6ced2bca3d31933affc96102983eee1ad7d4bcc60fd) and [script](https://github.com/oxc-project/oxc/pull/13723/files#diff-4c4b7045c68805aeeae7c0af94cf7cf7487cb0403496da974a6a23accdc457d0) for building `oxlint` packages. Most of necessary code modifications and refactoring was done in previous PRs (#13701, #13712, #13722, #13745), so this PR only includes changes necessary for packaging as NAPI. I've done my best to update release workflow, but am mostly "flying blind" without ability to test it, so very likely there are mistakes. A few notes and oddities: * I've kept the `oxlint` NPM package as CommonJS. We could probably switch to ESM, but I thought it better to minimize the changes in this PR. * NAPI-RS creates `.node` files named with a `-msvc` postfix for Windows. The scripts here remove that postfix so that filename of `.node` files and NPM package names match for all platforms, for simplicity. * `tasks/website` has a dependency on `oxlint` as a normal library. This resulted in linker errors, so have had to put all the NAPI stuff behind `napi` cargo feature. Tests for `tasks/website` are run separately in CI, to avoid feature unification turning on the `napi` feature for `website`. I've made a few comments below for the parts which aren't fairly self-explanatory.
1 parent 173c4d0 commit 53d04dd

File tree

102 files changed

+328
-436
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+328
-436
lines changed

.github/generated/ast_changes_watch_list.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
src:
55
- '.github/generated/ast_changes_watch_list.yml'
6+
- 'apps/oxlint/src-js/generated/constants.mjs'
7+
- 'apps/oxlint/src/generated/raw_transfer_constants.rs'
68
- 'crates/oxc_allocator/src/generated/assert_layouts.rs'
79
- 'crates/oxc_allocator/src/generated/fixed_size_constants.rs'
810
- 'crates/oxc_allocator/src/pool/fixed_size.rs'
@@ -64,8 +66,6 @@ src:
6466
- 'crates/oxc_syntax/src/serialize.rs'
6567
- 'crates/oxc_syntax/src/symbol.rs'
6668
- 'crates/oxc_traverse/src/generated/scopes_collector.rs'
67-
- 'napi/oxlint/src-js/generated/constants.mjs'
68-
- 'napi/oxlint/src/generated/raw_transfer_constants.rs'
6969
- 'napi/parser/generated/constants.mjs'
7070
- 'napi/parser/generated/deserialize/js.mjs'
7171
- 'napi/parser/generated/deserialize/ts.mjs'

.github/workflows/ci.yml

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ jobs:
2626
save-cache: ${{ github.ref_name == 'main' }}
2727
cache-key: warm
2828
- run: cargo ck
29-
- run: cargo test --all-features
29+
- run: cargo test --workspace --all-features --exclude website
30+
- run: cargo test -p website # Run separately to avoid feature unification problems with `oxlint`
3031
- run: git diff --exit-code # Must commit everything
3132

3233
test-ubuntu-aarch64:
@@ -41,7 +42,8 @@ jobs:
4142
save-cache: ${{ github.ref_name == 'main' }}
4243
cache-key: warm-aarch64
4344
- run: cargo ck
44-
- run: cargo test --all-features
45+
- run: cargo test --workspace --all-features --exclude website
46+
- run: cargo test -p website # Run separately to avoid feature unification problems with `oxlint`
4547
- run: git diff --exit-code # Must commit everything
4648

4749
test-mac: # Separate job to save a job on PRs
@@ -56,7 +58,8 @@ jobs:
5658
save-cache: ${{ github.ref_name == 'main' }}
5759
cache-key: warm
5860
- run: cargo ck
59-
- run: cargo test --all-features
61+
- run: cargo test --workspace --all-features --exclude website
62+
- run: cargo test -p website # Run separately to avoid feature unification problems with `oxlint`
6063
- run: git diff --exit-code # Must commit everything
6164

6265
test-windows:
@@ -98,7 +101,12 @@ jobs:
98101
save-if: ${{ github.ref_name == 'main' }}
99102
shared-key: windows-latest
100103

101-
- run: cargo test --all-features # cargo ck # no need to `cargo ck` because it's already checked in linux
104+
- name: Run tests
105+
# No need for `cargo ck` because it's already checked in linux
106+
# Run `website` tests separately to avoid feature unification problems with `oxlint`
107+
run: |
108+
cargo test --workspace --all-features --exclude website
109+
cargo test -p website
102110
working-directory: ${{ env.DEV_DRIVE_WORKSPACE }}
103111
shell: bash
104112

@@ -114,7 +122,9 @@ jobs:
114122
save-cache: ${{ github.ref_name == 'main' }}
115123
cache-key: s390x-unknown-linux-gnu
116124
tools: cross
117-
- run: cross test --all-features --target s390x-unknown-linux-gnu
125+
- run: cross test --workspace --all-features --exclude website --target s390x-unknown-linux-gnu
126+
# Run separately to avoid feature unification problems with `oxlint`
127+
- run: cross test -p website --target s390x-unknown-linux-gnu
118128

119129
test-wasm32-wasip1-threads:
120130
name: Test wasm32-wasip1-threads

.github/workflows/release_oxlint.yml

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,34 +48,42 @@ jobs:
4848
- os: windows-latest
4949
target: x86_64-pc-windows-msvc
5050
code-target: win32-x64
51+
build-oxlint: pnpm run build-napi-release --target x86_64-pc-windows-msvc
5152

5253
- os: windows-latest
5354
target: aarch64-pc-windows-msvc
5455
code-target: win32-arm64
56+
build-oxlint: pnpm run build-napi-release --target aarch64-pc-windows-msvc
5557

5658
- os: ubuntu-latest
5759
target: x86_64-unknown-linux-gnu
5860
code-target: linux-x64-gnu
61+
build-oxlint: pnpm run build-napi-release --target x86_64-unknown-linux-gnu --use-napi-cross
5962

6063
- os: ubuntu-latest
6164
target: aarch64-unknown-linux-gnu
6265
code-target: linux-arm64-gnu
66+
build-oxlint: pnpm run build-napi-release --target aarch64-unknown-linux-gnu --use-napi-cross
6367

6468
- os: ubuntu-latest
6569
target: x86_64-unknown-linux-musl
6670
code-target: linux-x64-musl
71+
build-oxlint: pnpm run build-napi-release --target x86_64-unknown-linux-musl -x
6772

6873
- os: ubuntu-latest
6974
target: aarch64-unknown-linux-musl
7075
code-target: linux-arm64-musl
76+
build-oxlint: pnpm run build-napi-release --target aarch64-unknown-linux-musl -x
7177

7278
- os: macos-latest
7379
target: x86_64-apple-darwin
7480
code-target: darwin-x64
81+
build-oxlint: pnpm run build-napi-release --target x86_64-apple-darwin
7582

7683
- os: macos-latest
7784
target: aarch64-apple-darwin
7885
code-target: darwin-arm64
86+
build-oxlint: pnpm run build-napi-release --target aarch64-apple-darwin
7987

8088
name: Package ${{ matrix.code-target }}
8189
runs-on: ${{ matrix.os }}
@@ -100,21 +108,35 @@ jobs:
100108
- name: Add Rust Target
101109
run: rustup target add ${{ matrix.target }}
102110

103-
- name: Build
111+
- uses: oxc-project/setup-node@f42e3bda950c7454575e78ee4eaac880a077700c # v1.0.0
112+
113+
- uses: goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406 # v2.2.1
114+
if: ${{ contains(matrix.target, 'musl') }}
115+
with:
116+
version: 0.13.0
117+
118+
- name: Build oxlint
119+
working-directory: apps/oxlint
120+
run: ${{ matrix.build-oxlint }} --features allocator
104121
shell: bash
105122
env:
106123
TARGET_CC: clang # for mimalloc
107-
run: |
108-
cross build --release -p oxlint --bin oxlint --features allocator --target=${{ matrix.target }}
109-
cross build --release -p oxc_language_server --bin oxc_language_server --target=${{ matrix.target }}
124+
125+
- name: Build language server
126+
shell: bash
127+
env:
128+
TARGET_CC: clang # for mimalloc
129+
run: cross build --release -p oxc_language_server --bin oxc_language_server --target=${{ matrix.target }}
110130

111131
# The binaries are zipped to fix permission loss https://github.com/actions/upload-artifact#permission-loss
112132
- name: Archive Binaries
113133
if: runner.os == 'Windows'
134+
# Windows `.node` files have `-msvc` postfix e.g. `oxlint.win32-x64-msvc.node`. Remove the postfix.
114135
run: |
115-
OXLINT_BIN_NAME=oxlint-${{ matrix.code-target }}
116-
mv target/${{ matrix.target }}/release/oxlint.exe $OXLINT_BIN_NAME.exe
117-
7z a $OXLINT_BIN_NAME.zip $OXLINT_BIN_NAME.exe
136+
OXLINT_BIN_SRC_NAME=oxlint.${{ matrix.code-target }}-msvc.node
137+
OXLINT_BIN_NAME=oxlint.${{ matrix.code-target }}.node
138+
mv apps/oxlint/src-js/$OXLINT_BIN_SRC_NAME $OXLINT_BIN_NAME
139+
7z a oxlint-${{ matrix.code-target }}.zip $OXLINT_BIN_NAME
118140
119141
OXLS_BIN_NAME=oxc_language_server-${{ matrix.code-target }}
120142
mv target/${{ matrix.target }}/release/oxc_language_server.exe $OXLS_BIN_NAME.exe
@@ -124,9 +146,9 @@ jobs:
124146
- name: Archive Binaries
125147
if: runner.os != 'Windows'
126148
run: |
127-
OXLINT_BIN_NAME=oxlint-${{ matrix.code-target }}
128-
mv target/${{ matrix.target }}/release/oxlint $OXLINT_BIN_NAME
129-
tar czf $OXLINT_BIN_NAME.tar.gz $OXLINT_BIN_NAME
149+
OXLINT_BIN_NAME=oxlint.${{ matrix.code-target }}.node
150+
mv apps/oxlint/src-js/$OXLINT_BIN_NAME .
151+
tar czf oxlint-${{ matrix.code-target }}.tar.gz $OXLINT_BIN_NAME
130152
131153
OXLS_BIN_NAME=oxc_language_server-${{ matrix.code-target }}
132154
mv target/${{ matrix.target }}/release/oxc_language_server $OXLS_BIN_NAME
@@ -184,6 +206,10 @@ jobs:
184206

185207
- uses: oxc-project/setup-node@fdbf0dfd334c4e6d56ceeb77d91c76339c2a0885 # v1.0.4
186208

209+
- name: Generate oxlint JS build
210+
working-directory: apps/oxlint
211+
run: pnpm run build-js
212+
187213
- name: Generate npm packages
188214
run: |
189215
node npm/oxlint/scripts/generate-packages.mjs
@@ -253,7 +279,7 @@ jobs:
253279
ref: main
254280
inputs: '{ "version": "${{ needs.check.outputs.version }}" }'
255281

256-
- name: Bump oxc-project/eslint-plugin-oxlint
282+
- name: Bump oxc-project/oxlint-migrate
257283
uses: benc-uk/workflow-dispatch@e2e5e9a103e331dad343f381a29e654aea3cf8fc # v1.2.4
258284
with:
259285
repo: oxc-project/oxlint-migrate

Cargo.lock

Lines changed: 3 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/oxlint/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
*.node
3+
dist/

apps/oxlint/Cargo.toml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,10 @@ description.workspace = true
1616
workspace = true
1717

1818
[lib]
19-
crate-type = ["lib"]
19+
crate-type = ["cdylib", "lib"]
2020
path = "src/lib.rs"
2121
doctest = false
2222

23-
[[bin]]
24-
name = "oxlint"
25-
path = "src/main.rs"
26-
test = false
27-
doctest = false
28-
2923
[dependencies]
3024
oxc_allocator = { workspace = true, features = ["fixed_size"] }
3125
oxc_diagnostics = { workspace = true }
@@ -36,13 +30,15 @@ bpaf = { workspace = true, features = ["autocomplete", "bright-color", "derive"]
3630
cow-utils = { workspace = true }
3731
ignore = { workspace = true, features = ["simd-accel"] }
3832
miette = { workspace = true }
39-
napi = { workspace = true }
33+
napi = { workspace = true, features = ["async"], optional = true }
34+
napi-derive = { workspace = true, optional = true }
4035
rayon = { workspace = true }
4136
rustc-hash = { workspace = true }
4237
serde = { workspace = true }
4338
serde_json = { workspace = true }
4439
simdutf8 = { workspace = true }
4540
tempfile = { workspace = true }
41+
tokio = { workspace = true, features = ["rt-multi-thread"] }
4642
tracing-subscriber = { workspace = true, features = [] } # Omit the `regex` feature
4743

4844
[target.'cfg(not(any(target_os = "linux", target_os = "freebsd", target_arch = "arm", target_family = "wasm")))'.dependencies]
@@ -54,11 +50,15 @@ mimalloc-safe = { workspace = true, optional = true, features = ["skip_collect_o
5450
[target.'cfg(all(target_os = "linux", target_arch = "aarch64"))'.dependencies]
5551
mimalloc-safe = { workspace = true, optional = true, features = ["skip_collect_on_exit", "local_dynamic_tls", "no_opt_arch"] }
5652

53+
[build-dependencies]
54+
napi-build = { workspace = true }
55+
5756
[dev-dependencies]
5857
insta = { workspace = true }
5958
lazy-regex = { workspace = true }
6059

6160
[features]
62-
default = []
61+
default = ["napi"]
62+
napi = ["dep:napi", "dep:napi-derive"]
6363
allocator = ["dep:mimalloc-safe"]
6464
force_test_reporter = ["oxc_linter/force_test_reporter"]
File renamed without changes.

napi/oxlint/package.json renamed to apps/oxlint/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "oxlint",
33
"version": "0.1.0",
4-
"bin": "dist/index.js",
4+
"bin": "dist/cli.js",
55
"type": "module",
66
"scripts": {
77
"build": "pnpm run build-napi-release && pnpm run build-js",
@@ -16,15 +16,15 @@
1616
"engines": {
1717
"node": ">=20.0.0"
1818
},
19-
"description": "Staging package for oxlint while we integrate custom JS plugins into oxlint",
19+
"description": "Linter for the JavaScript Oxidation Compiler",
2020
"author": "Boshen and oxc contributors",
2121
"license": "MIT",
2222
"homepage": "https://oxc.rs",
2323
"bugs": "https://github.com/oxc-project/oxc/issues",
2424
"repository": {
2525
"type": "git",
2626
"url": "https://github.com/oxc-project/oxc.git",
27-
"directory": "napi/oxlint"
27+
"directory": "apps/oxlint"
2828
},
2929
"publishConfig": {
3030
"registry": "https://registry.npmjs.org/",
@@ -41,6 +41,7 @@
4141
},
4242
"napi": {
4343
"binaryName": "oxlint",
44+
"packageName": "@oxlint/binding",
4445
"targets": [
4546
"win32-x64",
4647
"win32-arm64",

napi/oxlint/scripts/build.js renamed to apps/oxlint/scripts/build.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,35 @@
11
import { execSync } from 'node:child_process';
2-
import { copyFileSync, mkdirSync, readdirSync } from 'node:fs';
2+
import { copyFileSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
33
import { join } from 'node:path';
44

55
const oxlintDirPath = join(import.meta.dirname, '..'),
66
distDirPath = join(oxlintDirPath, 'dist'),
7-
parserDirPath = join(oxlintDirPath, '../parser');
7+
parserDirPath = join(oxlintDirPath, '../../napi/parser');
8+
9+
// Modify `bindings.js` to use correct package names
10+
console.log('Modifying bindings.js...');
11+
const bindingsPath = join(oxlintDirPath, 'src-js/bindings.js');
12+
let bindingsJs = readFileSync(bindingsPath, 'utf8');
13+
bindingsJs = bindingsJs.replace(/require\('@oxlint\/binding-(.+?)'\)/g, (_, name) => {
14+
name = name.replace(/-msvc(\/|$)/g, '$1');
15+
return `require('@oxlint/${name}')`;
16+
});
17+
writeFileSync(bindingsPath, bindingsJs);
818

919
// Build with tsdown
1020
console.log('Building with tsdown...');
1121
execSync('pnpm tsdown', { stdio: 'inherit', cwd: oxlintDirPath });
1222

13-
// Copy files from `napi/parser` to `napi/oxlint/dist`
23+
// Add `package.json` to `dist` dir.
24+
// `npm/oxlint` package is CommonJS, so we need this file to tell Node.js that `dist` is ESM.
25+
console.log('Adding package.json to dist...');
26+
writeFileSync(
27+
join(distDirPath, 'package.json'),
28+
JSON.stringify({ type: 'module' }, null, 2) + '\n',
29+
);
30+
console.log('- Created package.json');
31+
32+
// Copy files from `napi/parser` to `apps/oxlint/dist`
1433
console.log('Copying files from parser...');
1534

1635
const parserFilePaths = [
File renamed without changes.

0 commit comments

Comments
 (0)