diff --git a/Cargo.lock b/Cargo.lock index ea6bfa1fd..626d7b8d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -831,13 +831,14 @@ dependencies = [ [[package]] name = "napi" -version = "3.10.5" +version = "3.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6826e5ddc15589b2d68c8ad5321c18e85d40488e93e32962f362e572669bccf6" +checksum = "459197f1592f4c3dbbf9c1b13f5a4599a343e4ef66b96bc340e2a518b36a6662" dependencies = [ "bitflags", "ctor", "futures", + "libc", "napi-build", "napi-sys", "nohash-hasher", @@ -847,15 +848,15 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.3.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9c366d2c8c60b86fa632df75f745509b52f9128f91a6bad4c796e44abb505e1" +checksum = "60fdf9b392c50e7c4170fa633bd909490ed7835cea4c046776d1a4dd8d2ae0ab" [[package]] name = "napi-derive" -version = "3.5.10" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fe526e81c105d3640516fcde83909dd1afe757c0d7a15af58830b5bc0fb9a1" +checksum = "0fa55ea69990c90b888e9e77044410e304ce7f35de599dc6d0b5c1923d2e59af" dependencies = [ "convert_case 0.11.0", "ctor", @@ -867,9 +868,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "5.1.2" +version = "6.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514281397bcddd9ea9a876c7a21a57bff2374237a000ca9a64ea0211ec1993e2" +checksum = "df4056ac7c18e4438ccf0edaed4340ca0d269278c8ec19284f7b23cb039fd0ae" dependencies = [ "convert_case 0.11.0", "proc-macro2", @@ -880,9 +881,9 @@ dependencies = [ [[package]] name = "napi-sys" -version = "3.2.3" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73e43cf2eb0bd1bf95a43c07c076ebd2da5d1e015a71c3d201faeffffcc0ecac" +checksum = "85fbf1fa9f1babfe396d74bbbf52b3643770243e8f5b0b46715d4caf7f0dfc9a" dependencies = [ "libloading", ] diff --git a/napi/angular-compiler/index.js b/napi/angular-compiler/index.js index 7e28e3242..01686cc66 100644 --- a/napi/angular-compiler/index.js +++ b/napi/angular-compiler/index.js @@ -716,47 +716,163 @@ function requireNative() { } } -nativeBinding = requireNative() +function createLoadErrorChain(errors) { + return errors.reduce((previous, current) => { + let message + try { + message = current && typeof current.message === 'string' ? current.message : String(current) + } catch { + message = 'Unknown error' + } + const error = new Error(message) + error.cause = previous + return error + }, null) +} // NAPI_RS_FORCE_WASI is a tri-state flag: // unset / any other value → native binding preferred, WASI is only a fallback -// 'true' → force WASI fallback even if native loaded -// 'error' → force WASI and throw if no WASI binding is found +// 'true' → prefer WASI, but retain native as a lazy fallback +// 'error' → require WASI without initializing a native fallback // Treating any non-empty string as truthy (the historical behavior) meant // NAPI_RS_FORCE_WASI=false, NAPI_RS_FORCE_WASI=0, etc. inadvertently triggered // the WASI path, causing ENOENT for packages shipped without a .wasi.cjs file. +// +// NAPI_RS_WASI_FLAVOR selects one exact generated flavor and implies strict +// WASI loading. It never crosses into another flavor or falls back to native. +const __napiWasiFlavors = ['wasm32-wasi'] +const __napiWasiFlavor = process.env.NAPI_RS_WASI_FLAVOR +const __napiWasiFlavorRequested = + typeof __napiWasiFlavor === 'string' && __napiWasiFlavor.length > 0 +if (__napiWasiFlavorRequested && __napiWasiFlavors.indexOf(__napiWasiFlavor) === -1) { + throw new Error( + 'Unsupported WASI flavor "' + + __napiWasiFlavor + + '". Available flavors: ' + + __napiWasiFlavors.join(', '), + ) +} +const forceWasiError = process.env.NAPI_RS_FORCE_WASI === 'error' const forceWasi = - process.env.NAPI_RS_FORCE_WASI === 'true' || process.env.NAPI_RS_FORCE_WASI === 'error' + process.env.NAPI_RS_FORCE_WASI === 'true' || forceWasiError || __napiWasiFlavorRequested + +if (!forceWasi) { + nativeBinding = requireNative() +} if (!nativeBinding || forceWasi) { let wasiBinding = null - let wasiBindingError = null - try { - wasiBinding = require('./angular-compiler.wasi.cjs') - nativeBinding = wasiBinding - } catch (err) { - if (forceWasi) { - wasiBindingError = err + let wasiBindingLoaded = false + const wasiBindingErrors = [] + const __napiWasiResolveCandidate = (specifier, isPackage, localArtifacts) => { + try { + require.resolve(specifier) + } catch (resolveError) { + if (!resolveError || resolveError.code !== 'MODULE_NOT_FOUND') { + throw resolveError + } + if (isPackage) { + try { + require.resolve(specifier + '/package.json') + } catch (packageError) { + if (packageError && packageError.code === 'MODULE_NOT_FOUND') { + return resolveError + } + // An exports restriction proves the package exists even when its + // package.json is not public. Preserve the root resolution failure. + throw resolveError + } + // The package exists but its main/export target is broken. + throw resolveError + } + return resolveError } + if (localArtifacts) { + let artifactError = null + for (let i = 0; i < localArtifacts.length; i++) { + try { + require.resolve(localArtifacts[i]) + return null + } catch (resolveError) { + if (!resolveError || resolveError.code !== 'MODULE_NOT_FOUND') { + throw resolveError + } + artifactError = resolveError + } + } + return artifactError + } + return null } - if (!nativeBinding || forceWasi) { + if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === 'wasm32-wasi')) { + let candidateError = null + let candidateFailed = false try { - wasiBinding = require('@oxc-angular/binding-wasm32-wasi') - nativeBinding = wasiBinding + candidateError = __napiWasiResolveCandidate('./angular-compiler.wasi.cjs', false, [ + './angular-compiler.wasm32-wasi.debug.wasm', + './angular-compiler.wasm32-wasi.wasm', + ]) + candidateFailed = candidateError !== null + if (!candidateFailed) { + wasiBinding = require('./angular-compiler.wasi.cjs') + nativeBinding = wasiBinding + wasiBindingLoaded = true + } } catch (err) { - if (forceWasi) { - if (!wasiBindingError) { - wasiBindingError = err - } else { - wasiBindingError.cause = err + candidateError = err + candidateFailed = true + } + if (candidateFailed) { + wasiBindingErrors.push(candidateError) + loadErrors.push(candidateError) + } + } + if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === 'wasm32-wasi')) { + let candidateError = null + let candidateFailed = false + try { + candidateError = __napiWasiResolveCandidate( + '@oxc-angular/binding-wasm32-wasi', + true, + undefined, + ) + candidateFailed = candidateError !== null + if (!candidateFailed) { + if ( + process.env.NAPI_RS_ENFORCE_VERSION_CHECK && + process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0' + ) { + const bindingPackageVersion = + require('@oxc-angular/binding-wasm32-wasi/package.json').version + if (bindingPackageVersion !== '0.0.34') { + throw new Error( + `WASI binding package version mismatch, expected 0.0.34 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`, + ) + } } - loadErrors.push(err) + wasiBinding = require('@oxc-angular/binding-wasm32-wasi') + nativeBinding = wasiBinding + wasiBindingLoaded = true } + } catch (err) { + candidateError = err + candidateFailed = true } + if (candidateFailed) { + wasiBindingErrors.push(candidateError) + loadErrors.push(candidateError) + } + } + if (!wasiBindingLoaded && forceWasi && !forceWasiError && !__napiWasiFlavorRequested) { + nativeBinding = requireNative() } - if (process.env.NAPI_RS_FORCE_WASI === 'error' && !wasiBinding) { - const error = new Error('WASI binding not found and NAPI_RS_FORCE_WASI is set to error') - error.cause = wasiBindingError + if ((forceWasiError || __napiWasiFlavorRequested) && !wasiBindingLoaded) { + const error = new Error( + __napiWasiFlavorRequested + ? 'WASI binding for flavor "' + __napiWasiFlavor + '" not found' + : 'WASI binding not found and NAPI_RS_FORCE_WASI is set to error', + ) + error.cause = createLoadErrorChain(wasiBindingErrors) throw error } } @@ -770,10 +886,7 @@ if (!nativeBinding) { ) // assign instead of the `new Error(message, { cause })` options form, // which Node < 16.9 silently ignores - error.cause = loadErrors.reduce((err, cur) => { - cur.cause = err - return cur - }) + error.cause = createLoadErrorChain(loadErrors) throw error } throw new Error(`Failed to load native binding`) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c19575e7..f39456069 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,8 +7,8 @@ settings: catalogs: default: '@napi-rs/cli': - specifier: 3.7.3 - version: 3.7.3 + specifier: 3.8.5 + version: 3.8.5 '@oxc-node/cli': specifier: 0.1.0 version: 0.1.0 @@ -49,7 +49,7 @@ importers: devDependencies: '@napi-rs/cli': specifier: 'catalog:' - version: 3.7.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@24.1.0)(node-addon-api@7.1.1) + version: 3.8.5(@emnapi/core@1.11.2)(@types/node@24.1.0)(node-addon-api@7.1.1) oxfmt: specifier: 'catalog:' version: 0.60.0 @@ -77,7 +77,7 @@ importers: version: 22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3) '@napi-rs/cli': specifier: 'catalog:' - version: 3.7.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@24.1.0)(node-addon-api@7.1.1) + version: 3.8.5(@emnapi/core@1.11.2)(@types/node@24.1.0)(node-addon-api@7.1.1) '@oxc-node/cli': specifier: 'catalog:' version: 0.1.0 @@ -92,7 +92,7 @@ importers: version: 0.60.0 sass: specifier: ^1.93.2 - version: 1.101.7 + version: 1.102.0 typescript: specifier: 'catalog:' version: 6.0.3 @@ -1114,12 +1114,12 @@ packages: cpu: [x64] os: [win32] - '@napi-rs/cli@3.7.3': - resolution: {integrity: sha512-iu5BOoYjYVixp5jwE7JniHvg72XuKWXUfXteu+6Gt/XY4/mslsS+Qbipleg1+3CAUGHkWc+ebaMJj7Pc93BXSQ==} - engines: {node: '>= 16'} + '@napi-rs/cli@3.8.5': + resolution: {integrity: sha512-lOFzFYBeBpnFAajFiyu+RWCrh1j7/Ma7I5z87huUIGlUkyE8eYxIfNBuH8KOOxW3lkkUxP7CMcl5Hfq3EjgEkg==} + engines: {node: ^20.17.0 || ^22.13.0 || >= 23.5.0} hasBin: true peerDependencies: - '@emnapi/runtime': ^1.7.1 + '@emnapi/runtime': 2.0.0-alpha.3 peerDependenciesMeta: '@emnapi/runtime': optional: true @@ -3734,8 +3734,8 @@ packages: electron-to-chromium@1.5.402: resolution: {integrity: sha512-/oOpMaPT6Yg+6/1XQhyIPlzgj7Ye9zf+nNM2Uh6OcE2G2oNptWazFa+qB2Pdqqbsc9KnIDzgAntoYN0dbwOXwA==} - emnapi@1.11.1: - resolution: {integrity: sha512-kSRjhIcxjMFsBqk7ORvoc9aA5SBKDmecrtF5RMcmOTao0kD/zamaxsuTxMI8C1//wGUuvE7a+19pCE7AEhGVnA==} + emnapi@2.0.0-alpha.3: + resolution: {integrity: sha512-K9bc9Xx4OwSfhJpdSOpcfIKzn7/6emuubaIorf6I5e7WBAM79665rf6iHr9y50NL4qYMUP/AheTpD1Z4yU1EBw==} peerDependencies: node-addon-api: '>= 6.1.0' peerDependenciesMeta: @@ -5431,22 +5431,21 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': optional: true - '@napi-rs/cli@3.7.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@24.1.0)(node-addon-api@7.1.1)': + '@napi-rs/cli@3.8.5(@emnapi/core@1.11.2)(@types/node@24.1.0)(node-addon-api@7.1.1)': dependencies: '@inquirer/prompts': 8.5.2(@types/node@24.1.0) - '@napi-rs/cross-toolchain': 1.0.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) - '@napi-rs/wasm-tools': 1.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/cross-toolchain': 1.0.3(@emnapi/core@1.11.2) + '@napi-rs/wasm-tools': 1.0.1(@emnapi/core@1.11.2) '@octokit/rest': 22.0.1 clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 - emnapi: 1.11.1(node-addon-api@7.1.1) + emnapi: 2.0.0-alpha.3(node-addon-api@7.1.1) es-toolkit: 1.47.0 js-yaml: 4.2.0 obug: 2.1.4 semver: 7.8.5 typanion: 3.14.0 - optionalDependencies: - '@emnapi/runtime': 1.11.2 + typescript: 6.0.3 transitivePeerDependencies: - '@emnapi/core' - '@napi-rs/cross-toolchain-arm64-target-aarch64' @@ -5463,10 +5462,10 @@ snapshots: - node-addon-api - supports-color - '@napi-rs/cross-toolchain@1.0.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + '@napi-rs/cross-toolchain@1.0.3(@emnapi/core@1.11.2)': dependencies: - '@napi-rs/lzma': 1.4.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) - '@napi-rs/tar': 1.1.0(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/lzma': 1.4.5(@emnapi/core@1.11.2) + '@napi-rs/tar': 1.1.0(@emnapi/core@1.11.2) debug: 4.4.3 transitivePeerDependencies: - '@emnapi/core' @@ -5512,9 +5511,9 @@ snapshots: '@napi-rs/lzma-linux-x64-musl@1.4.5': optional: true - '@napi-rs/lzma-wasm32-wasi@1.4.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + '@napi-rs/lzma-wasm32-wasi@1.4.5(@emnapi/core@1.11.2)': dependencies: - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.2) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -5529,7 +5528,7 @@ snapshots: '@napi-rs/lzma-win32-x64-msvc@1.4.5': optional: true - '@napi-rs/lzma@1.4.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + '@napi-rs/lzma@1.4.5(@emnapi/core@1.11.2)': optionalDependencies: '@napi-rs/lzma-android-arm-eabi': 1.4.5 '@napi-rs/lzma-android-arm64': 1.4.5 @@ -5544,7 +5543,7 @@ snapshots: '@napi-rs/lzma-linux-s390x-gnu': 1.4.5 '@napi-rs/lzma-linux-x64-gnu': 1.4.5 '@napi-rs/lzma-linux-x64-musl': 1.4.5 - '@napi-rs/lzma-wasm32-wasi': 1.4.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/lzma-wasm32-wasi': 1.4.5(@emnapi/core@1.11.2) '@napi-rs/lzma-win32-arm64-msvc': 1.4.5 '@napi-rs/lzma-win32-ia32-msvc': 1.4.5 '@napi-rs/lzma-win32-x64-msvc': 1.4.5 @@ -5660,9 +5659,9 @@ snapshots: '@napi-rs/tar-linux-x64-musl@1.1.0': optional: true - '@napi-rs/tar-wasm32-wasi@1.1.0(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + '@napi-rs/tar-wasm32-wasi@1.1.0(@emnapi/core@1.11.2)': dependencies: - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.2) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -5677,7 +5676,7 @@ snapshots: '@napi-rs/tar-win32-x64-msvc@1.1.0': optional: true - '@napi-rs/tar@1.1.0(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + '@napi-rs/tar@1.1.0(@emnapi/core@1.11.2)': optionalDependencies: '@napi-rs/tar-android-arm-eabi': 1.1.0 '@napi-rs/tar-android-arm64': 1.1.0 @@ -5691,7 +5690,7 @@ snapshots: '@napi-rs/tar-linux-s390x-gnu': 1.1.0 '@napi-rs/tar-linux-x64-gnu': 1.1.0 '@napi-rs/tar-linux-x64-musl': 1.1.0 - '@napi-rs/tar-wasm32-wasi': 1.1.0(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/tar-wasm32-wasi': 1.1.0(@emnapi/core@1.11.2) '@napi-rs/tar-win32-arm64-msvc': 1.1.0 '@napi-rs/tar-win32-ia32-msvc': 1.1.0 '@napi-rs/tar-win32-x64-msvc': 1.1.0 @@ -5706,6 +5705,12 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.11.2)': + dependencies: + '@emnapi/core': 1.11.2 + '@tybys/wasm-util': 0.10.3 + optional: true + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': dependencies: '@emnapi/core': 1.11.2 @@ -5747,9 +5752,9 @@ snapshots: '@napi-rs/wasm-tools-linux-x64-musl@1.0.1': optional: true - '@napi-rs/wasm-tools-wasm32-wasi@1.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + '@napi-rs/wasm-tools-wasm32-wasi@1.0.1(@emnapi/core@1.11.2)': dependencies: - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.2) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -5764,7 +5769,7 @@ snapshots: '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1': optional: true - '@napi-rs/wasm-tools@1.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + '@napi-rs/wasm-tools@1.0.1(@emnapi/core@1.11.2)': optionalDependencies: '@napi-rs/wasm-tools-android-arm-eabi': 1.0.1 '@napi-rs/wasm-tools-android-arm64': 1.0.1 @@ -5775,7 +5780,7 @@ snapshots: '@napi-rs/wasm-tools-linux-arm64-musl': 1.0.1 '@napi-rs/wasm-tools-linux-x64-gnu': 1.0.1 '@napi-rs/wasm-tools-linux-x64-musl': 1.0.1 - '@napi-rs/wasm-tools-wasm32-wasi': 1.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/wasm-tools-wasm32-wasi': 1.0.1(@emnapi/core@1.11.2) '@napi-rs/wasm-tools-win32-arm64-msvc': 1.0.1 '@napi-rs/wasm-tools-win32-ia32-msvc': 1.0.1 '@napi-rs/wasm-tools-win32-x64-msvc': 1.0.1 @@ -7288,7 +7293,7 @@ snapshots: electron-to-chromium@1.5.402: {} - emnapi@1.11.1(node-addon-api@7.1.1): + emnapi@2.0.0-alpha.3(node-addon-api@7.1.1): optionalDependencies: node-addon-api: 7.1.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index dc0c2e714..fdd42e600 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -39,7 +39,7 @@ minimumReleaseAgeExclude: - oxlint-tsgolint catalog: - '@napi-rs/cli': 3.7.3 + '@napi-rs/cli': 3.8.5 '@oxc-node/cli': 0.1.0 '@oxc-node/core': 0.1.0 '@tailwindcss/vite': 4.3.3