@napi-rs/cli 3.0.0-alpha.8 → 3.0.0-alpha.81

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 (161) 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 +310 -65
  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 +140 -125
  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 +141 -222
  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 +168 -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 +7596 -13754
  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 +52 -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.d.ts +13 -1
  88. package/dist/utils/metadata.js +31 -11
  89. package/dist/utils/metadata.js.map +1 -1
  90. package/dist/utils/misc.d.ts +1 -2
  91. package/dist/utils/misc.js +3 -3
  92. package/dist/utils/misc.js.map +1 -1
  93. package/dist/utils/target.d.ts +7 -5
  94. package/dist/utils/target.js +17 -3
  95. package/dist/utils/target.js.map +1 -1
  96. package/dist/utils/typegen.d.ts +1 -1
  97. package/dist/utils/typegen.js +55 -20
  98. package/dist/utils/typegen.js.map +1 -1
  99. package/dist/utils/version.d.ts +2 -1
  100. package/dist/utils/version.js +10 -8
  101. package/dist/utils/version.js.map +1 -1
  102. package/package.json +27 -26
  103. package/src/api/artifacts.ts +81 -9
  104. package/src/api/build.ts +468 -88
  105. package/src/api/create-npm-dirs.ts +57 -9
  106. package/src/api/new.ts +89 -31
  107. package/src/api/pre-publish.ts +13 -7
  108. package/src/api/rename.ts +10 -1
  109. package/src/api/templates/cargo.toml.ts +1 -0
  110. package/src/api/templates/ci-template.ts +150 -125
  111. package/src/api/templates/ci.yml.ts +27 -6
  112. package/src/api/templates/js-binding.ts +147 -220
  113. package/src/api/templates/lib.rs.ts +1 -4
  114. package/src/api/templates/load-wasi-template.ts +182 -0
  115. package/src/api/templates/package.json.ts +47 -5
  116. package/src/api/templates/wasi-worker-template.ts +122 -0
  117. package/src/api/universalize.ts +13 -8
  118. package/src/api/version.ts +5 -2
  119. package/src/commands/artifacts.ts +2 -2
  120. package/src/commands/build.ts +1 -1
  121. package/src/commands/new.ts +46 -45
  122. package/src/def/artifacts.ts +22 -3
  123. package/src/def/build.ts +64 -8
  124. package/src/def/create-npm-dirs.ts +9 -0
  125. package/src/def/new.ts +28 -3
  126. package/src/def/pre-publish.ts +12 -3
  127. package/src/def/rename.ts +11 -2
  128. package/src/def/universalize.ts +9 -0
  129. package/src/def/version.ts +9 -0
  130. package/src/index.ts +2 -0
  131. package/src/utils/__tests__/__fixtures__/napi_type_def +130 -130
  132. package/src/utils/__tests__/__snapshots__/config.spec.ts.md +97 -0
  133. package/src/utils/__tests__/__snapshots__/config.spec.ts.snap +0 -0
  134. package/src/utils/__tests__/__snapshots__/target.spec.ts.md +28 -0
  135. package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
  136. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +711 -158
  137. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
  138. package/src/utils/__tests__/__snapshots__/version.spec.ts.md +8 -7
  139. package/src/utils/__tests__/__snapshots__/version.spec.ts.snap +0 -0
  140. package/src/utils/__tests__/config.spec.ts +81 -0
  141. package/src/utils/__tests__/typegen.spec.ts +18 -3
  142. package/src/utils/cargo.ts +2 -2
  143. package/src/utils/config.ts +116 -10
  144. package/src/utils/index.ts +0 -1
  145. package/src/utils/metadata.ts +52 -14
  146. package/src/utils/misc.ts +11 -3
  147. package/src/utils/target.ts +22 -4
  148. package/src/utils/typegen.ts +98 -49
  149. package/src/utils/version.ts +10 -8
  150. package/dist/api/load-wasi-template.d.ts +0 -1
  151. package/dist/api/load-wasi-template.js +0 -64
  152. package/dist/api/load-wasi-template.js.map +0 -1
  153. package/dist/api/wasi-worker-template.d.ts +0 -1
  154. package/dist/api/wasi-worker-template.js +0 -53
  155. package/dist/api/wasi-worker-template.js.map +0 -1
  156. package/dist/utils/ci.d.ts +0 -11
  157. package/dist/utils/ci.js +0 -96
  158. package/dist/utils/ci.js.map +0 -1
  159. package/src/api/load-wasi-template.ts +0 -66
  160. package/src/api/wasi-worker-template.ts +0 -52
  161. package/src/utils/ci.ts +0 -111
