@napi-rs/cli 3.9.0 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -4
- package/dist/cli.js +10359 -8729
- package/dist/index.cjs +10381 -8751
- package/dist/index.d.cts +83 -16
- package/dist/index.d.ts +83 -16
- package/dist/index.js +10359 -8729
- package/docs/wasi.md +318 -4
- package/package.json +5 -6
- package/src/api/__tests__/__snapshots__/templates.spec.ts.md +4003 -53
- package/src/api/__tests__/__snapshots__/templates.spec.ts.snap +0 -0
- package/src/api/__tests__/build-regressions.spec.ts +210 -3
- package/src/api/__tests__/build.spec.ts +2333 -3
- package/src/api/__tests__/create-npm-dirs.spec.ts +105 -3
- package/src/api/__tests__/pre-publish.spec.ts +153 -1
- package/src/api/__tests__/templates.spec.ts +1309 -1
- package/src/api/build.ts +756 -30
- package/src/api/create-npm-dirs.ts +23 -10
- package/src/api/new.ts +13 -18
- package/src/api/pre-publish.ts +34 -11
- package/src/api/rename.ts +10 -21
- package/src/api/templates/binding-target.ts +176 -0
- package/src/api/templates/index.ts +1 -0
- package/src/api/templates/js-binding.ts +54 -10
- package/src/api/templates/load-wasi-template.ts +661 -58
- package/src/api/templates/wasi-worker-template.ts +36 -31
- package/src/commands/build.ts +1 -1
- package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +18 -28
- package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
- package/src/utils/__tests__/misc.spec.ts +4 -0
- package/src/utils/__tests__/reconciliation.spec.ts +676 -0
- package/src/utils/__tests__/serialize.spec.ts +55 -0
- package/src/utils/__tests__/target.spec.ts +221 -0
- package/src/utils/__tests__/typegen.spec.ts +115 -0
- package/src/utils/config.ts +50 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/misc.ts +351 -79
- package/src/utils/serialize.ts +47 -0
- package/src/utils/target.ts +150 -1
- package/src/utils/typegen.ts +608 -42
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { wasiLoaderSuffix } from '../../utils/index.js'
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
assertBindingTargetIdentFree,
|
|
5
|
+
BINDING_TARGET_STAMP_HELPER,
|
|
6
|
+
NAPI_BINDING_TARGET_EXPORT,
|
|
7
|
+
NAPI_BINDING_TARGET_STAMP_FN,
|
|
8
|
+
} from './binding-target.js'
|
|
9
|
+
|
|
3
10
|
function resolveWasiFlavors(wasiFlavors?: string[]): string[] {
|
|
4
11
|
return wasiFlavors && wasiFlavors.length > 0 ? wasiFlavors : ['wasm32-wasi']
|
|
5
12
|
}
|
|
@@ -43,11 +50,11 @@ function createWasiFallbackChain(
|
|
|
43
50
|
specifier,
|
|
44
51
|
isPackage,
|
|
45
52
|
localArtifacts,
|
|
46
|
-
}) => ` if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === ${
|
|
53
|
+
}) => ` if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === '${flavor}')) {
|
|
47
54
|
let candidateError = null
|
|
48
55
|
let candidateFailed = false
|
|
49
56
|
try {
|
|
50
|
-
candidateError = __napiWasiResolveCandidate('${specifier}', ${isPackage}, ${
|
|
57
|
+
candidateError = __napiWasiResolveCandidate('${specifier}', ${isPackage}, ${localArtifacts ? `[${localArtifacts.map((artifact) => `'${artifact}'`).join(', ')}]` : 'undefined'})
|
|
51
58
|
candidateFailed = candidateError !== null
|
|
52
59
|
if (!candidateFailed) {${
|
|
53
60
|
isPackage && packageVersion
|
|
@@ -62,6 +69,7 @@ function createWasiFallbackChain(
|
|
|
62
69
|
}
|
|
63
70
|
wasiBinding = require('${specifier}')
|
|
64
71
|
nativeBinding = wasiBinding
|
|
72
|
+
__napiLoadedBindingTarget = '${flavor}'
|
|
65
73
|
wasiBindingLoaded = true
|
|
66
74
|
}
|
|
67
75
|
} catch (err) {
|
|
@@ -126,6 +134,7 @@ export function createCjsBinding(
|
|
|
126
134
|
wasiFlavors?: string[],
|
|
127
135
|
localWasiName?: string,
|
|
128
136
|
): string {
|
|
137
|
+
assertBindingTargetIdentFree(idents)
|
|
129
138
|
return `${bindingHeader}
|
|
130
139
|
${createCommonBinding(
|
|
131
140
|
localName,
|
|
@@ -134,6 +143,23 @@ ${createCommonBinding(
|
|
|
134
143
|
wasiFlavors,
|
|
135
144
|
localWasiName,
|
|
136
145
|
)}
|
|
146
|
+
${BINDING_TARGET_STAMP_HELPER}
|
|
147
|
+
// Stamp before the alias, not after. The guard only reads \`nativeBinding\`
|
|
148
|
+
// (\`hasOwnProperty\` plus a comparison), which is safe against any addon
|
|
149
|
+
// accessor; an assignment is not, because a \`#[napi(module_exports)]\` hook can
|
|
150
|
+
// expose a getter reporting this very value and a setter that throws. So the
|
|
151
|
+
// assignment lands on the loader's own \`module.exports\`, still the original
|
|
152
|
+
// object here, and the alias below replaces it.
|
|
153
|
+
//
|
|
154
|
+
// The assignment is what keeps the marker a statically visible CommonJS export:
|
|
155
|
+
// \`cjs-module-lexer\` is Node's CJS -> ESM named export detection, it cannot see
|
|
156
|
+
// a bare call, and the later \`module.exports = nativeBinding\` does not undo the
|
|
157
|
+
// detection. The assignment itself always succeeds — its target is this
|
|
158
|
+
// loader's own, still extensible \`module.exports\` — and the alias below then
|
|
159
|
+
// discards the value it wrote. What a consumer reads is whatever the guard put
|
|
160
|
+
// on \`nativeBinding\`, so on a frozen binding, where the guard skips, the
|
|
161
|
+
// linked import resolves to \`undefined\`.
|
|
162
|
+
module.exports.${NAPI_BINDING_TARGET_EXPORT} = ${NAPI_BINDING_TARGET_STAMP_FN}(nativeBinding, __napiLoadedBindingTarget)
|
|
137
163
|
module.exports = nativeBinding
|
|
138
164
|
${idents
|
|
139
165
|
.map((ident) => `module.exports.${ident} = nativeBinding.${ident}`)
|
|
@@ -149,11 +175,17 @@ export function createEsmBinding(
|
|
|
149
175
|
wasiFlavors?: string[],
|
|
150
176
|
localWasiName?: string,
|
|
151
177
|
): string {
|
|
178
|
+
assertBindingTargetIdentFree(idents)
|
|
179
|
+
// Both branches must carry it, or a zero-ident package silently loses the
|
|
180
|
+
// export.
|
|
181
|
+
const bindingTargetExport = `export const ${NAPI_BINDING_TARGET_EXPORT} = __napiLoadedBindingTarget`
|
|
152
182
|
const exportsCode =
|
|
153
183
|
idents.length > 0
|
|
154
184
|
? `const { ${idents.join(', ')} } = nativeBinding
|
|
155
|
-
${idents.map((ident) => `export { ${ident} }`).join('\n')}
|
|
156
|
-
|
|
185
|
+
${idents.map((ident) => `export { ${ident} }`).join('\n')}
|
|
186
|
+
${bindingTargetExport}`
|
|
187
|
+
: `export default nativeBinding
|
|
188
|
+
${bindingTargetExport}`
|
|
157
189
|
return `${bindingHeader}
|
|
158
190
|
import { createRequire } from 'module'
|
|
159
191
|
const require = createRequire(import.meta.url)
|
|
@@ -169,8 +201,7 @@ ${exportsCode}
|
|
|
169
201
|
`
|
|
170
202
|
}
|
|
171
203
|
|
|
172
|
-
const bindingHeader =
|
|
173
|
-
/* eslint-disable */
|
|
204
|
+
const bindingHeader = `/* eslint-disable */
|
|
174
205
|
// @ts-nocheck
|
|
175
206
|
/* auto-generated by NAPI-RS */
|
|
176
207
|
`
|
|
@@ -214,6 +245,10 @@ ${identLow}}${versionCheck}`
|
|
|
214
245
|
|
|
215
246
|
return `const { readFileSync } = require('fs')
|
|
216
247
|
let nativeBinding = null
|
|
248
|
+
// Which artifact actually loaded. The WASI fallback chain overwrites it with
|
|
249
|
+
// the flavor it resolved; the late native retry below leaves it alone because
|
|
250
|
+
// it only runs while no WASI candidate has been loaded.
|
|
251
|
+
let __napiLoadedBindingTarget = 'native'
|
|
217
252
|
const loadErrors = []
|
|
218
253
|
|
|
219
254
|
const isMusl = () => {
|
|
@@ -272,7 +307,16 @@ const isMuslFromChildProcess = () => {
|
|
|
272
307
|
function requireNative() {
|
|
273
308
|
if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {
|
|
274
309
|
try {
|
|
275
|
-
|
|
310
|
+
const overrideBinding = require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH)
|
|
311
|
+
// The override may be a generated WASI loader, which already reports its
|
|
312
|
+
// own flavor. Adopt it: \`module.exports\` aliases this object, so claiming
|
|
313
|
+
// 'native' would both misreport the artifact and overwrite the loader's
|
|
314
|
+
// marker through the alias.
|
|
315
|
+
__napiLoadedBindingTarget =
|
|
316
|
+
overrideBinding && typeof overrideBinding.${NAPI_BINDING_TARGET_EXPORT} === 'string'
|
|
317
|
+
? overrideBinding.${NAPI_BINDING_TARGET_EXPORT}
|
|
318
|
+
: 'native'
|
|
319
|
+
return overrideBinding
|
|
276
320
|
} catch (err) {
|
|
277
321
|
loadErrors.push(err)
|
|
278
322
|
}
|
|
@@ -287,9 +331,9 @@ function requireNative() {
|
|
|
287
331
|
} else if (process.platform === 'win32') {
|
|
288
332
|
if (process.arch === 'x64') {
|
|
289
333
|
if ((process.config && process.config.variables && process.config.variables.shlib_suffix === 'dll.a') || (process.config && process.config.variables && process.config.variables.node_target_type === 'shared_library')) {
|
|
290
|
-
${requireTuple('win32-x64-gnu')}
|
|
334
|
+
${requireTuple('win32-x64-gnu', 10)}
|
|
291
335
|
} else {
|
|
292
|
-
${requireTuple('win32-x64-msvc')}
|
|
336
|
+
${requireTuple('win32-x64-msvc', 10)}
|
|
293
337
|
}
|
|
294
338
|
} else if (process.arch === 'ia32') {
|
|
295
339
|
${requireTuple('win32-ia32-msvc')}
|
|
@@ -395,7 +439,7 @@ function createLoadErrorChain(errors) {
|
|
|
395
439
|
//
|
|
396
440
|
// NAPI_RS_WASI_FLAVOR selects one exact generated flavor and implies strict
|
|
397
441
|
// WASI loading. It never crosses into another flavor or falls back to native.
|
|
398
|
-
const __napiWasiFlavors = ${
|
|
442
|
+
const __napiWasiFlavors = [${flavors.map((flavor) => `'${flavor}'`).join(', ')}]
|
|
399
443
|
const __napiWasiFlavor = process.env.NAPI_RS_WASI_FLAVOR
|
|
400
444
|
const __napiWasiFlavorRequested =
|
|
401
445
|
typeof __napiWasiFlavor === 'string' && __napiWasiFlavor.length > 0
|