Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 189 additions & 8 deletions code/core/src/csf-tools/CsfFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,57 @@ describe('CsfFile', () => {
`);
});

it('typescript satisfies as', () => {
expect(
parse(
dedent`
import type { Meta, StoryFn, StoryObj } from '@storybook/react';
type PropTypes = {};
export default { title: 'foo/bar' } satisfies Meta<PropTypes> as Meta<PropTypes>;
export const A = { name: 'AA' } satisfies StoryObj<PropTypes>;
export const B = ((args) => {}) satisfies StoryFn<PropTypes>;
`,
true
)
).toMatchInlineSnapshot(`
meta:
title: foo/bar
stories:
- id: foo-bar--a
name: AA
parameters:
__isArgsStory: true
__id: foo-bar--a
__stats:
factory: false
play: false
render: false
loaders: false
beforeEach: false
globals: false
tags: false
storyFn: false
mount: false
moduleMock: false
- id: foo-bar--b
name: B
parameters:
__isArgsStory: true
__id: foo-bar--b
__stats:
factory: false
play: false
render: false
loaders: false
beforeEach: false
globals: false
tags: false
storyFn: false
mount: false
moduleMock: false
`);
});

it('typescript meta var', () => {
expect(
parse(
Expand Down Expand Up @@ -605,6 +656,136 @@ describe('CsfFile', () => {
`);
});

it('typescript satisfies as meta', () => {
expect(
parse(
dedent`
import type { Meta, StoryFn } from '@storybook/react';
type PropTypes = {};
const meta = { title: 'foo/bar/baz' } satisfies Meta<PropTypes> as Meta<PropTypes>;
export default meta;
export const A: StoryFn<PropTypes> = () => <>A</>;
export const B: StoryFn<PropTypes> = () => <>B</>;
`
)
).toMatchInlineSnapshot(`
meta:
title: foo/bar/baz
stories:
- id: foo-bar-baz--a
name: A
__stats:
factory: false
play: false
render: false
loaders: false
beforeEach: false
globals: false
tags: false
storyFn: true
mount: false
moduleMock: false
- id: foo-bar-baz--b
name: B
__stats:
factory: false
play: false
render: false
loaders: false
beforeEach: false
globals: false
tags: false
storyFn: true
mount: false
moduleMock: false
`);
});

it('typescript satisfies as stories', () => {
expect(
parse(
dedent`
import type { Meta, StoryFn, StoryObj } from '@storybook/react';
type PropTypes = {};
export default { title: 'foo/bar' } as Meta<PropTypes>;
export const A = { name: 'AA' } satisfies StoryObj<PropTypes> as StoryObj<PropTypes>;
export const B = ((args) => {}) satisfies StoryFn<PropTypes> as StoryFn<PropTypes>;
`,
true
)
).toMatchInlineSnapshot(`
meta:
title: foo/bar
stories:
- id: foo-bar--a
name: AA
parameters:
__isArgsStory: true
__id: foo-bar--a
__stats:
factory: false
play: false
render: false
loaders: false
beforeEach: false
globals: false
tags: false
storyFn: false
mount: false
moduleMock: false
- id: foo-bar--b
name: B
parameters:
__isArgsStory: true
__id: foo-bar--b
__stats:
factory: false
play: false
render: false
loaders: false
beforeEach: false
globals: false
tags: false
storyFn: false
mount: false
moduleMock: false
`);
});

it('typescript satisfies as export specifier', () => {
expect(
parse(
dedent`
import type { Meta, StoryFn } from '@storybook/react';
type PropTypes = {};
const meta = { title: 'foo/bar/baz' } satisfies Meta<PropTypes> as Meta<PropTypes>;
const story = { name: 'Story A' };
export { meta as default, story as A };
`,
true
)
).toMatchInlineSnapshot(`
meta:
title: foo/bar/baz
stories:
- id: foo-bar-baz--a
name: A
localName: story
parameters:
__id: foo-bar-baz--a
__stats:
play: false
render: false
loaders: false
beforeEach: false
globals: false
tags: false
storyFn: false
mount: false
moduleMock: false
`);
});

