@napi-rs/cli 3.0.0-alpha.1 → 3.0.0-alpha.100

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 (176) hide show
  1. package/cli.mjs +1 -1
  2. package/dist/api/__tests__/create-npm-dirs.spec.d.ts +1 -0
  3. package/dist/api/__tests__/new.spec.d.ts +1 -0
  4. package/dist/api/build.d.ts +2 -2
  5. package/dist/api/create-npm-dirs.d.ts +5 -0
  6. package/dist/api/templates/index.d.ts +0 -7
  7. package/dist/api/templates/js-binding.d.ts +2 -1
  8. package/dist/api/templates/load-wasi-template.d.ts +2 -0
  9. package/dist/api/templates/wasi-worker-template.d.ts +2 -0
  10. package/dist/cli.js +3961 -14
  11. package/dist/def/artifacts.d.ts +21 -1
  12. package/dist/def/build.d.ts +167 -4
  13. package/dist/def/create-npm-dirs.d.ts +10 -0
  14. package/dist/def/new.d.ts +25 -7
  15. package/dist/def/pre-publish.d.ts +21 -2
  16. package/dist/def/rename.d.ts +16 -6
  17. package/dist/def/universalize.d.ts +10 -0
  18. package/dist/def/version.d.ts +10 -0
  19. package/dist/index.cjs +10142 -20524
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.js +3711 -29
  22. package/dist/utils/__tests__/config.spec.d.ts +1 -0
  23. package/dist/utils/config.d.ts +70 -6
  24. package/dist/utils/index.d.ts +1 -1
  25. package/dist/utils/metadata.d.ts +13 -1
  26. package/dist/utils/misc.d.ts +3 -3
  27. package/dist/utils/read-config.d.ts +7 -0
  28. package/dist/utils/target.d.ts +9 -6
  29. package/dist/utils/typegen.d.ts +4 -1
  30. package/dist/utils/version.d.ts +2 -1
  31. package/package.json +60 -24
  32. package/src/api/__tests__/create-npm-dirs.spec.ts +210 -0
  33. package/src/api/__tests__/new.spec.ts +429 -0
  34. package/src/api/artifacts.ts +83 -8
  35. package/src/api/build.ts +682 -134
  36. package/src/api/create-npm-dirs.ts +64 -13
  37. package/src/api/new.ts +389 -125
  38. package/src/api/pre-publish.ts +27 -16
  39. package/src/api/rename.ts +103 -17
  40. package/src/api/templates/index.ts +0 -7
  41. package/src/api/templates/js-binding.ts +212 -107
  42. package/src/api/templates/load-wasi-template.ts +216 -0
  43. package/src/api/templates/wasi-worker-template.ts +122 -0
  44. package/src/api/universalize.ts +13 -8
  45. package/src/api/version.ts +5 -2
  46. package/src/commands/artifacts.ts +2 -2
  47. package/src/commands/build.ts +1 -1
  48. package/src/commands/new.ts +46 -49
  49. package/src/def/artifacts.ts +22 -3
  50. package/src/def/build.ts +83 -8
  51. package/src/def/create-npm-dirs.ts +9 -0
  52. package/src/def/new.ts +28 -3
  53. package/src/def/pre-publish.ts +24 -3
  54. package/src/def/rename.ts +11 -2
  55. package/src/def/universalize.ts +9 -0
  56. package/src/def/version.ts +9 -0
  57. package/src/index.ts +2 -0
  58. package/src/utils/__tests__/__fixtures__/napi_type_def +130 -130
  59. package/src/utils/__tests__/__snapshots__/config.spec.ts.md +97 -0
  60. package/src/utils/__tests__/__snapshots__/config.spec.ts.snap +0 -0
  61. package/src/utils/__tests__/__snapshots__/target.spec.ts.md +56 -0
  62. package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
  63. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +703 -164
  64. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
  65. package/src/utils/__tests__/__snapshots__/version.spec.ts.md +9 -8
  66. package/src/utils/__tests__/__snapshots__/version.spec.ts.snap +0 -0
  67. package/src/utils/__tests__/config.spec.ts +81 -0
  68. package/src/utils/__tests__/typegen.spec.ts +19 -4
  69. package/src/utils/cargo.ts +2 -2
  70. package/src/utils/config.ts +147 -13
  71. package/src/utils/index.ts +1 -1
  72. package/src/utils/log.ts +1 -1
  73. package/src/utils/metadata.ts +52 -14
  74. package/src/utils/misc.ts +21 -7
  75. package/src/utils/read-config.ts +20 -0
  76. package/src/utils/target.ts +53 -9
  77. package/src/utils/typegen.ts +100 -40
  78. package/src/utils/version.ts +11 -9
  79. package/dist/api/artifacts.js +0 -50
  80. package/dist/api/build.js +0 -404
  81. package/dist/api/create-npm-dirs.js +0 -63
  82. package/dist/api/new.js +0 -154
  83. package/dist/api/pre-publish.js +0 -157
  84. package/dist/api/rename.js +0 -28
  85. package/dist/api/templates/.gitignore.d.ts +0 -1
  86. package/dist/api/templates/.gitignore.js +0 -198
  87. package/dist/api/templates/.npmignore.d.ts +0 -1
  88. package/dist/api/templates/.npmignore.js +0 -14
  89. package/dist/api/templates/build.rs.d.ts +0 -1
  90. package/dist/api/templates/build.rs.js +0 -4
  91. package/dist/api/templates/cargo.toml.d.ts +0 -6
  92. package/dist/api/templates/cargo.toml.js +0 -25
  93. package/dist/api/templates/ci-template.d.ts +0 -1
  94. package/dist/api/templates/ci-template.js +0 -566
  95. package/dist/api/templates/ci.yml.d.ts +0 -1
  96. package/dist/api/templates/ci.yml.js +0 -92
  97. package/dist/api/templates/index.js +0 -8
  98. package/dist/api/templates/js-binding.js +0 -124
  99. package/dist/api/templates/lib.rs.d.ts +0 -1
  100. package/dist/api/templates/lib.rs.js +0 -10
  101. package/dist/api/templates/package.json.d.ts +0 -8
  102. package/dist/api/templates/package.json.js +0 -30
  103. package/dist/api/universalize.js +0 -38
  104. package/dist/api/version.js +0 -16
  105. package/dist/commands/artifacts.js +0 -19
  106. package/dist/commands/build.js +0 -34
  107. package/dist/commands/create-npm-dirs.js +0 -7
  108. package/dist/commands/help.js +0 -12
  109. package/dist/commands/new.js +0 -112
  110. package/dist/commands/pre-publish.js +0 -8
  111. package/dist/commands/rename.js +0 -7
  112. package/dist/commands/universalize.js +0 -7
  113. package/dist/commands/version.js +0 -7
  114. package/dist/def/artifacts.js +0 -38
  115. package/dist/def/build.js +0 -105
  116. package/dist/def/commands/artifacts.d.ts +0 -15
  117. package/dist/def/commands/artifacts.js +0 -29
  118. package/dist/def/commands/build.d.ts +0 -53
  119. package/dist/def/commands/build.js +0 -105
  120. package/dist/def/commands/create-npm-dirs.d.ts +0 -15
  121. package/dist/def/commands/create-npm-dirs.js +0 -29
  122. package/dist/def/commands/new.d.ts +0 -27
  123. package/dist/def/commands/new.js +0 -53
  124. package/dist/def/commands/pre-publish.d.ts +0 -23
  125. package/dist/def/commands/pre-publish.js +0 -45
  126. package/dist/def/commands/rename.d.ts +0 -25
  127. package/dist/def/commands/rename.js +0 -49
  128. package/dist/def/commands/universalize.d.ts +0 -13
  129. package/dist/def/commands/universalize.js +0 -25
  130. package/dist/def/commands/version.d.ts +0 -13
  131. package/dist/def/commands/version.js +0 -25
  132. package/dist/def/create-npm-dirs.js +0 -38
  133. package/dist/def/new.js +0 -66
  134. package/dist/def/options/artifacts.d.ts +0 -35
  135. package/dist/def/options/artifacts.js +0 -11
  136. package/dist/def/options/build.d.ts +0 -97
  137. package/dist/def/options/build.js +0 -3
  138. package/dist/def/options/create-npm-dirs.d.ts +0 -35
  139. package/dist/def/options/create-npm-dirs.js +0 -11
  140. package/dist/def/options/new.d.ts +0 -79
  141. package/dist/def/options/new.js +0 -15
  142. package/dist/def/options/pre-publish.d.ts +0 -65
  143. package/dist/def/options/pre-publish.js +0 -13
  144. package/dist/def/options/rename.d.ts +0 -75
  145. package/dist/def/options/rename.js +0 -11
  146. package/dist/def/options/universalize.d.ts +0 -28
  147. package/dist/def/options/universalize.js +0 -10
  148. package/dist/def/options/version.d.ts +0 -28
  149. package/dist/def/options/version.js +0 -10
  150. package/dist/def/pre-publish.js +0 -56
  151. package/dist/def/rename.js +0 -58
  152. package/dist/def/universalize.js +0 -33
  153. package/dist/def/version.js +0 -33
  154. package/dist/utils/__tests__/target.spec.js +0 -10
  155. package/dist/utils/__tests__/typegen.spec.js +0 -37
  156. package/dist/utils/__tests__/version.spec.js +0 -5
  157. package/dist/utils/cargo.js +0 -33
  158. package/dist/utils/ci.d.ts +0 -11
  159. package/dist/utils/ci.js +0 -86
  160. package/dist/utils/config.js +0 -42
  161. package/dist/utils/index.js +0 -9
  162. package/dist/utils/log.js +0 -14
  163. package/dist/utils/metadata.js +0 -19
  164. package/dist/utils/misc.js +0 -35
  165. package/dist/utils/target.js +0 -109
  166. package/dist/utils/typegen.js +0 -158
  167. package/dist/utils/version.js +0 -59
  168. package/src/api/templates/.gitignore.ts +0 -198
  169. package/src/api/templates/.npmignore.ts +0 -14
  170. package/src/api/templates/build.rs.ts +0 -4
  171. package/src/api/templates/cargo.toml.ts +0 -35
  172. package/src/api/templates/ci-template.ts +0 -566
  173. package/src/api/templates/ci.yml.ts +0 -116
  174. package/src/api/templates/lib.rs.ts +0 -10
  175. package/src/api/templates/package.json.ts +0 -44
  176. package/src/utils/ci.ts +0 -102
