From 387630a9ee489d522ae66662b9bebb6ca5f0431c Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Wed, 12 Oct 2022 20:37:32 +0200 Subject: [PATCH] more typesafe CSF3 types for svelte --- code/addons/highlight/package.json | 6 +- code/lib/core-common/src/index.ts | 1 + .../core-common/src/utils/satisfies.ts} | 0 code/package.json | 3 +- .../CSF3.test.tsx => public-types.test.tsx} | 17 +- code/renderers/react/src/public-types.ts | 34 ++- code/renderers/svelte/package.json | 7 +- .../svelte/src/___test___/Button.svelte | 12 + .../svelte/src/___test___/Decorator.svelte | 8 + .../svelte/src/___test___/Decorator2.svelte | 8 + .../svelte/src/docs/extractArgTypes.test.ts | 1 + .../svelte/src/docs/extractArgTypes.ts | 2 +- .../docs/extractComponentDescription.test.ts | 1 + .../svelte/src/docs/sourceDecorator.test.ts | 7 +- .../svelte/src/docs/sourceDecorator.ts | 2 +- code/renderers/svelte/src/globals.ts | 1 - .../renderers/svelte/src/public-types.test.ts | 224 ++++++++++++++++++ code/renderers/svelte/src/public-types.ts | 45 +++- code/renderers/svelte/src/render.ts | 9 +- code/renderers/svelte/src/types.ts | 36 ++- code/renderers/svelte/src/typings.d.ts | 4 +- .../svelte/templates/PreviewRender.svelte | 4 +- code/renderers/svelte/tsconfig.json | 4 +- code/yarn.lock | 72 +++--- package.json | 3 +- scripts/tasks/check.ts | 5 +- scripts/utils/options.test.ts | 8 +- 27 files changed, 419 insertions(+), 105 deletions(-) rename code/{renderers/react/src/__test__/utils.ts => lib/core-common/src/utils/satisfies.ts} (100%) rename code/renderers/react/src/{__test__/CSF3.test.tsx => public-types.test.tsx} (93%) create mode 100644 code/renderers/svelte/src/___test___/Button.svelte create mode 100644 code/renderers/svelte/src/___test___/Decorator.svelte create mode 100644 code/renderers/svelte/src/___test___/Decorator2.svelte create mode 100644 code/renderers/svelte/src/public-types.test.ts diff --git a/code/addons/highlight/package.json b/code/addons/highlight/package.json index dad00fa7e4db..92a6e14cea96 100644 --- a/code/addons/highlight/package.json +++ b/code/addons/highlight/package.json @@ -58,15 +58,15 @@ "@types/webpack-env": "^1.16.0", "typescript": "~4.6.3" }, + "publishConfig": { + "access": "public" + }, "bundler": { "entries": [ "./src/index.ts", "./src/highlight.ts" ] }, - "publishConfig": { - "access": "public" - }, "gitHead": "438114fcf62a763f0e8c07e2c34890dd987ca431", "sbmodern": "dist/modern/index.js", "storybook": { diff --git a/code/lib/core-common/src/index.ts b/code/lib/core-common/src/index.ts index 5b95a7716571..034c4a9301c6 100644 --- a/code/lib/core-common/src/index.ts +++ b/code/lib/core-common/src/index.ts @@ -28,6 +28,7 @@ export * from './utils/normalize-stories'; export * from './utils/readTemplate'; export * from './utils/findDistEsm'; export * from './utils/symlinks'; +export * from './utils/satisfies'; export * from './types'; diff --git a/code/renderers/react/src/__test__/utils.ts b/code/lib/core-common/src/utils/satisfies.ts similarity index 100% rename from code/renderers/react/src/__test__/utils.ts rename to code/lib/core-common/src/utils/satisfies.ts diff --git a/code/package.json b/code/package.json index fc972e5f977e..9211a17f13ac 100644 --- a/code/package.json +++ b/code/package.json @@ -111,6 +111,7 @@ ], "resolutions": { "@nrwl/cli": "14.6.1", + "@storybook/csf": "portal:/Users/kasperpeulen/code/storybook/csf", "@typescript-eslint/eslint-plugin": "^5.15.0", "@typescript-eslint/experimental-utils": "5.3.0", "@typescript-eslint/parser": "^5.15.0", @@ -336,7 +337,7 @@ "ts-jest": "^26.4.4", "ts-node": "^10.4.0", "tsup": "^6.2.2", - "typescript": "4.7.4", + "typescript": "~4.6.3", "util": "^0.12.4", "vite": "^3.1.7", "wait-on": "^5.2.1", diff --git a/code/renderers/react/src/__test__/CSF3.test.tsx b/code/renderers/react/src/public-types.test.tsx similarity index 93% rename from code/renderers/react/src/__test__/CSF3.test.tsx rename to code/renderers/react/src/public-types.test.tsx index 89bbb79aa3ea..7c407f77c324 100644 --- a/code/renderers/react/src/__test__/CSF3.test.tsx +++ b/code/renderers/react/src/public-types.test.tsx @@ -1,13 +1,13 @@ -import React, { KeyboardEventHandler, ReactNode } from 'react'; -import { expectTypeOf } from 'expect-type'; import { describe, test } from '@jest/globals'; +import { satisfies } from '@storybook/core-common'; import { StoryAnnotations } from '@storybook/csf'; +import { expectTypeOf } from 'expect-type'; +import React, { KeyboardEventHandler, ReactNode } from 'react'; import { SetOptional } from 'type-fest'; -import { Meta, StoryObj } from '../public-types'; -import { DecoratorFn } from '../public-api'; -import { satisfies } from './utils'; -import { ReactFramework } from '../types'; +import { DecoratorFn } from './public-api'; +import { Meta, StoryObj } from './public-types'; +import { ReactFramework } from './types'; type ReactStory = StoryAnnotations; @@ -75,6 +75,11 @@ describe('Args can be provided in multiple ways', () => { expectTypeOf(Basic).toEqualTypeOf(); } }); + + test('Component can be used as generic parameter for StoryObj', () => { + type Expected = ReactStory; + expectTypeOf>().toEqualTypeOf(); + }); }); test('✅ All void functions are optional', () => { diff --git a/code/renderers/react/src/public-types.ts b/code/renderers/react/src/public-types.ts index d724fc681c73..34452cf0c8a9 100644 --- a/code/renderers/react/src/public-types.ts +++ b/code/renderers/react/src/public-types.ts @@ -1,16 +1,15 @@ import type { AnnotatedStoryFn, Args, + ArgsFromMeta, ArgsStoryFn, ComponentAnnotations, - LoaderFunction, StoryAnnotations, } from '@storybook/csf'; -import { SetOptional, Simplify, UnionToIntersection } from 'type-fest'; import { ComponentProps, ComponentType, JSXElementConstructor } from 'react'; +import { SetOptional, Simplify } from 'type-fest'; import { ReactFramework } from './types'; -import { DecoratorFn } from './public-api'; type JSXElement = keyof JSX.IntrinsicElements | JSXElementConstructor; @@ -36,29 +35,28 @@ export type StoryFn = AnnotatedStoryFn; * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports) */ -export type StoryObj = MetaOrArgs extends { - render?: ArgsStoryFn; - component?: ComponentType; - loaders?: (infer Loaders)[]; +export type StoryObj = MetaOrCmpOrArgs extends { + render?: ArgsStoryFn; + component?: infer Component; args?: infer DefaultArgs; - decorators?: (infer Decorators)[]; } - ? Simplify & LoaderArgs> extends infer TArgs + ? Simplify< + (Component extends ComponentType ? ComponentProps : unknown) & + ArgsFromMeta + > extends infer TArgs ? StoryAnnotations< ReactFramework, TArgs, SetOptional)>> > : never - : StoryAnnotations; - -type DecoratorsArgs = UnionToIntersection< - Decorators extends DecoratorFn ? Args : unknown ->; - -type LoaderArgs = UnionToIntersection< - Loaders extends LoaderFunction ? Args : unknown ->; + : MetaOrCmpOrArgs extends ComponentType + ? StoryAnnotations< + ReactFramework, + ComponentProps, + ComponentProps + > + : StoryAnnotations; type ActionArgs = { [P in keyof Args as ((...args: any[]) => void) extends Args[P] ? P : never]: Args[P]; diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json index ace782a2c08d..73fc1ed41e28 100644 --- a/code/renderers/svelte/package.json +++ b/code/renderers/svelte/package.json @@ -50,7 +50,7 @@ "*.d.ts" ], "scripts": { - "check": "../../../scripts/node_modules/.bin/tsc --noEmit", + "check": "svelte-check --tsconfig ./tsconfig.json", "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { @@ -63,10 +63,13 @@ "global": "^4.4.0", "react": "16.14.0", "react-dom": "16.14.0", - "sveltedoc-parser": "^4.2.1" + "sveltedoc-parser": "^4.2.1", + "type-fest": "2.19.0" }, "devDependencies": { + "expect-type": "^0.14.2", "svelte": "^3.31.2", + "svelte-check": "^2.9.2", "typescript": "~4.6.3" }, "peerDependencies": { diff --git a/code/renderers/svelte/src/___test___/Button.svelte b/code/renderers/svelte/src/___test___/Button.svelte new file mode 100644 index 000000000000..b7fd6e8e325c --- /dev/null +++ b/code/renderers/svelte/src/___test___/Button.svelte @@ -0,0 +1,12 @@ + + + diff --git a/code/renderers/svelte/src/___test___/Decorator.svelte b/code/renderers/svelte/src/___test___/Decorator.svelte new file mode 100644 index 000000000000..4fc5241ba9d4 --- /dev/null +++ b/code/renderers/svelte/src/___test___/Decorator.svelte @@ -0,0 +1,8 @@ + + +
+ Decorator: {decoratorArg} + +
diff --git a/code/renderers/svelte/src/___test___/Decorator2.svelte b/code/renderers/svelte/src/___test___/Decorator2.svelte new file mode 100644 index 000000000000..57d98a6e2676 --- /dev/null +++ b/code/renderers/svelte/src/___test___/Decorator2.svelte @@ -0,0 +1,8 @@ + + +
+ Decorator: {decoratorArg2} + +
diff --git a/code/renderers/svelte/src/docs/extractArgTypes.test.ts b/code/renderers/svelte/src/docs/extractArgTypes.test.ts index c1911ffa3d1d..dcde4dddcce6 100644 --- a/code/renderers/svelte/src/docs/extractArgTypes.test.ts +++ b/code/renderers/svelte/src/docs/extractArgTypes.test.ts @@ -1,3 +1,4 @@ +import { describe, expect } from '@jest/globals'; import svelteDoc from 'sveltedoc-parser'; import * as fs from 'fs'; import { createArgTypes } from './extractArgTypes'; diff --git a/code/renderers/svelte/src/docs/extractArgTypes.ts b/code/renderers/svelte/src/docs/extractArgTypes.ts index 900d55b336a2..080367309c23 100644 --- a/code/renderers/svelte/src/docs/extractArgTypes.ts +++ b/code/renderers/svelte/src/docs/extractArgTypes.ts @@ -89,7 +89,7 @@ export const createArgTypes = (docgen: SvelteComponentDoc) => { /** * Function to convert the type from sveltedoc-parser to a storybook type - * @param typeName + * @param type * @returns string */ const parseTypeToControl = (type: JSDocType | undefined): any => { diff --git a/code/renderers/svelte/src/docs/extractComponentDescription.test.ts b/code/renderers/svelte/src/docs/extractComponentDescription.test.ts index 3e6eb3e779c3..f2e7866f6394 100644 --- a/code/renderers/svelte/src/docs/extractComponentDescription.test.ts +++ b/code/renderers/svelte/src/docs/extractComponentDescription.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, test } from '@jest/globals'; import { extractComponentDescription } from './extractComponentDescription'; describe('extractComponentDescription', () => { diff --git a/code/renderers/svelte/src/docs/sourceDecorator.test.ts b/code/renderers/svelte/src/docs/sourceDecorator.test.ts index 006a7bb4de05..eaa26616f792 100644 --- a/code/renderers/svelte/src/docs/sourceDecorator.test.ts +++ b/code/renderers/svelte/src/docs/sourceDecorator.test.ts @@ -1,12 +1,13 @@ +import { describe, expect, test } from '@jest/globals'; import type { Args } from '@storybook/api'; import { generateSvelteSource } from './sourceDecorator'; expect.addSnapshotSerializer({ print: (val: any) => val, - test: (val) => typeof val === 'string', + test: (val: unknown) => typeof val === 'string', }); -function generateForArgs(args: Args, slotProperty: string = null) { +function generateForArgs(args: Args, slotProperty: string | null = null) { return generateSvelteSource({ name: 'Component' }, args, {}, slotProperty); } @@ -42,6 +43,6 @@ describe('generateSvelteSource', () => { `); }); test('component is not set', () => { - expect(generateSvelteSource(null, null, null, null)).toBeNull(); + expect(generateSvelteSource(null, {}, {}, null)).toBeNull(); }); }); diff --git a/code/renderers/svelte/src/docs/sourceDecorator.ts b/code/renderers/svelte/src/docs/sourceDecorator.ts index d7b04f91c9df..05d90ffc5188 100644 --- a/code/renderers/svelte/src/docs/sourceDecorator.ts +++ b/code/renderers/svelte/src/docs/sourceDecorator.ts @@ -89,7 +89,7 @@ export function generateSvelteSource( component: any, args: Args, argTypes: ArgTypes, - slotProperty?: string + slotProperty?: string | null ): string | null { const name = getComponentName(component); diff --git a/code/renderers/svelte/src/globals.ts b/code/renderers/svelte/src/globals.ts index aabe0fd8fb42..a2fb5c9dad10 100644 --- a/code/renderers/svelte/src/globals.ts +++ b/code/renderers/svelte/src/globals.ts @@ -1,4 +1,3 @@ -// @ts-expect-error (Converted from ts-ignore) import global from 'global'; const { window: globalWindow } = global; diff --git a/code/renderers/svelte/src/public-types.test.ts b/code/renderers/svelte/src/public-types.test.ts new file mode 100644 index 000000000000..1f965457f1f0 --- /dev/null +++ b/code/renderers/svelte/src/public-types.test.ts @@ -0,0 +1,224 @@ +import { describe, test } from '@jest/globals'; +import { satisfies } from '@storybook/core-common'; +import { ComponentAnnotations, StoryAnnotations } from '@storybook/csf'; +import { expectTypeOf } from 'expect-type'; +import { ComponentProps, SvelteComponentTyped } from 'svelte'; +import Button from './___test___/Button.svelte'; +import Decorator from './___test___/Decorator.svelte'; +import Decorator2 from './___test___/Decorator2.svelte'; + +import { DecoratorFn, Meta, StoryObj } from './public-types'; +import { SvelteFramework } from './types'; + +type SvelteStory = StoryAnnotations< + SvelteFramework, + Args, + RequiredArgs +>; + +describe('Meta', () => { + test('Generic parameter of Meta can be a component', () => { + const meta: Meta