package/dist/api/build.js CHANGED
@@ -1,21 +1,28 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { createHash } from 'node:crypto';
3
+ import { existsSync, mkdirSync, unlinkSync, readFileSync, writeFileSync, } 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
  import * as colors from 'colorette';
8
+ import { groupBy, split } from 'lodash-es';
9
+ import { include as setjmpInclude, lib as setjmpLib } from 'wasm-sjlj';
7
10
  import { CLI_VERSION, copyFileAsync, debugFactory, DEFAULT_TYPE_DEF_HEADER, fileExists, getSystemDefaultTarget, getTargetLinker, mkdirAsync, parseMetadata, parseTriple, processTypeDef, readFileAsync, readNapiConfig, targetToEnvVar, tryInstallCargoBinary, unlinkAsync, writeFileAsync, } from '../utils/index.js';
8
- import { createWasiBinding } from './load-wasi-template.js';
9
- import { createCjsBinding } from './templates/index.js';
10
- import { WASI_WORKER_TEMPLATE } from './wasi-worker-template.js';
11
+ import { createCjsBinding, createEsmBinding } from './templates/index.js';
12
+ import { createWasiBinding, createWasiBrowserBinding, } from './templates/load-wasi-template.js';
13
+ import { createWasiBrowserWorkerBinding, WASI_WORKER_TEMPLATE, } from './templates/wasi-worker-template.js';
11
14
  const debug = debugFactory('build');
12
15
  const require = createRequire(import.meta.url);
