@napi-rs/cli 3.0.0-alpha.7 → 3.0.0-alpha.71

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.
Files changed (160) hide show
  1. package/cli.mjs +1 -1
  2. package/dist/api/artifacts.js +28 -7
  3. package/dist/api/artifacts.js.map +1 -1
  4. package/dist/api/build.js +247 -47
  5. package/dist/api/build.js.map +1 -1
  6. package/dist/api/create-npm-dirs.js +46 -9
  7. package/dist/api/create-npm-dirs.js.map +1 -1
  8. package/dist/api/new.js +57 -20
  9. package/dist/api/new.js.map +1 -1
  10. package/dist/api/pre-publish.js +9 -7
  11. package/dist/api/pre-publish.js.map +1 -1
  12. package/dist/api/rename.js +9 -1
  13. package/dist/api/rename.js.map +1 -1
  14. package/dist/api/templates/cargo.toml.js +1 -0
  15. package/dist/api/templates/cargo.toml.js.map +1 -1
  16. package/dist/api/templates/ci-template.d.ts +3 -1
  17. package/dist/api/templates/ci-template.js +144 -131
  18. package/dist/api/templates/ci-template.js.map +1 -1
  19. package/dist/api/templates/ci.yml.d.ts +3 -1
  20. package/dist/api/templates/ci.yml.js +21 -5
  21. package/dist/api/templates/ci.yml.js.map +1 -1
  22. package/dist/api/templates/js-binding.d.ts +1 -0
  23. package/dist/api/templates/js-binding.js +135 -221
  24. package/dist/api/templates/js-binding.js.map +1 -1
  25. package/dist/api/templates/lib.rs.js +1 -4
  26. package/dist/api/templates/lib.rs.js.map +1 -1
  27. package/dist/api/templates/load-wasi-template.d.ts +2 -0
  28. package/dist/api/templates/load-wasi-template.js +166 -0
  29. package/dist/api/templates/load-wasi-template.js.map +1 -0
  30. package/dist/api/templates/package.json.d.ts +9 -2
  31. package/dist/api/templates/package.json.js +26 -4
  32. package/dist/api/templates/package.json.js.map +1 -1
  33. package/dist/api/templates/wasi-worker-template.d.ts +2 -0
  34. package/dist/api/templates/wasi-worker-template.js +122 -0
  35. package/dist/api/templates/wasi-worker-template.js.map +1 -0
  36. package/dist/api/universalize.js +5 -5
  37. package/dist/api/universalize.js.map +1 -1
  38. package/dist/api/version.js +2 -2
  39. package/dist/api/version.js.map +1 -1
  40. package/dist/commands/artifacts.js +2 -2
  41. package/dist/commands/artifacts.js.map +1 -1
  42. package/dist/commands/build.js +1 -1
  43. package/dist/commands/build.js.map +1 -1
  44. package/dist/commands/new.js +34 -34
  45. package/dist/commands/new.js.map +1 -1
  46. package/dist/def/artifacts.d.ts +21 -1
  47. package/dist/def/artifacts.js +10 -2
  48. package/dist/def/artifacts.js.map +1 -1
  49. package/dist/def/build.d.ts +155 -4
  50. package/dist/def/build.js +30 -4
  51. package/dist/def/build.js.map +1 -1
  52. package/dist/def/create-npm-dirs.d.ts +10 -0
  53. package/dist/def/create-npm-dirs.js +4 -0
  54. package/dist/def/create-npm-dirs.js.map +1 -1
  55. package/dist/def/new.d.ts +25 -7
  56. package/dist/def/new.js +11 -1
  57. package/dist/def/new.js.map +1 -1
  58. package/dist/def/pre-publish.d.ts +12 -2
  59. package/dist/def/pre-publish.js +7 -3
  60. package/dist/def/pre-publish.js.map +1 -1
  61. package/dist/def/rename.d.ts +16 -6
  62. package/dist/def/rename.js +5 -1
  63. package/dist/def/rename.js.map +1 -1
  64. package/dist/def/universalize.d.ts +10 -0
  65. package/dist/def/universalize.js +4 -0
  66. package/dist/def/universalize.js.map +1 -1
  67. package/dist/def/version.d.ts +10 -0
  68. package/dist/def/version.js +4 -0
  69. package/dist/def/version.js.map +1 -1
  70. package/dist/index.cjs +8146 -14672
  71. package/dist/index.d.ts +1 -0
  72. package/dist/index.js +1 -0
  73. package/dist/index.js.map +1 -1
  74. package/dist/utils/__tests__/config.spec.d.ts +1 -0
  75. package/dist/utils/__tests__/config.spec.js +63 -0
  76. package/dist/utils/__tests__/config.spec.js.map +1 -0
  77. package/dist/utils/__tests__/typegen.spec.js +8 -4
  78. package/dist/utils/__tests__/typegen.spec.js.map +1 -1
  79. package/dist/utils/cargo.js +2 -2
  80. package/dist/utils/cargo.js.map +1 -1
  81. package/dist/utils/config.d.ts +48 -4
  82. package/dist/utils/config.js +37 -5
  83. package/dist/utils/config.js.map +1 -1
  84. package/dist/utils/index.d.ts +0 -1
  85. package/dist/utils/index.js +0 -1
  86. package/dist/utils/index.js.map +1 -1
  87. package/dist/utils/metadata.js +2 -2
  88. package/dist/utils/metadata.js.map +1 -1
  89. package/dist/utils/misc.d.ts +1 -2
  90. package/dist/utils/misc.js +3 -3
  91. package/dist/utils/misc.js.map +1 -1
  92. package/dist/utils/target.d.ts +7 -5
  93. package/dist/utils/target.js +17 -3
  94. package/dist/utils/target.js.map +1 -1
  95. package/dist/utils/typegen.d.ts +1 -1
  96. package/dist/utils/typegen.js +51 -17
  97. package/dist/utils/typegen.js.map +1 -1
  98. package/dist/utils/version.d.ts +2 -1
  99. package/dist/utils/version.js +10 -8
  100. package/dist/utils/version.js.map +1 -1
  101. package/package.json +27 -26
  102. package/src/api/artifacts.ts +81 -9
  103. package/src/api/build.ts +403 -66
  104. package/src/api/create-npm-dirs.ts +57 -9
  105. package/src/api/new.ts +89 -31
  106. package/src/api/pre-publish.ts +13 -7
  107. package/src/api/rename.ts +10 -1
  108. package/src/api/templates/cargo.toml.ts +1 -0
  109. package/src/api/templates/ci-template.ts +154 -131
  110. package/src/api/templates/ci.yml.ts +27 -6
  111. package/src/api/templates/js-binding.ts +141 -219
  112. package/src/api/templates/lib.rs.ts +1 -4
  113. package/src/api/templates/load-wasi-template.ts +180 -0
  114. package/src/api/templates/package.json.ts +47 -5
  115. package/src/api/templates/wasi-worker-template.ts +122 -0
  116. package/src/api/universalize.ts +13 -8
  117. package/src/api/version.ts +5 -2
  118. package/src/commands/artifacts.ts +2 -2
  119. package/src/commands/build.ts +1 -1
  120. package/src/commands/new.ts +46 -45
  121. package/src/def/artifacts.ts +22 -3
  122. package/src/def/build.ts +64 -8
  123. package/src/def/create-npm-dirs.ts +9 -0
  124. package/src/def/new.ts +28 -3
  125. package/src/def/pre-publish.ts +12 -3
  126. package/src/def/rename.ts +11 -2
  127. package/src/def/universalize.ts +9 -0
  128. package/src/def/version.ts +9 -0
  129. package/src/index.ts +2 -0
  130. package/src/utils/__tests__/__fixtures__/napi_type_def +130 -130
  131. package/src/utils/__tests__/__snapshots__/config.spec.ts.md +97 -0
  132. package/src/utils/__tests__/__snapshots__/config.spec.ts.snap +0 -0
  133. package/src/utils/__tests__/__snapshots__/target.spec.ts.md +28 -0
  134. package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
  135. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +711 -158
  136. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
  137. package/src/utils/__tests__/__snapshots__/version.spec.ts.md +8 -7
  138. package/src/utils/__tests__/__snapshots__/version.spec.ts.snap +0 -0
  139. package/src/utils/__tests__/config.spec.ts +81 -0
  140. package/src/utils/__tests__/typegen.spec.ts +18 -3
  141. package/src/utils/cargo.ts +2 -2
  142. package/src/utils/config.ts +112 -10
  143. package/src/utils/index.ts +0 -1
  144. package/src/utils/metadata.ts +2 -2
  145. package/src/utils/misc.ts +11 -3
  146. package/src/utils/target.ts +22 -4
  147. package/src/utils/typegen.ts +81 -36
  148. package/src/utils/version.ts +10 -8
  149. package/dist/api/load-wasi-template.d.ts +0 -1
  150. package/dist/api/load-wasi-template.js +0 -63
  151. package/dist/api/load-wasi-template.js.map +0 -1
  152. package/dist/api/wasi-worker-template.d.ts +0 -1
  153. package/dist/api/wasi-worker-template.js +0 -53
  154. package/dist/api/wasi-worker-template.js.map +0 -1
  155. package/dist/utils/ci.d.ts +0 -11
  156. package/dist/utils/ci.js +0 -96
  157. package/dist/utils/ci.js.map +0 -1
  158. package/src/api/load-wasi-template.ts +0 -65
  159. package/src/api/wasi-worker-template.ts +0 -52
  160. package/src/utils/ci.ts +0 -111
