@napi-rs/cli 3.0.0-alpha.3 → 3.0.0-alpha.31

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 (209) hide show
  1. package/dist/api/artifacts.js +29 -7
  2. package/dist/api/artifacts.js.map +1 -0
  3. package/dist/api/build.d.ts +1 -1
  4. package/dist/api/build.js +206 -32
  5. package/dist/api/build.js.map +1 -0
  6. package/dist/api/create-npm-dirs.js +50 -8
  7. package/dist/api/create-npm-dirs.js.map +1 -0
  8. package/dist/api/new.js +47 -20
  9. package/dist/api/new.js.map +1 -0
  10. package/dist/api/pre-publish.js +10 -7
  11. package/dist/api/pre-publish.js.map +1 -0
  12. package/dist/api/rename.js +10 -1
  13. package/dist/api/rename.js.map +1 -0
  14. package/dist/api/templates/.gitignore.d.ts +1 -1
  15. package/dist/api/templates/.gitignore.js +2 -0
  16. package/dist/api/templates/.gitignore.js.map +1 -0
  17. package/dist/api/templates/.npmignore.js +1 -0
  18. package/dist/api/templates/.npmignore.js.map +1 -0
  19. package/dist/api/templates/build.rs.js +1 -0
  20. package/dist/api/templates/build.rs.js.map +1 -0
  21. package/dist/api/templates/cargo.toml.js +1 -0
  22. package/dist/api/templates/cargo.toml.js.map +1 -0
  23. package/dist/api/templates/ci-template.d.ts +2 -1
  24. package/dist/api/templates/ci-template.js +156 -157
  25. package/dist/api/templates/ci-template.js.map +1 -0
  26. package/dist/api/templates/ci.yml.d.ts +2 -1
  27. package/dist/api/templates/ci.yml.js +19 -4
  28. package/dist/api/templates/ci.yml.js.map +1 -0
  29. package/dist/api/templates/index.js +1 -0
  30. package/dist/api/templates/index.js.map +1 -0
  31. package/dist/api/templates/js-binding.d.ts +1 -1
  32. package/dist/api/templates/js-binding.js +320 -107
  33. package/dist/api/templates/js-binding.js.map +1 -0
  34. package/dist/api/templates/lib.rs.js +2 -4
  35. package/dist/api/templates/lib.rs.js.map +1 -0
  36. package/dist/api/templates/load-wasi-template.d.ts +2 -0
  37. package/dist/api/templates/load-wasi-template.js +139 -0
  38. package/dist/api/templates/load-wasi-template.js.map +1 -0
  39. package/dist/api/templates/package.json.d.ts +9 -2
  40. package/dist/api/templates/package.json.js +55 -28
  41. package/dist/api/templates/package.json.js.map +1 -0
  42. package/dist/api/templates/wasi-worker-template.d.ts +2 -0
  43. package/dist/api/templates/wasi-worker-template.js +86 -0
  44. package/dist/api/templates/wasi-worker-template.js.map +1 -0
  45. package/dist/api/universalize.js +4 -3
  46. package/dist/api/universalize.js.map +1 -0
  47. package/dist/api/version.js +3 -2
  48. package/dist/api/version.js.map +1 -0
  49. package/dist/cli.js +1 -0
  50. package/dist/cli.js.map +1 -0
  51. package/dist/commands/artifacts.js +3 -2
  52. package/dist/commands/artifacts.js.map +1 -0
  53. package/dist/commands/build.js +2 -1
  54. package/dist/commands/build.js.map +1 -0
  55. package/dist/commands/create-npm-dirs.js +1 -0
  56. package/dist/commands/create-npm-dirs.js.map +1 -0
  57. package/dist/commands/help.js +1 -0
  58. package/dist/commands/help.js.map +1 -0
  59. package/dist/commands/new.js +15 -7
  60. package/dist/commands/new.js.map +1 -0
  61. package/dist/commands/pre-publish.js +1 -0
  62. package/dist/commands/pre-publish.js.map +1 -0
  63. package/dist/commands/rename.js +1 -0
  64. package/dist/commands/rename.js.map +1 -0
  65. package/dist/commands/universalize.js +1 -0
  66. package/dist/commands/universalize.js.map +1 -0
  67. package/dist/commands/version.js +1 -0
  68. package/dist/commands/version.js.map +1 -0
  69. package/dist/def/artifacts.d.ts +21 -1
  70. package/dist/def/artifacts.js +11 -2
  71. package/dist/def/artifacts.js.map +1 -0
  72. package/dist/def/build.d.ts +32 -2
  73. package/dist/def/build.js +23 -2
  74. package/dist/def/build.js.map +1 -0
  75. package/dist/def/create-npm-dirs.d.ts +10 -0
  76. package/dist/def/create-npm-dirs.js +5 -0
  77. package/dist/def/create-npm-dirs.js.map +1 -0
  78. package/dist/def/new.d.ts +24 -6
  79. package/dist/def/new.js +12 -1
  80. package/dist/def/new.js.map +1 -0
  81. package/dist/def/pre-publish.d.ts +10 -0
  82. package/dist/def/pre-publish.js +8 -3
  83. package/dist/def/pre-publish.js.map +1 -0
  84. package/dist/def/rename.d.ts +11 -1
  85. package/dist/def/rename.js +6 -1
  86. package/dist/def/rename.js.map +1 -0
  87. package/dist/def/universalize.d.ts +10 -0
  88. package/dist/def/universalize.js +5 -0
  89. package/dist/def/universalize.js.map +1 -0
  90. package/dist/def/version.d.ts +10 -0
  91. package/dist/def/version.js +5 -0
  92. package/dist/def/version.js.map +1 -0
  93. package/dist/index.cjs +6156 -8108
  94. package/dist/index.d.ts +1 -0
  95. package/dist/index.js +2 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/utils/__tests__/config.spec.d.ts +1 -0
  98. package/dist/utils/__tests__/config.spec.js +63 -0
  99. package/dist/utils/__tests__/config.spec.js.map +1 -0
  100. package/dist/utils/__tests__/target.spec.js +1 -0
  101. package/dist/utils/__tests__/target.spec.js.map +1 -0
  102. package/dist/utils/__tests__/typegen.spec.js +9 -4
  103. package/dist/utils/__tests__/typegen.spec.js.map +1 -0
  104. package/dist/utils/__tests__/version.spec.js +1 -0
  105. package/dist/utils/__tests__/version.spec.js.map +1 -0
  106. package/dist/utils/cargo.js +2 -1
  107. package/dist/utils/cargo.js.map +1 -0
  108. package/dist/utils/ci.js +10 -0
  109. package/dist/utils/ci.js.map +1 -0
  110. package/dist/utils/config.d.ts +24 -5
  111. package/dist/utils/config.js +39 -6
  112. package/dist/utils/config.js.map +1 -0
  113. package/dist/utils/index.js +1 -0
  114. package/dist/utils/index.js.map +1 -0
  115. package/dist/utils/log.js +1 -0
  116. package/dist/utils/log.js.map +1 -0
  117. package/dist/utils/metadata.js +3 -2
  118. package/dist/utils/metadata.js.map +1 -0
  119. package/dist/utils/misc.d.ts +1 -1
  120. package/dist/utils/misc.js +4 -3
  121. package/dist/utils/misc.js.map +1 -0
  122. package/dist/utils/target.d.ts +9 -5
  123. package/dist/utils/target.js +20 -1
  124. package/dist/utils/target.js.map +1 -0
  125. package/dist/utils/typegen.d.ts +4 -1
  126. package/dist/utils/typegen.js +27 -6
  127. package/dist/utils/typegen.js.map +1 -0
  128. package/dist/utils/version.d.ts +2 -1
  129. package/dist/utils/version.js +13 -10
  130. package/dist/utils/version.js.map +1 -0
  131. package/package.json +50 -15
  132. package/src/api/artifacts.ts +79 -9
  133. package/src/api/build.ts +331 -39
  134. package/src/api/create-npm-dirs.ts +62 -8
  135. package/src/api/new.ts +69 -33
  136. package/src/api/pre-publish.ts +21 -12
  137. package/src/api/rename.ts +10 -1
  138. package/src/api/templates/.gitignore.ts +1 -0
  139. package/src/api/templates/ci-template.ts +157 -157
  140. package/src/api/templates/ci.yml.ts +19 -4
  141. package/src/api/templates/js-binding.ts +312 -102
  142. package/src/api/templates/lib.rs.ts +1 -4
  143. package/src/api/templates/load-wasi-template.ts +146 -0
  144. package/src/api/templates/package.json.ts +78 -27
  145. package/src/api/templates/wasi-worker-template.ts +86 -0
  146. package/src/api/universalize.ts +6 -3
  147. package/src/api/version.ts +5 -2
  148. package/src/commands/artifacts.ts +2 -2
  149. package/src/commands/build.ts +1 -1
  150. package/src/commands/new.ts +14 -8
  151. package/src/def/artifacts.ts +22 -3
  152. package/src/def/build.ts +51 -4
  153. package/src/def/create-npm-dirs.ts +9 -0
  154. package/src/def/new.ts +28 -3
  155. package/src/def/pre-publish.ts +12 -3
  156. package/src/def/rename.ts +11 -2
  157. package/src/def/universalize.ts +9 -0
  158. package/src/def/version.ts +9 -0
  159. package/src/index.ts +2 -0
  160. package/src/utils/__tests__/__snapshots__/config.spec.ts.md +97 -0
  161. package/src/utils/__tests__/__snapshots__/config.spec.ts.snap +0 -0
  162. package/src/utils/__tests__/__snapshots__/target.spec.ts.md +14 -0
  163. package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
  164. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +555 -0
  165. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
  166. package/src/utils/__tests__/__snapshots__/version.spec.ts.md +9 -8
  167. package/src/utils/__tests__/__snapshots__/version.spec.ts.snap +0 -0
  168. package/src/utils/__tests__/config.spec.ts +81 -0
  169. package/src/utils/__tests__/typegen.spec.ts +19 -4
  170. package/src/utils/cargo.ts +1 -1
  171. package/src/utils/ci.ts +9 -0
  172. package/src/utils/config.ts +84 -9
  173. package/src/utils/metadata.ts +2 -2
  174. package/src/utils/misc.ts +11 -3
  175. package/src/utils/target.ts +28 -7
  176. package/src/utils/typegen.ts +30 -5
  177. package/src/utils/version.ts +11 -9
  178. package/dist/def/commands/artifacts.d.ts +0 -15
  179. package/dist/def/commands/artifacts.js +0 -29
  180. package/dist/def/commands/build.d.ts +0 -53
  181. package/dist/def/commands/build.js +0 -105
  182. package/dist/def/commands/create-npm-dirs.d.ts +0 -15
  183. package/dist/def/commands/create-npm-dirs.js +0 -29
  184. package/dist/def/commands/new.d.ts +0 -27
  185. package/dist/def/commands/new.js +0 -53
  186. package/dist/def/commands/pre-publish.d.ts +0 -23
  187. package/dist/def/commands/pre-publish.js +0 -45
  188. package/dist/def/commands/rename.d.ts +0 -25
  189. package/dist/def/commands/rename.js +0 -49
  190. package/dist/def/commands/universalize.d.ts +0 -13
  191. package/dist/def/commands/universalize.js +0 -25
  192. package/dist/def/commands/version.d.ts +0 -13
  193. package/dist/def/commands/version.js +0 -25
  194. package/dist/def/options/artifacts.d.ts +0 -35
  195. package/dist/def/options/artifacts.js +0 -11
  196. package/dist/def/options/build.d.ts +0 -97
  197. package/dist/def/options/build.js +0 -3
  198. package/dist/def/options/create-npm-dirs.d.ts +0 -35
  199. package/dist/def/options/create-npm-dirs.js +0 -11
  200. package/dist/def/options/new.d.ts +0 -79
  201. package/dist/def/options/new.js +0 -15
  202. package/dist/def/options/pre-publish.d.ts +0 -65
  203. package/dist/def/options/pre-publish.js +0 -13
  204. package/dist/def/options/rename.d.ts +0 -75
  205. package/dist/def/options/rename.js +0 -11
  206. package/dist/def/options/universalize.d.ts +0 -28
  207. package/dist/def/options/universalize.js +0 -10
  208. package/dist/def/options/version.d.ts +0 -28
  209. package/dist/def/options/version.js +0 -10
