From afa040660cd4d4a53a0ed4f3757b2b2aad8084e5 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 30 Nov 2023 20:00:52 +0800 Subject: [PATCH] fix(cli): add back constEnum option (#1829) --- cli/codegen/commands.ts | 5 + cli/docs/build.md | 1 + cli/src/api/build.ts | 17 +- cli/src/def/build.ts | 9 + .../__snapshots__/typegen.spec.ts.md | 555 ++++++++++++++++++ .../__snapshots__/typegen.spec.ts.snap | Bin 3961 -> 4198 bytes cli/src/utils/__tests__/typegen.spec.ts | 21 +- cli/src/utils/config.ts | 9 +- cli/src/utils/typegen.ts | 14 +- 9 files changed, 614 insertions(+), 17 deletions(-) diff --git a/cli/codegen/commands.ts b/cli/codegen/commands.ts index 2bdba2a0..2ded547f 100644 --- a/cli/codegen/commands.ts +++ b/cli/codegen/commands.ts @@ -159,6 +159,11 @@ const BUILD_OPTIONS: CommandSchema = { description: 'Package name in generated js binding file. Only works with `--platform` flag', }, + { + name: 'constEnum', + type: 'boolean', + description: 'Whether generate const enum for typescript bindings', + }, { name: 'jsBinding', type: 'string', diff --git a/cli/docs/build.md b/cli/docs/build.md index 0b02d9c4..9ecb3a9b 100644 --- a/cli/docs/build.md +++ b/cli/docs/build.md @@ -33,6 +33,7 @@ new NapiCli().build({ | outputDir | --output-dir,-o | string | false | | Path to where all the built files would be put. Default to the crate folder | | platform | --platform | boolean | false | | Add platform triple to the generated nodejs binding file, eg: `[name].linux-x64-gnu.node` | | jsPackageName | --js-package-name | string | false | | Package name in generated js binding file. Only works with `--platform` flag | +| constEnum | --const-enum | boolean | false | | Whether generate const enum for typescript bindings | | jsBinding | --js | string | false | | Path and filename of generated JS binding file. Only works with `--platform` flag. Relative to `--output_dir`. | | noJsBinding | --no-js | boolean | false | | Whether to disable the generation JS binding file. Only works with `--platform` flag. | | dts | --dts | string | false | | Path and filename of generated type def file. Relative to `--output_dir` | diff --git a/cli/src/api/build.ts b/cli/src/api/build.ts index be13b889..569713b3 100644 --- a/cli/src/api/build.ts +++ b/cli/src/api/build.ts @@ -81,8 +81,8 @@ export async function buildProject(options: BuildOptions) { options.target ? parseTriple(options.target) : process.env.CARGO_BUILD_TARGET - ? parseTriple(process.env.CARGO_BUILD_TARGET) - : getSystemDefaultTarget(), + ? parseTriple(process.env.CARGO_BUILD_TARGET) + : getSystemDefaultTarget(), crateDir, resolvePath(options.outputDir ?? crateDir), options.targetDir ?? @@ -373,8 +373,8 @@ class Builder { process.platform === 'darwin' ? 'darwin' : process.platform === 'win32' - ? 'windows' - : 'linux' + ? 'windows' + : 'linux' Object.assign(this.envs, { CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-android24-clang`, CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-androideabi24-clang`, @@ -559,10 +559,10 @@ class Builder { this.target.platform === 'darwin' ? `lib${cdyLib}.dylib` : this.target.platform === 'win32' - ? `${cdyLib}.dll` - : this.target.platform === 'wasi' || this.target.platform === 'wasm' - ? `${cdyLib}.wasm` - : `lib${cdyLib}.so` + ? `${cdyLib}.dll` + : this.target.platform === 'wasi' || this.target.platform === 'wasm' + ? `${cdyLib}.wasm` + : `lib${cdyLib}.so` let destName = this.config.binaryName // add platform suffix to binary name @@ -597,6 +597,7 @@ class Builder { const { dts, exports } = await processTypeDef( this.envs.TYPE_DEF_TMP_PATH, + this.options.constEnum ?? true, !this.options.noDtsHeader ? this.options.dtsHeader ?? DEFAULT_TYPE_DEF_HEADER : '', diff --git a/cli/src/def/build.ts b/cli/src/def/build.ts index 823d1ae2..da09b45d 100644 --- a/cli/src/def/build.ts +++ b/cli/src/def/build.ts @@ -47,6 +47,10 @@ export abstract class BaseBuildCommand extends Command { 'Package name in generated js binding file. Only works with `--platform` flag', }) + constEnum?: boolean = Option.Boolean('--const-enum', { + description: 'Whether generate const enum for typescript bindings', + }) + jsBinding?: string = Option.String('--js', { description: 'Path and filename of generated JS binding file. Only works with `--platform` flag. Relative to `--output_dir`.', @@ -133,6 +137,7 @@ export abstract class BaseBuildCommand extends Command { outputDir: this.outputDir, platform: this.platform, jsPackageName: this.jsPackageName, + constEnum: this.constEnum, jsBinding: this.jsBinding, noJsBinding: this.noJsBinding, dts: this.dts, @@ -190,6 +195,10 @@ export interface BuildOptions { * Package name in generated js binding file. Only works with `--platform` flag */ jsPackageName?: string + /** + * Whether generate const enum for typescript bindings + */ + constEnum?: boolean /** * Path and filename of generated JS binding file. Only works with `--platform` flag. Relative to `--output_dir`. */ diff --git a/cli/src/utils/__tests__/__snapshots__/typegen.spec.ts.md b/cli/src/utils/__tests__/__snapshots__/typegen.spec.ts.md index 5c1c2032..72336f90 100644 --- a/cli/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +++ b/cli/src/utils/__tests__/__snapshots__/typegen.spec.ts.md @@ -616,3 +616,558 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ ` + +## should process type def with noConstEnum correctly + +> Snapshot 1 + + `␊ + export class ExternalObject {␊ + readonly '': {␊ + readonly '': unique symbol␊ + [K: symbol]: T␊ + }␊ + }␊ + /**␊ + * \`constructor\` option for \`struct\` requires all fields to be public,␊ + * otherwise tag impl fn as constructor␊ + * #[napi(constructor)]␊ + */␊ + export class Animal {␊ + /** Kind of animal */␊ + readonly kind: Kind␊ + /** This is the constructor */␊ + constructor(kind: Kind, name: string)␊ + /** This is a factory method */␊ + static withKind(kind: Kind): Animal␊ + get name(): string␊ + set name(name: string)␊ + get type(): Kind␊ + set type(kind: Kind)␊ + /**␊ + * This is a␊ + * multi-line comment␊ + * with an emoji 🚀␊ + */␊ + whoami(): string␊ + /** This is static... */␊ + static getDogKind(): Kind␊ + /**␊ + * Here are some characters and character sequences␊ + * that should be escaped correctly:␊ + * \\[]{}/\\:""{␊ + * }␊ + */␊ + returnOtherClass(): Dog␊ + returnOtherClassWithCustomConstructor(): Bird␊ + overrideIndividualArgOnMethod(normalTy: string, overriddenTy: {n: string}): Bird␊ + }␊ + ␊ + export class AnimalWithDefaultConstructor {␊ + name: string␊ + kind: number␊ + constructor(name: string, kind: number)␊ + }␊ + ␊ + export class AnotherClassForEither {␊ + constructor()␊ + }␊ + ␊ + export class AnotherCssStyleSheet {␊ + get rules(): CssRuleList␊ + }␊ + export type AnotherCSSStyleSheet = AnotherCssStyleSheet␊ + ␊ + export class Asset {␊ + constructor()␊ + get filePath(): number␊ + }␊ + export type JsAsset = Asset␊ + ␊ + export class Assets {␊ + constructor()␊ + get(id: number): JsAsset | null␊ + }␊ + export type JsAssets = Assets␊ + ␊ + export class Bird {␊ + name: string␊ + constructor(name: string)␊ + getCount(): number␊ + getNameAsync(): Promise␊ + }␊ + ␊ + /** Smoking test for type generation */␊ + export class Blake2BHasher {␊ + static withKey(key: Blake2bKey): Blake2BHasher␊ + update(data: Buffer): void␊ + }␊ + export type Blake2bHasher = Blake2BHasher␊ + ␊ + export class Blake2BKey {␊ + ␊ + }␊ + export type Blake2bKey = Blake2BKey␊ + ␊ + export class ClassWithFactory {␊ + name: string␊ + static withName(name: string): ClassWithFactory␊ + setName(name: string): this␊ + }␊ + ␊ + export class Context {␊ + maybeNeed?: boolean␊ + buffer: Uint8Array␊ + constructor()␊ + static withData(data: string): Context␊ + static withBuffer(buf: Uint8Array): Context␊ + method(): string␊ + }␊ + ␊ + export class CssRuleList {␊ + getRules(): Array␊ + get parentStyleSheet(): CSSStyleSheet␊ + get name(): string | null␊ + }␊ + export type CSSRuleList = CssRuleList␊ + ␊ + export class CssStyleSheet {␊ + constructor(name: string, rules: Array)␊ + get rules(): CssRuleList␊ + anotherCssStyleSheet(): AnotherCssStyleSheet␊ + }␊ + export type CSSStyleSheet = CssStyleSheet␊ + ␊ + export class CustomFinalize {␊ + constructor(width: number, height: number)␊ + }␊ + ␊ + export class Dog {␊ + name: string␊ + constructor(name: string)␊ + }␊ + ␊ + export class Fib {␊ + [Symbol.iterator](): Iterator␊ + constructor()␊ + }␊ + ␊ + export class Fib2 {␊ + [Symbol.iterator](): Iterator␊ + static create(seed: number): Fib2␊ + }␊ + ␊ + export class Fib3 {␊ + current: number␊ + next: number␊ + constructor(current: number, next: number)␊ + [Symbol.iterator](): Iterator␊ + }␊ + ␊ + export class JsClassForEither {␊ + constructor()␊ + }␊ + ␊ + export class JsRemote {␊ + name(): string␊ + }␊ + ␊ + export class JsRepo {␊ + constructor(dir: string)␊ + remote(): JsRemote␊ + }␊ + ␊ + export class NinjaTurtle {␊ + name: string␊ + static isInstanceOf(value: unknown): boolean␊ + /** Create your ninja turtle! 🐢 */␊ + static newRaph(): NinjaTurtle␊ + getMaskColor(): string␊ + getName(): string␊ + returnThis(this: this): this␊ + }␊ + ␊ + export class NotWritableClass {␊ + name: string␊ + constructor(name: string)␊ + setName(name: string): void␊ + }␊ + ␊ + export class Optional {␊ + static optionEnd(required: string, optional?: string | undefined | null): string␊ + static optionStart(optional: string | undefined | null, required: string): string␊ + static optionStartEnd(optional1: string | undefined | null, required: string, optional2?: string | undefined | null): string␊ + static optionOnly(optional?: string | undefined | null): string␊ + }␊ + ␊ + export class Width {␊ + value: number␊ + constructor(value: number)␊ + }␊ + ␊ + export interface A {␊ + foo: number␊ + }␊ + ␊ + export function acceptThreadsafeFunction(func: (err: Error | null, value: number) => any): void␊ + ␊ + export function acceptThreadsafeFunctionFatal(func: (value: number) => any): void␊ + ␊ + export function acceptThreadsafeFunctionTupleArgs(func: (err: Error | null, arg0: number, arg1: boolean, arg2: string) => any): void␊ + ␊ + export function add(a: number, b: number): number␊ + ␊ + export enum ALIAS {␊ + A = 0,␊ + B = 1␊ + }␊ + ␊ + export interface AliasedStruct {␊ + a: ALIAS␊ + b: number␊ + }␊ + ␊ + export interface AllOptionalObject {␊ + name?: string␊ + age?: number␊ + }␊ + ␊ + export function appendBuffer(buf: Buffer): Buffer␊ + ␊ + export function arrayBufferPassThrough(buf: Uint8Array): Promise␊ + ␊ + export function asyncMultiTwo(arg: number): Promise␊ + ␊ + export function asyncPlus100(p: Promise): Promise␊ + ␊ + export function asyncReduceBuffer(buf: Buffer): Promise␊ + ␊ + export interface B {␊ + bar: number␊ + }␊ + ␊ + export function bigintAdd(a: bigint, b: bigint): bigint␊ + ␊ + export function bigintFromI128(): bigint␊ + ␊ + export function bigintFromI64(): bigint␊ + ␊ + export function bigintGetU64AsString(bi: bigint): string␊ + ␊ + export function bufferPassThrough(buf: Buffer): Promise␊ + ␊ + export interface C {␊ + baz: number␊ + }␊ + ␊ + export function callbackReturnPromise(functionInput: () => T | Promise, callback: (err: Error | null, result: T) => void): T | Promise␊ + ␊ + export function callThreadsafeFunction(callback: (...args: any[]) => any): void␊ + ␊ + export function captureErrorInCallback(cb1: () => void, cb2: (arg0: Error) => void): void␊ + ␊ + export function chronoDateAdd1Minute(input: Date): Date␊ + ␊ + export function chronoDateToMillis(input: Date): number␊ + ␊ + export function concatLatin1(s: string): string␊ + ␊ + export function concatStr(s: string): string␊ + ␊ + export function concatUtf16(s: string): string␊ + ␊ + export function contains(source: string, target: string): boolean␊ + ␊ + export function convertU32Array(input: Uint32Array): Array␊ + ␊ + export function createBigInt(): bigint␊ + ␊ + export function createBigIntI64(): bigint␊ + ␊ + export function createExternal(size: number): ExternalObject␊ + ␊ + export function createExternalString(content: string): ExternalObject␊ + ␊ + export function createExternalTypedArray(): Uint32Array␊ + ␊ + export function createObj(): object␊ + ␊ + export function createObjectWithClassField(): ObjectFieldClassInstance␊ + ␊ + export function createObjWithProperty(): { value: ArrayBuffer, get getter(): number }␊ + ␊ + export function createSymbol(): symbol␊ + ␊ + /** You could break the step and for an new continuous value. */␊ + export enum CustomNumEnum {␊ + One = 1,␊ + Two = 2,␊ + Three = 3,␊ + Four = 4,␊ + Six = 6,␊ + Eight = 8,␊ + Nine = 9,␊ + Ten = 10␊ + }␊ + ␊ + export function customStatusCode(): void␊ + ␊ + export interface Dates {␊ + start: Date␊ + end?: Date␊ + }␊ + ␊ + export function dateToNumber(input: Date): number␊ + ␊ + /** This is a const */␊ + export const DEFAULT_COST: number␊ + ␊ + export function derefUint8Array(a: Uint8Array, b: Uint8ClampedArray): number␊ + ␊ + export function either3(input: string | number | boolean): number␊ + ␊ + export function either4(input: string | number | boolean | Obj): number␊ + ␊ + export function eitherBoolOrFunction(input: boolean | ((...args: any[]) => any)): void␊ + ␊ + export function eitherFromObjects(input: A | B | C): string␊ + ␊ + export function eitherFromOption(): JsClassForEither | undefined␊ + ␊ + export function eitherStringOrNumber(input: string | number): number␊ + ␊ + export enum Empty {␊ + ␊ + }␊ + ␊ + export function enumToI32(e: CustomNumEnum): number␊ + ␊ + export function fibonacci(n: number): number␊ + ␊ + export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void␊ + ␊ + export function getBuffer(): Buffer␊ + ␊ + export function getCwd(callback: (arg0: string) => void): void␊ + ␊ + export function getEmptyBuffer(): Buffer␊ + ␊ + export function getExternal(external: ExternalObject): number␊ + ␊ + export function getGlobal(): typeof global␊ + ␊ + export function getMapping(): Record␊ + ␊ + export function getNestedNumArr(): number[][][]␊ + ␊ + export function getNull(): null␊ + ␊ + export function getNumArr(): number[]␊ + ␊ + /** Gets some numbers */␊ + export function getNums(): Array␊ + ␊ + export function getPackageJsonName(packageJson: PackageJson): string␊ + ␊ + export function getStrFromObject(): void␊ + ␊ + export function getterFromObj(): number␊ + ␊ + export function getUndefined(): void␊ + ␊ + export function getWords(): Array␊ + ␊ + /** default enum values are continuos i32s start from 0 */␊ + export enum Kind {␊ + /** Barks */␊ + Dog = 0,␊ + /** Kills birds */␊ + Cat = 1,␊ + /** Tasty */␊ + Duck = 2␊ + }␊ + ␊ + export function listObjKeys(obj: object): Array␊ + ␊ + export function mapOption(val?: number | undefined | null): number | null␊ + ␊ + export function mutateExternal(external: ExternalObject, newVal: number): void␊ + ␊ + export function mutateTypedArray(input: Float32Array): void␊ + ␊ + export interface Obj {␊ + v: string | number␊ + }␊ + ␊ + export interface ObjectFieldClassInstance {␊ + bird: Bird␊ + }␊ + ␊ + export interface ObjectOnlyFromJs {␊ + count: number␊ + callback: (err: Error | null, value: number) => any␊ + }␊ + ␊ + export function optionEnd(callback: (arg0: string, arg1?: string | undefined | null) => void): void␊ + ␊ + export function optionOnly(callback: (arg0?: string | undefined | null) => void): void␊ + ␊ + export function optionStart(callback: (arg0: string | undefined | null, arg1: string) => void): void␊ + ␊ + export function optionStartEnd(callback: (arg0: string | undefined | null, arg1: string, arg2?: string | undefined | null) => void): void␊ + ␊ + export function overrideIndividualArgOnFunction(notOverridden: string, f: () => string, notOverridden2: number): string␊ + ␊ + export function overrideIndividualArgOnFunctionWithCbArg(callback: (town: string, name?: string | undefined | null) => string, notOverridden: number): object␊ + ␊ + /** This is an interface for package.json */␊ + export interface PackageJson {␊ + name: string␊ + /** The version of the package */␊ + version: string␊ + dependencies?: Record␊ + devDependencies?: Record␊ + }␊ + ␊ + export function panic(): void␊ + ␊ + export function plusOne(this: Width): number␊ + ␊ + export function promiseInEither(input: number | Promise): Promise␊ + ␊ + /** napi = { version = 2, features = ["serde-json"] } */␊ + export function readFile(callback: (arg0: Error | undefined, arg1?: string | undefined | null) => void): void␊ + ␊ + export function readFileAsync(path: string): Promise␊ + ␊ + export function readPackageJson(): PackageJson␊ + ␊ + export function receiveAllOptionalObject(obj?: AllOptionalObject | undefined | null): void␊ + ␊ + export function receiveClassOrNumber(either: number | JsClassForEither): number␊ + ␊ + export function receiveDifferentClass(either: JsClassForEither | AnotherClassForEither): number␊ + ␊ + export function receiveMutClassOrNumber(either: number | JsClassForEither): number␊ + ␊ + export function receiveObjectOnlyFromJs(obj: { count: number, callback: (err: Error | null, count: number) => void }): void␊ + ␊ + export function receiveObjectWithClassField(object: ObjectFieldClassInstance): Bird␊ + ␊ + export function receiveStrictObject(strictObject: StrictObject): void␊ + ␊ + export function receiveString(s: string): string␊ + ␊ + export function returnEither(input: number): string | number␊ + ␊ + export function returnEitherClass(input: number): number | JsClassForEither␊ + ␊ + export function returnJsFunction(): (...args: any[]) => any␊ + ␊ + export function returnNull(): null␊ + ␊ + export function returnUndefined(): void␊ + ␊ + export function returnUndefinedIfInvalid(input: boolean): boolean␊ + ␊ + export function returnUndefinedIfInvalidPromise(input: Promise): Promise␊ + ␊ + export function roundtripStr(s: string): string␊ + ␊ + export function runScript(script: string): unknown␊ + ␊ + export function setSymbolInObj(symbol: symbol): object␊ + ␊ + export interface StrictObject {␊ + name: string␊ + }␊ + ␊ + export function sumMapping(nums: Record): number␊ + ␊ + export function sumNums(nums: Array): number␊ + ␊ + export function testSerdeRoundtrip(data: any): any␊ + ␊ + export function threadsafeFunctionClosureCapture(func: (...args: any[]) => any): void␊ + ␊ + export function threadsafeFunctionFatalMode(cb: (...args: any[]) => any): void␊ + ␊ + export function threadsafeFunctionFatalModeError(cb: (...args: any[]) => any): void␊ + ␊ + export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void␊ + ␊ + export function throwError(): void␊ + ␊ + export function toJsObj(): object␊ + ␊ + export function tsfnAsyncCall(func: (...args: any[]) => any): Promise␊ + ␊ + export function tsfnCallWithCallback(func: (...args: any[]) => any): void␊ + ␊ + export function tsRename(a: { foo: number }): string[]␊ + ␊ + export interface TsTypeChanged {␊ + typeOverride: object␊ + typeOverrideOptional?: object␊ + }␊ + ␊ + export function validateArray(arr: Array): number␊ + ␊ + export function validateBigint(input: bigint): bigint␊ + ␊ + export function validateBoolean(i: boolean): boolean␊ + ␊ + export function validateBuffer(b: Buffer): number␊ + ␊ + export function validateDate(d: Date): number␊ + ␊ + export function validateDateTime(d: Date): number␊ + ␊ + export function validateExternal(e: ExternalObject): number␊ + ␊ + export function validateFunction(cb: () => number): number␊ + ␊ + export function validateHashMap(input: Record): number␊ + ␊ + export function validateNull(i: null): boolean␊ + ␊ + export function validateNumber(i: number): number␊ + ␊ + export function validateOptional(input1?: string | undefined | null, input2?: boolean | undefined | null): boolean␊ + ␊ + export function validatePromise(p: Promise): Promise␊ + ␊ + export function validateString(s: string): string␊ + ␊ + export function validateSymbol(s: symbol): boolean␊ + ␊ + export function validateTypedArray(input: Uint8Array): number␊ + ␊ + export function validateUndefined(i: undefined): boolean␊ + ␊ + export function withAbortController(a: number, b: number, signal: AbortSignal): Promise␊ + ␊ + export function withoutAbortController(a: number, b: number): Promise␊ + ␊ + export function xxh64Alias(input: Buffer): bigint␊ + ␊ + export namespace xxh2 {␊ + export function xxh2Plus(a: number, b: number): number␊ + export function xxh3Xxh64Alias(input: Buffer): bigint␊ + }␊ + ␊ + export namespace xxh3 {␊ + /** Xxh3 class */␊ + export class Xxh3 {␊ + constructor()␊ + /** update */␊ + update(input: Buffer): void␊ + digest(): bigint␊ + }␊ + export const ALIGNMENT: number␊ + /** xxh128 function */␊ + export function xxh128(input: Buffer): bigint␊ + export function xxh3_64(input: Buffer): bigint␊ + }␊ + ␊ + ` diff --git a/cli/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap b/cli/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap index 7425cbeddc5f53b2ef2260ecff89d9ed09bba201..a17f23289dabfaf34a242174d60156727e384bf0 100644 GIT binary patch literal 4198 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 literal 3961 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 T-`%_0VZ8qX6t`>QaXJ71&SIRo diff --git a/cli/src/utils/__tests__/typegen.spec.ts b/cli/src/utils/__tests__/typegen.spec.ts index f00d8ebe..f426f718 100644 --- a/cli/src/utils/__tests__/typegen.spec.ts +++ b/cli/src/utils/__tests__/typegen.spec.ts @@ -18,13 +18,13 @@ test('should ident string correctly', (t) => { foo() { a = b } - + bar = () => { - + } boz = 1 } - + namespace B { namespace C { type D = A @@ -43,6 +43,21 @@ test('should process type def correctly', async (t) => { '__fixtures__', 'napi_type_def', ), + true, + ) + + t.snapshot(dts) +}) + +test('should process type def with noConstEnum correctly', async (t) => { + const { dts } = await processTypeDef( + join( + fileURLToPath(import.meta.url), + '../', + '__fixtures__', + 'napi_type_def', + ), + false, ) t.snapshot(dts) diff --git a/cli/src/utils/config.ts b/cli/src/utils/config.ts index e5b2837e..c83bd9be 100644 --- a/cli/src/utils/config.ts +++ b/cli/src/utils/config.ts @@ -24,6 +24,11 @@ interface UserNapiConfig { */ npmClient?: string + /** + * Whether generate const enum for typescript bindings + */ + constEnum?: boolean + /** * @deprecated binaryName instead */ @@ -114,8 +119,8 @@ export async function readNapiConfig(path: string): Promise { let targets: string[] = userNapiConfig.targets ?? [] // compatible with old config - if (userNapiConfig.package?.name) { - napiConfig.packageName = userNapiConfig.package.name + if (userNapiConfig?.name) { + napiConfig.packageName = userNapiConfig.name } if (!targets.length) { diff --git a/cli/src/utils/typegen.ts b/cli/src/utils/typegen.ts index ad9cb003..610c1705 100644 --- a/cli/src/utils/typegen.ts +++ b/cli/src/utils/typegen.ts @@ -25,7 +25,11 @@ interface TypeDefLine { js_mod?: string } -function prettyPrint(line: TypeDefLine, ident: number): string { +function prettyPrint( + line: TypeDefLine, + constEnum: boolean, + ident: number, +): string { let s = line.js_doc ?? '' switch (line.kind) { case TypeDefKind.Interface: @@ -33,7 +37,8 @@ function prettyPrint(line: TypeDefLine, ident: number): string { break case TypeDefKind.Enum: - s += `export const enum ${line.name} {\n${line.def}\n}` + const enumName = constEnum ? 'const enum' : 'enum' + s += `export ${enumName} ${line.name} {\n${line.def}\n}` break case TypeDefKind.Struct: @@ -52,6 +57,7 @@ function prettyPrint(line: TypeDefLine, ident: number): string { export async function processTypeDef( intermediateTypeFile: string, + constEnum: boolean, header?: string, ) { const exports: string[] = [] @@ -65,7 +71,7 @@ export async function processTypeDef( ([namespace, defs]) => { if (namespace === TOP_LEVEL_NAMESPACE) { for (const def of defs) { - dts += prettyPrint(def, 0) + '\n\n' + dts += prettyPrint(def, constEnum, 0) + '\n\n' switch (def.kind) { case TypeDefKind.Const: case TypeDefKind.Enum: @@ -85,7 +91,7 @@ export async function processTypeDef( exports.push(namespace) dts += `export namespace ${namespace} {\n` for (const def of defs) { - dts += prettyPrint(def, 2) + '\n' + dts += prettyPrint(def, constEnum, 2) + '\n' } dts += '}\n\n' }