From 937cff21fed05d187eab7822903042a3828720f7 Mon Sep 17 00:00:00 2001 From: Lars Rickert Date: Fri, 23 Feb 2024 22:55:19 +0100 Subject: [PATCH 1/6] feat(vue): improve displayed types for array, union and intersection --- code/frameworks/vue3-vite/src/types.ts | 43 +- .../src/argTypes/docgen/utils/docgenInfo.ts | 4 +- .../extractArgTypes.test.ts.snap | 677 +++-- .../vue3/src/docs/extractArgTypes.test.ts | 314 ++- .../vue3/src/docs/extractArgTypes.ts | 369 ++- .../tests-meta-components/meta-components.ts | 2222 +++++++++-------- 6 files changed, 2176 insertions(+), 1453 deletions(-) diff --git a/code/frameworks/vue3-vite/src/types.ts b/code/frameworks/vue3-vite/src/types.ts index c6ee52bf144a..4b77d28e7a94 100644 --- a/code/frameworks/vue3-vite/src/types.ts +++ b/code/frameworks/vue3-vite/src/types.ts @@ -1,9 +1,16 @@ import type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite'; import type { StorybookConfig as StorybookConfigBase } from '@storybook/types'; +import type { ComponentMeta } from 'vue-component-meta'; +import type { ComponentDoc } from 'vue-docgen-api'; type FrameworkName = '@storybook/vue3-vite'; type BuilderName = '@storybook/builder-vite'; +/** + * Available docgen plugins for vue. + */ +export type VueDocgenPlugin = 'vue-docgen-api' | 'vue-component-meta'; + export type FrameworkOptions = { builder?: BuilderOptions; /** @@ -14,7 +21,7 @@ export type FrameworkOptions = { * "vue-component-meta" will become the new default in the future and "vue-docgen-api" will be removed. * @default "vue-docgen-api" */ - docgen?: 'vue-docgen-api' | 'vue-component-meta'; + docgen?: VueDocgenPlugin; }; type StorybookConfigFramework = { @@ -43,3 +50,37 @@ export type StorybookConfig = Omit< > & StorybookConfigVite & StorybookConfigFramework; + +/** + * Gets the type of a single array element. + */ +type ArrayElement = T extends readonly (infer A)[] ? A : never; + +/** + * Type of "__docgenInfo" depending on the used docgenPlugin. + */ +export type VueDocgenInfo = T extends 'vue-component-meta' + ? ComponentMeta + : ComponentDoc; + +/** + * Single prop/event/slot/exposed entry of "__docgenInfo" depending on the used docgenPlugin. + * + * @example + * ```ts + * type PropInfo = VueDocgenInfoEntry<"vue-component-meta", "props">; + * ``` + */ +export type VueDocgenInfoEntry< + T extends VueDocgenPlugin, + TKey extends 'props' | 'events' | 'slots' | 'exposed' | 'expose' = + | 'props' + | 'events' + | 'slots' + | 'exposed' + | 'expose', +> = ArrayElement< + T extends 'vue-component-meta' + ? VueDocgenInfo<'vue-component-meta'>[Exclude] + : VueDocgenInfo<'vue-docgen-api'>[Exclude] +>; diff --git a/code/lib/docs-tools/src/argTypes/docgen/utils/docgenInfo.ts b/code/lib/docs-tools/src/argTypes/docgen/utils/docgenInfo.ts index 70084ed8ed91..6d1a7005ca0c 100644 --- a/code/lib/docs-tools/src/argTypes/docgen/utils/docgenInfo.ts +++ b/code/lib/docs-tools/src/argTypes/docgen/utils/docgenInfo.ts @@ -3,7 +3,9 @@ import type { Component } from '../../types'; import { str } from './string'; -export function hasDocgen(component: Component): boolean { +export function hasDocgen( + component: Component +): component is object & { __docgenInfo: T } { return !!component.__docgenInfo; } diff --git a/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap b/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap index b4a5c410991a..6df158abb06c 100644 --- a/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap +++ b/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap @@ -1,71 +1,147 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`extractArgTypes > should extract events for Vue component 1`] = ` +exports[`extractArgTypes (vue-docgen-api) > should extract events for component 1`] = ` { "bar": { + "control": { + "disabled": true, + }, + "description": "Test description bar", + "name": "bar", + "table": { + "category": "events", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "{ year: number; title?: any }", + }, + }, + "type": { + "name": "other", + "required": false, + "value": "{ year: number; title?: any }", + }, + }, + "baz": { + "control": { + "disabled": true, + }, + "description": "Test description baz", + "name": "baz", + "table": { + "category": "events", + "defaultValue": null, + "jsDocTags": undefined, + "type": undefined, + }, + "type": { + "name": "other", + "required": false, + "value": "", + }, + }, +} +`; + +exports[`extractArgTypes (vue-docgen-api) > should extract expose for component 1`] = ` +{ + "count": { + "control": { + "disabled": true, + }, + "description": "a count number", + "name": "count", + "table": { + "category": "expose", + "defaultValue": null, + "jsDocTags": undefined, + "type": undefined, + }, + "type": { + "name": "other", + "value": "", + }, + }, + "label": { + "control": { + "disabled": true, + }, + "description": "a label string", + "name": "label", + "table": { + "category": "expose", + "defaultValue": null, + "jsDocTags": undefined, + "type": undefined, + }, + "type": { + "name": "other", + "value": "", + }, + }, +} +`; + +exports[`extractArgTypes (vue-docgen-api) > should extract props for component 1`] = ` +{ + "array": { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, + "description": "description required array object", + "name": "array", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "MyNestedProps[]", + }, }, - "description": "", + "type": { + "name": "other", + "required": true, + "value": "Array([object Object])", + }, + }, + "arrayOptional": { + "control": { + "disabled": false, + }, + "description": "description optional array object", + "name": "arrayOptional", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "MyNestedProps[]", + }, + }, + "type": { + "name": "other", + "required": false, + "value": "Array([object Object])", + }, + }, + "bar": { + "control": { + "disabled": false, + }, + "description": "description bar is optional number", "name": "bar", "table": { "category": "props", "defaultValue": { - "summary": undefined, + "summary": "1", }, - "jsDocTags": [], + "jsDocTags": undefined, "type": { - "summary": "[value: { year: number; title?: any; }]", + "summary": "number", }, }, "type": { - "name": [ - { - "kind": "object", - "schema": { - "title": { - "declarations": [ - { - "file": "/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue", - "range": [ - 269, - 280, - ], - }, - ], - "description": "", - "global": false, - "name": "title", - "required": false, - "schema": "any", - "tags": [], - "type": "any", - }, - "year": { - "declarations": [ - { - "file": "/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue", - "range": [ - 255, - 268, - ], - }, - ], - "description": "", - "global": false, - "name": "year", - "required": true, - "schema": "number", - "tags": [], - "type": "number", - }, - }, - "type": "{ year: number; title?: any; }", - }, - ], + "name": "number", "required": false, }, }, @@ -73,204 +149,483 @@ exports[`extractArgTypes > should extract events for Vue component 1`] = ` "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, - "description": "", + "description": "description baz is required boolean", "name": "baz", "table": { "category": "props", - "defaultValue": { - "summary": undefined, + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "boolean", }, - "jsDocTags": [], + }, + "type": { + "name": "boolean", + "required": true, + }, + }, + "enumValue": { + "control": { + "disabled": false, + }, + "description": "description enum value", + "name": "enumValue", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, "type": { - "summary": "[]", + "summary": "MyEnum", }, }, "type": { - "name": [], - "required": false, + "name": "other", + "required": true, + "value": "MyEnum", }, }, "foo": { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, - "description": "", + "description": "string foo", "name": "foo", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "string", + }, + }, + "type": { + "name": "string", + "required": true, + }, + }, + "inlined": { + "control": { + "disabled": false, + }, + "description": undefined, + "name": "inlined", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "{ foo: string }", + }, + }, + "type": { + "name": "other", + "required": true, + "value": "{ foo: string }", + }, + }, + "literalFromContext": { + "control": { + "disabled": false, + }, + "description": "description literal type alias that require context", + "name": "literalFromContext", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "MyCategories", + }, + }, + "type": { + "name": "other", + "required": true, + "value": "MyCategories", + }, + }, + "nested": { + "control": { + "disabled": false, + }, + "description": "description nested is required nested object", + "name": "nested", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "MyNestedProps", + }, + }, + "type": { + "name": "other", + "required": true, + "value": "MyNestedProps", + }, + }, + "nestedIntersection": { + "control": { + "disabled": false, + }, + "description": "description required nested object with intersection", + "name": "nestedIntersection", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "MyNestedProps & { + /** + * description required additional property + */ + additionalProp: string; +}", + }, + }, + "type": { + "name": "other", + "required": true, + "value": "intersection([object Object],[object Object])", + }, + }, + "nestedOptional": { + "control": { + "disabled": false, + }, + "description": "description optional nested object", + "name": "nestedOptional", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "MyNestedProps | MyIgnoredNestedProps", + }, + }, + "type": { + "name": "union", + "required": false, + "value": [ + { + "name": "other", + "value": "MyNestedProps", + }, + { + "name": "other", + "value": "MyIgnoredNestedProps", + }, + ], + }, + }, + "recursive": { + "control": { + "disabled": false, + }, + "description": undefined, + "name": "recursive", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "MyNestedRecursiveProps", + }, + }, + "type": { + "name": "other", + "required": false, + "value": "MyNestedRecursiveProps", + }, + }, + "stringArray": { + "control": { + "disabled": false, + }, + "description": "description stringArray is string array", + "name": "stringArray", "table": { "category": "props", "defaultValue": { - "summary": undefined, + "summary": "() => ['foo', 'bar']", }, - "jsDocTags": [], + "jsDocTags": undefined, "type": { - "summary": "[data?: { foo: string; }]", + "summary": "string[]", + }, + }, + "type": { + "name": "other", + "required": false, + "value": "Array([object Object])", + }, + }, + "union": { + "control": { + "disabled": false, + }, + "description": "description union is required union type", + "name": "union", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "string | number", }, }, "type": { - "name": [ + "name": "union", + "required": true, + "value": [ { - "kind": "enum", - "schema": [ - "undefined", - { - "kind": "object", - "schema": { - "foo": { - "declarations": [ - { - "file": "/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue", - "range": [ - 207, - 218, - ], - }, - ], - "description": "", - "global": false, - "name": "foo", - "required": true, - "schema": "string", - "tags": [], - "type": "string", - }, - }, - "type": "{ foo: string; }", - }, - ], - "type": "{ foo: string; } | undefined", + "name": "string", + }, + { + "name": "number", }, ], + }, + }, + "unionOptional": { + "control": { + "disabled": false, + }, + "description": "description unionOptional is optional union type", + "name": "unionOptional", + "table": { + "category": "props", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "string | number | boolean", + }, + }, + "type": { + "name": "union", "required": false, + "value": [ + { + "name": "string", + }, + { + "name": "number", + }, + { + "name": "boolean", + }, + ], }, }, } `; -exports[`extractArgTypes > should extract slots type for Vue component 1`] = ` +exports[`extractArgTypes (vue-docgen-api) > should extract slots for component 1`] = ` { "default": { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, - "description": "", + "description": undefined, "name": "default", "table": { - "category": "props", - "defaultValue": { - "summary": undefined, + "category": "slots", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "{ num: unknown }", }, - "jsDocTags": [], + }, + "type": { + "name": "other", + "required": false, + "value": "{ num: unknown }", + }, + }, + "named": { + "control": { + "disabled": false, + }, + "description": undefined, + "name": "named", + "table": { + "category": "slots", + "defaultValue": null, + "jsDocTags": undefined, "type": { - "summary": "{ num: number; }", + "summary": "{ str: unknown }", }, }, "type": { - "name": "object", + "name": "other", "required": false, - "value": { - "num": { - "name": "number", - "required": true, - }, + "value": "{ str: unknown }", + }, + }, + "no-bind": { + "control": { + "disabled": false, + }, + "description": undefined, + "name": "no-bind", + "table": { + "category": "slots", + "defaultValue": null, + "jsDocTags": undefined, + "type": undefined, + }, + "type": { + "name": "other", + "required": false, + "value": "", + }, + }, + "vbind": { + "control": { + "disabled": false, + }, + "description": undefined, + "name": "vbind", + "table": { + "category": "slots", + "defaultValue": null, + "jsDocTags": undefined, + "type": { + "summary": "{ num: unknown, str: unknown }", }, }, + "type": { + "name": "other", + "required": false, + "value": "{ num: unknown, str: unknown }", + }, }, - "named": { +} +`; + +exports[`extractArgTypes > should extract events for Vue component 1`] = ` +{ + "bar": { + "control": { + "disabled": true, + }, + "description": "", + "name": "bar", + "table": { + "category": "events", + "type": { + "summary": "[value: { year: number; title?: any; }]", + }, + }, + "type": { + "name": "other", + "value": "[value: { year: number; title?: any; }]", + }, + }, + "baz": { + "control": { + "disabled": true, + }, + "description": "", + "name": "baz", + "table": { + "category": "events", + "type": { + "summary": "[]", + }, + }, + "type": { + "name": "other", + "value": "[]", + }, + }, + "foo": { + "control": { + "disabled": true, + }, + "description": "", + "name": "foo", + "table": { + "category": "events", + "type": { + "summary": "[data?: { foo: string; }]", + }, + }, + "type": { + "name": "other", + "value": "[data?: { foo: string; } | undefined]", + }, + }, +} +`; + +exports[`extractArgTypes > should extract slots type for Vue component 1`] = ` +{ + "default": { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, + "description": "", + "name": "default", + "table": { + "category": "slots", + "type": { + "summary": "{ num: number; }", + }, + }, + "type": { + "name": "other", + "value": "{ num: number; }", + }, + }, + "named": { + "control": { + "disabled": false, }, "description": "", "name": "named", "table": { - "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "category": "slots", "type": { "summary": "{ str: string; }", }, }, "type": { - "name": "object", - "required": false, - "value": { - "str": { - "name": "string", - "required": true, - }, - }, + "name": "other", + "value": "{ str: string; }", }, }, "no-bind": { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, "description": "", "name": "no-bind", "table": { - "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "category": "slots", "type": { "summary": "{}", }, }, "type": { - "name": "object", - "required": false, - "value": {}, + "name": "other", + "value": "{}", }, }, "vbind": { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, "description": "", "name": "vbind", "table": { - "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "category": "slots", "type": { "summary": "{ num: number; str: string; }", }, }, "type": { - "name": "object", - "required": false, - "value": { - "num": { - "name": "number", - "required": true, - }, - "str": { - "name": "string", - "required": true, - }, - }, + "name": "other", + "value": "{ num: number; str: string; }", }, }, } diff --git a/code/renderers/vue3/src/docs/extractArgTypes.test.ts b/code/renderers/vue3/src/docs/extractArgTypes.test.ts index 2c978af54dd0..118e5273bb65 100644 --- a/code/renderers/vue3/src/docs/extractArgTypes.test.ts +++ b/code/renderers/vue3/src/docs/extractArgTypes.test.ts @@ -9,9 +9,17 @@ import { referenceTypeEvents, referenceTypeProps, templateSlots, + vueDocgenMocks, } from './tests-meta-components/meta-components'; -vitest.mock('@storybook/docs-tools'); +vitest.mock('@storybook/docs-tools', async (importOriginal) => { + const module: Record = await importOriginal(); + return { + ...module, + extractComponentProps: vi.fn(), + hasDocgen: vi.fn(), + }; +}); describe('extractArgTypes', () => { beforeEach(() => { @@ -19,16 +27,19 @@ describe('extractArgTypes', () => { }); it('should return null if component does not contain docs', () => { - (hasDocgen as Mock).mockReturnValueOnce(false); + (hasDocgen as unknown as Mock).mockReturnValueOnce(false); (extractComponentProps as Mock).mockReturnValueOnce([] as any); expect(extractArgTypes({} as any)).toBeNull(); }); - it('should extract arg types for component', () => { + it('should extract props for component', () => { const component = referenceTypeProps; - (hasDocgen as Mock).mockReturnValueOnce(true); - (extractComponentProps as Mock).mockReturnValue(mockExtractComponentPropsReturn); + (hasDocgen as unknown as Mock).mockReturnValueOnce(true); + + (extractComponentProps as Mock).mockImplementation((_, section) => { + return section === 'props' ? mockExtractComponentPropsReturn : []; + }); const argTypes = extractArgTypes(component); @@ -38,17 +49,12 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description required array object", "name": "array", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "MyNestedProps[]", }, @@ -72,17 +78,12 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description optional array object", "name": "arrayOptional", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "MyNestedProps[]", }, @@ -116,7 +117,6 @@ describe('extractArgTypes', () => { "defaultValue": { "summary": "1", }, - "jsDocTags": [], "type": { "summary": "number", }, @@ -130,17 +130,12 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description baz is required boolean", "name": "baz", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "boolean", }, @@ -154,17 +149,12 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description enum value", "name": "enumValue", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "MyEnum", }, @@ -183,34 +173,12 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "@default: "rounded"
@since: v1.0.0
@see: https://vuejs.org/
@deprecated: v1.1.0