package/src/api/build.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { spawn } from 'child_process'
2
- import { createHash } from 'crypto'
3
- import { tmpdir } from 'os'
4
- import { parse, join, resolve } from 'path'
1
+ import { spawn } from 'node:child_process'
2
+ import { createHash } from 'node:crypto'
3
+ import { existsSync, mkdirSync } from 'node:fs'
4
+ import { createRequire } from 'node:module'
5
+ import { tmpdir, homedir } from 'node:os'
6
+ import { parse, join, resolve } from 'node:path'
5
7
 
6
8
  import * as colors from 'colorette'
7
9
 
@@ -20,6 +22,7 @@ import {
20
22
  parseMetadata,
21
23
  parseTriple,
22
24
  processTypeDef,
25
+ readFileAsync,
23
26
  readNapiConfig,
24
27
  Target,
25
28
  targetToEnvVar,
@@ -28,11 +31,20 @@ import {
28
31
  writeFileAsync,
29
32
  } from '../utils/index.js'
30
33
 
31
- import { createJsBinding } from './templates/index.js'
34
+ import { createCjsBinding } from './templates/index.js'
35
+ import {
36
+ createWasiBinding,
37
+ createWasiBrowserBinding,
38
+ } from './templates/load-wasi-template.js'
39
+ import {
40
+ WASI_WORKER_BROWSER_TEMPLATE,
41
+ WASI_WORKER_TEMPLATE,
42
+ } from './templates/wasi-worker-template.js'
32
43
 
33
44
  const debug = debugFactory('build')
45
+ const require = createRequire(import.meta.url)
34
46
 
35
- type OutputKind = 'js' | 'dts' | 'node' | 'exe'
47
+ type OutputKind = 'js' | 'dts' | 'node' | 'exe' | 'wasm'
36
48
  type Output = {
37
49
  kind: OutputKind
38
50
  path: string
@@ -76,15 +88,18 @@ export async function buildProject(options: BuildOptions) {
76
88
  options.target
77
89
  ? parseTriple(options.target)
78
90
  : process.env.CARGO_BUILD_TARGET
79
- ? parseTriple(process.env.CARGO_BUILD_TARGET)
80
- : getSystemDefaultTarget(),
91
+ ? parseTriple(process.env.CARGO_BUILD_TARGET)
92
+ : getSystemDefaultTarget(),
81
93
  crateDir,
82
94
  resolvePath(options.outputDir ?? crateDir),
83
95
  options.targetDir ??
84
96
  process.env.CARGO_BUILD_TARGET_DIR ??
85
97
  metadata.target_directory,
86
98
  await readNapiConfig(
87
- resolvePath(options.packageJsonPath ?? 'package.json'),
99
+ resolvePath(
100
+ options.configPath ?? options.packageJsonPath ?? 'package.json',
101
+ ),
102
+ options.configPath ? resolvePath(options.configPath) : undefined,
88
103
  ),
89
104
  )
90
105
 
@@ -138,24 +153,136 @@ class Builder {
138
153
  .setPackage()
139
154
  .setFeatures()
140
155
  .setTarget()
156
+ .pickCrossToolchain()
141
157
  .setEnvs()
142
158
  .setBypassArgs()
143
159
  .exec()
144
160
  }
145
161
 
162
+ private pickCrossToolchain() {
163
+ if (!this.options.useNapiCross) {
164
+ return this
165
+ }
166
+ if (this.options.useCross) {
167
+ debug.warn(
168
+ 'You are trying to use both `--cross` and `--use-napi-cross` options, `--use-cross` will be ignored.',
169
+ )
170
+ }
171
+
172
+ if (this.options.crossCompile) {
173
+ debug.warn(
174
+ 'You are trying to use both `--cross-compile` and `--use-napi-cross` options, `--cross-compile` will be ignored.',
175
+ )
176
+ }
177
+
178
+ try {
179
+ const { version, download } = require('@napi-rs/cross-toolchain')
180
+
181
+ const toolchainPath = join(
182
+ homedir(),
183
+ '.napi-rs',
184
+ 'cross-toolchain',
185
+ version,
186
+ this.target.triple,
187
+ )
188
+ mkdirSync(toolchainPath, { recursive: true })
189
+ if (existsSync(join(toolchainPath, 'package.json'))) {
190
+ debug(`Toolchain ${toolchainPath} exists, skip extracting`)
191
+ } else {
192
+ const tarArchive = download(process.arch, this.target.triple)
193
+ tarArchive.unpack(toolchainPath)
194
+ }
195
+ const upperCaseTarget = targetToEnvVar(this.target.triple)
196
+ const linkerEnv = `CARGO_TARGET_${upperCaseTarget}_LINKER`
197
+ this.envs[linkerEnv] = join(
198
+ toolchainPath,
199
+ 'bin',
200
+ `${this.target.triple}-gcc`,
201
+ )
202
+ if (!process.env.TARGET_SYSROOT) {
203
+ this.envs[`TARGET_SYSROOT`] = join(
204
+ toolchainPath,
205
+ this.target.triple,
206
+ 'sysroot',
207
+ )
208
+ }
209
+ if (!process.env.TARGET_AR) {
210
+ this.envs[`TARGET_AR`] = join(
211
+ toolchainPath,
212
+ 'bin',
213
+ `${this.target.triple}-ar`,
214
+ )
215
+ }
216
+ if (!process.env.TARGET_RANLIB) {
217
+ this.envs[`TARGET_RANLIB`] = join(
218
+ toolchainPath,
219
+ 'bin',
220
+ `${this.target.triple}-ranlib`,
221
+ )
222
+ }
223
+ if (!process.env.TARGET_READELF) {
224
+ this.envs[`TARGET_READELF`] = join(
225
+ toolchainPath,
226
+ 'bin',
227
+ `${this.target.triple}-readelf`,
228
+ )
229
+ }
230
+ if (!process.env.TARGET_C_INCLUDE_PATH) {
231
+ this.envs[`TARGET_C_INCLUDE_PATH`] = join(
232
+ toolchainPath,
233
+ this.target.triple,
234
+ 'sysroot',
235
+ 'usr',
236
+ 'include/',
237
+ )
238
+ }
239
+ if (!process.env.CC && !process.env.TARGET_CC) {
240
+ this.envs[`CC`] = join(
241
+ toolchainPath,
242
+ 'bin',
243
+ `${this.target.triple}-gcc`,
244
+ )
245
+ this.envs[`TARGET_CC`] = join(
246
+ toolchainPath,
247
+ 'bin',
248
+ `${this.target.triple}-gcc`,
249
+ )
250
+ }
251
+ if (
252
+ (process.env.CC === 'clang' &&
253
+ (process.env.TARGET_CC === 'clang' || !process.env.TARGET_CC)) ||
254
+ process.env.TARGET_CC === 'clang'
255
+ ) {
256
+ this.envs.CFLAGS = `--sysroot=${this.envs.TARGET_SYSROOT}`
257
+ }
258
+ } catch (e) {
259
+ debug.warn('Pick cross toolchain failed', e as Error)
260
+ // ignore, do nothing
261
+ }
262
+ return this
263
+ }
264
+
146
265
  private exec() {
147
266
  debug(`Start building crate: ${this.crate.name}`)
148
267
  debug(' %i', `cargo ${this.args.join(' ')}`)
149
268
 
150
269
  const controller = new AbortController()
151
270
 
271
+ const watch = this.options.watch
152
272
  const buildTask = new Promise<void>((resolve, reject) => {
153
- const buildProcess = spawn('cargo', this.args, {
273
+ if (this.options.useCross && this.options.crossCompile) {
274
+ throw new Error(
275
+ '`--use-cross` and `--cross-compile` can not be used together',
276
+ )
277
+ }
278
+ const command =
279
+ process.env.CARGO ?? (this.options.useCross ? 'cross' : 'cargo')
280
+ const buildProcess = spawn(command, this.args, {
154
281
  env: {
155
282
  ...process.env,
156
283
  ...this.envs,
157
284
  },
158
- stdio: 'inherit',
285
+ stdio: watch ? ['inherit', 'inherit', 'pipe'] : 'inherit',
159
286
  cwd: this.cwd,
160
287
  signal: controller.signal,
161
288
  })
@@ -176,6 +303,15 @@ class Builder {
176
303
  }),
177
304
  )
178
305
  })
306
+
307
+ // watch mode only, they are piped through stderr
308
+ buildProcess.stderr?.on('data', (data) => {
309
+ const output = data.toString()
310
+ console.error(output)
311
+ if (/Finished\s(dev|release)/.test(output)) {
312
+ this.postBuild().catch(() => {})
313
+ }
314
+ })
179
315
  })
180
316
 
181
317
  return {
@@ -205,6 +341,7 @@ class Builder {
205
341
  this.crateDir,
206
342
  '--',
207
343
  'cargo',
344
+ 'build',
208
345
  )
209
346
  set = true
210
347
  }
@@ -351,18 +488,35 @@ class Builder {
351
488
  const targetArch = this.target.arch === 'arm' ? 'armv7a' : 'aarch64'
352
489
  const targetPlatform =
353
490
  this.target.arch === 'arm' ? 'androideabi24' : 'android24'
491
+ const hostPlatform =
492
+ process.platform === 'darwin'
493
+ ? 'darwin'
494
+ : process.platform === 'win32'
495
+ ? 'windows'
496
+ : 'linux'
354
497
  Object.assign(this.envs, {
355
- CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-android24-clang`,
356
- CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-androideabi24-clang`,
357
- CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
358
- CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
359
- AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar`,
498
+ CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-android24-clang`,
499
+ CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-androideabi24-clang`,
500
+ CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
501
+ CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
502
+ AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ar`,
503
+ RANLIB: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ranlib`,
360
504
  ANDROID_NDK: ANDROID_NDK_LATEST_HOME,
361
- PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${process.env.PATH}`,
505
+ PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin:${process.env.PATH}`,
362
506
  })
363
507
  }
364
508
  // END LINKER
365
509
 
510
+ if (this.target.platform === 'wasi') {
511
+ const emnapi = join(
512
+ require.resolve('emnapi'),
513
+ '..',
514
+ 'lib',
515
+ 'wasm32-wasi-threads',
516
+ )
517
+ this.envs.EMNAPI_LINK_DIR = emnapi
518
+ }
519
+
366
520
  debug('Set envs: ')
367
521
  Object.entries(this.envs).forEach(([k, v]) => {
368
522
  debug(' %i', `${k}=${v}`)
@@ -373,11 +527,17 @@ class Builder {
373
527
 
374
528
  private setFeatures() {
375
529
  const args = []
530
+ if (this.options.allFeatures && this.options.allFeatures) {
531
+ throw new Error(
532
+ 'Cannot specify --all-features and --no-default-features together',
533
+ )
534
+ }
376
535
  if (this.options.allFeatures) {
377
536
  args.push('--all-features')
378
537
  } else if (this.options.noDefaultFeatures) {
379
538
  args.push('--no-default-features')
380
- } else if (this.options.features) {
539
+ }
540
+ if (this.options.features) {
381
541
  args.push('--features', ...this.options.features)
382
542
  }
383
543
 
@@ -401,6 +561,14 @@ class Builder {
401
561
  this.args.push('--target-dir', this.options.targetDir)
402
562
  }
403
563
 
564
+ if (this.options.profile) {
565
+ this.args.push('--profile', this.options.profile)
566
+ }
567
+
568
+ if (this.options.manifestPath) {
569
+ this.args.push('--manifest-path', this.options.manifestPath)
570
+ }
571
+
404
572
  if (this.options.cargoOptions?.length) {
405
573
  this.args.push(...this.options.cargoOptions)
406
574
  }
@@ -442,12 +610,48 @@ class Builder {
442
610
  })
443
611
  }
444
612
 
445
- await this.copyArtifact()
613
+ const dest = await this.copyArtifact()
446
614
 
447
615
  // only for cdylib
448
616
  if (this.cdyLibName) {
449
- await this.generateTypeDef()
450
- await this.writeJsBinding()
617
+ const idents = await this.generateTypeDef()
618
+ const intermediateWasiRegisterFile = this.envs.WASI_REGISTER_TMP_PATH
619
+ const wasiRegisterFunctions =
620
+ this.target.arch === 'wasm32'
621
+ ? await (async function readIntermediateWasiRegisterFile() {
622
+ const fileContent = await readFileAsync(
623
+ intermediateWasiRegisterFile,
624
+ 'utf8',
625
+ ).catch((err) => {
626
+ console.warn(
627
+ `Read ${colors.yellowBright(
628
+ intermediateWasiRegisterFile,
629
+ )} failed, reason: ${err.message}`,
630
+ )
631
+ return ``
632
+ })
633
+ return fileContent
634
+ .split('\n')
635
+ .map((l) => l.trim())
636
+ .filter((l) => l.length)
637
+ .map((line) => {
638
+ const [_, fn] = line.split(':')
639
+ return fn.trim()
640
+ })
641
+ })()
642
+ : []
643
+ const jsOutput = await this.writeJsBinding(idents)
644
+ const wasmBindingsOutput = await this.writeWasiBinding(
645
+ wasiRegisterFunctions,
646
+ dest ?? 'index.wasm',
647
+ idents,
648
+ )
649
+ if (jsOutput) {
650
+ this.outputs.push(jsOutput)
651
+ }
652
+ if (wasmBindingsOutput) {
653
+ this.outputs.push(...wasmBindingsOutput)
654
+ }
451
655
  }
452
656
 
453
657
  return this.outputs
@@ -459,12 +663,10 @@ class Builder {
459
663
  return
460
664
  }
461
665
 
462
- const src = join(
463
- this.targetDir,
464
- this.target.triple,
465
- this.options.release ? 'release' : 'debug',
466
- srcName,
467
- )
666
+ const profile =
667
+ this.options.profile ?? (this.options.release ? 'release' : 'debug')
668
+ const src = join(this.targetDir, this.target.triple, profile, srcName)
669
+ debug(`Copy artifact from: [${src}]`)
468
670
  const dest = join(this.outputDir, destName)
469
671
 
470
672
  try {
@@ -479,6 +681,7 @@ class Builder {
479
681
  kind: dest.endsWith('.node') ? 'node' : 'exe',
480
682
  path: dest,
481
683
  })
684
+ return dest
482
685
  } catch (e) {
483
686
  throw new Error('Failed to copy artifact', {
484
687
  cause: e,
@@ -494,8 +697,10 @@ class Builder {
494
697
  this.target.platform === 'darwin'
495
698
  ? `lib${cdyLib}.dylib`
496
699
  : this.target.platform === 'win32'
497
- ? `${cdyLib}.dll`
498
- : `lib${cdyLib}.so`
700
+ ? `${cdyLib}.dll`
701
+ : this.target.platform === 'wasi' || this.target.platform === 'wasm'
702
+ ? `${cdyLib}.wasm`
703
+ : `lib${cdyLib}.so`
499
704
 
500
705
  let destName = this.config.binaryName
501
706
  // add platform suffix to binary name
@@ -504,7 +709,11 @@ class Builder {
504
709
  if (this.options.platform) {
505
710
  destName += `.${this.target.platformArchABI}`
506
711
  }
507
- destName += '.node'
712
+ if (srcName.endsWith('.wasm')) {
713
+ destName += '.wasm'
714
+ } else {
715
+ destName += '.node'
716
+ }
508
717
 
509
718
  return [srcName, destName]
510
719
  } else if (this.binName) {
@@ -519,13 +728,14 @@ class Builder {
519
728
 
520
729
  private async generateTypeDef() {
521
730
  if (!(await fileExists(this.envs.TYPE_DEF_TMP_PATH))) {
522
- return
731
+ return []
523
732
  }
524
733
 
525
734
  const dest = join(this.outputDir, this.options.dts ?? 'index.d.ts')
526
735
 
527
- const dts = await processTypeDef(
736
+ const { dts, exports } = await processTypeDef(
528
737
  this.envs.TYPE_DEF_TMP_PATH,
738
+ this.options.constEnum ?? true,
529
739
  !this.options.noDtsHeader
530
740
  ? this.options.dtsHeader ?? DEFAULT_TYPE_DEF_HEADER
531
741
  : '',
@@ -543,27 +753,109 @@ class Builder {
543
753
  debug.error('Failed to write type def file')
544
754
  debug.error(e as Error)
545
755
  }
756
+
757
+ return exports
546
758
  }
547
759
 
548
- private async writeJsBinding() {
549
- if (!this.options.platform || this.options.noJsBinding) {
760
+ private async writeJsBinding(idents: string[]) {
761
+ if (
762
+ !this.options.platform ||
763
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
764
+ this.options.noJsBinding ||
765
+ idents.length === 0
766
+ ) {
550
767
  return
551
768
  }
552
769
 
553
- const dest = join(this.outputDir, this.options.jsBinding ?? 'index.js')
770
+ const name = this.options.jsBinding ?? 'index.js'
554
771
 
555
- const js = createJsBinding(this.config.binaryName, this.config.packageName)
772
+ const cjs = createCjsBinding(
773
+ this.config.binaryName,
774
+ this.config.packageName,
775
+ idents,
776
+ )
556
777
 
557
778
  try {
779
+ const dest = join(this.outputDir, name)
558
780
  debug('Writing js binding to:')
559
781
  debug(' %i', dest)
560
- await writeFileAsync(dest, js, 'utf-8')
561
- this.outputs.push({
782
+ await writeFileAsync(dest, cjs, 'utf-8')
783
+ return {
562
784
  kind: 'js',
563
785
  path: dest,
564
- })
786
+ } satisfies Output
565
787
  } catch (e) {
566
788
  throw new Error('Failed to write js binding file', { cause: e })
567
789
  }
568
790
  }
791
+
792
+ private async writeWasiBinding(
793
+ wasiRegisterFunctions: string[],
794
+ distFileName: string | undefined,
795
+ idents: string[],
796
+ ) {
797
+ if (distFileName && wasiRegisterFunctions.length) {
798
+ const { name, dir } = parse(distFileName)
799
+ const bindingPath = join(dir, `${this.config.binaryName}.wasi.cjs`)
800
+ const browserBindingPath = join(
801
+ dir,
802
+ `${this.config.binaryName}.wasi-browser.js`,
803
+ )
804
+ const workerPath = join(dir, 'wasi-worker.mjs')
805
+ const browserWorkerPath = join(dir, 'wasi-worker-browser.mjs')
806
+ const exportsCode = idents
807
+ .map(
808
+ (ident) => `module.exports.${ident} = __napiModule.exports.${ident}`,
809
+ )
810
+ .join('\n')
811
+ await writeFileAsync(
812
+ bindingPath,
813
+ createWasiBinding(
814
+ name,
815
+ this.config.packageName,
816
+ wasiRegisterFunctions,
817
+ ) +
818
+ exportsCode +
819
+ '\n',
820
+ 'utf8',
821
+ )
822
+ await writeFileAsync(
823
+ browserBindingPath,
824
+ createWasiBrowserBinding(name, wasiRegisterFunctions) +
825
+ idents
826
+ .map(
827
+ (ident) =>
828
+ `export const ${ident} = __napiModule.exports.${ident}`,
829
+ )
830
+ .join('\n') +
831
+ '\n',
832
+ 'utf8',
833
+ )
834
+ await writeFileAsync(workerPath, WASI_WORKER_TEMPLATE, 'utf8')
835
+ await writeFileAsync(
836
+ browserWorkerPath,
837
+ WASI_WORKER_BROWSER_TEMPLATE,
838
+ 'utf8',
839
+ )
840
+ return [
841
+ {
842
+ kind: 'js',
843
+ path: bindingPath,
844
+ },
845
+ {
846
+ kind: 'js',
847
+ path: browserBindingPath,
848
+ },
849
+ {
850
+ kind: 'js',
851
+ path: workerPath,
852
+ },
853
+ {
854
+ kind: 'js',
855
+ path: browserWorkerPath,
856
+ },
857
+ ] satisfies Output[]
858
+ }
859
+ return []
860
+ }
569
861
  }
@@ -1,4 +1,6 @@
1
- import { join, resolve } from 'path'
1
+ import { join, resolve } from 'node:path'
2
+
3
+ import { parse } from 'semver'
2
4
 
3
5
  import {
4
6
  applyDefaultCreateNpmDirsOptions,
@@ -13,6 +15,8 @@ import {
13
15
  Target,
14
16
  } from '../utils/index.js'
15
17
 
18
+ import type { PackageMeta } from './templates/package.json.js'
19
+
16
20
  const debug = debugFactory('create-npm-dirs')
17
21
 
18
22
  export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
@@ -43,20 +47,25 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
43
47
  const packageJsonPath = resolve(options.cwd, options.packageJsonPath)
44
48
  const npmPath = resolve(options.cwd, options.npmDir)
45
49
 
46
- debug(`Read content from [${packageJsonPath}]`)
50
+ debug(`Read content from [${options.configPath ?? packageJsonPath}]`)
47
51
 
48
52
  const { targets, binaryName, packageName, packageJson } =
49
- await readNapiConfig(packageJsonPath)
53
+ await readNapiConfig(
54
+ packageJsonPath,
55
+ options.configPath ? resolve(options.cwd, options.configPath) : undefined,
56
+ )
50
57
 
51
58
  for (const target of targets) {
52
59
  const targetDir = join(npmPath, `${target.platformArchABI}`)
53
60
  await mkdirAsync(targetDir)
54
61
 
55
- const binaryFileName = `${binaryName}.${target.platformArchABI}.node`
62
+ const binaryFileName =
63
+ target.arch === 'wasm32'
64
+ ? `${binaryName}.${target.platformArchABI}.wasm`
65
+ : `${binaryName}.${target.platformArchABI}.node`
56
66
  const scopedPackageJson = {
57
67
  name: `${packageName}-${target.platformArchABI}`,
58
68
  version: packageJson.version,
59
- os: [target.platform],
60
69
  cpu: target.arch !== 'universal' ? [target.arch] : undefined,
61
70
  main: binaryFileName,
62
71
  files: [binaryFileName],
@@ -74,9 +83,54 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
74
83
  'bugs',
75
84
  ),
76
85
  }
86
+ if (target.arch !== 'wasm32') {
87
+ // @ts-expect-error
88
+ scopedPackageJson.os = [target.platform]
89
+ } else {
90
+ const entry = `${binaryName}.wasi.cjs`
91
+ scopedPackageJson.files.push(entry, `wasi-worker.mjs`)
92
+ scopedPackageJson.main = entry
93
+ // @ts-expect-error
94
+ scopedPackageJson.browser = `${binaryName}.wasi-browser.js`
95
+ let needRestrictNodeVersion = true
96
+ if (scopedPackageJson.engines?.node) {
97
+ try {
98
+ const { major } = parse(scopedPackageJson.engines.node) ?? {
99
+ major: 0,
100
+ }
101
+ if (major >= 14) {
102
+ needRestrictNodeVersion = false
103
+ }
104
+ } catch {
105
+ // ignore
106
+ }
107
+ }
108
+ if (needRestrictNodeVersion) {
109
+ scopedPackageJson.engines = {
110
+ node: '>=14.0.0',
111
+ }
112
+ }
113
+ const emnapiCore = await fetch(
114
+ `https://registry.npmjs.org/@emnapi/core`,
115
+ ).then((res) => res.json() as Promise<PackageMeta>)
116
+ const emnapiRuntime = await fetch(
117
+ `https://registry.npmjs.org/@emnapi/runtime`,
118
+ ).then((res) => res.json() as Promise<PackageMeta>)
119
+ const wasiUtil = await fetch(
120
+ `https://registry.npmjs.org/@tybys/wasm-util`,
121
+ ).then((res) => res.json() as Promise<PackageMeta>)
122
+ const memfsBrowser = await fetch(
123
+ `https://registry.npmjs.org/memfs-browser`,
124
+ ).then((res) => res.json() as Promise<PackageMeta>)
125
+ // @ts-expect-error
126
+ scopedPackageJson.dependencies = {
127
+ '@emnapi/core': `^${emnapiCore['dist-tags'].latest}`,
128
+ '@emnapi/runtime': `^${emnapiRuntime['dist-tags'].latest}`,
129
+ '@tybys/wasm-util': `^${wasiUtil['dist-tags'].latest}`,
130
+ 'memfs-browser': `^${memfsBrowser['dist-tags'].latest}`,
131
+ }
132
+ }
77
133
 
78
- // Only works with yarn 3.1+
79
- // https://github.com/yarnpkg/berry/pull/3981
80
134
  if (target.abi === 'gnu') {
81
135
  // @ts-expect-error
82
136
  scopedPackageJson.libc = ['glibc']
@@ -93,7 +147,7 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
93
147
  const targetReadme = join(targetDir, 'README.md')
94
148
  await writeFileAsync(targetReadme, readme(packageName, target))
95
149
 
96
- debug.info(`${packageName}-${target.platformArchABI} created`)
150
+ debug.info(`${packageName} -${target.platformArchABI} created`)
97
151
  }
98
152
  }
99
153