@napi-rs/cli 3.0.0-alpha.9 → 3.0.0-alpha.90
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/cli.mjs +1 -1
- package/dist/api/__tests__/new.spec.d.ts +1 -0
- package/dist/api/__tests__/new.spec.js +283 -0
- package/dist/api/__tests__/new.spec.js.map +1 -0
- package/dist/api/artifacts.js +28 -7
- package/dist/api/artifacts.js.map +1 -1
- package/dist/api/build.d.ts +1 -1
- package/dist/api/build.js +324 -115
- package/dist/api/build.js.map +1 -1
- package/dist/api/create-npm-dirs.js +46 -9
- package/dist/api/create-npm-dirs.js.map +1 -1
- package/dist/api/new.js +312 -107
- package/dist/api/new.js.map +1 -1
- package/dist/api/pre-publish.js +9 -7
- package/dist/api/pre-publish.js.map +1 -1
- package/dist/api/rename.js +74 -12
- package/dist/api/rename.js.map +1 -1
- package/dist/api/templates/cargo.toml.js +1 -0
- package/dist/api/templates/cargo.toml.js.map +1 -1
- package/dist/api/templates/ci-template.d.ts +3 -1
- package/dist/api/templates/ci-template.js +140 -125
- package/dist/api/templates/ci-template.js.map +1 -1
- package/dist/api/templates/ci.yml.d.ts +3 -1
- package/dist/api/templates/ci.yml.js +21 -5
- package/dist/api/templates/ci.yml.js.map +1 -1
- package/dist/api/templates/js-binding.d.ts +1 -0
- package/dist/api/templates/js-binding.js +142 -222
- package/dist/api/templates/js-binding.js.map +1 -1
- package/dist/api/templates/load-wasi-template.d.ts +2 -0
- package/dist/api/templates/load-wasi-template.js +168 -0
- package/dist/api/templates/load-wasi-template.js.map +1 -0
- package/dist/api/templates/package.json.d.ts +9 -2
- package/dist/api/templates/package.json.js +26 -4
- package/dist/api/templates/package.json.js.map +1 -1
- package/dist/api/templates/wasi-worker-template.d.ts +2 -0
- package/dist/api/templates/wasi-worker-template.js +122 -0
- package/dist/api/templates/wasi-worker-template.js.map +1 -0
- package/dist/api/universalize.js +5 -5
- package/dist/api/universalize.js.map +1 -1
- package/dist/api/version.js +2 -2
- package/dist/api/version.js.map +1 -1
- package/dist/commands/artifacts.js +2 -2
- package/dist/commands/artifacts.js.map +1 -1
- package/dist/commands/build.js +1 -1
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/new.js +34 -34
- package/dist/commands/new.js.map +1 -1
- package/dist/def/artifacts.d.ts +21 -1
- package/dist/def/artifacts.js +10 -2
- package/dist/def/artifacts.js.map +1 -1
- package/dist/def/build.d.ts +149 -4
- package/dist/def/build.js +26 -4
- package/dist/def/build.js.map +1 -1
- package/dist/def/create-npm-dirs.d.ts +10 -0
- package/dist/def/create-npm-dirs.js +4 -0
- package/dist/def/create-npm-dirs.js.map +1 -1
- package/dist/def/new.d.ts +25 -7
- package/dist/def/new.js +11 -1
- package/dist/def/new.js.map +1 -1
- package/dist/def/pre-publish.d.ts +12 -2
- package/dist/def/pre-publish.js +7 -3
- package/dist/def/pre-publish.js.map +1 -1
- package/dist/def/rename.d.ts +16 -6
- package/dist/def/rename.js +5 -1
- package/dist/def/rename.js.map +1 -1
- package/dist/def/universalize.d.ts +10 -0
- package/dist/def/universalize.js +4 -0
- package/dist/def/universalize.js.map +1 -1
- package/dist/def/version.d.ts +10 -0
- package/dist/def/version.js +4 -0
- package/dist/def/version.js.map +1 -1
- package/dist/index.cjs +8743 -14849
- package/dist/utils/__tests__/config.spec.d.ts +1 -0
- package/dist/utils/__tests__/config.spec.js +63 -0
- package/dist/utils/__tests__/config.spec.js.map +1 -0
- package/dist/utils/cargo.js +2 -2
- package/dist/utils/cargo.js.map +1 -1
- package/dist/utils/config.d.ts +48 -4
- package/dist/utils/config.js +36 -4
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/log.js +1 -1
- package/dist/utils/log.js.map +1 -1
- package/dist/utils/metadata.d.ts +13 -1
- package/dist/utils/metadata.js +31 -11
- package/dist/utils/metadata.js.map +1 -1
- package/dist/utils/misc.d.ts +3 -3
- package/dist/utils/misc.js +13 -11
- package/dist/utils/misc.js.map +1 -1
- package/dist/utils/read-config.d.ts +7 -0
- package/dist/utils/read-config.js +8 -0
- package/dist/utils/read-config.js.map +1 -0
- package/dist/utils/target.d.ts +7 -5
- package/dist/utils/target.js +17 -3
- package/dist/utils/target.js.map +1 -1
- package/dist/utils/typegen.d.ts +1 -1
- package/dist/utils/typegen.js +63 -32
- package/dist/utils/typegen.js.map +1 -1
- package/dist/utils/version.d.ts +2 -1
- package/dist/utils/version.js +10 -8
- package/dist/utils/version.js.map +1 -1
- package/package.json +34 -32
- package/src/api/__tests__/new.spec.ts +429 -0
- package/src/api/artifacts.ts +81 -9
- package/src/api/build.ts +498 -149
- package/src/api/create-npm-dirs.ts +57 -9
- package/src/api/new.ts +389 -122
- package/src/api/pre-publish.ts +13 -7
- package/src/api/rename.ts +103 -17
- package/src/api/templates/cargo.toml.ts +1 -0
- package/src/api/templates/ci-template.ts +150 -125
- package/src/api/templates/ci.yml.ts +27 -6
- package/src/api/templates/js-binding.ts +148 -220
- package/src/api/templates/load-wasi-template.ts +182 -0
- package/src/api/templates/package.json.ts +47 -5
- package/src/api/templates/wasi-worker-template.ts +122 -0
- package/src/api/universalize.ts +13 -8
- package/src/api/version.ts +5 -2
- package/src/commands/artifacts.ts +2 -2
- package/src/commands/build.ts +1 -1
- package/src/commands/new.ts +46 -45
- package/src/def/artifacts.ts +22 -3
- package/src/def/build.ts +55 -8
- package/src/def/create-npm-dirs.ts +9 -0
- package/src/def/new.ts +28 -3
- package/src/def/pre-publish.ts +12 -3
- package/src/def/rename.ts +11 -2
- package/src/def/universalize.ts +9 -0
- package/src/def/version.ts +9 -0
- package/src/utils/__tests__/__fixtures__/napi_type_def +130 -130
- 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 +28 -0
- package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
- package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +316 -332
- package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
- package/src/utils/__tests__/__snapshots__/version.spec.ts.md +8 -7
- package/src/utils/__tests__/__snapshots__/version.spec.ts.snap +0 -0
- package/src/utils/__tests__/config.spec.ts +81 -0
- package/src/utils/cargo.ts +2 -2
- package/src/utils/config.ts +110 -9
- package/src/utils/index.ts +1 -1
- package/src/utils/log.ts +1 -1
- package/src/utils/metadata.ts +52 -14
- package/src/utils/misc.ts +21 -12
- package/src/utils/read-config.ts +20 -0
- package/src/utils/target.ts +22 -4
- package/src/utils/typegen.ts +87 -52
- package/src/utils/version.ts +10 -8
- package/dist/api/load-wasi-template.d.ts +0 -1
- package/dist/api/load-wasi-template.js +0 -64
- package/dist/api/load-wasi-template.js.map +0 -1
- package/dist/api/wasi-worker-template.d.ts +0 -1
- package/dist/api/wasi-worker-template.js +0 -53
- package/dist/api/wasi-worker-template.js.map +0 -1
- package/dist/utils/ci.d.ts +0 -11
- package/dist/utils/ci.js +0 -96
- package/dist/utils/ci.js.map +0 -1
- package/src/api/load-wasi-template.ts +0 -66
- package/src/api/wasi-worker-template.ts +0 -52
- package/src/utils/ci.ts +0 -111
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { join, resolve } from 'path'
|
|
1
|
+
import { join, resolve } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import { parse } from 'semver'
|
|
2
4
|
|
|
3
5
|
import {
|
|
4
6
|
applyDefaultCreateNpmDirsOptions,
|
|
@@ -13,6 +15,8 @@ import {
|
|
|
13
15
|
Target,
|
|
14
16
|
} from '../utils/index.js'
|
|
15
17
|
|
|
18
|
+
import type { PackageMeta } from './templates/package.json.js'
|
|
19
|
+
|
|
16
20
|
const debug = debugFactory('create-npm-dirs')
|
|
17
21
|
|
|
18
22
|
export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
|
|
@@ -43,20 +47,25 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
|
|
|
43
47
|
const packageJsonPath = resolve(options.cwd, options.packageJsonPath)
|
|
44
48
|
const npmPath = resolve(options.cwd, options.npmDir)
|
|
45
49
|
|
|
46
|
-
debug(`Read content from [${packageJsonPath}]`)
|
|
50
|
+
debug(`Read content from [${options.configPath ?? packageJsonPath}]`)
|
|
47
51
|
|
|
48
52
|
const { targets, binaryName, packageName, packageJson } =
|
|
49
|
-
await readNapiConfig(
|
|
53
|
+
await readNapiConfig(
|
|
54
|
+
packageJsonPath,
|
|
55
|
+
options.configPath ? resolve(options.cwd, options.configPath) : undefined,
|
|
56
|
+
)
|
|
50
57
|
|
|
51
58
|
for (const target of targets) {
|
|
52
59
|
const targetDir = join(npmPath, `${target.platformArchABI}`)
|
|
53
60
|
await mkdirAsync(targetDir)
|
|
54
61
|
|
|
55
|
-
const binaryFileName =
|
|
62
|
+
const binaryFileName =
|
|
63
|
+
target.arch === 'wasm32'
|
|
64
|
+
? `${binaryName}.${target.platformArchABI}.wasm`
|
|
65
|
+
: `${binaryName}.${target.platformArchABI}.node`
|
|
56
66
|
const scopedPackageJson = {
|
|
57
67
|
name: `${packageName}-${target.platformArchABI}`,
|
|
58
68
|
version: packageJson.version,
|
|
59
|
-
os: [target.platform],
|
|
60
69
|
cpu: target.arch !== 'universal' ? [target.arch] : undefined,
|
|
61
70
|
main: binaryFileName,
|
|
62
71
|
files: [binaryFileName],
|
|
@@ -74,9 +83,48 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
|
|
|
74
83
|
'bugs',
|
|
75
84
|
),
|
|
76
85
|
}
|
|
86
|
+
if (target.arch !== 'wasm32') {
|
|
87
|
+
// @ts-expect-error
|
|
88
|
+
scopedPackageJson.os = [target.platform]
|
|
89
|
+
} else {
|
|
90
|
+
const entry = `${binaryName}.wasi.cjs`
|
|
91
|
+
scopedPackageJson.main = entry
|
|
92
|
+
// @ts-expect-error
|
|
93
|
+
scopedPackageJson.browser = `${binaryName}.wasi-browser.js`
|
|
94
|
+
scopedPackageJson.files.push(
|
|
95
|
+
entry,
|
|
96
|
+
// @ts-expect-error
|
|
97
|
+
scopedPackageJson.browser,
|
|
98
|
+
`wasi-worker.mjs`,
|
|
99
|
+
`wasi-worker-browser.mjs`,
|
|
100
|
+
)
|
|
101
|
+
let needRestrictNodeVersion = true
|
|
102
|
+
if (scopedPackageJson.engines?.node) {
|
|
103
|
+
try {
|
|
104
|
+
const { major } = parse(scopedPackageJson.engines.node) ?? {
|
|
105
|
+
major: 0,
|
|
106
|
+
}
|
|
107
|
+
if (major >= 14) {
|
|
108
|
+
needRestrictNodeVersion = false
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
// ignore
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (needRestrictNodeVersion) {
|
|
115
|
+
scopedPackageJson.engines = {
|
|
116
|
+
node: '>=14.0.0',
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const wasmRuntime = await fetch(
|
|
120
|
+
`https://registry.npmjs.org/@napi-rs/wasm-runtime`,
|
|
121
|
+
).then((res) => res.json() as Promise<PackageMeta>)
|
|
122
|
+
// @ts-expect-error
|
|
123
|
+
scopedPackageJson.dependencies = {
|
|
124
|
+
'@napi-rs/wasm-runtime': `^${wasmRuntime['dist-tags'].latest}`,
|
|
125
|
+
}
|
|
126
|
+
}
|
|
77
127
|
|
|
78
|
-
// Only works with yarn 3.1+
|
|
79
|
-
// https://github.com/yarnpkg/berry/pull/3981
|
|
80
128
|
if (target.abi === 'gnu') {
|
|
81
129
|
// @ts-expect-error
|
|
82
130
|
scopedPackageJson.libc = ['glibc']
|
|
@@ -88,12 +136,12 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
|
|
|
88
136
|
const targetPackageJson = join(targetDir, 'package.json')
|
|
89
137
|
await writeFileAsync(
|
|
90
138
|
targetPackageJson,
|
|
91
|
-
JSON.stringify(scopedPackageJson, null, 2),
|
|
139
|
+
JSON.stringify(scopedPackageJson, null, 2) + '\n',
|
|
92
140
|
)
|
|
93
141
|
const targetReadme = join(targetDir, 'README.md')
|
|
94
142
|
await writeFileAsync(targetReadme, readme(packageName, target))
|
|
95
143
|
|
|
96
|
-
debug.info(`${packageName}-${target.platformArchABI} created`)
|
|
144
|
+
debug.info(`${packageName} -${target.platformArchABI} created`)
|
|
97
145
|
}
|
|
98
146
|
}
|
|
99
147
|
|
package/src/api/new.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { exec, execSync } from 'node:child_process'
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { promises as fs } from 'node:fs'
|
|
6
|
+
|
|
7
|
+
import { load as yamlLoad, dump as yamlDump } from 'js-yaml'
|
|
2
8
|
|
|
3
9
|
import {
|
|
4
10
|
applyDefaultNewOptions,
|
|
@@ -6,35 +12,289 @@ import {
|
|
|
6
12
|
} from '../def/new.js'
|
|
7
13
|
import {
|
|
8
14
|
AVAILABLE_TARGETS,
|
|
9
|
-
CLI_VERSION,
|
|
10
15
|
debugFactory,
|
|
11
16
|
DEFAULT_TARGETS,
|
|
12
17
|
mkdirAsync,
|
|
13
|
-
|
|
18
|
+
readdirAsync,
|
|
19
|
+
statAsync,
|
|
20
|
+
SupportedPackageManager,
|
|
14
21
|
} from '../utils/index.js'
|
|
15
22
|
import { napiEngineRequirement } from '../utils/version.js'
|
|
23
|
+
import { renameProject } from './rename.js'
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
createBuildRs,
|
|
19
|
-
createCargoToml,
|
|
20
|
-
createGithubActionsCIYml,
|
|
21
|
-
createLibRs,
|
|
22
|
-
createPackageJson,
|
|
23
|
-
gitIgnore,
|
|
24
|
-
npmIgnore,
|
|
25
|
-
} from './templates/index.js'
|
|
25
|
+
// Template imports removed as we're now using external templates
|
|
26
26
|
|
|
27
27
|
const debug = debugFactory('new')
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
type NewOptions = Required<RawNewOptions>
|
|
30
|
+
|
|
31
|
+
const TEMPLATE_REPOS = {
|
|
32
|
+
yarn: 'https://github.com/napi-rs/package-template',
|
|
33
|
+
pnpm: 'https://github.com/napi-rs/package-template-pnpm',
|
|
34
|
+
} as const
|
|
35
|
+
|
|
36
|
+
async function checkGitCommand(): Promise<boolean> {
|
|
37
|
+
try {
|
|
38
|
+
await new Promise((resolve) => {
|
|
39
|
+
const cp = exec('git --version')
|
|
40
|
+
cp.on('error', () => {
|
|
41
|
+
resolve(false)
|
|
42
|
+
})
|
|
43
|
+
cp.on('exit', (code) => {
|
|
44
|
+
if (code === 0) {
|
|
45
|
+
resolve(true)
|
|
46
|
+
} else {
|
|
47
|
+
resolve(false)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
return true
|
|
52
|
+
} catch {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function ensureCacheDir(
|
|
58
|
+
packageManager: SupportedPackageManager,
|
|
59
|
+
): Promise<string> {
|
|
60
|
+
const cacheDir = path.join(homedir(), '.napi-rs', 'template', packageManager)
|
|
61
|
+
await mkdirAsync(cacheDir, { recursive: true })
|
|
62
|
+
return cacheDir
|
|
32
63
|
}
|
|
33
64
|
|
|
34
|
-
|
|
65
|
+
async function downloadTemplate(
|
|
66
|
+
packageManager: SupportedPackageManager,
|
|
67
|
+
cacheDir: string,
|
|
68
|
+
): Promise<void> {
|
|
69
|
+
const repoUrl = TEMPLATE_REPOS[packageManager]
|
|
70
|
+
const templatePath = path.join(cacheDir, 'repo')
|
|
71
|
+
|
|
72
|
+
if (existsSync(templatePath)) {
|
|
73
|
+
debug(`Template cache found at ${templatePath}, updating...`)
|
|
74
|
+
try {
|
|
75
|
+
// Fetch latest changes and reset to remote
|
|
76
|
+
await new Promise<void>((resolve, reject) => {
|
|
77
|
+
const cp = exec('git fetch origin', { cwd: templatePath })
|
|
78
|
+
cp.on('error', reject)
|
|
79
|
+
cp.on('exit', (code) => {
|
|
80
|
+
if (code === 0) {
|
|
81
|
+
resolve()
|
|
82
|
+
} else {
|
|
83
|
+
reject(
|
|
84
|
+
new Error(
|
|
85
|
+
`Failed to fetch latest changes, git process exited with code ${code}`,
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
execSync('git reset --hard origin/main', {
|
|
92
|
+
cwd: templatePath,
|
|
93
|
+
stdio: 'ignore',
|
|
94
|
+
})
|
|
95
|
+
debug('Template updated successfully')
|
|
96
|
+
} catch (error) {
|
|
97
|
+
debug(`Failed to update template: ${error}`)
|
|
98
|
+
throw new Error(`Failed to update template from ${repoUrl}: ${error}`)
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
debug(`Cloning template from ${repoUrl}...`)
|
|
102
|
+
try {
|
|
103
|
+
execSync(`git clone ${repoUrl} repo`, { cwd: cacheDir, stdio: 'inherit' })
|
|
104
|
+
debug('Template cloned successfully')
|
|
105
|
+
} catch (error) {
|
|
106
|
+
throw new Error(`Failed to clone template from ${repoUrl}: ${error}`)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function copyDirectory(
|
|
112
|
+
src: string,
|
|
113
|
+
dest: string,
|
|
114
|
+
includeWasiBindings: boolean,
|
|
115
|
+
): Promise<void> {
|
|
116
|
+
await mkdirAsync(dest, { recursive: true })
|
|
117
|
+
const entries = await fs.readdir(src, { withFileTypes: true })
|
|
118
|
+
|
|
119
|
+
for (const entry of entries) {
|
|
120
|
+
const srcPath = path.join(src, entry.name)
|
|
121
|
+
const destPath = path.join(dest, entry.name)
|
|
122
|
+
|
|
123
|
+
// Skip .git directory
|
|
124
|
+
if (entry.name === '.git') {
|
|
125
|
+
continue
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (entry.isDirectory()) {
|
|
129
|
+
await copyDirectory(srcPath, destPath, includeWasiBindings)
|
|
130
|
+
} else {
|
|
131
|
+
if (
|
|
132
|
+
!includeWasiBindings &&
|
|
133
|
+
(entry.name.endsWith('.wasi-browser.js') ||
|
|
134
|
+
entry.name.endsWith('.wasi.cjs') ||
|
|
135
|
+
entry.name.endsWith('wasi-worker.browser.mjs ') ||
|
|
136
|
+
entry.name.endsWith('wasi-worker.mjs') ||
|
|
137
|
+
entry.name.endsWith('browser.js'))
|
|
138
|
+
) {
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
await fs.copyFile(srcPath, destPath)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function filterTargetsInPackageJson(
|
|
147
|
+
filePath: string,
|
|
148
|
+
enabledTargets: string[],
|
|
149
|
+
): Promise<void> {
|
|
150
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
151
|
+
const packageJson = JSON.parse(content)
|
|
152
|
+
|
|
153
|
+
// Filter napi.targets
|
|
154
|
+
if (packageJson.napi?.targets) {
|
|
155
|
+
packageJson.napi.targets = packageJson.napi.targets.filter(
|
|
156
|
+
(target: string) => enabledTargets.includes(target),
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
await fs.writeFile(filePath, JSON.stringify(packageJson, null, 2) + '\n')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function filterTargetsInGithubActions(
|
|
164
|
+
filePath: string,
|
|
165
|
+
enabledTargets: string[],
|
|
166
|
+
): Promise<void> {
|
|
167
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
168
|
+
const yaml = yamlLoad(content) as any
|
|
169
|
+
|
|
170
|
+
const macOSAndWindowsTargets = new Set([
|
|
171
|
+
'x86_64-pc-windows-msvc',
|
|
172
|
+
'aarch64-pc-windows-msvc',
|
|
173
|
+
'x86_64-apple-darwin',
|
|
174
|
+
])
|
|
175
|
+
|
|
176
|
+
const linuxTargets = new Set([
|
|
177
|
+
'x86_64-unknown-linux-gnu',
|
|
178
|
+
'x86_64-unknown-linux-musl',
|
|
179
|
+
'aarch64-unknown-linux-gnu',
|
|
180
|
+
'aarch64-unknown-linux-musl',
|
|
181
|
+
'armv7-unknown-linux-gnueabihf',
|
|
182
|
+
'armv7-unknown-linux-musleabihf',
|
|
183
|
+
'riscv64gc-unknown-linux-gnu',
|
|
184
|
+
'powerpc64le-unknown-linux-gnu',
|
|
185
|
+
's390x-unknown-linux-gnu',
|
|
186
|
+
'aarch64-linux-android',
|
|
187
|
+
'armv7-linux-androideabi',
|
|
188
|
+
])
|
|
189
|
+
|
|
190
|
+
// Check if any Linux targets are enabled
|
|
191
|
+
const hasLinuxTargets = enabledTargets.some((target) =>
|
|
192
|
+
linuxTargets.has(target),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
// Filter the matrix configurations in the build job
|
|
196
|
+
if (yaml?.jobs?.build?.strategy?.matrix?.settings) {
|
|
197
|
+
yaml.jobs.build.strategy.matrix.settings =
|
|
198
|
+
yaml.jobs.build.strategy.matrix.settings.filter((setting: any) => {
|
|
199
|
+
if (setting.target) {
|
|
200
|
+
return enabledTargets.includes(setting.target)
|
|
201
|
+
}
|
|
202
|
+
return true
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const jobsToRemove: string[] = []
|
|
207
|
+
|
|
208
|
+
if (enabledTargets.every((target) => !macOSAndWindowsTargets.has(target))) {
|
|
209
|
+
jobsToRemove.push('test-macOS-windows-binding')
|
|
210
|
+
} else {
|
|
211
|
+
// Filter the matrix configurations in the test-macOS-windows-binding job
|
|
212
|
+
if (
|
|
213
|
+
yaml?.jobs?.['test-macOS-windows-binding']?.strategy?.matrix?.settings
|
|
214
|
+
) {
|
|
215
|
+
yaml.jobs['test-macOS-windows-binding'].strategy.matrix.settings =
|
|
216
|
+
yaml.jobs['test-macOS-windows-binding'].strategy.matrix.settings.filter(
|
|
217
|
+
(setting: any) => {
|
|
218
|
+
if (setting.target) {
|
|
219
|
+
return enabledTargets.includes(setting.target)
|
|
220
|
+
}
|
|
221
|
+
return true
|
|
222
|
+
},
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// If no Linux targets are enabled, remove Linux-specific jobs
|
|
228
|
+
if (!hasLinuxTargets) {
|
|
229
|
+
// Remove test-linux-binding job
|
|
230
|
+
if (yaml?.jobs?.['test-linux-binding']) {
|
|
231
|
+
jobsToRemove.push('test-linux-binding')
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
// Filter the matrix configurations in the test-linux-x64-gnu-binding job
|
|
235
|
+
if (yaml?.jobs?.['test-linux-binding']?.strategy?.matrix?.target) {
|
|
236
|
+
yaml.jobs['test-linux-binding'].strategy.matrix.target = yaml.jobs[
|
|
237
|
+
'test-linux-binding'
|
|
238
|
+
].strategy.matrix.target.filter((target: string) => {
|
|
239
|
+
if (target) {
|
|
240
|
+
return enabledTargets.includes(target)
|
|
241
|
+
}
|
|
242
|
+
return true
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (!enabledTargets.includes('wasm32-wasip1-threads')) {
|
|
248
|
+
jobsToRemove.push('test-wasi')
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!enabledTargets.includes('x86_64-unknown-freebsd')) {
|
|
252
|
+
jobsToRemove.push('build-freebsd')
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Filter other test jobs based on target
|
|
256
|
+
for (const [jobName, jobConfig] of Object.entries(yaml.jobs || {})) {
|
|
257
|
+
if (
|
|
258
|
+
jobName.startsWith('test-') &&
|
|
259
|
+
jobName !== 'test-macOS-windows-binding' &&
|
|
260
|
+
jobName !== 'test-linux-x64-gnu-binding'
|
|
261
|
+
) {
|
|
262
|
+
// Extract target from job name or config
|
|
263
|
+
const job = jobConfig as any
|
|
264
|
+
if (job.strategy?.matrix?.settings?.[0]?.target) {
|
|
265
|
+
const target = job.strategy.matrix.settings[0].target
|
|
266
|
+
if (!enabledTargets.includes(target)) {
|
|
267
|
+
jobsToRemove.push(jobName)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Remove jobs for disabled targets
|
|
274
|
+
for (const jobName of jobsToRemove) {
|
|
275
|
+
delete yaml.jobs[jobName]
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (Array.isArray(yaml.jobs?.publish?.needs)) {
|
|
279
|
+
yaml.jobs.publish.needs = yaml.jobs.publish.needs.filter(
|
|
280
|
+
(need: string) => !jobsToRemove.includes(need),
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Write back the filtered YAML
|
|
285
|
+
const updatedYaml = yamlDump(yaml, {
|
|
286
|
+
lineWidth: -1,
|
|
287
|
+
noRefs: true,
|
|
288
|
+
sortKeys: false,
|
|
289
|
+
})
|
|
290
|
+
await fs.writeFile(filePath, updatedYaml)
|
|
291
|
+
}
|
|
35
292
|
|
|
36
293
|
function processOptions(options: RawNewOptions) {
|
|
37
294
|
debug('Processing options...')
|
|
295
|
+
if (!options.path) {
|
|
296
|
+
throw new Error('Please provide the path as the argument')
|
|
297
|
+
}
|
|
38
298
|
options.path = path.resolve(process.cwd(), options.path)
|
|
39
299
|
debug(`Resolved target path to: ${options.path}`)
|
|
40
300
|
|
|
@@ -54,6 +314,20 @@ function processOptions(options: RawNewOptions) {
|
|
|
54
314
|
throw new Error('At least one target must be enabled')
|
|
55
315
|
}
|
|
56
316
|
}
|
|
317
|
+
if (
|
|
318
|
+
options.targets.some((target) => target === 'wasm32-wasi-preview1-threads')
|
|
319
|
+
) {
|
|
320
|
+
const out = execSync(`rustup target list`, {
|
|
321
|
+
encoding: 'utf8',
|
|
322
|
+
})
|
|
323
|
+
if (out.includes('wasm32-wasip1-threads')) {
|
|
324
|
+
options.targets = options.targets.map((target) =>
|
|
325
|
+
target === 'wasm32-wasi-preview1-threads'
|
|
326
|
+
? 'wasm32-wasip1-threads'
|
|
327
|
+
: target,
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
57
331
|
|
|
58
332
|
return applyDefaultNewOptions(options) as NewOptions
|
|
59
333
|
}
|
|
@@ -67,131 +341,124 @@ export async function newProject(userOptions: RawNewOptions) {
|
|
|
67
341
|
debug('Targets to be enabled:')
|
|
68
342
|
debug(options.targets)
|
|
69
343
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
await mkdirAsync(options.path, { recursive: true })
|
|
76
|
-
}
|
|
77
|
-
} catch (e) {
|
|
78
|
-
throw new Error(`Failed to create target directory: ${options.path}`, {
|
|
79
|
-
cause: e,
|
|
80
|
-
})
|
|
344
|
+
// Check if git is available
|
|
345
|
+
if (!(await checkGitCommand())) {
|
|
346
|
+
throw new Error(
|
|
347
|
+
'Git is not installed or not available in PATH. Please install Git to continue.',
|
|
348
|
+
)
|
|
81
349
|
}
|
|
82
350
|
|
|
83
|
-
|
|
84
|
-
debug(`Project created at: ${options.path}`)
|
|
85
|
-
}
|
|
351
|
+
const packageManager = options.packageManager as SupportedPackageManager
|
|
86
352
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
generateCargoToml,
|
|
90
|
-
generateLibRs,
|
|
91
|
-
generateBuildRs,
|
|
92
|
-
generatePackageJson,
|
|
93
|
-
generateGithubWorkflow,
|
|
94
|
-
generateIgnoreFiles,
|
|
95
|
-
].flatMap((generator) => {
|
|
96
|
-
const output = generator(options)
|
|
97
|
-
|
|
98
|
-
if (!output) {
|
|
99
|
-
return []
|
|
100
|
-
}
|
|
353
|
+
// Ensure target directory exists and is empty
|
|
354
|
+
await ensurePath(options.path, options.dryRun)
|
|
101
355
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
} else {
|
|
108
|
-
return [{ ...output, target: path.join(options.path, output.target) }]
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
}
|
|
356
|
+
if (!options.dryRun) {
|
|
357
|
+
try {
|
|
358
|
+
// Download or update template
|
|
359
|
+
const cacheDir = await ensureCacheDir(packageManager)
|
|
360
|
+
await downloadTemplate(packageManager, cacheDir)
|
|
112
361
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
deriveFeatures: options.enableTypeDef ? ['type-def'] : [],
|
|
121
|
-
}),
|
|
122
|
-
}
|
|
123
|
-
}
|
|
362
|
+
// Copy template files to target directory
|
|
363
|
+
const templatePath = path.join(cacheDir, 'repo')
|
|
364
|
+
await copyDirectory(
|
|
365
|
+
templatePath,
|
|
366
|
+
options.path,
|
|
367
|
+
options.targets.includes('wasm32-wasip1-threads'),
|
|
368
|
+
)
|
|
124
369
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
370
|
+
// Rename project using the rename API
|
|
371
|
+
await renameProject({
|
|
372
|
+
cwd: options.path,
|
|
373
|
+
name: options.name,
|
|
374
|
+
binaryName: getBinaryName(options.name),
|
|
375
|
+
})
|
|
131
376
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
377
|
+
// Filter targets in package.json
|
|
378
|
+
const packageJsonPath = path.join(options.path, 'package.json')
|
|
379
|
+
if (existsSync(packageJsonPath)) {
|
|
380
|
+
await filterTargetsInPackageJson(packageJsonPath, options.targets)
|
|
381
|
+
}
|
|
138
382
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
383
|
+
// Filter targets in GitHub Actions CI
|
|
384
|
+
const ciPath = path.join(options.path, '.github', 'workflows', 'CI.yml')
|
|
385
|
+
if (existsSync(ciPath) && options.enableGithubActions) {
|
|
386
|
+
await filterTargetsInGithubActions(ciPath, options.targets)
|
|
387
|
+
} else if (
|
|
388
|
+
!options.enableGithubActions &&
|
|
389
|
+
existsSync(path.join(options.path, '.github'))
|
|
390
|
+
) {
|
|
391
|
+
// Remove .github directory if GitHub Actions is not enabled
|
|
392
|
+
await fs.rm(path.join(options.path, '.github'), {
|
|
393
|
+
recursive: true,
|
|
394
|
+
force: true,
|
|
395
|
+
})
|
|
396
|
+
}
|
|
152
397
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
398
|
+
// Update package.json with additional configurations
|
|
399
|
+
const pkgJsonContent = await fs.readFile(packageJsonPath, 'utf-8')
|
|
400
|
+
const pkgJson = JSON.parse(pkgJsonContent)
|
|
401
|
+
|
|
402
|
+
// Update engine requirement
|
|
403
|
+
if (!pkgJson.engines) {
|
|
404
|
+
pkgJson.engines = {}
|
|
405
|
+
}
|
|
406
|
+
pkgJson.engines.node = napiEngineRequirement(options.minNodeApiVersion)
|
|
157
407
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
408
|
+
// Update license if different from template
|
|
409
|
+
if (options.license && pkgJson.license !== options.license) {
|
|
410
|
+
pkgJson.license = options.license
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Update test framework if needed
|
|
414
|
+
if (options.testFramework !== 'ava') {
|
|
415
|
+
// This would require more complex logic to update test scripts and dependencies
|
|
416
|
+
debug(
|
|
417
|
+
`Test framework ${options.testFramework} requested but not yet implemented`,
|
|
418
|
+
)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
await fs.writeFile(
|
|
422
|
+
packageJsonPath,
|
|
423
|
+
JSON.stringify(pkgJson, null, 2) + '\n',
|
|
424
|
+
)
|
|
425
|
+
} catch (error) {
|
|
426
|
+
throw new Error(`Failed to create project: ${error}`)
|
|
427
|
+
}
|
|
161
428
|
}
|
|
162
|
-
}
|
|
163
429
|
|
|
164
|
-
|
|
165
|
-
return [
|
|
166
|
-
{
|
|
167
|
-
target: './.gitignore',
|
|
168
|
-
content: gitIgnore,
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
target: './.npmignore',
|
|
172
|
-
content: npmIgnore,
|
|
173
|
-
},
|
|
174
|
-
]
|
|
430
|
+
debug(`Project created at: ${options.path}`)
|
|
175
431
|
}
|
|
176
432
|
|
|
177
|
-
async function
|
|
178
|
-
|
|
179
|
-
if (!output) {
|
|
180
|
-
continue
|
|
181
|
-
}
|
|
433
|
+
async function ensurePath(path: string, dryRun = false) {
|
|
434
|
+
const stat = await statAsync(path, {}).catch(() => undefined)
|
|
182
435
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
436
|
+
// file descriptor exists
|
|
437
|
+
if (stat) {
|
|
438
|
+
if (stat.isFile()) {
|
|
439
|
+
throw new Error(
|
|
440
|
+
`Path ${path} for creating new napi-rs project already exists and it's not a directory.`,
|
|
441
|
+
)
|
|
442
|
+
} else if (stat.isDirectory()) {
|
|
443
|
+
const files = await readdirAsync(path)
|
|
444
|
+
if (files.length) {
|
|
445
|
+
throw new Error(
|
|
446
|
+
`Path ${path} for creating new napi-rs project already exists and it's not empty.`,
|
|
447
|
+
)
|
|
448
|
+
}
|
|
188
449
|
}
|
|
450
|
+
}
|
|
189
451
|
|
|
452
|
+
if (!dryRun) {
|
|
190
453
|
try {
|
|
191
|
-
|
|
192
|
-
|
|
454
|
+
debug(`Try to create target directory: ${path}`)
|
|
455
|
+
if (!dryRun) {
|
|
456
|
+
await mkdirAsync(path, { recursive: true })
|
|
457
|
+
}
|
|
193
458
|
} catch (e) {
|
|
194
|
-
throw new Error(`Failed to
|
|
459
|
+
throw new Error(`Failed to create target directory: ${path}`, {
|
|
460
|
+
cause: e,
|
|
461
|
+
})
|
|
195
462
|
}
|
|
196
463
|
}
|
|
197
464
|
}
|