13
16
  export async function buildProject(options) {
14
17
  debug('napi build command receive options: %O', options);
18
+ options = {
19
+ dtsCache: true,
20
+ ...options,
21
+ };
15
22
  const cwd = options.cwd ?? process.cwd();
16
23
  const resolvePath = (...paths) => resolve(cwd, ...paths);
17
24
  const manifestPath = resolvePath(options.manifestPath ?? 'Cargo.toml');
18
- const metadata = parseMetadata(manifestPath);
25
+ const metadata = await parseMetadata(manifestPath);
19
26
  const pkg = metadata.packages.find((p) => {
20
27
  // package with given name
21
28
  if (options.package) {
@@ -28,6 +35,9 @@ export async function buildProject(options) {
28
35
  if (!pkg) {
29
36
  throw new Error('Unable to find crate to build. It seems you are trying to build a crate in a workspace, try using `--package` option to specify the package to build.');
30
37
  }
38
+ const depsNapiPackages = pkg.dependencies
39
+ .map((p) => metadata.packages.find((c) => c.name === p.name))
40
+ .filter((c) => c != null && c.dependencies.some((d) => d.name == 'napi-derive'));
31
41
  const crateDir = parse(pkg.manifest_path).dir;
32
42
  const builder = new Builder(options, pkg, cwd, options.target
33
43
  ? parseTriple(options.target)
@@ -35,7 +45,7 @@ export async function buildProject(options) {
35
45
  ? parseTriple(process.env.CARGO_BUILD_TARGET)
36
46
  : getSystemDefaultTarget(), crateDir, resolvePath(options.outputDir ?? crateDir), options.targetDir ??
37
47
  process.env.CARGO_BUILD_TARGET_DIR ??
38
- metadata.target_directory, await readNapiConfig(resolvePath(options.packageJsonPath ?? 'package.json')));
48
+ metadata.target_directory, await readNapiConfig(resolvePath(options.configPath ?? options.packageJsonPath ?? 'package.json'), options.configPath ? resolvePath(options.configPath) : undefined), depsNapiPackages);
39
49
  return builder.build();
40
50
  }
41
51
  class Builder {
@@ -47,10 +57,11 @@ class Builder {
47
57
  outputDir;
48
58
  targetDir;
49
59
  config;
60
+ depsNapiPackages;
50
61
  args = [];
51
62
  envs = {};
52
63
  outputs = [];
53
- constructor(options, crate, cwd, target, crateDir, outputDir, targetDir, config) {
64
+ constructor(options, crate, cwd, target, crateDir, outputDir, targetDir, config, depsNapiPackages) {
54
65
  this.options = options;
55
66
  this.crate = crate;
56
67
  this.cwd = cwd;
@@ -59,6 +70,7 @@ class Builder {
59
70
  this.outputDir = outputDir;
60
71
  this.targetDir = targetDir;
61
72
  this.config = config;
73
+ this.depsNapiPackages = depsNapiPackages;
62
74
  }
63
75
  get cdyLibName() {
64
76
  return this.crate.targets.find((t) => t.crate_types.includes('cdylib'))
@@ -85,16 +97,95 @@ class Builder {
85
97
  .setPackage()
86
98
  .setFeatures()
87
99
  .setTarget()
100
+ .pickCrossToolchain()
88
101
  .setEnvs()
89
102
  .setBypassArgs()
90
103
  .exec();
91
104
  }
105
+ pickCrossToolchain() {
106
+ if (!this.options.useNapiCross) {
107
+ return this;
108
+ }
109
+ if (this.options.useCross) {
110
+ debug.warn('You are trying to use both `--cross` and `--use-napi-cross` options, `--use-cross` will be ignored.');
111
+ }
112
+ if (this.options.crossCompile) {
113
+ debug.warn('You are trying to use both `--cross-compile` and `--use-napi-cross` options, `--cross-compile` will be ignored.');
114
+ }
115
+ try {
116
+ const { version, download } = require('@napi-rs/cross-toolchain');
117
+ const alias = {
118
+ 's390x-unknown-linux-gnu': 's390x-ibm-linux-gnu',
119
+ };
120
+ const toolchainPath = join(homedir(), '.napi-rs', 'cross-toolchain', version, this.target.triple);
121
+ mkdirSync(toolchainPath, { recursive: true });
122
+ if (existsSync(join(toolchainPath, 'package.json'))) {
123
+ debug(`Toolchain ${toolchainPath} exists, skip extracting`);
124
+ }
125
+ else {
126
+ const tarArchive = download(process.arch, this.target.triple);
127
+ tarArchive.unpack(toolchainPath);
128
+ }
129
+ const upperCaseTarget = targetToEnvVar(this.target.triple);
130
+ const crossTargetName = alias[this.target.triple] ?? this.target.triple;
131
+ const linkerEnv = `CARGO_TARGET_${upperCaseTarget}_LINKER`;
132
+ this.envs[linkerEnv] = join(toolchainPath, 'bin', `${crossTargetName}-gcc`);
133
+ if (!process.env.TARGET_SYSROOT) {
134
+ this.envs[`TARGET_SYSROOT`] = join(toolchainPath, crossTargetName, 'sysroot');
135
+ }
136
+ if (!process.env.TARGET_AR) {
137
+ this.envs[`TARGET_AR`] = join(toolchainPath, 'bin', `${crossTargetName}-ar`);
138
+ }
139
+ if (!process.env.TARGET_RANLIB) {
140
+ this.envs[`TARGET_RANLIB`] = join(toolchainPath, 'bin', `${crossTargetName}-ranlib`);
141
+ }
142
+ if (!process.env.TARGET_READELF) {
143
+ this.envs[`TARGET_READELF`] = join(toolchainPath, 'bin', `${crossTargetName}-readelf`);
144
+ }
145
+ if (!process.env.TARGET_C_INCLUDE_PATH) {
146
+ this.envs[`TARGET_C_INCLUDE_PATH`] = join(toolchainPath, crossTargetName, 'sysroot', 'usr', 'include/');
147
+ }
148
+ if (!process.env.CC && !process.env.TARGET_CC) {
149
+ this.envs[`CC`] = join(toolchainPath, 'bin', `${crossTargetName}-gcc`);
150
+ this.envs[`TARGET_CC`] = join(toolchainPath, 'bin', `${crossTargetName}-gcc`);
151
+ }
152
+ if (!process.env.CXX && !process.env.TARGET_CXX) {
153
+ this.envs[`CXX`] = join(toolchainPath, 'bin', `${crossTargetName}-g++`);
154
+ this.envs[`TARGET_CXX`] = join(toolchainPath, 'bin', `${crossTargetName}-g++`);
155
+ }
156
+ if ((process.env.CC?.startsWith('clang') &&
157
+ (process.env.TARGET_CC?.startsWith('clang') ||
158
+ !process.env.TARGET_CC)) ||
159
+ process.env.TARGET_CC?.startsWith('clang')) {
160
+ const CFLAGS = process.env.CFLAGS ?? '';
161
+ this.envs.CFLAGS = `--sysroot=${this.envs.TARGET_SYSROOT} --gcc-toolchain=${toolchainPath} ${CFLAGS}`;
162
+ }
163
+ if ((process.env.CXX?.startsWith('clang++') &&
164
+ (process.env.TARGET_CXX?.startsWith('clang++') ||
165
+ !process.env.TARGET_CXX)) ||
166
+ process.env.TARGET_CXX?.startsWith('clang++')) {
167
+ const CXXFLAGS = process.env.CXXFLAGS ?? '';
168
+ this.envs.CXXFLAGS = `--sysroot=${this.envs.TARGET_SYSROOT} --gcc-toolchain=${toolchainPath} ${CXXFLAGS} ${CXXFLAGS}`;
169
+ }
170
+ this.envs.PATH = this.envs.PATH
171
+ ? `${toolchainPath}/bin:${this.envs.PATH}:${process.env.PATH}`
172
+ : `${toolchainPath}/bin:${process.env.PATH}`;
173
+ }
174
+ catch (e) {
175
+ debug.warn('Pick cross toolchain failed', e);
176
+ // ignore, do nothing
177
+ }
178
+ return this;
179
+ }
92
180
  exec() {
93
181
  debug(`Start building crate: ${this.crate.name}`);
94
182
  debug(' %i', `cargo ${this.args.join(' ')}`);
95
183
  const controller = new AbortController();
96
184
  const watch = this.options.watch;
97
185
  const buildTask = new Promise((resolve, reject) => {
186
+ if (this.options.useCross && this.options.crossCompile) {
187
+ throw new Error('`--use-cross` and `--cross-compile` can not be used together');
188
+ }
98
189
  const command = process.env.CARGO ?? (this.options.useCross ? 'cross' : 'cargo');
99
190
  const buildProcess = spawn(command, this.args, {
100
191
  env: {
@@ -123,7 +214,7 @@ class Builder {
123
214
  buildProcess.stderr?.on('data', (data) => {
124
215
  const output = data.toString();
125
216
  console.error(output);
126
- if (/Finished\s(dev|release)/.test(output)) {
217
+ if (/Finished\s(`dev`|`release`)/.test(output)) {
127
218
  this.postBuild().catch(() => { });
128
219
  }
129
220
  });
@@ -221,11 +312,68 @@ class Builder {
221
312
  setEnvs() {
222
313
  // type definition intermediate file
223
314
  this.envs.TYPE_DEF_TMP_PATH = this.getIntermediateTypeFile();
224
- // WASI register intermediate file
225
- this.envs.WASI_REGISTER_TMP_PATH = this.getIntermediateWasiRegisterFile();
226
- // TODO:
227
- // remove after napi-derive@v3 release
228
- this.envs.CARGO_CFG_NAPI_RS_CLI_VERSION = CLI_VERSION;
315
+ // Validate the packages and dependencies
316
+ if (existsSync(this.envs.TYPE_DEF_TMP_PATH)) {
317
+ const { depsNapiPackages, crate } = this;
318
+ let shouldInvalidateSelf = false;
319
+ const content = readFileSync(this.envs.TYPE_DEF_TMP_PATH, 'utf-8');
320
+ const typedefRaw = content
321
+ .split('\n')
322
+ .filter((line) => line.trim().length)
323
+ .map((line) => {
324
+ const [pkgName, ...jsonContents] = split(line, ':');
325
+ return {
326
+ pkgName,
327
+ jsonContent: jsonContents.join(':'),
328
+ };
329
+ });
330
+ const groupedTypedefRaw = groupBy(typedefRaw, ({ pkgName }) => pkgName);
331
+ const invalidPackages = new Set();
332
+ for (const [pkgName, value] of Object.entries(groupedTypedefRaw)) {
333
+ const packageInvalidKey = `NAPI_PACKAGE_${pkgName.toUpperCase().replaceAll('-', '_')}_INVALID`;
334
+ let done = false;
335
+ for (const { jsonContent } of value) {
336
+ try {
337
+ // package_name: { "done": true } was written by napi-build in project build.rs
338
+ // if it exists, the package was successfully built and typedef was written
339
+ const json = JSON.parse(jsonContent);
340
+ if (json.done === true) {
341
+ done = true;
342
+ break;
343
+ }
344
+ }
345
+ catch {
346
+ done = false;
347
+ break;
348
+ }
349
+ }
350
+ if (!done) {
351
+ process.env[packageInvalidKey] = `${Date.now()}`;
352
+ shouldInvalidateSelf = true;
353
+ invalidPackages.add(pkgName);
354
+ }
355
+ }
356
+ const typedefPackages = new Set(Object.keys(groupedTypedefRaw));
357
+ for (const crate of depsNapiPackages) {
358
+ if (!typedefPackages.has(crate.name)) {
359
+ debug('Set invalid package typedef: %i', crate.name);
360
+ shouldInvalidateSelf = true;
361
+ process.env[`NAPI_PACKAGE_${crate.name.toUpperCase().replaceAll('-', '_')}_INVALID`] = `${Date.now()}`;
362
+ }
363
+ }
364
+ if (shouldInvalidateSelf) {
365
+ debug('Set invalid package typedef: %i', crate.name);
366
+ process.env[`NAPI_PACKAGE_${crate.name.toUpperCase().replaceAll('-', '_')}_INVALID`] = `${Date.now()}`;
367
+ }
368
+ // clean invalid packages typedef
369
+ if (invalidPackages.size) {
370
+ debug('Clean invalid packages typedef: %O', invalidPackages);
371
+ writeFileSync(this.envs.TYPE_DEF_TMP_PATH, typedefRaw
372
+ .filter(({ pkgName }) => !invalidPackages.has(pkgName))
373
+ .map(({ pkgName, jsonContent }) => `${pkgName}:${jsonContent}`)
374
+ .join('\n'));
375
+ }
376
+ }
229
377
  // RUSTFLAGS
230
378
  let rustflags = process.env.RUSTFLAGS ?? process.env.CARGO_BUILD_RUSTFLAGS ?? '';
231
379
  if (this.target.abi?.includes('musl') &&
@@ -248,7 +396,7 @@ class Builder {
248
396
  // will detect by cargo config when it becomes stable
249
397
  // see: https://github.com/rust-lang/cargo/issues/9301
250
398
  const linkerEnv = `CARGO_TARGET_${targetToEnvVar(this.target.triple)}_LINKER`;
251
- if (linker && !process.env[linkerEnv]) {
399
+ if (linker && !process.env[linkerEnv] && !this.envs[linkerEnv]) {
252
400
  this.envs[linkerEnv] = linker;
253
401
  }
254
402
  if (this.target.platform === 'android') {
@@ -266,10 +414,10 @@ class Builder {
266
414
  Object.assign(this.envs, {
267
415
  CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-android24-clang`,
268
416
  CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-androideabi24-clang`,
269
- CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
270
- CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
271
- AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ar`,
272
- RANLIB: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ranlib`,
417
+ TARGET_CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
418
+ TARGET_CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
419
+ TARGET_AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ar`,
420
+ TARGET_RANLIB: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ranlib`,
273
421
  ANDROID_NDK: ANDROID_NDK_LATEST_HOME,
274
422
  PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin:${process.env.PATH}`,
275
423
  });
@@ -278,6 +426,21 @@ class Builder {
278
426
  if (this.target.platform === 'wasi') {
279
427
  const emnapi = join(require.resolve('emnapi'), '..', 'lib', 'wasm32-wasi-threads');
280
428
  this.envs.EMNAPI_LINK_DIR = emnapi;
429
+ this.envs.SETJMP_LINK_DIR = setjmpLib;
430
+ const { WASI_SDK_PATH } = process.env;
431
+ if (WASI_SDK_PATH && existsSync(WASI_SDK_PATH)) {
432
+ this.envs.CARGO_TARGET_WASM32_WASI_PREVIEW1_THREADS_LINKER = join(WASI_SDK_PATH, 'bin', 'wasm-ld');
433
+ this.envs.CARGO_TARGET_WASM32_WASIP1_LINKER = join(WASI_SDK_PATH, 'bin', 'wasm-ld');
434
+ this.envs.CARGO_TARGET_WASM32_WASIP1_THREADS_LINKER = join(WASI_SDK_PATH, 'bin', 'wasm-ld');
435
+ this.envs.CARGO_TARGET_WASM32_WASIP2_LINKER = join(WASI_SDK_PATH, 'bin', 'wasm-ld');
436
+ this.setEnvIfNotExists('CC', join(WASI_SDK_PATH, 'bin', 'clang'));
437
+ this.setEnvIfNotExists('CXX', join(WASI_SDK_PATH, 'bin', 'clang++'));
438
+ this.setEnvIfNotExists('AR', join(WASI_SDK_PATH, 'bin', 'ar'));
439
+ this.setEnvIfNotExists('RANLIB', join(WASI_SDK_PATH, 'bin', 'ranlib'));
440
+ this.setEnvIfNotExists('CFLAGS', `--target=wasm32-wasi-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj -I${setjmpInclude}`);
441
+ this.setEnvIfNotExists('CXXFLAGS', `--target=wasm32-wasi-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj -I${setjmpInclude}`);
442
+ this.setEnvIfNotExists(`LDFLAGS`, `-fuse-ld=${WASI_SDK_PATH}/bin/wasm-ld --target=wasm32-wasi-threads`);
443
+ }
281
444
  }
282
445
  debug('Set envs: ');
283
446
  Object.entries(this.envs).forEach(([k, v]) => {
@@ -287,13 +450,16 @@ class Builder {
287
450
  }
288
451
  setFeatures() {
289
452
  const args = [];
453
+ if (this.options.allFeatures && this.options.noDefaultFeatures) {
454
+ throw new Error('Cannot specify --all-features and --no-default-features together');
455
+ }
290
456
  if (this.options.allFeatures) {
291
457
  args.push('--all-features');
292
458
  }
293
459
  else if (this.options.noDefaultFeatures) {
294
460
  args.push('--no-default-features');
295
461
  }
296
- else if (this.options.features) {
462
+ if (this.options.features) {
297
463
  args.push('--features', ...this.options.features);
298
464
  }
299
465
  debug('Set features flags: ');
@@ -314,24 +480,28 @@ class Builder {
314
480
  if (this.options.profile) {
315
481
  this.args.push('--profile', this.options.profile);
316
482
  }
483
+ if (this.options.manifestPath) {
484
+ this.args.push('--manifest-path', this.options.manifestPath);
485
+ }
317
486
  if (this.options.cargoOptions?.length) {
318
487
  this.args.push(...this.options.cargoOptions);
319
488
  }
320
489
  return this;
321
490
  }
322
491
  getIntermediateTypeFile() {
323
- return join(tmpdir(), `${this.crate.name}-${createHash('sha256')
492
+ const dtsPath = join(tmpdir(), `${this.crate.name}-${createHash('sha256')
324
493
  .update(this.crate.manifest_path)
325
494
  .update(CLI_VERSION)
326
495
  .digest('hex')
327
- .substring(0, 8)}.napi_type_def.tmp`);
328
- }
329
- getIntermediateWasiRegisterFile() {
330
- return join(tmpdir(), `${this.crate.name}-${createHash('sha256')
331
- .update(this.crate.manifest_path)
332
- .update(CLI_VERSION)
333
- .digest('hex')
334
- .substring(0, 8)}.napi_wasi_register.tmp`);
496
+ .substring(0, 8)}.napi_type_def`);
497
+ if (!this.options.dtsCache) {
498
+ try {
499
+ unlinkSync(dtsPath);
500
+ }
501
+ catch { }
502
+ return `${dtsPath}_${Date.now()}.tmp`;
503
+ }
504
+ return `${dtsPath}.tmp`;
335
505
  }
336
506
  async postBuild() {
337
507
  try {
@@ -345,30 +515,23 @@ class Builder {
345
515
  cause: e,
346
516
  });
347
517
  }
348
- const dest = await this.copyArtifact();
518
+ const wasmBinaryName = await this.copyArtifact();
349
519
  // only for cdylib
350
520
  if (this.cdyLibName) {
351
521
  const idents = await this.generateTypeDef();
352
- const intermediateWasiRegisterFile = this.envs.WASI_REGISTER_TMP_PATH;
353
- const wasiRegisterFunctions = this.target.arch === 'wasm32'
354
- ? JSON.parse(await readFileAsync(intermediateWasiRegisterFile, 'utf8').catch((err) => {
355
- console.warn(`Read ${colors.yellowBright(intermediateWasiRegisterFile)} failed, reason: ${err.message}`);
356
- return `[]`;
357
- }))
358
- : [];
359
522
  const jsOutput = await this.writeJsBinding(idents);
360
- const wasmOutput = await this.writeWasiBinding(wasiRegisterFunctions, dest ?? 'index.wasm', idents);
523
+ const wasmBindingsOutput = await this.writeWasiBinding(wasmBinaryName, idents);
361
524
  if (jsOutput) {
362
525
  this.outputs.push(jsOutput);
363
526
  }
364
- if (wasmOutput) {
365
- this.outputs.push(wasmOutput);
527
+ if (wasmBindingsOutput) {
528
+ this.outputs.push(...wasmBindingsOutput);
366
529
  }
367
530
  }
368
531
  return this.outputs;
369
532
  }
370
533
  async copyArtifact() {
371
- const [srcName, destName] = this.getArtifactNames();
534
+ const [srcName, destName, wasmBinaryName] = this.getArtifactNames();
372
535
  if (!srcName || !destName) {
373
536
  return;
374
537
  }
@@ -376,6 +539,7 @@ class Builder {
376
539
  const src = join(this.targetDir, this.target.triple, profile, srcName);
377
540
  debug(`Copy artifact from: [${src}]`);
378
541
  const dest = join(this.outputDir, destName);
542
+ const isWasm = dest.endsWith('.wasm');
379
543
  try {
380
544
  if (await fileExists(dest)) {
381
545
  debug('Old artifact found, remove it first');
@@ -383,12 +547,44 @@ class Builder {
383
547
  }
384
548
  debug('Copy artifact to:');
385
549
  debug(' %i', dest);
386
- await copyFileAsync(src, dest);
550
+ if (isWasm) {
551
+ const { ModuleConfig } = await import('@napi-rs/wasm-tools');
552
+ debug('Generate debug wasm module');
553
+ try {
554
+ const debugWasmModule = new ModuleConfig()
555
+ .generateDwarf(true)
556
+ .generateNameSection(true)
557
+ .generateProducersSection(true)
558
+ .preserveCodeTransform(true)
559
+ .strictValidate(false)
560
+ .parse(await readFileAsync(src));
561
+ const debugWasmBinary = debugWasmModule.emitWasm(true);
562
+ await writeFileAsync(dest.replace(/\.wasm$/, '.debug.wasm'), debugWasmBinary);
563
+ debug('Generate release wasm module');
564
+ const releaseWasmModule = new ModuleConfig()
565
+ .generateDwarf(false)
566
+ .generateNameSection(false)
567
+ .generateProducersSection(false)
568
+ .preserveCodeTransform(false)
569
+ .strictValidate(false)
570
+ .onlyStableFeatures(false)
571
+ .parse(debugWasmBinary);
572
+ const releaseWasmBinary = releaseWasmModule.emitWasm(false);
573
+ await writeFileAsync(dest, releaseWasmBinary);
574
+ }
575
+ catch (e) {
576
+ debug.warn(`Failed to generate debug wasm module: ${e.message ?? e}`);
577
+ await copyFileAsync(src, dest);
578
+ }
579
+ }
580
+ else {
581
+ await copyFileAsync(src, dest);
582
+ }
387
583
  this.outputs.push({
388
- kind: dest.endsWith('.node') ? 'node' : 'exe',
584
+ kind: dest.endsWith('.node') ? 'node' : isWasm ? 'wasm' : 'exe',
389
585
  path: dest,
390
586
  });
391
- return dest;
587
+ return wasmBinaryName ? join(this.outputDir, wasmBinaryName) : null;
392
588
  }
393
589
  catch (e) {
394
590
  throw new Error('Failed to copy artifact', {
@@ -399,6 +595,7 @@ class Builder {
399
595
  getArtifactNames() {
400
596
  if (this.cdyLibName) {
401
597
  const cdyLib = this.cdyLibName.replace(/-/g, '_');
598
+ const wasiTarget = this.config.targets.find((t) => t.platform === 'wasi');
402
599
  const srcName = this.target.platform === 'darwin'
403
600
  ? `lib${cdyLib}.dylib`
404
601
  : this.target.platform === 'win32'
@@ -414,12 +611,18 @@ class Builder {
414
611
  destName += `.${this.target.platformArchABI}`;
415
612
  }
416
613
  if (srcName.endsWith('.wasm')) {
417
- destName += '.wasi-wasm32.wasm';
614
+ destName += '.wasm';
418
615
  }
419
616
  else {
420
617
  destName += '.node';
421
618
  }
422
- return [srcName, destName];
619
+ return [
620
+ srcName,
621
+ destName,
622
+ wasiTarget
623
+ ? `${this.config.binaryName}.${wasiTarget.platformArchABI}.wasm`
624
+ : null,
625
+ ];
423
626
  }
424
627
  else if (this.binName) {
425
628
  const srcName = this.target.platform === 'win32' ? `${this.binName}.exe` : this.binName;
@@ -432,8 +635,16 @@ class Builder {
432
635
  return [];
433
636
  }
434
637
  const dest = join(this.outputDir, this.options.dts ?? 'index.d.ts');
435
- const { dts, exports } = await processTypeDef(this.envs.TYPE_DEF_TMP_PATH, !this.options.noDtsHeader
436
- ? this.options.dtsHeader ?? DEFAULT_TYPE_DEF_HEADER
638
+ const { dts, exports } = await processTypeDef(this.envs.TYPE_DEF_TMP_PATH, this.options.constEnum ?? this.config.constEnum ?? true, !this.options.noDtsHeader
639
+ ? (this.options.dtsHeader ??
640
+ (this.config.dtsHeaderFile
641
+ ? await readFileAsync(join(this.cwd, this.config.dtsHeaderFile), 'utf-8').catch(() => {
642
+ debug.warn(`Failed to read dts header file ${this.config.dtsHeaderFile}`);
643
+ return null;
644
+ })
645
+ : null) ??
646
+ this.config.dtsHeader ??
647
+ DEFAULT_TYPE_DEF_HEADER)
437
648
  : '');
438
649
  try {
439
650
  debug('Writing type def to:');
@@ -457,13 +668,14 @@ class Builder {
457
668
  idents.length === 0) {
458
669
  return;
459
670
  }
460
- const name = parse(this.options.jsBinding ?? 'index.js').name;
461
- const cjs = createCjsBinding(this.config.binaryName, this.config.packageName, idents);
671
+ const name = this.options.jsBinding ?? 'index.js';
672
+ const createBinding = this.options.esm ? createEsmBinding : createCjsBinding;
673
+ const binding = createBinding(this.config.binaryName, this.config.packageName, idents);
462
674
  try {
463
- const dest = join(this.outputDir, `${name}.js`);
675
+ const dest = join(this.outputDir, name);
464
676
  debug('Writing js binding to:');
465
677
  debug(' %i', dest);
466
- await writeFileAsync(dest, cjs, 'utf-8');
678
+ await writeFileAsync(dest, binding, 'utf-8');
467
679
  return {
468
680
  kind: 'js',
469
681
  path: dest,
@@ -473,26 +685,59 @@ class Builder {
473
685
  throw new Error('Failed to write js binding file', { cause: e });
474
686
  }
475
687
  }
476
- async writeWasiBinding(wasiRegisterFunctions, distFileName, idents) {
477
- if (distFileName && wasiRegisterFunctions.length) {
688
+ async writeWasiBinding(distFileName, idents) {
689
+ if (distFileName) {
478
690
  const { name, dir } = parse(distFileName);
479
- const newPath = join(dir, `${this.config.binaryName}.wasi.mjs`);
691
+ const bindingPath = join(dir, `${this.config.binaryName}.wasi.cjs`);
692
+ const browserBindingPath = join(dir, `${this.config.binaryName}.wasi-browser.js`);
480
693
  const workerPath = join(dir, 'wasi-worker.mjs');
481
- const declareCodes = `const { ${idents.join(', ')} } = binding\n`;
482
- const exportsCode = `export {\n${idents
483
- .map((ident) => ` ${ident}`)
484
- .join(',\n')}\n}`;
485
- await writeFileAsync(newPath, createWasiBinding(name, wasiRegisterFunctions) +
486
- declareCodes +
694
+ const browserWorkerPath = join(dir, 'wasi-worker-browser.mjs');
695
+ const browserEntryPath = join(dir, 'browser.js');
696
+ const exportsCode = `module.exports = __napiModule.exports\n` +
697
+ idents
698
+ .map((ident) => `module.exports.${ident} = __napiModule.exports.${ident}`)
699
+ .join('\n');
700
+ await writeFileAsync(bindingPath, createWasiBinding(name, this.config.packageName, this.config.wasm?.initialMemory, this.config.wasm?.maximumMemory) +
487
701
  exportsCode +
488
702
  '\n', 'utf8');
703
+ await writeFileAsync(browserBindingPath, createWasiBrowserBinding(name, this.config.wasm?.initialMemory, this.config.wasm?.maximumMemory, this.config.wasm?.browser?.fs, this.config.wasm?.browser?.asyncInit) +
704
+ `export default __napiModule.exports\n` +
705
+ idents
706
+ .map((ident) => `export const ${ident} = __napiModule.exports.${ident}`)
707
+ .join('\n') +
708
+ '\n', 'utf8');
489
709
  await writeFileAsync(workerPath, WASI_WORKER_TEMPLATE, 'utf8');
490
- return {
491
- kind: 'wasm',
492
- path: newPath,
493
- };
710
+ await writeFileAsync(browserWorkerPath, createWasiBrowserWorkerBinding(this.config.wasm?.browser?.fs ?? false), 'utf8');
711
+ await writeFileAsync(browserEntryPath, `export * from '${this.config.packageName}-wasm32-wasi'\n`);
712
+ return [
713
+ {
714
+ kind: 'js',
715
+ path: bindingPath,
716
+ },
717
+ {
718
+ kind: 'js',
719
+ path: browserBindingPath,
720
+ },
721
+ {
722
+ kind: 'js',
723
+ path: workerPath,
724
+ },
725
+ {
726
+ kind: 'js',
727
+ path: browserWorkerPath,
728
+ },
729
+ {
730
+ kind: 'js',
731
+ path: browserEntryPath,
732
+ },
733
+ ];
734
+ }
735
+ return [];
736
+ }
737
+ setEnvIfNotExists(env, value) {
738
+ if (!process.env[env]) {
739
+ this.envs[env] = value;
494
740
  }
495
- return null;
496
741
  }
497
742
  }
498
743
  //# sourceMappingURL=build.js.map