feat(cli): support read config from the given config file (#1859)

This commit is contained in:
LongYinan 2023-12-15 21:54:33 +08:00 committed by GitHub
parent 6f40f94d09
commit 5cab2bc57b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 397 additions and 40 deletions

View file

@ -31,7 +31,7 @@ const NEW_OPTIONS: CommandSchema = {
{ {
name: 'path', name: 'path',
type: 'string', type: 'string',
description: 'The path where the napi-rs project will be created.', description: 'The path where the NAPI-RS project will be created.',
required: true, required: true,
}, },
], ],
@ -108,7 +108,7 @@ const NEW_OPTIONS: CommandSchema = {
const BUILD_OPTIONS: CommandSchema = { const BUILD_OPTIONS: CommandSchema = {
name: 'build', name: 'build',
description: 'Build the napi-rs project', description: 'Build the NAPI-RS project',
args: [], args: [],
options: [ options: [
{ {
@ -129,6 +129,12 @@ const BUILD_OPTIONS: CommandSchema = {
type: 'string', type: 'string',
description: 'Path to `Cargo.toml`', description: 'Path to `Cargo.toml`',
}, },
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{ {
name: 'packageJsonPath', name: 'packageJsonPath',
type: 'string', type: 'string',
@ -253,7 +259,7 @@ const BUILD_OPTIONS: CommandSchema = {
name: 'watch', name: 'watch',
type: 'boolean', type: 'boolean',
description: description:
'watch the crate changes and build continiously with `cargo-watch` crates', 'watch the crate changes and build continuously with `cargo-watch` crates',
short: 'w', short: 'w',
}, },
{ {
@ -288,6 +294,12 @@ const ARTIFACTS_OPTIONS: CommandSchema = {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
default: 'process.cwd()', default: 'process.cwd()',
}, },
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{ {
name: 'packageJsonPath', name: 'packageJsonPath',
type: 'string', type: 'string',
@ -323,6 +335,12 @@ const CREATE_NPM_DIRS_OPTIONS: CommandSchema = {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
default: 'process.cwd()', default: 'process.cwd()',
}, },
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{ {
name: 'packageJsonPath', name: 'packageJsonPath',
type: 'string', type: 'string',
@ -346,7 +364,7 @@ const CREATE_NPM_DIRS_OPTIONS: CommandSchema = {
const RENAME_OPTIONS: CommandSchema = { const RENAME_OPTIONS: CommandSchema = {
name: 'rename', name: 'rename',
description: 'Rename the napi-rs project', description: 'Rename the NAPI-RS project',
args: [], args: [],
options: [ options: [
{ {
@ -356,6 +374,12 @@ const RENAME_OPTIONS: CommandSchema = {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
default: 'process.cwd()', default: 'process.cwd()',
}, },
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{ {
name: 'packageJsonPath', name: 'packageJsonPath',
type: 'string', type: 'string',
@ -416,6 +440,12 @@ const UNIVERSALIZE_OPTIONS: CommandSchema = {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
default: 'process.cwd()', default: 'process.cwd()',
}, },
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{ {
name: 'packageJsonPath', name: 'packageJsonPath',
type: 'string', type: 'string',
@ -445,6 +475,12 @@ const VERSION_OPTIONS: CommandSchema = {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
default: 'process.cwd()', default: 'process.cwd()',
}, },
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{ {
name: 'packageJsonPath', name: 'packageJsonPath',
type: 'string', type: 'string',
@ -472,6 +508,12 @@ const PRE_PUBLISH_OPTIONS: CommandSchema = {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
default: 'process.cwd()', default: 'process.cwd()',
}, },
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{ {
name: 'packageJsonPath', name: 'packageJsonPath',
type: 'string', type: 'string',

View file

@ -26,6 +26,7 @@ new NapiCli().artifacts({
| --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ | | --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --help,-h | | | | get help | | | --help,-h | | | | get help |
| cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path | | cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` | | packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` |
| outputDir | --output-dir,-o | string | false | './artifacts' | Path to the folder where all built `.node` files put, same as `--output-dir` of build command | | outputDir | --output-dir,-o | string | false | './artifacts' | Path to the folder where all built `.node` files put, same as `--output-dir` of build command |
| npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put | | npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put |

View file

@ -2,7 +2,7 @@
> This file is generated by cli/codegen. Do not edit this file manually. > This file is generated by cli/codegen. Do not edit this file manually.
Build the napi-rs project Build the NAPI-RS project
## Usage ## Usage
@ -28,6 +28,7 @@ new NapiCli().build({
| target | --target,-t | string | false | | Build for the target triple, bypassed to `cargo build --target` | | target | --target,-t | string | false | | Build for the target triple, bypassed to `cargo build --target` |
| cwd | --cwd | string | false | | The working directory of where napi command will be executed in, all other paths options are relative to this path | | cwd | --cwd | string | false | | The working directory of where napi command will be executed in, all other paths options are relative to this path |
| manifestPath | --manifest-path | string | false | | Path to `Cargo.toml` | | manifestPath | --manifest-path | string | false | | Path to `Cargo.toml` |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| packageJsonPath | --package-json-path | string | false | | Path to `package.json` | | packageJsonPath | --package-json-path | string | false | | Path to `package.json` |
| targetDir | --target-dir | string | false | | Directory for all crate generated artifacts, see `cargo build --target-dir` | | targetDir | --target-dir | string | false | | Directory for all crate generated artifacts, see `cargo build --target-dir` |
| outputDir | --output-dir,-o | string | false | | Path to where all the built files would be put. Default to the crate folder | | outputDir | --output-dir,-o | string | false | | Path to where all the built files would be put. Default to the crate folder |
@ -48,7 +49,7 @@ new NapiCli().build({
| crossCompile | --cross-compile,-x | boolean | false | | [experimental] cross-compile for the specified target with `cargo-xwin` on windows and `cargo-zigbuild` on other platform | | crossCompile | --cross-compile,-x | boolean | false | | [experimental] cross-compile for the specified target with `cargo-xwin` on windows and `cargo-zigbuild` on other platform |
| useCross | --use-cross | boolean | false | | [experimental] use [cross](https://github.com/cross-rs/cross) instead of `cargo` | | useCross | --use-cross | boolean | false | | [experimental] use [cross](https://github.com/cross-rs/cross) instead of `cargo` |
| useNapiCross | --use-napi-cross | boolean | false | | [experimental] use @napi-rs/cross-toolchain to cross-compile Linux arm/arm64/x64 gnu targets. | | useNapiCross | --use-napi-cross | boolean | false | | [experimental] use @napi-rs/cross-toolchain to cross-compile Linux arm/arm64/x64 gnu targets. |
| watch | --watch,-w | boolean | false | | watch the crate changes and build continiously with `cargo-watch` crates | | watch | --watch,-w | boolean | false | | watch the crate changes and build continuously with `cargo-watch` crates |
| features | --features,-F | string[] | false | | Space-separated list of features to activate | | features | --features,-F | string[] | false | | Space-separated list of features to activate |
| allFeatures | --all-features | boolean | false | | Activate all available features | | allFeatures | --all-features | boolean | false | | Activate all available features |
| noDefaultFeatures | --no-default-features | boolean | false | | Do not activate the `default` feature | | noDefaultFeatures | --no-default-features | boolean | false | | Do not activate the `default` feature |

View file

@ -26,6 +26,7 @@ new NapiCli().createNpmDirs({
| --------------- | ------------------- | ------- | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ | | --------------- | ------------------- | ------- | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --help,-h | | | | get help | | | --help,-h | | | | get help |
| cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path | | cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` | | packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` |
| npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put | | npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put |
| dryRun | --dry-run | boolean | false | false | Dry run without touching file system | | dryRun | --dry-run | boolean | false | false | Dry run without touching file system |

View file

@ -25,7 +25,7 @@ new NapiCli().new({
| Options | CLI Options | type | required | default | description | | Options | CLI Options | type | required | default | description |
| -------------------- | ------------------------ | -------- | -------- | ------- | -------------------------------------------------------------------------------- | | -------------------- | ------------------------ | -------- | -------- | ------- | -------------------------------------------------------------------------------- |
| | --help,-h | | | | get help | | | --help,-h | | | | get help |
| path | <path> | true | string | | The path where the napi-rs project will be created. | | path | <path> | true | string | | The path where the NAPI-RS project will be created. |
| name | --name,-n | string | false | | The name of the project, default to the name of the directory if not provided | | name | --name,-n | string | false | | The name of the project, default to the name of the directory if not provided |
| minNodeApiVersion | --min-node-api,-v | number | false | 4 | The minimum Node-API version to support | | minNodeApiVersion | --min-node-api,-v | number | false | 4 | The minimum Node-API version to support |
| license | --license,-l | string | false | 'MIT' | License for open-sourced project | | license | --license,-l | string | false | 'MIT' | License for open-sourced project |

View file

@ -26,6 +26,7 @@ new NapiCli().prePublish({
| --------------- | ------------------- | ---------------- | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ | | --------------- | ------------------- | ---------------- | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --help,-h | | | | get help | | | --help,-h | | | | get help |
| cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path | | cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` | | packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` |
| npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put | | npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put |
| tagStyle | --tag-style | 'npm' \| 'lerna' | false | 'lerna' | git tag style, `npm` or `lerna` | | tagStyle | --tag-style | 'npm' \| 'lerna' | false | 'lerna' | git tag style, `npm` or `lerna` |

View file

@ -2,7 +2,7 @@
> This file is generated by cli/codegen. Do not edit this file manually. > This file is generated by cli/codegen. Do not edit this file manually.
Rename the napi-rs project Rename the NAPI-RS project
## Usage ## Usage
@ -26,6 +26,7 @@ new NapiCli().rename({
| --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ | | --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --help,-h | | | | get help | | | --help,-h | | | | get help |
| cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path | | cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` | | packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` |
| npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put | | npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put |
| name | --name,-n | string | false | | The new name of the project | | name | --name,-n | string | false | | The new name of the project |

View file

@ -26,5 +26,6 @@ new NapiCli().universalize({
| --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ | | --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --help,-h | | | | get help | | | --help,-h | | | | get help |
| cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path | | cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` | | packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` |
| outputDir | --output-dir,-o | string | false | './' | Path to the folder where all built `.node` files put, same as `--output-dir` of build command | | outputDir | --output-dir,-o | string | false | './' | Path to the folder where all built `.node` files put, same as `--output-dir` of build command |

View file

@ -26,5 +26,6 @@ new NapiCli().version({
| --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ | | --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --help,-h | | | | get help | | | --help,-h | | | | get help |
| cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path | | cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` | | packageJsonPath | --package-json-path | string | false | 'package.json' | Path to `package.json` |
| npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put | | npmDir | --npm-dir | string | false | 'npm' | Path to the folder where the npm packages put |

View file

@ -90,7 +90,10 @@ export async function buildProject(options: BuildOptions) {
process.env.CARGO_BUILD_TARGET_DIR ?? process.env.CARGO_BUILD_TARGET_DIR ??
metadata.target_directory, metadata.target_directory,
await readNapiConfig( await readNapiConfig(
resolvePath(options.packageJsonPath ?? 'package.json'), resolvePath(
options.configPath ?? options.packageJsonPath ?? 'package.json',
),
options.configPath ? resolvePath(options.configPath) : undefined,
), ),
) )

View file

@ -43,10 +43,13 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
const packageJsonPath = resolve(options.cwd, options.packageJsonPath) const packageJsonPath = resolve(options.cwd, options.packageJsonPath)
const npmPath = resolve(options.cwd, options.npmDir) const npmPath = resolve(options.cwd, options.npmDir)
debug(`Read content from [${packageJsonPath}]`) debug(`Read content from [${options.configPath ?? packageJsonPath}]`)
const { targets, binaryName, packageName, packageJson } = const { targets, binaryName, packageName, packageJson } =
await readNapiConfig(packageJsonPath) await readNapiConfig(
packageJsonPath,
options.configPath ? resolve(options.cwd, options.configPath) : undefined,
)
for (const target of targets) { for (const target of targets) {
const targetDir = join(npmPath, `${target.platformArchABI}`) const targetDir = join(npmPath, `${target.platformArchABI}`)

View file

@ -31,10 +31,14 @@ export async function prePublish(userOptions: PrePublishOptions) {
const options = applyDefaultPrePublishOptions(userOptions) const options = applyDefaultPrePublishOptions(userOptions)
const configPath = relative(
options.cwd,
options.configPath ?? options.packageJsonPath,
)
const packageJsonPath = relative(options.cwd, options.packageJsonPath) const packageJsonPath = relative(options.cwd, options.packageJsonPath)
const { packageJson, targets, packageName, binaryName, npmClient } = const { packageJson, targets, packageName, binaryName, npmClient } =
await readNapiConfig(packageJsonPath) await readNapiConfig(configPath, configPath)
async function createGhRelease(packageName: string, version: string) { async function createGhRelease(packageName: string, version: string) {
if (!options.ghRelease) { if (!options.ghRelease) {

View file

@ -30,6 +30,15 @@ export async function renameProject(userOptions: RenameOptions) {
}, },
) )
if (options.configPath) {
const configPath = resolve(options.cwd, options.configPath)
const configContent = await readFileAsync(configPath, 'utf8')
const configData = JSON.parse(configContent)
configData.binaryName = options.binaryName
configData.packageName = options.packageName
await writeFileAsync(configPath, JSON.stringify(configData, null, 2))
}
await writeFileAsync( await writeFileAsync(
packageJsonPath, packageJsonPath,
JSON.stringify(packageJsonData, null, 2), JSON.stringify(packageJsonData, null, 2),

View file

@ -27,7 +27,10 @@ export async function universalizeBinaries(userOptions: UniversalizeOptions) {
const packageJsonPath = join(options.cwd, options.packageJsonPath) const packageJsonPath = join(options.cwd, options.packageJsonPath)
const config = await readNapiConfig(packageJsonPath) const config = await readNapiConfig(
packageJsonPath,
options.configPath ? resolve(options.cwd, options.configPath) : undefined,
)
const target = config.targets.find( const target = config.targets.find(
(t) => t.platform === process.platform && t.arch === 'universal', (t) => t.platform === process.platform && t.arch === 'universal',

View file

@ -13,7 +13,10 @@ export async function version(userOptions: VersionOptions) {
const options = applyDefaultVersionOptions(userOptions) const options = applyDefaultVersionOptions(userOptions)
const packageJsonPath = resolve(options.cwd, options.packageJsonPath) const packageJsonPath = resolve(options.cwd, options.packageJsonPath)
const config = await readNapiConfig(packageJsonPath) const config = await readNapiConfig(
packageJsonPath,
options.configPath ? resolve(options.cwd, options.configPath) : undefined,
)
for (const target of config.targets) { for (const target of config.targets) {
const pkgDir = resolve(options.cwd, options.npmDir, target.platformArchABI) const pkgDir = resolve(options.cwd, options.npmDir, target.platformArchABI)

View file

@ -15,6 +15,10 @@ export abstract class BaseArtifactsCommand extends Command {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
}) })
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', { packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`', description: 'Path to `package.json`',
}) })
@ -31,6 +35,7 @@ export abstract class BaseArtifactsCommand extends Command {
getOptions() { getOptions() {
return { return {
cwd: this.cwd, cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath, packageJsonPath: this.packageJsonPath,
outputDir: this.outputDir, outputDir: this.outputDir,
npmDir: this.npmDir, npmDir: this.npmDir,
@ -48,6 +53,10 @@ export interface ArtifactsOptions {
* @default process.cwd() * @default process.cwd()
*/ */
cwd?: string cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/** /**
* Path to `package.json` * Path to `package.json`
* *

View file

@ -6,7 +6,7 @@ export abstract class BaseBuildCommand extends Command {
static paths = [['build']] static paths = [['build']]
static usage = Command.Usage({ static usage = Command.Usage({
description: 'Build the napi-rs project', description: 'Build the NAPI-RS project',
}) })
target?: string = Option.String('--target,-t', { target?: string = Option.String('--target,-t', {
@ -23,6 +23,10 @@ export abstract class BaseBuildCommand extends Command {
description: 'Path to `Cargo.toml`', description: 'Path to `Cargo.toml`',
}) })
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath?: string = Option.String('--package-json-path', { packageJsonPath?: string = Option.String('--package-json-path', {
description: 'Path to `package.json`', description: 'Path to `package.json`',
}) })
@ -117,7 +121,7 @@ export abstract class BaseBuildCommand extends Command {
watch?: boolean = Option.Boolean('--watch,-w', { watch?: boolean = Option.Boolean('--watch,-w', {
description: description:
'watch the crate changes and build continiously with `cargo-watch` crates', 'watch the crate changes and build continuously with `cargo-watch` crates',
}) })
features?: string[] = Option.Array('--features,-F', { features?: string[] = Option.Array('--features,-F', {
@ -137,6 +141,7 @@ export abstract class BaseBuildCommand extends Command {
target: this.target, target: this.target,
cwd: this.cwd, cwd: this.cwd,
manifestPath: this.manifestPath, manifestPath: this.manifestPath,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath, packageJsonPath: this.packageJsonPath,
targetDir: this.targetDir, targetDir: this.targetDir,
outputDir: this.outputDir, outputDir: this.outputDir,
@ -166,7 +171,7 @@ export abstract class BaseBuildCommand extends Command {
} }
/** /**
* Build the napi-rs project * Build the NAPI-RS project
*/ */
export interface BuildOptions { export interface BuildOptions {
/** /**
@ -181,6 +186,10 @@ export interface BuildOptions {
* Path to `Cargo.toml` * Path to `Cargo.toml`
*/ */
manifestPath?: string manifestPath?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/** /**
* Path to `package.json` * Path to `package.json`
*/ */
@ -262,7 +271,7 @@ export interface BuildOptions {
*/ */
useNapiCross?: boolean useNapiCross?: boolean
/** /**
* watch the crate changes and build continiously with `cargo-watch` crates * watch the crate changes and build continuously with `cargo-watch` crates
*/ */
watch?: boolean watch?: boolean
/** /**

View file

@ -14,6 +14,10 @@ export abstract class BaseCreateNpmDirsCommand extends Command {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
}) })
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', { packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`', description: 'Path to `package.json`',
}) })
@ -29,6 +33,7 @@ export abstract class BaseCreateNpmDirsCommand extends Command {
getOptions() { getOptions() {
return { return {
cwd: this.cwd, cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath, packageJsonPath: this.packageJsonPath,
npmDir: this.npmDir, npmDir: this.npmDir,
dryRun: this.dryRun, dryRun: this.dryRun,
@ -46,6 +51,10 @@ export interface CreateNpmDirsOptions {
* @default process.cwd() * @default process.cwd()
*/ */
cwd?: string cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/** /**
* Path to `package.json` * Path to `package.json`
* *

View file

@ -72,7 +72,7 @@ export abstract class BaseNewCommand extends Command {
*/ */
export interface NewOptions { export interface NewOptions {
/** /**
* The path where the napi-rs project will be created. * The path where the NAPI-RS project will be created.
*/ */
path: string path: string
/** /**

View file

@ -15,6 +15,10 @@ export abstract class BasePrePublishCommand extends Command {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
}) })
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', { packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`', description: 'Path to `package.json`',
}) })
@ -46,6 +50,7 @@ export abstract class BasePrePublishCommand extends Command {
getOptions() { getOptions() {
return { return {
cwd: this.cwd, cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath, packageJsonPath: this.packageJsonPath,
npmDir: this.npmDir, npmDir: this.npmDir,
tagStyle: this.tagStyle, tagStyle: this.tagStyle,
@ -67,6 +72,10 @@ export interface PrePublishOptions {
* @default process.cwd() * @default process.cwd()
*/ */
cwd?: string cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/** /**
* Path to `package.json` * Path to `package.json`
* *

View file

@ -6,7 +6,7 @@ export abstract class BaseRenameCommand extends Command {
static paths = [['rename']] static paths = [['rename']]
static usage = Command.Usage({ static usage = Command.Usage({
description: 'Rename the napi-rs project', description: 'Rename the NAPI-RS project',
}) })
cwd = Option.String('--cwd', process.cwd(), { cwd = Option.String('--cwd', process.cwd(), {
@ -14,6 +14,10 @@ export abstract class BaseRenameCommand extends Command {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
}) })
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', { packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`', description: 'Path to `package.json`',
}) })
@ -49,6 +53,7 @@ export abstract class BaseRenameCommand extends Command {
getOptions() { getOptions() {
return { return {
cwd: this.cwd, cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath, packageJsonPath: this.packageJsonPath,
npmDir: this.npmDir, npmDir: this.npmDir,
name: this.$$name, name: this.$$name,
@ -62,7 +67,7 @@ export abstract class BaseRenameCommand extends Command {
} }
/** /**
* Rename the napi-rs project * Rename the NAPI-RS project
*/ */
export interface RenameOptions { export interface RenameOptions {
/** /**
@ -71,6 +76,10 @@ export interface RenameOptions {
* @default process.cwd() * @default process.cwd()
*/ */
cwd?: string cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/** /**
* Path to `package.json` * Path to `package.json`
* *

View file

@ -14,6 +14,10 @@ export abstract class BaseUniversalizeCommand extends Command {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
}) })
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', { packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`', description: 'Path to `package.json`',
}) })
@ -26,6 +30,7 @@ export abstract class BaseUniversalizeCommand extends Command {
getOptions() { getOptions() {
return { return {
cwd: this.cwd, cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath, packageJsonPath: this.packageJsonPath,
outputDir: this.outputDir, outputDir: this.outputDir,
} }
@ -42,6 +47,10 @@ export interface UniversalizeOptions {
* @default process.cwd() * @default process.cwd()
*/ */
cwd?: string cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/** /**
* Path to `package.json` * Path to `package.json`
* *

View file

@ -14,6 +14,10 @@ export abstract class BaseVersionCommand extends Command {
'The working directory of where napi command will be executed in, all other paths options are relative to this path', 'The working directory of where napi command will be executed in, all other paths options are relative to this path',
}) })
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', { packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`', description: 'Path to `package.json`',
}) })
@ -25,6 +29,7 @@ export abstract class BaseVersionCommand extends Command {
getOptions() { getOptions() {
return { return {
cwd: this.cwd, cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath, packageJsonPath: this.packageJsonPath,
npmDir: this.npmDir, npmDir: this.npmDir,
} }
@ -41,6 +46,10 @@ export interface VersionOptions {
* @default process.cwd() * @default process.cwd()
*/ */
cwd?: string cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/** /**
* Path to `package.json` * Path to `package.json`
* *

View file

@ -0,0 +1,97 @@
# Snapshot report for `src/utils/__tests__/config.spec.ts`
The actual snapshot is saved in `config.spec.ts.snap`.
Generated by [AVA](https://avajs.dev).
## should be able to read config from package.json
> Snapshot 1
{
binaryName: 'testing',
npmClient: 'npm',
packageJson: {
name: '@napi-rs/testing',
napi: {
binaryName: 'testing',
packageName: '@napi-rs/testing',
targets: [
'x86_64-unknown-linux-gnu',
'x86_64-pc-windows-msvc',
'x86_64-apple-darwin',
],
},
version: '0.0.0',
},
packageName: '@napi-rs/testing',
targets: [
{
abi: 'gnu',
arch: 'x64',
platform: 'linux',
platformArchABI: 'linux-x64-gnu',
triple: 'x86_64-unknown-linux-gnu',
},
{
abi: 'msvc',
arch: 'x64',
platform: 'win32',
platformArchABI: 'win32-x64-msvc',
triple: 'x86_64-pc-windows-msvc',
},
{
abi: null,
arch: 'x64',
platform: 'darwin',
platformArchABI: 'darwin-x64',
triple: 'x86_64-apple-darwin',
},
],
}
## should be able to read config from napi.json
> Snapshot 1
{
binaryName: 'testing',
npmClient: 'npm',
packageJson: {
name: '@napi-rs/testing',
napi: {
binaryName: 'testing',
packageName: '@node-rs/testing',
targets: [
'x86_64-unknown-linux-gnu',
'x86_64-apple-darwin',
'aarch64-apple-darwin',
],
},
version: '0.0.0',
},
packageName: '@node-rs/testing',
targets: [
{
abi: 'gnu',
arch: 'x64',
platform: 'linux',
platformArchABI: 'linux-x64-gnu',
triple: 'x86_64-unknown-linux-gnu',
},
{
abi: null,
arch: 'x64',
platform: 'darwin',
platformArchABI: 'darwin-x64',
triple: 'x86_64-apple-darwin',
},
{
abi: null,
arch: 'arm64',
platform: 'darwin',
platformArchABI: 'darwin-arm64',
triple: 'aarch64-apple-darwin',
},
],
}

View file

@ -9,12 +9,13 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1 > Snapshot 1
[ [
'>= 8.6.0', '>= 8.6.0 < 9 || >= 9.0.0 < 10 || >= 10.0.0',
'>= 8.10.0 < 9 || >= 9.3.0', '>= 8.10.0 < 9 || >= 9.3.0 < 10 || >= 10.0.0',
'>= 6.14.2 < 7 || >= 8.11.2 < 9 || >= 9.11.0', '>= 6.14.2 < 7 || >= 8.11.2 < 9 || >= 9.11.0 < 10 || >= 10.0.0',
'>= 10.16.0 < 11 || >= 11.8.0', '>= 10.16.0 < 11 || >= 11.8.0 < 12 || >= 12.0.0',
'>= 10.17.0 < 11 || >= 12.11.0', '>= 10.17.0 < 11 || >= 12.11.0 < 13 || >= 13.0.0',
'>= 10.20.0 < 11 || >= 12.17.0 < 13 || >= 14.0.0', '>= 10.20.0 < 11 || >= 12.17.0 < 13 || >= 14.0.0',
'>= 10.23.0 < 11 || >= 12.19.0 < 13 || >= 14.12.0', '>= 10.23.0 < 11 || >= 12.19.0 < 13 || >= 14.12.0 < 15 || >= 15.0.0',
'>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0', '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0',
'>= 18.17.0 < 19 || >= 20.3.0 < 21 || >= 21.1.0',
] ]

View file

@ -0,0 +1,81 @@
import { unlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import ava, { TestFn } from 'ava'
import {
CommonPackageJsonFields,
UserNapiConfig,
readNapiConfig,
} from '../config.js'
const NON_EXISTENT_FILE = 'non-existent-file'
const test = ava as TestFn<{
configPath: string
packageJson: string
pkgJson: CommonPackageJsonFields
config: UserNapiConfig
}>
test.before(async (t) => {
const tmp = tmpdir()
const configPath = join(tmp, 'napi.json')
const packageJson = join(tmp, 'package.json')
const pkgJson = {
name: '@napi-rs/testing',
version: '0.0.0',
napi: {
binaryName: 'testing',
packageName: '@napi-rs/testing',
targets: [
'x86_64-unknown-linux-gnu',
'x86_64-pc-windows-msvc',
'x86_64-apple-darwin',
],
},
}
await writeFile(packageJson, JSON.stringify(pkgJson, null, 2))
const config = {
binaryName: 'testing',
packageName: '@node-rs/testing',
targets: [
'x86_64-unknown-linux-gnu',
'x86_64-apple-darwin',
'aarch64-apple-darwin',
],
}
await writeFile(configPath, JSON.stringify(config, null, 2))
t.context = { configPath, config, packageJson, pkgJson }
})
test.after(async (t) => {
await unlink(t.context.configPath)
await unlink(t.context.packageJson)
})
test('should throw if package.json not found', async (t) => {
await t.throwsAsync(() => readNapiConfig(NON_EXISTENT_FILE), {
message: `package.json not found at ${NON_EXISTENT_FILE}`,
})
})
test('should throw if napi.json not found', async (t) => {
const { packageJson } = t.context
await t.throwsAsync(() => readNapiConfig(packageJson, NON_EXISTENT_FILE), {
message: `NAPI-RS config not found at ${NON_EXISTENT_FILE}`,
})
})
test('should be able to read config from package.json', async (t) => {
const { packageJson } = t.context
const config = await readNapiConfig(packageJson)
t.snapshot(config)
})
test('should be able to read config from napi.json', async (t) => {
const { packageJson, configPath } = t.context
const config = await readNapiConfig(packageJson, configPath)
t.snapshot(config)
})

View file

@ -1,9 +1,10 @@
import { underline, yellow } from 'colorette'
import { merge, omit } from 'lodash-es' import { merge, omit } from 'lodash-es'
import { fileExists, readFileAsync } from './misc.js' import { fileExists, readFileAsync } from './misc.js'
import { DEFAULT_TARGETS, parseTriple, Target } from './target.js' import { DEFAULT_TARGETS, parseTriple, Target } from './target.js'
interface UserNapiConfig { export interface UserNapiConfig {
/** /**
* Name of the binary to be generated, default to `index` * Name of the binary to be generated, default to `index`
*/ */
@ -89,9 +90,15 @@ export type NapiConfig = Required<
packageJson: CommonPackageJsonFields packageJson: CommonPackageJsonFields
} }
export async function readNapiConfig(path: string): Promise<NapiConfig> { export async function readNapiConfig(
path: string,
configPath?: string,
): Promise<NapiConfig> {
if (configPath && !(await fileExists(configPath))) {
throw new Error(`NAPI-RS config not found at ${configPath}`)
}
if (!(await fileExists(path))) { if (!(await fileExists(path))) {
throw new Error(`napi-rs config not found at ${path}`) throw new Error(`package.json not found at ${path}`)
} }
// May support multiple config sources later on. // May support multiple config sources later on.
const content = await readFileAsync(path, 'utf8') const content = await readFileAsync(path, 'utf8')
@ -99,12 +106,34 @@ export async function readNapiConfig(path: string): Promise<NapiConfig> {
try { try {
pkgJson = JSON.parse(content) as CommonPackageJsonFields pkgJson = JSON.parse(content) as CommonPackageJsonFields
} catch (e) { } catch (e) {
throw new Error('Failed to parse napi-rs config', { throw new Error(`Failed to parse package.json at ${path}`, {
cause: e, cause: e,
}) })
} }
let separatedConfig: UserNapiConfig | undefined
if (configPath) {
const configContent = await readFileAsync(configPath, 'utf8')
try {
separatedConfig = JSON.parse(configContent) as UserNapiConfig
} catch (e) {
throw new Error(`Failed to parse NAPI-RS config at ${configPath}`, {
cause: e,
})
}
}
const userNapiConfig = pkgJson.napi ?? {} const userNapiConfig = pkgJson.napi ?? {}
if (pkgJson.napi && separatedConfig) {
const pkgJsonPath = underline(path)
const configPathUnderline = underline(configPath!)
console.warn(
yellow(
`Both napi field in ${pkgJsonPath} and [NAPI-RS config](${configPathUnderline}) file are found, the NAPI-RS config file will be used.`,
),
)
Object.assign(userNapiConfig, separatedConfig)
}
const napiConfig: NapiConfig = merge( const napiConfig: NapiConfig = merge(
{ {
binaryName: 'index', binaryName: 'index',
@ -120,16 +149,26 @@ export async function readNapiConfig(path: string): Promise<NapiConfig> {
// compatible with old config // compatible with old config
if (userNapiConfig?.name) { if (userNapiConfig?.name) {
console.warn(
`[DEPRECATED] napi.name is deprecated, use napi.binaryName instead.`,
)
napiConfig.binaryName = userNapiConfig.name napiConfig.binaryName = userNapiConfig.name
} }
if (!targets.length) { if (!targets.length) {
let deprecatedWarned = false
const warning = `[DEPRECATED] napi.triples is deprecated, use napi.targets instead.`
if (userNapiConfig.triples?.defaults) { if (userNapiConfig.triples?.defaults) {
deprecatedWarned = true
console.warn(warning)
targets = targets.concat(DEFAULT_TARGETS) targets = targets.concat(DEFAULT_TARGETS)
} }
if (userNapiConfig.triples?.additional?.length) { if (userNapiConfig.triples?.additional?.length) {
targets = targets.concat(userNapiConfig.triples.additional) targets = targets.concat(userNapiConfig.triples.additional)
if (!deprecatedWarned) {
console.warn(warning)
}
} }
} }

View file

@ -7,20 +7,22 @@ export enum NapiVersion {
Napi6, Napi6,
Napi7, Napi7,
Napi8, Napi8,
Napi9,
} }
/// because node support new napi version in some minor version updates, so we might meet such situation: /// because node support new napi version in some minor version updates, so we might meet such situation:
/// `node v10.20.0` supports `napi5` and `napi6`, but `node v12.0.0` only support `napi4`, /// `node v10.20.0` supports `napi5` and `napi6`, but `node v12.0.0` only support `napi4`,
/// by which, we can not tell directly napi version supportness from node version directly. /// by which, we can not tell directly napi version supportless from node version directly.
const NAPI_VERSION_MATRIX = new Map<NapiVersion, string>([ const NAPI_VERSION_MATRIX = new Map<NapiVersion, string>([
[NapiVersion.Napi1, '8.6.0'], [NapiVersion.Napi1, '8.6.0 | 9.0.0 | 10.0.0'],
[NapiVersion.Napi2, '8.10.0 | 9.3.0'], [NapiVersion.Napi2, '8.10.0 | 9.3.0 | 10.0.0'],
[NapiVersion.Napi3, '6.14.2 | 8.11.2 | 9.11.0'], [NapiVersion.Napi3, '6.14.2 | 8.11.2 | 9.11.0 | 10.0.0'],
[NapiVersion.Napi4, '10.16.0 | 11.8.0'], [NapiVersion.Napi4, '10.16.0 | 11.8.0 | 12.0.0'],
[NapiVersion.Napi5, '10.17.0 | 12.11.0'], [NapiVersion.Napi5, '10.17.0 | 12.11.0 | 13.0.0'],
[NapiVersion.Napi6, '10.20.0 | 12.17.0 | 14.0.0'], [NapiVersion.Napi6, '10.20.0 | 12.17.0 | 14.0.0'],
[NapiVersion.Napi7, '10.23.0 | 12.19.0 | 14.12.0'], [NapiVersion.Napi7, '10.23.0 | 12.19.0 | 14.12.0 | 15.0.0'],
[NapiVersion.Napi8, '12.22.0 | 14.17.0 | 15.12.0'], [NapiVersion.Napi8, '12.22.0 | 14.17.0 | 15.12.0 | 16.0.0'],
[NapiVersion.Napi9, '18.17.0 | 20.3.0 | 21.1.0'],
]) ])
interface NodeVersion { interface NodeVersion {