@napi-rs/cli 3.7.2 → 3.7.3
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 +201 -52
- package/dist/index.cjs +200 -51
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +201 -52
- package/package.json +3 -3
- package/src/api/__tests__/__snapshots__/templates.spec.ts.md +353 -0
- package/src/api/__tests__/__snapshots__/templates.spec.ts.snap +0 -0
- package/src/api/__tests__/android-build.spec.ts +113 -0
- package/src/api/__tests__/artifacts.spec.ts +95 -0
- package/src/api/__tests__/build-regressions.spec.ts +128 -0
- package/src/api/__tests__/build.spec.ts +1020 -0
- package/src/api/__tests__/create-npm-dirs.spec.ts +561 -0
- package/src/api/__tests__/new-node-api-version.spec.ts +87 -0
- package/src/api/__tests__/new.spec.ts +527 -0
- package/src/api/__tests__/rename.spec.ts +181 -0
- package/src/api/__tests__/templates.spec.ts +164 -0
- package/src/api/__tests__/universalize.spec.ts +128 -0
- package/src/api/artifacts.ts +7 -16
- package/src/api/build.ts +346 -105
- package/src/api/new.ts +65 -1
- package/src/commands/__tests__/new.spec.ts +13 -0
- package/src/def/build.ts +6 -6
- package/src/utils/__tests__/__fixtures__/napi_type_def +202 -0
- package/src/utils/__tests__/__fixtures__/runtime_string_enum_flag +2 -0
- package/src/utils/__tests__/__snapshots__/config.spec.ts.md +97 -0
- package/src/utils/__tests__/__snapshots__/config.spec.ts.snap +0 -0
- package/src/utils/__tests__/__snapshots__/target.spec.ts.md +180 -0
- package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
- package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +1197 -0
- package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
- package/src/utils/__tests__/__snapshots__/version.spec.ts.md +22 -0
- package/src/utils/__tests__/__snapshots__/version.spec.ts.snap +0 -0
- package/src/utils/__tests__/config.spec.ts +81 -0
- package/src/utils/__tests__/metadata.spec.ts +28 -0
- package/src/utils/__tests__/misc.spec.ts +56 -0
- package/src/utils/__tests__/target.spec.ts +19 -0
- package/src/utils/__tests__/typegen.spec.ts +85 -0
- package/src/utils/__tests__/version.spec.ts +7 -0
- package/src/utils/version.ts +2 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import ava, { type ExecutionContext } from 'ava'
|
|
2
|
+
import { parseSync } from 'oxc-parser'
|
|
3
|
+
|
|
4
|
+
import { createCjsBinding, createEsmBinding } from '../templates/js-binding.js'
|
|
5
|
+
import { createWasiBrowserBinding } from '../templates/load-wasi-template.js'
|
|
6
|
+
import { createWasiBrowserWorkerBinding } from '../templates/wasi-worker-template.js'
|
|
7
|
+
|
|
8
|
+
const test = ava
|
|
9
|
+
|
|
10
|
+
// Snapshot tests for full template output
|
|
11
|
+
|
|
12
|
+
test('createWasiBrowserBinding default', (t) => {
|
|
13
|
+
t.snapshot(createWasiBrowserBinding('test-wasi'))
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('createWasiBrowserBinding with errorEvent', (t) => {
|
|
17
|
+
t.snapshot(
|
|
18
|
+
createWasiBrowserBinding(
|
|
19
|
+
'test-wasi',
|
|
20
|
+
4000,
|
|
21
|
+
65536,
|
|
22
|
+
false,
|
|
23
|
+
false,
|
|
24
|
+
false,
|
|
25
|
+
true,
|
|
26
|
+
),
|
|
27
|
+
)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('createWasiBrowserBinding with errorEvent and fs', (t) => {
|
|
31
|
+
t.snapshot(
|
|
32
|
+
createWasiBrowserBinding(
|
|
33
|
+
'test-wasi',
|
|
34
|
+
4000,
|
|
35
|
+
65536,
|
|
36
|
+
true,
|
|
37
|
+
false,
|
|
38
|
+
false,
|
|
39
|
+
true,
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('createWasiBrowserWorkerBinding default', (t) => {
|
|
45
|
+
t.snapshot(createWasiBrowserWorkerBinding(false, false))
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('createWasiBrowserWorkerBinding with errorEvent', (t) => {
|
|
49
|
+
t.snapshot(createWasiBrowserWorkerBinding(false, true))
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('createWasiBrowserWorkerBinding with errorEvent and fs', (t) => {
|
|
53
|
+
t.snapshot(createWasiBrowserWorkerBinding(true, true))
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
function assertValidJS(t: ExecutionContext, code: string, label: string) {
|
|
57
|
+
const { errors } = parseSync('test.mjs', code, { sourceType: 'module' })
|
|
58
|
+
t.deepEqual(
|
|
59
|
+
errors,
|
|
60
|
+
[],
|
|
61
|
+
`${label}: generated code should have no syntax errors`,
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const browserBindingCases: Array<{
|
|
66
|
+
name: string
|
|
67
|
+
args: Parameters<typeof createWasiBrowserBinding>
|
|
68
|
+
}> = [
|
|
69
|
+
{ name: 'default', args: ['test'] },
|
|
70
|
+
{ name: 'fs', args: ['test', 4000, 65536, true] },
|
|
71
|
+
{ name: 'asyncInit', args: ['test', 4000, 65536, false, true] },
|
|
72
|
+
{ name: 'buffer', args: ['test', 4000, 65536, false, false, true] },
|
|
73
|
+
{
|
|
74
|
+
name: 'errorEvent',
|
|
75
|
+
args: ['test', 4000, 65536, false, false, false, true],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'fs + errorEvent',
|
|
79
|
+
args: ['test', 4000, 65536, true, false, false, true],
|
|
80
|
+
},
|
|
81
|
+
{ name: 'fs + buffer', args: ['test', 4000, 65536, true, false, true] },
|
|
82
|
+
{
|
|
83
|
+
name: 'fs + buffer + errorEvent',
|
|
84
|
+
args: ['test', 4000, 65536, true, false, true, true],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'asyncInit + errorEvent',
|
|
88
|
+
args: ['test', 4000, 65536, false, true, false, true],
|
|
89
|
+
},
|
|
90
|
+
{ name: 'all options', args: ['test', 4000, 65536, true, true, true, true] },
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
for (const { name, args } of browserBindingCases) {
|
|
94
|
+
test(`createWasiBrowserBinding syntax valid: ${name}`, (t) => {
|
|
95
|
+
assertValidJS(t, createWasiBrowserBinding(...args), name)
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const workerBindingCases: Array<{
|
|
100
|
+
name: string
|
|
101
|
+
args: Parameters<typeof createWasiBrowserWorkerBinding>
|
|
102
|
+
}> = [
|
|
103
|
+
{ name: 'default', args: [false, false] },
|
|
104
|
+
{ name: 'fs', args: [true, false] },
|
|
105
|
+
{ name: 'errorEvent', args: [false, true] },
|
|
106
|
+
{ name: 'fs + errorEvent', args: [true, true] },
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
for (const { name, args } of workerBindingCases) {
|
|
110
|
+
test(`createWasiBrowserWorkerBinding syntax valid: ${name}`, (t) => {
|
|
111
|
+
assertValidJS(t, createWasiBrowserWorkerBinding(...args), name)
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// The CJS binding loader ships inside published packages whose `engines`
|
|
116
|
+
// can declare support for old Node versions (e.g. `>= 10`). It must therefore
|
|
117
|
+
// avoid syntax/APIs newer than what those runtimes support:
|
|
118
|
+
// - `require('node:*')` — the `node:` scheme in CommonJS `require()` is only
|
|
119
|
+
// available on Node >= 14.18 / 16.
|
|
120
|
+
// - optional chaining (`?.`) and nullish coalescing (`??`) — Node >= 14.
|
|
121
|
+
// - the `new Error(message, { cause })` options form — Node < 16.9 ignores
|
|
122
|
+
// the second argument, dropping the load-error chain; assign
|
|
123
|
+
// `error.cause` instead.
|
|
124
|
+
const cjsBindingCases: Array<{ name: string; code: string }> = [
|
|
125
|
+
{
|
|
126
|
+
name: 'default',
|
|
127
|
+
code: createCjsBinding('test', '@scope/test', ['sum', 'sub']),
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'with version check',
|
|
131
|
+
code: createCjsBinding('test', '@scope/test', ['sum', 'sub'], '1.0.0'),
|
|
132
|
+
},
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
// Matches a `node:` builtin scheme in either a `require('node:fs')` or an
|
|
136
|
+
// `import ... from 'node:module'` specifier.
|
|
137
|
+
const NODE_SCHEME_RE = /['"]node:/
|
|
138
|
+
|
|
139
|
+
for (const { name, code } of cjsBindingCases) {
|
|
140
|
+
test(`createCjsBinding is Node 12 compatible: ${name}`, (t) => {
|
|
141
|
+
assertValidJS(t, code, name)
|
|
142
|
+
t.false(
|
|
143
|
+
NODE_SCHEME_RE.test(code),
|
|
144
|
+
'CJS loader must not use the node: scheme (unsupported on Node < 14.18/16 for require())',
|
|
145
|
+
)
|
|
146
|
+
t.false(code.includes('?.'), 'CJS loader must not use optional chaining')
|
|
147
|
+
t.false(code.includes('??'), 'CJS loader must not use nullish coalescing')
|
|
148
|
+
t.false(
|
|
149
|
+
/\bcause:/.test(code),
|
|
150
|
+
'CJS loader must not pass `{ cause }` to the Error constructor (ignored on Node < 16.9); assign `error.cause` instead',
|
|
151
|
+
)
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
test('createEsmBinding is Node 12 compatible', (t) => {
|
|
156
|
+
const code = createEsmBinding('test', '@scope/test', ['sum'])
|
|
157
|
+
assertValidJS(t, code, 'esm')
|
|
158
|
+
t.false(
|
|
159
|
+
NODE_SCHEME_RE.test(code),
|
|
160
|
+
'ESM loader must not use the node: scheme (incl. `import ... from "node:module"`)',
|
|
161
|
+
)
|
|
162
|
+
t.false(code.includes('?.'), 'ESM loader must not use optional chaining')
|
|
163
|
+
t.false(code.includes('??'), 'ESM loader must not use nullish coalescing')
|
|
164
|
+
})
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { mkdir, rm, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
import ava, { type TestFn } from 'ava'
|
|
7
|
+
|
|
8
|
+
import { universalizeBinaries } from '../universalize.js'
|
|
9
|
+
|
|
10
|
+
const test = ava as TestFn<{
|
|
11
|
+
tmpDir: string
|
|
12
|
+
cwd: string
|
|
13
|
+
packageJsonPath: string
|
|
14
|
+
}>
|
|
15
|
+
|
|
16
|
+
test.beforeEach(async (t) => {
|
|
17
|
+
const timestamp = Date.now()
|
|
18
|
+
const random = Math.random().toString(36).substring(7)
|
|
19
|
+
const tmpDir = join(
|
|
20
|
+
tmpdir(),
|
|
21
|
+
'napi-rs-test',
|
|
22
|
+
`universalize-${timestamp}-${random}`,
|
|
23
|
+
)
|
|
24
|
+
const cwd = join(tmpDir, 'cwd')
|
|
25
|
+
const packageJsonDir = join(tmpDir, 'pkg')
|
|
26
|
+
const packageJsonPath = join(packageJsonDir, 'package.json')
|
|
27
|
+
|
|
28
|
+
await mkdir(cwd, { recursive: true })
|
|
29
|
+
await mkdir(packageJsonDir, { recursive: true })
|
|
30
|
+
|
|
31
|
+
t.context = {
|
|
32
|
+
tmpDir,
|
|
33
|
+
cwd,
|
|
34
|
+
packageJsonPath,
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test.afterEach.always(async (t) => {
|
|
39
|
+
if (existsSync(t.context.tmpDir)) {
|
|
40
|
+
await rm(t.context.tmpDir, { recursive: true, force: true })
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('resolves an absolute packageJsonPath instead of joining it with cwd', async (t) => {
|
|
45
|
+
const { cwd, packageJsonPath } = t.context
|
|
46
|
+
|
|
47
|
+
await writeFile(
|
|
48
|
+
packageJsonPath,
|
|
49
|
+
`${JSON.stringify(
|
|
50
|
+
{
|
|
51
|
+
name: 'universalize-repro',
|
|
52
|
+
napi: {
|
|
53
|
+
binaryName: 'universalize-repro',
|
|
54
|
+
targets: ['universal-apple-darwin'],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
null,
|
|
58
|
+
2,
|
|
59
|
+
)}\n`,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
const error = await t.throwsAsync(() =>
|
|
63
|
+
universalizeBinaries({
|
|
64
|
+
cwd,
|
|
65
|
+
packageJsonPath,
|
|
66
|
+
}),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
t.truthy(error)
|
|
70
|
+
t.notRegex(error.message, new RegExp(`${cwd}.+package\\.json`))
|
|
71
|
+
|
|
72
|
+
if (process.platform === 'darwin') {
|
|
73
|
+
t.regex(error.message, /Some binary files were not found:/)
|
|
74
|
+
} else {
|
|
75
|
+
t.is(
|
|
76
|
+
error.message,
|
|
77
|
+
`'universal' arch for platform '${process.platform}' not found in config!`,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('throws when lipo fails to create a universal binary', async (t) => {
|
|
83
|
+
if (process.platform !== 'darwin') {
|
|
84
|
+
t.pass()
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const { cwd, packageJsonPath, tmpDir } = t.context
|
|
89
|
+
const outputDir = join(tmpDir, 'out')
|
|
90
|
+
const outputPath = join(outputDir, 'universalize-repro.darwin-universal.node')
|
|
91
|
+
|
|
92
|
+
await mkdir(outputDir, { recursive: true })
|
|
93
|
+
await writeFile(
|
|
94
|
+
packageJsonPath,
|
|
95
|
+
`${JSON.stringify(
|
|
96
|
+
{
|
|
97
|
+
name: 'universalize-repro',
|
|
98
|
+
napi: {
|
|
99
|
+
binaryName: 'universalize-repro',
|
|
100
|
+
targets: ['universal-apple-darwin'],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
null,
|
|
104
|
+
2,
|
|
105
|
+
)}\n`,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
await writeFile(
|
|
109
|
+
join(outputDir, 'universalize-repro.darwin-x64.node'),
|
|
110
|
+
'not a mach-o\n',
|
|
111
|
+
)
|
|
112
|
+
await writeFile(
|
|
113
|
+
join(outputDir, 'universalize-repro.darwin-arm64.node'),
|
|
114
|
+
'not a mach-o\n',
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
const error = await t.throwsAsync(() =>
|
|
118
|
+
universalizeBinaries({
|
|
119
|
+
cwd,
|
|
120
|
+
packageJsonPath,
|
|
121
|
+
outputDir,
|
|
122
|
+
}),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
t.truthy(error)
|
|
126
|
+
t.regex(error.message, /Failed to create universal binary/)
|
|
127
|
+
t.false(existsSync(outputPath))
|
|
128
|
+
})
|
package/src/api/artifacts.ts
CHANGED
|
@@ -87,27 +87,18 @@ export async function collectArtifacts(userOptions: ArtifactsOptions) {
|
|
|
87
87
|
|
|
88
88
|
const wasiTarget = targets.find((t) => t.platform === 'wasi')
|
|
89
89
|
if (wasiTarget) {
|
|
90
|
+
const buildOutputDir = options.buildOutputDir
|
|
91
|
+
? resolve(options.cwd, options.buildOutputDir)
|
|
92
|
+
: options.cwd
|
|
90
93
|
const wasiDir = join(
|
|
91
94
|
options.cwd,
|
|
92
95
|
options.npmDir,
|
|
93
96
|
wasiTarget.platformArchABI,
|
|
94
97
|
)
|
|
95
|
-
const cjsFile = join(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
)
|
|
99
|
-
const workerFile = join(
|
|
100
|
-
options.buildOutputDir ?? options.cwd,
|
|
101
|
-
`wasi-worker.mjs`,
|
|
102
|
-
)
|
|
103
|
-
const browserEntry = join(
|
|
104
|
-
options.buildOutputDir ?? options.cwd,
|
|
105
|
-
`${binaryName}.wasi-browser.js`,
|
|
106
|
-
)
|
|
107
|
-
const browserWorkerFile = join(
|
|
108
|
-
options.buildOutputDir ?? options.cwd,
|
|
109
|
-
`wasi-worker-browser.mjs`,
|
|
110
|
-
)
|
|
98
|
+
const cjsFile = join(buildOutputDir, `${binaryName}.wasi.cjs`)
|
|
99
|
+
const workerFile = join(buildOutputDir, `wasi-worker.mjs`)
|
|
100
|
+
const browserEntry = join(buildOutputDir, `${binaryName}.wasi-browser.js`)
|
|
101
|
+
const browserWorkerFile = join(buildOutputDir, `wasi-worker-browser.mjs`)
|
|
111
102
|
debug.info(
|
|
112
103
|
`Move wasi binding file [${colors.yellowBright(
|
|
113
104
|
cjsFile,
|