@napi-rs/cli 3.7.3 → 3.8.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.
- package/README.md +33 -0
- package/cli.mjs +9 -12
- package/dist/cli.js +9277 -1313
- package/dist/index.cjs +9266 -1302
- package/dist/index.d.cts +176 -158
- package/dist/index.d.ts +176 -158
- package/dist/index.js +9277 -1313
- package/docs/artifacts.md +33 -0
- package/docs/build.md +58 -0
- package/docs/create-npm-dirs.md +32 -0
- package/docs/new.md +39 -0
- package/docs/pre-publish.md +37 -0
- package/docs/rename.md +37 -0
- package/docs/universalize.md +31 -0
- package/docs/version.md +31 -0
- package/docs/wasi.md +161 -0
- package/package.json +11 -10
- package/src/api/__tests__/__snapshots__/templates.spec.ts.md +1019 -114
- package/src/api/__tests__/__snapshots__/templates.spec.ts.snap +0 -0
- package/src/api/__tests__/artifacts.spec.ts +17 -0
- package/src/api/__tests__/create-npm-dirs.spec.ts +14 -15
- package/src/api/__tests__/new.spec.ts +41 -5
- package/src/api/artifacts.ts +934 -108
- package/src/api/build.ts +1325 -194
- package/src/api/create-npm-dirs.ts +472 -101
- package/src/api/new.ts +354 -35
- package/src/api/pre-publish.ts +2845 -99
- package/src/api/rename.ts +1638 -124
- package/src/api/templates/js-binding.ts +216 -38
- package/src/api/templates/load-wasi-template.ts +1641 -111
- package/src/api/templates/wasi-worker-template.ts +32 -3
- package/src/commands/rename.ts +8 -3
- package/src/def/artifacts.ts +2 -2
- package/src/utils/__tests__/__fixtures__/optional-napi-derive/Cargo.toml +3 -0
- package/src/utils/__tests__/__fixtures__/optional-napi-derive/main-crate/Cargo.toml +8 -0
- package/src/utils/__tests__/__fixtures__/optional-napi-derive/main-crate/src/lib.rs +1 -0
- package/src/utils/__tests__/__fixtures__/optional-napi-derive/napi-derive/Cargo.toml +5 -0
- package/src/utils/__tests__/__fixtures__/optional-napi-derive/napi-derive/src/lib.rs +1 -0
- package/src/utils/__tests__/__fixtures__/optional-napi-derive/with-optional-derive/Cargo.toml +11 -0
- package/src/utils/__tests__/__fixtures__/optional-napi-derive/with-optional-derive/src/lib.rs +1 -0
- package/src/utils/__tests__/__snapshots__/target.spec.ts.md +2 -2
- package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
- package/src/utils/__tests__/metadata.spec.ts +43 -2
- package/src/utils/__tests__/misc.spec.ts +124 -3
- package/src/utils/__tests__/version.spec.ts +47 -1
- package/src/utils/config.ts +15 -2
- package/src/utils/metadata.ts +206 -7
- package/src/utils/misc.ts +6079 -0
- package/src/utils/target.ts +66 -8
- package/src/utils/typegen.ts +1223 -63
- package/src/utils/version.ts +96 -0
package/src/utils/metadata.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
2
|
import fs from 'node:fs'
|
|
3
|
+
import { dirname, resolve } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { debugFactory } from './log.js'
|
|
6
|
+
|
|
7
|
+
const debug = debugFactory('metadata')
|
|
3
8
|
|
|
4
9
|
export type CrateTargetKind =
|
|
5
10
|
| 'bin'
|
|
@@ -28,7 +33,7 @@ export interface Crate {
|
|
|
28
33
|
manifest_path: string
|
|
29
34
|
dependencies: Array<{
|
|
30
35
|
name: string
|
|
31
|
-
source: string
|
|
36
|
+
source: string | null
|
|
32
37
|
req: string
|
|
33
38
|
kind: string | null
|
|
34
39
|
rename: string | null
|
|
@@ -40,24 +45,218 @@ export interface Crate {
|
|
|
40
45
|
}>
|
|
41
46
|
}
|
|
42
47
|
|
|
48
|
+
export interface CargoResolveNode {
|
|
49
|
+
id: string
|
|
50
|
+
dependencies: string[]
|
|
51
|
+
deps: Array<{
|
|
52
|
+
name: string
|
|
53
|
+
pkg: string
|
|
54
|
+
dep_kinds: Array<{
|
|
55
|
+
kind: string | null
|
|
56
|
+
target: string | null
|
|
57
|
+
}>
|
|
58
|
+
}>
|
|
59
|
+
features: string[]
|
|
60
|
+
}
|
|
61
|
+
|
|
43
62
|
export interface CargoWorkspaceMetadata {
|
|
44
63
|
version: number
|
|
45
64
|
packages: Crate[]
|
|
46
65
|
workspace_members: string[]
|
|
47
66
|
target_directory: string
|
|
48
67
|
workspace_root: string
|
|
68
|
+
resolve: {
|
|
69
|
+
root: string | null
|
|
70
|
+
nodes: CargoResolveNode[]
|
|
71
|
+
} | null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Crates that will actually compile `napi-derive` in this build, and are therefore
|
|
75
|
+
// expected to emit a type-def intermediate file. Prefer the resolved dependency graph:
|
|
76
|
+
// a crate whose `napi-derive` dependency is optional and stays disabled in the current
|
|
77
|
+
// build never emits a type-def file, so force-building it would invalidate cargo's
|
|
78
|
+
// fingerprint on every build without ever satisfying the type-def check. Fall back
|
|
79
|
+
// to declared dependencies when the resolve graph is unavailable.
|
|
80
|
+
export function getNapiDeriveDependentCrates(
|
|
81
|
+
metadata: CargoWorkspaceMetadata,
|
|
82
|
+
): Crate[] {
|
|
83
|
+
const resolveNodes = metadata.resolve?.nodes
|
|
84
|
+
if (!resolveNodes) {
|
|
85
|
+
return metadata.packages.filter((crate) =>
|
|
86
|
+
crate.dependencies.some((d) => d.name === 'napi-derive'),
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
const napiDerivePackageIds = new Set(
|
|
90
|
+
metadata.packages.filter((p) => p.name === 'napi-derive').map((p) => p.id),
|
|
91
|
+
)
|
|
92
|
+
const dependentPackageIds = new Set(
|
|
93
|
+
resolveNodes
|
|
94
|
+
.filter((node) =>
|
|
95
|
+
node.deps.some((dep) => napiDerivePackageIds.has(dep.pkg)),
|
|
96
|
+
)
|
|
97
|
+
.map((node) => node.id),
|
|
98
|
+
)
|
|
99
|
+
return metadata.packages.filter((crate) => dependentPackageIds.has(crate.id))
|
|
49
100
|
}
|
|
50
101
|
|
|
51
|
-
|
|
102
|
+
interface ParseMetadataOptions {
|
|
103
|
+
allFeatures?: boolean
|
|
104
|
+
cargoOptions?: string[]
|
|
105
|
+
cwd?: string
|
|
106
|
+
featurePackage?: string
|
|
107
|
+
features?: string[]
|
|
108
|
+
filterPlatform?: string
|
|
109
|
+
noDefaultFeatures?: boolean
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function createCargoMetadataInvocation(
|
|
113
|
+
manifestPath: string,
|
|
114
|
+
options: ParseMetadataOptions = {},
|
|
115
|
+
) {
|
|
116
|
+
const globalArgs: string[] = []
|
|
117
|
+
const metadataArgs = [
|
|
118
|
+
'metadata',
|
|
119
|
+
'--manifest-path',
|
|
120
|
+
manifestPath,
|
|
121
|
+
'--format-version',
|
|
122
|
+
'1',
|
|
123
|
+
]
|
|
124
|
+
const features = [
|
|
125
|
+
...new Set(
|
|
126
|
+
(options.features ?? []).flatMap((feature) =>
|
|
127
|
+
feature.split(/[,\s]+/).filter(Boolean),
|
|
128
|
+
),
|
|
129
|
+
),
|
|
130
|
+
]
|
|
131
|
+
let allFeatures = options.allFeatures === true
|
|
132
|
+
let noDefaultFeatures = options.noDefaultFeatures === true
|
|
133
|
+
const cargoOptions = options.cargoOptions ?? []
|
|
134
|
+
for (let index = 0; index < cargoOptions.length; index += 1) {
|
|
135
|
+
const option = cargoOptions[index]
|
|
136
|
+
if (option === '--config' || option === '-Z') {
|
|
137
|
+
const value = cargoOptions[index + 1]
|
|
138
|
+
if (value !== undefined) {
|
|
139
|
+
globalArgs.push(option, value)
|
|
140
|
+
index += 1
|
|
141
|
+
}
|
|
142
|
+
} else if (option.startsWith('--config=') || option.startsWith('-Z')) {
|
|
143
|
+
globalArgs.push(option)
|
|
144
|
+
} else if (option === '--features' || option === '-F') {
|
|
145
|
+
const value = cargoOptions[index + 1]
|
|
146
|
+
if (value !== undefined) {
|
|
147
|
+
features.push(...value.split(/[,\s]+/).filter(Boolean))
|
|
148
|
+
index += 1
|
|
149
|
+
}
|
|
150
|
+
} else if (option.startsWith('--features=') || option.startsWith('-F=')) {
|
|
151
|
+
features.push(
|
|
152
|
+
...option
|
|
153
|
+
.slice(option.indexOf('=') + 1)
|
|
154
|
+
.split(/[,\s]+/)
|
|
155
|
+
.filter(Boolean),
|
|
156
|
+
)
|
|
157
|
+
} else if (option.startsWith('-F') && option.length > 2) {
|
|
158
|
+
features.push(
|
|
159
|
+
...option
|
|
160
|
+
.slice(2)
|
|
161
|
+
.split(/[,\s]+/)
|
|
162
|
+
.filter(Boolean),
|
|
163
|
+
)
|
|
164
|
+
} else if (option === '--all-features') {
|
|
165
|
+
allFeatures = true
|
|
166
|
+
} else if (option === '--no-default-features') {
|
|
167
|
+
noDefaultFeatures = true
|
|
168
|
+
} else if (
|
|
169
|
+
option === '--locked' ||
|
|
170
|
+
option === '--offline' ||
|
|
171
|
+
option === '--frozen'
|
|
172
|
+
) {
|
|
173
|
+
metadataArgs.push(option)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const selectedFeatures = [
|
|
177
|
+
...new Set(
|
|
178
|
+
features.map((feature) =>
|
|
179
|
+
options.featurePackage && !feature.includes('/')
|
|
180
|
+
? `${options.featurePackage}/${feature}`
|
|
181
|
+
: feature,
|
|
182
|
+
),
|
|
183
|
+
),
|
|
184
|
+
].sort()
|
|
185
|
+
if (selectedFeatures.length > 0) {
|
|
186
|
+
metadataArgs.push('--features', selectedFeatures.join(','))
|
|
187
|
+
}
|
|
188
|
+
if (allFeatures) {
|
|
189
|
+
metadataArgs.push('--all-features')
|
|
190
|
+
}
|
|
191
|
+
if (noDefaultFeatures) {
|
|
192
|
+
metadataArgs.push('--no-default-features')
|
|
193
|
+
}
|
|
194
|
+
if (options.filterPlatform) {
|
|
195
|
+
metadataArgs.push('--filter-platform', options.filterPlatform)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
// Deliberately NOT `process.env.CARGO ?? 'cargo'`: `$CARGO` only overrides
|
|
200
|
+
// the cargo/cross binary spawned for the actual build (see the Builder in
|
|
201
|
+
// api/build.ts) — tests poison `$CARGO` with a nonexistent path to assert
|
|
202
|
+
// no real build is spawned, and `cross metadata` is not a thing either.
|
|
203
|
+
// Metadata always comes from the host `cargo`.
|
|
204
|
+
command: 'cargo',
|
|
205
|
+
args: [...globalArgs, ...metadataArgs],
|
|
206
|
+
cwd: resolve(options.cwd ?? dirname(manifestPath)),
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function parseMetadata(
|
|
211
|
+
manifestPath: string,
|
|
212
|
+
options: ParseMetadataOptions = {},
|
|
213
|
+
) {
|
|
52
214
|
if (!fs.existsSync(manifestPath)) {
|
|
53
215
|
throw new Error(`No crate found in manifest: ${manifestPath}`)
|
|
54
216
|
}
|
|
55
217
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
218
|
+
const invocation = createCargoMetadataInvocation(manifestPath, options)
|
|
219
|
+
// Resolving with the build's feature flags keeps `metadata.resolve` in sync
|
|
220
|
+
// with what `cargo build` will actually compile. Feature flags are rejected
|
|
221
|
+
// in some setups (e.g. a virtual workspace root manifest), so fall back to a
|
|
222
|
+
// plain invocation without them.
|
|
223
|
+
const featurelessArgs = stripFeatureArgs(invocation.args)
|
|
224
|
+
if (featurelessArgs.length !== invocation.args.length) {
|
|
225
|
+
try {
|
|
226
|
+
return await execCargoMetadata(invocation)
|
|
227
|
+
} catch (e) {
|
|
228
|
+
debug.warn(
|
|
229
|
+
`cargo metadata failed with feature flags, retrying without them: ${e}`,
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
return execCargoMetadata({ ...invocation, args: featurelessArgs })
|
|
233
|
+
}
|
|
234
|
+
return execCargoMetadata(invocation)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function stripFeatureArgs(args: string[]): string[] {
|
|
238
|
+
const stripped: string[] = []
|
|
239
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
240
|
+
const arg = args[index]
|
|
241
|
+
if (arg === '--features') {
|
|
242
|
+
// also skip the flag's value
|
|
243
|
+
index += 1
|
|
244
|
+
} else if (arg !== '--all-features' && arg !== '--no-default-features') {
|
|
245
|
+
stripped.push(arg)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return stripped
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function execCargoMetadata(invocation: {
|
|
252
|
+
command: string
|
|
253
|
+
args: string[]
|
|
254
|
+
cwd: string
|
|
255
|
+
}) {
|
|
256
|
+
const childProcess = spawn(invocation.command, invocation.args, {
|
|
257
|
+
cwd: invocation.cwd,
|
|
258
|
+
stdio: 'pipe',
|
|
259
|
+
})
|
|
61
260
|
|
|
62
261
|
let stdout = ''
|
|
63
262
|
let stderr = ''
|