@@ -9,12 +9,13 @@ Generated by [AVA](https://avajs.dev).
9
9
  > Snapshot 1
10
10
 
11
11
  [
12
- '>= 8.6.0',
13
- '>= 8.10.0 && < 9 || >= 9.3.0',
14
- '>= 6.14.2 && < 7 || >= 8.11.2 && < 9 || >= 9.11.0',
15
- '>= 10.16.0 && < 11 || >= 11.8.0',
16
- '>= 10.17.0 && < 11 || >= 12.11.0',
17
- '>= 10.20.0 && < 11 || >= 12.17.0 && < 13 || >= 14.0.0',
18
- '>= 10.23.0 && < 11 || >= 12.19.0 && < 13 || >= 14.12.0',
19
- '>= 12.22.0 && < 13 || >= 14.17.0 && < 15 || >= 15.12.0',
12
+ '>= 8.6.0 < 9 || >= 9.0.0 < 10 || >= 10.0.0',
13
+ '>= 8.10.0 < 9 || >= 9.3.0 < 10 || >= 10.0.0',
14
+ '>= 6.14.2 < 7 || >= 8.11.2 < 9 || >= 9.11.0 < 10 || >= 10.0.0',
15
+ '>= 10.16.0 < 11 || >= 11.8.0 < 12 || >= 12.0.0',
16
+ '>= 10.17.0 < 11 || >= 12.11.0 < 13 || >= 13.0.0',
17
+ '>= 10.20.0 < 11 || >= 12.17.0 < 13 || >= 14.0.0',
18
+ '>= 10.23.0 < 11 || >= 12.19.0 < 13 || >= 14.12.0 < 15 || >= 15.0.0',
19
+ '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0',
20
+ '>= 18.17.0 < 19 || >= 20.3.0 < 21 || >= 21.1.0',
20
21
  ]
@@ -0,0 +1,81 @@
1
+ import { unlink, writeFile } from 'node:fs/promises'
2
+ import { tmpdir } from 'node:os'
3
+ import { join } from 'node:path'
4
+
5
+ import ava, { TestFn } from 'ava'
6
+
7
+ import {
8
+ CommonPackageJsonFields,
9
+ UserNapiConfig,
10
+ readNapiConfig,
11
+ } from '../config.js'
12
+
13
+ const NON_EXISTENT_FILE = 'non-existent-file'
14
+
15
+ const test = ava as TestFn<{
16
+ configPath: string
17
+ packageJson: string
18
+ pkgJson: CommonPackageJsonFields
19
+ config: UserNapiConfig
20
+ }>
21
+
22
+ test.before(async (t) => {
23
+ const tmp = tmpdir()
24
+ const configPath = join(tmp, 'napi.json')
25
+ const packageJson = join(tmp, 'package.json')
26
+ const pkgJson = {
27
+ name: '@napi-rs/testing',
28
+ version: '0.0.0',
29
+ napi: {
30
+ binaryName: 'testing',
31
+ packageName: '@napi-rs/testing',
32
+ targets: [
33
+ 'x86_64-unknown-linux-gnu',
34
+ 'x86_64-pc-windows-msvc',
35
+ 'x86_64-apple-darwin',
36
+ ],
37
+ },
38
+ }
39
+ await writeFile(packageJson, JSON.stringify(pkgJson, null, 2))
40
+ const config = {
41
+ binaryName: 'testing',
42
+ packageName: '@node-rs/testing',
43
+ targets: [
44
+ 'x86_64-unknown-linux-gnu',
45
+ 'x86_64-apple-darwin',
46
+ 'aarch64-apple-darwin',
47
+ ],
48
+ }
49
+ await writeFile(configPath, JSON.stringify(config, null, 2))
50
+ t.context = { configPath, config, packageJson, pkgJson }
51
+ })
52
+
53
+ test.after(async (t) => {
54
+ await unlink(t.context.configPath)
55
+ await unlink(t.context.packageJson)
56
+ })
57
+
58
+ test('should throw if package.json not found', async (t) => {
59
+ await t.throwsAsync(() => readNapiConfig(NON_EXISTENT_FILE), {
60
+ message: `package.json not found at ${NON_EXISTENT_FILE}`,
61
+ })
62
+ })
63
+
64
+ test('should throw if napi.json not found', async (t) => {
65
+ const { packageJson } = t.context
66
+ await t.throwsAsync(() => readNapiConfig(packageJson, NON_EXISTENT_FILE), {
67
+ message: `NAPI-RS config not found at ${NON_EXISTENT_FILE}`,
68
+ })
69
+ })
70
+
71
+ test('should be able to read config from package.json', async (t) => {
72
+ const { packageJson } = t.context
73
+ const config = await readNapiConfig(packageJson)
74
+ t.snapshot(config)
75
+ })
76
+
77
+ test('should be able to read config from napi.json', async (t) => {
78
+ const { packageJson, configPath } = t.context
79
+ const config = await readNapiConfig(packageJson, configPath)
80
+ t.snapshot(config)
81
+ })
@@ -18,13 +18,13 @@ test('should ident string correctly', (t) => {
18
18
  foo() {
19
19
  a = b
20
20
  }
21
-
21
+
22
22
  bar = () => {
23
-
23
+
24
24
  }
25
25
  boz = 1
26
26
  }
27
-
27
+
28
28
  namespace B {
29
29
  namespace C {
30
30
  type D = A
@@ -36,13 +36,28 @@ test('should ident string correctly', (t) => {
36
36
  })
37
37
 
38
38
  test('should process type def correctly', async (t) => {
39
- const dts = await processTypeDef(
39
+ const { dts } = await processTypeDef(
40
+ join(
41
+ fileURLToPath(import.meta.url),
42
+ '../',
43
+ '__fixtures__',
44
+ 'napi_type_def',
45
+ ),
46
+ true,
47
+ )
48
+
49
+ t.snapshot(dts)
50
+ })
51
+
52
+ test('should process type def with noConstEnum correctly', async (t) => {
53
+ const { dts } = await processTypeDef(
40
54
  join(
41
55
  fileURLToPath(import.meta.url),
42
56
  '../',
43
57
  '__fixtures__',
44
58
  'napi_type_def',
45
59
  ),
60
+ false,
46
61
  )
47
62
 
48
63
  t.snapshot(dts)
@@ -1,4 +1,4 @@
1
- import { execSync } from 'child_process'
1
+ import { execSync } from 'node:child_process'
2
2
 
3
3
  import { debug } from './log.js'
4
4
 
@@ -28,7 +28,7 @@ function detectCargoBinary(bin: string) {
28
28
  })
29
29
  debug('Cargo binary detected: %s', bin)
30
30
  return true
31
- } catch (e) {
31
+ } catch {
32
32
  debug('Cargo binary not detected: %s', bin)
33
33
  return false
34
34
  }
@@ -1,9 +1,22 @@
1
+ import { underline, yellow } from 'colorette'
1
2
  import { merge, omit } from 'lodash-es'
2
3
 
3
4
  import { fileExists, readFileAsync } from './misc.js'
4
5
  import { DEFAULT_TARGETS, parseTriple, Target } from './target.js'
5
6
 
6
- interface UserNapiConfig {
7
+ export type ValueOfConstArray<T> = T[Exclude<keyof T, keyof Array<any>>]
8
+
9
+ export const SupportedPackageManagers = ['yarn', 'pnpm'] as const
10
+ export const SupportedTestFrameworks = ['ava'] as const
11
+
12
+ export type SupportedPackageManager = ValueOfConstArray<
13
+ typeof SupportedPackageManagers
14
+ >
15
+ export type SupportedTestFramework = ValueOfConstArray<
16
+ typeof SupportedTestFrameworks
17
+ >
18
+
19
+ export interface UserNapiConfig {
7
20
  /**
8
21
  * Name of the binary to be generated, default to `index`
9
22
  */
@@ -24,6 +37,55 @@ interface UserNapiConfig {
24
37
  */
25
38
  npmClient?: string
26
39
 
40
+ /**
41
+ * Whether generate const enum for typescript bindings
42
+ */
43
+ constEnum?: boolean
44
+
45
+ /**
46
+ * dts header prepend to the generated dts file
47
+ */
48
+ dtsHeader?: string
49
+
50
+ /**
51
+ * dts header file path to be prepended to the generated dts file
52
+ * if both dtsHeader and dtsHeaderFile are provided, dtsHeaderFile will be used
53
+ */
54
+ dtsHeaderFile?: string
55
+
56
+ /**
57
+ * wasm compilation options
58
+ */
59
+ wasm?: {
60
+ /**
61
+ * https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Memory
62
+ * @default 4000 pages (256MiB)
63
+ */
64
+ initialMemory?: number
65
+ /**
66
+ * @default 65536 pages (4GiB)
67
+ */
68
+ maximumMemory?: number
69
+
70
+ /**
71
+ * Browser wasm binding configuration
72
+ */
73
+ browser: {
74
+ /**
75
+ * Whether to use fs module in browser
76
+ */
77
+ fs?: boolean
78
+ /**
79
+ * Whether to initialize wasm asynchronously
80
+ */
81
+ asyncInit?: boolean
82
+ /**
83
+ * Whether to inject `buffer` to emnapi context
84
+ */
85
+ buffer?: boolean
86
+ }
87
+ }
88
+
27
89
  /**
28
90
  * @deprecated binaryName instead
29
91
  */
@@ -41,7 +103,7 @@ interface UserNapiConfig {
41
103
  /**
42
104
  * Whether enable default targets
43
105
  */
44
- default: boolean
106
+ defaults: boolean
45
107
  /**
46
108
  * Additional targets to be compiled for
47
109
  */
@@ -49,7 +111,7 @@ interface UserNapiConfig {
49
111
  }
50
112
  }
51
113
 
52
- interface CommonPackageJsonFields {
114
+ export interface CommonPackageJsonFields {
53
115
  name: string
54
116
  version: string
55
117
  description?: string
@@ -57,6 +119,10 @@ interface CommonPackageJsonFields {
57
119
  author?: string
58
120
  authors?: string[]
59
121
  license?: string
122
+ cpu?: string[]
123
+ os?: string[]
124
+ libc?: string[]
125
+ files?: string[]
60
126
  repository?: any
61
127
  homepage?: any
62
128
  engines?: Record<string, string>
@@ -64,18 +130,41 @@ interface CommonPackageJsonFields {
64
130
  bugs?: any
65
131
  // eslint-disable-next-line no-use-before-define
66
132
  napi?: UserNapiConfig
133
+ type?: 'module' | 'commonjs'
134
+ scripts?: Record<string, string>
135
+
136
+ // modules
137
+ main?: string
138
+ module?: string
139
+ types?: string
140
+ browser?: string
141
+ exports?: any
142
+
143
+ dependencies?: Record<string, string>
144
+ devDependencies?: Record<string, string>
145
+
146
+ ava?: {
147
+ timeout?: string
148
+ }
67
149
  }
68
150
 
69
151
  export type NapiConfig = Required<
70
152
  Pick<UserNapiConfig, 'binaryName' | 'packageName' | 'npmClient'>
71
- > & {
72
- targets: Target[]
73
- packageJson: CommonPackageJsonFields
74
- }
153
+ > &
154
+ Pick<UserNapiConfig, 'wasm' | 'dtsHeader' | 'dtsHeaderFile' | 'constEnum'> & {
155
+ targets: Target[]
156
+ packageJson: CommonPackageJsonFields
157
+ }
75
158
 
76
- export async function readNapiConfig(path: string): Promise<NapiConfig> {
159
+ export async function readNapiConfig(
160
+ path: string,
161
+ configPath?: string,
162
+ ): Promise<NapiConfig> {
163
+ if (configPath && !(await fileExists(configPath))) {
164
+ throw new Error(`NAPI-RS config not found at ${configPath}`)
165
+ }
77
166
  if (!(await fileExists(path))) {
78
- throw new Error(`napi-rs config not found at ${path}`)
167
+ throw new Error(`package.json not found at ${path}`)
79
168
  }
80
169
  // May support multiple config sources later on.
81
170
  const content = await readFileAsync(path, 'utf8')
@@ -83,12 +172,34 @@ export async function readNapiConfig(path: string): Promise<NapiConfig> {
83
172
  try {
84
173
  pkgJson = JSON.parse(content) as CommonPackageJsonFields
85
174
  } catch (e) {
86
- throw new Error('Failed to parse napi-rs config', {
175
+ throw new Error(`Failed to parse package.json at ${path}`, {
87
176
  cause: e,
88
177
  })
89
178
  }
90
179
 
180
+ let separatedConfig: UserNapiConfig | undefined
181
+ if (configPath) {
182
+ const configContent = await readFileAsync(configPath, 'utf8')
183
+ try {
184
+ separatedConfig = JSON.parse(configContent) as UserNapiConfig
185
+ } catch (e) {
186
+ throw new Error(`Failed to parse NAPI-RS config at ${configPath}`, {
187
+ cause: e,
188
+ })
189
+ }
190
+ }
191
+
91
192
  const userNapiConfig = pkgJson.napi ?? {}
193
+ if (pkgJson.napi && separatedConfig) {
194
+ const pkgJsonPath = underline(path)
195
+ const configPathUnderline = underline(configPath!)
196
+ console.warn(
197
+ yellow(
198
+ `Both napi field in ${pkgJsonPath} and [NAPI-RS config](${configPathUnderline}) file are found, the NAPI-RS config file will be used.`,
199
+ ),
200
+ )
201
+ Object.assign(userNapiConfig, separatedConfig)
202
+ }
92
203
  const napiConfig: NapiConfig = merge(
93
204
  {
94
205
  binaryName: 'index',
@@ -103,20 +214,43 @@ export async function readNapiConfig(path: string): Promise<NapiConfig> {
103
214
  let targets: string[] = userNapiConfig.targets ?? []
104
215
 
105
216
  // compatible with old config
106
- if (userNapiConfig.package?.name) {
107
- napiConfig.packageName = userNapiConfig.package.name
217
+ if (userNapiConfig?.name) {
218
+ console.warn(
219
+ yellow(
220
+ `[DEPRECATED] napi.name is deprecated, use napi.binaryName instead.`,
221
+ ),
222
+ )
223
+ napiConfig.binaryName = userNapiConfig.name
108
224
  }
109
225
 
110
226
  if (!targets.length) {
111
- if (userNapiConfig.triples?.default) {
227
+ let deprecatedWarned = false
228
+ const warning = yellow(
229
+ `[DEPRECATED] napi.triples is deprecated, use napi.targets instead.`,
230
+ )
231
+ if (userNapiConfig.triples?.defaults) {
232
+ deprecatedWarned = true
233
+ console.warn(warning)
112
234
  targets = targets.concat(DEFAULT_TARGETS)
113
235
  }
114
236
 
115
237
  if (userNapiConfig.triples?.additional?.length) {
116
238
  targets = targets.concat(userNapiConfig.triples.additional)
239
+ if (!deprecatedWarned) {
240
+ console.warn(warning)
241
+ }
117
242
  }
118
243
  }
119
244
 
245
+ // find duplicate targets
246
+ const uniqueTargets = new Set(targets)
247
+ if (uniqueTargets.size !== targets.length) {
248
+ const duplicateTarget = targets.find(
249
+ (target, index) => targets.indexOf(target) !== index,
250
+ )
251
+ throw new Error(`Duplicate targets are not allowed: ${duplicateTarget}`)
252
+ }
253
+
120
254
  napiConfig.targets = targets.map(parseTriple)
121
255
 
122
256
  return napiConfig
@@ -1,4 +1,3 @@
1
- export * from './ci.js'
2
1
  export * from './log.js'
3
2
  export * from './misc.js'
4
3
  export * from './target.js'
@@ -7,3 +6,4 @@ export * from './metadata.js'
7
6
  export * from './config.js'
8
7
  export * from './cargo.js'
9
8
  export * from './typegen.js'
9
+ export * from './read-config.js'
package/src/utils/log.ts CHANGED
@@ -25,7 +25,7 @@ export const debugFactory = (namespace: string) => {
25
25
  console.error(
26
26
  colors.white(colors.bgRed(' ERROR ')),
27
27
  ...args.map((arg) =>
28
- arg instanceof Error ? arg.stack ?? arg.message : arg,
28
+ arg instanceof Error ? (arg.stack ?? arg.message) : arg,
29
29
  ),
30
30
  )
31
31
 
@@ -1,5 +1,5 @@
1
- import { execSync } from 'child_process'
2
- import fs from 'fs'
1
+ import { spawn } from 'node:child_process'
2
+ import fs from 'node:fs'
3
3
 
4
4
  export type CrateTargetKind =
5
5
  | 'bin'
@@ -26,6 +26,18 @@ export interface Crate {
26
26
  targets: CrateTarget[]
27
27
  features: Record<string, string[]>
28
28
  manifest_path: string
29
+ dependencies: Array<{
30
+ name: string
31
+ source: string
32
+ req: string
33
+ kind: string | null
34
+ rename: string | null
35
+ optional: boolean
36
+ uses_default_features: boolean
37
+ features: string[]
38
+ target: string | null
39
+ registry: string | null
40
+ }>
29
41
  }
30
42
 
31
43
  export interface CargoWorkspaceMetadata {
@@ -36,24 +48,50 @@ export interface CargoWorkspaceMetadata {
36
48
  workspace_root: string
37
49
  }
38
50
 
39
- export function parseMetadata(manifestPath: string) {
51
+ export async function parseMetadata(manifestPath: string) {
40
52
  if (!fs.existsSync(manifestPath)) {
41
53
  throw new Error(`No crate found in manifest: ${manifestPath}`)
42
54
  }
43
55
 
44
- const cmd = `cargo metadata --manifest-path ${manifestPath} --format-version 1 --no-deps`
56
+ const childProcess = spawn(
57
+ 'cargo',
58
+ ['metadata', '--manifest-path', manifestPath, '--format-version', '1'],
59
+ { stdio: 'pipe' },
60
+ )
45
61
 
46
- try {
47
- const output = execSync(cmd, {
48
- encoding: 'utf-8',
62
+ let stdout = ''
63
+ let stderr = ''
64
+ let status = 0
65
+ let error = null
66
+
67
+ childProcess.stdout.on('data', (data) => {
68
+ stdout += data
69
+ })
70
+
71
+ childProcess.stderr.on('data', (data) => {
72
+ stderr += data
73
+ })
74
+
75
+ await new Promise<void>((resolve) => {
76
+ childProcess.on('close', (code) => {
77
+ status = code ?? 0
78
+ resolve()
79
+ })
80
+ })
81
+
82
+ if (error) {
83
+ throw new Error('cargo metadata failed to run', { cause: error })
84
+ }
85
+ if (status !== 0) {
86
+ const simpleMessage = `cargo metadata exited with code ${status}`
87
+ throw new Error(`${simpleMessage} and error message:\n\n${stderr}`, {
88
+ cause: new Error(simpleMessage),
49
89
  })
50
- return JSON.parse(output) as CargoWorkspaceMetadata
90
+ }
91
+
92
+ try {
93
+ return JSON.parse(stdout) as CargoWorkspaceMetadata
51
94
  } catch (e) {
52
- throw new Error(
53
- `Failed to parse cargo metadata output by command: ${cmd}`,
54
- {
55
- cause: e,
56
- },
57
- )
95
+ throw new Error('Failed to parse cargo metadata JSON', { cause: e })
58
96
  }
59
97
  }
package/src/utils/misc.ts CHANGED
@@ -1,12 +1,17 @@
1
- import { readFile, writeFile, copyFile, mkdir, unlink, stat, readdir } from 'fs'
2
- import { createRequire } from 'module'
3
- import { promisify } from 'util'
1
+ import {
2
+ readFile,
3
+ writeFile,
4
+ copyFile,
5
+ mkdir,
6
+ unlink,
7
+ stat,
8
+ readdir,
9
+ } from 'node:fs'
10
+ import { promisify } from 'node:util'
4
11
 
12
+ import pkgJson from '../../package.json' with { type: 'json' }
5
13
  import { debug } from './log.js'
6
14
 
7
- const require = createRequire(import.meta.url)
8
- const pkgJson = require('../../package.json')
9
-
10
15
  export const readFileAsync = promisify(readFile)
11
16
  export const writeFileAsync = promisify(writeFile)
12
17
  export const unlinkAsync = promisify(unlink)
@@ -22,6 +27,15 @@ export async function fileExists(path: string) {
22
27
  return exists
23
28
  }
24
29
 
30
+ export async function dirExistsAsync(path: string) {
31
+ try {
32
+ const stats = await statAsync(path)
33
+ return stats.isDirectory()
34
+ } catch {
35
+ return false
36
+ }
37
+ }
38
+
25
39
  export function pick<O, K extends keyof O>(o: O, ...keys: K[]): Pick<O, K> {
26
40
  return keys.reduce((acc, key) => {
27
41
  acc[key] = o[key]
@@ -38,7 +52,7 @@ export async function updatePackageJson(
38
52
  debug(`File not exists ${path}`)
39
53
  return
40
54
  }
41
- const old = require(path)
55
+ const old = JSON.parse(await readFileAsync(path, 'utf8'))
42
56
  await writeFileAsync(path, JSON.stringify({ ...old, ...partial }, null, 2))
43
57
  }
44
58
 
@@ -0,0 +1,20 @@
1
+ import { resolve } from 'node:path'
2
+
3
+ import { readNapiConfig } from './config.js'
4
+
5
+ interface MinimalNapiOptions {
6
+ cwd: string
7
+ configPath?: string
8
+ packageJsonPath?: string
9
+ }
10
+
11
+ export async function readConfig(options: MinimalNapiOptions) {
12
+ const resolvePath = (...paths: string[]) => resolve(options.cwd, ...paths)
13
+ const config = await readNapiConfig(
14
+ resolvePath(
15
+ options.configPath ?? options.packageJsonPath ?? 'package.json',
16
+ ),
17
+ options.configPath ? resolvePath(options.configPath) : undefined,
18
+ )
19
+ return config
20
+ }