@napi-rs/cli 2.15.1 → 3.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/README.md +17 -78
  2. package/cli.mjs +12 -0
  3. package/dist/api/artifacts.d.ts +2 -0
  4. package/dist/api/artifacts.js +50 -0
  5. package/dist/api/build.d.ts +14 -0
  6. package/dist/api/build.js +404 -0
  7. package/dist/api/create-npm-dirs.d.ts +2 -0
  8. package/dist/api/create-npm-dirs.js +63 -0
  9. package/dist/api/new.d.ts +4 -0
  10. package/dist/api/new.js +154 -0
  11. package/dist/api/pre-publish.d.ts +2 -0
  12. package/dist/api/pre-publish.js +157 -0
  13. package/dist/api/rename.d.ts +2 -0
  14. package/dist/api/rename.js +28 -0
  15. package/dist/api/templates/.gitignore.d.ts +1 -0
  16. package/dist/api/templates/.gitignore.js +198 -0
  17. package/dist/api/templates/.npmignore.d.ts +1 -0
  18. package/dist/api/templates/.npmignore.js +14 -0
  19. package/dist/api/templates/build.rs.d.ts +1 -0
  20. package/dist/api/templates/build.rs.js +4 -0
  21. package/dist/api/templates/cargo.toml.d.ts +6 -0
  22. package/dist/api/templates/cargo.toml.js +25 -0
  23. package/dist/api/templates/ci-template.d.ts +1 -0
  24. package/dist/api/templates/ci-template.js +566 -0
  25. package/dist/api/templates/ci.yml.d.ts +1 -0
  26. package/dist/api/templates/ci.yml.js +92 -0
  27. package/dist/api/templates/index.d.ts +8 -0
  28. package/dist/api/templates/index.js +8 -0
  29. package/dist/api/templates/js-binding.d.ts +1 -0
  30. package/dist/api/templates/js-binding.js +124 -0
  31. package/dist/api/templates/lib.rs.d.ts +1 -0
  32. package/dist/api/templates/lib.rs.js +10 -0
  33. package/dist/api/templates/package.json.d.ts +8 -0
  34. package/dist/api/templates/package.json.js +30 -0
  35. package/dist/api/universalize.d.ts +2 -0
  36. package/dist/api/universalize.js +38 -0
  37. package/dist/api/version.d.ts +2 -0
  38. package/dist/api/version.js +16 -0
  39. package/dist/cli.d.ts +1 -0
  40. package/dist/cli.js +25 -0
  41. package/dist/commands/artifacts.d.ts +6 -0
  42. package/dist/commands/artifacts.js +19 -0
  43. package/dist/commands/build.d.ts +6 -0
  44. package/dist/commands/build.js +34 -0
  45. package/dist/commands/create-npm-dirs.d.ts +4 -0
  46. package/dist/commands/create-npm-dirs.js +7 -0
  47. package/dist/commands/help.d.ts +10 -0
  48. package/dist/commands/help.js +12 -0
  49. package/dist/commands/new.d.ts +12 -0
  50. package/dist/commands/new.js +112 -0
  51. package/dist/commands/pre-publish.d.ts +4 -0
  52. package/dist/commands/pre-publish.js +8 -0
  53. package/dist/commands/rename.d.ts +4 -0
  54. package/dist/commands/rename.js +7 -0
  55. package/dist/commands/universalize.d.ts +4 -0
  56. package/dist/commands/universalize.js +7 -0
  57. package/dist/commands/version.d.ts +4 -0
  58. package/dist/commands/version.js +7 -0
  59. package/dist/def/artifacts.d.ts +50 -0
  60. package/dist/def/artifacts.js +38 -0
  61. package/dist/def/build.d.ts +150 -0
  62. package/dist/def/build.js +105 -0
  63. package/dist/def/commands/artifacts.d.ts +15 -0
  64. package/dist/def/commands/artifacts.js +29 -0
  65. package/dist/def/commands/build.d.ts +53 -0
  66. package/dist/def/commands/build.js +105 -0
  67. package/dist/def/commands/create-npm-dirs.d.ts +15 -0
  68. package/dist/def/commands/create-npm-dirs.js +29 -0
  69. package/dist/def/commands/new.d.ts +27 -0
  70. package/dist/def/commands/new.js +53 -0
  71. package/dist/def/commands/pre-publish.d.ts +23 -0
  72. package/dist/def/commands/pre-publish.js +45 -0
  73. package/dist/def/commands/rename.d.ts +25 -0
  74. package/dist/def/commands/rename.js +49 -0
  75. package/dist/def/commands/universalize.d.ts +13 -0
  76. package/dist/def/commands/universalize.js +25 -0
  77. package/dist/def/commands/version.d.ts +13 -0
  78. package/dist/def/commands/version.js +25 -0
  79. package/dist/def/create-npm-dirs.d.ts +50 -0
  80. package/dist/def/create-npm-dirs.js +38 -0
  81. package/dist/def/new.d.ts +106 -0
  82. package/dist/def/new.js +66 -0
  83. package/dist/def/options/artifacts.d.ts +35 -0
  84. package/dist/def/options/artifacts.js +11 -0
  85. package/dist/def/options/build.d.ts +97 -0
  86. package/dist/def/options/build.js +3 -0
  87. package/dist/def/options/create-npm-dirs.d.ts +35 -0
  88. package/dist/def/options/create-npm-dirs.js +11 -0
  89. package/dist/def/options/new.d.ts +79 -0
  90. package/dist/def/options/new.js +15 -0
  91. package/dist/def/options/pre-publish.d.ts +65 -0
  92. package/dist/def/options/pre-publish.js +13 -0
  93. package/dist/def/options/rename.d.ts +75 -0
  94. package/dist/def/options/rename.js +11 -0
  95. package/dist/def/options/universalize.d.ts +28 -0
  96. package/dist/def/options/universalize.js +10 -0
  97. package/dist/def/options/version.d.ts +28 -0
  98. package/dist/def/options/version.js +10 -0
  99. package/dist/def/pre-publish.d.ts +88 -0
  100. package/dist/def/pre-publish.js +56 -0
  101. package/dist/def/rename.d.ts +100 -0
  102. package/dist/def/rename.js +58 -0
  103. package/dist/def/universalize.d.ts +41 -0
  104. package/dist/def/universalize.js +33 -0
  105. package/dist/def/version.d.ts +41 -0
  106. package/dist/def/version.js +33 -0
  107. package/dist/index.cjs +20641 -0
  108. package/dist/index.d.ts +30 -0
  109. package/dist/index.js +30 -0
  110. package/dist/utils/__tests__/target.spec.d.ts +1 -0
  111. package/dist/utils/__tests__/target.spec.js +10 -0
  112. package/dist/utils/__tests__/typegen.spec.d.ts +1 -0
  113. package/dist/utils/__tests__/typegen.spec.js +37 -0
  114. package/dist/utils/__tests__/version.spec.d.ts +1 -0
  115. package/dist/utils/__tests__/version.spec.js +5 -0
  116. package/dist/utils/cargo.d.ts +1 -0
  117. package/dist/utils/cargo.js +33 -0
  118. package/dist/utils/ci.d.ts +11 -0
  119. package/dist/utils/ci.js +86 -0
  120. package/dist/utils/config.d.ts +65 -0
  121. package/dist/utils/config.js +42 -0
  122. package/dist/utils/index.d.ts +9 -0
  123. package/dist/utils/index.js +9 -0
  124. package/dist/utils/log.d.ts +10 -0
  125. package/dist/utils/log.js +14 -0
  126. package/dist/utils/metadata.d.ts +24 -0
  127. package/dist/utils/metadata.js +19 -0
  128. package/dist/utils/misc.d.ts +13 -0
  129. package/dist/utils/misc.js +35 -0
  130. package/dist/utils/target.d.ts +30 -0
  131. package/dist/utils/target.js +109 -0
  132. package/dist/utils/typegen.d.ts +3 -0
  133. package/dist/utils/typegen.js +158 -0
  134. package/dist/utils/version.d.ts +11 -0
  135. package/dist/utils/version.js +59 -0
  136. package/package.json +63 -27
  137. package/src/api/artifacts.ts +93 -0
  138. package/src/api/build.ts +549 -0
  139. package/src/api/create-npm-dirs.ts +105 -0
  140. package/src/api/new.ts +206 -0
  141. package/src/api/pre-publish.ts +216 -0
  142. package/src/api/rename.ts +51 -0
  143. package/src/api/templates/.gitignore.ts +198 -0
  144. package/src/api/templates/.npmignore.ts +14 -0
  145. package/src/api/templates/build.rs.ts +4 -0
  146. package/src/api/templates/cargo.toml.ts +35 -0
  147. package/src/api/templates/ci-template.ts +566 -0
  148. package/src/api/templates/ci.yml.ts +116 -0
  149. package/src/api/templates/index.ts +8 -0
  150. package/src/api/templates/js-binding.ts +130 -0
  151. package/src/api/templates/lib.rs.ts +10 -0
  152. package/src/api/templates/package.json.ts +44 -0
  153. package/src/api/universalize.ts +76 -0
  154. package/src/api/version.ts +26 -0
  155. package/src/cli.ts +29 -0
  156. package/src/commands/artifacts.ts +23 -0
  157. package/src/commands/build.ts +42 -0
  158. package/src/commands/create-npm-dirs.ts +8 -0
  159. package/src/commands/help.ts +13 -0
  160. package/src/commands/new.ts +138 -0
  161. package/src/commands/pre-publish.ts +9 -0
  162. package/src/commands/rename.ts +8 -0
  163. package/src/commands/universalize.ts +8 -0
  164. package/src/commands/version.ts +8 -0
  165. package/src/def/artifacts.ts +79 -0
  166. package/src/def/build.ts +242 -0
  167. package/src/def/create-npm-dirs.ts +79 -0
  168. package/src/def/new.ts +144 -0
  169. package/src/def/pre-publish.ts +120 -0
  170. package/src/def/rename.ts +122 -0
  171. package/src/def/universalize.ts +66 -0
  172. package/src/def/version.ts +65 -0
  173. package/src/index.ts +31 -0
  174. package/src/utils/__tests__/__fixtures__/napi_type_def +201 -0
  175. package/src/utils/__tests__/__snapshots__/target.spec.ts.md +110 -0
  176. package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
  177. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +618 -0
  178. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
  179. package/src/utils/__tests__/__snapshots__/version.spec.ts.md +20 -0
  180. package/src/utils/__tests__/__snapshots__/version.spec.ts.snap +0 -0
  181. package/src/utils/__tests__/target.spec.ts +19 -0
  182. package/src/utils/__tests__/typegen.spec.ts +49 -0
  183. package/src/utils/__tests__/version.spec.ts +13 -0
  184. package/src/utils/cargo.ts +35 -0
  185. package/src/utils/ci.ts +102 -0
  186. package/src/utils/config.ts +123 -0
  187. package/src/utils/index.ts +9 -0
  188. package/src/utils/log.ts +34 -0
  189. package/src/utils/metadata.ts +59 -0
  190. package/src/utils/misc.ts +45 -0
  191. package/src/utils/target.ts +145 -0
  192. package/src/utils/typegen.ts +193 -0
  193. package/src/utils/version.ts +76 -0
  194. package/scripts/index.js +0 -153779
