diff --git a/addons/docs/src/frameworks/angular/compodoc.test.ts b/addons/docs/src/frameworks/angular/compodoc.test.ts index 6e1590c4bc74..95a7731d878f 100644 --- a/addons/docs/src/frameworks/angular/compodoc.test.ts +++ b/addons/docs/src/frameworks/angular/compodoc.test.ts @@ -1,5 +1,5 @@ -import { extractType } from './compodoc'; -import { Decorator } from './types'; +import { extractType, setCompodocJson } from './compodoc'; +import { CompodocJson, Decorator } from './types'; const makeProperty = (compodocType?: string) => ({ type: compodocType, @@ -8,8 +8,96 @@ const makeProperty = (compodocType?: string) => ({ optional: true, }); +const getDummyCompodocJson = () => { + return { + miscellaneous: { + typealiases: [ + { + name: 'EnumAlias', + ctype: 'miscellaneous', + subtype: 'typealias', + rawtype: 'EnumNumeric', + file: 'src/stories/component-with-enums/enums.component.ts', + description: '', + kind: 161, + }, + { + name: 'TypeAlias', + ctype: 'miscellaneous', + subtype: 'typealias', + rawtype: '"Type Alias 1" | "Type Alias 2" | "Type Alias 3"', + file: 'src/stories/component-with-enums/enums.component.ts', + description: '', + kind: 168, + }, + ], + enumerations: [ + { + name: 'EnumNumeric', + childs: [ + { + name: 'FIRST', + }, + { + name: 'SECOND', + }, + { + name: 'THIRD', + }, + ], + ctype: 'miscellaneous', + subtype: 'enum', + description: '

Button Priority

\n', + file: 'src/stories/component-with-enums/enums.component.ts', + }, + { + name: 'EnumNumericInitial', + childs: [ + { + name: 'UNO', + value: '1', + }, + { + name: 'DOS', + }, + { + name: 'TRES', + }, + ], + ctype: 'miscellaneous', + subtype: 'enum', + description: '', + file: 'src/stories/component-with-enums/enums.component.ts', + }, + { + name: 'EnumStringValues', + childs: [ + { + name: 'PRIMARY', + value: 'PRIMARY', + }, + { + name: 'SECONDARY', + value: 'SECONDARY', + }, + { + name: 'TERTIARY', + value: 'TERTIARY', + }, + ], + ctype: 'miscellaneous', + subtype: 'enum', + description: '', + file: 'src/stories/component-with-enums/enums.component.ts', + }, + ], + }, + } as CompodocJson; +}; + describe('extractType', () => { describe('with compodoc type', () => { + setCompodocJson(getDummyCompodocJson()); it.each([ ['string', { name: 'string' }], ['boolean', { name: 'boolean' }], @@ -21,6 +109,10 @@ describe('extractType', () => { ['T[]', { name: 'object' }], ['[]', { name: 'object' }], ['"primary" | "secondary"', { name: 'enum', value: ['primary', 'secondary'] }], + ['TypeAlias', { name: 'enum', value: ['Type Alias 1', 'Type Alias 2', 'Type Alias 3'] }], + ['EnumNumeric', { name: 'object' }], + ['EnumNumericInitial', { name: 'object' }], + ['EnumStringValues', { name: 'enum', value: ['PRIMARY', 'SECONDARY', 'TERTIARY'] }], ])('%s', (compodocType, expected) => { expect(extractType(makeProperty(compodocType), null)).toEqual(expected); }); diff --git a/addons/docs/src/frameworks/angular/compodoc.ts b/addons/docs/src/frameworks/angular/compodoc.ts index e0c47427d1f7..20ef868123d9 100644 --- a/addons/docs/src/frameworks/angular/compodoc.ts +++ b/addons/docs/src/frameworks/angular/compodoc.ts @@ -25,7 +25,7 @@ export const setCompodocJson = (compodocJson: CompodocJson) => { }; // @ts-ignore -export const getCompdocJson = (): CompodocJson => window.__STORYBOOK_COMPODOC_JSON__; +export const getCompodocJson = (): CompodocJson => window.__STORYBOOK_COMPODOC_JSON__; export const checkValidComponentOrDirective = (component: Component | Directive) => { if (!component.name) { @@ -90,7 +90,7 @@ const getComponentData = (component: Component | Directive) => { return null; } checkValidComponentOrDirective(component); - const compodocJson = getCompdocJson(); + const compodocJson = getCompodocJson(); checkValidCompodocJson(compodocJson); const { name } = component; const metadata = findComponentByName(name, compodocJson); @@ -113,6 +113,13 @@ const extractTypeFromValue = (defaultValue: any) => { }; const extractEnumValues = (compodocType: any) => { + const compodocJson = getCompodocJson(); + const enumType = compodocJson?.miscellaneous.enumerations.find((x) => x.name === compodocType); + + if (enumType?.childs.every((x) => x.value)) { + return enumType.childs.map((x) => x.value); + } + if (typeof compodocType !== 'string' || compodocType.indexOf('|') === -1) { return null; } @@ -135,7 +142,8 @@ export const extractType = (property: Property, defaultValue: any) => { case null: return { name: 'void' }; default: { - const enumValues = extractEnumValues(compodocType); + const resolvedType = resolveTypealias(compodocType); + const enumValues = extractEnumValues(resolvedType); return enumValues ? { name: 'enum', value: enumValues } : { name: 'object' }; } } @@ -152,6 +160,12 @@ const extractDefaultValue = (property: Property) => { } }; +const resolveTypealias = (compodocType: string): string => { + const compodocJson = getCompodocJson(); + const typeAlias = compodocJson?.miscellaneous.typealiases.find((x) => x.name === compodocType); + return typeAlias ? resolveTypealias(typeAlias.rawtype) : compodocType; +}; + export const extractArgTypesFromData = (componentData: Class | Directive | Injectable | Pipe) => { const sectionToItems: Record = {}; const compodocClasses = ['component', 'directive'].includes(componentData.type) diff --git a/addons/docs/src/frameworks/angular/types.ts b/addons/docs/src/frameworks/angular/types.ts index 9f7e64afbabf..db5bd6a1a648 100644 --- a/addons/docs/src/frameworks/angular/types.ts +++ b/addons/docs/src/frameworks/angular/types.ts @@ -66,10 +66,40 @@ export interface Decorator { name: string; } +export interface TypeAlias { + name: string; + ctype: string; + subtype: string; + rawtype: string; + file: string; + kind: number; + description?: string; + rawdescription?: string; +} + +export interface EnumType { + name: string; + childs: EnumTypeChild[]; + ctype: string; + subtype: string; + file: string; + description?: string; + rawdescription?: string; +} + +export interface EnumTypeChild { + name: string; + value?: string; +} + export interface CompodocJson { directives: Directive[]; components: Component[]; pipes: Pipe[]; injectables: Injectable[]; classes: Class[]; + miscellaneous?: { + typealiases?: TypeAlias[]; + enumerations?: EnumType[]; + }; } diff --git a/examples/angular-cli/src/stories/component-with-enums/__snapshots__/enums.component.stories.storyshot b/examples/angular-cli/src/stories/component-with-enums/__snapshots__/enums.component.stories.storyshot new file mode 100644 index 000000000000..a6d00d8f5aa5 --- /dev/null +++ b/examples/angular-cli/src/stories/component-with-enums/__snapshots__/enums.component.stories.storyshot @@ -0,0 +1,32 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Storyshots Enum Types Basic 1`] = ` + + +
+
+ unionType: union a +
+
+ aliasedUnionType: Type Alias 1 +
+
+ enumNumeric: +
+
+ enumNumericInitial: 1 +
+
+ enumStrings: PRIMARY +
+
+ enumAlias: +
+
+
+
+`; diff --git a/examples/angular-cli/src/stories/component-with-enums/enums.component.html b/examples/angular-cli/src/stories/component-with-enums/enums.component.html new file mode 100644 index 000000000000..08584b9824f4 --- /dev/null +++ b/examples/angular-cli/src/stories/component-with-enums/enums.component.html @@ -0,0 +1,8 @@ +
+
unionType: {{ unionType }}
+
aliasedUnionType: {{ aliasedUnionType }}
+
enumNumeric: {{ enumNumeric }}
+
enumNumericInitial: {{ enumNumericInitial }}
+
enumStrings: {{ enumStrings }}
+
enumAlias: {{ enumAlias }}
+
diff --git a/examples/angular-cli/src/stories/component-with-enums/enums.component.stories.ts b/examples/angular-cli/src/stories/component-with-enums/enums.component.stories.ts new file mode 100644 index 000000000000..269e87bf2b97 --- /dev/null +++ b/examples/angular-cli/src/stories/component-with-enums/enums.component.stories.ts @@ -0,0 +1,25 @@ +import { Story, Meta } from '@storybook/angular'; +import { + EnumsComponent, + EnumNumeric, + EnumNumericInitial, + EnumStringValues, +} from './enums.component'; + +export default { + title: 'Enum Types', + component: EnumsComponent, +} as Meta; + +export const Basic: Story = (args) => ({ + component: EnumsComponent, + props: args, +}); +Basic.args = { + unionType: 'union a', + aliasedUnionType: 'Type Alias 1', + enumNumeric: EnumNumeric.FIRST, + enumNumericInitial: EnumNumericInitial.UNO, + enumStrings: EnumStringValues.PRIMARY, + enumAlias: EnumNumeric.FIRST, +}; diff --git a/examples/angular-cli/src/stories/component-with-enums/enums.component.ts b/examples/angular-cli/src/stories/component-with-enums/enums.component.ts new file mode 100644 index 000000000000..48e781942386 --- /dev/null +++ b/examples/angular-cli/src/stories/component-with-enums/enums.component.ts @@ -0,0 +1,53 @@ +import { Component, Input } from '@angular/core'; + +/** + * This component is used for testing the various forms of enum types + */ +@Component({ + selector: 'app-enums', + templateUrl: './enums.component.html', +}) +export class EnumsComponent { + /** Union Type of string literals */ + @Input() unionType: 'Union A' | 'Union B' | 'Union C'; + + /** Union Type assigned as a Type Alias */ + @Input() aliasedUnionType: TypeAlias; + + /** Base Enum Type with no assigned values */ + @Input() enumNumeric: EnumNumeric; + + /** Enum with initial numeric value and auto-incrementing subsequent values */ + @Input() enumNumericInitial: EnumNumericInitial; + + /** Enum with string values */ + @Input() enumStrings: EnumStringValues; + + /** Type Aliased Enum Type */ + @Input() enumAlias: EnumAlias; +} + +/** + * Button Priority + */ +export enum EnumNumeric { + FIRST, + SECOND, + THIRD, +} + +export enum EnumNumericInitial { + UNO = 1, + DOS, + TRES, +} + +export enum EnumStringValues { + PRIMARY = 'PRIMARY', + SECONDARY = 'SECONDARY', + TERTIARY = 'TERTIARY', +} + +export type EnumAlias = EnumNumeric; + +type TypeAlias = 'Type Alias 1' | 'Type Alias 2' | 'Type Alias 3';