diff --git a/demo/basic/generated/kotlin/IHtmlApi.kt b/demo/basic/generated/kotlin/IHtmlApi.kt index 261d309..c633d2b 100644 --- a/demo/basic/generated/kotlin/IHtmlApi.kt +++ b/demo/basic/generated/kotlin/IHtmlApi.kt @@ -33,6 +33,7 @@ interface IHtmlApiBridge { fun getName(callback: Callback) fun getAge(gender: IHtmlApiGetAgeGender, callback: Callback) fun testDictionaryWithAnyKey(dict: Map) + fun testDefaultValue(bool: Boolean? = null, bool2: Boolean? = null, num: Float = 1) } open class IHtmlApiBridge(editor: WebEditor, gson: Gson) : JsBridge(editor, gson, "htmlApi"), IHtmlApiBridge { @@ -86,6 +87,14 @@ open class IHtmlApiBridge(editor: WebEditor, gson: Gson) : JsBridge(editor, gson "dict" to dict )) } + + override fun testDefaultValue(bool: Boolean? = null, bool2: Boolean? = null, num: Float = 1) { + executeJs("testDefaultValue", mapOf( + "bool" to bool + "bool2" to bool2 + "num" to num + )) + } } data class JSBaseSize( diff --git a/demo/basic/generated/swift/IHtmlApi.swift b/demo/basic/generated/swift/IHtmlApi.swift index 3fd72f5..237c24b 100644 --- a/demo/basic/generated/swift/IHtmlApi.swift +++ b/demo/basic/generated/swift/IHtmlApi.swift @@ -85,6 +85,20 @@ public class IHtmlApi { ) jsExecutor.execute(with: "htmlApi", feature: "testDictionaryWithAnyKey", args: args, completion: completion) } + + public func testDefaultValue(bool: Bool? = nil, bool2: Bool? = nil, num: Double = 1, completion: BridgeJSExecutor.Completion? = nil) { + struct Args: Encodable { + let bool: Bool? + let bool2: Bool? + let num: Double + } + let args = Args( + bool: bool, + bool2: bool2, + num: num + ) + jsExecutor.execute(with: "htmlApi", feature: "testDefaultValue", args: args, completion: completion) + } } public struct BaseSize: Codable { diff --git a/demo/basic/interfaces.ts b/demo/basic/interfaces.ts index a053f57..2f44560 100644 --- a/demo/basic/interfaces.ts +++ b/demo/basic/interfaces.ts @@ -76,6 +76,18 @@ export interface IHtmlApi { getName(): 'A2' | 'B2'; getAge({ gender }: { gender: 'Male' | 'Female' }): 21 | 22; testDictionaryWithAnyKey({ dict }: { dict: DictionaryWithAnyKey }): void; + + testDefaultValue(options: { + /** + * @default null + */ + bool?: boolean; + bool2?: boolean; + /** + * @default 1 + */ + num: number; + }): void; } /** diff --git a/documentation/interface-guide.md b/documentation/interface-guide.md index 19e94b7..27b74c4 100644 --- a/documentation/interface-guide.md +++ b/documentation/interface-guide.md @@ -216,6 +216,7 @@ ts-gyb parses tags in [JSDoc](https://jsdoc.app) documentation. - `@shouldExport`: Specify whether an `interface` should be exported. Set it to `true` to export. - `@overrideModuleName`: Change the name of the interface for ts-gyb. This is helpful for dropping the `I` prefix in TypeScript interface name. - `@overrideTypeName`: Similar to `@overrideModuleName`, this is used to override the name of custom types used in method parameters or return values. +- `@default`: default value for Module Interface's function parameter, ```typescript /** @@ -225,6 +226,18 @@ ts-gyb parses tags in [JSDoc](https://jsdoc.app) documentation. interface InterfaceWithTags { // The name of the module would be `ProperNamedInterface` in generated code ... + + foo(bar: { + /** + * @default null + */ + bool?: boolean; + bool2?: boolean; + /** + * @default 1 + */ + num: number; + }): void; } ``` diff --git a/package-lock.json b/package-lock.json index 312dff0..bc9f332 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ts-gyb", - "version": "0.10.1", + "version": "0.11.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ts-gyb", - "version": "0.10.1", + "version": "0.11.0", "license": "MIT", "dependencies": { "chalk": "^4.1.1", diff --git a/package.json b/package.json index 63d7db9..2235552 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts-gyb", - "version": "0.10.1", + "version": "0.11.0", "description": "Generate Native API based on TS interface", "repository": { "type": "git", diff --git a/src/parser/ValueParser.ts b/src/parser/ValueParser.ts index c9cc4d5..ee50f3e 100644 --- a/src/parser/ValueParser.ts +++ b/src/parser/ValueParser.ts @@ -145,8 +145,9 @@ export class ValueParser { const documentation = ts.displayPartsToString(symbol?.getDocumentationComment(this.checker)); const staticValue = this.parseLiteralNode(node.type); + if (staticValue !== null) { - return { name, type: staticValue.type, staticValue: staticValue.value, documentation }; + return { name, type: staticValue.type, staticValue: staticValue.value, documentation, defaultValue: "" }; } if (node.type.kind === ts.SyntaxKind.NeverKeyword) { @@ -155,10 +156,24 @@ export class ValueParser { const valueType = this.valueTypeFromNode(node); + const jsDocTags = symbol?.getJsDocTags(this.checker); + let defaultValue = ""; + jsDocTags?.forEach((tag) => { + if (tag.name === 'default' && tag.text?.length === 1) { + if (tag.text[0].kind === 'text') { + defaultValue = tag.text[0].text; + } + } + }); + if (defaultValue.length === 0 && valueType.kind === ValueTypeKind.optionalType) { + defaultValue = "null"; + } + return { name, type: valueType, documentation, + defaultValue }; } diff --git a/src/renderer/renderer.ts b/src/renderer/renderer.ts index d17f4c0..306e7c9 100644 --- a/src/renderer/renderer.ts +++ b/src/renderer/renderer.ts @@ -8,5 +8,7 @@ export function renderCode(templatePath: string, view: View): string { return Mustache.render(template, view, (partialName) => { const partialPath = path.join(directory, `${partialName}.mustache`); return fs.readFileSync(partialPath).toString(); + }, { + escape: (value: string) => value, }); } diff --git a/src/renderer/value-transformer/KotlinValueTransformer.ts b/src/renderer/value-transformer/KotlinValueTransformer.ts index bb2b904..e8214fc 100644 --- a/src/renderer/value-transformer/KotlinValueTransformer.ts +++ b/src/renderer/value-transformer/KotlinValueTransformer.ts @@ -133,4 +133,8 @@ export class KotlinValueTransformer implements ValueTransformer { convertTypeNameFromCustomMap(name: string): string { return this.typeNameMap[name] ?? name; } + + null(): string { + return 'null'; + } } diff --git a/src/renderer/value-transformer/SwiftValueTransformer.ts b/src/renderer/value-transformer/SwiftValueTransformer.ts index 891af84..941e8e6 100644 --- a/src/renderer/value-transformer/SwiftValueTransformer.ts +++ b/src/renderer/value-transformer/SwiftValueTransformer.ts @@ -144,4 +144,8 @@ export class SwiftValueTransformer implements ValueTransformer { convertTypeNameFromCustomMap(name: string): string { return this.typeNameMap[name] ?? name; } + + null(): string { + return 'nil'; + } } diff --git a/src/renderer/value-transformer/ValueTransformer.ts b/src/renderer/value-transformer/ValueTransformer.ts index 6ced0b6..eebefc2 100644 --- a/src/renderer/value-transformer/ValueTransformer.ts +++ b/src/renderer/value-transformer/ValueTransformer.ts @@ -6,4 +6,5 @@ export interface ValueTransformer { convertValue(value: Value, type: ValueType): string; convertEnumKey(text: string): string; convertTypeNameFromCustomMap(name: string): string; + null(): string; } diff --git a/src/renderer/views/MethodView.ts b/src/renderer/views/MethodView.ts index bea827e..389099e 100644 --- a/src/renderer/views/MethodView.ts +++ b/src/renderer/views/MethodView.ts @@ -10,13 +10,23 @@ export class MethodView { } get parametersDeclaration(): string { - return this.parameters.map((parameter) => `${parameter.name}: ${parameter.type}`).join(', '); + return this.parameters.map((parameter) => { + if (parameter.defaultValue.length === 0) { + return `${parameter.name}: ${parameter.type}`; + } + let { defaultValue } = parameter; + if (defaultValue === 'null') { + defaultValue = this.valueTransformer.null(); + } + return `${parameter.name}: ${parameter.type} = ${defaultValue}`; + }).join(', '); } - get parameters(): { name: string; type: string; last: boolean }[] { + get parameters(): { name: string; type: string; defaultValue: string; last: boolean }[] { return this.method.parameters.map((parameter, index) => ({ name: parameter.name, type: this.valueTransformer.convertValueType(parameter.type), + defaultValue: parameter.defaultValue, last: index === this.method.parameters.length - 1, })); } diff --git a/src/types.ts b/src/types.ts index 8fb5724..2330736 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,6 +20,7 @@ export interface Field { type: ValueType; staticValue?: Value; documentation: string; + defaultValue: string; } export type ValueType = NonEmptyType | OptionalType;