string foo", "name": "foo", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [ - { - "name": "default", - "text": ""rounded"", - }, - { - "name": "since", - "text": "v1.0.0", - }, - { - "name": "see", - "text": "https://vuejs.org/", - }, - { - "name": "deprecated", - "text": "v1.1.0", - }, - ], + "defaultValue": undefined, "type": { "summary": "string", }, @@ -224,17 +192,12 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "", "name": "inlined", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "{ foo: string; }", }, @@ -254,17 +217,12 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description literal type alias that require context", "name": "literalFromContext", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": ""Uncategorized" | "Content" | "Interaction" | "Display" | "Forms" | "Addons"", }, @@ -286,17 +244,12 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description nested is required nested object", "name": "nested", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "MyNestedProps", }, @@ -316,17 +269,12 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description required nested object with intersection", "name": "nestedIntersection", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "MyNestedProps & { additionalProp: string; }", }, @@ -350,79 +298,53 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description optional nested object", "name": "nestedOptional", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "MyNestedProps | MyIgnoredNestedProps", }, }, "type": { - "name": { - "kind": "enum", - "schema": [ - "undefined", - { - "kind": "object", - "schema": { - "nestedProp": { - "declarations": [], - "description": "nested prop documentation", - "global": false, - "name": "nestedProp", - "required": true, - "schema": "string", - "tags": [], - "type": "string", - }, + "name": "union", + "required": false, + "value": [ + { + "name": "object", + "required": false, + "value": { + "nestedProp": { + "name": "string", + "required": true, }, - "type": "MyNestedProps", }, - { - "kind": "object", - "schema": { - "nestedProp": { - "declarations": [], - "description": "", - "global": false, - "name": "nestedProp", - "required": true, - "schema": "string", - "tags": [], - "type": "string", - }, + }, + { + "name": "object", + "required": false, + "value": { + "nestedProp": { + "name": "string", + "required": true, }, - "type": "MyIgnoredNestedProps", }, - ], - "type": "MyNestedProps | MyIgnoredNestedProps | undefined", - }, - "required": false, + }, + ], }, }, "recursive": { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "", "name": "recursive", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "MyNestedRecursiveProps", }, @@ -432,8 +354,9 @@ describe('extractArgTypes', () => { "required": false, "value": { "recursive": { - "name": "MyNestedRecursiveProps", + "name": "other", "required": true, + "value": "MyNestedRecursiveProps", }, }, }, @@ -452,7 +375,6 @@ describe('extractArgTypes', () => { "defaultValue": { "summary": "["foo", "bar"]", }, - "jsDocTags": [], "type": { "summary": "string[]", }, @@ -470,48 +392,62 @@ describe('extractArgTypes', () => { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description union is required union type", "name": "union", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "string | number", }, }, "type": { - "name": "string", + "name": "union", "required": true, + "value": [ + { + "name": "string", + "required": false, + }, + { + "name": "number", + "required": false, + }, + ], }, }, "unionOptional": { "control": { "disabled": false, }, - "defaultValue": { - "summary": undefined, - }, + "defaultValue": undefined, "description": "description unionOptional is optional union type", "name": "unionOptional", "table": { "category": "props", - "defaultValue": { - "summary": undefined, - }, - "jsDocTags": [], + "defaultValue": undefined, "type": { "summary": "string | number | boolean", }, }, "type": { - "name": "string", + "name": "union", "required": false, + "value": [ + { + "name": "string", + "required": false, + }, + { + "name": "number", + "required": false, + }, + { + "name": "boolean", + "required": false, + }, + ], }, }, } @@ -520,8 +456,10 @@ describe('extractArgTypes', () => { it('should extract events for Vue component', () => { const component = referenceTypeEvents; - (hasDocgen as Mock).mockReturnValueOnce(true); - (extractComponentProps as Mock).mockReturnValue(mockExtractComponentEventsReturn); + (hasDocgen as unknown as Mock).mockReturnValueOnce(true); + (extractComponentProps as Mock).mockImplementation((_, section) => { + return section === 'events' ? mockExtractComponentEventsReturn : []; + }); const argTypes = extractArgTypes(component); @@ -530,8 +468,68 @@ describe('extractArgTypes', () => { it('should extract slots type for Vue component', () => { const component = templateSlots; - (hasDocgen as Mock).mockReturnValueOnce(true); - (extractComponentProps as Mock).mockReturnValue(mockExtractComponentSlotsReturn); + (hasDocgen as unknown as Mock).mockReturnValueOnce(true); + (extractComponentProps as Mock).mockImplementation((_, section) => { + return section === 'slots' ? mockExtractComponentSlotsReturn : []; + }); + + const argTypes = extractArgTypes(component); + + expect(argTypes).toMatchSnapshot(); + }); +}); + +describe('extractArgTypes (vue-docgen-api)', () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + it('should extract props for component', async () => { + const component = vueDocgenMocks.props.component; + (hasDocgen as unknown as Mock).mockReturnValueOnce(true); + + (extractComponentProps as Mock).mockImplementation((_, section) => { + return section === 'props' ? vueDocgenMocks.props.extractedProps : []; + }); + + const argTypes = extractArgTypes(component); + + expect(argTypes).toMatchSnapshot(); + }); + + it('should extract events for component', async () => { + const component = vueDocgenMocks.events.component; + (hasDocgen as unknown as Mock).mockReturnValueOnce(true); + + (extractComponentProps as Mock).mockImplementation((_, section) => { + return section === 'events' ? vueDocgenMocks.events.extractedProps : []; + }); + + const argTypes = extractArgTypes(component); + + expect(argTypes).toMatchSnapshot(); + }); + + it('should extract slots for component', async () => { + const component = vueDocgenMocks.slots.component; + (hasDocgen as unknown as Mock).mockReturnValueOnce(true); + + (extractComponentProps as Mock).mockImplementation((_, section) => { + return section === 'slots' ? vueDocgenMocks.slots.extractedProps : []; + }); + + const argTypes = extractArgTypes(component); + + expect(argTypes).toMatchSnapshot(); + }); + + it('should extract expose for component', async () => { + const component = vueDocgenMocks.expose.component; + (hasDocgen as unknown as Mock).mockReturnValueOnce(true); + + (extractComponentProps as Mock).mockImplementation((_, section) => { + return section === 'expose' ? vueDocgenMocks.expose.extractedProps : []; + }); const argTypes = extractArgTypes(component); diff --git a/code/renderers/vue3/src/docs/extractArgTypes.ts b/code/renderers/vue3/src/docs/extractArgTypes.ts index 5a535d40599c..a5e8d516dfb1 100644 --- a/code/renderers/vue3/src/docs/extractArgTypes.ts +++ b/code/renderers/vue3/src/docs/extractArgTypes.ts @@ -1,60 +1,49 @@ -import type { SBType, StrictArgTypes } from '@storybook/types'; - +import type { ExtractedProp } from '@storybook/docs-tools'; import { + convert, extractComponentProps, - convert as genericConvert, hasDocgen, type ArgTypesExtractor, - type DocgenInfo, } from '@storybook/docs-tools'; +import type { SBType, StrictArgTypes, StrictInputType } from '@storybook/types'; +import type { VueDocgenInfo, VueDocgenInfoEntry, VueDocgenPlugin } from '@storybook/vue3-vite'; -type Schema = { kind: string; schema: [] | object; type?: string } | string; -type MetaDocgenInfo = DocgenInfo & { - type: string | { name: string; value: string[] }; - default: string; - global: boolean; - name: string; - schema?: Schema; - tags?: { name: string; text: string }[]; -}; +type PropertyMetaSchema = VueDocgenInfoEntry<'vue-component-meta', 'props'>['schema']; // "exposed" is used by the vue-component-meta plugin while "expose" is used by vue-docgen-api const ARG_TYPE_SECTIONS = ['props', 'events', 'slots', 'exposed', 'expose'] as const; export const extractArgTypes: ArgTypesExtractor = (component) => { - if (!hasDocgen(component)) { + if (!hasDocgen>(component)) { return null; } + const usedDocgenPlugin: VueDocgenPlugin = + // eslint-disable-next-line no-underscore-dangle + 'exposed' in component.__docgenInfo ? 'vue-component-meta' : 'vue-docgen-api'; + const argTypes: StrictArgTypes = {}; ARG_TYPE_SECTIONS.forEach((section) => { const props = extractComponentProps(component, section); props.forEach((extractedProp) => { - const docgenInfo = extractedProp.docgenInfo as MetaDocgenInfo; + let argType: StrictInputType | undefined; - if (argTypes[docgenInfo.name] || docgenInfo.global) { - return; // skip duplicate and global props + if (usedDocgenPlugin === 'vue-docgen-api') { + const docgenInfo = + extractedProp.docgenInfo as unknown as VueDocgenInfoEntry<'vue-docgen-api'>; + argType = extractFromVueDocgenApi(docgenInfo, section, extractedProp); + } else { + const docgenInfo = + extractedProp.docgenInfo as unknown as VueDocgenInfoEntry<'vue-component-meta'>; + argType = extractFromVueComponentMeta(docgenInfo, section); } - const type = - typeof docgenInfo.type === 'string' ? docgenInfo.type : docgenInfo.type?.name ?? ''; - const sbType = section === 'props' ? convertPropType(docgenInfo) : ({ name: type } as SBType); - - const defaultValue = { summary: docgenInfo.default }; - - argTypes[docgenInfo.name] = { - name: docgenInfo.name, - description: formatDescriptionWithTags(docgenInfo.description, docgenInfo.tags), - defaultValue, - type: sbType, - table: { - type: { summary: type.replace(' | undefined', '') }, - jsDocTags: docgenInfo.tags ?? [], - defaultValue, - category: section, - }, + // skip duplicate and global props + if (!argType || argTypes[argType.name]) return; + argTypes[argType.name] = { + ...argType, control: { disabled: !['props', 'slots'].includes(section) }, }; }); @@ -64,81 +53,293 @@ export const extractArgTypes: ArgTypesExtractor = (component) => { }; /** - * Converts the given prop type into a SBType so it can be correctly displayed in the UI (controls etc.). + * Extracts the argType for a prop/event/slot/expose generated with "vue-docgen-api". + * + * @param docgenInfo __docgenInfo from "vue-docgen-api" + * @param section Whether the arg is a prop, event, slot or expose + * @param extractedProp Extracted prop, needed when "section" is "slots" */ -export const convertPropType = (propInfo: MetaDocgenInfo): SBType => { - const schema = propInfo.schema; - const required = propInfo.required ?? false; - const fallbackSbType = { name: schema, required } as SBType; +export const extractFromVueDocgenApi = ( + docgenInfo: VueDocgenInfoEntry<'vue-docgen-api'>, + section: (typeof ARG_TYPE_SECTIONS)[number], + extractedProp?: ExtractedProp +): StrictInputType => { + let type: string | undefined; + let sbType: SBType | undefined; - if (!schema) return genericConvert(propInfo) ?? fallbackSbType; - if (typeof schema === 'string') return fallbackSbType; + if (section === 'events') { + const eventInfo = docgenInfo as VueDocgenInfoEntry<'vue-docgen-api', 'events'>; + type = eventInfo.type?.names.join(); + sbType = { name: 'other', value: type ?? '', required: false }; + } - // convert enum schemas (e.g. union or enum type to corresponding SBType) - // so the enum values can be selected via radio/dropdown in the UI - if (schema.kind === 'enum' && Array.isArray(schema.schema)) { - // filter out empty or "undefined" for optional props - const definedValues = schema.schema.filter((item) => item != null && item !== 'undefined'); + if (section === 'slots') { + const slotInfo = docgenInfo as VueDocgenInfoEntry<'vue-docgen-api', 'slots'>; - if (definedValues.length === 1 && typeof definedValues[0] === 'object') { - return convertPropType({ schema: definedValues[0] } as MetaDocgenInfo); - } + const slotParams = slotInfo.bindings + ?.filter((binding) => !!binding.name) + .map((binding) => { + return `${binding.name}: ${binding.type?.name ?? 'unknown'}`; + }) + .join(', '); - const values = definedValues - .filter((item: Schema) => typeof item === 'string') - .map((item: Schema) => (typeof item !== 'string' ? item.schema.toString() : item)) - .map((item: string) => item.replace(/'/g, '"')); + type = slotParams ? `{ ${slotParams} }` : undefined; + sbType = { name: 'other', value: type ?? '', required: false }; + } - if (values.length === 0) return fallbackSbType; + if (section === 'props') { + const propInfo = docgenInfo as VueDocgenInfoEntry<'vue-docgen-api', 'props'>; - const isBoolean = values.length === 2 && values.includes('true') && values.includes('false'); - if (isBoolean) return { name: 'boolean', required }; + type = propInfo.type?.name; + sbType = extractedProp ? convert(extractedProp.docgenInfo) : { name: 'other', value: type }; - const isLateralUnion = - values.length > 1 && values.every((item) => item.startsWith('"') && item.endsWith('"')); - const isEnum = - !isLateralUnion && - values.length > 1 && - values.every((item) => typeof item === 'string' && item.includes('.')); + // try to get more specific types for array, union and intersection + if ( + propInfo.type && + 'elements' in propInfo.type && + Array.isArray(propInfo.type.elements) && + propInfo.type.elements.length > 0 + ) { + const elements = (propInfo.type.elements as { name: string }[]).map((i) => i.name); - if (isLateralUnion || isEnum) { - const valuesWithoutQuotes = values.map((item: string) => item.replace(/"/g, '')); - return { name: 'enum', value: valuesWithoutQuotes, required }; - } + if (type === 'Array') { + const arrayElements = elements.length === 1 ? elements[0] : `(${elements.join(' | ')})`; + type = `${arrayElements}[]`; + } + + if (type === 'union') { + type = elements.join(' | '); + } - return { name: values[0], required } as SBType; + if (type === 'intersection') { + type = elements.join(' & '); + } + } } - // recursively convert object properties to SBType - if (schema.kind === 'object' && typeof schema.schema === 'object') { - const schemaObject = schema.schema as Record; + return { + name: docgenInfo.name, + description: docgenInfo.description, + type: sbType + ? { + ...sbType, + required: 'required' in docgenInfo ? docgenInfo.required ?? false : false, + } + : { name: 'other', value: type ?? '' }, + table: { + type: type ? { summary: type } : undefined, + defaultValue: extractedProp?.propDef.defaultValue, + jsDocTags: extractedProp?.propDef.jsDocTags, + category: section, + }, + }; +}; + +/** + * Extracts the argType for a prop/event/slot/exposed generated with "vue-component-meta". + + * @param docgenInfo __docgenInfo from "vue-component-meta" + * @param section Whether the arg is a prop, event, slot or exposed + */ +export const extractFromVueComponentMeta = ( + docgenInfo: VueDocgenInfoEntry<'vue-component-meta'>, + section: (typeof ARG_TYPE_SECTIONS)[number] +): StrictInputType | undefined => { + if ('global' in docgenInfo && docgenInfo.global) return; + + const tableType = { summary: docgenInfo.type.replace(' | undefined', '') }; + + if (section === 'props') { + const propInfo = docgenInfo as VueDocgenInfoEntry<'vue-component-meta', 'props'>; + const defaultValue = propInfo.default ? { summary: propInfo.default } : undefined; return { - name: 'object', - required, - value: Object.entries(schemaObject).reduce>((obj, [key, value]) => { - obj[key] = convertPropType(value); - return obj; - }, {}), + name: propInfo.name, + description: formatDescriptionWithTags(propInfo.description, propInfo.tags), + defaultValue, + type: getStorybookTypeFromVueComponentMeta(propInfo), + table: { + type: tableType, + defaultValue, + category: section, + }, }; - } - - if (schema.kind === 'array' && Array.isArray(schema.schema)) { + } else { return { - name: 'array', - value: convertPropType({ schema: schema.schema[0] } as MetaDocgenInfo), - required, + name: docgenInfo.name, + description: 'description' in docgenInfo ? docgenInfo.description : '', + type: { name: 'other', value: docgenInfo.type }, + table: { + type: tableType, + category: section, + }, }; } +}; + +/** + * Converts the given prop info that was generated with "vue-component-meta" into a SBType. + */ +export const getStorybookTypeFromVueComponentMeta = ( + propInfo: Pick, 'schema' | 'required' | 'type'> +): SBType => { + const schema = propInfo.schema; + const required = propInfo.required; + const fallbackSbType: SBType = { name: 'other', value: propInfo.type, required }; + + const KNOWN_SCHEMAS = ['string', 'number', 'function', 'boolean', 'symbol'] as const; + type KnownSchema = (typeof KNOWN_SCHEMAS)[number]; + + if (typeof schema === 'string') { + if (KNOWN_SCHEMAS.includes(schema as KnownSchema)) { + return { name: schema as KnownSchema, required }; + } + return fallbackSbType; + } + + switch (schema.kind) { + case 'enum': { + // filter out empty or "undefined" for optional props + let definedSchemas = schema.schema?.filter((item) => item !== 'undefined') ?? []; + + if (isBooleanSchema(definedSchemas)) { + return { name: 'boolean', required }; + } + + if (isLiteralUnionSchema(definedSchemas) || isEnumSchema(definedSchemas)) { + // remove quotes from literals + const literals = definedSchemas.map((literal) => literal.replace(/"/g, '')); + return { name: 'enum', value: literals, required }; + } + + if (definedSchemas.length === 1) { + return getStorybookTypeFromVueComponentMeta({ + schema: definedSchemas[0], + type: propInfo.type, + required, + }); + } + + // for union types like "string | number | boolean", + // the schema will be "string | number | true | false" + // so we need to replace "true | false" with boolean + if ( + definedSchemas.length > 2 && + definedSchemas.includes('true') && + definedSchemas.includes('false') + ) { + definedSchemas = definedSchemas.filter((i) => i !== 'true' && i !== 'false'); + definedSchemas.push('boolean'); + } + + return { + name: 'union', + value: definedSchemas.map((i) => { + if (typeof i === 'object') { + return getStorybookTypeFromVueComponentMeta({ + schema: i, + type: i.type, + required: false, + }); + } else { + return getStorybookTypeFromVueComponentMeta({ schema: i, type: i, required: false }); + } + }), + required, + }; + } + + case 'array': { + // filter out empty or "undefined" for optional props + const definedSchemas = schema.schema?.filter((item) => item !== 'undefined') ?? []; + if (definedSchemas.length === 0) return fallbackSbType; + + if (definedSchemas.length === 1) { + return { + name: 'array', + value: getStorybookTypeFromVueComponentMeta({ + schema: definedSchemas[0], + type: propInfo.type, + required: false, + }), + required, + }; + } + + return { + name: 'union', + value: definedSchemas.map((i) => { + if (typeof i === 'object') { + return getStorybookTypeFromVueComponentMeta({ + schema: i, + type: i.type, + required: false, + }); + } else { + return getStorybookTypeFromVueComponentMeta({ schema: i, type: i, required: false }); + } + }), + required, + }; + } - return fallbackSbType; + case 'object': + return { + name: 'object', + value: Object.entries(schema.schema ?? {}).reduce>( + (obj, [propName, propSchema]) => { + obj[propName] = getStorybookTypeFromVueComponentMeta(propSchema); + return obj; + }, + {} + ), + required, + }; + + default: + return fallbackSbType; + } }; /** * Adds the descriptions for the given tags if available. */ -const formatDescriptionWithTags = (description: string, tags: MetaDocgenInfo['tags']): string => { +const formatDescriptionWithTags = ( + description: string, + tags: VueDocgenInfoEntry<'vue-component-meta', 'props'>['tags'] +): string => { if (!tags?.length || !description) return description ?? ''; const tagDescriptions = tags.map((tag) => `@${tag.name}: ${tag.text}`).join('
'); return `${tagDescriptions}

