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',
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,
},
],
@ -108,7 +108,7 @@ const NEW_OPTIONS: CommandSchema = {
const BUILD_OPTIONS: CommandSchema = {
name: 'build',
description: 'Build the napi-rs project',
description: 'Build the NAPI-RS project',
args: [],
options: [
{
@ -129,6 +129,12 @@ const BUILD_OPTIONS: CommandSchema = {
type: 'string',
description: 'Path to `Cargo.toml`',
},
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{
name: 'packageJsonPath',
type: 'string',
@ -253,7 +259,7 @@ const BUILD_OPTIONS: CommandSchema = {
name: 'watch',
type: 'boolean',
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',
},
{
@ -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',
default: 'process.cwd()',
},
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{
name: 'packageJsonPath',
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',
default: 'process.cwd()',
},
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{
name: 'packageJsonPath',
type: 'string',
@ -346,7 +364,7 @@ const CREATE_NPM_DIRS_OPTIONS: CommandSchema = {
const RENAME_OPTIONS: CommandSchema = {
name: 'rename',
description: 'Rename the napi-rs project',
description: 'Rename the NAPI-RS project',
args: [],
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',
default: 'process.cwd()',
},
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{
name: 'packageJsonPath',
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',
default: 'process.cwd()',
},
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{
name: 'packageJsonPath',
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',
default: 'process.cwd()',
},
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{
name: 'packageJsonPath',
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',
default: 'process.cwd()',
},
{
name: 'configPath',
type: 'string',
description: 'Path to `napi` config json file',
short: 'c',
},
{
name: 'packageJsonPath',
type: 'string',

View file

@ -26,6 +26,7 @@ new NapiCli().artifacts({
| --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --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 |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| 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 |
| 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.
Build the napi-rs project
Build the NAPI-RS project
## Usage
@ -28,6 +28,7 @@ new NapiCli().build({
| 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 |
| 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` |
| 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 |
@ -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 |
| 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. |
| 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 |
| allFeatures | --all-features | boolean | false | | Activate all available features |
| 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 |
| 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` |
| 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 |

View file

@ -25,7 +25,7 @@ new NapiCli().new({
| Options | CLI Options | type | required | default | description |
| -------------------- | ------------------------ | -------- | -------- | ------- | -------------------------------------------------------------------------------- |
| | --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 |
| 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 |

View file

@ -26,6 +26,7 @@ new NapiCli().prePublish({
| --------------- | ------------------- | ---------------- | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --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 |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| 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 |
| 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.
Rename the napi-rs project
Rename the NAPI-RS project
## Usage
@ -26,6 +26,7 @@ new NapiCli().rename({
| --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --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 |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| 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 |
| name | --name,-n | string | false | | The new name of the project |

View file

@ -26,5 +26,6 @@ new NapiCli().universalize({
| --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --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 |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| 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 |

View file

@ -26,5 +26,6 @@ new NapiCli().version({
| --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| | --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 |
| configPath | --config-path,-c | string | false | | Path to `napi` config json file |
| 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 |

View file

@ -90,7 +90,10 @@ export async function buildProject(options: BuildOptions) {
process.env.CARGO_BUILD_TARGET_DIR ??
metadata.target_directory,
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 npmPath = resolve(options.cwd, options.npmDir)
debug(`Read content from [${packageJsonPath}]`)
debug(`Read content from [${options.configPath ?? packageJsonPath}]`)
const { targets, binaryName, packageName, packageJson } =
await readNapiConfig(packageJsonPath)
await readNapiConfig(
packageJsonPath,
options.configPath ? resolve(options.cwd, options.configPath) : undefined,
)
for (const target of targets) {
const targetDir = join(npmPath, `${target.platformArchABI}`)

View file

@ -31,10 +31,14 @@ export async function prePublish(userOptions: PrePublishOptions) {
const options = applyDefaultPrePublishOptions(userOptions)
const configPath = relative(
options.cwd,
options.configPath ?? options.packageJsonPath,
)
const packageJsonPath = relative(options.cwd, options.packageJsonPath)
const { packageJson, targets, packageName, binaryName, npmClient } =
await readNapiConfig(packageJsonPath)
await readNapiConfig(configPath, configPath)
async function createGhRelease(packageName: string, version: string) {
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(
packageJsonPath,
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 config = await readNapiConfig(packageJsonPath)
const config = await readNapiConfig(
packageJsonPath,
options.configPath ? resolve(options.cwd, options.configPath) : undefined,
)
const target = config.targets.find(
(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 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) {
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',
})
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`',
})
@ -31,6 +35,7 @@ export abstract class BaseArtifactsCommand extends Command {
getOptions() {
return {
cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath,
outputDir: this.outputDir,
npmDir: this.npmDir,
@ -48,6 +53,10 @@ export interface ArtifactsOptions {
* @default process.cwd()
*/
cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/**
* Path to `package.json`
*

View file

@ -6,7 +6,7 @@ export abstract class BaseBuildCommand extends Command {
static paths = [['build']]
static usage = Command.Usage({
description: 'Build the napi-rs project',
description: 'Build the NAPI-RS project',
})
target?: string = Option.String('--target,-t', {
@ -23,6 +23,10 @@ export abstract class BaseBuildCommand extends Command {
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', {
description: 'Path to `package.json`',
})
@ -117,7 +121,7 @@ export abstract class BaseBuildCommand extends Command {
watch?: boolean = Option.Boolean('--watch,-w', {
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', {
@ -137,6 +141,7 @@ export abstract class BaseBuildCommand extends Command {
target: this.target,
cwd: this.cwd,
manifestPath: this.manifestPath,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath,
targetDir: this.targetDir,
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 {
/**
@ -181,6 +186,10 @@ export interface BuildOptions {
* Path to `Cargo.toml`
*/
manifestPath?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/**
* Path to `package.json`
*/
@ -262,7 +271,7 @@ export interface BuildOptions {
*/
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
/**

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',
})
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`',
})
@ -29,6 +33,7 @@ export abstract class BaseCreateNpmDirsCommand extends Command {
getOptions() {
return {
cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath,
npmDir: this.npmDir,
dryRun: this.dryRun,
@ -46,6 +51,10 @@ export interface CreateNpmDirsOptions {
* @default process.cwd()
*/
cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/**
* Path to `package.json`
*

View file

@ -72,7 +72,7 @@ export abstract class BaseNewCommand extends Command {
*/
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
/**

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',
})
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`',
})
@ -46,6 +50,7 @@ export abstract class BasePrePublishCommand extends Command {
getOptions() {
return {
cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath,
npmDir: this.npmDir,
tagStyle: this.tagStyle,
@ -67,6 +72,10 @@ export interface PrePublishOptions {
* @default process.cwd()
*/
cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/**
* Path to `package.json`
*

View file

@ -6,7 +6,7 @@ export abstract class BaseRenameCommand extends Command {
static paths = [['rename']]
static usage = Command.Usage({
description: 'Rename the napi-rs project',
description: 'Rename the NAPI-RS project',
})
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',
})
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`',
})
@ -49,6 +53,7 @@ export abstract class BaseRenameCommand extends Command {
getOptions() {
return {
cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath,
npmDir: this.npmDir,
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 {
/**
@ -71,6 +76,10 @@ export interface RenameOptions {
* @default process.cwd()
*/
cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/**
* 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',
})
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`',
})
@ -26,6 +30,7 @@ export abstract class BaseUniversalizeCommand extends Command {
getOptions() {
return {
cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath,
outputDir: this.outputDir,
}
@ -42,6 +47,10 @@ export interface UniversalizeOptions {
* @default process.cwd()
*/
cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/**
* 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',
})
configPath?: string = Option.String('--config-path,-c', {
description: 'Path to `napi` config json file',
})
packageJsonPath = Option.String('--package-json-path', 'package.json', {
description: 'Path to `package.json`',
})
@ -25,6 +29,7 @@ export abstract class BaseVersionCommand extends Command {
getOptions() {
return {
cwd: this.cwd,
configPath: this.configPath,
packageJsonPath: this.packageJsonPath,
npmDir: this.npmDir,
}
@ -41,6 +46,10 @@ export interface VersionOptions {
* @default process.cwd()
*/
cwd?: string
/**
* Path to `napi` config json file
*/
configPath?: string
/**
* 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
[
'>= 8.6.0',
'>= 8.10.0 < 9 || >= 9.3.0',
'>= 6.14.2 < 7 || >= 8.11.2 < 9 || >= 9.11.0',
'>= 10.16.0 < 11 || >= 11.8.0',
'>= 10.17.0 < 11 || >= 12.11.0',
'>= 8.6.0 < 9 || >= 9.0.0 < 10 || >= 10.0.0',
'>= 8.10.0 < 9 || >= 9.3.0 < 10 || >= 10.0.0',
'>= 6.14.2 < 7 || >= 8.11.2 < 9 || >= 9.11.0 < 10 || >= 10.0.0',
'>= 10.16.0 < 11 || >= 11.8.0 < 12 || >= 12.0.0',
'>= 10.17.0 < 11 || >= 12.11.0 < 13 || >= 13.0.0',
'>= 10.20.0 < 11 || >= 12.17.0 < 13 || >= 14.0.0',
'>= 10.23.0 < 11 || >= 12.19.0 < 13 || >= 14.12.0',
'>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.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 < 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 { fileExists, readFileAsync } from './misc.js'
import { DEFAULT_TARGETS, parseTriple, Target } from './target.js'
interface UserNapiConfig {
export interface UserNapiConfig {
/**
* Name of the binary to be generated, default to `index`
*/
@ -89,9 +90,15 @@ export type NapiConfig = Required<
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))) {
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.
const content = await readFileAsync(path, 'utf8')
@ -99,12 +106,34 @@ export async function readNapiConfig(path: string): Promise<NapiConfig> {
try {
pkgJson = JSON.parse(content) as CommonPackageJsonFields
} catch (e) {
throw new Error('Failed to parse napi-rs config', {
throw new Error(`Failed to parse package.json at ${path}`, {
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 ?? {}
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(
{
binaryName: 'index',
@ -120,16 +149,26 @@ export async function readNapiConfig(path: string): Promise<NapiConfig> {
// compatible with old config
if (userNapiConfig?.name) {
console.warn(
`[DEPRECATED] napi.name is deprecated, use napi.binaryName instead.`,
)
napiConfig.binaryName = userNapiConfig.name
}
if (!targets.length) {
let deprecatedWarned = false
const warning = `[DEPRECATED] napi.triples is deprecated, use napi.targets instead.`
if (userNapiConfig.triples?.defaults) {
deprecatedWarned = true
console.warn(warning)
targets = targets.concat(DEFAULT_TARGETS)
}
if (userNapiConfig.triples?.additional?.length) {
targets = targets.concat(userNapiConfig.triples.additional)
if (!deprecatedWarned) {
console.warn(warning)
}
}
}

View file

@ -7,20 +7,22 @@ export enum NapiVersion {
Napi6,
Napi7,
Napi8,
Napi9,
}
/// 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`,
/// 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>([
[NapiVersion.Napi1, '8.6.0'],
[NapiVersion.Napi2, '8.10.0 | 9.3.0'],
[NapiVersion.Napi3, '6.14.2 | 8.11.2 | 9.11.0'],
[NapiVersion.Napi4, '10.16.0 | 11.8.0'],
[NapiVersion.Napi5, '10.17.0 | 12.11.0'],
[NapiVersion.Napi1, '8.6.0 | 9.0.0 | 10.0.0'],
[NapiVersion.Napi2, '8.10.0 | 9.3.0 | 10.0.0'],
[NapiVersion.Napi3, '6.14.2 | 8.11.2 | 9.11.0 | 10.0.0'],
[NapiVersion.Napi4, '10.16.0 | 11.8.0 | 12.0.0'],
[NapiVersion.Napi5, '10.17.0 | 12.11.0 | 13.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.Napi8, '12.22.0 | 14.17.0 | 15.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 | 16.0.0'],
[NapiVersion.Napi9, '18.17.0 | 20.3.0 | 21.1.0'],
])
interface NodeVersion {