@napi-rs/cli 3.6.1 → 3.6.2
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/dist/cli.js +146 -92
- package/dist/index.cjs +145 -91
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +146 -92
- package/package.json +2 -2
- package/src/api/build.ts +18 -16
- package/src/api/create-npm-dirs.ts +73 -18
- package/src/api/new.ts +74 -15
- package/src/api/pre-publish.ts +1 -0
- package/src/api/rename.ts +12 -0
- package/src/api/universalize.ts +2 -2
- package/src/commands/build.ts +1 -0
- package/src/commands/new.ts +12 -5
- package/src/utils/misc.ts +25 -1
- package/src/utils/version.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@napi-rs/cli",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.2",
|
|
4
4
|
"description": "Cli tools for napi-rs",
|
|
5
5
|
"author": "LongYinan <lynweklm@gmail.com>",
|
|
6
6
|
"homepage": "https://napi.rs/",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"ava": "^7.0.0",
|
|
85
85
|
"empathic": "^2.0.0",
|
|
86
86
|
"env-paths": "^4.0.0",
|
|
87
|
-
"oxc-parser": "^0.
|
|
87
|
+
"oxc-parser": "^0.125.0",
|
|
88
88
|
"prettier": "^3.6.2",
|
|
89
89
|
"tsdown": "^0.21.0",
|
|
90
90
|
"tslib": "^2.8.1",
|
package/src/api/build.ts
CHANGED
|
@@ -542,7 +542,7 @@ class Builder {
|
|
|
542
542
|
require.resolve('emnapi'),
|
|
543
543
|
'..',
|
|
544
544
|
'lib',
|
|
545
|
-
'wasm32-
|
|
545
|
+
'wasm32-wasip1-threads',
|
|
546
546
|
)
|
|
547
547
|
this.envs.EMNAPI_LINK_DIR = emnapi
|
|
548
548
|
const emnapiVersion = require('emnapi/package.json').version
|
|
@@ -593,15 +593,15 @@ class Builder {
|
|
|
593
593
|
)
|
|
594
594
|
this.setEnvIfNotExists(
|
|
595
595
|
'TARGET_CFLAGS',
|
|
596
|
-
`--target=wasm32-
|
|
596
|
+
`--target=wasm32-wasip1-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj`,
|
|
597
597
|
)
|
|
598
598
|
this.setEnvIfNotExists(
|
|
599
599
|
'TARGET_CXXFLAGS',
|
|
600
|
-
`--target=wasm32-
|
|
600
|
+
`--target=wasm32-wasip1-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj`,
|
|
601
601
|
)
|
|
602
602
|
this.setEnvIfNotExists(
|
|
603
603
|
`TARGET_LDFLAGS`,
|
|
604
|
-
`-fuse-ld=${WASI_SDK_PATH}/bin/wasm-ld --target=wasm32-
|
|
604
|
+
`-fuse-ld=${WASI_SDK_PATH}/bin/wasm-ld --target=wasm32-wasip1-threads`,
|
|
605
605
|
)
|
|
606
606
|
}
|
|
607
607
|
}
|
|
@@ -1093,19 +1093,21 @@ export async function generateTypeDef(
|
|
|
1093
1093
|
return { exports: [], dts: '' }
|
|
1094
1094
|
}
|
|
1095
1095
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1096
|
+
const typeDefFiles = files
|
|
1097
|
+
.filter((file) => file.isFile())
|
|
1098
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
1099
|
+
|
|
1100
|
+
const processedTypeDefs = await Promise.all(
|
|
1101
|
+
typeDefFiles.map((file) =>
|
|
1102
|
+
processTypeDef(
|
|
1103
|
+
join(options.typeDefDir, file.name),
|
|
1104
|
+
options.constEnum ?? true,
|
|
1105
|
+
),
|
|
1106
|
+
),
|
|
1107
|
+
)
|
|
1105
1108
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
}
|
|
1109
|
+
dts = processedTypeDefs.map(({ dts }) => dts).join('')
|
|
1110
|
+
exports = processedTypeDefs.flatMap(({ exports }) => exports)
|
|
1109
1111
|
|
|
1110
1112
|
if (dts.indexOf('ExternalObject<') > -1) {
|
|
1111
1113
|
header += `
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createRequire } from 'node:module'
|
|
2
2
|
import { join, resolve } from 'node:path'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { Comparator, Range, minVersion, subset } from 'semver'
|
|
5
5
|
|
|
6
6
|
const require = createRequire(import.meta.url)
|
|
7
|
+
const minimumWasiNodeVersion = '>=14.0.0'
|
|
7
8
|
|
|
8
9
|
import {
|
|
9
10
|
applyDefaultCreateNpmDirsOptions,
|
|
@@ -156,23 +157,11 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
|
|
|
156
157
|
`wasi-worker.mjs`,
|
|
157
158
|
`wasi-worker-browser.mjs`,
|
|
158
159
|
)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
if (major >= 14) {
|
|
166
|
-
needRestrictNodeVersion = false
|
|
167
|
-
}
|
|
168
|
-
} catch {
|
|
169
|
-
// ignore
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (needRestrictNodeVersion) {
|
|
173
|
-
scopedPackageJson.engines = {
|
|
174
|
-
node: '>=14.0.0',
|
|
175
|
-
}
|
|
160
|
+
scopedPackageJson.engines = {
|
|
161
|
+
...scopedPackageJson.engines,
|
|
162
|
+
node: scopedPackageJson.engines?.node
|
|
163
|
+
? restrictWasiNodeEngine(scopedPackageJson.engines.node)
|
|
164
|
+
: minimumWasiNodeVersion,
|
|
176
165
|
}
|
|
177
166
|
const emnapiVersion = require('emnapi/package.json').version
|
|
178
167
|
scopedPackageJson.dependencies = {
|
|
@@ -206,3 +195,69 @@ function readme(packageName: string, target: Target) {
|
|
|
206
195
|
This is the **${target.triple}** binary for \`${packageName}\`
|
|
207
196
|
`
|
|
208
197
|
}
|
|
198
|
+
|
|
199
|
+
function restrictWasiNodeEngine(nodeRange: string) {
|
|
200
|
+
try {
|
|
201
|
+
if (subset(nodeRange, minimumWasiNodeVersion)) {
|
|
202
|
+
return nodeRange
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (subset(minimumWasiNodeVersion, nodeRange)) {
|
|
206
|
+
return minimumWasiNodeVersion
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const minimumComparator = new Comparator(minimumWasiNodeVersion)
|
|
210
|
+
const restrictedRangeSets = new Range(nodeRange).set
|
|
211
|
+
.map((comparators) =>
|
|
212
|
+
normalizeComparatorSet([...comparators, minimumComparator]),
|
|
213
|
+
)
|
|
214
|
+
.filter(
|
|
215
|
+
(candidate): candidate is string =>
|
|
216
|
+
candidate !== undefined && minVersion(candidate) !== null,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
if (restrictedRangeSets.length > 0) {
|
|
220
|
+
return restrictedRangeSets.join(' || ')
|
|
221
|
+
}
|
|
222
|
+
} catch {
|
|
223
|
+
// ignore
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return minimumWasiNodeVersion
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function normalizeComparatorSet(comparators: Comparator[]) {
|
|
230
|
+
const exactMatch = comparators.find(({ operator }) => operator === '')
|
|
231
|
+
if (exactMatch) {
|
|
232
|
+
return comparators.every((comparator) => comparator.test(exactMatch.semver))
|
|
233
|
+
? exactMatch.value
|
|
234
|
+
: undefined
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
let lowerBound: Comparator | undefined
|
|
238
|
+
let upperBound: Comparator | undefined
|
|
239
|
+
|
|
240
|
+
for (const comparator of comparators) {
|
|
241
|
+
if (comparator.operator === '>' || comparator.operator === '>=') {
|
|
242
|
+
if (
|
|
243
|
+
!lowerBound ||
|
|
244
|
+
comparator.semver.compare(lowerBound.semver) > 0 ||
|
|
245
|
+
(comparator.semver.compare(lowerBound.semver) === 0 &&
|
|
246
|
+
comparator.operator === '>')
|
|
247
|
+
) {
|
|
248
|
+
lowerBound = comparator
|
|
249
|
+
}
|
|
250
|
+
} else if (comparator.operator === '<' || comparator.operator === '<=') {
|
|
251
|
+
if (
|
|
252
|
+
!upperBound ||
|
|
253
|
+
comparator.semver.compare(upperBound.semver) < 0 ||
|
|
254
|
+
(comparator.semver.compare(upperBound.semver) === 0 &&
|
|
255
|
+
comparator.operator === '<')
|
|
256
|
+
) {
|
|
257
|
+
upperBound = comparator
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return [lowerBound?.value, upperBound?.value].filter(Boolean).join(' ')
|
|
263
|
+
}
|
package/src/api/new.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { homedir } from 'node:os'
|
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { promises as fs } from 'node:fs'
|
|
6
6
|
|
|
7
|
+
import { parse as parseToml, stringify as stringifyToml } from '@std/toml'
|
|
7
8
|
import { load as yamlLoad, dump as yamlDump } from 'js-yaml'
|
|
8
9
|
|
|
9
10
|
import {
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
debugFactory,
|
|
16
17
|
DEFAULT_TARGETS,
|
|
17
18
|
mkdirAsync,
|
|
19
|
+
parseTriple,
|
|
18
20
|
readdirAsync,
|
|
19
21
|
statAsync,
|
|
20
22
|
type SupportedPackageManager,
|
|
@@ -33,6 +35,8 @@ const TEMPLATE_REPOS = {
|
|
|
33
35
|
pnpm: 'https://github.com/napi-rs/package-template-pnpm',
|
|
34
36
|
} as const
|
|
35
37
|
|
|
38
|
+
const WASI_TARGET = 'wasm32-wasip1-threads'
|
|
39
|
+
|
|
36
40
|
async function checkGitCommand(): Promise<boolean> {
|
|
37
41
|
return new Promise<boolean>((resolve) => {
|
|
38
42
|
const cp = exec('git --version')
|
|
@@ -125,7 +129,7 @@ async function copyDirectory(
|
|
|
125
129
|
entry.name.endsWith('.wasi.cjs') ||
|
|
126
130
|
entry.name.endsWith('wasi-worker-browser.mjs') ||
|
|
127
131
|
entry.name.endsWith('wasi-worker.mjs') ||
|
|
128
|
-
entry.name
|
|
132
|
+
entry.name === 'browser.js')
|
|
129
133
|
) {
|
|
130
134
|
continue
|
|
131
135
|
}
|
|
@@ -140,6 +144,7 @@ async function filterTargetsInPackageJson(
|
|
|
140
144
|
): Promise<void> {
|
|
141
145
|
const content = await fs.readFile(filePath, 'utf-8')
|
|
142
146
|
const packageJson = JSON.parse(content)
|
|
147
|
+
const includeWasiBindings = enabledTargets.includes(WASI_TARGET)
|
|
143
148
|
|
|
144
149
|
// Filter napi.targets
|
|
145
150
|
if (packageJson.napi?.targets) {
|
|
@@ -148,9 +153,63 @@ async function filterTargetsInPackageJson(
|
|
|
148
153
|
)
|
|
149
154
|
}
|
|
150
155
|
|
|
156
|
+
if (!includeWasiBindings) {
|
|
157
|
+
if (
|
|
158
|
+
packageJson.browser === 'browser.js' ||
|
|
159
|
+
packageJson.browser === './browser.js'
|
|
160
|
+
) {
|
|
161
|
+
delete packageJson.browser
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (Array.isArray(packageJson.files)) {
|
|
165
|
+
packageJson.files = packageJson.files.filter(
|
|
166
|
+
(file: unknown) => file !== 'browser.js' && file !== './browser.js',
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
151
171
|
await fs.writeFile(filePath, JSON.stringify(packageJson, null, 2) + '\n')
|
|
152
172
|
}
|
|
153
173
|
|
|
174
|
+
async function updateCargoTomlTypeDef(
|
|
175
|
+
filePath: string,
|
|
176
|
+
enableTypeDef: boolean,
|
|
177
|
+
): Promise<void> {
|
|
178
|
+
if (enableTypeDef) {
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
183
|
+
const cargoToml = parseToml(content) as Record<string, any>
|
|
184
|
+
const dependencies = cargoToml.dependencies
|
|
185
|
+
|
|
186
|
+
if (!dependencies || !dependencies['napi-derive']) {
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const napiDeriveDependency = dependencies['napi-derive']
|
|
191
|
+
const dependencyConfig =
|
|
192
|
+
typeof napiDeriveDependency === 'string'
|
|
193
|
+
? { version: napiDeriveDependency }
|
|
194
|
+
: { ...napiDeriveDependency }
|
|
195
|
+
|
|
196
|
+
const existingFeatures = Array.isArray(dependencyConfig.features)
|
|
197
|
+
? dependencyConfig.features.filter(
|
|
198
|
+
(feature: unknown): feature is string => typeof feature === 'string',
|
|
199
|
+
)
|
|
200
|
+
: []
|
|
201
|
+
|
|
202
|
+
dependencyConfig['default-features'] = false
|
|
203
|
+
dependencyConfig.features = [
|
|
204
|
+
'strict',
|
|
205
|
+
...existingFeatures.filter((feature) => feature !== 'strict'),
|
|
206
|
+
].filter((feature) => feature !== 'type-def')
|
|
207
|
+
|
|
208
|
+
dependencies['napi-derive'] = dependencyConfig
|
|
209
|
+
|
|
210
|
+
await fs.writeFile(filePath, stringifyToml(cargoToml))
|
|
211
|
+
}
|
|
212
|
+
|
|
154
213
|
async function filterTargetsInGithubActions(
|
|
155
214
|
filePath: string,
|
|
156
215
|
enabledTargets: string[],
|
|
@@ -158,13 +217,6 @@ async function filterTargetsInGithubActions(
|
|
|
158
217
|
const content = await fs.readFile(filePath, 'utf-8')
|
|
159
218
|
const yaml = yamlLoad(content) as any
|
|
160
219
|
|
|
161
|
-
const macOSAndWindowsTargets = new Set([
|
|
162
|
-
'x86_64-pc-windows-msvc',
|
|
163
|
-
'x86_64-pc-windows-gnu',
|
|
164
|
-
'aarch64-pc-windows-msvc',
|
|
165
|
-
'x86_64-apple-darwin',
|
|
166
|
-
])
|
|
167
|
-
|
|
168
220
|
const linuxTargets = new Set([
|
|
169
221
|
'x86_64-unknown-linux-gnu',
|
|
170
222
|
'x86_64-unknown-linux-musl',
|
|
@@ -184,6 +236,10 @@ async function filterTargetsInGithubActions(
|
|
|
184
236
|
const hasLinuxTargets = enabledTargets.some((target) =>
|
|
185
237
|
linuxTargets.has(target),
|
|
186
238
|
)
|
|
239
|
+
const hasMacOSOrWindowsTargets = enabledTargets.some((target) => {
|
|
240
|
+
const platform = parseTriple(target).platform
|
|
241
|
+
return platform === 'darwin' || platform === 'win32'
|
|
242
|
+
})
|
|
187
243
|
|
|
188
244
|
// Filter the matrix configurations in the build job
|
|
189
245
|
if (yaml?.jobs?.build?.strategy?.matrix?.settings) {
|
|
@@ -198,7 +254,7 @@ async function filterTargetsInGithubActions(
|
|
|
198
254
|
|
|
199
255
|
const jobsToRemove: string[] = []
|
|
200
256
|
|
|
201
|
-
if (
|
|
257
|
+
if (!hasMacOSOrWindowsTargets) {
|
|
202
258
|
jobsToRemove.push('test-macOS-windows-binding')
|
|
203
259
|
} else {
|
|
204
260
|
// Filter the matrix configurations in the test-macOS-windows-binding job
|
|
@@ -237,7 +293,7 @@ async function filterTargetsInGithubActions(
|
|
|
237
293
|
}
|
|
238
294
|
}
|
|
239
295
|
|
|
240
|
-
if (!enabledTargets.includes(
|
|
296
|
+
if (!enabledTargets.includes(WASI_TARGET)) {
|
|
241
297
|
jobsToRemove.push('test-wasi')
|
|
242
298
|
}
|
|
243
299
|
|
|
@@ -313,11 +369,9 @@ function processOptions(options: RawNewOptions) {
|
|
|
313
369
|
const out = execSync(`rustup target list`, {
|
|
314
370
|
encoding: 'utf8',
|
|
315
371
|
})
|
|
316
|
-
if (out.includes(
|
|
372
|
+
if (out.includes(WASI_TARGET)) {
|
|
317
373
|
options.targets = options.targets.map((target) =>
|
|
318
|
-
target === 'wasm32-wasi-preview1-threads'
|
|
319
|
-
? 'wasm32-wasip1-threads'
|
|
320
|
-
: target,
|
|
374
|
+
target === 'wasm32-wasi-preview1-threads' ? WASI_TARGET : target,
|
|
321
375
|
)
|
|
322
376
|
}
|
|
323
377
|
}
|
|
@@ -357,7 +411,7 @@ export async function newProject(userOptions: RawNewOptions) {
|
|
|
357
411
|
await copyDirectory(
|
|
358
412
|
templatePath,
|
|
359
413
|
options.path,
|
|
360
|
-
options.targets.includes(
|
|
414
|
+
options.targets.includes(WASI_TARGET),
|
|
361
415
|
)
|
|
362
416
|
|
|
363
417
|
// Rename project using the rename API
|
|
@@ -367,6 +421,11 @@ export async function newProject(userOptions: RawNewOptions) {
|
|
|
367
421
|
binaryName: getBinaryName(options.name),
|
|
368
422
|
})
|
|
369
423
|
|
|
424
|
+
const cargoTomlPath = path.join(options.path, 'Cargo.toml')
|
|
425
|
+
if (existsSync(cargoTomlPath)) {
|
|
426
|
+
await updateCargoTomlTypeDef(cargoTomlPath, options.enableTypeDef)
|
|
427
|
+
}
|
|
428
|
+
|
|
370
429
|
// Filter targets in package.json
|
|
371
430
|
const packageJsonPath = path.join(options.path, 'package.json')
|
|
372
431
|
if (existsSync(packageJsonPath)) {
|
package/src/api/pre-publish.ts
CHANGED
package/src/api/rename.ts
CHANGED
|
@@ -41,6 +41,18 @@ export async function renameProject(userOptions: RenameOptions) {
|
|
|
41
41
|
},
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
+
if (options.repository) {
|
|
45
|
+
if (
|
|
46
|
+
packageJsonData.repository &&
|
|
47
|
+
typeof packageJsonData.repository === 'object' &&
|
|
48
|
+
!Array.isArray(packageJsonData.repository)
|
|
49
|
+
) {
|
|
50
|
+
packageJsonData.repository.url = options.repository
|
|
51
|
+
} else {
|
|
52
|
+
packageJsonData.repository = options.repository
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
44
56
|
if (options.configPath) {
|
|
45
57
|
const configPath = resolve(options.cwd, options.configPath)
|
|
46
58
|
const configContent = await readFileAsync(configPath, 'utf8')
|
package/src/api/universalize.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process'
|
|
2
|
-
import {
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
applyDefaultUniversalizeOptions,
|
|
@@ -25,7 +25,7 @@ const universalizers: Partial<
|
|
|
25
25
|
export async function universalizeBinaries(userOptions: UniversalizeOptions) {
|
|
26
26
|
const options = applyDefaultUniversalizeOptions(userOptions)
|
|
27
27
|
|
|
28
|
-
const packageJsonPath =
|
|
28
|
+
const packageJsonPath = resolve(options.cwd, options.packageJsonPath)
|
|
29
29
|
|
|
30
30
|
const config = await readNapiConfig(
|
|
31
31
|
packageJsonPath,
|
package/src/commands/build.ts
CHANGED
package/src/commands/new.ts
CHANGED
|
@@ -11,10 +11,20 @@ import {
|
|
|
11
11
|
DEFAULT_TARGETS,
|
|
12
12
|
type TargetTriple,
|
|
13
13
|
} from '../utils/index.js'
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
napiEngineRequirement,
|
|
16
|
+
SUPPORTED_NAPI_VERSIONS,
|
|
17
|
+
} from '../utils/version.js'
|
|
15
18
|
|
|
16
19
|
const debug = debugFactory('new')
|
|
17
20
|
|
|
21
|
+
export function getNapiVersionChoices() {
|
|
22
|
+
return SUPPORTED_NAPI_VERSIONS.map((version) => ({
|
|
23
|
+
name: `napi${version} (${napiEngineRequirement(version)})`,
|
|
24
|
+
value: version,
|
|
25
|
+
}))
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
export class NewCommand extends BaseNewCommand {
|
|
19
29
|
interactive = Option.Boolean('--interactive,-i', true, {
|
|
20
30
|
description:
|
|
@@ -77,10 +87,7 @@ export class NewCommand extends BaseNewCommand {
|
|
|
77
87
|
message: 'Minimum node-api version (with node version requirement)',
|
|
78
88
|
loop: false,
|
|
79
89
|
pageSize: 10,
|
|
80
|
-
choices:
|
|
81
|
-
name: `napi${i + 1} (${napiEngineRequirement(i + 1)})`,
|
|
82
|
-
value: i + 1,
|
|
83
|
-
})),
|
|
90
|
+
choices: getNapiVersionChoices(),
|
|
84
91
|
// choice index
|
|
85
92
|
default: this.minNodeApiVersion - 1,
|
|
86
93
|
})
|
package/src/utils/misc.ts
CHANGED
|
@@ -43,6 +43,27 @@ export function pick<O, K extends keyof O>(o: O, ...keys: K[]): Pick<O, K> {
|
|
|
43
43
|
}, {} as O)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function isPlainObject(value: unknown): value is Record<string, any> {
|
|
47
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function mergePackageJson(
|
|
51
|
+
old: Record<string, any>,
|
|
52
|
+
partial: Record<string, any>,
|
|
53
|
+
): Record<string, any> {
|
|
54
|
+
const merged = { ...old }
|
|
55
|
+
|
|
56
|
+
for (const [key, value] of Object.entries(partial)) {
|
|
57
|
+
if (isPlainObject(merged[key]) && isPlainObject(value)) {
|
|
58
|
+
merged[key] = mergePackageJson(merged[key], value)
|
|
59
|
+
} else {
|
|
60
|
+
merged[key] = value
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return merged
|
|
65
|
+
}
|
|
66
|
+
|
|
46
67
|
export async function updatePackageJson(
|
|
47
68
|
path: string,
|
|
48
69
|
partial: Record<string, any>,
|
|
@@ -53,7 +74,10 @@ export async function updatePackageJson(
|
|
|
53
74
|
return
|
|
54
75
|
}
|
|
55
76
|
const old = JSON.parse(await readFileAsync(path, 'utf8'))
|
|
56
|
-
await writeFileAsync(
|
|
77
|
+
await writeFileAsync(
|
|
78
|
+
path,
|
|
79
|
+
JSON.stringify(mergePackageJson(old, partial), null, 2),
|
|
80
|
+
)
|
|
57
81
|
}
|
|
58
82
|
|
|
59
83
|
export const CLI_VERSION = pkgJson.version
|
package/src/utils/version.ts
CHANGED
|
@@ -25,6 +25,10 @@ const NAPI_VERSION_MATRIX = new Map<NapiVersion, string>([
|
|
|
25
25
|
[NapiVersion.Napi9, '18.17.0 | 20.3.0 | 21.1.0'],
|
|
26
26
|
])
|
|
27
27
|
|
|
28
|
+
export const SUPPORTED_NAPI_VERSIONS = Object.values(NapiVersion).filter(
|
|
29
|
+
(v): v is NapiVersion => typeof v === 'number',
|
|
30
|
+
)
|
|
31
|
+
|
|
28
32
|
interface NodeVersion {
|
|
29
33
|
major: number
|
|
30
34
|
minor: number
|