${description}`; }; + +/** + * Checks whether the given schemas are all literal union schemas. + * + * @example "foo" | "bar" | "baz" + */ +const isLiteralUnionSchema = (schemas: PropertyMetaSchema[]): schemas is `"${string}"`[] => { + return schemas.every( + (schema) => typeof schema === 'string' && schema.startsWith('"') && schema.endsWith('"') + ); +}; + +/** + * Checks whether the given schemas are all enums. + * + * @example [MyEnum.Foo, MyEnum.Bar] + */ +const isEnumSchema = (schemas: PropertyMetaSchema[]): schemas is string[] => { + return schemas.every((schema) => typeof schema === 'string' && schema.includes('.')); +}; + +/** + * Checks whether the given schemas are representing a boolean. + * + * @example [true, false] + */ +const isBooleanSchema = ( + schemas: PropertyMetaSchema[] +): schemas is ['true', 'false'] | ['false', 'true'] => { + return schemas.length === 2 && schemas.includes('true') && schemas.includes('false'); +}; diff --git a/code/renderers/vue3/src/docs/tests-meta-components/meta-components.ts b/code/renderers/vue3/src/docs/tests-meta-components/meta-components.ts index 085b59a1e9ae..043244a8fd3b 100644 --- a/code/renderers/vue3/src/docs/tests-meta-components/meta-components.ts +++ b/code/renderers/vue3/src/docs/tests-meta-components/meta-components.ts @@ -1,8 +1,11 @@ -export const referenceTypeProps = { - __name: 'component', +import type { ExtractedProp } from '@storybook/docs-tools'; +import { TypeSystem } from '@storybook/docs-tools'; +import type { VueDocgenInfo } from 'frameworks/vue3-vite/src'; + +type TestComponent = { __docgenInfo: VueDocgenInfo<'vue-component-meta'> }; + +export const referenceTypeProps: TestComponent = { __docgenInfo: { - exportName: 'default', - displayName: 'component', type: 1, props: [ { @@ -468,380 +471,167 @@ export const referenceTypeProps = { ], events: [], slots: [], - exposed: [ - { - name: 'foo', - type: 'string', - description: 'string foo', - declarations: [], - schema: 'string', + exposed: [], + }, +}; + +export const mockExtractComponentPropsReturn = [ + { + propDef: { + name: 'bar', + type: {}, + required: false, + description: 'description bar is optional number', + defaultValue: null, + sbType: { + name: 'other', }, - { - name: 'bar', - type: 'number', - description: 'description bar is optional number', - declarations: [], - schema: 'number', + }, + docgenInfo: { + name: 'bar', + global: false, + description: 'description bar is optional number', + tags: [], + required: false, + type: 'number | undefined', + declarations: [], + schema: { + kind: 'enum', + type: 'number | undefined', + schema: ['undefined', 'number'], }, - { - name: 'baz', - type: 'boolean', - description: 'description baz is required boolean', - declarations: [], - schema: { - kind: 'enum', - type: 'boolean', - schema: ['false', 'true'], - }, + default: '1', + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'stringArray', + type: {}, + required: false, + description: 'description stringArray is string array', + defaultValue: null, + sbType: { + name: 'other', }, - { - name: 'stringArray', - type: 'string[]', - description: 'description stringArray is string array', - declarations: [], - schema: { - kind: 'array', - type: 'string[]', - schema: ['string'], - }, + }, + docgenInfo: { + name: 'stringArray', + global: false, + description: 'description stringArray is string array', + tags: [], + required: false, + type: 'string[] | undefined', + declarations: [], + schema: { + kind: 'enum', + type: 'string[] | undefined', + schema: [ + 'undefined', + { + kind: 'array', + type: 'string[]', + schema: ['string'], + }, + ], }, - { - name: 'union', - type: 'string | number', - description: 'description union is required union type', - declarations: [], - schema: { - kind: 'enum', - type: 'string | number', - schema: ['string', 'number'], - }, + default: '["foo", "bar"]', + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'key', + type: {}, + required: false, + description: '', + defaultValue: null, + sbType: { + name: 'other', }, - { - name: 'unionOptional', - type: 'string | number | boolean | undefined', - description: 'description unionOptional is optional union type', - declarations: [], - schema: { - kind: 'enum', - type: 'string | number | boolean | undefined', - schema: ['undefined', 'string', 'number', 'false', 'true'], - }, + }, + docgenInfo: { + name: 'key', + global: true, + description: '', + tags: [], + required: false, + type: 'string | number | symbol | undefined', + declarations: [], + schema: { + kind: 'enum', + type: 'string | number | symbol | undefined', + schema: ['undefined', 'string', 'number', 'symbol'], }, - { - name: 'nested', - type: 'MyNestedProps', - description: 'description nested is required nested object', - declarations: [], - schema: { - kind: 'object', - type: 'MyNestedProps', - schema: { - nestedProp: { - name: 'nestedProp', - global: false, - description: 'nested prop documentation', - tags: [], - required: true, - type: 'string', - declarations: [], - schema: 'string', - }, - }, - }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'ref', + type: {}, + required: false, + description: '', + defaultValue: null, + sbType: { + name: 'other', }, - { - name: 'nestedIntersection', - type: 'MyNestedProps & { additionalProp: string; }', - description: 'description required nested object with intersection', - declarations: [], - schema: { - kind: 'object', - type: 'MyNestedProps & { additionalProp: string; }', - schema: { - nestedProp: { - name: 'nestedProp', - global: false, - description: 'nested prop documentation', - tags: [], - required: true, - type: 'string', - declarations: [], - schema: 'string', - }, - additionalProp: { - name: 'additionalProp', - global: false, - description: 'description required additional property', - tags: [], - required: true, - type: 'string', - declarations: [], - schema: 'string', - }, + }, + docgenInfo: { + name: 'ref', + global: true, + description: '', + tags: [], + required: false, + type: 'VNodeRef | undefined', + declarations: [], + schema: { + kind: 'enum', + type: 'VNodeRef | undefined', + schema: [ + 'undefined', + 'string', + 'Ref', + { + kind: 'event', + type: '(ref: Element | ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, ComponentOptionsBase, {}, {}> | null, refs: Record<...>): void', + schema: [], }, - }, + ], }, - { - name: 'nestedOptional', - type: 'MyNestedProps | MyIgnoredNestedProps | undefined', - description: 'description optional nested object', - declarations: [], - schema: { - kind: 'enum', - type: 'MyNestedProps | MyIgnoredNestedProps | undefined', - schema: [ - 'undefined', - { - kind: 'object', - type: 'MyNestedProps', - schema: { - nestedProp: { - name: 'nestedProp', - global: false, - description: 'nested prop documentation', - tags: [], - required: true, - type: 'string', - declarations: [], - schema: 'string', - }, - }, - }, - { - kind: 'object', - type: 'MyIgnoredNestedProps', - schema: { - nestedProp: { - name: 'nestedProp', - global: false, - description: '', - tags: [], - required: true, - type: 'string', - declarations: [], - schema: 'string', - }, - }, - }, - ], - }, - }, - { - name: 'array', - type: 'MyNestedProps[]', - description: 'description required array object', - declarations: [], - schema: { - kind: 'array', - type: 'MyNestedProps[]', - schema: [ - { - kind: 'object', - type: 'MyNestedProps', - schema: { - nestedProp: { - name: 'nestedProp', - global: false, - description: 'nested prop documentation', - tags: [], - required: true, - type: 'string', - declarations: [], - schema: 'string', - }, - }, - }, - ], - }, - }, - { - name: 'arrayOptional', - type: 'MyNestedProps[] | undefined', - description: 'description optional array object', - declarations: [], - schema: { - kind: 'enum', - type: 'MyNestedProps[] | undefined', - schema: [ - 'undefined', - { - kind: 'array', - type: 'MyNestedProps[]', - schema: [ - { - kind: 'object', - type: 'MyNestedProps', - schema: { - nestedProp: { - name: 'nestedProp', - global: false, - description: 'nested prop documentation', - tags: [], - required: true, - type: 'string', - declarations: [], - schema: 'string', - }, - }, - }, - ], - }, - ], - }, - }, - { - name: 'enumValue', - type: 'MyEnum', - description: 'description enum value', - declarations: [], - schema: { - kind: 'enum', - type: 'MyEnum', - schema: ['MyEnum.Small', 'MyEnum.Medium', 'MyEnum.Large'], - }, - }, - { - name: 'literalFromContext', - type: '"Uncategorized" | "Content" | "Interaction" | "Display" | "Forms" | "Addons"', - description: 'description literal type alias that require context', - declarations: [], - schema: { - kind: 'enum', - type: '"Uncategorized" | "Content" | "Interaction" | "Display" | "Forms" | "Addons"', - schema: [ - '"Uncategorized"', - '"Content"', - '"Interaction"', - '"Display"', - '"Forms"', - '"Addons"', - ], - }, - }, - { - name: 'inlined', - type: '{ foo: string; }', - description: '', - declarations: [], - schema: { - kind: 'object', - type: '{ foo: string; }', - schema: { - foo: { - name: 'foo', - global: false, - description: '', - tags: [], - required: true, - type: 'string', - declarations: [], - schema: 'string', - }, - }, - }, - }, - { - name: 'recursive', - type: 'MyNestedRecursiveProps | undefined', - description: '', - declarations: [], - schema: { - kind: 'enum', - type: 'MyNestedRecursiveProps | undefined', - schema: [ - 'undefined', - { - kind: 'object', - type: 'MyNestedRecursiveProps', - schema: { - recursive: { - name: 'recursive', - global: false, - description: '', - tags: [], - required: true, - type: 'MyNestedRecursiveProps', - declarations: [], - schema: 'MyNestedRecursiveProps', - }, - }, - }, - ], - }, - }, - ], - sourceFiles: - '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3_vue3-vite-default-ts/component-meta/reference-type-props/component.vue', - }, -}; - -export const mockExtractComponentPropsReturn = [ - { - propDef: { - name: 'bar', - type: {}, - required: false, - description: 'description bar is optional number', - defaultValue: null, - sbType: { - name: 'other', - }, - }, - docgenInfo: { - name: 'bar', - global: false, - description: 'description bar is optional number', - tags: [], - required: false, - type: 'number | undefined', - declarations: [], - schema: { - kind: 'enum', - type: 'number | undefined', - schema: ['undefined', 'number'], - }, - default: '1', }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { - name: 'stringArray', + name: 'ref_for', type: {}, required: false, - description: 'description stringArray is string array', + description: '', defaultValue: null, sbType: { name: 'other', }, }, docgenInfo: { - name: 'stringArray', - global: false, - description: 'description stringArray is string array', + name: 'ref_for', + global: true, + description: '', tags: [], required: false, - type: 'string[] | undefined', + type: 'boolean | undefined', declarations: [], schema: { kind: 'enum', - type: 'string[] | undefined', - schema: [ - 'undefined', - { - kind: 'array', - type: 'string[]', - schema: ['string'], - }, - ], + type: 'boolean | undefined', + schema: ['undefined', 'false', 'true'], }, - default: '["foo", "bar"]', }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { - name: 'key', + name: 'ref_key', type: {}, required: false, description: '', @@ -851,24 +641,24 @@ export const mockExtractComponentPropsReturn = [ }, }, docgenInfo: { - name: 'key', + name: 'ref_key', global: true, description: '', tags: [], required: false, - type: 'string | number | symbol | undefined', + type: 'string | undefined', declarations: [], schema: { kind: 'enum', - type: 'string | number | symbol | undefined', - schema: ['undefined', 'string', 'number', 'symbol'], + type: 'string | undefined', + schema: ['undefined', 'string'], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { - name: 'ref', + name: 'class', type: {}, required: false, description: '', @@ -878,33 +668,20 @@ export const mockExtractComponentPropsReturn = [ }, }, docgenInfo: { - name: 'ref', + name: 'class', global: true, description: '', tags: [], required: false, - type: 'VNodeRef | undefined', + type: 'unknown', declarations: [], - schema: { - kind: 'enum', - type: 'VNodeRef | undefined', - schema: [ - 'undefined', - 'string', - 'Ref', - { - kind: 'event', - type: '(ref: Element | ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, ComponentOptionsBase, {}, {}> | null, refs: Record<...>): void', - schema: [], - }, - ], - }, + schema: 'unknown', }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { - name: 'ref_for', + name: 'style', type: {}, required: false, description: '', @@ -914,100 +691,23 @@ export const mockExtractComponentPropsReturn = [ }, }, docgenInfo: { - name: 'ref_for', + name: 'style', global: true, description: '', tags: [], required: false, - type: 'boolean | undefined', + type: 'unknown', declarations: [], - schema: { - kind: 'enum', - type: 'boolean | undefined', - schema: ['undefined', 'false', 'true'], - }, + schema: 'unknown', }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { - name: 'ref_key', + name: 'foo', type: {}, - required: false, - description: '', - defaultValue: null, - sbType: { - name: 'other', - }, - }, - docgenInfo: { - name: 'ref_key', - global: true, - description: '', - tags: [], - required: false, - type: 'string | undefined', - declarations: [], - schema: { - kind: 'enum', - type: 'string | undefined', - schema: ['undefined', 'string'], - }, - }, - typeSystem: 'JavaScript', - }, - { - propDef: { - name: 'class', - type: {}, - required: false, - description: '', - defaultValue: null, - sbType: { - name: 'other', - }, - }, - docgenInfo: { - name: 'class', - global: true, - description: '', - tags: [], - required: false, - type: 'unknown', - declarations: [], - schema: 'unknown', - }, - typeSystem: 'JavaScript', - }, - { - propDef: { - name: 'style', - type: {}, - required: false, - description: '', - defaultValue: null, - sbType: { - name: 'other', - }, - }, - docgenInfo: { - name: 'style', - global: true, - description: '', - tags: [], - required: false, - type: 'unknown', - declarations: [], - schema: 'unknown', - }, - typeSystem: 'JavaScript', - }, - { - propDef: { - name: 'foo', - type: {}, - required: true, - description: 'string foo', + required: true, + description: 'string foo', defaultValue: null, sbType: { name: 'other', @@ -1040,7 +740,7 @@ export const mockExtractComponentPropsReturn = [ declarations: [], schema: 'string', }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1067,7 +767,7 @@ export const mockExtractComponentPropsReturn = [ schema: ['false', 'true'], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1094,7 +794,7 @@ export const mockExtractComponentPropsReturn = [ schema: ['string', 'number'], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1121,7 +821,7 @@ export const mockExtractComponentPropsReturn = [ schema: ['undefined', 'string', 'number', 'false', 'true'], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1159,7 +859,7 @@ export const mockExtractComponentPropsReturn = [ }, }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1207,7 +907,7 @@ export const mockExtractComponentPropsReturn = [ }, }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1268,7 +968,7 @@ export const mockExtractComponentPropsReturn = [ ], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1312,7 +1012,7 @@ export const mockExtractComponentPropsReturn = [ ], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1363,7 +1063,7 @@ export const mockExtractComponentPropsReturn = [ ], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1390,7 +1090,7 @@ export const mockExtractComponentPropsReturn = [ schema: ['MyEnum.Small', 'MyEnum.Medium', 'MyEnum.Large'], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1424,7 +1124,7 @@ export const mockExtractComponentPropsReturn = [ ], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1462,7 +1162,7 @@ export const mockExtractComponentPropsReturn = [ }, }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1507,147 +1207,20 @@ export const mockExtractComponentPropsReturn = [ ], }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, ]; -export const referenceTypeEvents = { - __name: 'component', - emits: ['foo', 'bar', 'baz'], - __hmrId: '3a8b03b5', - __file: - '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', +export const referenceTypeEvents: TestComponent = { __docgenInfo: { - exportName: 'default', - displayName: 'component', - props: [ - { - name: 'key', - global: true, - description: '', - tags: [], - required: false, - type: 'string | number | symbol | undefined', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [47082, 47113], - }, - ], - schema: { - kind: 'enum', - type: 'string | number | symbol | undefined', - schema: ['undefined', 'string', 'number', 'symbol'], - }, - }, - { - name: 'ref', - global: true, - description: '', - tags: [], - required: false, - type: 'VNodeRef | undefined', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [47118, 47133], - }, - ], - schema: { - kind: 'enum', - type: 'VNodeRef | undefined', - schema: [ - 'undefined', - 'string', - 'Ref', - { - kind: 'event', - type: '(ref: Element | ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, ComponentOptionsBase, {}, {}> | null, refs: Record<...>): void', - schema: [], - }, - ], - }, - }, - { - name: 'ref_for', - global: true, - description: '', - tags: [], - required: false, - type: 'boolean | undefined', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [47138, 47156], - }, - ], - schema: { - kind: 'enum', - type: 'boolean | undefined', - schema: ['undefined', 'false', 'true'], - }, - }, - { - name: 'ref_key', - global: true, - description: '', - tags: [], - required: false, - type: 'string | undefined', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [47161, 47178], - }, - ], - schema: { - kind: 'enum', - type: 'string | undefined', - schema: ['undefined', 'string'], - }, - }, - { - name: 'class', - global: true, - description: '', - tags: [], - required: false, - type: 'unknown', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [52888, 52904], - }, - ], - schema: 'unknown', - }, - { - name: 'style', - global: true, - description: '', - tags: [], - required: false, - type: 'unknown', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [52909, 52925], - }, - ], - schema: 'unknown', - }, - ], + type: 1, + props: [], events: [ { name: 'foo', type: '[data?: { foo: string; } | undefined]', signature: '(event: "foo", data?: { foo: string; } | undefined): void', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [4468, 4503], - }, - ], + declarations: [], schema: [ { kind: 'enum', @@ -1665,12 +1238,7 @@ export const referenceTypeEvents = { tags: [], required: true, type: 'string', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', - range: [207, 218], - }, - ], + declarations: [], schema: 'string', }, }, @@ -1683,12 +1251,7 @@ export const referenceTypeEvents = { name: 'bar', type: '[value: { year: number; title?: any; }]', signature: '(event: "bar", value: { year: number; title?: any; }): void', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [4468, 4503], - }, - ], + declarations: [], schema: [ { kind: 'object', @@ -1701,12 +1264,7 @@ export const referenceTypeEvents = { tags: [], required: true, type: 'number', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', - range: [255, 268], - }, - ], + declarations: [], schema: 'number', }, title: { @@ -1716,12 +1274,7 @@ export const referenceTypeEvents = { tags: [], required: false, type: 'any', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', - range: [269, 280], - }, - ], + declarations: [], schema: 'any', }, }, @@ -1732,140 +1285,12 @@ export const referenceTypeEvents = { name: 'baz', type: '[]', signature: '(event: "baz"): void', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [4468, 4503], - }, - ], + declarations: [], schema: [], }, ], slots: [], - exposed: [ - { - name: 'onFoo', - type: '((data?: { foo: string; } | undefined) => any) | undefined', - description: '', - declarations: [], - schema: { - kind: 'enum', - type: '((data?: { foo: string; } | undefined) => any) | undefined', - schema: [ - 'undefined', - { - kind: 'event', - type: '(data?: { foo: string; } | undefined): any', - schema: [ - { - kind: 'enum', - type: '{ foo: string; } | undefined', - schema: [ - 'undefined', - { - kind: 'object', - type: '{ foo: string; }', - schema: { - foo: { - name: 'foo', - global: false, - description: '', - tags: [], - required: true, - type: 'string', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', - range: [207, 218], - }, - ], - schema: 'string', - }, - }, - }, - ], - }, - ], - }, - ], - }, - }, - { - name: 'onBar', - type: '((value: { year: number; title?: any; }) => any) | undefined', - description: '', - declarations: [], - schema: { - kind: 'enum', - type: '((value: { year: number; title?: any; }) => any) | undefined', - schema: [ - 'undefined', - { - kind: 'event', - type: '(value: { year: number; title?: any; }): any', - schema: [ - { - kind: 'object', - type: '{ year: number; title?: any; }', - schema: { - year: { - name: 'year', - global: false, - description: '', - tags: [], - required: true, - type: 'number', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', - range: [255, 268], - }, - ], - schema: 'number', - }, - title: { - name: 'title', - global: false, - description: '', - tags: [], - required: false, - type: 'any', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', - range: [269, 280], - }, - ], - schema: 'any', - }, - }, - }, - ], - }, - ], - }, - }, - { - name: 'onBaz', - type: '(() => any) | undefined', - description: '', - declarations: [], - schema: { - kind: 'enum', - type: '(() => any) | undefined', - schema: [ - 'undefined', - { - kind: 'event', - type: '(): any', - schema: [], - }, - ], - }, - }, - ], - sourceFiles: - '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', + exposed: [], }, }; @@ -1883,12 +1308,7 @@ export const mockExtractComponentEventsReturn = [ name: 'foo', type: '[data?: { foo: string; } | undefined]', signature: '(event: "foo", data?: { foo: string; } | undefined): void', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [4468, 4503], - }, - ], + declarations: [], schema: [ { kind: 'enum', @@ -1906,12 +1326,7 @@ export const mockExtractComponentEventsReturn = [ tags: [], required: true, type: 'string', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', - range: [207, 218], - }, - ], + declarations: [], schema: 'string', }, }, @@ -1920,7 +1335,7 @@ export const mockExtractComponentEventsReturn = [ }, ], }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1935,12 +1350,7 @@ export const mockExtractComponentEventsReturn = [ name: 'bar', type: '[value: { year: number; title?: any; }]', signature: '(event: "bar", value: { year: number; title?: any; }): void', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [4468, 4503], - }, - ], + declarations: [], schema: [ { kind: 'object', @@ -1953,12 +1363,7 @@ export const mockExtractComponentEventsReturn = [ tags: [], required: true, type: 'number', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', - range: [255, 268], - }, - ], + declarations: [], schema: 'number', }, title: { @@ -1968,19 +1373,14 @@ export const mockExtractComponentEventsReturn = [ tags: [], required: false, type: 'any', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/reference-type-events/component.vue', - range: [269, 280], - }, - ], + declarations: [], schema: 'any', }, }, }, ], }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -1995,142 +1395,17 @@ export const mockExtractComponentEventsReturn = [ name: 'baz', type: '[]', signature: '(event: "baz"): void', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [4468, 4503], - }, - ], + declarations: [], schema: [], }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, ]; -export const templateSlots = { - __hmrId: 'c8033161', - __file: - '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/template-slots/component.vue', +export const templateSlots: TestComponent = { __docgenInfo: { - exportName: 'default', - displayName: 'component', - props: [ - { - name: 'key', - global: true, - description: '', - tags: [], - required: false, - type: 'string | number | symbol | undefined', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [47082, 47113], - }, - ], - schema: { - kind: 'enum', - type: 'string | number | symbol | undefined', - schema: ['undefined', 'string', 'number', 'symbol'], - }, - }, - { - name: 'ref', - global: true, - description: '', - tags: [], - required: false, - type: 'VNodeRef | undefined', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [47118, 47133], - }, - ], - schema: { - kind: 'enum', - type: 'VNodeRef | undefined', - schema: [ - 'undefined', - 'string', - 'Ref', - { - kind: 'event', - type: '(ref: Element | ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, ComponentOptionsBase, {}, {}> | null, refs: Record<...>): void', - schema: [], - }, - ], - }, - }, - { - name: 'ref_for', - global: true, - description: '', - tags: [], - required: false, - type: 'boolean | undefined', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [47138, 47156], - }, - ], - schema: { - kind: 'enum', - type: 'boolean | undefined', - schema: ['undefined', 'false', 'true'], - }, - }, - { - name: 'ref_key', - global: true, - description: '', - tags: [], - required: false, - type: 'string | undefined', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [47161, 47178], - }, - ], - schema: { - kind: 'enum', - type: 'string | undefined', - schema: ['undefined', 'string'], - }, - }, - { - name: 'class', - global: true, - description: '', - tags: [], - required: false, - type: 'unknown', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [52888, 52904], - }, - ], - schema: 'unknown', - }, - { - name: 'style', - global: true, - description: '', - tags: [], - required: false, - type: 'unknown', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [52909, 52925], - }, - ], - schema: 'unknown', - }, - ], + type: 1, + props: [], events: [], slots: [ { @@ -2204,12 +1479,7 @@ export const templateSlots = { tags: [], required: true, type: 'number', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/template-slots/component.vue', - range: [153, 161], - }, - ], + declarations: [], schema: 'number', }, str: { @@ -2219,123 +1489,14 @@ export const templateSlots = { tags: [], required: true, type: 'string', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/template-slots/component.vue', - range: [163, 173], - }, - ], - schema: 'string', - }, - }, - }, - }, - ], - exposed: [ - { - name: '$slots', - type: 'Readonly & { "no-bind"?(_: {}): any; default?(_: { num: number; }): any; named?(_: { str: string; }): any; vbind?(_: { num: number; str: string; }): any; }', - description: '', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/node_modules/@vue/runtime-core/dist/runtime-core.d.ts', - range: [8406, 8433], - }, - ], - schema: { - kind: 'object', - type: 'Readonly & { "no-bind"?(_: {}): any; default?(_: { num: number; }): any; named?(_: { str: string; }): any; vbind?(_: { num: number; str: string; }): any; }', - schema: { - 'no-bind': { - name: 'no-bind', - global: false, - description: '', - tags: [], - required: false, - type: '((_: {}) => any) | undefined', - declarations: [], - schema: { - kind: 'enum', - type: '((_: {}) => any) | undefined', - schema: [ - 'undefined', - { - kind: 'event', - type: '(_: {}): any', - schema: [], - }, - ], - }, - }, - default: { - name: 'default', - global: false, - description: '', - tags: [], - required: false, - type: '((_: { num: number; }) => any) | undefined', - declarations: [], - schema: { - kind: 'enum', - type: '((_: { num: number; }) => any) | undefined', - schema: [ - 'undefined', - { - kind: 'event', - type: '(_: { num: number; }): any', - schema: [], - }, - ], - }, - }, - named: { - name: 'named', - global: false, - description: '', - tags: [], - required: false, - type: '((_: { str: string; }) => any) | undefined', - declarations: [], - schema: { - kind: 'enum', - type: '((_: { str: string; }) => any) | undefined', - schema: [ - 'undefined', - { - kind: 'event', - type: '(_: { str: string; }): any', - schema: [], - }, - ], - }, - }, - vbind: { - name: 'vbind', - global: false, - description: '', - tags: [], - required: false, - type: '((_: { num: number; str: string; }) => any) | undefined', declarations: [], - schema: { - kind: 'enum', - type: '((_: { num: number; str: string; }) => any) | undefined', - schema: [ - 'undefined', - { - kind: 'event', - type: '(_: { num: number; str: string; }): any', - schema: [], - }, - ], - }, + schema: 'string', }, }, }, }, ], - sourceFiles: - '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/template-slots/component.vue', + exposed: [], }, }; @@ -2361,7 +1522,7 @@ export const mockExtractComponentSlotsReturn = [ schema: {}, }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -2395,7 +1556,7 @@ export const mockExtractComponentSlotsReturn = [ }, }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -2429,7 +1590,7 @@ export const mockExtractComponentSlotsReturn = [ }, }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, { propDef: { @@ -2457,12 +1618,7 @@ export const mockExtractComponentSlotsReturn = [ tags: [], required: true, type: 'number', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/template-slots/component.vue', - range: [153, 161], - }, - ], + declarations: [], schema: 'number', }, str: { @@ -2472,17 +1628,987 @@ export const mockExtractComponentSlotsReturn = [ tags: [], required: true, type: 'string', - declarations: [ - { - file: '/storybook/sandbox/vue3-vite-default-ts/src/stories/renderers/vue3/component-meta/template-slots/component.vue', - range: [163, 173], - }, - ], + declarations: [], schema: 'string', }, }, }, }, - typeSystem: 'JavaScript', + typeSystem: TypeSystem.JAVASCRIPT, }, ]; + +export const vueDocgenMocks = { + props: { + component: { + __docgenInfo: { + description: '', + tags: {}, + props: [ + { + name: 'foo', + description: 'string foo', + tags: { + default: [ + { + description: '"rounded"', + title: 'default', + }, + ], + since: [ + { + description: 'v1.0.0', + title: 'since', + }, + ], + see: [ + { + description: 'https://vuejs.org/', + title: 'see', + }, + ], + deprecated: [ + { + description: 'v1.1.0', + title: 'deprecated', + }, + ], + }, + required: true, + type: { + name: 'string', + }, + }, + { + name: 'bar', + description: 'description bar is optional number', + required: false, + type: { + name: 'number', + }, + defaultValue: { + func: false, + value: '1', + }, + }, + { + name: 'baz', + description: 'description baz is required boolean', + required: true, + type: { + name: 'boolean', + }, + }, + { + name: 'stringArray', + description: 'description stringArray is string array', + required: false, + type: { + name: 'Array', + elements: [ + { + name: 'string', + }, + ], + }, + defaultValue: { + func: false, + value: "() => ['foo', 'bar']", + }, + }, + { + name: 'union', + description: 'description union is required union type', + required: true, + type: { + name: 'union', + elements: [ + { + name: 'string', + }, + { + name: 'number', + }, + ], + }, + }, + { + name: 'unionOptional', + description: 'description unionOptional is optional union type', + required: false, + type: { + name: 'union', + elements: [ + { + name: 'string', + }, + { + name: 'number', + }, + { + name: 'boolean', + }, + ], + }, + }, + { + name: 'nested', + description: 'description nested is required nested object', + required: true, + type: { + name: 'MyNestedProps', + }, + }, + { + name: 'nestedIntersection', + description: 'description required nested object with intersection', + required: true, + type: { + name: 'intersection', + elements: [ + { + name: 'MyNestedProps', + }, + { + name: '{\n /**\n * description required additional property\n */\n additionalProp: string;\n}', + }, + ], + }, + }, + { + name: 'nestedOptional', + description: 'description optional nested object', + required: false, + type: { + name: 'union', + elements: [ + { + name: 'MyNestedProps', + }, + { + name: 'MyIgnoredNestedProps', + }, + ], + }, + }, + { + name: 'array', + description: 'description required array object', + required: true, + type: { + name: 'Array', + elements: [ + { + name: 'MyNestedProps', + }, + ], + }, + }, + { + name: 'arrayOptional', + description: 'description optional array object', + required: false, + type: { + name: 'Array', + elements: [ + { + name: 'MyNestedProps', + }, + ], + }, + }, + { + name: 'enumValue', + description: 'description enum value', + required: true, + type: { + name: 'MyEnum', + }, + }, + { + name: 'literalFromContext', + description: 'description literal type alias that require context', + required: true, + type: { + name: 'MyCategories', + }, + }, + { + name: 'inlined', + required: true, + type: { + name: '{ foo: string }', + }, + }, + { + name: 'recursive', + required: false, + type: { + name: 'MyNestedRecursiveProps', + }, + }, + ], + }, + }, + extractedProps: [ + { + propDef: { + name: 'foo', + type: { + summary: 'string', + }, + required: true, + description: 'string foo', + defaultValue: null, + sbType: { + name: 'string', + }, + }, + docgenInfo: { + name: 'foo', + description: 'string foo', + tags: { + default: [ + { + description: '"rounded"', + title: 'default', + }, + ], + since: [ + { + description: 'v1.0.0', + title: 'since', + }, + ], + see: [ + { + description: 'https://vuejs.org/', + title: 'see', + }, + ], + deprecated: [ + { + description: 'v1.1.0', + title: 'deprecated', + }, + ], + }, + required: true, + type: { + name: 'string', + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'bar', + type: { + summary: 'number', + }, + required: false, + description: 'description bar is optional number', + defaultValue: { + summary: '1', + }, + sbType: { + name: 'number', + }, + }, + docgenInfo: { + name: 'bar', + description: 'description bar is optional number', + required: false, + type: { + name: 'number', + }, + defaultValue: { + func: false, + value: '1', + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'baz', + type: { + summary: 'boolean', + }, + required: true, + description: 'description baz is required boolean', + defaultValue: null, + sbType: { + name: 'boolean', + }, + }, + docgenInfo: { + name: 'baz', + description: 'description baz is required boolean', + required: true, + type: { + name: 'boolean', + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'stringArray', + type: { + summary: 'Array', + }, + required: false, + description: 'description stringArray is string array', + defaultValue: { + summary: "() => ['foo', 'bar']", + }, + sbType: { + name: 'other', + value: 'Array([object Object])', + }, + }, + docgenInfo: { + name: 'stringArray', + description: 'description stringArray is string array', + required: false, + type: { + name: 'Array', + elements: [ + { + name: 'string', + }, + ], + value: [ + { + name: 'string', + }, + ], + }, + defaultValue: { + func: false, + value: "() => ['foo', 'bar']", + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'union', + type: { + summary: 'union', + }, + required: true, + description: 'description union is required union type', + defaultValue: null, + sbType: { + name: 'union', + value: [ + { + name: 'string', + }, + { + name: 'number', + }, + ], + }, + }, + docgenInfo: { + name: 'union', + description: 'description union is required union type', + required: true, + type: { + name: 'union', + elements: [ + { + name: 'string', + }, + { + name: 'number', + }, + ], + value: [ + { + name: 'string', + }, + { + name: 'number', + }, + ], + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'unionOptional', + type: { + summary: 'union', + }, + required: false, + description: 'description unionOptional is optional union type', + defaultValue: null, + sbType: { + name: 'union', + value: [ + { + name: 'string', + }, + { + name: 'number', + }, + { + name: 'boolean', + }, + ], + }, + }, + docgenInfo: { + name: 'unionOptional', + description: 'description unionOptional is optional union type', + required: false, + type: { + name: 'union', + elements: [ + { + name: 'string', + }, + { + name: 'number', + }, + { + name: 'boolean', + }, + ], + value: [ + { + name: 'string', + }, + { + name: 'number', + }, + { + name: 'boolean', + }, + ], + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'nested', + type: { + summary: 'MyNestedProps', + }, + required: true, + description: 'description nested is required nested object', + defaultValue: null, + sbType: { + name: 'other', + value: 'MyNestedProps', + }, + }, + docgenInfo: { + name: 'nested', + description: 'description nested is required nested object', + required: true, + type: { + name: 'MyNestedProps', + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'nestedIntersection', + type: { + summary: 'intersection', + }, + required: true, + description: 'description required nested object with intersection', + defaultValue: null, + sbType: { + name: 'other', + value: 'intersection([object Object],[object Object])', + }, + }, + docgenInfo: { + name: 'nestedIntersection', + description: 'description required nested object with intersection', + required: true, + type: { + name: 'intersection', + elements: [ + { + name: 'MyNestedProps', + }, + { + name: '{\n /**\n * description required additional property\n */\n additionalProp: string;\n}', + }, + ], + value: [ + { + name: 'MyNestedProps', + }, + { + name: '{\n /**\n * description required additional property\n */\n additionalProp: string;\n}', + }, + ], + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'nestedOptional', + type: { + summary: 'union', + }, + required: false, + description: 'description optional nested object', + defaultValue: null, + sbType: { + name: 'union', + value: [ + { + name: 'other', + value: 'MyNestedProps', + }, + { + name: 'other', + value: 'MyIgnoredNestedProps', + }, + ], + }, + }, + docgenInfo: { + name: 'nestedOptional', + description: 'description optional nested object', + required: false, + type: { + name: 'union', + elements: [ + { + name: 'MyNestedProps', + }, + { + name: 'MyIgnoredNestedProps', + }, + ], + value: [ + { + name: 'MyNestedProps', + }, + { + name: 'MyIgnoredNestedProps', + }, + ], + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'array', + type: { + summary: 'Array', + }, + required: true, + description: 'description required array object', + defaultValue: null, + sbType: { + name: 'other', + value: 'Array([object Object])', + }, + }, + docgenInfo: { + name: 'array', + description: 'description required array object', + required: true, + type: { + name: 'Array', + elements: [ + { + name: 'MyNestedProps', + }, + ], + value: [ + { + name: 'MyNestedProps', + }, + ], + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'arrayOptional', + type: { + summary: 'Array', + }, + required: false, + description: 'description optional array object', + defaultValue: null, + sbType: { + name: 'other', + value: 'Array([object Object])', + }, + }, + docgenInfo: { + name: 'arrayOptional', + description: 'description optional array object', + required: false, + type: { + name: 'Array', + elements: [ + { + name: 'MyNestedProps', + }, + ], + value: [ + { + name: 'MyNestedProps', + }, + ], + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'enumValue', + type: { + summary: 'MyEnum', + }, + required: true, + description: 'description enum value', + defaultValue: null, + sbType: { + name: 'other', + value: 'MyEnum', + }, + }, + docgenInfo: { + name: 'enumValue', + description: 'description enum value', + required: true, + type: { + name: 'MyEnum', + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'literalFromContext', + type: { + summary: 'MyCategories', + }, + required: true, + description: 'description literal type alias that require context', + defaultValue: null, + sbType: { + name: 'other', + value: 'MyCategories', + }, + }, + docgenInfo: { + name: 'literalFromContext', + description: 'description literal type alias that require context', + required: true, + type: { + name: 'MyCategories', + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'inlined', + type: { + summary: '{ foo: string }', + }, + required: true, + defaultValue: null, + sbType: { + name: 'other', + value: '{ foo: string }', + }, + }, + docgenInfo: { + name: 'inlined', + required: true, + type: { + name: '{ foo: string }', + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'recursive', + type: { + summary: 'MyNestedRecursiveProps', + }, + required: false, + defaultValue: null, + sbType: { + name: 'other', + value: 'MyNestedRecursiveProps', + }, + }, + docgenInfo: { + name: 'recursive', + required: false, + type: { + name: 'MyNestedRecursiveProps', + }, + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + ], + }, + events: { + component: { + __docgenInfo: { + exportName: 'default', + displayName: 'component', + description: '', + tags: {}, + events: [ + { + name: 'bar', + type: { + names: ['{ year: number; title?: any }'], + }, + description: 'Test description bar', + }, + { + name: 'baz', + description: 'Test description baz', + }, + ], + }, + }, + extractedProps: [ + { + propDef: { + name: 'bar', + type: {}, + description: 'Test description bar', + defaultValue: null, + sbType: { + name: 'other', + }, + }, + docgenInfo: { + name: 'bar', + type: { + names: ['{ year: number; title?: any }'], + }, + description: 'Test description bar', + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + { + propDef: { + name: 'baz', + type: null, + description: 'Test description baz', + defaultValue: null, + sbType: null, + }, + docgenInfo: { + name: 'baz', + description: 'Test description baz', + }, + typeSystem: TypeSystem.JAVASCRIPT, + }, + ], + }, + slots: { + component: { + __docgenInfo: { + displayName: 'component', + exportName: 'default', + description: '', + tags: {}, + slots: [ + { + name: 'no-bind', + }, + { + name: 'default', + scoped: true, + bindings: [ + { + name: 'num', + title: 'binding', + }, + ], + }, + { + name: 'named', + scoped: true, + bindings: [ + { + name: 'str', + title: 'binding', + }, + ], + }, + { + name: 'vbind', + scoped: true, + bindings: [ + { + name: 'num', + title: 'binding', + }, + { + name: 'str', + title: 'binding', + }, + ], + }, + ], + }, + }, + extractedProps: [ + { + propDef: { + name: 'no-bind', + type: { + summary: 'unknown', + }, + defaultValue: null, + }, + docgenInfo: { + name: 'no-bind', + }, + typeSystem: TypeSystem.UNKNOWN, + }, + { + propDef: { + name: 'default', + type: { + summary: 'unknown', + }, + defaultValue: null, + }, + docgenInfo: { + name: 'default', + scoped: true, + bindings: [ + { + name: 'num', + title: 'binding', + }, + ], + }, + typeSystem: TypeSystem.UNKNOWN, + }, + { + propDef: { + name: 'named', + type: { + summary: 'unknown', + }, + defaultValue: null, + }, + docgenInfo: { + name: 'named', + scoped: true, + bindings: [ + { + name: 'str', + title: 'binding', + }, + ], + }, + typeSystem: TypeSystem.UNKNOWN, + }, + { + propDef: { + name: 'vbind', + type: { + summary: 'unknown', + }, + defaultValue: null, + }, + docgenInfo: { + name: 'vbind', + scoped: true, + bindings: [ + { + name: 'num', + title: 'binding', + }, + { + name: 'str', + title: 'binding', + }, + ], + }, + typeSystem: TypeSystem.UNKNOWN, + }, + ], + }, + expose: { + component: { + __docgenInfo: { + exportName: 'default', + displayName: 'component', + description: '', + tags: {}, + expose: [ + { + name: 'label', + description: 'a label string', + }, + { + name: 'count', + description: 'a count number', + }, + ], + }, + }, + extractedProps: [ + { + propDef: { + name: 'label', + type: { + summary: 'unknown', + }, + description: 'a label string', + defaultValue: null, + }, + docgenInfo: { + name: 'label', + description: 'a label string', + }, + typeSystem: TypeSystem.UNKNOWN, + }, + { + propDef: { + name: 'count', + type: { + summary: 'unknown', + }, + description: 'a count number', + defaultValue: null, + }, + docgenInfo: { + name: 'count', + description: 'a count number', + }, + typeSystem: TypeSystem.UNKNOWN, + }, + ], + }, +} satisfies Record< + string, + { component: { __docgenInfo: VueDocgenInfo<'vue-docgen-api'> }; extractedProps: ExtractedProp[] } +>; From 390888239bc6aa99b0d646ad9c5066b7c3e8368c Mon Sep 17 00:00:00 2001 From: Lars Rickert Date: Fri, 23 Feb 2024 23:34:27 +0100 Subject: [PATCH 2/6] fix slot type separator --- .../vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap | 4 ++-- code/renderers/vue3/src/docs/extractArgTypes.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap b/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap index 6df158abb06c..aa8863e3c1c6 100644 --- a/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap +++ b/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap @@ -490,13 +490,13 @@ exports[`extractArgTypes (vue-docgen-api) > should extract slots for component 1 "defaultValue": null, "jsDocTags": undefined, "type": { - "summary": "{ num: unknown, str: unknown }", + "summary": "{ num: unknown; str: unknown }", }, }, "type": { "name": "other", "required": false, - "value": "{ num: unknown, str: unknown }", + "value": "{ num: unknown; str: unknown }", }, }, } diff --git a/code/renderers/vue3/src/docs/extractArgTypes.ts b/code/renderers/vue3/src/docs/extractArgTypes.ts index a5e8d516dfb1..3522ee7915a4 100644 --- a/code/renderers/vue3/src/docs/extractArgTypes.ts +++ b/code/renderers/vue3/src/docs/extractArgTypes.ts @@ -81,7 +81,7 @@ export const extractFromVueDocgenApi = ( .map((binding) => { return `${binding.name}: ${binding.type?.name ?? 'unknown'}`; }) - .join(', '); + .join('; '); type = slotParams ? `{ ${slotParams} }` : undefined; sbType = { name: 'other', value: type ?? '', required: false }; From 1fb5c28ff9f848c7bbde23b69e1398e498200f35 Mon Sep 17 00:00:00 2001 From: Lars Rickert Date: Fri, 23 Feb 2024 23:47:51 +0100 Subject: [PATCH 3/6] update docs --- .../vue3/src/docs/extractArgTypes.ts | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/code/renderers/vue3/src/docs/extractArgTypes.ts b/code/renderers/vue3/src/docs/extractArgTypes.ts index 3522ee7915a4..6ac705a118f0 100644 --- a/code/renderers/vue3/src/docs/extractArgTypes.ts +++ b/code/renderers/vue3/src/docs/extractArgTypes.ts @@ -31,8 +31,7 @@ export const extractArgTypes: ArgTypesExtractor = (component) => { let argType: StrictInputType | undefined; if (usedDocgenPlugin === 'vue-docgen-api') { - const docgenInfo = - extractedProp.docgenInfo as unknown as VueDocgenInfoEntry<'vue-docgen-api'>; + const docgenInfo = extractedProp.docgenInfo as VueDocgenInfoEntry<'vue-docgen-api'>; argType = extractFromVueDocgenApi(docgenInfo, section, extractedProp); } else { const docgenInfo = @@ -76,14 +75,15 @@ export const extractFromVueDocgenApi = ( if (section === 'slots') { const slotInfo = docgenInfo as VueDocgenInfoEntry<'vue-docgen-api', 'slots'>; - const slotParams = slotInfo.bindings + // extract type of slot bindings/props + const slotBindings = slotInfo.bindings ?.filter((binding) => !!binding.name) .map((binding) => { return `${binding.name}: ${binding.type?.name ?? 'unknown'}`; }) .join('; '); - type = slotParams ? `{ ${slotParams} }` : undefined; + type = slotBindings ? `{ ${slotBindings} }` : undefined; sbType = { name: 'other', value: type ?? '', required: false }; } @@ -94,6 +94,7 @@ export const extractFromVueDocgenApi = ( sbType = extractedProp ? convert(extractedProp.docgenInfo) : { name: 'other', value: type }; // try to get more specific types for array, union and intersection + // e.g. "string[]" instead of "Array" if ( propInfo.type && 'elements' in propInfo.type && @@ -107,25 +108,17 @@ export const extractFromVueDocgenApi = ( type = `${arrayElements}[]`; } - if (type === 'union') { - type = elements.join(' | '); - } - - if (type === 'intersection') { - type = elements.join(' & '); - } + if (type === 'union') type = elements.join(' | '); + else if (type === 'intersection') type = elements.join(' & '); } } + const required = 'required' in docgenInfo ? docgenInfo.required ?? false : false; + return { name: docgenInfo.name, description: docgenInfo.description, - type: sbType - ? { - ...sbType, - required: 'required' in docgenInfo ? docgenInfo.required ?? false : false, - } - : { name: 'other', value: type ?? '' }, + type: sbType ? { ...sbType, required } : { name: 'other', value: type ?? '' }, table: { type: type ? { summary: type } : undefined, defaultValue: extractedProp?.propDef.defaultValue, @@ -145,6 +138,7 @@ export const extractFromVueComponentMeta = ( docgenInfo: VueDocgenInfoEntry<'vue-component-meta'>, section: (typeof ARG_TYPE_SECTIONS)[number] ): StrictInputType | undefined => { + // ignore global props if ('global' in docgenInfo && docgenInfo.global) return; const tableType = { summary: docgenInfo.type.replace(' | undefined', '') }; @@ -157,7 +151,7 @@ export const extractFromVueComponentMeta = ( name: propInfo.name, description: formatDescriptionWithTags(propInfo.description, propInfo.tags), defaultValue, - type: getStorybookTypeFromVueComponentMeta(propInfo), + type: convertVueComponentMetaProp(propInfo), table: { type: tableType, defaultValue, @@ -169,10 +163,7 @@ export const extractFromVueComponentMeta = ( name: docgenInfo.name, description: 'description' in docgenInfo ? docgenInfo.description : '', type: { name: 'other', value: docgenInfo.type }, - table: { - type: tableType, - category: section, - }, + table: { type: tableType, category: section }, }; } }; @@ -180,7 +171,7 @@ export const extractFromVueComponentMeta = ( /** * Converts the given prop info that was generated with "vue-component-meta" into a SBType. */ -export const getStorybookTypeFromVueComponentMeta = ( +export const convertVueComponentMetaProp = ( propInfo: Pick, 'schema' | 'required' | 'type'> ): SBType => { const schema = propInfo.schema; @@ -213,7 +204,7 @@ export const getStorybookTypeFromVueComponentMeta = ( } if (definedSchemas.length === 1) { - return getStorybookTypeFromVueComponentMeta({ + return convertVueComponentMetaProp({ schema: definedSchemas[0], type: propInfo.type, required, @@ -236,13 +227,13 @@ export const getStorybookTypeFromVueComponentMeta = ( name: 'union', value: definedSchemas.map((i) => { if (typeof i === 'object') { - return getStorybookTypeFromVueComponentMeta({ + return convertVueComponentMetaProp({ schema: i, type: i.type, required: false, }); } else { - return getStorybookTypeFromVueComponentMeta({ schema: i, type: i, required: false }); + return convertVueComponentMetaProp({ schema: i, type: i, required: false }); } }), required, @@ -257,7 +248,7 @@ export const getStorybookTypeFromVueComponentMeta = ( if (definedSchemas.length === 1) { return { name: 'array', - value: getStorybookTypeFromVueComponentMeta({ + value: convertVueComponentMetaProp({ schema: definedSchemas[0], type: propInfo.type, required: false, @@ -270,13 +261,13 @@ export const getStorybookTypeFromVueComponentMeta = ( name: 'union', value: definedSchemas.map((i) => { if (typeof i === 'object') { - return getStorybookTypeFromVueComponentMeta({ + return convertVueComponentMetaProp({ schema: i, type: i.type, required: false, }); } else { - return getStorybookTypeFromVueComponentMeta({ schema: i, type: i, required: false }); + return convertVueComponentMetaProp({ schema: i, type: i, required: false }); } }), required, @@ -288,7 +279,7 @@ export const getStorybookTypeFromVueComponentMeta = ( name: 'object', value: Object.entries(schema.schema ?? {}).reduce>( (obj, [propName, propSchema]) => { - obj[propName] = getStorybookTypeFromVueComponentMeta(propSchema); + obj[propName] = convertVueComponentMetaProp(propSchema); return obj; }, {} From 926e1be5e03e59bcb5adcb68c0d63b6bcb46399a Mon Sep 17 00:00:00 2001 From: Lars Rickert Date: Sat, 24 Feb 2024 00:11:31 +0100 Subject: [PATCH 4/6] update docs --- code/renderers/vue3/src/docs/extractArgTypes.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/code/renderers/vue3/src/docs/extractArgTypes.ts b/code/renderers/vue3/src/docs/extractArgTypes.ts index 6ac705a118f0..151476491c95 100644 --- a/code/renderers/vue3/src/docs/extractArgTypes.ts +++ b/code/renderers/vue3/src/docs/extractArgTypes.ts @@ -30,6 +30,8 @@ export const extractArgTypes: ArgTypesExtractor = (component) => { props.forEach((extractedProp) => { let argType: StrictInputType | undefined; + // use the corresponding extractor whether vue-docgen-api or vue-component-meta + // was used for the docinfo if (usedDocgenPlugin === 'vue-docgen-api') { const docgenInfo = extractedProp.docgenInfo as VueDocgenInfoEntry<'vue-docgen-api'>; argType = extractFromVueDocgenApi(docgenInfo, section, extractedProp); @@ -41,6 +43,7 @@ export const extractArgTypes: ArgTypesExtractor = (component) => { // skip duplicate and global props if (!argType || argTypes[argType.name]) return; + argTypes[argType.name] = { ...argType, control: { disabled: !['props', 'slots'].includes(section) }, @@ -223,6 +226,7 @@ export const convertVueComponentMetaProp = ( definedSchemas.push('boolean'); } + // recursively convert every type of the union return { name: 'union', value: definedSchemas.map((i) => { @@ -257,6 +261,8 @@ export const convertVueComponentMetaProp = ( }; } + // recursively convert every type of the array + // e.g. "(string | number)[]" return { name: 'union', value: definedSchemas.map((i) => { @@ -274,6 +280,7 @@ export const convertVueComponentMetaProp = ( }; } + // recursively/deeply convert all properties of the object case 'object': return { name: 'object', From 49b0e9d366837d86060dfa5447976e6d828686af Mon Sep 17 00:00:00 2001 From: Lars Rickert Date: Sat, 24 Feb 2024 00:15:14 +0100 Subject: [PATCH 5/6] fix type issues for mock data --- .../vue3/src/docs/tests-meta-components/meta-components.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/renderers/vue3/src/docs/tests-meta-components/meta-components.ts b/code/renderers/vue3/src/docs/tests-meta-components/meta-components.ts index 043244a8fd3b..ad10ccc96a52 100644 --- a/code/renderers/vue3/src/docs/tests-meta-components/meta-components.ts +++ b/code/renderers/vue3/src/docs/tests-meta-components/meta-components.ts @@ -1,4 +1,3 @@ -import type { ExtractedProp } from '@storybook/docs-tools'; import { TypeSystem } from '@storybook/docs-tools'; import type { VueDocgenInfo } from 'frameworks/vue3-vite/src'; @@ -2608,7 +2607,4 @@ export const vueDocgenMocks = { }, ], }, -} satisfies Record< - string, - { component: { __docgenInfo: VueDocgenInfo<'vue-docgen-api'> }; extractedProps: ExtractedProp[] } ->; +}; From 10d6d072952abe10aa72a783e2fd3de296ffd3fc Mon Sep 17 00:00:00 2001 From: Lars Rickert Date: Sat, 24 Feb 2024 00:25:38 +0100 Subject: [PATCH 6/6] move inline snapshot to file snaptshot --- .../extractArgTypes.test.ts.snap | 524 ++++++++++++++++-- .../vue3/src/docs/extractArgTypes.test.ts | 412 +------------- 2 files changed, 469 insertions(+), 467 deletions(-) diff --git a/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap b/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap index aa8863e3c1c6..cbdcb9f51226 100644 --- a/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap +++ b/code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap @@ -1,5 +1,61 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`extractArgTypes (vue-docgen-api) > should extract events for Vue component 1`] = ` +{ + "bar": { + "control": { + "disabled": true, + }, + "description": "", + "name": "bar", + "table": { + "category": "events", + "type": { + "summary": "[value: { year: number; title?: any; }]", + }, + }, + "type": { + "name": "other", + "value": "[value: { year: number; title?: any; }]", + }, + }, + "baz": { + "control": { + "disabled": true, + }, + "description": "", + "name": "baz", + "table": { + "category": "events", + "type": { + "summary": "[]", + }, + }, + "type": { + "name": "other", + "value": "[]", + }, + }, + "foo": { + "control": { + "disabled": true, + }, + "description": "", + "name": "foo", + "table": { + "category": "events", + "type": { + "summary": "[data?: { foo: string; }]", + }, + }, + "type": { + "name": "other", + "value": "[data?: { foo: string; } | undefined]", + }, + }, +} +`; + exports[`extractArgTypes (vue-docgen-api) > should extract events for component 1`] = ` { "bar": { @@ -83,6 +139,416 @@ exports[`extractArgTypes (vue-docgen-api) > should extract expose for component `; exports[`extractArgTypes (vue-docgen-api) > should extract props for component 1`] = ` +{ + "array": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description required array object", + "name": "array", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "MyNestedProps[]", + }, + }, + "type": { + "name": "array", + "required": true, + "value": { + "name": "object", + "required": false, + "value": { + "nestedProp": { + "name": "string", + "required": true, + }, + }, + }, + }, + }, + "arrayOptional": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description optional array object", + "name": "arrayOptional", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "MyNestedProps[]", + }, + }, + "type": { + "name": "array", + "required": false, + "value": { + "name": "object", + "required": false, + "value": { + "nestedProp": { + "name": "string", + "required": true, + }, + }, + }, + }, + }, + "bar": { + "control": { + "disabled": false, + }, + "defaultValue": { + "summary": "1", + }, + "description": "description bar is optional number", + "name": "bar", + "table": { + "category": "props", + "defaultValue": { + "summary": "1", + }, + "type": { + "summary": "number", + }, + }, + "type": { + "name": "number", + "required": false, + }, + }, + "baz": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description baz is required boolean", + "name": "baz", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "boolean", + }, + }, + "type": { + "name": "boolean", + "required": true, + }, + }, + "enumValue": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description enum value", + "name": "enumValue", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "MyEnum", + }, + }, + "type": { + "name": "enum", + "required": true, + "value": [ + "MyEnum.Small", + "MyEnum.Medium", + "MyEnum.Large", + ], + }, + }, + "foo": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "@default: "rounded"
@since: v1.0.0
@see: https://vuejs.org/
@deprecated: v1.1.0

string foo", + "name": "foo", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "string", + }, + }, + "type": { + "name": "string", + "required": true, + }, + }, + "inlined": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "", + "name": "inlined", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "{ foo: string; }", + }, + }, + "type": { + "name": "object", + "required": true, + "value": { + "foo": { + "name": "string", + "required": true, + }, + }, + }, + }, + "literalFromContext": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description literal type alias that require context", + "name": "literalFromContext", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": ""Uncategorized" | "Content" | "Interaction" | "Display" | "Forms" | "Addons"", + }, + }, + "type": { + "name": "enum", + "required": true, + "value": [ + "Uncategorized", + "Content", + "Interaction", + "Display", + "Forms", + "Addons", + ], + }, + }, + "nested": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description nested is required nested object", + "name": "nested", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "MyNestedProps", + }, + }, + "type": { + "name": "object", + "required": true, + "value": { + "nestedProp": { + "name": "string", + "required": true, + }, + }, + }, + }, + "nestedIntersection": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description required nested object with intersection", + "name": "nestedIntersection", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "MyNestedProps & { additionalProp: string; }", + }, + }, + "type": { + "name": "object", + "required": true, + "value": { + "additionalProp": { + "name": "string", + "required": true, + }, + "nestedProp": { + "name": "string", + "required": true, + }, + }, + }, + }, + "nestedOptional": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description optional nested object", + "name": "nestedOptional", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "MyNestedProps | MyIgnoredNestedProps", + }, + }, + "type": { + "name": "union", + "required": false, + "value": [ + { + "name": "object", + "required": false, + "value": { + "nestedProp": { + "name": "string", + "required": true, + }, + }, + }, + { + "name": "object", + "required": false, + "value": { + "nestedProp": { + "name": "string", + "required": true, + }, + }, + }, + ], + }, + }, + "recursive": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "", + "name": "recursive", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "MyNestedRecursiveProps", + }, + }, + "type": { + "name": "object", + "required": false, + "value": { + "recursive": { + "name": "other", + "required": true, + "value": "MyNestedRecursiveProps", + }, + }, + }, + }, + "stringArray": { + "control": { + "disabled": false, + }, + "defaultValue": { + "summary": "["foo", "bar"]", + }, + "description": "description stringArray is string array", + "name": "stringArray", + "table": { + "category": "props", + "defaultValue": { + "summary": "["foo", "bar"]", + }, + "type": { + "summary": "string[]", + }, + }, + "type": { + "name": "array", + "required": false, + "value": { + "name": "string", + "required": false, + }, + }, + }, + "union": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description union is required union type", + "name": "union", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "string | number", + }, + }, + "type": { + "name": "union", + "required": true, + "value": [ + { + "name": "string", + "required": false, + }, + { + "name": "number", + "required": false, + }, + ], + }, + }, + "unionOptional": { + "control": { + "disabled": false, + }, + "defaultValue": undefined, + "description": "description unionOptional is optional union type", + "name": "unionOptional", + "table": { + "category": "props", + "defaultValue": undefined, + "type": { + "summary": "string | number | boolean", + }, + }, + "type": { + "name": "union", + "required": false, + "value": [ + { + "name": "string", + "required": false, + }, + { + "name": "number", + "required": false, + }, + { + "name": "boolean", + "required": false, + }, + ], + }, + }, +} +`; + +exports[`extractArgTypes (vue-docgen-api) > should extract props for component 2`] = ` { "array": { "control": { @@ -502,63 +968,7 @@ exports[`extractArgTypes (vue-docgen-api) > should extract slots for component 1 } `; -exports[`extractArgTypes > should extract events for Vue component 1`] = ` -{ - "bar": { - "control": { - "disabled": true, - }, - "description": "", - "name": "bar", - "table": { - "category": "events", - "type": { - "summary": "[value: { year: number; title?: any; }]", - }, - }, - "type": { - "name": "other", - "value": "[value: { year: number; title?: any; }]", - }, - }, - "baz": { - "control": { - "disabled": true, - }, - "description": "", - "name": "baz", - "table": { - "category": "events", - "type": { - "summary": "[]", - }, - }, - "type": { - "name": "other", - "value": "[]", - }, - }, - "foo": { - "control": { - "disabled": true, - }, - "description": "", - "name": "foo", - "table": { - "category": "events", - "type": { - "summary": "[data?: { foo: string; }]", - }, - }, - "type": { - "name": "other", - "value": "[data?: { foo: string; } | undefined]", - }, - }, -} -`; - -exports[`extractArgTypes > should extract slots type for Vue component 1`] = ` +exports[`extractArgTypes (vue-docgen-api) > should extract slots type for Vue component 1`] = ` { "default": { "control": { diff --git a/code/renderers/vue3/src/docs/extractArgTypes.test.ts b/code/renderers/vue3/src/docs/extractArgTypes.test.ts index 118e5273bb65..053266882e87 100644 --- a/code/renderers/vue3/src/docs/extractArgTypes.test.ts +++ b/code/renderers/vue3/src/docs/extractArgTypes.test.ts @@ -21,7 +21,7 @@ vitest.mock('@storybook/docs-tools', async (importOriginal) => { }; }); -describe('extractArgTypes', () => { +describe('extractArgTypes (vue-docgen-api)', () => { beforeEach(() => { vi.resetAllMocks(); }); @@ -43,415 +43,7 @@ describe('extractArgTypes', () => { const argTypes = extractArgTypes(component); - expect(argTypes).toMatchInlineSnapshot(` - { - "array": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description required array object", - "name": "array", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "MyNestedProps[]", - }, - }, - "type": { - "name": "array", - "required": true, - "value": { - "name": "object", - "required": false, - "value": { - "nestedProp": { - "name": "string", - "required": true, - }, - }, - }, - }, - }, - "arrayOptional": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description optional array object", - "name": "arrayOptional", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "MyNestedProps[]", - }, - }, - "type": { - "name": "array", - "required": false, - "value": { - "name": "object", - "required": false, - "value": { - "nestedProp": { - "name": "string", - "required": true, - }, - }, - }, - }, - }, - "bar": { - "control": { - "disabled": false, - }, - "defaultValue": { - "summary": "1", - }, - "description": "description bar is optional number", - "name": "bar", - "table": { - "category": "props", - "defaultValue": { - "summary": "1", - }, - "type": { - "summary": "number", - }, - }, - "type": { - "name": "number", - "required": false, - }, - }, - "baz": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description baz is required boolean", - "name": "baz", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "boolean", - }, - }, - "type": { - "name": "boolean", - "required": true, - }, - }, - "enumValue": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description enum value", - "name": "enumValue", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "MyEnum", - }, - }, - "type": { - "name": "enum", - "required": true, - "value": [ - "MyEnum.Small", - "MyEnum.Medium", - "MyEnum.Large", - ], - }, - }, - "foo": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "@default: "rounded"
@since: v1.0.0
@see: https://vuejs.org/
@deprecated: v1.1.0

