diff --git a/fixtures/components/complex-types/button-group/interfaces.ts b/fixtures/components/complex-types/button-group/interfaces.ts index 817db98..d152123 100644 --- a/fixtures/components/complex-types/button-group/interfaces.ts +++ b/fixtures/components/complex-types/button-group/interfaces.ts @@ -2,6 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 export interface ButtonGroupProps { + /** + * Main action for the group + */ + mainAction?: { + alwaysFalse: false; + alwaysOne: 1; + alwaysSomething: 'something'; + }; + /** * This is variant */ diff --git a/fixtures/components/slots/container/index.tsx b/fixtures/components/slots/container/index.tsx index b4a6a3b..21db701 100644 --- a/fixtures/components/slots/container/index.tsx +++ b/fixtures/components/slots/container/index.tsx @@ -13,12 +13,20 @@ export interface ContainerProps { * @displayname content */ children?: React.ReactNode; + + /** + * Media content + */ + media?: { + content: React.ReactNode; + }; } -export default function Container({ header, children }: ContainerProps) { +export default function Container({ header, children, media }: ContainerProps) { return (
{header}
+ {media?.content} {children}
); diff --git a/src/components/interfaces.ts b/src/components/interfaces.ts index 2408f9d..7aa313c 100644 --- a/src/components/interfaces.ts +++ b/src/components/interfaces.ts @@ -63,6 +63,7 @@ export interface ObjectDefinitionProperty { name: string; optional: boolean; type: string; + inlineType?: TypeDefinition; } export interface FunctionDefinition { diff --git a/src/components/object-definition.ts b/src/components/object-definition.ts index 81f7b73..52e10de 100644 --- a/src/components/object-definition.ts +++ b/src/components/object-definition.ts @@ -22,11 +22,12 @@ export function getObjectDefinition( const realTypeName = stringifyType(realType, checker); if ( realType.flags & ts.TypeFlags.String || - realType.flags & ts.TypeFlags.StringLiteral || + realType.flags & ts.TypeFlags.Literal || realType.flags & ts.TypeFlags.Boolean || realType.flags & ts.TypeFlags.Number || isArrayType(realType) || - realTypeName === 'HTMLElement' + realTypeName === 'HTMLElement' || + type === 'React.ReactNode' ) { // do not expand built-in Javascript methods or primitive values return { type }; @@ -38,24 +39,25 @@ export function getObjectDefinition( const properties = realType .getProperties() .map(prop => { - const propType = checker.getTypeAtLocation(extractDeclaration(prop)); + const propNode = extractDeclaration(prop) as ts.PropertyDeclaration; + const propType = checker.getTypeAtLocation(propNode); + const typeString = stringifyType(propType, checker); + return { name: prop.getName(), - type: stringifyType(propType, checker), optional: isOptional(propType), + ...getObjectDefinition(typeString, propType, propNode.type, checker), }; }) .sort((a, b) => a.name.localeCompare(b.name)); - if (properties.every(prop => prop.type.length < 200)) { - return { - type: type, - inlineType: { - name: realTypeName, - type: 'object', - properties: properties, - }, - }; - } + return { + type: type, + inlineType: { + name: realTypeName.length < 100 ? realTypeName : 'object', + type: 'object', + properties: properties, + }, + }; } if (realType.getCallSignatures().length > 0) { if (realType.getCallSignatures().length > 1) { diff --git a/test/components/__snapshots__/complex-types.test.ts.snap b/test/components/__snapshots__/complex-types.test.ts.snap new file mode 100644 index 0000000..145556e --- /dev/null +++ b/test/components/__snapshots__/complex-types.test.ts.snap @@ -0,0 +1,128 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`should print long inline types 1`] = ` +[ + { + "analyticsTag": undefined, + "defaultValue": undefined, + "deprecatedTag": undefined, + "description": undefined, + "i18nTag": undefined, + "inlineType": { + "name": "ButtonProps.Style", + "properties": [ + { + "inlineType": { + "name": "object", + "properties": [ + { + "inlineType": { + "name": "object", + "properties": [ + { + "name": "active", + "optional": true, + "type": "string", + }, + { + "name": "default", + "optional": true, + "type": "string", + }, + { + "name": "disabled", + "optional": true, + "type": "string", + }, + { + "name": "hover", + "optional": true, + "type": "string", + }, + ], + "type": "object", + }, + "name": "background", + "optional": true, + "type": "{ active?: string | undefined; default?: string | undefined; disabled?: string | undefined; hover?: string | undefined; }", + }, + { + "inlineType": { + "name": "object", + "properties": [ + { + "name": "active", + "optional": true, + "type": "string", + }, + { + "name": "default", + "optional": true, + "type": "string", + }, + { + "name": "disabled", + "optional": true, + "type": "string", + }, + { + "name": "hover", + "optional": true, + "type": "string", + }, + ], + "type": "object", + }, + "name": "borderColor", + "optional": true, + "type": "{ active?: string | undefined; default?: string | undefined; disabled?: string | undefined; hover?: string | undefined; }", + }, + { + "inlineType": { + "name": "object", + "properties": [ + { + "name": "active", + "optional": true, + "type": "string", + }, + { + "name": "default", + "optional": true, + "type": "string", + }, + { + "name": "disabled", + "optional": true, + "type": "string", + }, + { + "name": "hover", + "optional": true, + "type": "string", + }, + ], + "type": "object", + }, + "name": "color", + "optional": true, + "type": "{ active?: string | undefined; default?: string | undefined; disabled?: string | undefined; hover?: string | undefined; }", + }, + ], + "type": "object", + }, + "name": "root", + "optional": true, + "type": "{ background?: { active?: string | undefined; default?: string | undefined; disabled?: string | undefined; hover?: string | undefined; } | undefined; color?: { active?: string | undefined; default?: string | undefined; disabled?: string | undefined; hover?: string | undefined; } | undefined; borderColor?: { ...; } |...", + }, + ], + "type": "object", + }, + "name": "style", + "optional": false, + "systemTags": undefined, + "type": "ButtonProps.Style", + "visualRefreshTag": undefined, + }, +] +`; diff --git a/test/components/complex-types.test.ts b/test/components/complex-types.test.ts index c99d591..89a1c63 100644 --- a/test/components/complex-types.test.ts +++ b/test/components/complex-types.test.ts @@ -60,6 +60,17 @@ test('should have correct property types', () => { name: 'allItemsSelectionLabel', optional: true, type: '((data: TableProps.SelectionState) => string)', + inlineType: { + name: '(data: TableProps.SelectionState) => string', + parameters: [ + { + name: 'data', + type: 'TableProps.SelectionState', + }, + ], + returnType: 'string', + type: 'function', + }, }, ], }, @@ -149,7 +160,13 @@ test('should properly display string union types', () => { { name: 'type', optional: true, - type: '"link" | "link-group" | "expandable-link-group"', + type: 'string', + inlineType: { + name: '"link" | "link-group" | "expandable-link-group"', + type: 'union', + valueDescriptions: undefined, + values: ['link', 'link-group', 'expandable-link-group'], + }, }, ], }); @@ -186,6 +203,33 @@ test('should parse string literal type as single-value union', () => { type: 'ReadonlyArray', optional: false, }, + { + name: 'mainAction', + description: 'Main action for the group', + type: '{ alwaysFalse: false; alwaysOne: 1; alwaysSomething: "something"; }', + optional: true, + inlineType: { + name: '{ alwaysFalse: false; alwaysOne: 1; alwaysSomething: "something"; }', + type: 'object', + properties: [ + { + name: 'alwaysFalse', + optional: false, + type: 'false', + }, + { + name: 'alwaysOne', + optional: false, + type: '1', + }, + { + name: 'alwaysSomething', + optional: false, + type: '"something"', + }, + ], + }, + }, { name: 'variant', description: 'This is variant', @@ -195,12 +239,6 @@ test('should parse string literal type as single-value union', () => { ]); }); -test('should trim long inline types', () => { - expect(button.properties).toEqual([ - { - name: 'style', - type: 'ButtonProps.Style', - optional: false, - }, - ]); +test('should print long inline types', () => { + expect(button.properties).toMatchSnapshot(); }); diff --git a/test/components/slots.test.ts b/test/components/slots.test.ts index b492c78..3264db7 100644 --- a/test/components/slots.test.ts +++ b/test/components/slots.test.ts @@ -13,7 +13,25 @@ beforeAll(() => { }); test('should have correct region definitions', () => { - expect(component.properties).toEqual([]); + expect(component.properties).toEqual([ + { + name: 'media', + description: 'Media content', + optional: true, + type: '{ content: React.ReactNode; }', + inlineType: { + name: '{ content: React.ReactNode; }', + properties: [ + { + name: 'content', + optional: true, + type: 'React.ReactNode', + }, + ], + type: 'object', + }, + }, + ]); expect(component.regions).toEqual([ { name: 'children',