@@ -0,0 +1,549 @@
1
+ import { spawn } from 'child_process'
2
+ import { createHash } from 'crypto'
3
+ import { tmpdir } from 'os'
4
+ import { parse, join, resolve } from 'path'
5
+
6
+ import * as colors from 'colorette'
7
+
8
+ import { BuildOptions as RawBuildOptions } from '../def/build.js'
9
+ import {
10
+ CLI_VERSION,
11
+ copyFileAsync,
12
+ Crate,
13
+ debugFactory,
14
+ DEFAULT_TYPE_DEF_HEADER,
15
+ fileExists,
16
+ getSystemDefaultTarget,
17
+ getTargetLinker,
18
+ mkdirAsync,
19
+ NapiConfig,
20
+ parseMetadata,
21
+ parseTriple,
22
+ processTypeDef,
23
+ readNapiConfig,
24
+ Target,
25
+ targetToEnvVar,
26
+ tryInstallCargoBinary,
27
+ unlinkAsync,
28
+ writeFileAsync,
29
+ } from '../utils/index.js'
30
+
31
+ import { createJsBinding } from './templates/index.js'
32
+
33
+ const debug = debugFactory('build')
34
+
35
+ type OutputKind = 'js' | 'dts' | 'node' | 'exe'
36
+ type Output = {
37
+ kind: OutputKind
38
+ path: string
39
+ }
40
+
41
+ type BuildOptions = RawBuildOptions & {
42
+ cargoOptions?: string[]
43
+ }
44
+
45
+ export async function buildProject(options: BuildOptions) {
46
+ debug('napi build command receive options: %O', options)
47
+
48
+ const cwd = options.cwd ?? process.cwd()
49
+
50
+ const resolvePath = (...paths: string[]) => resolve(cwd, ...paths)
51
+
52
+ const manifestPath = resolvePath(options.manifestPath ?? 'Cargo.toml')
53
+ const metadata = parseMetadata(manifestPath)
54
+
55
+ const pkg = metadata.packages.find((p) => {
56
+ // package with given name
57
+ if (options.package) {
58
+ return p.name === options.package
59
+ } else {
60
+ return p.manifest_path === manifestPath
61
+ }
62
+ })
63
+
64
+ if (!pkg) {
65
+ throw new Error(
66
+ '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.',
67
+ )
68
+ }
69
+
70
+ const crateDir = parse(pkg.manifest_path).dir
71
+
72
+ const builder = new Builder(
73
+ options,
74
+ pkg,
75
+ cwd,
76
+ options.target
77
+ ? parseTriple(options.target)
78
+ : process.env.CARGO_BUILD_TARGET
79
+ ? parseTriple(process.env.CARGO_BUILD_TARGET)
80
+ : getSystemDefaultTarget(),
81
+ crateDir,
82
+ resolvePath(options.outputDir ?? crateDir),
83
+ options.targetDir ??
84
+ process.env.CARGO_BUILD_TARGET_DIR ??
85
+ metadata.target_directory,
86
+ await readNapiConfig(
87
+ resolvePath(options.packageJsonPath ?? 'package.json'),
88
+ ),
89
+ )
90
+
91
+ return builder.build()
92
+ }
93
+
94
+ class Builder {
95
+ private readonly args: string[] = []
96
+ private readonly envs: Record<string, string> = {}
97
+ private readonly outputs: Output[] = []
98
+
99
+ constructor(
100
+ private readonly options: BuildOptions,
101
+ private readonly crate: Crate,
102
+ private readonly cwd: string,
103
+ private readonly target: Target,
104
+ private readonly crateDir: string,
105
+ private readonly outputDir: string,
106
+ private readonly targetDir: string,
107
+ private readonly config: NapiConfig,
108
+ ) {}
109
+
110
+ get cdyLibName() {
111
+ return this.crate.targets.find((t) => t.crate_types.includes('cdylib'))
112
+ ?.name
113
+ }
114
+
115
+ get binName() {
116
+ return (
117
+ this.options.bin ??
118
+ // only available if not cdylib or bin name specified
119
+ (this.cdyLibName
120
+ ? null
121
+ : this.crate.targets.find((t) => t.crate_types.includes('bin'))?.name)
122
+ )
123
+ }
124
+
125
+ build() {
126
+ if (!this.cdyLibName) {
127
+ const warning =
128
+ 'Missing `crate-type = ["cdylib"]` in [lib] config. The build result will not be available as node addon.'
129
+
130
+ if (this.binName) {
131
+ debug.warn(warning)
132
+ } else {
133
+ throw new Error(warning)
134
+ }
135
+ }
136
+
137
+ return this.pickBinary()
138
+ .setPackage()
139
+ .setFeatures()
140
+ .setTarget()
141
+ .setEnvs()
142
+ .setBypassArgs()
143
+ .exec()
144
+ }
145
+
146
+ private exec() {
147
+ debug(`Start building crate: ${this.crate.name}`)
148
+ debug(' %i', `cargo ${this.args.join(' ')}`)
149
+
150
+ const controller = new AbortController()
151
+
152
+ const buildTask = new Promise<void>((resolve, reject) => {
153
+ const buildProcess = spawn('cargo', this.args, {
154
+ env: {
155
+ ...process.env,
156
+ ...this.envs,
157
+ },
158
+ stdio: 'inherit',
159
+ cwd: this.cwd,
160
+ signal: controller.signal,
161
+ })
162
+
163
+ buildProcess.once('exit', (code) => {
164
+ if (code === 0) {
165
+ debug('%i', `Build crate ${this.crate.name} successfully!`)
166
+ resolve()
167
+ } else {
168
+ reject(new Error(`Build failed with exit code ${code}`))
169
+ }
170
+ })
171
+
172
+ buildProcess.once('error', (e) => {
173
+ reject(
174
+ new Error(`Build failed with error: ${e.message}`, {
175
+ cause: e,
176
+ }),
177
+ )
178
+ })
179
+ })
180
+
181
+ return {
182
+ task: buildTask.then(() => this.postBuild()),
183
+ abort: () => controller.abort(),
184
+ }
185
+ }
186
+
187
+ private pickBinary() {
188
+ let set = false
189
+ if (this.options.watch) {
190
+ if (process.env.CI) {
191
+ debug.warn('Watch mode is not supported in CI environment')
192
+ } else {
193
+ debug('Use %i', 'cargo-watch')
194
+ tryInstallCargoBinary('cargo-watch', 'watch')
195
+ // yarn napi watch --target x86_64-unknown-linux-gnu [--cross-compile]
196
+ // ===>
197
+ // cargo watch [...] -- build --target x86_64-unknown-linux-gnu
198
+ // cargo watch [...] -- zigbuild --target x86_64-unknown-linux-gnu
199
+ this.args.push(
200
+ 'watch',
201
+ '--why',
202
+ '-i',
203
+ '*.{js,ts,node}',
204
+ '-w',
205
+ this.crateDir,
206
+ '--',
207
+ 'cargo',
208
+ )
209
+ set = true
210
+ }
211
+ }
212
+
213
+ if (this.options.crossCompile) {
214
+ if (this.target.platform === 'win32') {
215
+ if (process.platform === 'win32') {
216
+ debug.warn(
217
+ 'You are trying to cross compile to win32 platform on win32 platform which is unnecessary.',
218
+ )
219
+ } else {
220
+ // use cargo-xwin to cross compile to win32 platform
221
+ debug('Use %i', 'cargo-xwin')
222
+ tryInstallCargoBinary('cargo-xwin', 'xwin')
223
+ this.args.push('xwin', 'build')
224
+ if (this.target.arch === 'ia32') {
225
+ this.envs.XWIN_ARCH = 'x86'
226
+ }
227
+ set = true
228
+ }
229
+ } else {
230
+ if (
231
+ this.target.platform === 'linux' &&
232
+ process.platform === 'linux' &&
233
+ this.target.arch === process.arch &&
234
+ (function (abi: string | null) {
235
+ const glibcVersionRuntime =
236
+ // @ts-expect-error
237
+ process.report?.getReport()?.header?.glibcVersionRuntime
238
+ const libc = glibcVersionRuntime ? 'gnu' : 'musl'
239
+ return abi === libc
240
+ })(this.target.abi)
241
+ ) {
242
+ debug.warn(
243
+ 'You are trying to cross compile to linux target on linux platform which is unnecessary.',
244
+ )
245
+ } else if (
246
+ this.target.platform === 'darwin' &&
247
+ process.platform === 'darwin'
248
+ ) {
249
+ debug.warn(
250
+ 'You are trying to cross compile to darwin target on darwin platform which is unnecessary.',
251
+ )
252
+ } else {
253
+ // use cargo-zigbuild to cross compile to other platforms
254
+ debug('Use %i', 'cargo-zigbuild')
255
+ tryInstallCargoBinary('cargo-zigbuild', 'zigbuild')
256
+ this.args.push('zigbuild')
257
+ set = true
258
+ }
259
+ }
260
+ }
261
+
262
+ if (!set) {
263
+ this.args.push('build')
264
+ }
265
+ return this
266
+ }
267
+
268
+ private setPackage() {
269
+ const args = []
270
+
271
+ if (this.options.package) {
272
+ args.push('--package', this.options.package)
273
+ }
274
+
275
+ if (this.binName) {
276
+ args.push('--bin', this.binName)
277
+ }
278
+
279
+ if (args.length) {
280
+ debug('Set package flags: ')
281
+ debug(' %O', args)
282
+ this.args.push(...args)
283
+ }
284
+
285
+ return this
286
+ }
287
+
288
+ private setTarget() {
289
+ debug('Set compiling target to: ')
290
+ debug(' %i', this.target.triple)
291
+
292
+ this.args.push('--target', this.target.triple)
293
+
294
+ return this
295
+ }
296
+
297
+ private setEnvs() {
298
+ // type definition intermediate file
299
+ this.envs.TYPE_DEF_TMP_PATH = this.getIntermediateTypeFile()
300
+ this.envs.CARGO_CFG_NAPI_RS_CLI_VERSION = CLI_VERSION
301
+
302
+ // RUSTFLAGS
303
+ let rustflags =
304
+ process.env.RUSTFLAGS ?? process.env.CARGO_BUILD_RUSTFLAGS ?? ''
305
+
306
+ if (
307
+ this.target.abi?.includes('musl') &&
308
+ !rustflags.includes('target-feature=-crt-static')
309
+ ) {
310
+ rustflags += ' -C target-feature=-crt-static'
311
+ }
312
+
313
+ if (this.options.strip && !rustflags.includes('link-arg=-s')) {
314
+ rustflags += ' -C link-arg=-s'
315
+ }
316
+
317
+ if (rustflags.length) {
318
+ this.envs.RUSTFLAGS = rustflags
319
+ }
320
+ // END RUSTFLAGS
321
+
322
+ // LINKER
323
+ const linker = getTargetLinker(this.target.triple)
324
+ if (
325
+ linker &&
326
+ !process.env.RUSTC_LINKER &&
327
+ !process.env[`CARGET_TARGET_${targetToEnvVar(this.target.triple)}_LINKER`]
328
+ ) {
329
+ this.envs.RUSTC_LINKER = linker
330
+ }
331
+
332
+ if (this.target.platform === 'android') {
333
+ const { ANDROID_NDK_LATEST_HOME } = process.env
334
+ if (!ANDROID_NDK_LATEST_HOME) {
335
+ debug.warn(
336
+ `${colors.red(
337
+ 'ANDROID_NDK_LATEST_HOME',
338
+ )} environment variable is missing`,
339
+ )
340
+ }
341
+
342
+ const targetArch = this.target.arch === 'arm' ? 'armv7a' : 'aarch64'
343
+ const targetPlatform =
344
+ this.target.arch === 'arm' ? 'androideabi24' : 'android24'
345
+ Object.assign(this.envs, {
346
+ CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-android24-clang`,
347
+ CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-androideabi24-clang`,
348
+ CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
349
+ CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
350
+ AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar`,
351
+ ANDROID_NDK: ANDROID_NDK_LATEST_HOME,
352
+ PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${process.env.PATH}`,
353
+ })
354
+ }
355
+ // END LINKER
356
+
357
+ debug('Set envs: ')
358
+ Object.entries(this.envs).forEach(([k, v]) => {
359
+ debug(' %i', `${k}=${v}`)
360
+ })
361
+
362
+ return this
363
+ }
364
+
365
+ private setFeatures() {
366
+ const args = []
367
+ if (this.options.allFeatures) {
368
+ args.push('--all-features')
369
+ } else if (this.options.noDefaultFeatures) {
370
+ args.push('--no-default-features')
371
+ } else if (this.options.features) {
372
+ args.push('--features', ...this.options.features)
373
+ }
374
+
375
+ debug('Set features flags: ')
376
+ debug(' %O', args)
377
+ this.args.push(...args)
378
+
379
+ return this
380
+ }
381
+
382
+ private setBypassArgs() {
383
+ if (this.options.release) {
384
+ this.args.push('--release')
385
+ }
386
+
387
+ if (this.options.verbose) {
388
+ this.args.push('--verbose')
389
+ }
390
+
391
+ if (this.options.targetDir) {
392
+ this.args.push('--target-dir', this.options.targetDir)
393
+ }
394
+
395
+ if (this.options.cargoOptions?.length) {
396
+ this.args.push(...this.options.cargoOptions)
397
+ }
398
+
399
+ return this
400
+ }
401
+
402
+ private getIntermediateTypeFile() {
403
+ return join(
404
+ tmpdir(),
405
+ `${this.crate.name}-${createHash('sha256')
406
+ .update(this.crate.manifest_path)
407
+ .update(CLI_VERSION)
408
+ .digest('hex')
409
+ .substring(0, 8)}.napi_type_def.tmp`,
410
+ )
411
+ }
412
+
413
+ private async postBuild() {
414
+ try {
415
+ debug(`Try to create output directory:`)
416
+ debug(' %i', this.outputDir)
417
+ await mkdirAsync(this.outputDir, { recursive: true })
418
+ debug(`Output directory created`)
419
+ } catch (e) {
420
+ throw new Error(`Failed to create output directory ${this.outputDir}`, {
421
+ cause: e,
422
+ })
423
+ }
424
+
425
+ await this.copyArtifact()
426
+
427
+ // only for cdylib
428
+ if (this.cdyLibName) {
429
+ await this.generateTypeDef()
430
+ await this.writeJsBinding()
431
+ }
432
+
433
+ return this.outputs
434
+ }
435
+
436
+ private async copyArtifact() {
437
+ const [srcName, destName] = this.getArtifactNames()
438
+ if (!srcName || !destName) {
439
+ return
440
+ }
441
+
442
+ const src = join(
443
+ this.targetDir,
444
+ this.target.triple,
445
+ this.options.release ? 'release' : 'debug',
446
+ srcName,
447
+ )
448
+ const dest = join(this.outputDir, destName)
449
+
450
+ try {
451
+ if (await fileExists(dest)) {
452
+ debug('Old artifact found, remove it first')
453
+ await unlinkAsync(dest)
454
+ }
455
+ debug('Copy artifact to:')
456
+ debug(' %i', dest)
457
+ await copyFileAsync(src, dest)
458
+ this.outputs.push({
459
+ kind: dest.endsWith('.node') ? 'node' : 'exe',
460
+ path: dest,
461
+ })
462
+ } catch (e) {
463
+ throw new Error('Failed to copy artifact', {
464
+ cause: e,
465
+ })
466
+ }
467
+ }
468
+
469
+ private getArtifactNames() {
470
+ if (this.cdyLibName) {
471
+ const cdyLib = this.cdyLibName.replace(/-/g, '_')
472
+
473
+ const srcName =
474
+ this.target.platform === 'darwin'
475
+ ? `lib${cdyLib}.dylib`
476
+ : this.target.platform === 'win32'
477
+ ? `${cdyLib}.dll`
478
+ : `lib${cdyLib}.so`
479
+
480
+ let destName = this.config.binaryName
481
+ // add platform suffix to binary name
482
+ // index[.linux-x64-gnu].node
483
+ // ^^^^^^^^^^^^^^
484
+ if (this.options.platform) {
485
+ destName += `.${this.target.platformArchABI}`
486
+ }
487
+ destName += '.node'
488
+
489
+ return [srcName, destName]
490
+ } else if (this.binName) {
491
+ const srcName =
492
+ this.target.platform === 'win32' ? `${this.binName}.exe` : this.binName
493
+
494
+ return [srcName, srcName]
495
+ }
496
+
497
+ return []
498
+ }
499
+
500
+ private async generateTypeDef() {
501
+ if (!(await fileExists(this.envs.TYPE_DEF_TMP_PATH))) {
502
+ return
503
+ }
504
+
505
+ const dest = join(this.outputDir, this.options.dts ?? 'index.d.ts')
506
+
507
+ const dts = await processTypeDef(
508
+ this.envs.TYPE_DEF_TMP_PATH,
509
+ !this.options.noDtsHeader
510
+ ? this.options.dtsHeader ?? DEFAULT_TYPE_DEF_HEADER
511
+ : '',
512
+ )
513
+
514
+ try {
515
+ debug('Writing type def to:')
516
+ debug(' %i', dest)
517
+ await writeFileAsync(dest, dts, 'utf-8')
518
+ this.outputs.push({
519
+ kind: 'dts',
520
+ path: dest,
521
+ })
522
+ } catch (e) {
523
+ debug.error('Failed to write type def file')
524
+ debug.error(e as Error)
525
+ }
526
+ }
527
+
528
+ private async writeJsBinding() {
529
+ if (!this.options.platform || this.options.noJsBinding) {
530
+ return
531
+ }
532
+
533
+ const dest = join(this.outputDir, this.options.jsBinding ?? 'index.js')
534
+
535
+ const js = createJsBinding(this.config.binaryName, this.config.packageName)
536
+
537
+ try {
538
+ debug('Writing js binding to:')
539
+ debug(' %i', dest)
540
+ await writeFileAsync(dest, js, 'utf-8')
541
+ this.outputs.push({
542
+ kind: 'js',
543
+ path: dest,
544
+ })
545
+ } catch (e) {
546
+ throw new Error('Failed to write js binding file', { cause: e })
547
+ }
548
+ }
549
+ }
@@ -0,0 +1,105 @@
1
+ import { join, resolve } from 'path'
2
+
3
+ import {
4
+ applyDefaultCreateNpmDirsOptions,
5
+ CreateNpmDirsOptions,
6
+ } from '../def/create-npm-dirs.js'
7
+ import {
8
+ debugFactory,
9
+ readNapiConfig,
10
+ mkdirAsync as rawMkdirAsync,
11
+ pick,
12
+ writeFileAsync as rawWriteFileAsync,
13
+ Target,
14
+ } from '../utils/index.js'
15
+
16
+ const debug = debugFactory('create-npm-dirs')
17
+
18
+ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
19
+ const options = applyDefaultCreateNpmDirsOptions(userOptions)
20
+
21
+ async function mkdirAsync(dir: string) {
22
+ debug('Try to create dir: %i', dir)
23
+ if (options.dryRun) {
24
+ return
25
+ }
26
+
27
+ await rawMkdirAsync(dir, {
28
+ recursive: true,
29
+ })
30
+ }
31
+
32
+ async function writeFileAsync(file: string, content: string) {
33
+ debug('Writing file %i', file)
34
+
35
+ if (options.dryRun) {
36
+ debug(content)
37
+ return
38
+ }
39
+
40
+ await rawWriteFileAsync(file, content)
41
+ }
42
+
43
+ const packageJsonPath = resolve(options.cwd, options.packageJsonPath)
44
+ const npmPath = resolve(options.cwd, options.npmDir)
45
+
46
+ debug(`Read content from [${packageJsonPath}]`)
47
+
48
+ const { targets, binaryName, packageName, packageJson } =
49
+ await readNapiConfig(packageJsonPath)
50
+
51
+ for (const target of targets) {
52
+ const targetDir = join(npmPath, `${target.platformArchABI}`)
53
+ await mkdirAsync(targetDir)
54
+
55
+ const binaryFileName = `${binaryName}.${target.platformArchABI}.node`
56
+ const scopedPackageJson = {
57
+ name: `${packageName}-${target.platformArchABI}`,
58
+ version: packageJson.version,
59
+ os: [target.platform],
60
+ cpu: target.arch !== 'universal' ? [target.arch] : undefined,
61
+ main: binaryFileName,
62
+ files: [binaryFileName],
63
+ ...pick(
64
+ packageJson,
65
+ 'description',
66
+ 'keywords',
67
+ 'author',
68
+ 'authors',
69
+ 'homepage',
70
+ 'license',
71
+ 'engines',
72
+ 'publishConfig',
73
+ 'repository',
74
+ 'bugs',
75
+ ),
76
+ }
77
+
78
+ // Only works with yarn 3.1+
79
+ // https://github.com/yarnpkg/berry/pull/3981
80
+ if (target.abi === 'gnu') {
81
+ // @ts-expect-error
82
+ scopedPackageJson.libc = ['glibc']
83
+ } else if (target.abi === 'musl') {
84
+ // @ts-expect-error
85
+ scopedPackageJson.libc = ['musl']
86
+ }
87
+
88
+ const targetPackageJson = join(targetDir, 'package.json')
89
+ await writeFileAsync(
90
+ targetPackageJson,
91
+ JSON.stringify(scopedPackageJson, null, 2),
92
+ )
93
+ const targetReadme = join(targetDir, 'README.md')
94
+ await writeFileAsync(targetReadme, readme(packageName, target))
95
+
96
+ debug.info(`${packageName}-${target.platformArchABI} created`)
97
+ }
98
+ }
99
+
100
+ function readme(packageName: string, target: Target) {
101
+ return `# \`${packageName}-${target.platformArchABI}\`
102
+
103
+ This is the **${target.triple}** binary for \`${packageName}\`
104
+ `
105
+ }