it('component object', () => {
expect(
parse(
Expand Down Expand Up @@ -1995,7 +2176,7 @@ describe('CsfFile', () => {
const { indexInputs } = loadCsf(
dedent`
const Component = (props) => <div>hello</div>;

export default {
title: 'custom foo title',
component: Component,
Expand Down Expand Up @@ -2513,7 +2694,7 @@ describe('CsfFile', () => {
).toThrowErrorMatchingInlineSnapshot(`
[MultipleMetaError: CSF: multiple meta objects (line 4, col 24)

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error]
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]
`);
});

Expand All @@ -2531,7 +2712,7 @@ describe('CsfFile', () => {
).toThrowErrorMatchingInlineSnapshot(`
[MultipleMetaError: CSF: multiple meta objects (line 3, col 25)

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error]
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]
`);
});

Expand All @@ -2549,7 +2730,7 @@ describe('CsfFile', () => {
).toThrowErrorMatchingInlineSnapshot(`
[MultipleMetaError: CSF: multiple meta objects

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error]
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]
`);
});

Expand All @@ -2565,7 +2746,7 @@ describe('CsfFile', () => {
).toThrowErrorMatchingInlineSnapshot(`
[BadMetaError: CSF: meta() factory must be imported from .storybook/preview configuration (line 1, col 0)

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error]
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]
`);
});

Expand All @@ -2582,7 +2763,7 @@ describe('CsfFile', () => {
).toThrowErrorMatchingInlineSnapshot(`
[BadMetaError: CSF: meta() factory must be imported from .storybook/preview configuration (line 4, col 28)

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error]
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]
`);
});

Expand All @@ -2599,7 +2780,7 @@ describe('CsfFile', () => {
).toThrowErrorMatchingInlineSnapshot(`
[MixedFactoryError: CSF: expected factory story (line 4, col 17)

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error]
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]
`);
});

Expand All @@ -2616,7 +2797,7 @@ describe('CsfFile', () => {
).toThrowErrorMatchingInlineSnapshot(`
[MixedFactoryError: CSF: expected non-factory story (line 4, col 28)

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error]
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]
`);
});
});
Expand Down
48 changes: 38 additions & 10 deletions code/core/src/csf-tools/CsfFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export class NoMetaError extends Error {
super(dedent`
CSF: ${msg} ${formatLocation(ast, fileName)}

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export
`);
this.name = this.constructor.name;
}
Expand All @@ -193,7 +193,7 @@ export class MultipleMetaError extends Error {
super(dedent`
CSF: ${message} ${formatLocation(ast, fileName)}

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export
`);
this.name = this.constructor.name;
}
Expand All @@ -205,7 +205,7 @@ export class MixedFactoryError extends Error {
super(dedent`
CSF: ${message} ${formatLocation(ast, fileName)}

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export
`);
this.name = this.constructor.name;
}
Expand All @@ -217,7 +217,7 @@ export class BadMetaError extends Error {
super(dedent`
CSF: ${message} ${formatLocation(ast, fileName)}

More info: https://storybook.js.org/docs/writing-stories#default-export?ref=error
More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export
`);
this.name = this.constructor.name;
}
Expand Down Expand Up @@ -442,10 +442,18 @@ export class CsfFile {
metaNode = decl;
} else if (
// export default { ... } as Meta<...>
// export default { ... } satisfies Meta<...>
(t.isTSAsExpression(decl) || t.isTSSatisfiesExpression(decl)) &&
t.isObjectExpression(decl.expression)
) {
metaNode = decl.expression;
} else if (
// export default { ... } satisfies Meta as Meta<...>
t.isTSAsExpression(decl) &&
t.isTSSatisfiesExpression(decl.expression) &&
t.isObjectExpression(decl.expression.expression)
) {
metaNode = decl.expression.expression;
}

if (metaNode && t.isProgram(parent)) {
Expand Down Expand Up @@ -495,10 +503,22 @@ export class CsfFile {
}
let storyNode;
if (t.isVariableDeclarator(decl)) {
storyNode =
t.isTSAsExpression(decl.init) || t.isTSSatisfiesExpression(decl.init)
? decl.init.expression
: decl.init;
if (
t.isTSAsExpression(decl.init) &&
t.isTSSatisfiesExpression(decl.init.expression)
) {
// { ... } satisfies Meta<...> as Meta<...>
storyNode = decl.init.expression.expression;
} else if (
t.isTSAsExpression(decl.init) ||
t.isTSSatisfiesExpression(decl.init)
) {
// { ... } as Meta<...>
// { ... } satisfies Meta<...>
storyNode = decl.init.expression;
} else {
storyNode = decl.init;
}
} else {
storyNode = decl;
}
Expand Down Expand Up @@ -596,10 +616,18 @@ export class CsfFile {
metaNode = decl;
} else if (
// export default { ... } as Meta<...>
t.isTSAsExpression(decl) &&
// export default { ... } satisfies Meta<...>
(t.isTSAsExpression(decl) || t.isTSSatisfiesExpression(decl)) &&
t.isObjectExpression(decl.expression)
) {
metaNode = decl.expression;
} else if (
// export default { ... } satisfies Meta as Meta<...>
t.isTSAsExpression(decl) &&
t.isTSSatisfiesExpression(decl.expression) &&
t.isObjectExpression(decl.expression.expression)
) {
metaNode = decl.expression.expression;
}

if (metaNode && t.isProgram(parent)) {
Expand Down Expand Up @@ -681,7 +709,7 @@ export class CsfFile {
throw new Error(dedent`
Unexpected \`storiesOf\` usage: ${formatLocation(node, self._options.fileName)}.

SB8 does not support \`storiesOf\`.
SB8 does not support \`storiesOf\`.
`);
}
if (
Expand Down