@napi-rs/cli 3.6.1 → 3.7.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/dist/cli.js +250 -150
- package/dist/index.cjs +253 -153
- package/dist/index.d.cts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +250 -150
- package/package.json +10 -10
- package/src/api/build.ts +34 -14
- 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/templates/js-binding.ts +14 -4
- package/src/api/templates/load-wasi-template.ts +1 -1
- package/src/api/templates/wasi-worker-template.ts +2 -3
- package/src/api/universalize.ts +29 -7
- package/src/commands/build.ts +1 -0
- package/src/commands/new.ts +12 -5
- package/src/def/build.ts +10 -0
- package/src/utils/config.ts +9 -1
- package/src/utils/misc.ts +25 -1
- package/src/utils/typegen.ts +37 -4
- 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.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"description": "Cli tools for napi-rs",
|
|
5
5
|
"author": "LongYinan <lynweklm@gmail.com>",
|
|
6
6
|
"homepage": "https://napi.rs/",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@octokit/rest": "^22.0.1",
|
|
67
67
|
"clipanion": "^4.0.0-rc.4",
|
|
68
68
|
"colorette": "^2.0.20",
|
|
69
|
-
"emnapi": "^1.
|
|
69
|
+
"emnapi": "^1.10.0",
|
|
70
70
|
"es-toolkit": "^1.41.0",
|
|
71
71
|
"js-yaml": "^4.1.0",
|
|
72
72
|
"obug": "^2.0.0",
|
|
@@ -81,14 +81,14 @@
|
|
|
81
81
|
"@types/js-yaml": "^4.0.9",
|
|
82
82
|
"@types/node": "^24.10.0",
|
|
83
83
|
"@types/semver": "^7.7.1",
|
|
84
|
-
"ava": "^
|
|
84
|
+
"ava": "^8.0.0",
|
|
85
85
|
"empathic": "^2.0.0",
|
|
86
86
|
"env-paths": "^4.0.0",
|
|
87
|
-
"oxc-parser": "^0.
|
|
87
|
+
"oxc-parser": "^0.133.0",
|
|
88
88
|
"prettier": "^3.6.2",
|
|
89
|
-
"tsdown": "^0.
|
|
89
|
+
"tsdown": "^0.22.0",
|
|
90
90
|
"tslib": "^2.8.1",
|
|
91
|
-
"typescript": "^
|
|
91
|
+
"typescript": "^6.0.3"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|
|
94
94
|
"@emnapi/runtime": "^1.7.1"
|
|
@@ -105,12 +105,12 @@
|
|
|
105
105
|
"scripts": {
|
|
106
106
|
"codegen": "node --import @oxc-node/core/register ./codegen/index.ts",
|
|
107
107
|
"build": "tsdown",
|
|
108
|
-
"test": "node --import @oxc-node/core/register ../node_modules/ava/entrypoints/cli.
|
|
108
|
+
"test": "node --import @oxc-node/core/register ../node_modules/ava/entrypoints/cli.js"
|
|
109
109
|
},
|
|
110
110
|
"ava": {
|
|
111
|
-
"extensions":
|
|
112
|
-
"ts"
|
|
113
|
-
|
|
111
|
+
"extensions": [
|
|
112
|
+
"ts"
|
|
113
|
+
],
|
|
114
114
|
"timeout": "2m",
|
|
115
115
|
"workerThreads": false,
|
|
116
116
|
"files": [
|
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
|
}
|
|
@@ -874,6 +874,8 @@ class Builder {
|
|
|
874
874
|
configDtsHeader: this.config.dtsHeader,
|
|
875
875
|
configDtsHeaderFile: this.config.dtsHeaderFile,
|
|
876
876
|
constEnum: this.options.constEnum ?? this.config.constEnum,
|
|
877
|
+
runtimeStringEnum:
|
|
878
|
+
this.options.runtimeStringEnum ?? this.config.runtimeStringEnum,
|
|
877
879
|
cwd: this.options.cwd,
|
|
878
880
|
})
|
|
879
881
|
|
|
@@ -1050,9 +1052,16 @@ export interface GenerateTypeDefOptions {
|
|
|
1050
1052
|
configDtsHeader?: string
|
|
1051
1053
|
configDtsHeaderFile?: string
|
|
1052
1054
|
constEnum?: boolean
|
|
1055
|
+
runtimeStringEnum?: boolean
|
|
1053
1056
|
cwd: string
|
|
1054
1057
|
}
|
|
1055
1058
|
|
|
1059
|
+
/**
|
|
1060
|
+
* Walk the napi-derive intermediate type-def directory, render every entry
|
|
1061
|
+
* into TypeScript via {@link processTypeDef}, and return the concatenated
|
|
1062
|
+
* `.d.ts` source plus the list of identifiers to re-export from
|
|
1063
|
+
* `index.js`.
|
|
1064
|
+
*/
|
|
1056
1065
|
export async function generateTypeDef(
|
|
1057
1066
|
options: GenerateTypeDefOptions,
|
|
1058
1067
|
): Promise<{ exports: string[]; dts: string }> {
|
|
@@ -1093,20 +1102,31 @@ export async function generateTypeDef(
|
|
|
1093
1102
|
return { exports: [], dts: '' }
|
|
1094
1103
|
}
|
|
1095
1104
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
}
|
|
1105
|
+
const typeDefFiles = files
|
|
1106
|
+
.filter((file) => file.isFile())
|
|
1107
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
1100
1108
|
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1109
|
+
const constEnum = options.constEnum ?? true
|
|
1110
|
+
const runtimeStringEnum = options.runtimeStringEnum ?? false
|
|
1111
|
+
if (runtimeStringEnum && constEnum) {
|
|
1112
|
+
debug.warn(
|
|
1113
|
+
'`--runtime-string-enum` has no effect when `--const-enum` is enabled (the default). Pass `--no-const-enum` to activate runtime string enum emission.',
|
|
1104
1114
|
)
|
|
1105
|
-
|
|
1106
|
-
dts += fileDts
|
|
1107
|
-
exports.push(...fileExports)
|
|
1108
1115
|
}
|
|
1109
1116
|
|
|
1117
|
+
const processedTypeDefs = await Promise.all(
|
|
1118
|
+
typeDefFiles.map((file) =>
|
|
1119
|
+
processTypeDef(
|
|
1120
|
+
join(options.typeDefDir, file.name),
|
|
1121
|
+
constEnum,
|
|
1122
|
+
runtimeStringEnum,
|
|
1123
|
+
),
|
|
1124
|
+
),
|
|
1125
|
+
)
|
|
1126
|
+
|
|
1127
|
+
dts = processedTypeDefs.map(({ dts }) => dts).join('')
|
|
1128
|
+
exports = processedTypeDefs.flatMap(({ exports }) => exports)
|
|
1129
|
+
|
|
1110
1130
|
if (dts.indexOf('ExternalObject<') > -1) {
|
|
1111
1131
|
header += `
|
|
1112
1132
|
export declare class ExternalObject<T> {
|
|
@@ -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: string[] = 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')
|
|
@@ -227,23 +227,33 @@ function requireNative() {
|
|
|
227
227
|
|
|
228
228
|
nativeBinding = requireNative()
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
// NAPI_RS_FORCE_WASI is a tri-state flag:
|
|
231
|
+
// unset / any other value → native binding preferred, WASI is only a fallback
|
|
232
|
+
// 'true' → force WASI fallback even if native loaded
|
|
233
|
+
// 'error' → force WASI and throw if no WASI binding is found
|
|
234
|
+
// Treating any non-empty string as truthy (the historical behavior) meant
|
|
235
|
+
// NAPI_RS_FORCE_WASI=false, NAPI_RS_FORCE_WASI=0, etc. inadvertently triggered
|
|
236
|
+
// the WASI path, causing ENOENT for packages shipped without a .wasi.cjs file.
|
|
237
|
+
const forceWasi =
|
|
238
|
+
process.env.NAPI_RS_FORCE_WASI === 'true' || process.env.NAPI_RS_FORCE_WASI === 'error'
|
|
239
|
+
|
|
240
|
+
if (!nativeBinding || forceWasi) {
|
|
231
241
|
let wasiBinding = null
|
|
232
242
|
let wasiBindingError = null
|
|
233
243
|
try {
|
|
234
244
|
wasiBinding = require('./${localName}.wasi.cjs')
|
|
235
245
|
nativeBinding = wasiBinding
|
|
236
246
|
} catch (err) {
|
|
237
|
-
if (
|
|
247
|
+
if (forceWasi) {
|
|
238
248
|
wasiBindingError = err
|
|
239
249
|
}
|
|
240
250
|
}
|
|
241
|
-
if (!nativeBinding ||
|
|
251
|
+
if (!nativeBinding || forceWasi) {
|
|
242
252
|
try {
|
|
243
253
|
wasiBinding = require('${pkgName}-wasm32-wasi')
|
|
244
254
|
nativeBinding = wasiBinding
|
|
245
255
|
} catch (err) {
|
|
246
|
-
if (
|
|
256
|
+
if (forceWasi) {
|
|
247
257
|
if (!wasiBindingError) {
|
|
248
258
|
wasiBindingError = err
|
|
249
259
|
} else {
|
|
@@ -34,7 +34,7 @@ const __wasi = new __WASI({
|
|
|
34
34
|
: ''
|
|
35
35
|
|
|
36
36
|
const workerErrorHandler = errorEvent
|
|
37
|
-
? ` worker.addEventListener('
|
|
37
|
+
? ` worker.addEventListener('message', (event) => {
|
|
38
38
|
if (event.data && typeof event.data === 'object' && event.data.type === 'error') {
|
|
39
39
|
window.dispatchEvent(new CustomEvent('napi-rs-worker-error', { detail: event.data }))
|
|
40
40
|
}
|
|
@@ -109,10 +109,9 @@ const fs = createFsProxy(__memfsExported)`
|
|
|
109
109
|
errorOutputs.length = 0
|
|
110
110
|
}`
|
|
111
111
|
: ''
|
|
112
|
+
const errorOutputsDecl = errorEvent ? `\nconst errorOutputs = []\n` : ''
|
|
112
113
|
return `${fsImport}
|
|
113
|
-
|
|
114
|
-
const errorOutputs = []
|
|
115
|
-
|
|
114
|
+
${errorOutputsDecl}
|
|
116
115
|
const handler = new MessageHandler({
|
|
117
116
|
onLoad({ wasmModule, wasmMemory }) {
|
|
118
117
|
${wasiCreation}
|
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,
|
|
@@ -12,20 +12,38 @@ import { UniArchsByPlatform } from '../utils/target.js'
|
|
|
12
12
|
|
|
13
13
|
const debug = debugFactory('universalize')
|
|
14
14
|
|
|
15
|
+
function createDarwinUniversalBinary(inputs: string[], output: string) {
|
|
16
|
+
const result = spawnSync('lipo', ['-create', '-output', output, ...inputs], {
|
|
17
|
+
stdio: 'inherit',
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
if (result.error) {
|
|
21
|
+
throw result.error
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (result.signal) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Failed to create universal binary '${output}': lipo terminated with signal ${result.signal}.`,
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (result.status !== 0) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Failed to create universal binary '${output}': lipo exited with status ${result.status}.`,
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
15
37
|
const universalizers: Partial<
|
|
16
38
|
Record<NodeJS.Platform, (inputs: string[], output: string) => void>
|
|
17
39
|
> = {
|
|
18
|
-
darwin:
|
|
19
|
-
spawnSync('lipo', ['-create', '-output', output, ...inputs], {
|
|
20
|
-
stdio: 'inherit',
|
|
21
|
-
})
|
|
22
|
-
},
|
|
40
|
+
darwin: createDarwinUniversalBinary,
|
|
23
41
|
}
|
|
24
42
|
|
|
25
43
|
export async function universalizeBinaries(userOptions: UniversalizeOptions) {
|
|
26
44
|
const options = applyDefaultUniversalizeOptions(userOptions)
|
|
27
45
|
|
|
28
|
-
const packageJsonPath =
|
|
46
|
+
const packageJsonPath = resolve(options.cwd, options.packageJsonPath)
|
|
29
47
|
|
|
30
48
|
const config = await readNapiConfig(
|
|
31
49
|
packageJsonPath,
|
|
@@ -77,5 +95,9 @@ export async function universalizeBinaries(userOptions: UniversalizeOptions) {
|
|
|
77
95
|
|
|
78
96
|
universalizers[process.platform]?.(srcFiles, output)
|
|
79
97
|
|
|
98
|
+
if (!(await fileExists(output))) {
|
|
99
|
+
throw new Error(`Universal binary was not created: ${output}`)
|
|
100
|
+
}
|
|
101
|
+
|
|
80
102
|
debug(`Produced universal binary: ${output}`)
|
|
81
103
|
}
|
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/def/build.ts
CHANGED
|
@@ -55,6 +55,11 @@ export abstract class BaseBuildCommand extends Command {
|
|
|
55
55
|
description: 'Whether generate const enum for typescript bindings',
|
|
56
56
|
})
|
|
57
57
|
|
|
58
|
+
runtimeStringEnum?: boolean = Option.Boolean('--runtime-string-enum', {
|
|
59
|
+
description:
|
|
60
|
+
'Emit `#[napi(string_enum)]` enums as runtime enums (`export declare enum`) under `--no-const-enum`. Default: type-only union.',
|
|
61
|
+
})
|
|
62
|
+
|
|
58
63
|
jsBinding?: string = Option.String('--js', {
|
|
59
64
|
description:
|
|
60
65
|
'Path and filename of generated JS binding file. Only works with `--platform` flag. Relative to `--output-dir`.',
|
|
@@ -157,6 +162,7 @@ export abstract class BaseBuildCommand extends Command {
|
|
|
157
162
|
platform: this.platform,
|
|
158
163
|
jsPackageName: this.jsPackageName,
|
|
159
164
|
constEnum: this.constEnum,
|
|
165
|
+
runtimeStringEnum: this.runtimeStringEnum,
|
|
160
166
|
jsBinding: this.jsBinding,
|
|
161
167
|
noJsBinding: this.noJsBinding,
|
|
162
168
|
dts: this.dts,
|
|
@@ -225,6 +231,10 @@ export interface BuildOptions {
|
|
|
225
231
|
* Whether generate const enum for typescript bindings
|
|
226
232
|
*/
|
|
227
233
|
constEnum?: boolean
|
|
234
|
+
/**
|
|
235
|
+
* Emit `#[napi(string_enum)]` enums as runtime enums (`export declare enum`) under `--no-const-enum`. Default: type-only union.
|
|
236
|
+
*/
|
|
237
|
+
runtimeStringEnum?: boolean
|
|
228
238
|
/**
|
|
229
239
|
* Path and filename of generated JS binding file. Only works with `--platform` flag. Relative to `--output-dir`.
|
|
230
240
|
*/
|