string foo", - "name": "foo", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "string", - }, - }, - "type": { - "name": "string", - "required": true, - }, - }, - "inlined": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "", - "name": "inlined", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "{ foo: string; }", - }, - }, - "type": { - "name": "object", - "required": true, - "value": { - "foo": { - "name": "string", - "required": true, - }, - }, - }, - }, - "literalFromContext": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description literal type alias that require context", - "name": "literalFromContext", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": ""Uncategorized" | "Content" | "Interaction" | "Display" | "Forms" | "Addons"", - }, - }, - "type": { - "name": "enum", - "required": true, - "value": [ - "Uncategorized", - "Content", - "Interaction", - "Display", - "Forms", - "Addons", - ], - }, - }, - "nested": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description nested is required nested object", - "name": "nested", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "MyNestedProps", - }, - }, - "type": { - "name": "object", - "required": true, - "value": { - "nestedProp": { - "name": "string", - "required": true, - }, - }, - }, - }, - "nestedIntersection": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description required nested object with intersection", - "name": "nestedIntersection", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "MyNestedProps & { additionalProp: string; }", - }, - }, - "type": { - "name": "object", - "required": true, - "value": { - "additionalProp": { - "name": "string", - "required": true, - }, - "nestedProp": { - "name": "string", - "required": true, - }, - }, - }, - }, - "nestedOptional": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description optional nested object", - "name": "nestedOptional", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "MyNestedProps | MyIgnoredNestedProps", - }, - }, - "type": { - "name": "union", - "required": false, - "value": [ - { - "name": "object", - "required": false, - "value": { - "nestedProp": { - "name": "string", - "required": true, - }, - }, - }, - { - "name": "object", - "required": false, - "value": { - "nestedProp": { - "name": "string", - "required": true, - }, - }, - }, - ], - }, - }, - "recursive": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "", - "name": "recursive", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "MyNestedRecursiveProps", - }, - }, - "type": { - "name": "object", - "required": false, - "value": { - "recursive": { - "name": "other", - "required": true, - "value": "MyNestedRecursiveProps", - }, - }, - }, - }, - "stringArray": { - "control": { - "disabled": false, - }, - "defaultValue": { - "summary": "["foo", "bar"]", - }, - "description": "description stringArray is string array", - "name": "stringArray", - "table": { - "category": "props", - "defaultValue": { - "summary": "["foo", "bar"]", - }, - "type": { - "summary": "string[]", - }, - }, - "type": { - "name": "array", - "required": false, - "value": { - "name": "string", - "required": false, - }, - }, - }, - "union": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description union is required union type", - "name": "union", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "string | number", - }, - }, - "type": { - "name": "union", - "required": true, - "value": [ - { - "name": "string", - "required": false, - }, - { - "name": "number", - "required": false, - }, - ], - }, - }, - "unionOptional": { - "control": { - "disabled": false, - }, - "defaultValue": undefined, - "description": "description unionOptional is optional union type", - "name": "unionOptional", - "table": { - "category": "props", - "defaultValue": undefined, - "type": { - "summary": "string | number | boolean", - }, - }, - "type": { - "name": "union", - "required": false, - "value": [ - { - "name": "string", - "required": false, - }, - { - "name": "number", - "required": false, - }, - { - "name": "boolean", - "required": false, - }, - ], - }, - }, - } - `); + expect(argTypes).toMatchSnapshot(); }); it('should extract events for Vue component', () => {