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

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 +23 -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 +184 -32
  5. package/dist/api/build.js.map +1 -0
  6. package/dist/api/create-npm-dirs.js +43 -7
  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 +1 -0
  37. package/dist/api/templates/load-wasi-template.js +78 -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 +1 -0
  43. package/dist/api/templates/wasi-worker-template.js +53 -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 +6020 -8093
  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 +53 -9
  133. package/src/api/build.ts +289 -39
  134. package/src/api/create-npm-dirs.ts +51 -7
  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 +81 -0
  144. package/src/api/templates/package.json.ts +78 -27
  145. package/src/api/templates/wasi-worker-template.ts +52 -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,14 @@ 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 { createWasiBinding } from './templates/load-wasi-template.js'
36
+ import { WASI_WORKER_TEMPLATE } from './templates/wasi-worker-template.js'
32
37
 
33
38
  const debug = debugFactory('build')
39
+ const require = createRequire(import.meta.url)
34
40
 
35
- type OutputKind = 'js' | 'dts' | 'node' | 'exe'
41
+ type OutputKind = 'js' | 'dts' | 'node' | 'exe' | 'wasm'
36
42
  type Output = {
37
43
  kind: OutputKind
38
44
  path: string
@@ -76,15 +82,18 @@ export async function buildProject(options: BuildOptions) {
76
82
  options.target
77
83
  ? parseTriple(options.target)
78
84
  : process.env.CARGO_BUILD_TARGET
79
- ? parseTriple(process.env.CARGO_BUILD_TARGET)
80
- : getSystemDefaultTarget(),
85
+ ? parseTriple(process.env.CARGO_BUILD_TARGET)
86
+ : getSystemDefaultTarget(),
81
87
  crateDir,
82
88
  resolvePath(options.outputDir ?? crateDir),
83
89
  options.targetDir ??
84
90
  process.env.CARGO_BUILD_TARGET_DIR ??
85
91
  metadata.target_directory,
86
92
  await readNapiConfig(
87
- resolvePath(options.packageJsonPath ?? 'package.json'),
93
+ resolvePath(
94
+ options.configPath ?? options.packageJsonPath ?? 'package.json',
95
+ ),
96
+ options.configPath ? resolvePath(options.configPath) : undefined,
88
97
  ),
89
98
  )
90
99
 
@@ -138,24 +147,136 @@ class Builder {
138
147
  .setPackage()
139
148
  .setFeatures()
140
149
  .setTarget()
150
+ .pickCrossToolchain()
141
151
  .setEnvs()
142
152
  .setBypassArgs()
143
153
  .exec()
144
154
  }
145
155
 
156
+ private pickCrossToolchain() {
157
+ if (!this.options.useNapiCross) {
158
+ return this
159
+ }
160
+ if (this.options.useCross) {
161
+ debug.warn(
162
+ 'You are trying to use both `--cross` and `--use-napi-cross` options, `--use-cross` will be ignored.',
163
+ )
164
+ }
165
+
166
+ if (this.options.crossCompile) {
167
+ debug.warn(
168
+ 'You are trying to use both `--cross-compile` and `--use-napi-cross` options, `--cross-compile` will be ignored.',
169
+ )
170
+ }
171
+
172
+ try {
173
+ const { version, download } = require('@napi-rs/cross-toolchain')
174
+
175
+ const toolchainPath = join(
176
+ homedir(),
177
+ '.napi-rs',
178
+ 'cross-toolchain',
179
+ version,
180
+ this.target.triple,
181
+ )
182
+ mkdirSync(toolchainPath, { recursive: true })
183
+ if (existsSync(join(toolchainPath, 'package.json'))) {
184
+ debug(`Toolchain ${toolchainPath} exists, skip extracting`)
185
+ } else {
186
+ const tarArchive = download(process.arch, this.target.triple)
187
+ tarArchive.unpack(toolchainPath)
188
+ }
189
+ const upperCaseTarget = targetToEnvVar(this.target.triple)
190
+ const linkerEnv = `CARGO_TARGET_${upperCaseTarget}_LINKER`
191
+ this.envs[linkerEnv] = join(
192
+ toolchainPath,
193
+ 'bin',
194
+ `${this.target.triple}-gcc`,
195
+ )
196
+ if (!process.env.TARGET_SYSROOT) {
197
+ this.envs[`TARGET_SYSROOT`] = join(
198
+ toolchainPath,
199
+ this.target.triple,
200
+ 'sysroot',
201
+ )
202
+ }
203
+ if (!process.env.TARGET_AR) {
204
+ this.envs[`TARGET_AR`] = join(
205
+ toolchainPath,
206
+ 'bin',
207
+ `${this.target.triple}-ar`,
208
+ )
209
+ }
210
+ if (!process.env.TARGET_RANLIB) {
211
+ this.envs[`TARGET_RANLIB`] = join(
212
+ toolchainPath,
213
+ 'bin',
214
+ `${this.target.triple}-ranlib`,
215
+ )
216
+ }
217
+ if (!process.env.TARGET_READELF) {
218
+ this.envs[`TARGET_READELF`] = join(
219
+ toolchainPath,
220
+ 'bin',
221
+ `${this.target.triple}-readelf`,
222
+ )
223
+ }
224
+ if (!process.env.TARGET_C_INCLUDE_PATH) {
225
+ this.envs[`TARGET_C_INCLUDE_PATH`] = join(
226
+ toolchainPath,
227
+ this.target.triple,
228
+ 'sysroot',
229
+ 'usr',
230
+ 'include/',
231
+ )
232
+ }
233
+ if (!process.env.CC && !process.env.TARGET_CC) {
234
+ this.envs[`CC`] = join(
235
+ toolchainPath,
236
+ 'bin',
237
+ `${this.target.triple}-gcc`,
238
+ )
239
+ this.envs[`TARGET_CC`] = join(
240
+ toolchainPath,
241
+ 'bin',
242
+ `${this.target.triple}-gcc`,
243
+ )
244
+ }
245
+ if (
246
+ (process.env.CC === 'clang' &&
247
+ (process.env.TARGET_CC === 'clang' || !process.env.TARGET_CC)) ||
248
+ process.env.TARGET_CC === 'clang'
249
+ ) {
250
+ this.envs.CFLAGS = `--sysroot=${this.envs.TARGET_SYSROOT}`
251
+ }
252
+ } catch (e) {
253
+ debug.warn('Pick cross toolchain failed', e as Error)
254
+ // ignore, do nothing
255
+ }
256
+ return this
257
+ }
258
+
146
259
  private exec() {
147
260
  debug(`Start building crate: ${this.crate.name}`)
148
261
  debug(' %i', `cargo ${this.args.join(' ')}`)
149
262
 
150
263
  const controller = new AbortController()
151
264
 
265
+ const watch = this.options.watch
152
266
  const buildTask = new Promise<void>((resolve, reject) => {
153
- const buildProcess = spawn('cargo', this.args, {
267
+ if (this.options.useCross && this.options.crossCompile) {
268
+ throw new Error(
269
+ '`--use-cross` and `--cross-compile` can not be used together',
270
+ )
271
+ }
272
+ const command =
273
+ process.env.CARGO ?? (this.options.useCross ? 'cross' : 'cargo')
274
+ const buildProcess = spawn(command, this.args, {
154
275
  env: {
155
276
  ...process.env,
156
277
  ...this.envs,
157
278
  },
158
- stdio: 'inherit',
279
+ stdio: watch ? ['inherit', 'inherit', 'pipe'] : 'inherit',
159
280
  cwd: this.cwd,
160
281
  signal: controller.signal,
161
282
  })
@@ -176,6 +297,15 @@ class Builder {
176
297
  }),
177
298
  )
178
299
  })
300
+
301
+ // watch mode only, they are piped through stderr
302
+ buildProcess.stderr?.on('data', (data) => {
303
+ const output = data.toString()
304
+ console.error(output)
305
+ if (/Finished\s(dev|release)/.test(output)) {
306
+ this.postBuild().catch(() => {})
307
+ }
308
+ })
179
309
  })
