diff --git a/code/jest.config.js b/code/jest.config.js index 55f8ea175520..0e444db10997 100644 --- a/code/jest.config.js +++ b/code/jest.config.js @@ -47,6 +47,8 @@ module.exports = { '/examples/*/src/*.*', '/examples/*/src/*/*.*', '/examples/*/src/*/*/*.*', + // TODO: Can not get svelte-jester to work, but also not necessary for this test, as it is run by tsc/svelte-check. + '/renderers/svelte/src/public-types.test.ts', ], collectCoverage: false, collectCoverageFrom: [ diff --git a/code/lib/core-common/src/index.ts b/code/lib/core-common/src/index.ts index d0178dd2f3ba..cacd45d82417 100644 --- a/code/lib/core-common/src/index.ts +++ b/code/lib/core-common/src/index.ts @@ -29,6 +29,7 @@ export * from './utils/symlinks'; export * from './utils/template'; export * from './utils/validate-config'; export * from './utils/validate-configuration-files'; +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 f7b3b683fe63..92d815f19e65 100644 --- a/code/package.json +++ b/code/package.json @@ -337,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 04e4abcc192d..e3c3eee5b6b0 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 eb854548b702..1c636b9f9c16 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..5c6636bea050 --- /dev/null +++ b/code/renderers/svelte/src/public-types.test.ts @@ -0,0 +1,230 @@ +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