package/src/api/build.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import { spawn } from 'node:child_process'
2
2
  import { createHash } from 'node:crypto'
3
+ import { existsSync, mkdirSync, unlinkSync } from 'node:fs'
3
4
  import { createRequire } from 'node:module'
4
- import { tmpdir } from 'node:os'
5
+ import { tmpdir, homedir } from 'node:os'
5
6
  import { parse, join, resolve } from 'node:path'
6
7
 
7
8
  import * as colors from 'colorette'
9
+ import { include as setjmpInclude, lib as setjmpLib } from 'wasm-sjlj'
8
10
 
9
11
  import { BuildOptions as RawBuildOptions } from '../def/build.js'
10
12
  import {
@@ -30,9 +32,15 @@ import {
30
32
  writeFileAsync,
31
33
  } from '../utils/index.js'
32
34
 
33
- import { createWasiBinding } from './load-wasi-template.js'
34
- import { createCjsBinding } from './templates/index.js'
35
- import { WASI_WORKER_TEMPLATE } from './wasi-worker-template.js'
35
+ import { createCjsBinding, createEsmBinding } from './templates/index.js'
36
+ import {
37
+ createWasiBinding,
38
+ createWasiBrowserBinding,
39
+ } from './templates/load-wasi-template.js'
40
+ import {
41
+ createWasiBrowserWorkerBinding,
42
+ WASI_WORKER_TEMPLATE,
43
+ } from './templates/wasi-worker-template.js'
36
44
 
37
45
  const debug = debugFactory('build')
38
46
  const require = createRequire(import.meta.url)
@@ -50,6 +58,11 @@ type BuildOptions = RawBuildOptions & {
50
58
  export async function buildProject(options: BuildOptions) {
51
59
  debug('napi build command receive options: %O', options)
52
60
 
61
+ options = {
62
+ dtsCache: true,
63
+ ...options,
64
+ }
65
+
53
66
  const cwd = options.cwd ?? process.cwd()
54
67
 
55
68
  const resolvePath = (...paths: string[]) => resolve(cwd, ...paths)
@@ -81,15 +94,18 @@ export async function buildProject(options: BuildOptions) {
81
94
  options.target
82
95
  ? parseTriple(options.target)
83
96
  : process.env.CARGO_BUILD_TARGET
84
- ? parseTriple(process.env.CARGO_BUILD_TARGET)
85
- : getSystemDefaultTarget(),
97
+ ? parseTriple(process.env.CARGO_BUILD_TARGET)
98
+ : getSystemDefaultTarget(),
86
99
  crateDir,
87
100
  resolvePath(options.outputDir ?? crateDir),
88
101
  options.targetDir ??
89
102
  process.env.CARGO_BUILD_TARGET_DIR ??
90
103
  metadata.target_directory,
91
104
  await readNapiConfig(
92
- resolvePath(options.packageJsonPath ?? 'package.json'),
105
+ resolvePath(
106
+ options.configPath ?? options.packageJsonPath ?? 'package.json',
107
+ ),
108
+ options.configPath ? resolvePath(options.configPath) : undefined,
93
109
  ),
94
110
  )
95
111
 
@@ -143,11 +159,138 @@ class Builder {
143
159
  .setPackage()
144
160
  .setFeatures()
145
161
  .setTarget()
162
+ .pickCrossToolchain()
146
163
  .setEnvs()
147
164
  .setBypassArgs()
148
165
  .exec()
149
166
  }
150
167
 
168
+ private pickCrossToolchain() {
169
+ if (!this.options.useNapiCross) {
170
+ return this
171
+ }
172
+ if (this.options.useCross) {
173
+ debug.warn(
174
+ 'You are trying to use both `--cross` and `--use-napi-cross` options, `--use-cross` will be ignored.',
175
+ )
176
+ }
177
+
178
+ if (this.options.crossCompile) {
179
+ debug.warn(
180
+ 'You are trying to use both `--cross-compile` and `--use-napi-cross` options, `--cross-compile` will be ignored.',
181
+ )
182
+ }
183
+
184
+ try {
185
+ const { version, download } = require('@napi-rs/cross-toolchain')
186
+
187
+ const alias: Record<string, string> = {
188
+ 's390x-unknown-linux-gnu': 's390x-ibm-linux-gnu',
189
+ }
190
+
191
+ const toolchainPath = join(
192
+ homedir(),
193
+ '.napi-rs',
194
+ 'cross-toolchain',
195
+ version,
196
+ this.target.triple,
197
+ )
198
+ mkdirSync(toolchainPath, { recursive: true })
199
+ if (existsSync(join(toolchainPath, 'package.json'))) {
200
+ debug(`Toolchain ${toolchainPath} exists, skip extracting`)
201
+ } else {
202
+ const tarArchive = download(process.arch, this.target.triple)
203
+ tarArchive.unpack(toolchainPath)
204
+ }
205
+ const upperCaseTarget = targetToEnvVar(this.target.triple)
206
+ const crossTargetName = alias[this.target.triple] ?? this.target.triple
207
+ const linkerEnv = `CARGO_TARGET_${upperCaseTarget}_LINKER`
208
+ this.envs[linkerEnv] = join(
209
+ toolchainPath,
210
+ 'bin',
211
+ `${crossTargetName}-gcc`,
212
+ )
213
+ if (!process.env.TARGET_SYSROOT) {
214
+ this.envs[`TARGET_SYSROOT`] = join(
215
+ toolchainPath,
216
+ crossTargetName,
217
+ 'sysroot',
218
+ )
219
+ }
220
+ if (!process.env.TARGET_AR) {
221
+ this.envs[`TARGET_AR`] = join(
222
+ toolchainPath,
223
+ 'bin',
224
+ `${crossTargetName}-ar`,
225
+ )
226
+ }
227
+ if (!process.env.TARGET_RANLIB) {
228
+ this.envs[`TARGET_RANLIB`] = join(
229
+ toolchainPath,
230
+ 'bin',
231
+ `${crossTargetName}-ranlib`,
232
+ )
233
+ }
234
+ if (!process.env.TARGET_READELF) {
235
+ this.envs[`TARGET_READELF`] = join(
236
+ toolchainPath,
237
+ 'bin',
238
+ `${crossTargetName}-readelf`,
239
+ )
240
+ }
241
+ if (!process.env.TARGET_C_INCLUDE_PATH) {
242
+ this.envs[`TARGET_C_INCLUDE_PATH`] = join(
243
+ toolchainPath,
244
+ crossTargetName,
245
+ 'sysroot',
246
+ 'usr',
247
+ 'include/',
248
+ )
249
+ }
250
+ if (!process.env.CC && !process.env.TARGET_CC) {
251
+ this.envs[`CC`] = join(toolchainPath, 'bin', `${crossTargetName}-gcc`)
252
+ this.envs[`TARGET_CC`] = join(
253
+ toolchainPath,
254
+ 'bin',
255
+ `${crossTargetName}-gcc`,
256
+ )
257
+ }
258
+ if (!process.env.CXX && !process.env.TARGET_CXX) {
259
+ this.envs[`CXX`] = join(
260
+ toolchainPath,
261
+ 'bin',
262
+ `${this.target.triple}-g++`,
263
+ )
264
+ this.envs[`TARGET_CXX`] = join(
265
+ toolchainPath,
266
+ 'bin',
267
+ `${this.target.triple}-g++`,
268
+ )
269
+ }
270
+ if (
271
+ (process.env.CC === 'clang' &&
272
+ (process.env.TARGET_CC === 'clang' || !process.env.TARGET_CC)) ||
273
+ process.env.TARGET_CC === 'clang'
274
+ ) {
275
+ this.envs.CFLAGS = `--sysroot=${this.envs.TARGET_SYSROOT} --gcc-toolchain=${toolchainPath}`
276
+ }
277
+ if (
278
+ (process.env.CXX === 'clang++' &&
279
+ (process.env.TARGET_CXX === 'clang++' || !process.env.TARGET_CXX)) ||
280
+ process.env.TARGET_CXX === 'clang++'
281
+ ) {
282
+ this.envs.CXXFLAGS = `--sysroot=${this.envs.TARGET_SYSROOT} --gcc-toolchain=${toolchainPath}`
283
+ }
284
+ this.envs.PATH = this.envs.PATH
285
+ ? `${toolchainPath}/bin:${this.envs.PATH}:${process.env.PATH}`
286
+ : `${toolchainPath}/bin:${process.env.PATH}`
287
+ } catch (e) {
288
+ debug.warn('Pick cross toolchain failed', e as Error)
289
+ // ignore, do nothing
290
+ }
291
+ return this
292
+ }
293
+
151
294
  private exec() {
152
295
  debug(`Start building crate: ${this.crate.name}`)
153
296
  debug(' %i', `cargo ${this.args.join(' ')}`)
@@ -156,6 +299,11 @@ class Builder {
156
299
 
157
300
  const watch = this.options.watch
158
301
  const buildTask = new Promise<void>((resolve, reject) => {
302
+ if (this.options.useCross && this.options.crossCompile) {
303
+ throw new Error(
304
+ '`--use-cross` and `--cross-compile` can not be used together',
305
+ )
306
+ }
159
307
  const command =
160
308
  process.env.CARGO ?? (this.options.useCross ? 'cross' : 'cargo')
161
309
  const buildProcess = spawn(command, this.args, {
@@ -189,7 +337,7 @@ class Builder {
189
337
  buildProcess.stderr?.on('data', (data) => {
190
338
  const output = data.toString()
191
339
  console.error(output)
192
- if (/Finished\s(dev|release)/.test(output)) {
340
+ if (/Finished\s(`dev`|`release`)/.test(output)) {
193
341
  this.postBuild().catch(() => {})
194
342
  }
195
343
  })
@@ -352,7 +500,7 @@ class Builder {
352
500
  const linkerEnv = `CARGO_TARGET_${targetToEnvVar(
353
501
  this.target.triple,
354
502
  )}_LINKER`
355
- if (linker && !process.env[linkerEnv]) {
503
+ if (linker && !process.env[linkerEnv] && !this.envs[linkerEnv]) {
356
504
  this.envs[linkerEnv] = linker
357
505
  }
358
506
 
@@ -373,15 +521,15 @@ class Builder {
373
521
  process.platform === 'darwin'
374
522
  ? 'darwin'
375
523
  : process.platform === 'win32'
376
- ? 'windows'
377
- : 'linux'
524
+ ? 'windows'
525
+ : 'linux'
378
526
  Object.assign(this.envs, {
379
527
  CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-android24-clang`,
380
528
  CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-androideabi24-clang`,
381
- CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
382
- CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
383
- AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ar`,
384
- RANLIB: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ranlib`,
529
+ TARGET_CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
530
+ TARGET_CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
531
+ TARGET_AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ar`,
532
+ TARGET_RANLIB: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ranlib`,
385
533
  ANDROID_NDK: ANDROID_NDK_LATEST_HOME,
386
534
  PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin:${process.env.PATH}`,
387
535
  })
@@ -396,6 +544,47 @@ class Builder {
396
544
  'wasm32-wasi-threads',
397
545
  )
398
546
  this.envs.EMNAPI_LINK_DIR = emnapi
547
+ this.envs.SETJMP_LINK_DIR = setjmpLib
548
+ const { WASI_SDK_PATH } = process.env
549
+
550
+ if (WASI_SDK_PATH && existsSync(WASI_SDK_PATH)) {
551
+ this.envs.CARGO_TARGET_WASM32_WASI_PREVIEW1_THREADS_LINKER = join(
552
+ WASI_SDK_PATH,
553
+ 'bin',
554
+ 'wasm-ld',
555
+ )
556
+ this.envs.CARGO_TARGET_WASM32_WASIP1_LINKER = join(
557
+ WASI_SDK_PATH,
558
+ 'bin',
559
+ 'wasm-ld',
560
+ )
561
+ this.envs.CARGO_TARGET_WASM32_WASIP1_THREADS_LINKER = join(
562
+ WASI_SDK_PATH,
563
+ 'bin',
564
+ 'wasm-ld',
565
+ )
566
+ this.envs.CARGO_TARGET_WASM32_WASIP2_LINKER = join(
567
+ WASI_SDK_PATH,
568
+ 'bin',
569
+ 'wasm-ld',
570
+ )
571
+ this.setEnvIfNotExists('CC', join(WASI_SDK_PATH, 'bin', 'clang'))
572
+ this.setEnvIfNotExists('CXX', join(WASI_SDK_PATH, 'bin', 'clang++'))
573
+ this.setEnvIfNotExists('AR', join(WASI_SDK_PATH, 'bin', 'ar'))
574
+ this.setEnvIfNotExists('RANLIB', join(WASI_SDK_PATH, 'bin', 'ranlib'))
575
+ this.setEnvIfNotExists(
576
+ 'CFLAGS',
577
+ `--target=wasm32-wasi-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj -I${setjmpInclude}`,
578
+ )
579
+ this.setEnvIfNotExists(
580
+ 'CXXFLAGS',
581
+ `--target=wasm32-wasi-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj -I${setjmpInclude}`,
582
+ )
583
+ this.setEnvIfNotExists(
584
+ `LDFLAGS`,
585
+ `-fuse-ld=${WASI_SDK_PATH}/bin/wasm-ld --target=wasm32-wasi-threads`,
586
+ )
587
+ }
399
588
  }
400
589
 
401
590
  debug('Set envs: ')
@@ -408,11 +597,17 @@ class Builder {
408
597
 
409
598
  private setFeatures() {
410
599
  const args = []
600
+ if (this.options.allFeatures && this.options.noDefaultFeatures) {
601
+ throw new Error(
602
+ 'Cannot specify --all-features and --no-default-features together',
603
+ )
604
+ }
411
605
  if (this.options.allFeatures) {
412
606
  args.push('--all-features')
413
607
  } else if (this.options.noDefaultFeatures) {
414
608
  args.push('--no-default-features')
415
- } else if (this.options.features) {
609
+ }
610
+ if (this.options.features) {
416
611
  args.push('--features', ...this.options.features)
417
612
  }
418
613
 
@@ -440,6 +635,10 @@ class Builder {
440
635
  this.args.push('--profile', this.options.profile)
441
636
  }
442
637
 
638
+ if (this.options.manifestPath) {
639
+ this.args.push('--manifest-path', this.options.manifestPath)
640
+ }
641
+
443
642
  if (this.options.cargoOptions?.length) {
444
643
  this.args.push(...this.options.cargoOptions)
445
644
  }
@@ -448,14 +647,21 @@ class Builder {
448
647
  }
449
648
 
450
649
  private getIntermediateTypeFile() {
451
- return join(
650
+ const dtsPath = join(
452
651
  tmpdir(),
453
652
  `${this.crate.name}-${createHash('sha256')
454
653
  .update(this.crate.manifest_path)
455
654
  .update(CLI_VERSION)
456
655
  .digest('hex')
457
- .substring(0, 8)}.napi_type_def.tmp`,
656
+ .substring(0, 8)}.napi_type_def`,
458
657
  )
658
+ if (!this.options.dtsCache) {
659
+ try {
660
+ unlinkSync(dtsPath)
661
+ } catch {}
662
+ return `${dtsPath}_${Date.now()}.tmp`
663
+ }
664
+ return `${dtsPath}.tmp`
459
665
  }
460
666
 
461
667
  private getIntermediateWasiRegisterFile() {
@@ -481,38 +687,48 @@ class Builder {
481
687
  })
482
688
  }
483
689
 
484
- const dest = await this.copyArtifact()
690
+ const wasmBinaryName = await this.copyArtifact()
485
691
 
486
692
  // only for cdylib
487
693
  if (this.cdyLibName) {
488
694
  const idents = await this.generateTypeDef()
489
695
  const intermediateWasiRegisterFile = this.envs.WASI_REGISTER_TMP_PATH
490
- const wasiRegisterFunctions =
491
- this.target.arch === 'wasm32'
492
- ? JSON.parse(
493
- await readFileAsync(intermediateWasiRegisterFile, 'utf8').catch(
494
- (err) => {
495
- console.warn(
496
- `Read ${colors.yellowBright(
497
- intermediateWasiRegisterFile,
498
- )} failed, reason: ${err.message}`,
499
- )
500
- return `[]`
501
- },
502
- ),
503
- )
504
- : []
696
+ const wasiRegisterFunctions = this.config.targets.some(
697
+ (t) => t.platform === 'wasi',
698
+ )
699
+ ? await (async function readIntermediateWasiRegisterFile() {
700
+ const fileContent = await readFileAsync(
701
+ intermediateWasiRegisterFile,
702
+ 'utf8',
703
+ ).catch((err) => {
704
+ console.warn(
705
+ `Read ${colors.yellowBright(
706
+ intermediateWasiRegisterFile,
707
+ )} failed, reason: ${err.message}`,
708
+ )
709
+ return ``
710
+ })
711
+ return fileContent
712
+ .split('\n')
713
+ .map((l) => l.trim())
714
+ .filter((l) => l.length)
715
+ .map((line) => {
716
+ const [_, fn] = line.split(':')
717
+ return fn.trim()
718
+ })
719
+ })()
720
+ : []
505
721
  const jsOutput = await this.writeJsBinding(idents)
506
- const wasmOutput = await this.writeWasiBinding(
722
+ const wasmBindingsOutput = await this.writeWasiBinding(
507
723
  wasiRegisterFunctions,
508
- dest ?? 'index.wasm',
724
+ wasmBinaryName ?? 'index.wasm',
509
725
  idents,
510
726
  )
511
727
  if (jsOutput) {
512
728
  this.outputs.push(jsOutput)
513
729
  }
514
- if (wasmOutput) {
515
- this.outputs.push(wasmOutput)
730
+ if (wasmBindingsOutput) {
731
+ this.outputs.push(...wasmBindingsOutput)
516
732
  }
517
733
  }
518
734
 
@@ -520,7 +736,7 @@ class Builder {
520
736
  }
521
737
 
522
738
  private async copyArtifact() {
523
- const [srcName, destName] = this.getArtifactNames()
739
+ const [srcName, destName, wasmBinaryName] = this.getArtifactNames()
524
740
  if (!srcName || !destName) {
525
741
  return
526
742
  }
@@ -530,6 +746,7 @@ class Builder {
530
746
  const src = join(this.targetDir, this.target.triple, profile, srcName)
531
747
  debug(`Copy artifact from: [${src}]`)
532
748
  const dest = join(this.outputDir, destName)
749
+ const isWasm = dest.endsWith('.wasm')
533
750
 
534
751
  try {
535
752
  if (await fileExists(dest)) {
@@ -538,12 +755,47 @@ class Builder {
538
755
  }
539
756
  debug('Copy artifact to:')
540
757
  debug(' %i', dest)
541
- await copyFileAsync(src, dest)
758
+ if (isWasm) {
759
+ const { ModuleConfig } = await import('@napi-rs/wasm-tools')
760
+ debug('Generate debug wasm module')
761
+ try {
762
+ const debugWasmModule = new ModuleConfig()
763
+ .generateDwarf(true)
764
+ .generateNameSection(true)
765
+ .generateProducersSection(true)
766
+ .preserveCodeTransform(true)
767
+ .strictValidate(false)
768
+ .parse(await readFileAsync(src))
769
+ const debugWasmBinary = debugWasmModule.emitWasm(true)
770
+ await writeFileAsync(
771
+ dest.replace('.wasm', '.debug.wasm'),
772
+ debugWasmBinary,
773
+ )
774
+ debug('Generate release wasm module')
775
+ const releaseWasmModule = new ModuleConfig()
776
+ .generateDwarf(false)
777
+ .generateNameSection(false)
778
+ .generateProducersSection(false)
779
+ .preserveCodeTransform(false)
780
+ .strictValidate(false)
781
+ .onlyStableFeatures(false)
782
+ .parse(debugWasmBinary)
783
+ const releaseWasmBinary = releaseWasmModule.emitWasm(false)
784
+ await writeFileAsync(dest, releaseWasmBinary)
785
+ } catch (e) {
786
+ debug.warn(
787
+ `Failed to generate debug wasm module: ${(e as any).message ?? e}`,
788
+ )
789
+ await copyFileAsync(src, dest)
790
+ }
791
+ } else {
792
+ await copyFileAsync(src, dest)
793
+ }
542
794
  this.outputs.push({
543
- kind: dest.endsWith('.node') ? 'node' : 'exe',
795
+ kind: dest.endsWith('.node') ? 'node' : isWasm ? 'wasm' : 'exe',
544
796
  path: dest,
545
797
  })
546
- return dest
798
+ return wasmBinaryName ? join(this.outputDir, wasmBinaryName) : null
547
799
  } catch (e) {
548
800
  throw new Error('Failed to copy artifact', {
549
801
  cause: e,
@@ -554,15 +806,16 @@ class Builder {
554
806
  private getArtifactNames() {
555
807
  if (this.cdyLibName) {
556
808
  const cdyLib = this.cdyLibName.replace(/-/g, '_')
809
+ const wasiTarget = this.config.targets.find((t) => t.platform === 'wasi')
557
810
 
558
811
  const srcName =
559
812
  this.target.platform === 'darwin'
560
813
  ? `lib${cdyLib}.dylib`
561
814
  : this.target.platform === 'win32'
562
- ? `${cdyLib}.dll`
563
- : this.target.platform === 'wasi' || this.target.platform === 'wasm'
564
- ? `${cdyLib}.wasm`
565
- : `lib${cdyLib}.so`
815
+ ? `${cdyLib}.dll`
816
+ : this.target.platform === 'wasi' || this.target.platform === 'wasm'
817
+ ? `${cdyLib}.wasm`
818
+ : `lib${cdyLib}.so`
566
819
 
567
820
  let destName = this.config.binaryName
568
821
  // add platform suffix to binary name
@@ -572,12 +825,18 @@ class Builder {
572
825
  destName += `.${this.target.platformArchABI}`
573
826
  }
574
827
  if (srcName.endsWith('.wasm')) {
575
- destName += '.wasi-wasm32.wasm'
828
+ destName += '.wasm'
576
829
  } else {
577
830
  destName += '.node'
578
831
  }
579
832
 
580
- return [srcName, destName]
833
+ return [
834
+ srcName,
835
+ destName,
836
+ wasiTarget
837
+ ? `${this.config.binaryName}.${wasiTarget.platformArchABI}.wasm`
838
+ : null,
839
+ ]
581
840
  } else if (this.binName) {
582
841
  const srcName =
583
842
  this.target.platform === 'win32' ? `${this.binName}.exe` : this.binName
@@ -597,8 +856,22 @@ class Builder {
597
856
 
598
857
  const { dts, exports } = await processTypeDef(
599
858
  this.envs.TYPE_DEF_TMP_PATH,
859
+ this.options.constEnum ?? this.config.constEnum ?? true,
600
860
  !this.options.noDtsHeader
601
- ? this.options.dtsHeader ?? DEFAULT_TYPE_DEF_HEADER
861
+ ? (this.options.dtsHeader ??
862
+ (this.config.dtsHeaderFile
863
+ ? await readFileAsync(
864
+ join(this.cwd, this.config.dtsHeaderFile),
865
+ 'utf-8',
866
+ ).catch(() => {
867
+ debug.warn(
868
+ `Failed to read dts header file ${this.config.dtsHeaderFile}`,
869
+ )
870
+ return null
871
+ })
872
+ : null) ??
873
+ this.config.dtsHeader ??
874
+ DEFAULT_TYPE_DEF_HEADER)
602
875
  : '',
603
876
  )
604
877
 
@@ -628,19 +901,20 @@ class Builder {
628
901
  return
629
902
  }
630
903
 
631
- const name = parse(this.options.jsBinding ?? 'index.js').name
904
+ const name = this.options.jsBinding ?? 'index.js'
632
905
 
633
- const cjs = createCjsBinding(
906
+ const createBinding = this.options.esm ? createEsmBinding : createCjsBinding
907
+ const binding = createBinding(
634
908
  this.config.binaryName,
635
909
  this.config.packageName,
636
910
  idents,
637
911
  )
638
912
 
639
913
  try {
640
- const dest = join(this.outputDir, `${name}.js`)
914
+ const dest = join(this.outputDir, name)
641
915
  debug('Writing js binding to:')
642
916
  debug(' %i', dest)
643
- await writeFileAsync(dest, cjs, 'utf-8')
917
+ await writeFileAsync(dest, binding, 'utf-8')
644
918
  return {
645
919
  kind: 'js',
646
920
  path: dest,
@@ -657,26 +931,89 @@ class Builder {
657
931
  ) {
658
932
  if (distFileName && wasiRegisterFunctions.length) {
659
933
  const { name, dir } = parse(distFileName)
660
- const newPath = join(dir, `${this.config.binaryName}.wasi.mjs`)
934
+ const bindingPath = join(dir, `${this.config.binaryName}.wasi.cjs`)
935
+ const browserBindingPath = join(
936
+ dir,
937
+ `${this.config.binaryName}.wasi-browser.js`,
938
+ )
661
939
  const workerPath = join(dir, 'wasi-worker.mjs')
662
- const declareCodes = `const { ${idents.join(', ')} } = binding\n`
663
- const exportsCode = `export {\n${idents
664
- .map((ident) => ` ${ident}`)
665
- .join(',\n')}\n}`
940
+ const browserWorkerPath = join(dir, 'wasi-worker-browser.mjs')
941
+ const browserEntryPath = join(dir, 'browser.js')
942
+ const exportsCode = idents
943
+ .map(
944
+ (ident) => `module.exports.${ident} = __napiModule.exports.${ident}`,
945
+ )
946
+ .join('\n')
666
947
  await writeFileAsync(
667
- newPath,
668
- createWasiBinding(name, wasiRegisterFunctions) +
669
- declareCodes +
948
+ bindingPath,
949
+ createWasiBinding(
950
+ name,
951
+ this.config.packageName,
952
+ wasiRegisterFunctions,
953
+ this.config.wasm?.initialMemory,
954
+ this.config.wasm?.maximumMemory,
955
+ ) +
670
956
  exportsCode +
671
957
  '\n',
672
958
  'utf8',
673
959
  )
960
+ await writeFileAsync(
961
+ browserBindingPath,
962
+ createWasiBrowserBinding(
963
+ name,
964
+ wasiRegisterFunctions,
965
+ this.config.wasm?.initialMemory,
966
+ this.config.wasm?.maximumMemory,
967
+ this.config.wasm?.browser?.fs,
968
+ ) +
969
+ idents
970
+ .map(
971
+ (ident) =>
972
+ `export const ${ident} = __napiModule.exports.${ident}`,
973
+ )
974
+ .join('\n') +
975
+ '\n',
976
+ 'utf8',
977
+ )
674
978
  await writeFileAsync(workerPath, WASI_WORKER_TEMPLATE, 'utf8')
675
- return {
676
- kind: 'wasm',
677
- path: newPath,
678
- } satisfies Output
979
+ await writeFileAsync(
980
+ browserWorkerPath,
981
+ createWasiBrowserWorkerBinding(this.config.wasm?.browser?.fs ?? false),
982
+ 'utf8',
983
+ )
984
+ await writeFileAsync(
985
+ browserEntryPath,
986
+ `export * from '${this.config.packageName}-wasm32-wasi'\n`,
987
+ )
988
+ return [
989
+ {
990
+ kind: 'js',
991
+ path: bindingPath,
992
+ },
993
+ {
994
+ kind: 'js',
995
+ path: browserBindingPath,
996
+ },
997
+ {
998
+ kind: 'js',
999
+ path: workerPath,
1000
+ },
1001
+ {
1002
+ kind: 'js',
1003
+ path: browserWorkerPath,
1004
+ },
1005
+ {
1006
+ kind: 'js',
1007
+ path: browserEntryPath,
1008
+ },
1009
+ ] satisfies Output[]
1010
+ }
1011
+ return []
1012
+ }
1013
+
1014
+ private setEnvIfNotExists(env: string, value: string) {
1015
+ if (!process.env[env]) {
1016
+ this.envs[env] = value
679
1017
  }
680
- return null
681
1018
  }
682
1019
  }