diff --git a/.github/generated/ast_changes_watch_list.yml b/.github/generated/ast_changes_watch_list.yml index d3ad4b28bb23b..42604240c1c21 100644 --- a/.github/generated/ast_changes_watch_list.yml +++ b/.github/generated/ast_changes_watch_list.yml @@ -3,6 +3,8 @@ src: - '.github/generated/ast_changes_watch_list.yml' + - 'apps/oxlint/src-js/generated/constants.mjs' + - 'apps/oxlint/src/generated/raw_transfer_constants.rs' - 'crates/oxc_allocator/src/generated/assert_layouts.rs' - 'crates/oxc_allocator/src/generated/fixed_size_constants.rs' - 'crates/oxc_allocator/src/pool/fixed_size.rs' @@ -64,8 +66,6 @@ src: - 'crates/oxc_syntax/src/serialize.rs' - 'crates/oxc_syntax/src/symbol.rs' - 'crates/oxc_traverse/src/generated/scopes_collector.rs' - - 'napi/oxlint/src-js/generated/constants.mjs' - - 'napi/oxlint/src/generated/raw_transfer_constants.rs' - 'napi/parser/generated/constants.mjs' - 'napi/parser/generated/deserialize/js.mjs' - 'napi/parser/generated/deserialize/ts.mjs' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 680cd8732b7fe..4c8e49962c89f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,8 @@ jobs: save-cache: ${{ github.ref_name == 'main' }} cache-key: warm - run: cargo ck - - run: cargo test --all-features + - run: cargo test --workspace --all-features --exclude website + - run: cargo test -p website # Run separately to avoid feature unification problems with `oxlint` - run: git diff --exit-code # Must commit everything test-ubuntu-aarch64: @@ -41,7 +42,8 @@ jobs: save-cache: ${{ github.ref_name == 'main' }} cache-key: warm-aarch64 - run: cargo ck - - run: cargo test --all-features + - run: cargo test --workspace --all-features --exclude website + - run: cargo test -p website # Run separately to avoid feature unification problems with `oxlint` - run: git diff --exit-code # Must commit everything test-mac: # Separate job to save a job on PRs @@ -56,7 +58,8 @@ jobs: save-cache: ${{ github.ref_name == 'main' }} cache-key: warm - run: cargo ck - - run: cargo test --all-features + - run: cargo test --workspace --all-features --exclude website + - run: cargo test -p website # Run separately to avoid feature unification problems with `oxlint` - run: git diff --exit-code # Must commit everything test-windows: @@ -98,7 +101,12 @@ jobs: save-if: ${{ github.ref_name == 'main' }} shared-key: windows-latest - - run: cargo test --all-features # cargo ck # no need to `cargo ck` because it's already checked in linux + - name: Run tests + # No need for `cargo ck` because it's already checked in linux + # Run `website` tests separately to avoid feature unification problems with `oxlint` + run: | + cargo test --workspace --all-features --exclude website + cargo test -p website working-directory: ${{ env.DEV_DRIVE_WORKSPACE }} shell: bash @@ -114,7 +122,9 @@ jobs: save-cache: ${{ github.ref_name == 'main' }} cache-key: s390x-unknown-linux-gnu tools: cross - - run: cross test --all-features --target s390x-unknown-linux-gnu + - run: cross test --workspace --all-features --exclude website --target s390x-unknown-linux-gnu + # Run separately to avoid feature unification problems with `oxlint` + - run: cross test -p website --target s390x-unknown-linux-gnu test-wasm32-wasip1-threads: name: Test wasm32-wasip1-threads diff --git a/.github/workflows/release_oxlint.yml b/.github/workflows/release_oxlint.yml index 238a59ba25352..796a287fdd73f 100644 --- a/.github/workflows/release_oxlint.yml +++ b/.github/workflows/release_oxlint.yml @@ -48,34 +48,42 @@ jobs: - os: windows-latest target: x86_64-pc-windows-msvc code-target: win32-x64 + build-oxlint: pnpm run build-napi-release --target x86_64-pc-windows-msvc - os: windows-latest target: aarch64-pc-windows-msvc code-target: win32-arm64 + build-oxlint: pnpm run build-napi-release --target aarch64-pc-windows-msvc - os: ubuntu-latest target: x86_64-unknown-linux-gnu code-target: linux-x64-gnu + build-oxlint: pnpm run build-napi-release --target x86_64-unknown-linux-gnu --use-napi-cross - os: ubuntu-latest target: aarch64-unknown-linux-gnu code-target: linux-arm64-gnu + build-oxlint: pnpm run build-napi-release --target aarch64-unknown-linux-gnu --use-napi-cross - os: ubuntu-latest target: x86_64-unknown-linux-musl code-target: linux-x64-musl + build-oxlint: pnpm run build-napi-release --target x86_64-unknown-linux-musl -x - os: ubuntu-latest target: aarch64-unknown-linux-musl code-target: linux-arm64-musl + build-oxlint: pnpm run build-napi-release --target aarch64-unknown-linux-musl -x - os: macos-latest target: x86_64-apple-darwin code-target: darwin-x64 + build-oxlint: pnpm run build-napi-release --target x86_64-apple-darwin - os: macos-latest target: aarch64-apple-darwin code-target: darwin-arm64 + build-oxlint: pnpm run build-napi-release --target aarch64-apple-darwin name: Package ${{ matrix.code-target }} runs-on: ${{ matrix.os }} @@ -100,21 +108,35 @@ jobs: - name: Add Rust Target run: rustup target add ${{ matrix.target }} - - name: Build + - uses: oxc-project/setup-node@f42e3bda950c7454575e78ee4eaac880a077700c # v1.0.0 + + - uses: goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406 # v2.2.1 + if: ${{ contains(matrix.target, 'musl') }} + with: + version: 0.13.0 + + - name: Build oxlint + working-directory: apps/oxlint + run: ${{ matrix.build-oxlint }} --features allocator shell: bash env: TARGET_CC: clang # for mimalloc - run: | - cross build --release -p oxlint --bin oxlint --features allocator --target=${{ matrix.target }} - cross build --release -p oxc_language_server --bin oxc_language_server --target=${{ matrix.target }} + + - name: Build language server + shell: bash + env: + TARGET_CC: clang # for mimalloc + run: cross build --release -p oxc_language_server --bin oxc_language_server --target=${{ matrix.target }} # The binaries are zipped to fix permission loss https://github.com/actions/upload-artifact#permission-loss - name: Archive Binaries if: runner.os == 'Windows' + # Windows `.node` files have `-msvc` postfix e.g. `oxlint.win32-x64-msvc.node`. Remove the postfix. run: | - OXLINT_BIN_NAME=oxlint-${{ matrix.code-target }} - mv target/${{ matrix.target }}/release/oxlint.exe $OXLINT_BIN_NAME.exe - 7z a $OXLINT_BIN_NAME.zip $OXLINT_BIN_NAME.exe + OXLINT_BIN_SRC_NAME=oxlint.${{ matrix.code-target }}-msvc.node + OXLINT_BIN_NAME=oxlint.${{ matrix.code-target }}.node + mv apps/oxlint/src-js/$OXLINT_BIN_SRC_NAME $OXLINT_BIN_NAME + 7z a oxlint-${{ matrix.code-target }}.zip $OXLINT_BIN_NAME OXLS_BIN_NAME=oxc_language_server-${{ matrix.code-target }} mv target/${{ matrix.target }}/release/oxc_language_server.exe $OXLS_BIN_NAME.exe @@ -124,9 +146,9 @@ jobs: - name: Archive Binaries if: runner.os != 'Windows' run: | - OXLINT_BIN_NAME=oxlint-${{ matrix.code-target }} - mv target/${{ matrix.target }}/release/oxlint $OXLINT_BIN_NAME - tar czf $OXLINT_BIN_NAME.tar.gz $OXLINT_BIN_NAME + OXLINT_BIN_NAME=oxlint.${{ matrix.code-target }}.node + mv apps/oxlint/src-js/$OXLINT_BIN_NAME . + tar czf oxlint-${{ matrix.code-target }}.tar.gz $OXLINT_BIN_NAME OXLS_BIN_NAME=oxc_language_server-${{ matrix.code-target }} mv target/${{ matrix.target }}/release/oxc_language_server $OXLS_BIN_NAME @@ -184,6 +206,10 @@ jobs: - uses: oxc-project/setup-node@fdbf0dfd334c4e6d56ceeb77d91c76339c2a0885 # v1.0.4 + - name: Generate oxlint JS build + working-directory: apps/oxlint + run: pnpm run build-js + - name: Generate npm packages run: | node npm/oxlint/scripts/generate-packages.mjs @@ -253,7 +279,7 @@ jobs: ref: main inputs: '{ "version": "${{ needs.check.outputs.version }}" }' - - name: Bump oxc-project/eslint-plugin-oxlint + - name: Bump oxc-project/oxlint-migrate uses: benc-uk/workflow-dispatch@e2e5e9a103e331dad343f381a29e654aea3cf8fc # v1.2.4 with: repo: oxc-project/oxlint-migrate diff --git a/Cargo.lock b/Cargo.lock index 6514c3ac0ed54..796bbf0ebc7fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2064,19 +2064,6 @@ dependencies = [ "syn", ] -[[package]] -name = "oxc_linter_napi" -version = "0.1.0" -dependencies = [ - "napi", - "napi-build", - "napi-derive", - "oxc_allocator", - "oxlint", - "serde_json", - "tokio", -] - [[package]] name = "oxc_macros" version = "0.0.0" @@ -2546,6 +2533,8 @@ dependencies = [ "lazy-regex", "mimalloc-safe", "napi", + "napi-build", + "napi-derive", "oxc-miette", "oxc_allocator", "oxc_diagnostics", @@ -2557,6 +2546,7 @@ dependencies = [ "serde_json", "simdutf8", "tempfile", + "tokio", "tracing-subscriber", ] diff --git a/apps/oxlint/.gitignore b/apps/oxlint/.gitignore new file mode 100644 index 0000000000000..f3c3e09737cb9 --- /dev/null +++ b/apps/oxlint/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +*.node +dist/ diff --git a/apps/oxlint/Cargo.toml b/apps/oxlint/Cargo.toml index def7e1b13f522..7105e8c69c8de 100644 --- a/apps/oxlint/Cargo.toml +++ b/apps/oxlint/Cargo.toml @@ -16,16 +16,10 @@ description.workspace = true workspace = true [lib] -crate-type = ["lib"] +crate-type = ["cdylib", "lib"] path = "src/lib.rs" doctest = false -[[bin]] -name = "oxlint" -path = "src/main.rs" -test = false -doctest = false - [dependencies] oxc_allocator = { workspace = true, features = ["fixed_size"] } oxc_diagnostics = { workspace = true } @@ -36,13 +30,15 @@ bpaf = { workspace = true, features = ["autocomplete", "bright-color", "derive"] cow-utils = { workspace = true } ignore = { workspace = true, features = ["simd-accel"] } miette = { workspace = true } -napi = { workspace = true } +napi = { workspace = true, features = ["async"], optional = true } +napi-derive = { workspace = true, optional = true } rayon = { workspace = true } rustc-hash = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } simdutf8 = { workspace = true } tempfile = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread"] } tracing-subscriber = { workspace = true, features = [] } # Omit the `regex` feature [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 [target.'cfg(all(target_os = "linux", target_arch = "aarch64"))'.dependencies] mimalloc-safe = { workspace = true, optional = true, features = ["skip_collect_on_exit", "local_dynamic_tls", "no_opt_arch"] } +[build-dependencies] +napi-build = { workspace = true } + [dev-dependencies] insta = { workspace = true } lazy-regex = { workspace = true } [features] -default = [] +default = ["napi"] +napi = ["dep:napi", "dep:napi-derive"] allocator = ["dep:mimalloc-safe"] force_test_reporter = ["oxc_linter/force_test_reporter"] diff --git a/napi/oxlint/build.rs b/apps/oxlint/build.rs similarity index 100% rename from napi/oxlint/build.rs rename to apps/oxlint/build.rs diff --git a/napi/oxlint/package.json b/apps/oxlint/package.json similarity index 89% rename from napi/oxlint/package.json rename to apps/oxlint/package.json index 8f8c612d8952c..a632dbc6e9bcd 100644 --- a/napi/oxlint/package.json +++ b/apps/oxlint/package.json @@ -1,7 +1,7 @@ { "name": "oxlint", "version": "0.1.0", - "bin": "dist/index.js", + "bin": "dist/cli.js", "type": "module", "scripts": { "build": "pnpm run build-napi-release && pnpm run build-js", @@ -16,7 +16,7 @@ "engines": { "node": ">=20.0.0" }, - "description": "Staging package for oxlint while we integrate custom JS plugins into oxlint", + "description": "Linter for the JavaScript Oxidation Compiler", "author": "Boshen and oxc contributors", "license": "MIT", "homepage": "https://oxc.rs", @@ -24,7 +24,7 @@ "repository": { "type": "git", "url": "https://github.com/oxc-project/oxc.git", - "directory": "napi/oxlint" + "directory": "apps/oxlint" }, "publishConfig": { "registry": "https://registry.npmjs.org/", @@ -41,6 +41,7 @@ }, "napi": { "binaryName": "oxlint", + "packageName": "@oxlint/binding", "targets": [ "win32-x64", "win32-arm64", diff --git a/napi/oxlint/scripts/build.js b/apps/oxlint/scripts/build.js similarity index 59% rename from napi/oxlint/scripts/build.js rename to apps/oxlint/scripts/build.js index a32452224de35..e61150a33923f 100755 --- a/napi/oxlint/scripts/build.js +++ b/apps/oxlint/scripts/build.js @@ -1,16 +1,35 @@ import { execSync } from 'node:child_process'; -import { copyFileSync, mkdirSync, readdirSync } from 'node:fs'; +import { copyFileSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; const oxlintDirPath = join(import.meta.dirname, '..'), distDirPath = join(oxlintDirPath, 'dist'), - parserDirPath = join(oxlintDirPath, '../parser'); + parserDirPath = join(oxlintDirPath, '../../napi/parser'); + +// Modify `bindings.js` to use correct package names +console.log('Modifying bindings.js...'); +const bindingsPath = join(oxlintDirPath, 'src-js/bindings.js'); +let bindingsJs = readFileSync(bindingsPath, 'utf8'); +bindingsJs = bindingsJs.replace(/require\('@oxlint\/binding-(.+?)'\)/g, (_, name) => { + name = name.replace(/-msvc(\/|$)/g, '$1'); + return `require('@oxlint/${name}')`; +}); +writeFileSync(bindingsPath, bindingsJs); // Build with tsdown console.log('Building with tsdown...'); execSync('pnpm tsdown', { stdio: 'inherit', cwd: oxlintDirPath }); -// Copy files from `napi/parser` to `napi/oxlint/dist` +// Add `package.json` to `dist` dir. +// `npm/oxlint` package is CommonJS, so we need this file to tell Node.js that `dist` is ESM. +console.log('Adding package.json to dist...'); +writeFileSync( + join(distDirPath, 'package.json'), + JSON.stringify({ type: 'module' }, null, 2) + '\n', +); +console.log('- Created package.json'); + +// Copy files from `napi/parser` to `apps/oxlint/dist` console.log('Copying files from parser...'); const parserFilePaths = [ diff --git a/napi/oxlint/src-js/bindings.d.ts b/apps/oxlint/src-js/bindings.d.ts similarity index 100% rename from napi/oxlint/src-js/bindings.d.ts rename to apps/oxlint/src-js/bindings.d.ts diff --git a/napi/oxlint/src-js/bindings.js b/apps/oxlint/src-js/bindings.js similarity index 83% rename from napi/oxlint/src-js/bindings.js rename to apps/oxlint/src-js/bindings.js index 8d6c68c838fbe..45d42a941a1a5 100644 --- a/napi/oxlint/src-js/bindings.js +++ b/apps/oxlint/src-js/bindings.js @@ -79,8 +79,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-android-arm64') - const bindingPackageVersion = require('oxlint-android-arm64/package.json').version + const binding = require('@oxlint/android-arm64') + const bindingPackageVersion = require('@oxlint/android-arm64/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -95,8 +95,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-android-arm-eabi') - const bindingPackageVersion = require('oxlint-android-arm-eabi/package.json').version + const binding = require('@oxlint/android-arm-eabi') + const bindingPackageVersion = require('@oxlint/android-arm-eabi/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -115,8 +115,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-win32-x64-msvc') - const bindingPackageVersion = require('oxlint-win32-x64-msvc/package.json').version + const binding = require('@oxlint/win32-x64') + const bindingPackageVersion = require('@oxlint/win32-x64/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -131,8 +131,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-win32-ia32-msvc') - const bindingPackageVersion = require('oxlint-win32-ia32-msvc/package.json').version + const binding = require('@oxlint/win32-ia32') + const bindingPackageVersion = require('@oxlint/win32-ia32/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -147,8 +147,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-win32-arm64-msvc') - const bindingPackageVersion = require('oxlint-win32-arm64-msvc/package.json').version + const binding = require('@oxlint/win32-arm64') + const bindingPackageVersion = require('@oxlint/win32-arm64/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -166,8 +166,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-darwin-universal') - const bindingPackageVersion = require('oxlint-darwin-universal/package.json').version + const binding = require('@oxlint/darwin-universal') + const bindingPackageVersion = require('@oxlint/darwin-universal/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -182,8 +182,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-darwin-x64') - const bindingPackageVersion = require('oxlint-darwin-x64/package.json').version + const binding = require('@oxlint/darwin-x64') + const bindingPackageVersion = require('@oxlint/darwin-x64/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -198,8 +198,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-darwin-arm64') - const bindingPackageVersion = require('oxlint-darwin-arm64/package.json').version + const binding = require('@oxlint/darwin-arm64') + const bindingPackageVersion = require('@oxlint/darwin-arm64/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -218,8 +218,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-freebsd-x64') - const bindingPackageVersion = require('oxlint-freebsd-x64/package.json').version + const binding = require('@oxlint/freebsd-x64') + const bindingPackageVersion = require('@oxlint/freebsd-x64/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -234,8 +234,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-freebsd-arm64') - const bindingPackageVersion = require('oxlint-freebsd-arm64/package.json').version + const binding = require('@oxlint/freebsd-arm64') + const bindingPackageVersion = require('@oxlint/freebsd-arm64/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -255,8 +255,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-x64-musl') - const bindingPackageVersion = require('oxlint-linux-x64-musl/package.json').version + const binding = require('@oxlint/linux-x64-musl') + const bindingPackageVersion = require('@oxlint/linux-x64-musl/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -271,8 +271,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-x64-gnu') - const bindingPackageVersion = require('oxlint-linux-x64-gnu/package.json').version + const binding = require('@oxlint/linux-x64-gnu') + const bindingPackageVersion = require('@oxlint/linux-x64-gnu/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -289,8 +289,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-arm64-musl') - const bindingPackageVersion = require('oxlint-linux-arm64-musl/package.json').version + const binding = require('@oxlint/linux-arm64-musl') + const bindingPackageVersion = require('@oxlint/linux-arm64-musl/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -305,8 +305,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-arm64-gnu') - const bindingPackageVersion = require('oxlint-linux-arm64-gnu/package.json').version + const binding = require('@oxlint/linux-arm64-gnu') + const bindingPackageVersion = require('@oxlint/linux-arm64-gnu/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -323,8 +323,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-arm-musleabihf') - const bindingPackageVersion = require('oxlint-linux-arm-musleabihf/package.json').version + const binding = require('@oxlint/linux-arm-musleabihf') + const bindingPackageVersion = require('@oxlint/linux-arm-musleabihf/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -339,8 +339,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-arm-gnueabihf') - const bindingPackageVersion = require('oxlint-linux-arm-gnueabihf/package.json').version + const binding = require('@oxlint/linux-arm-gnueabihf') + const bindingPackageVersion = require('@oxlint/linux-arm-gnueabihf/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -357,8 +357,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-loong64-musl') - const bindingPackageVersion = require('oxlint-linux-loong64-musl/package.json').version + const binding = require('@oxlint/linux-loong64-musl') + const bindingPackageVersion = require('@oxlint/linux-loong64-musl/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -373,8 +373,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-loong64-gnu') - const bindingPackageVersion = require('oxlint-linux-loong64-gnu/package.json').version + const binding = require('@oxlint/linux-loong64-gnu') + const bindingPackageVersion = require('@oxlint/linux-loong64-gnu/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -391,8 +391,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-riscv64-musl') - const bindingPackageVersion = require('oxlint-linux-riscv64-musl/package.json').version + const binding = require('@oxlint/linux-riscv64-musl') + const bindingPackageVersion = require('@oxlint/linux-riscv64-musl/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -407,8 +407,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-riscv64-gnu') - const bindingPackageVersion = require('oxlint-linux-riscv64-gnu/package.json').version + const binding = require('@oxlint/linux-riscv64-gnu') + const bindingPackageVersion = require('@oxlint/linux-riscv64-gnu/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -424,8 +424,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-ppc64-gnu') - const bindingPackageVersion = require('oxlint-linux-ppc64-gnu/package.json').version + const binding = require('@oxlint/linux-ppc64-gnu') + const bindingPackageVersion = require('@oxlint/linux-ppc64-gnu/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -440,8 +440,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-linux-s390x-gnu') - const bindingPackageVersion = require('oxlint-linux-s390x-gnu/package.json').version + const binding = require('@oxlint/linux-s390x-gnu') + const bindingPackageVersion = require('@oxlint/linux-s390x-gnu/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -460,8 +460,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-openharmony-arm64') - const bindingPackageVersion = require('oxlint-openharmony-arm64/package.json').version + const binding = require('@oxlint/openharmony-arm64') + const bindingPackageVersion = require('@oxlint/openharmony-arm64/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -476,8 +476,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-openharmony-x64') - const bindingPackageVersion = require('oxlint-openharmony-x64/package.json').version + const binding = require('@oxlint/openharmony-x64') + const bindingPackageVersion = require('@oxlint/openharmony-x64/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -492,8 +492,8 @@ function requireNative() { loadErrors.push(e) } try { - const binding = require('oxlint-openharmony-arm') - const bindingPackageVersion = require('oxlint-openharmony-arm/package.json').version + const binding = require('@oxlint/openharmony-arm') + const bindingPackageVersion = require('@oxlint/openharmony-arm/package.json').version if (bindingPackageVersion !== '0.1.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { throw new Error(`Native binding package version mismatch, expected 0.1.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) } @@ -524,7 +524,7 @@ if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { } if (!nativeBinding) { try { - wasiBinding = require('oxlint-wasm32-wasi') + wasiBinding = require('@oxlint/wasm32-wasi') nativeBinding = wasiBinding } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { diff --git a/napi/oxlint/src-js/index.ts b/apps/oxlint/src-js/cli.ts similarity index 100% rename from napi/oxlint/src-js/index.ts rename to apps/oxlint/src-js/cli.ts diff --git a/napi/oxlint/src-js/generated/constants.mjs b/apps/oxlint/src-js/generated/constants.mjs similarity index 100% rename from napi/oxlint/src-js/generated/constants.mjs rename to apps/oxlint/src-js/generated/constants.mjs diff --git a/napi/oxlint/src-js/plugins/context.ts b/apps/oxlint/src-js/plugins/context.ts similarity index 100% rename from napi/oxlint/src-js/plugins/context.ts rename to apps/oxlint/src-js/plugins/context.ts diff --git a/napi/oxlint/src-js/plugins/index.ts b/apps/oxlint/src-js/plugins/index.ts similarity index 100% rename from napi/oxlint/src-js/plugins/index.ts rename to apps/oxlint/src-js/plugins/index.ts diff --git a/napi/oxlint/src-js/plugins/lint.ts b/apps/oxlint/src-js/plugins/lint.ts similarity index 100% rename from napi/oxlint/src-js/plugins/lint.ts rename to apps/oxlint/src-js/plugins/lint.ts diff --git a/napi/oxlint/src-js/plugins/load.ts b/apps/oxlint/src-js/plugins/load.ts similarity index 100% rename from napi/oxlint/src-js/plugins/load.ts rename to apps/oxlint/src-js/plugins/load.ts diff --git a/napi/oxlint/src-js/plugins/types.ts b/apps/oxlint/src-js/plugins/types.ts similarity index 100% rename from napi/oxlint/src-js/plugins/types.ts rename to apps/oxlint/src-js/plugins/types.ts diff --git a/napi/oxlint/src-js/plugins/utils.ts b/apps/oxlint/src-js/plugins/utils.ts similarity index 100% rename from napi/oxlint/src-js/plugins/utils.ts rename to apps/oxlint/src-js/plugins/utils.ts diff --git a/napi/oxlint/src-js/plugins/visitor.ts b/apps/oxlint/src-js/plugins/visitor.ts similarity index 100% rename from napi/oxlint/src-js/plugins/visitor.ts rename to apps/oxlint/src-js/plugins/visitor.ts diff --git a/napi/oxlint/src/generated/raw_transfer_constants.rs b/apps/oxlint/src/generated/raw_transfer_constants.rs similarity index 100% rename from napi/oxlint/src/generated/raw_transfer_constants.rs rename to apps/oxlint/src/generated/raw_transfer_constants.rs diff --git a/napi/oxlint/src/external_linter.rs b/apps/oxlint/src/js_plugins/external_linter.rs similarity index 99% rename from napi/oxlint/src/external_linter.rs rename to apps/oxlint/src/js_plugins/external_linter.rs index 4b9f22ae2b838..d5087a49ba102 100644 --- a/napi/oxlint/src/external_linter.rs +++ b/apps/oxlint/src/js_plugins/external_linter.rs @@ -7,14 +7,14 @@ use napi::{ }; use oxc_allocator::{Allocator, free_fixed_size_allocator}; -use oxlint::{ +use oxc_linter::{ ExternalLinter, ExternalLinterLintFileCb, ExternalLinterLoadPluginCb, LintFileResult, PluginLoadResult, }; use crate::{ - JsLintFileCb, JsLoadPluginCb, generated::raw_transfer_constants::{BLOCK_ALIGN, BUFFER_SIZE}, + run::{JsLintFileCb, JsLoadPluginCb}, }; /// Wrap JS callbacks as normal Rust functions, and create [`ExternalLinter`]. diff --git a/apps/oxlint/src/js_plugins/mod.rs b/apps/oxlint/src/js_plugins/mod.rs index 191a7601bc587..819fe152c10ef 100644 --- a/apps/oxlint/src/js_plugins/mod.rs +++ b/apps/oxlint/src/js_plugins/mod.rs @@ -1,3 +1,5 @@ +mod external_linter; mod raw_fs; +pub use external_linter::create_external_linter; pub use raw_fs::RawTransferFileSystem; diff --git a/apps/oxlint/src/lib.rs b/apps/oxlint/src/lib.rs index b764aed31738b..fa71ce05c4e34 100644 --- a/apps/oxlint/src/lib.rs +++ b/apps/oxlint/src/lib.rs @@ -1,15 +1,10 @@ -/// Re-exported external linter types for use in `napi/oxlint`. -pub use oxc_linter::{ - ExternalLinter, ExternalLinterLintFileCb, ExternalLinterLoadPluginCb, LintFileResult, - PluginLoadResult, -}; +// Ignore dead code warnings when building `tasks/website`, which disables `napi` Cargo feature +#![cfg_attr(not(feature = "napi"), allow(dead_code))] mod command; -mod js_plugins; mod lint; mod output_formatter; mod result; -mod run; mod walk; #[cfg(test)] @@ -20,8 +15,23 @@ pub mod cli { pub use super::{command::*, lint::LintRunner, result::CliRunResult}; } -/// Main export for binary -pub use run::lint; +// Only include code to run linter when the `napi` feature is enabled. +// Without this, `tasks/website` will not compile on Linux or Windows. +// `tasks/website` depends on `oxlint` as a normal library, which causes linker errors if NAPI is enabled. +#[cfg(feature = "napi")] +mod run; +#[cfg(feature = "napi")] +pub use run::*; + +// JS plugins are only supported on 64-bit little-endian platforms at present. +// Note: `raw_transfer_constants` module will not compile on 32-bit systems. +#[cfg(all(feature = "napi", target_pointer_width = "64", target_endian = "little"))] +mod generated { + pub mod raw_transfer_constants; +} + +#[cfg(all(feature = "napi", target_pointer_width = "64", target_endian = "little"))] +mod js_plugins; #[cfg(all(feature = "allocator", not(miri), not(target_family = "wasm")))] #[global_allocator] diff --git a/apps/oxlint/src/lint.rs b/apps/oxlint/src/lint.rs index e267634fa3a37..94614c222354a 100644 --- a/apps/oxlint/src/lint.rs +++ b/apps/oxlint/src/lint.rs @@ -22,7 +22,6 @@ use oxc_linter::{ use crate::{ cli::{CliRunResult, LintCommand, MiscOptions, ReportUnusedDirectives, WarningOptions}, - js_plugins::RawTransferFileSystem, output_formatter::{LintCommandInfo, OutputFormatter}, walk::Walk, }; @@ -368,7 +367,21 @@ impl LintRunner { // Use `RawTransferFileSystem` if `ExternalLinter` exists. // This reads the source text into start of allocator, instead of the end. if has_external_linter { - lint_service.with_file_system(Box::new(RawTransferFileSystem)); + #[cfg(all( + feature = "napi", + target_pointer_width = "64", + target_endian = "little" + ))] + lint_service.with_file_system(Box::new(crate::js_plugins::RawTransferFileSystem)); + + #[cfg(not(all( + feature = "napi", + target_pointer_width = "64", + target_endian = "little" + )))] + unreachable!( + "On unsupported platforms, or with `napi` Cargo feature disabled, `ExternalLinter` should not exist" + ); } lint_service.run(&tx_error); diff --git a/apps/oxlint/src/main.rs b/apps/oxlint/src/main.rs deleted file mode 100644 index a1da54bc4cb60..0000000000000 --- a/apps/oxlint/src/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -use oxlint::{cli::CliRunResult, lint}; - -fn main() -> CliRunResult { - lint(None) -} diff --git a/apps/oxlint/src/run.rs b/apps/oxlint/src/run.rs index 65cc1592907a6..7b2f2d17dcd05 100644 --- a/apps/oxlint/src/run.rs +++ b/apps/oxlint/src/run.rs @@ -1,11 +1,68 @@ -use std::io::BufWriter; +use std::{ + io::BufWriter, + process::{ExitCode, Termination}, +}; -use oxc_linter::ExternalLinter; +use napi::{ + Status, + bindgen_prelude::{FnArgs, Promise, Uint8Array}, + threadsafe_function::ThreadsafeFunction, +}; +use napi_derive::napi; use crate::{lint::LintRunner, result::CliRunResult}; +/// JS callback to load a JS plugin. +#[napi] +pub type JsLoadPluginCb = ThreadsafeFunction< + // Arguments + String, // Absolute path of plugin file + // Return value + Promise, // `PluginLoadResult`, serialized to JSON + // Arguments (repeated) + String, + // Error status + Status, + // CalleeHandled + false, +>; + +/// JS callback to lint a file. +#[napi] +pub type JsLintFileCb = ThreadsafeFunction< + // Arguments + FnArgs<( + String, // Absolute path of file to lint + u32, // Buffer ID + Option, // Buffer (optional) + Vec, // Array of rule IDs + )>, + // Return value + String, // `Vec`, serialized to JSON + // Arguments (repeated) + FnArgs<(String, u32, Option, Vec)>, + // Error status + Status, + // CalleeHandled + false, +>; + +/// NAPI entry point. +/// +/// JS side passes in two callbacks: +/// 1. `load_plugin`: Load a JS plugin from a file path. +/// 2. `lint_file`: Lint a file. +/// +/// Returns `true` if linting succeeded without errors, `false` otherwise. +#[expect(clippy::allow_attributes)] +#[allow(clippy::trailing_empty_array, clippy::unused_async)] // https://github.com/napi-rs/napi-rs/issues/2758 +#[napi] +pub async fn lint(load_plugin: JsLoadPluginCb, lint_file: JsLintFileCb) -> bool { + lint_impl(load_plugin, lint_file).report() == ExitCode::SUCCESS +} + /// Run the linter. -pub fn lint(mut external_linter: Option) -> CliRunResult { +fn lint_impl(load_plugin: JsLoadPluginCb, lint_file: JsLintFileCb) -> CliRunResult { init_tracing(); init_miette(); @@ -32,25 +89,24 @@ pub fn lint(mut external_linter: Option) -> CliRunResult { command.handle_threads(); - #[expect(clippy::print_stderr)] - if command.experimental_js_plugins { - // If no `ExternalLinter`, this function was not called by `napi/oxlint` - if external_linter.is_none() { - eprintln!("ERROR: JS plugins are not supported at present"); - return CliRunResult::InvalidOptionConfig; + let external_linter = if command.experimental_js_plugins { + // JS plugins are only supported on 64-bit little-endian platforms at present + #[cfg(all(target_pointer_width = "64", target_endian = "little"))] + { + Some(super::js_plugins::create_external_linter(load_plugin, lint_file)) } - // Exit early if not 64-bit little-endian, to avoid a panic later on when trying to create - // a fixed-size allocator for raw transfer - if cfg!(not(all(target_pointer_width = "64", target_endian = "little"))) { + #[cfg(not(all(target_pointer_width = "64", target_endian = "little")))] + #[expect(clippy::print_stderr)] + { eprintln!( "ERROR: JS plugins are only supported on 64-bit little-endian platforms at present" ); return CliRunResult::InvalidOptionConfig; } } else { - external_linter = None; - } + None + }; // stdio is blocked by LineWriter, use a BufWriter to reduce syscalls. // See `https://github.com/rust-lang/rust/issues/60673`. diff --git a/napi/oxlint/test/__snapshots__/e2e.test.ts.snap b/apps/oxlint/test/__snapshots__/e2e.test.ts.snap similarity index 100% rename from napi/oxlint/test/__snapshots__/e2e.test.ts.snap rename to apps/oxlint/test/__snapshots__/e2e.test.ts.snap diff --git a/napi/oxlint/test/compile-visitor.test.ts b/apps/oxlint/test/compile-visitor.test.ts similarity index 100% rename from napi/oxlint/test/compile-visitor.test.ts rename to apps/oxlint/test/compile-visitor.test.ts diff --git a/napi/oxlint/test/e2e.test.ts b/apps/oxlint/test/e2e.test.ts similarity index 97% rename from napi/oxlint/test/e2e.test.ts rename to apps/oxlint/test/e2e.test.ts index 9817faf98bf64..a12b9b07bb39a 100644 --- a/napi/oxlint/test/e2e.test.ts +++ b/apps/oxlint/test/e2e.test.ts @@ -5,10 +5,10 @@ import { describe, expect, it } from 'vitest'; import { execa } from 'execa'; const PACKAGE_ROOT_PATH = path.dirname(import.meta.dirname); -const ENTRY_POINT_PATH = path.join(PACKAGE_ROOT_PATH, 'dist/index.js'); +const CLI_PATH = path.join(PACKAGE_ROOT_PATH, 'dist/cli.js'); async function runOxlintWithoutPlugins(cwd: string, args: string[] = []) { - return await execa('node', [ENTRY_POINT_PATH, ...args], { + return await execa('node', [CLI_PATH, ...args], { cwd: path.join(PACKAGE_ROOT_PATH, cwd), reject: false, }); diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin/.oxlintrc.json b/apps/oxlint/test/fixtures/basic_custom_plugin/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin/.oxlintrc.json rename to apps/oxlint/test/fixtures/basic_custom_plugin/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin/index.js b/apps/oxlint/test/fixtures/basic_custom_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin/index.js rename to apps/oxlint/test/fixtures/basic_custom_plugin/index.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin/test_plugin/index.js b/apps/oxlint/test/fixtures/basic_custom_plugin/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin/test_plugin/index.js rename to apps/oxlint/test/fixtures/basic_custom_plugin/test_plugin/index.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/.oxlintrc.json b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/.oxlintrc.json rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/01.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/01.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/01.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/01.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/02.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/02.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/02.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/02.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/03.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/03.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/03.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/03.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/04.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/04.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/04.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/04.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/05.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/05.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/05.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/05.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/06.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/06.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/06.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/06.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/07.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/07.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/07.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/07.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/08.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/08.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/08.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/08.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/09.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/09.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/09.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/09.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/10.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/10.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/10.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/10.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/11.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/11.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/11.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/11.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/12.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/12.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/12.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/12.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/13.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/13.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/13.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/13.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/14.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/14.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/14.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/14.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/15.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/15.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/15.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/15.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/16.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/16.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/16.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/16.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/17.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/17.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/17.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/17.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/18.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/18.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/18.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/18.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/19.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/19.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/19.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/19.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/20.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/20.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/files/20.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/files/20.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_many_files/test_plugin/index.js b/apps/oxlint/test/fixtures/basic_custom_plugin_many_files/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_many_files/test_plugin/index.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_many_files/test_plugin/index.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/.oxlintrc.json b/apps/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/.oxlintrc.json rename to apps/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/index.js b/apps/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/index.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/index.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/index.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/test_plugin/index.js b/apps/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/test_plugin/index.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_multiple_rules/test_plugin/index.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_warn_severity/.oxlintrc.json b/apps/oxlint/test/fixtures/basic_custom_plugin_warn_severity/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_warn_severity/.oxlintrc.json rename to apps/oxlint/test/fixtures/basic_custom_plugin_warn_severity/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_warn_severity/index.js b/apps/oxlint/test/fixtures/basic_custom_plugin_warn_severity/index.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_warn_severity/index.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_warn_severity/index.js diff --git a/napi/oxlint/test/fixtures/basic_custom_plugin_warn_severity/test_plugin/index.js b/apps/oxlint/test/fixtures/basic_custom_plugin_warn_severity/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/basic_custom_plugin_warn_severity/test_plugin/index.js rename to apps/oxlint/test/fixtures/basic_custom_plugin_warn_severity/test_plugin/index.js diff --git a/napi/oxlint/test/fixtures/built_in_errors/.oxlintrc.json b/apps/oxlint/test/fixtures/built_in_errors/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/built_in_errors/.oxlintrc.json rename to apps/oxlint/test/fixtures/built_in_errors/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/built_in_errors/index.js b/apps/oxlint/test/fixtures/built_in_errors/index.js similarity index 100% rename from napi/oxlint/test/fixtures/built_in_errors/index.js rename to apps/oxlint/test/fixtures/built_in_errors/index.js diff --git a/napi/oxlint/test/fixtures/built_in_no_errors/.oxlintrc.json b/apps/oxlint/test/fixtures/built_in_no_errors/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/built_in_no_errors/.oxlintrc.json rename to apps/oxlint/test/fixtures/built_in_no_errors/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/built_in_no_errors/index.js b/apps/oxlint/test/fixtures/built_in_no_errors/index.js similarity index 100% rename from napi/oxlint/test/fixtures/built_in_no_errors/index.js rename to apps/oxlint/test/fixtures/built_in_no_errors/index.js diff --git a/napi/oxlint/test/fixtures/context_properties/.oxlintrc.json b/apps/oxlint/test/fixtures/context_properties/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/context_properties/.oxlintrc.json rename to apps/oxlint/test/fixtures/context_properties/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/context_properties/files/1.js b/apps/oxlint/test/fixtures/context_properties/files/1.js similarity index 100% rename from napi/oxlint/test/fixtures/context_properties/files/1.js rename to apps/oxlint/test/fixtures/context_properties/files/1.js diff --git a/napi/oxlint/test/fixtures/context_properties/files/2.js b/apps/oxlint/test/fixtures/context_properties/files/2.js similarity index 100% rename from napi/oxlint/test/fixtures/context_properties/files/2.js rename to apps/oxlint/test/fixtures/context_properties/files/2.js diff --git a/napi/oxlint/test/fixtures/context_properties/test_plugin/index.js b/apps/oxlint/test/fixtures/context_properties/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/context_properties/test_plugin/index.js rename to apps/oxlint/test/fixtures/context_properties/test_plugin/index.js diff --git a/napi/oxlint/test/fixtures/custom_plugin_disable_directives/.oxlintrc.json b/apps/oxlint/test/fixtures/custom_plugin_disable_directives/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_disable_directives/.oxlintrc.json rename to apps/oxlint/test/fixtures/custom_plugin_disable_directives/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/custom_plugin_disable_directives/index.js b/apps/oxlint/test/fixtures/custom_plugin_disable_directives/index.js similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_disable_directives/index.js rename to apps/oxlint/test/fixtures/custom_plugin_disable_directives/index.js diff --git a/napi/oxlint/test/fixtures/custom_plugin_disable_directives/test_plugin/index.js b/apps/oxlint/test/fixtures/custom_plugin_disable_directives/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_disable_directives/test_plugin/index.js rename to apps/oxlint/test/fixtures/custom_plugin_disable_directives/test_plugin/index.js diff --git a/napi/oxlint/test/fixtures/custom_plugin_missing_rule/.oxlintrc.json b/apps/oxlint/test/fixtures/custom_plugin_missing_rule/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_missing_rule/.oxlintrc.json rename to apps/oxlint/test/fixtures/custom_plugin_missing_rule/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/custom_plugin_missing_rule/test_plugin/index.js b/apps/oxlint/test/fixtures/custom_plugin_missing_rule/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_missing_rule/test_plugin/index.js rename to apps/oxlint/test/fixtures/custom_plugin_missing_rule/test_plugin/index.js diff --git a/napi/oxlint/test/fixtures/custom_plugin_via_overrides/.oxlintrc.json b/apps/oxlint/test/fixtures/custom_plugin_via_overrides/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_via_overrides/.oxlintrc.json rename to apps/oxlint/test/fixtures/custom_plugin_via_overrides/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/custom_plugin_via_overrides/index.js b/apps/oxlint/test/fixtures/custom_plugin_via_overrides/index.js similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_via_overrides/index.js rename to apps/oxlint/test/fixtures/custom_plugin_via_overrides/index.js diff --git a/napi/oxlint/test/fixtures/custom_plugin_via_overrides/test_plugin/index.js b/apps/oxlint/test/fixtures/custom_plugin_via_overrides/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_via_overrides/test_plugin/index.js rename to apps/oxlint/test/fixtures/custom_plugin_via_overrides/test_plugin/index.js diff --git a/napi/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/.oxlintrc.json b/apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/.oxlintrc.json rename to apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/index.js b/apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/index.js similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/index.js rename to apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/index.js diff --git a/napi/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/test_plugin/index.js b/apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/test_plugin/index.js rename to apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/test_plugin/index.js diff --git a/napi/oxlint/test/fixtures/missing_custom_plugin/.oxlintrc.json b/apps/oxlint/test/fixtures/missing_custom_plugin/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/missing_custom_plugin/.oxlintrc.json rename to apps/oxlint/test/fixtures/missing_custom_plugin/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/utf16_offsets/.oxlintrc.json b/apps/oxlint/test/fixtures/utf16_offsets/.oxlintrc.json similarity index 100% rename from napi/oxlint/test/fixtures/utf16_offsets/.oxlintrc.json rename to apps/oxlint/test/fixtures/utf16_offsets/.oxlintrc.json diff --git a/napi/oxlint/test/fixtures/utf16_offsets/index.js b/apps/oxlint/test/fixtures/utf16_offsets/index.js similarity index 100% rename from napi/oxlint/test/fixtures/utf16_offsets/index.js rename to apps/oxlint/test/fixtures/utf16_offsets/index.js diff --git a/napi/oxlint/test/fixtures/utf16_offsets/test_plugin/index.js b/apps/oxlint/test/fixtures/utf16_offsets/test_plugin/index.js similarity index 100% rename from napi/oxlint/test/fixtures/utf16_offsets/test_plugin/index.js rename to apps/oxlint/test/fixtures/utf16_offsets/test_plugin/index.js diff --git a/napi/oxlint/tsconfig.json b/apps/oxlint/tsconfig.json similarity index 75% rename from napi/oxlint/tsconfig.json rename to apps/oxlint/tsconfig.json index 00460b3a6cc15..f1a7450d93b5b 100644 --- a/napi/oxlint/tsconfig.json +++ b/apps/oxlint/tsconfig.json @@ -6,5 +6,9 @@ "target": "ESNext", "noImplicitAny": true, "skipLibCheck": true - } + }, + "exclude": [ + "node_modules", + "fixtures" + ] } diff --git a/napi/oxlint/tsdown.config.ts b/apps/oxlint/tsdown.config.ts similarity index 91% rename from napi/oxlint/tsdown.config.ts rename to apps/oxlint/tsdown.config.ts index f887d9b1f4670..80df92f41058f 100644 --- a/napi/oxlint/tsdown.config.ts +++ b/apps/oxlint/tsdown.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'tsdown'; export default defineConfig({ - entry: ['src-js/index.ts', 'src-js/plugins/index.ts'], + entry: ['src-js/cli.ts', 'src-js/plugins/index.ts'], format: ['esm'], platform: 'node', target: 'node20', diff --git a/napi/oxlint/vitest.config.mts b/apps/oxlint/vitest.config.mts similarity index 100% rename from napi/oxlint/vitest.config.mts rename to apps/oxlint/vitest.config.mts diff --git a/dprint.json b/dprint.json index ba0517d96ab97..1e0f16c09e8dd 100644 --- a/dprint.json +++ b/dprint.json @@ -17,8 +17,8 @@ "**/CHANGELOG.md", "pnpm-workspace.yaml", "pnpm-lock.yaml", - "napi/oxlint/src-js/bindings.js", - "napi/oxlint/src-js/bindings.d.ts", + "apps/oxlint/src-js/bindings.js", + "apps/oxlint/src-js/bindings.d.ts", "napi/{transform,minify,playground}/index.js", "napi/{parser,transform,minify,playground}/index.d.ts", "napi/{parser,transform,minify,playground}/*.wasi-browser.js", diff --git a/napi/oxlint/.gitignore b/napi/oxlint/.gitignore deleted file mode 100644 index 849ddff3b7ec9..0000000000000 --- a/napi/oxlint/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist/ diff --git a/napi/oxlint/Cargo.toml b/napi/oxlint/Cargo.toml deleted file mode 100644 index 3caa0d3cc5477..0000000000000 --- a/napi/oxlint/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "oxc_linter_napi" -version = "0.1.0" -authors.workspace = true -categories.workspace = true -edition.workspace = true -homepage.workspace = true -include = ["/src", "build.rs"] -keywords.workspace = true -license.workspace = true -publish = false -repository.workspace = true -rust-version.workspace = true -description.workspace = true - -[lints] -workspace = true - -[lib] -crate-type = ["cdylib", "lib"] -test = false -doctest = false - -[dependencies] -oxc_allocator = { workspace = true, features = ["fixed_size"] } -oxlint = { workspace = true, features = ["allocator"] } - -napi = { workspace = true, features = ["async"] } -napi-derive = { workspace = true } -serde_json = { workspace = true } -tokio = { workspace = true, features = ["rt-multi-thread"] } - -[build-dependencies] -napi-build = { workspace = true } - -[features] -default = [] -force_test_reporter = ["oxlint/force_test_reporter"] diff --git a/napi/oxlint/README.md b/napi/oxlint/README.md deleted file mode 100644 index 6c1e88e453bfd..0000000000000 --- a/napi/oxlint/README.md +++ /dev/null @@ -1 +0,0 @@ -# Oxlint 2 diff --git a/napi/oxlint/src/lib.rs b/napi/oxlint/src/lib.rs deleted file mode 100644 index c0a763e3db19c..0000000000000 --- a/napi/oxlint/src/lib.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::process::{ExitCode, Termination}; - -use napi::{ - Status, - bindgen_prelude::{FnArgs, Promise, Uint8Array}, - threadsafe_function::ThreadsafeFunction, -}; -use napi_derive::napi; - -use oxlint::lint as oxlint_lint; - -// JS plugins are only supported on 64-bit little-endian platforms at present. -// Note: `raw_transfer_constants` module will not compile on 32-bit systems. -#[cfg(all(target_pointer_width = "64", target_endian = "little"))] -mod generated { - pub mod raw_transfer_constants; -} - -#[cfg(all(target_pointer_width = "64", target_endian = "little"))] -mod external_linter; - -/// JS callback to load a JS plugin. -#[napi] -pub type JsLoadPluginCb = ThreadsafeFunction< - // Arguments - String, // Absolute path of plugin file - // Return value - Promise, // `PluginLoadResult`, serialized to JSON - // Arguments (repeated) - String, - // Error status - Status, - // CalleeHandled - false, ->; - -/// JS callback to lint a file. -#[napi] -pub type JsLintFileCb = ThreadsafeFunction< - // Arguments - FnArgs<( - String, // Absolute path of file to lint - u32, // Buffer ID - Option, // Buffer (optional) - Vec, // Array of rule IDs - )>, - // Return value - String, // `Vec`, serialized to JSON - // Arguments (repeated) - FnArgs<(String, u32, Option, Vec)>, - // Error status - Status, - // CalleeHandled - false, ->; - -/// NAPI entry point. -/// -/// JS side passes in two callbacks: -/// 1. `load_plugin`: Load a JS plugin from a file path. -/// 2. `lint_file`: Lint a file. -/// -/// Returns `true` if linting succeeded without errors, `false` otherwise. -#[expect(clippy::allow_attributes)] -#[allow(clippy::trailing_empty_array, clippy::unused_async)] // https://github.com/napi-rs/napi-rs/issues/2758 -#[napi] -pub async fn lint(load_plugin: JsLoadPluginCb, lint_file: JsLintFileCb) -> bool { - // JS plugins are only supported on 64-bit little-endian platforms at present - #[cfg(all(target_pointer_width = "64", target_endian = "little"))] - let external_linter = Some(external_linter::create_external_linter(load_plugin, lint_file)); - - #[cfg(not(all(target_pointer_width = "64", target_endian = "little")))] - let external_linter = None; - - oxlint_lint(external_linter).report() == ExitCode::SUCCESS -} diff --git a/npm/oxlint/bin/oxlint b/npm/oxlint/bin/oxlint index 40a5c240103a4..1d64f2662785b 100755 --- a/npm/oxlint/bin/oxlint +++ b/npm/oxlint/bin/oxlint @@ -1,149 +1,19 @@ #!/usr/bin/env node -const isMusl = () => { - let musl = false; - if (process.platform === "linux") { - musl = isMuslFromFilesystem(); - if (musl === null) { - musl = isMuslFromReport(); - } - if (musl === null) { - musl = isMuslFromChildProcess(); - } - } - return musl; -}; - -const isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-"); - -const isMuslFromFilesystem = () => { - const { readFileSync } = require("fs"); - try { - return readFileSync("/usr/bin/ldd", "utf-8").includes("musl"); - } catch(_error) { - return null; - } -}; - -const isMuslFromReport = () => { - const report = - typeof process.report.getReport === "function" - ? process.report.getReport() - : null; - if (!report) { - return null; - } - if (report.header && report.header.glibcVersionRuntime) { - return false; - } - if (Array.isArray(report.sharedObjects)) { - if (report.sharedObjects.some(isFileMusl)) { - return true; - } - } - return false; -}; - -const isMuslFromChildProcess = () => { - try { - 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; - } -}; - -const { platform, arch, env, version, release } = process; - -const PLATFORMS = { - win32: { - x64: { - musl: "@oxlint/win32-x64/oxlint.exe", - gnu: "@oxlint/win32-x64/oxlint.exe", - }, - arm64: { - musl: "@oxlint/win32-arm64/oxlint.exe", - gnu: "@oxlint/win32-arm64/oxlint.exe", - }, - }, - darwin: { - x64: { - musl: "@oxlint/darwin-x64/oxlint", - gnu: "@oxlint/darwin-x64/oxlint", - }, - arm64: { - musl: "@oxlint/darwin-arm64/oxlint", - gnu: "@oxlint/darwin-arm64/oxlint", - }, - }, - linux: { - x64: { - musl: "@oxlint/linux-x64-musl/oxlint", - gnu: "@oxlint/linux-x64-gnu/oxlint", - }, - arm64: { - musl: "@oxlint/linux-arm64-musl/oxlint", - gnu: "@oxlint/linux-arm64-gnu/oxlint", - }, - }, -}; - -let binPath = ( - PLATFORMS && - PLATFORMS[platform] && - PLATFORMS[platform][arch] && - PLATFORMS[platform][arch][isMusl() ? "musl" : "gnu"] -) || null; - -if (binPath) { - const result = require("child_process").spawnSync( - require.resolve(binPath), - process.argv.slice(2), - { - shell: false, - stdio: "inherit", - env: Object.assign({}, env, { - JS_RUNTIME_VERSION: version, - JS_RUNTIME_NAME: release.name, - NODE_PACKAGE_MANAGER: detectPackageManager(), - }), - } - ); - - if (result.error) { - throw result.error; - } - - process.exitCode = result.status; -} else { - let target = `${platform}-${arch}`; - if (isMusl()) { - target = `${target}-musl`; - } - console.error( - `The oxlint CLI package doesn't ship with prebuilt binaries for your platform (${target}) yet. ` + - "You can create an issue at https://github.com/oxc-project/oxc/issues for support." - ); +// This script is run as CommonJS, so use dynamic import to load ESM module `dist/cli.js`. +// Even if runtime supports require(ESM), can't use `require` here, because `dist/cli.js` +// uses top-level `await`. +// +// `dist/cli.js` uses require(ESM) internally, but only on path where `--experimental-js-plugins` +// CLI option is used. So we still support runtimes without require(ESM) for users who aren't +// using experimental options. +import("../dist/cli.js").catch(onError); + +function onError(err) { + console.error(err); + // Note: NodeJS recommends setting `process.exitCode` instead of calling `process.exit()`. + // `process.exit()` kills the process immediately and `stdout` may not be flushed before process dies. + // https://nodejs.org/api/process.html#processexitcode + // Process should exit immediately after this anyway, because event loop is empty. process.exitCode = 1; } - -/** - * NPM, Yarn, and other package manager set the `npm_config_user_agent`. It has the following format: - * - * ``` - * "npm/8.3.0 node/v16.13.2 win32 x64 workspaces/false - * ``` - * - * @returns The package manager string (`npm/8.3.0`) or null if the user agent string isn't set. - */ -function detectPackageManager() { - const userAgent = env.npm_config_user_agent; - - if (userAgent == null) { - return null; - } - - return userAgent.split(" ")[0]; -} diff --git a/npm/oxlint/package.json b/npm/oxlint/package.json index d616e3c12bdab..5c463687e40dc 100644 --- a/npm/oxlint/package.json +++ b/npm/oxlint/package.json @@ -27,6 +27,7 @@ "bin/oxlint", "bin/oxc_language_server", "configuration_schema.json", + "dist", "README.md" ] } diff --git a/npm/oxlint/scripts/generate-packages.mjs b/npm/oxlint/scripts/generate-packages.mjs index 1ccfc6e735954..bd62879f33b54 100644 --- a/npm/oxlint/scripts/generate-packages.mjs +++ b/npm/oxlint/scripts/generate-packages.mjs @@ -6,10 +6,12 @@ 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 OXLINT_ROOT = resolve(fileURLToPath(import.meta.url), '../..'); // /npm/oxlint +const PACKAGES_ROOT = resolve(OXLINT_ROOT, '..'); // /npm const REPO_ROOT = resolve(PACKAGES_ROOT, '..'); -const MANIFEST_PATH = resolve(OXLINT_ROOT, 'package.json'); +const MANIFEST_PATH = resolve(OXLINT_ROOT, 'package.json'); // /npm/oxlint/package.json +const OXLINT_DIST_SRC = resolve(REPO_ROOT, 'apps/oxlint/dist'); // /apps/oxlint/dist +const OXLINT_DIST_DEST = resolve(OXLINT_ROOT, 'dist'); // /npm/oxlint/dist const rootManifest = JSON.parse( fs.readFileSync(MANIFEST_PATH).toString('utf-8'), @@ -42,6 +44,8 @@ function generateNativePackage(target) { const manifest = { name: packageName, version, + type: 'commonjs', + main: `${OXLINT_BIN_NAME}.${target}.node`, author, license, homepage, @@ -51,7 +55,7 @@ function generateNativePackage(target) { cpu: [arch], ...libc, publishConfig: { - executableFiles: ['oxlint', 'oxc_language_server'], + executableFiles: ['oxc_language_server'], }, }; @@ -59,21 +63,16 @@ function generateNativePackage(target) { console.log(`Create manifest ${manifestPath}`); fs.writeFileSync(manifestPath, JSON.stringify(manifest)); - // Copy the binary - const ext = platform === 'win32' ? '.exe' : ''; - - const oxlintBinSource = resolve( - REPO_ROOT, - `${OXLINT_BIN_NAME}-${target}${ext}`, - ); - const oxlintBinTarget = resolve(packageRoot, `${OXLINT_BIN_NAME}${ext}`); + // Copy the binaries + const oxlintBinSource = resolve(REPO_ROOT, `${OXLINT_BIN_NAME}.${target}.node`); + const oxlintBinTarget = resolve(packageRoot, `${OXLINT_BIN_NAME}.${target}.node`); + const ext = platform === 'win32' ? '.exe' : ''; const oxlsBinSource = resolve(REPO_ROOT, `${OXLS_BIN_NAME}-${target}${ext}`); const oxlsBinTarget = resolve(packageRoot, `${OXLS_BIN_NAME}${ext}`); console.log(`Copy linter binary ${oxlintBinSource}`); fs.copyFileSync(oxlintBinSource, oxlintBinTarget); - fs.chmodSync(oxlintBinTarget, 0o755); console.log(`Copy language server binary ${oxlsBinSource}`); fs.copyFileSync(oxlsBinSource, oxlsBinTarget); @@ -111,8 +110,13 @@ function writeManifest() { fs.writeFileSync(manifestPath, content); } -// NOTE: Must update npm/oxlint/bin/oxlint -// and npm/oxlint/bin/oxc_language_server +// Copy `dist` directory from `apps/oxlint/dist` to `npm/oxlint/dist`. +// `apps/oxlint/scripts/build.js` must be run before this script to create the `dist` directory. +function copyDistFiles() { + fs.cpSync(OXLINT_DIST_SRC, OXLINT_DIST_DEST, { recursive: true }); +} + +// NOTE: Must update npm/oxlint/bin/oxc_language_server const TARGETS = [ 'win32-x64', 'win32-arm64', @@ -129,3 +133,4 @@ for (const target of TARGETS) { } writeManifest(); +copyDistFiles(); diff --git a/oxlintrc.json b/oxlintrc.json index 9a0b0eb1a32cc..5651c90c35758 100644 --- a/oxlintrc.json +++ b/oxlintrc.json @@ -42,6 +42,7 @@ "npm/runtime/**", "tasks/coverage/**", "crates/oxc_semantic/tests/**", - "napi/**" // TODO + "napi/**", // TODO + "apps/oxlint" // TODO ] } diff --git a/package.json b/package.json index 426cdef05e943..dd6bc56d0c4b7 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,10 @@ "private": true, "packageManager": "pnpm@10.16.1", "scripts": { - "build": "pnpm --workspace-concurrency=1 --filter './napi/*' build", - "build-dev": "pnpm --workspace-concurrency=1 --filter './napi/*' build-dev", - "build-test": "pnpm --workspace-concurrency=1 --filter './napi/*' build-test", - "test": "pnpm --workspace-concurrency=1 --filter './napi/*' test", + "build": "pnpm --workspace-concurrency=1 --filter './napi/*' --filter './apps/*' build", + "build-dev": "pnpm --workspace-concurrency=1 --filter './napi/*' --filter './apps/*' build-dev", + "build-test": "pnpm --workspace-concurrency=1 --filter './napi/*' --filter './apps/*' build-test", + "test": "pnpm --workspace-concurrency=1 --filter './napi/*' --filter './apps/*' test", "lint": "oxlint -c oxlintrc.json --type-aware --deny-warnings" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8255b700106dc..299342aa16158 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,6 +42,21 @@ importers: specifier: 'catalog:' version: 3.2.4(@types/node@24.3.1)(@vitest/browser@3.2.4)(jiti@2.5.1) + apps/oxlint: + devDependencies: + execa: + specifier: ^9.6.0 + version: 9.6.0 + tsdown: + specifier: ^0.15.0 + version: 0.15.1(typescript@5.9.2) + typescript: + specifier: 'catalog:' + version: 5.9.2 + vitest: + specifier: 'catalog:' + version: 3.2.4(@types/node@24.3.1)(@vitest/browser@3.2.4)(jiti@2.5.1) + editors/vscode: dependencies: vscode-languageclient: @@ -91,21 +106,6 @@ importers: specifier: 'catalog:' version: 3.2.4(@types/node@24.3.1)(@vitest/browser@3.2.4)(jiti@2.5.1) - napi/oxlint: - devDependencies: - execa: - specifier: ^9.6.0 - version: 9.6.0 - tsdown: - specifier: ^0.15.0 - version: 0.15.1(typescript@5.9.2) - typescript: - specifier: 'catalog:' - version: 5.9.2 - vitest: - specifier: 'catalog:' - version: 3.2.4(@types/node@24.3.1)(@vitest/browser@3.2.4)(jiti@2.5.1) - napi/parser: dependencies: '@oxc-project/types': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b953b78d9fb35..c022c5a711f02 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,5 @@ packages: + - apps/* - napi/* - wasm/* - npm/* diff --git a/tasks/ast_tools/src/generators/raw_transfer.rs b/tasks/ast_tools/src/generators/raw_transfer.rs index 902677ad58618..0e40ba47cacc5 100644 --- a/tasks/ast_tools/src/generators/raw_transfer.rs +++ b/tasks/ast_tools/src/generators/raw_transfer.rs @@ -9,7 +9,7 @@ use quote::quote; use rustc_hash::FxHashSet; use crate::{ - ALLOCATOR_CRATE_PATH, Generator, NAPI_OXLINT_PACKAGE_PATH, NAPI_PARSER_PACKAGE_PATH, + ALLOCATOR_CRATE_PATH, Generator, NAPI_PARSER_PACKAGE_PATH, OXLINT_APP_PATH, codegen::{Codegen, DeriveId}, derives::estree::{ get_fieldless_variant_value, get_struct_field_name, should_flatten_field, @@ -77,7 +77,7 @@ impl Generator for RawTransferGenerator { code: constants_js.clone(), }, Output::Javascript { - path: format!("{NAPI_OXLINT_PACKAGE_PATH}/src-js/generated/constants.mjs"), + path: format!("{OXLINT_APP_PATH}/src-js/generated/constants.mjs"), code: constants_js, }, Output::Rust { @@ -85,7 +85,7 @@ impl Generator for RawTransferGenerator { tokens: constants_rust.clone(), }, Output::Rust { - path: format!("{NAPI_OXLINT_PACKAGE_PATH}/src/generated/raw_transfer_constants.rs"), + path: format!("{OXLINT_APP_PATH}/src/generated/raw_transfer_constants.rs"), tokens: constants_rust.clone(), }, Output::Rust { diff --git a/tasks/ast_tools/src/main.rs b/tasks/ast_tools/src/main.rs index 499f5395b83a0..9c3914ac8762c 100644 --- a/tasks/ast_tools/src/main.rs +++ b/tasks/ast_tools/src/main.rs @@ -257,7 +257,7 @@ const TYPESCRIPT_DEFINITIONS_PATH: &str = "npm/oxc-types/types.d.ts"; const NAPI_PARSER_PACKAGE_PATH: &str = "napi/parser"; /// Path to NAPI oxlint package -const NAPI_OXLINT_PACKAGE_PATH: &str = "napi/oxlint"; +const OXLINT_APP_PATH: &str = "apps/oxlint"; /// Path to write AST changes filter list to const AST_CHANGES_WATCH_LIST_PATH: &str = ".github/generated/ast_changes_watch_list.yml"; diff --git a/tasks/website/Cargo.toml b/tasks/website/Cargo.toml index 2b67eb62610d3..53cf23097b075 100644 --- a/tasks/website/Cargo.toml +++ b/tasks/website/Cargo.toml @@ -21,7 +21,8 @@ bpaf = { workspace = true, features = ["docgen"] } handlebars = { workspace = true } itertools = { workspace = true } oxc_linter = { workspace = true, features = ["ruledocs"] } -oxlint = { path = "../../apps/oxlint" } +# Disable default features to avoid `napi-rs` dependency, which causes linker errors +oxlint = { path = "../../apps/oxlint", default-features = false } pico-args = { workspace = true } project-root = { workspace = true } schemars = { workspace = true }