@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
package/README.md CHANGED
@@ -9,88 +9,27 @@
9
9
 
10
10
  > Cli tools for napi-rs
11
11
 
12
+ ```sh
13
+ # or npm, pnpm
14
+ yarn add @napi-rs/cli -D
15
+ yarn napi build
16
+ ```
17
+
12
18
  ## Commands
13
19
 
20
+ | Command | desc | docs |
21
+ | --------------- | -------------------------------------------------------------- | --------------------------------------------------- |
22
+ | new | create new napi-rs project | [./docs/new.md](./docs/new.md) |
23
+ | build | build napi-rs project | [./docs/build.md](./docs/build.md) |
24
+ | create-npm-dirs | Create npm package dirs for different platforms | [./docs/create-npm-dirs](./docs/create-npm-dirs.md) |
25
+ | artifacts | Copy artifacts from Github Actions into specified dir | [./docs/artifacts.md](./docs/artifacts.md) |
26
+ | rename | Rename the napi-rs project | [./docs/rename.md](./docs/rename.md) |
27
+ | universalize | Combile built binaries into one universal binary | [./docs/universalize.md](./docs/universalize.md) |
28
+ | version | Update version in created npm packages by `create-npm-dirs` | [./docs/version.md](./docs/version.md) |
29
+ | pre-publish | Update package.json and copy addons into per platform packages | [./docs/pre-publish.md](./docs/pre-publish.md) |
30
+
14
31
  ### Debug mode
15
32
 
16
33
  ```bash
17
34
  DEBUG="napi:*" napi [command]
18
35
  ```
