diff --git a/src/compiler/types/generate-prop-types.ts b/src/compiler/types/generate-prop-types.ts index bb8ebbf25a2..b87446986cb 100644 --- a/src/compiler/types/generate-prop-types.ts +++ b/src/compiler/types/generate-prop-types.ts @@ -18,6 +18,11 @@ export const generatePropTypes = (cmpMeta: d.ComponentCompilerMeta, typeImportDa cmpProp.docs.tags = [...(cmpProp.docs.tags || []), { name: 'readonly', text: '' }]; doc = getTextDocs(cmpProp.docs); } + if (cmpProp.defaultValue !== undefined && !doc?.match('@default')) { + cmpProp.docs = cmpProp.docs || { tags: [], text: '' }; + cmpProp.docs.tags = [...(cmpProp.docs.tags || []), { name: 'default', text: cmpProp.defaultValue }]; + doc = getTextDocs(cmpProp.docs); + } return { name: cmpProp.name, type: getType(cmpProp, typeImportData, cmpMeta.sourceFilePath), diff --git a/src/compiler/types/tests/generate-prop-types.spec.ts b/src/compiler/types/tests/generate-prop-types.spec.ts index 75ef6d78dda..800648b64a5 100644 --- a/src/compiler/types/tests/generate-prop-types.spec.ts +++ b/src/compiler/types/tests/generate-prop-types.spec.ts @@ -189,5 +189,61 @@ describe('generate-prop-types', () => { expect(actualTypeInfo).toEqual(expectedTypeInfo); }); + + it('appends `@default` to jsdoc when the property has a default value', () => { + const stubImportTypes = stubTypesImportData(); + const componentMeta = stubComponentCompilerMeta({ + properties: [ + stubComponentCompilerProperty({ + defaultValue: "'hello'", + }), + ], + }); + + const expectedTypeInfo: d.TypeInfo = [ + { + jsdoc: "@default 'hello'", + internal: false, + name: 'propName', + optional: false, + required: false, + type: 'UserCustomPropType', + }, + ]; + + const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes); + + expect(actualTypeInfo).toEqual(expectedTypeInfo); + }); + + it('does not duplicate `@default` in jsdoc when it is already present', () => { + const stubImportTypes = stubTypesImportData(); + const componentMeta = stubComponentCompilerMeta({ + properties: [ + stubComponentCompilerProperty({ + defaultValue: "'hello'", + docs: { + text: '', + tags: [{ name: 'default', text: "'existing default'" }], + }, + }), + ], + }); + + const expectedTypeInfo: d.TypeInfo = [ + { + jsdoc: "@default 'existing default'", + internal: false, + name: 'propName', + optional: false, + required: false, + type: 'UserCustomPropType', + }, + ]; + + const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes); + + expect(actualTypeInfo).toEqual(expectedTypeInfo); + }); }); }); diff --git a/test/end-to-end/src/components.d.ts b/test/end-to-end/src/components.d.ts index 5937a9a57af..8e1a3c568b9 100644 --- a/test/end-to-end/src/components.d.ts +++ b/test/end-to-end/src/components.d.ts @@ -39,6 +39,9 @@ export namespace Components { interface CmpC { } interface CmpDsd { + /** + * @default 0 + */ "initialCounter": number; } interface CmpServerVsClient { @@ -85,6 +88,9 @@ export namespace Components { interface ImportAssets { } interface ListenCmp { + /** + * @default false + */ "opened": boolean; } interface MethodCmp { @@ -100,13 +106,17 @@ export namespace Components { * @returns some string */ "someMethodWithArgs": (unit: string, value: number) => Promise; + /** + * @default 0 + */ "someProp": number; } interface MyCmp { /** * bar prop * @returns bar - * @readonly + * @readonly + * @default 'bar' */ "barProp": string; /** @@ -122,7 +132,8 @@ export namespace Components { /** * bar prop * @returns bar - * @readonly + * @readonly + * @default 'bar' */ "barProp": string; /** @@ -153,6 +164,9 @@ export namespace Components { interface PrerenderCmp { } interface PropCmp { + /** + * @default 'life preservers' + */ "clothes": string; "first": string; /** @@ -166,8 +180,14 @@ export namespace Components { "mode"?: any; } interface RuntimeDecorators { + /** + * @default 'basicProp' + */ "basicProp": string; "decoratedGetterSetterProp": number; + /** + * @default -10 + */ "decoratedProp": number; } interface ScopedCarDetail { @@ -625,6 +645,9 @@ declare namespace LocalJSX { interface CmpC { } interface CmpDsd { + /** + * @default 0 + */ "initialCounter"?: number; } interface CmpServerVsClient { @@ -657,16 +680,23 @@ declare namespace LocalJSX { interface ImportAssets { } interface ListenCmp { + /** + * @default false + */ "opened"?: boolean; } interface MethodCmp { + /** + * @default 0 + */ "someProp"?: number; } interface MyCmp { /** * bar prop * @returns bar - * @readonly + * @readonly + * @default 'bar' */ "barProp"?: string; /** @@ -682,7 +712,8 @@ declare namespace LocalJSX { /** * bar prop * @returns bar - * @readonly + * @readonly + * @default 'bar' */ "barProp"?: string; /** @@ -713,6 +744,9 @@ declare namespace LocalJSX { interface PrerenderCmp { } interface PropCmp { + /** + * @default 'life preservers' + */ "clothes"?: string; "first"?: string; /** @@ -726,8 +760,14 @@ declare namespace LocalJSX { "mode"?: any; } interface RuntimeDecorators { + /** + * @default 'basicProp' + */ "basicProp"?: string; "decoratedGetterSetterProp"?: number; + /** + * @default -10 + */ "decoratedProp"?: number; } interface ScopedCarDetail { diff --git a/test/wdio/src/components.d.ts b/test/wdio/src/components.d.ts index 187e93e56ee..ef4d1b33a89 100644 --- a/test/wdio/src/components.d.ts +++ b/test/wdio/src/components.d.ts @@ -19,6 +19,9 @@ export namespace Components { interface CmpClientShadow { } interface CmpD { + /** + * @default '' + */ "uniqueId": string; } interface CmpScopedA { @@ -134,6 +137,9 @@ declare namespace LocalJSX { interface CmpClientShadow { } interface CmpD { + /** + * @default '' + */ "uniqueId"?: string; } interface CmpScopedA { diff --git a/test/wdio/ts-target-props/components.d.ts b/test/wdio/ts-target-props/components.d.ts index 80680349509..841b701ee06 100644 --- a/test/wdio/ts-target-props/components.d.ts +++ b/test/wdio/ts-target-props/components.d.ts @@ -7,8 +7,14 @@ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; export namespace Components { interface TsTargetProps { + /** + * @default 'basicProp' + */ "basicProp": string; "decoratedGetterSetterProp": number; + /** + * @default -10 + */ "decoratedProp": number; "dynamicLifecycle": string[]; } @@ -26,8 +32,14 @@ declare global { } declare namespace LocalJSX { interface TsTargetProps { + /** + * @default 'basicProp' + */ "basicProp"?: string; "decoratedGetterSetterProp"?: number; + /** + * @default -10 + */ "decoratedProp"?: number; "dynamicLifecycle"?: string[]; }