180
310
 
181
311
  return {
@@ -205,6 +335,7 @@ class Builder {
205
335
  this.crateDir,
206
336
  '--',
207
337
  'cargo',
338
+ 'build',
208
339
  )
209
340
  set = true
210
341
  }
@@ -351,18 +482,35 @@ class Builder {
351
482
  const targetArch = this.target.arch === 'arm' ? 'armv7a' : 'aarch64'
352
483
  const targetPlatform =
353
484
  this.target.arch === 'arm' ? 'androideabi24' : 'android24'
485
+ const hostPlatform =
486
+ process.platform === 'darwin'
487
+ ? 'darwin'
488
+ : process.platform === 'win32'
489
+ ? 'windows'
490
+ : 'linux'
354
491
  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`,
492
+ CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-android24-clang`,
493
+ CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-androideabi24-clang`,
494
+ CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
495
+ CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
496
+ AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ar`,
497
+ RANLIB: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ranlib`,
360
498
  ANDROID_NDK: ANDROID_NDK_LATEST_HOME,
361
- PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${process.env.PATH}`,
499
+ PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin:${process.env.PATH}`,
362
500
  })
363
501
  }
364
502
  // END LINKER
365
503
 
504
+ if (this.target.platform === 'wasi') {
505
+ const emnapi = join(
506
+ require.resolve('emnapi'),
507
+ '..',
508
+ 'lib',
509
+ 'wasm32-wasi-threads',
510
+ )
511
+ this.envs.EMNAPI_LINK_DIR = emnapi
512
+ }
513
+
366
514
  debug('Set envs: ')
367
515
  Object.entries(this.envs).forEach(([k, v]) => {
368
516
  debug(' %i', `${k}=${v}`)
@@ -373,11 +521,17 @@ class Builder {
373
521
 
374
522
  private setFeatures() {
375
523
  const args = []
524
+ if (this.options.allFeatures && this.options.allFeatures) {
525
+ throw new Error(
526
+ 'Cannot specify --all-features and --no-default-features together',
527
+ )
528
+ }
376
529
  if (this.options.allFeatures) {
377
530
  args.push('--all-features')
378
531
  } else if (this.options.noDefaultFeatures) {
379
532
  args.push('--no-default-features')
380
- } else if (this.options.features) {
533
+ }
534
+ if (this.options.features) {
381
535
  args.push('--features', ...this.options.features)
382
536
  }
383
537
 
@@ -401,6 +555,14 @@ class Builder {
401
555
  this.args.push('--target-dir', this.options.targetDir)
402
556
  }
403
557
 
558
+ if (this.options.profile) {
559
+ this.args.push('--profile', this.options.profile)
560
+ }
561
+
562
+ if (this.options.manifestPath) {
563
+ this.args.push('--manifest-path', this.options.manifestPath)
564
+ }
565
+
404
566
  if (this.options.cargoOptions?.length) {
405
567
  this.args.push(...this.options.cargoOptions)
406
568
  }
@@ -442,12 +604,48 @@ class Builder {
442
604
  })
443
605
  }
444
606
 
445
- await this.copyArtifact()
607
+ const dest = await this.copyArtifact()
446
608
 
447
609
  // only for cdylib
448
610
  if (this.cdyLibName) {
449
- await this.generateTypeDef()
450
- await this.writeJsBinding()
611
+ const idents = await this.generateTypeDef()
612
+ const intermediateWasiRegisterFile = this.envs.WASI_REGISTER_TMP_PATH
613
+ const wasiRegisterFunctions =
614
+ this.target.arch === 'wasm32'
615
+ ? await (async function readIntermediateWasiRegisterFile() {
616
+ const fileContent = await readFileAsync(
617
+ intermediateWasiRegisterFile,
618
+ 'utf8',
619
+ ).catch((err) => {
620
+ console.warn(
621
+ `Read ${colors.yellowBright(
622
+ intermediateWasiRegisterFile,
623
+ )} failed, reason: ${err.message}`,
624
+ )
625
+ return ``
626
+ })
627
+ return fileContent
628
+ .split('\n')
629
+ .map((l) => l.trim())
630
+ .filter((l) => l.length)
631
+ .map((line) => {
632
+ const [_, fn] = line.split(':')
633
+ return fn.trim()
634
+ })
635
+ })()
636
+ : []
637
+ const jsOutput = await this.writeJsBinding(idents)
638
+ const wasmOutput = await this.writeWasiBinding(
639
+ wasiRegisterFunctions,
640
+ dest ?? 'index.wasm',
641
+ idents,
642
+ )
643
+ if (jsOutput) {
644
+ this.outputs.push(jsOutput)
645
+ }
646
+ if (wasmOutput) {
647
+ this.outputs.push(wasmOutput)
648
+ }
451
649
  }
452
650
 
453
651
  return this.outputs
@@ -459,12 +657,10 @@ class Builder {
459
657
  return
460
658
  }
461
659
 
462
- const src = join(
463
- this.targetDir,
464
- this.target.triple,
465
- this.options.release ? 'release' : 'debug',
466
- srcName,
467
- )
660
+ const profile =
661
+ this.options.profile ?? (this.options.release ? 'release' : 'debug')
662
+ const src = join(this.targetDir, this.target.triple, profile, srcName)
663
+ debug(`Copy artifact from: [${src}]`)
468
664
  const dest = join(this.outputDir, destName)
469
665
 
470
666
  try {
@@ -479,6 +675,7 @@ class Builder {
479
675
  kind: dest.endsWith('.node') ? 'node' : 'exe',
480
676
  path: dest,
481
677
  })
678
+ return dest
482
679
  } catch (e) {
483
680
  throw new Error('Failed to copy artifact', {
484
681
  cause: e,
@@ -494,8 +691,10 @@ class Builder {
494
691
  this.target.platform === 'darwin'
495
692
  ? `lib${cdyLib}.dylib`
496
693
  : this.target.platform === 'win32'
497
- ? `${cdyLib}.dll`
498
- : `lib${cdyLib}.so`
694
+ ? `${cdyLib}.dll`
695
+ : this.target.platform === 'wasi' || this.target.platform === 'wasm'
696
+ ? `${cdyLib}.wasm`
697
+ : `lib${cdyLib}.so`
499
698
 
500
699
  let destName = this.config.binaryName
501
700
  // add platform suffix to binary name
@@ -504,7 +703,11 @@ class Builder {
504
703
  if (this.options.platform) {
505
704
  destName += `.${this.target.platformArchABI}`
506
705
  }
507
- destName += '.node'
706
+ if (srcName.endsWith('.wasm')) {
707
+ destName += '.wasm'
708
+ } else {
709
+ destName += '.node'
710
+ }
508
711
 
509
712
  return [srcName, destName]
510
713
  } else if (this.binName) {
@@ -519,13 +722,14 @@ class Builder {
519
722
 
520
723
  private async generateTypeDef() {
521
724
  if (!(await fileExists(this.envs.TYPE_DEF_TMP_PATH))) {
522
- return
725
+ return []
523
726
  }
524
727
 
525
728
  const dest = join(this.outputDir, this.options.dts ?? 'index.d.ts')
526
729
 
527
- const dts = await processTypeDef(
730
+ const { dts, exports } = await processTypeDef(
528
731
  this.envs.TYPE_DEF_TMP_PATH,
732
+ this.options.constEnum ?? true,
529
733
  !this.options.noDtsHeader
530
734
  ? this.options.dtsHeader ?? DEFAULT_TYPE_DEF_HEADER
531
735
  : '',
@@ -543,27 +747,73 @@ class Builder {
543
747
  debug.error('Failed to write type def file')
544
748
  debug.error(e as Error)
545
749
  }
750
+
751
+ return exports
546
752
  }
547
753
 
548
- private async writeJsBinding() {
549
- if (!this.options.platform || this.options.noJsBinding) {
754
+ private async writeJsBinding(idents: string[]) {
755
+ if (
756
+ !this.options.platform ||
757
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
758
+ this.options.noJsBinding ||
759
+ idents.length === 0
760
+ ) {
550
761
  return
551
762
  }
552
763
 
553
- const dest = join(this.outputDir, this.options.jsBinding ?? 'index.js')
764
+ const name = this.options.jsBinding ?? 'index.js'
554
765
 
555
- const js = createJsBinding(this.config.binaryName, this.config.packageName)
766
+ const cjs = createCjsBinding(
767
+ this.config.binaryName,
768
+ this.config.packageName,
769
+ idents,
770
+ )
556
771
 
557
772
  try {
773
+ const dest = join(this.outputDir, name)
558
774
  debug('Writing js binding to:')
559
775
  debug(' %i', dest)
560
- await writeFileAsync(dest, js, 'utf-8')
561
- this.outputs.push({
776
+ await writeFileAsync(dest, cjs, 'utf-8')
777
+ return {
562
778
  kind: 'js',
563
779
  path: dest,
564
- })
780
+ } satisfies Output
565
781
  } catch (e) {
566
782
  throw new Error('Failed to write js binding file', { cause: e })
567
783
  }
568
784
  }
785
+
786
+ private async writeWasiBinding(
787
+ wasiRegisterFunctions: string[],
788
+ distFileName: string | undefined,
789
+ idents: string[],
790
+ ) {
791
+ if (distFileName && wasiRegisterFunctions.length) {
792
+ const { name, dir } = parse(distFileName)
793
+ const newPath = join(dir, `${this.config.binaryName}.wasi.cjs`)
794
+ const workerPath = join(dir, 'wasi-worker.mjs')
795
+ const exportsCode = idents
796
+ .map(
797
+ (ident) => `module.exports.${ident} = __napiModule.exports.${ident}`,
798
+ )
799
+ .join(',\n')
800
+ await writeFileAsync(
801
+ newPath,
802
+ createWasiBinding(
803
+ name,
804
+ this.config.packageName,
805
+ wasiRegisterFunctions,
806
+ ) +
807
+ exportsCode +
808
+ '\n',
809
+ 'utf8',
810
+ )
811
+ await writeFileAsync(workerPath, WASI_WORKER_TEMPLATE, 'utf8')
812
+ return {
813
+ kind: 'wasm',
814
+ path: newPath,
815
+ } satisfies Output
816
+ }
817
+ return null
818
+ }
569
819
  }
@@ -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,44 @@ 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
+ let needRestrictNodeVersion = true
94
+ if (scopedPackageJson.engines?.node) {
95
+ try {
96
+ const { major } = parse(scopedPackageJson.engines.node) ?? {
97
+ major: 0,
98
+ }
99
+ if (major >= 14) {
100
+ needRestrictNodeVersion = false
101
+ }
102
+ } catch {
103
+ // ignore
104
+ }
105
+ }
106
+ if (needRestrictNodeVersion) {
107
+ scopedPackageJson.engines = {
108
+ node: '>=14.0.0',
109
+ }
110
+ }
111
+ const emnapiCore = await fetch(
112
+ `https://registry.npmjs.org/@emnapi/core`,
113
+ ).then((res) => res.json() as Promise<PackageMeta>)
114
+ const emnapiRuntime = await fetch(
115
+ `https://registry.npmjs.org/@emnapi/runtime`,
116
+ ).then((res) => res.json() as Promise<PackageMeta>)
117
+ // @ts-expect-error
118
+ scopedPackageJson.dependencies = {
119
+ '@emnapi/core': `^${emnapiCore['dist-tags'].latest}`,
120
+ '@emnapi/runtime': `^${emnapiRuntime['dist-tags'].latest}`,
121
+ }
122
+ }
77
123
 
78
- // Only works with yarn 3.1+
79
- // https://github.com/yarnpkg/berry/pull/3981
80
124
  if (target.abi === 'gnu') {
81
125
  // @ts-expect-error
82
126
  scopedPackageJson.libc = ['glibc']