19
-
20
- ### `napi build`
21
-
22
- > Build command. Build rust codes and copy the dynamic lib binary file to the dist dir.
23
-
24
- #### `--platform`
25
-
26
- > default `false`
27
-
28
- Append `platform-arch-[abi]` name to dist file. eg: `index.darwin-x64.node`.
29
-
30
- #### `--release`
31
-
32
- > default `false`
33
-
34
- Is release build. This flag will be passed to `Cargo` directly.
35
-
36
- #### `--features`
37
-
38
- > default `''`
39
-
40
- Cargo features, passthrough to `cargo build` command.
41
-
42
- #### `--config,-c`
43
-
44
- > default `package.json`
45
-
46
- `napi-rs` config file name. `napi-rs` config example :
47
-
48
- ```js
49
- {
50
- "name": "@native-binding/fib",
51
- "version": "0.1.0",
52
- "napi": {
53
- "name": "fib", // binary name
54
- "triples": {
55
- "defaults": true, // default true, if this value is true, will build `x86_64-pc-windows-msvc`, `x86_64-apple-darwin` and `x86_64-unknown-linux-gnu`
56
- "additional": [
57
- "x86_64-unknown-linux-musl",
58
- "x86_64-unknown-freebsd",
59
- "aarch64-unknown-linux-gnu"
60
- ]
61
- }
62
- }
63
- }
64
- ```
65
-
66
- #### `--cargo-name`
67
-
68
- > default `undefined`
69
-
70
- If not set, cli will read the `package.name` field in `Cargo.toml` under `process.cwd()`. The `-` in the name will be replaced with `_`.
71
-
72
- #### `--target`
73
-
74
- > default `undefined`
75
-
76
- > Note you should have `rustup` installed if omit the `--target` flag. The `@napi-rs/cli` will try to find the default target on your system via `rustup` if no `--target` specified.
77
-
78
- You can also define this value using the `RUST_TARGET` environment variable.
79
-
80
- This value will be passed to `Cargo build` command directly. eg: `napi build --target x86_64-unknown-linux-musl`
81
-
82
- #### `--cargo-flags`
83
-
84
- > default `undefined`
85
-
86
- Other flags you want pass to `Cargo build`.
87
-
88
- #### `--cargo-cwd`
89
-
90
- > default `undefined`
91
-
92
- This flag can be used to build binaries that are not in the current directory. The path that is passed to this flag should be relative to the current directory.
93
-
94
- ### `napi artifacts`
95
-
96
- > Copy artifact files in Github actions.
package/cli.mjs ADDED
@@ -0,0 +1,12 @@
1
+ import { execSync } from 'child_process'
2
+ import { resolve } from 'path'
3
+ import { fileURLToPath } from 'url'
4
+
5
+ execSync(
6
+ `node --loader ts-node/esm/transpile-only ${resolve(fileURLToPath(import.meta.url), '../src/cli.ts')} ${process.argv
7
+ .slice(2)
8
+ .join(' ')}`,
9
+ {
10
+ stdio: 'inherit',
11
+ },
12
+ )
@@ -0,0 +1,2 @@
1
+ import { ArtifactsOptions } from '../def/artifacts.js';
2
+ export declare function collectArtifacts(userOptions: ArtifactsOptions): Promise<void>;
@@ -0,0 +1,50 @@
1
+ import { join, parse, resolve } from 'path';
2
+ import * as colors from 'colorette';
3
+ import { applyDefaultArtifactsOptions, } from '../def/artifacts.js';
4
+ import { readNapiConfig, debugFactory, readFileAsync, writeFileAsync, UniArchsByPlatform, readdirAsync, } from '../utils/index.js';
5
+ const debug = debugFactory('artifacts');
6
+ export async function collectArtifacts(userOptions) {
7
+ const options = applyDefaultArtifactsOptions(userOptions);
8
+ const packageJsonPath = resolve(options.cwd, options.packageJsonPath);
9
+ const { targets, binaryName } = await readNapiConfig(packageJsonPath);
10
+ const distDirs = targets.map((platform) => resolve(options.cwd, options.npmDir, platform.platformArchABI));
11
+ const universalSourceBins = new Set(targets
12
+ .filter((platform) => platform.arch === 'universal')
13
+ .flatMap((p) => UniArchsByPlatform[p.platform]?.map((a) => `${p.platform}-${a}`))
14
+ .filter(Boolean));
15
+ await collectNodeBinaries(resolve(options.cwd, options.outputDir)).then((output) => Promise.all(output.map(async (filePath) => {
16
+ debug.info(`Read [${colors.yellowBright(filePath)}]`);
17
+ const sourceContent = await readFileAsync(filePath);
18
+ const parsedName = parse(filePath);
19
+ const [_binaryName, platformArchABI] = parsedName.name.split('.');
20
+ if (_binaryName !== binaryName) {
21
+ debug.warn(`[${_binaryName}] is not matched with [${binaryName}], skip`);
22
+ return;
23
+ }
24
+ const dir = distDirs.find((dir) => dir.includes(platformArchABI));
25
+ if (!dir && universalSourceBins.has(platformArchABI)) {
26
+ debug.warn(`[${platformArchABI}] has no dist dir but it is source bin for universal arch, skip`);
27
+ return;
28
+ }
29
+ if (!dir) {
30
+ throw new Error(`No dist dir found for ${filePath}`);
31
+ }
32
+ const distFilePath = join(dir, parsedName.base);
33
+ debug.info(`Write file content to [${colors.yellowBright(distFilePath)}]`);
34
+ await writeFileAsync(distFilePath, sourceContent);
35
+ const distFilePathLocal = join(parse(packageJsonPath).dir, parsedName.base);
36
+ debug.info(`Write file content to [${colors.yellowBright(distFilePathLocal)}]`);
37
+ await writeFileAsync(distFilePathLocal, sourceContent);
38
+ })));
39
+ }
40
+ async function collectNodeBinaries(root) {
41
+ const files = await readdirAsync(root, { withFileTypes: true });
42
+ const nodeBinaries = files
43
+ .filter((file) => file.isFile() && file.name.endsWith('.node'))
44
+ .map((file) => join(root, file.name));
45
+ const dirs = files.filter((file) => file.isDirectory());
46
+ for (const dir of dirs) {
47
+ nodeBinaries.push(...(await collectNodeBinaries(join(root, dir.name))));
48
+ }
49
+ return nodeBinaries;
50
+ }
@@ -0,0 +1,14 @@
1
+ import { BuildOptions as RawBuildOptions } from '../def/build.js';
2
+ type OutputKind = 'js' | 'dts' | 'node' | 'exe';
3
+ type Output = {
4
+ kind: OutputKind;
5
+ path: string;
6
+ };
7
+ type BuildOptions = RawBuildOptions & {
8
+ cargoOptions?: string[];
9
+ };
10
+ export declare function buildProject(options: BuildOptions): Promise<{
11
+ task: Promise<Output[]>;
12
+ abort: () => void;
13
+ }>;
14
+ export {};
@@ -0,0 +1,404 @@
1
+ import { spawn } from 'child_process';
2
+ import { createHash } from 'crypto';
3
+ import { tmpdir } from 'os';
4
+ import { parse, join, resolve } from 'path';
5
+ import * as colors from 'colorette';
6
+ import { CLI_VERSION, copyFileAsync, debugFactory, DEFAULT_TYPE_DEF_HEADER, fileExists, getSystemDefaultTarget, getTargetLinker, mkdirAsync, parseMetadata, parseTriple, processTypeDef, readNapiConfig, targetToEnvVar, tryInstallCargoBinary, unlinkAsync, writeFileAsync, } from '../utils/index.js';
7
+ import { createJsBinding } from './templates/index.js';
8
+ const debug = debugFactory('build');
9
+ export async function buildProject(options) {
10
+ debug('napi build command receive options: %O', options);
11
+ const cwd = options.cwd ?? process.cwd();
12
+ const resolvePath = (...paths) => resolve(cwd, ...paths);
13
+ const manifestPath = resolvePath(options.manifestPath ?? 'Cargo.toml');
14
+ const metadata = parseMetadata(manifestPath);
15
+ const pkg = metadata.packages.find((p) => {
16
+ // package with given name
17
+ if (options.package) {
18
+ return p.name === options.package;
19
+ }
20
+ else {
21
+ return p.manifest_path === manifestPath;
22
+ }
23
+ });
24
+ if (!pkg) {
25
+ 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.');
26
+ }
27
+ const crateDir = parse(pkg.manifest_path).dir;
28
+ const builder = new Builder(options, pkg, cwd, options.target
29
+ ? parseTriple(options.target)
30
+ : process.env.CARGO_BUILD_TARGET
31
+ ? parseTriple(process.env.CARGO_BUILD_TARGET)
32
+ : getSystemDefaultTarget(), crateDir, resolvePath(options.outputDir ?? crateDir), options.targetDir ??
33
+ process.env.CARGO_BUILD_TARGET_DIR ??
34
+ metadata.target_directory, await readNapiConfig(resolvePath(options.packageJsonPath ?? 'package.json')));
35
+ return builder.build();
36
+ }
37
+ class Builder {
38
+ options;
39
+ crate;
40
+ cwd;
41
+ target;
42
+ crateDir;
43
+ outputDir;
44
+ targetDir;
45
+ config;
46
+ args = [];
47
+ envs = {};
48
+ outputs = [];
49
+ constructor(options, crate, cwd, target, crateDir, outputDir, targetDir, config) {
50
+ this.options = options;
51
+ this.crate = crate;
52
+ this.cwd = cwd;
53
+ this.target = target;
54
+ this.crateDir = crateDir;
55
+ this.outputDir = outputDir;
56
+ this.targetDir = targetDir;
57
+ this.config = config;
58
+ }
59
+ get cdyLibName() {
60
+ return this.crate.targets.find((t) => t.crate_types.includes('cdylib'))
61
+ ?.name;
62
+ }
63
+ get binName() {
64
+ return (this.options.bin ??
65
+ // only available if not cdylib or bin name specified
66
+ (this.cdyLibName
67
+ ? null
68
+ : this.crate.targets.find((t) => t.crate_types.includes('bin'))?.name));
69
+ }
70
+ build() {
71
+ if (!this.cdyLibName) {
72
+ const warning = 'Missing `crate-type = ["cdylib"]` in [lib] config. The build result will not be available as node addon.';
73
+ if (this.binName) {
74
+ debug.warn(warning);
75
+ }
76
+ else {
77
+ throw new Error(warning);
78
+ }
79
+ }
80
+ return this.pickBinary()
81
+ .setPackage()
82
+ .setFeatures()
83
+ .setTarget()
84
+ .setEnvs()
85
+ .setBypassArgs()
86
+ .exec();
87
+ }
88
+ exec() {
89
+ debug(`Start building crate: ${this.crate.name}`);
90
+ debug(' %i', `cargo ${this.args.join(' ')}`);
91
+ const controller = new AbortController();
92
+ const buildTask = new Promise((resolve, reject) => {
93
+ const buildProcess = spawn('cargo', this.args, {
94
+ env: {
95
+ ...process.env,
96
+ ...this.envs,
97
+ },
98
+ stdio: 'inherit',
99
+ cwd: this.cwd,
100
+ signal: controller.signal,
101
+ });
102
+ buildProcess.once('exit', (code) => {
103
+ if (code === 0) {
104
+ debug('%i', `Build crate ${this.crate.name} successfully!`);
105
+ resolve();
106
+ }
107
+ else {
108
+ reject(new Error(`Build failed with exit code ${code}`));
109
+ }
110
+ });
111
+ buildProcess.once('error', (e) => {
112
+ reject(new Error(`Build failed with error: ${e.message}`, {
113
+ cause: e,
114
+ }));
115
+ });
116
+ });
117
+ return {
118
+ task: buildTask.then(() => this.postBuild()),
119
+ abort: () => controller.abort(),
120
+ };
121
+ }
122
+ pickBinary() {
123
+ let set = false;
124
+ if (this.options.watch) {
125
+ if (process.env.CI) {
126
+ debug.warn('Watch mode is not supported in CI environment');
127
+ }
128
+ else {
129
+ debug('Use %i', 'cargo-watch');
130
+ tryInstallCargoBinary('cargo-watch', 'watch');
131
+ // yarn napi watch --target x86_64-unknown-linux-gnu [--cross-compile]
132
+ // ===>
133
+ // cargo watch [...] -- build --target x86_64-unknown-linux-gnu
134
+ // cargo watch [...] -- zigbuild --target x86_64-unknown-linux-gnu
135
+ this.args.push('watch', '--why', '-i', '*.{js,ts,node}', '-w', this.crateDir, '--', 'cargo');
136
+ set = true;
137
+ }
138
+ }
139
+ if (this.options.crossCompile) {
140
+ if (this.target.platform === 'win32') {
141
+ if (process.platform === 'win32') {
142
+ debug.warn('You are trying to cross compile to win32 platform on win32 platform which is unnecessary.');
143
+ }
144
+ else {
145
+ // use cargo-xwin to cross compile to win32 platform
146
+ debug('Use %i', 'cargo-xwin');
147
+ tryInstallCargoBinary('cargo-xwin', 'xwin');
148
+ this.args.push('xwin', 'build');
149
+ if (this.target.arch === 'ia32') {
150
+ this.envs.XWIN_ARCH = 'x86';
151
+ }
152
+ set = true;
153
+ }
154
+ }
155
+ else {
156
+ if (this.target.platform === 'linux' &&
157
+ process.platform === 'linux' &&
158
+ this.target.arch === process.arch &&
159
+ (function (abi) {
160
+ const glibcVersionRuntime =
161
+ // @ts-expect-error
162
+ process.report?.getReport()?.header?.glibcVersionRuntime;
163
+ const libc = glibcVersionRuntime ? 'gnu' : 'musl';
164
+ return abi === libc;
165
+ })(this.target.abi)) {
166
+ debug.warn('You are trying to cross compile to linux target on linux platform which is unnecessary.');
167
+ }
168
+ else if (this.target.platform === 'darwin' &&
169
+ process.platform === 'darwin') {
170
+ debug.warn('You are trying to cross compile to darwin target on darwin platform which is unnecessary.');
171
+ }
172
+ else {
173
+ // use cargo-zigbuild to cross compile to other platforms
174
+ debug('Use %i', 'cargo-zigbuild');
175
+ tryInstallCargoBinary('cargo-zigbuild', 'zigbuild');
176
+ this.args.push('zigbuild');
177
+ set = true;
178
+ }
179
+ }
180
+ }
181
+ if (!set) {
182
+ this.args.push('build');
183
+ }
184
+ return this;
185
+ }
186
+ setPackage() {
187
+ const args = [];
188
+ if (this.options.package) {
189
+ args.push('--package', this.options.package);
190
+ }
191
+ if (this.binName) {
192
+ args.push('--bin', this.binName);
193
+ }
194
+ if (args.length) {
195
+ debug('Set package flags: ');
196
+ debug(' %O', args);
197
+ this.args.push(...args);
198
+ }
199
+ return this;
200
+ }
201
+ setTarget() {
202
+ debug('Set compiling target to: ');
203
+ debug(' %i', this.target.triple);
204
+ this.args.push('--target', this.target.triple);
205
+ return this;
206
+ }
207
+ setEnvs() {
208
+ // type definition intermediate file
209
+ this.envs.TYPE_DEF_TMP_PATH = this.getIntermediateTypeFile();
210
+ this.envs.CARGO_CFG_NAPI_RS_CLI_VERSION = CLI_VERSION;
211
+ // RUSTFLAGS
212
+ let rustflags = process.env.RUSTFLAGS ?? process.env.CARGO_BUILD_RUSTFLAGS ?? '';
213
+ if (this.target.abi?.includes('musl') &&
214
+ !rustflags.includes('target-feature=-crt-static')) {
215
+ rustflags += ' -C target-feature=-crt-static';
216
+ }
217
+ if (this.options.strip && !rustflags.includes('link-arg=-s')) {
218
+ rustflags += ' -C link-arg=-s';
219
+ }
220
+ if (rustflags.length) {
221
+ this.envs.RUSTFLAGS = rustflags;
222
+ }
223
+ // END RUSTFLAGS
224
+ // LINKER
225
+ const linker = getTargetLinker(this.target.triple);
226
+ if (linker &&
227
+ !process.env.RUSTC_LINKER &&
228
+ !process.env[`CARGET_TARGET_${targetToEnvVar(this.target.triple)}_LINKER`]) {
229
+ this.envs.RUSTC_LINKER = linker;
230
+ }
231
+ if (this.target.platform === 'android') {
232
+ const { ANDROID_NDK_LATEST_HOME } = process.env;
233
+ if (!ANDROID_NDK_LATEST_HOME) {
234
+ debug.warn(`${colors.red('ANDROID_NDK_LATEST_HOME')} environment variable is missing`);
235
+ }
236
+ const targetArch = this.target.arch === 'arm' ? 'armv7a' : 'aarch64';
237
+ const targetPlatform = this.target.arch === 'arm' ? 'androideabi24' : 'android24';
238
+ Object.assign(this.envs, {
239
+ CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-android24-clang`,
240
+ CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-androideabi24-clang`,
241
+ CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
242
+ CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
243
+ AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar`,
244
+ ANDROID_NDK: ANDROID_NDK_LATEST_HOME,
245
+ PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${process.env.PATH}`,
246
+ });
247
+ }
248
+ // END LINKER
249
+ debug('Set envs: ');
250
+ Object.entries(this.envs).forEach(([k, v]) => {
251
+ debug(' %i', `${k}=${v}`);
252
+ });
253
+ return this;
254
+ }
255
+ setFeatures() {
256
+ const args = [];
257
+ if (this.options.allFeatures) {
258
+ args.push('--all-features');
259
+ }
260
+ else if (this.options.noDefaultFeatures) {
261
+ args.push('--no-default-features');
262
+ }
263
+ else if (this.options.features) {
264
+ args.push('--features', ...this.options.features);
265
+ }
266
+ debug('Set features flags: ');
267
+ debug(' %O', args);
268
+ this.args.push(...args);
269
+ return this;
270
+ }
271
+ setBypassArgs() {
272
+ if (this.options.release) {
273
+ this.args.push('--release');
274
+ }
275
+ if (this.options.verbose) {
276
+ this.args.push('--verbose');
277
+ }
278
+ if (this.options.targetDir) {
279
+ this.args.push('--target-dir', this.options.targetDir);
280
+ }
281
+ if (this.options.cargoOptions?.length) {
282
+ this.args.push(...this.options.cargoOptions);
283
+ }
284
+ return this;
285
+ }
286
+ getIntermediateTypeFile() {
287
+ return join(tmpdir(), `${this.crate.name}-${createHash('sha256')
288
+ .update(this.crate.manifest_path)
289
+ .update(CLI_VERSION)
290
+ .digest('hex')
291
+ .substring(0, 8)}.napi_type_def.tmp`);
292
+ }
293
+ async postBuild() {
294
+ try {
295
+ debug(`Try to create output directory:`);
296
+ debug(' %i', this.outputDir);
297
+ await mkdirAsync(this.outputDir, { recursive: true });
298
+ debug(`Output directory created`);
299
+ }
300
+ catch (e) {
301
+ throw new Error(`Failed to create output directory ${this.outputDir}`, {
302
+ cause: e,
303
+ });
304
+ }
305
+ await this.copyArtifact();
306
+ // only for cdylib
307
+ if (this.cdyLibName) {
308
+ await this.generateTypeDef();
309
+ await this.writeJsBinding();
310
+ }
311
+ return this.outputs;
312
+ }
313
+ async copyArtifact() {
314
+ const [srcName, destName] = this.getArtifactNames();
315
+ if (!srcName || !destName) {
316
+ return;
317
+ }
318
+ const src = join(this.targetDir, this.target.triple, this.options.release ? 'release' : 'debug', srcName);
319
+ const dest = join(this.outputDir, destName);
320
+ try {
321
+ if (await fileExists(dest)) {
322
+ debug('Old artifact found, remove it first');
323
+ await unlinkAsync(dest);
324
+ }
325
+ debug('Copy artifact to:');
326
+ debug(' %i', dest);
327
+ await copyFileAsync(src, dest);
328
+ this.outputs.push({
329
+ kind: dest.endsWith('.node') ? 'node' : 'exe',
330
+ path: dest,
331
+ });
332
+ }
333
+ catch (e) {
334
+ throw new Error('Failed to copy artifact', {
335
+ cause: e,
336
+ });
337
+ }
338
+ }
339
+ getArtifactNames() {
340
+ if (this.cdyLibName) {
341
+ const cdyLib = this.cdyLibName.replace(/-/g, '_');
342
+ const srcName = this.target.platform === 'darwin'
343
+ ? `lib${cdyLib}.dylib`
344
+ : this.target.platform === 'win32'
345
+ ? `${cdyLib}.dll`
346
+ : `lib${cdyLib}.so`;
347
+ let destName = this.config.binaryName;
348
+ // add platform suffix to binary name
349
+ // index[.linux-x64-gnu].node
350
+ // ^^^^^^^^^^^^^^
351
+ if (this.options.platform) {
352
+ destName += `.${this.target.platformArchABI}`;
353
+ }
354
+ destName += '.node';
355
+ return [srcName, destName];
356
+ }
357
+ else if (this.binName) {
358
+ const srcName = this.target.platform === 'win32' ? `${this.binName}.exe` : this.binName;
359
+ return [srcName, srcName];
360
+ }
361
+ return [];
362
+ }
363
+ async generateTypeDef() {
364
+ if (!(await fileExists(this.envs.TYPE_DEF_TMP_PATH))) {
365
+ return;
366
+ }
367
+ const dest = join(this.outputDir, this.options.dts ?? 'index.d.ts');
368
+ const dts = await processTypeDef(this.envs.TYPE_DEF_TMP_PATH, !this.options.noDtsHeader
369
+ ? this.options.dtsHeader ?? DEFAULT_TYPE_DEF_HEADER
370
+ : '');
371
+ try {
372
+ debug('Writing type def to:');
373
+ debug(' %i', dest);
374
+ await writeFileAsync(dest, dts, 'utf-8');
375
+ this.outputs.push({
376
+ kind: 'dts',
377
+ path: dest,
378
+ });
379
+ }
380
+ catch (e) {
381
+ debug.error('Failed to write type def file');
382
+ debug.error(e);
383
+ }
384
+ }
385
+ async writeJsBinding() {
386
+ if (!this.options.platform || this.options.noJsBinding) {
387
+ return;
388
+ }
389
+ const dest = join(this.outputDir, this.options.jsBinding ?? 'index.js');
390
+ const js = createJsBinding(this.config.binaryName, this.config.packageName);
391
+ try {
392
+ debug('Writing js binding to:');
393
+ debug(' %i', dest);
394
+ await writeFileAsync(dest, js, 'utf-8');
395
+ this.outputs.push({
396
+ kind: 'js',
397
+ path: dest,
398
+ });
399
+ }
400
+ catch (e) {
401
+ throw new Error('Failed to write js binding file', { cause: e });
402
+ }
403
+ }
404
+ }
@@ -0,0 +1,2 @@
1
+ import { CreateNpmDirsOptions } from '../def/create-npm-dirs.js';
2
+ export declare function createNpmDirs(userOptions: CreateNpmDirsOptions): Promise<void>;
@@ -0,0 +1,63 @@
1
+ import { join, resolve } from 'path';
2
+ import { applyDefaultCreateNpmDirsOptions, } from '../def/create-npm-dirs.js';
3
+ import { debugFactory, readNapiConfig, mkdirAsync as rawMkdirAsync, pick, writeFileAsync as rawWriteFileAsync, } from '../utils/index.js';
4
+ const debug = debugFactory('create-npm-dirs');
5
+ export async function createNpmDirs(userOptions) {
6
+ const options = applyDefaultCreateNpmDirsOptions(userOptions);
7
+ async function mkdirAsync(dir) {
8
+ debug('Try to create dir: %i', dir);
9
+ if (options.dryRun) {
10
+ return;
11
+ }
12
+ await rawMkdirAsync(dir, {
13
+ recursive: true,
14
+ });
15
+ }
16
+ async function writeFileAsync(file, content) {
17
+ debug('Writing file %i', file);
18
+ if (options.dryRun) {
19
+ debug(content);
20
+ return;
21
+ }
22
+ await rawWriteFileAsync(file, content);
23
+ }
24
+ const packageJsonPath = resolve(options.cwd, options.packageJsonPath);
25
+ const npmPath = resolve(options.cwd, options.npmDir);
26
+ debug(`Read content from [${packageJsonPath}]`);
27
+ const { targets, binaryName, packageName, packageJson } = await readNapiConfig(packageJsonPath);
28
+ for (const target of targets) {
29
+ const targetDir = join(npmPath, `${target.platformArchABI}`);
30
+ await mkdirAsync(targetDir);
31
+ const binaryFileName = `${binaryName}.${target.platformArchABI}.node`;
32
+ const scopedPackageJson = {
33
+ name: `${packageName}-${target.platformArchABI}`,
34
+ version: packageJson.version,
35
+ os: [target.platform],
36
+ cpu: target.arch !== 'universal' ? [target.arch] : undefined,
37
+ main: binaryFileName,
38
+ files: [binaryFileName],
39
+ ...pick(packageJson, 'description', 'keywords', 'author', 'authors', 'homepage', 'license', 'engines', 'publishConfig', 'repository', 'bugs'),
40
+ };
41
+ // Only works with yarn 3.1+
42
+ // https://github.com/yarnpkg/berry/pull/3981
43
+ if (target.abi === 'gnu') {
44
+ // @ts-expect-error
45
+ scopedPackageJson.libc = ['glibc'];
46
+ }
47
+ else if (target.abi === 'musl') {
48
+ // @ts-expect-error
49
+ scopedPackageJson.libc = ['musl'];
50
+ }
51
+ const targetPackageJson = join(targetDir, 'package.json');
52
+ await writeFileAsync(targetPackageJson, JSON.stringify(scopedPackageJson, null, 2));
53
+ const targetReadme = join(targetDir, 'README.md');
54
+ await writeFileAsync(targetReadme, readme(packageName, target));
55
+ debug.info(`${packageName}-${target.platformArchABI} created`);
56
+ }
57
+ }
58
+ function readme(packageName, target) {
59
+ return `# \`${packageName}-${target.platformArchABI}\`
60
+
61
+ This is the **${target.triple}** binary for \`${packageName}\`
62
+ `;
63
+ }
@@ -0,0 +1,4 @@
1
+ import { NewOptions as RawNewOptions } from '../def/new.js';
2
+ type NewOptions = Required<RawNewOptions>;
3
+ export declare function newProject(userOptions: RawNewOptions): Promise<void>;
4
+ export { NewOptions };