@storybook/addon-svelte-csf 5.1.0 → 5.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/compiler/post-transform/appendix/create-export-order.test.d.ts +1 -0
  2. package/dist/compiler/post-transform/appendix/create-export-order.test.js +21 -0
  3. package/dist/compiler/post-transform/appendix/create-import.test.d.ts +1 -0
  4. package/dist/compiler/post-transform/appendix/create-import.test.js +9 -0
  5. package/dist/compiler/post-transform/appendix/create-named-export-stories.test.d.ts +1 -0
  6. package/dist/compiler/post-transform/appendix/create-named-export-stories.test.js +35 -0
  7. package/dist/compiler/post-transform/appendix/create-runtime-story-variable-declaration.test.d.ts +1 -0
  8. package/dist/compiler/post-transform/appendix/create-runtime-story-variable-declaration.test.js +100 -0
  9. package/dist/compiler/post-transform/appendix/create-variable-from-runtime-stories-call.test.d.ts +1 -0
  10. package/dist/compiler/post-transform/appendix/create-variable-from-runtime-stories-call.test.js +22 -0
  11. package/dist/compiler/post-transform/define-meta/index.test.d.ts +1 -0
  12. package/dist/compiler/post-transform/define-meta/index.test.js +96 -0
  13. package/dist/compiler/post-transform/index.test.d.ts +1 -0
  14. package/dist/compiler/post-transform/index.test.js +279 -0
  15. package/dist/compiler/post-transform/remove-export-default.test.d.ts +1 -0
  16. package/dist/compiler/post-transform/remove-export-default.test.js +33 -0
  17. package/dist/compiler/post-transform/story/index.test.d.ts +1 -0
  18. package/dist/compiler/post-transform/story/index.test.js +147 -0
  19. package/dist/compiler/pre-transform/codemods/component-meta-to-define-meta.test.d.ts +1 -0
  20. package/dist/compiler/pre-transform/codemods/component-meta-to-define-meta.test.js +121 -0
  21. package/dist/compiler/pre-transform/codemods/export-const-to-define-meta.test.d.ts +1 -0
  22. package/dist/compiler/pre-transform/codemods/export-const-to-define-meta.test.js +68 -0
  23. package/dist/compiler/pre-transform/codemods/import-declaration.test.d.ts +1 -0
  24. package/dist/compiler/pre-transform/codemods/import-declaration.test.js +24 -0
  25. package/dist/compiler/pre-transform/codemods/legacy-story.test.d.ts +1 -0
  26. package/dist/compiler/pre-transform/codemods/legacy-story.test.js +287 -0
  27. package/dist/compiler/pre-transform/codemods/template-to-snippet.test.d.ts +1 -0
  28. package/dist/compiler/pre-transform/codemods/template-to-snippet.test.js +75 -0
  29. package/dist/compiler/pre-transform/index.test.d.ts +1 -0
  30. package/dist/compiler/pre-transform/index.test.js +256 -0
  31. package/dist/parser/analyse/story/attributes/identifiers.test.d.ts +1 -0
  32. package/dist/parser/analyse/story/attributes/identifiers.test.js +294 -0
  33. package/dist/parser/analyse/story/attributes.test.d.ts +1 -0
  34. package/dist/parser/analyse/story/attributes.test.js +151 -0
  35. package/dist/parser/analyse/story/content.test.d.ts +1 -0
  36. package/dist/parser/analyse/story/content.test.js +263 -0
  37. package/dist/parser/extract/svelte/define-meta.test.d.ts +1 -0
  38. package/dist/parser/extract/svelte/define-meta.test.js +32 -0
  39. package/dist/parser/extract/svelte/fragment-nodes.test.d.ts +1 -0
  40. package/dist/parser/extract/svelte/fragment-nodes.test.js +101 -0
  41. package/dist/parser/extract/svelte/module-nodes.test.d.ts +1 -0
  42. package/dist/parser/extract/svelte/module-nodes.test.js +143 -0
  43. package/dist/parser/extract/svelte/nodes.test.d.ts +1 -0
  44. package/dist/parser/extract/svelte/nodes.test.js +29 -0
  45. package/dist/parser/extract/svelte/story/attributes.test.d.ts +1 -0
  46. package/dist/parser/extract/svelte/story/attributes.test.js +50 -0
  47. package/dist/parser/extract/svelte/story/template.test.d.ts +1 -0
  48. package/dist/parser/extract/svelte/story/template.test.js +51 -0
  49. package/dist/runtime/emit-code.test.d.ts +1 -0
  50. package/dist/runtime/emit-code.test.js +149 -0
  51. package/dist/utils/identifier-utils.test.d.ts +1 -0
  52. package/dist/utils/identifier-utils.test.js +22 -0
  53. package/package.json +24 -28
@@ -0,0 +1,75 @@
1
+ import pkg from '@storybook/addon-svelte-csf/package.json' with { type: 'json' };
2
+ import { print } from 'svelte-ast-print';
3
+ import { describe, it } from 'vitest';
4
+ import { transformTemplateToSnippet } from './template-to-snippet.js';
5
+ import { parseAndExtractSvelteNode } from '../../../../tests/extractor.js';
6
+ describe(transformTemplateToSnippet.name, () => {
7
+ it("covers a case without provided prop 'id'", async ({ expect }) => {
8
+ const code = `
9
+ <script context="module" lang="ts">
10
+ import { Template } from "${pkg.name}";
11
+ </script>
12
+
13
+ <Template let:args>
14
+ <Button {...args} variant="primary" />
15
+ </Template>
16
+ `;
17
+ const component = await parseAndExtractSvelteNode(code, 'Component');
18
+ expect(print(transformTemplateToSnippet({ component }))).toMatchInlineSnapshot(`
19
+ "{#snippet sb_default_template(args)}
20
+ <Button {...args} variant="primary" />
21
+ {/snippet}"
22
+ `);
23
+ });
24
+ it("covers a case with provided prop 'id'", async ({ expect }) => {
25
+ const code = `
26
+ <script context="module" lang="ts">
27
+ import { Template } from "${pkg.name}";
28
+ </script>
29
+
30
+ <Template id="coolTemplate" let:args>
31
+ <Button {...args} variant="primary" />
32
+ </Template>
33
+ `;
34
+ const component = await parseAndExtractSvelteNode(code, 'Component');
35
+ expect(print(transformTemplateToSnippet({ component }))).toMatchInlineSnapshot(`
36
+ "{#snippet coolTemplate(args)}
37
+ <Button {...args} variant="primary" />
38
+ {/snippet}"
39
+ `);
40
+ });
41
+ it("covers a case with provided prop 'id' and prop `id` not being a valid identifier", async ({ expect, }) => {
42
+ const code = `
43
+ <script context="module" lang="ts">
44
+ import { Template } from "${pkg.name}";
45
+ </script>
46
+
47
+ <Template id="cool-template" let:args>
48
+ <Button {...args} variant="primary" />
49
+ </Template>
50
+ `;
51
+ const component = await parseAndExtractSvelteNode(code, 'Component');
52
+ expect(print(transformTemplateToSnippet({ component }))).toMatchInlineSnapshot(`
53
+ "{#snippet template_haitqt(args)}
54
+ <Button {...args} variant="primary" />
55
+ {/snippet}"
56
+ `);
57
+ });
58
+ it("works with 'let:context' directive", async ({ expect }) => {
59
+ const code = `
60
+ <script context="module" lang="ts">
61
+ import { Template } from "${pkg.name}";
62
+ </script>
63
+
64
+ <Template let:context>
65
+ <p>{context.args}</p>
66
+ </Template>
67
+ `;
68
+ const component = await parseAndExtractSvelteNode(code, 'Component');
69
+ expect(print(transformTemplateToSnippet({ component }))).toMatchInlineSnapshot(`
70
+ "{#snippet sb_default_template(_args, context)}
71
+ <p>{context.args}</p>
72
+ {/snippet}"
73
+ `);
74
+ });
75
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,256 @@
1
+ import pkg from '@storybook/addon-svelte-csf/package.json' with { type: 'json' };
2
+ import dedent from 'dedent';
3
+ import { print } from 'svelte-ast-print';
4
+ import { describe, it } from 'vitest';
5
+ import { codemodLegacyNodes } from './index.js';
6
+ import { getSvelteAST } from '../../parser/ast.js';
7
+ describe(codemodLegacyNodes.name, () => {
8
+ it("replaces 'export const meta' with 'defineMeta'", async ({ expect }) => {
9
+ const code = dedent(`
10
+ <script context="module">
11
+ import { Story } from "${pkg.name}";
12
+
13
+ /** This is a description for the **Button** component stories. */
14
+ export const meta = {
15
+ title: "Atoms/Button",
16
+ component: Button,
17
+ };
18
+ </script>
19
+
20
+ <!-- This is a description for **default** Button. -->
21
+ <Story name="Default" />
22
+ `);
23
+ const ast = getSvelteAST({ code });
24
+ const transformed = await codemodLegacyNodes({ ast });
25
+ expect(print(transformed)).toMatchInlineSnapshot(`
26
+ "<script context="module">
27
+ import { defineMeta } from "@storybook/addon-svelte-csf";
28
+
29
+ /** This is a description for the **Button** component stories. */
30
+ const { Story } = defineMeta({ title: "Atoms/Button", component: Button });
31
+ </script>
32
+
33
+ <!-- This is a description for **default** Button. -->
34
+ <Story name="Default" tags={["svelte-csf-v4"]} />"
35
+ `);
36
+ });
37
+ it("replaces 'Meta' with inserting 'defineMeta' to module tag", async ({ expect }) => {
38
+ const code = dedent(`
39
+ <script context="module">
40
+ import { Meta, Template } from "${pkg.name}";
41
+ </script>
42
+
43
+ <!-- This is a description for the **Button** component stories. -->
44
+ <Meta title="Atoms/Button" component={Button} />
45
+ `);
46
+ const ast = getSvelteAST({ code });
47
+ const transformed = await codemodLegacyNodes({ ast });
48
+ expect(print(transformed)).toMatchInlineSnapshot(`
49
+ "<script context="module">
50
+ import { defineMeta } from "@storybook/addon-svelte-csf";
51
+
52
+ /** This is a description for the **Button** component stories. */
53
+ const { Story } = defineMeta({ title: "Atoms/Button", component: Button });
54
+ </script>"
55
+ `);
56
+ });
57
+ it("replaces 'Template' with snippet block", async ({ expect }) => {
58
+ const code = dedent(`
59
+ <script>
60
+ import { Meta, Template } from "${pkg.name}";
61
+ </script>
62
+
63
+ <!-- This is a description for the **Button** component stories. -->
64
+ <Meta title="Atoms/Button" component={Button} />
65
+
66
+ <Template let:args>
67
+ <Button {...args} />
68
+ </Template>
69
+
70
+ <Story name="Default" />
71
+ `);
72
+ const ast = getSvelteAST({ code });
73
+ const transformed = await codemodLegacyNodes({ ast });
74
+ expect(print(transformed)).toMatchInlineSnapshot(`
75
+ "<script module>
76
+ import { defineMeta } from "@storybook/addon-svelte-csf";
77
+
78
+ /** This is a description for the **Button** component stories. */
79
+ const { Story } = defineMeta({ title: "Atoms/Button", component: Button });
80
+ </script>
81
+
82
+ {#snippet sb_default_template(args)}
83
+ <Button {...args} />
84
+ {/snippet}
85
+ <Story name="Default" />"
86
+ `);
87
+ });
88
+ it('transforms legacy syntax correctly', async ({ expect }) => {
89
+ const code = dedent(`
90
+ <script context="module">
91
+ import { Meta, Story, Template } from "${pkg.name}";
92
+ </script>
93
+
94
+ <!-- This is a description for the **Button** component stories. -->
95
+ <Meta title="Atoms/Button" component={Button} />
96
+
97
+ <Template id="sample" let:args let:context>
98
+ <p>{context.id}</p>
99
+ <Button {...args} />
100
+ </Template>
101
+
102
+ <Story name="Default" autodocs source={"<Button {...args} />"} template="sample" let:args let:context>
103
+ <p>{context.id}</p>
104
+ <Button {...args} />
105
+ </Story>
106
+ `);
107
+ const ast = getSvelteAST({ code });
108
+ const transformed = await codemodLegacyNodes({ ast });
109
+ expect(print(transformed)).toMatchInlineSnapshot(`
110
+ "<script context="module">
111
+ import { defineMeta } from "@storybook/addon-svelte-csf";
112
+
113
+ /** This is a description for the **Button** component stories. */
114
+ const { Story } = defineMeta({ title: "Atoms/Button", component: Button });
115
+ </script>
116
+
117
+ {#snippet sample(args, context)}
118
+ <p>{context.id}</p>
119
+ <Button {...args} />
120
+
121
+ {/snippet} <Story name="Default" template={sample} tags={["autodocs", "svelte-csf-v4"]} parameters={{
122
+ docs: { source: { code: "<Button {...args} />" } }
123
+ }}>
124
+ {#snippet template(args, context)}
125
+ <p>{context.id}</p>
126
+ <Button {...args} />
127
+
128
+ {/snippet}
129
+ </Story>"
130
+ `);
131
+ });
132
+ it('moves package import declaration from instance to module tag', async ({ expect }) => {
133
+ const code = dedent(`
134
+ <script>
135
+ import { Meta, Story, Template } from "${pkg.name}";
136
+ </script>
137
+ `);
138
+ const ast = getSvelteAST({ code });
139
+ const transformed = await codemodLegacyNodes({ ast });
140
+ expect(print(transformed)).toMatchInlineSnapshot(`
141
+ "<script module>
142
+ import { defineMeta } from "@storybook/addon-svelte-csf";
143
+ </script>"
144
+ `);
145
+ });
146
+ it('moves transformed export const meta from instance to module tag', async ({ expect }) => {
147
+ const code = dedent(`
148
+ <script>
149
+ import { Story, Template } from "${pkg.name}";
150
+
151
+ export const meta = {
152
+ args: {
153
+ primary: true,
154
+ },
155
+ tags: ["autodocs"],
156
+ };
157
+ </script>
158
+ `);
159
+ const ast = getSvelteAST({ code });
160
+ const transformed = await codemodLegacyNodes({ ast });
161
+ expect(print(transformed)).toMatchInlineSnapshot(`
162
+ "<script module>
163
+ import { defineMeta } from "@storybook/addon-svelte-csf";
164
+
165
+ const { Story } = defineMeta({
166
+ args: { primary: true },
167
+ tags: ["autodocs"]
168
+ });
169
+ </script>"
170
+ `);
171
+ });
172
+ it('moves transformed export const meta and stories component import declaration from instance to module tag', async ({ expect, }) => {
173
+ const code = dedent(`
174
+ <script>
175
+ import { Story, Template } from "${pkg.name}";
176
+ import Button from "./Button.svelte";
177
+
178
+ export const meta = {
179
+ component: Button,
180
+ args: {
181
+ primary: true,
182
+ },
183
+ tags: ["autodocs"],
184
+ };
185
+ </script>
186
+ `);
187
+ const ast = getSvelteAST({ code });
188
+ const transformed = await codemodLegacyNodes({ ast });
189
+ expect(print(transformed)).toMatchInlineSnapshot(`
190
+ "<script module>
191
+ import { defineMeta } from "@storybook/addon-svelte-csf";
192
+ import Button from "./Button.svelte";
193
+
194
+ const { Story } = defineMeta({
195
+ component: Button,
196
+ args: { primary: true },
197
+ tags: ["autodocs"]
198
+ });
199
+ </script>"
200
+ `);
201
+ });
202
+ it('throws error on more than one unidentified <Template> components', async ({ expect }) => {
203
+ const code = `
204
+ <script module lang="ts">
205
+ import { Story, Template } from "${pkg.name}";
206
+ </script>
207
+
208
+ <Template let:context>
209
+ <p>{context.args}</p>
210
+ </Template>
211
+
212
+ <Story name="Default" />
213
+
214
+ <Template let:args>
215
+ <Button {...args} />
216
+ </Template>
217
+
218
+ <Story name="NextOne" />
219
+ `;
220
+ const ast = getSvelteAST({ code });
221
+ await expect(codemodLegacyNodes({ ast })).rejects.toThrowErrorMatchingInlineSnapshot(`
222
+ [SB_SVELTE_CSF_LEGACY_API_0003 (DuplicatedUnidentifiedTemplateError): Stories file: undefined
223
+ has two '<Template />' components without provided prop 'id'. This leads to unwanted runtime behavior.
224
+
225
+ Please provide an 'id' to one of them.
226
+ And for the '<Story />' component(s) which are supposed to use it, add the 'template' prop with the same 'id' value.
227
+
228
+ More info: https://github.com/storybookjs/addon-svelte-csf/blob/v${pkg.version}/ERRORS.md#SB_SVELTE_CSF_LEGACY_API_0003
229
+ ]
230
+ `);
231
+ });
232
+ it('moves import declaration of stories target component from instance tag to module tag', async ({ expect, }) => {
233
+ const code = `
234
+ <script context="module" lang="ts">
235
+ export const meta: Meta<Button> = {
236
+ component: Button,
237
+ };
238
+ </script>
239
+
240
+ <script>
241
+ import { Story } from "${pkg.name}";
242
+ import Button from "./Button.svelte";
243
+ </script>
244
+ `;
245
+ const ast = getSvelteAST({ code });
246
+ const transformed = await codemodLegacyNodes({ ast });
247
+ expect(print(transformed)).toMatchInlineSnapshot(`
248
+ "<script context="module" lang="ts">
249
+ import { defineMeta } from "@storybook/addon-svelte-csf";
250
+ import Button from "./Button.svelte";
251
+
252
+ const { Story } = defineMeta({ component: Button });
253
+ </script>"
254
+ `);
255
+ });
256
+ });
@@ -0,0 +1,294 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { getStoryIdentifiers, getStoriesIdentifiers } from './identifiers.js';
3
+ import { getSvelteAST } from '../../../ast.js';
4
+ import { extractSvelteASTNodes } from '../../../extract/svelte/nodes.js';
5
+ import { extractStoryAttributesNodes } from '../../../extract/svelte/story/attributes.js';
6
+ import { StorybookSvelteCSFError } from '../../../../utils/error.js';
7
+ describe(getStoryIdentifiers.name, () => {
8
+ it("extracts 'exportName' attribute when is a Text string", async () => {
9
+ const ast = getSvelteAST({
10
+ code: `
11
+ <script module>
12
+ import { defineMeta } from "@storybook/addon-svelte-csf"
13
+ const { Story } = defineMeta();
14
+ </script>
15
+ <Story exportName="Text" />
16
+ `,
17
+ });
18
+ const nodes = await extractSvelteASTNodes({ ast });
19
+ const { component } = nodes.storyComponents[0];
20
+ const { exportName, name } = extractStoryAttributesNodes({
21
+ component,
22
+ attributes: ['exportName', 'name'],
23
+ });
24
+ expect(getStoryIdentifiers({
25
+ exportNameNode: exportName,
26
+ nameNode: name,
27
+ component,
28
+ })).toEqual({
29
+ exportName: 'Text',
30
+ name: undefined,
31
+ });
32
+ });
33
+ it("extracts 'exportName' attribute when is an expression with literal", async () => {
34
+ const ast = getSvelteAST({
35
+ code: `
36
+ <script module>
37
+ import { defineMeta } from "@storybook/addon-svelte-csf"
38
+ const { Story } = defineMeta();
39
+ </script>
40
+ <Story exportName={"ExpressionWithLiteral"} />
41
+ `,
42
+ });
43
+ const nodes = await extractSvelteASTNodes({ ast });
44
+ const { component } = nodes.storyComponents[0];
45
+ const { exportName, name } = extractStoryAttributesNodes({
46
+ component,
47
+ attributes: ['exportName', 'name'],
48
+ });
49
+ expect(getStoryIdentifiers({
50
+ exportNameNode: exportName,
51
+ nameNode: name,
52
+ component,
53
+ })).toEqual({
54
+ exportName: 'ExpressionWithLiteral',
55
+ name: undefined,
56
+ });
57
+ });
58
+ it("throws when '<Story />' doesn't provide an 'exportName' or 'name' attribute prop", async () => {
59
+ const ast = getSvelteAST({
60
+ code: `
61
+ <script module>
62
+ import { defineMeta } from "@storybook/addon-svelte-csf"
63
+ const { Story } = defineMeta();
64
+ </script>
65
+ <Story />
66
+ `,
67
+ });
68
+ const nodes = await extractSvelteASTNodes({ ast });
69
+ const { component } = nodes.storyComponents[0];
70
+ const { exportName, name } = extractStoryAttributesNodes({
71
+ component,
72
+ attributes: ['exportName', 'name'],
73
+ });
74
+ expect(() => getStoryIdentifiers({
75
+ exportNameNode: exportName,
76
+ nameNode: name,
77
+ filename: 'invalid.stories.svelte',
78
+ component,
79
+ })).toThrowErrorMatchingInlineSnapshot(`
80
+ [SB_SVELTE_CSF_PARSER_ANALYSE_STORY_0004 (NoStoryIdentifierError): Missing 'name' or 'exportName' attribute (prop) in a '<Story />' definition in the stories file: 'file://${process.cwd()}/invalid.stories.svelte'.
81
+ All stories must either have a 'name' or an 'exportName' prop, or both.
82
+
83
+ More info: https://github.com/storybookjs/addon-svelte-csf/blob/v${StorybookSvelteCSFError.packageVersion}/ERRORS.md#SB_SVELTE_CSF_PARSER_ANALYSE_STORY_0004
84
+ ]
85
+ `);
86
+ });
87
+ it("it ignores the 'exportName' attribute of '<Story>'s children component", async () => {
88
+ const ast = getSvelteAST({
89
+ code: `
90
+ <script module>
91
+ import { defineMeta } from "@storybook/addon-svelte-csf"
92
+ const { Story } = defineMeta();
93
+ </script>
94
+ <Story exportName="Default">
95
+ <Icon exportName="close" />
96
+ </Story>
97
+ `,
98
+ });
99
+ const nodes = await extractSvelteASTNodes({ ast });
100
+ const { component } = nodes.storyComponents[0];
101
+ const { exportName } = extractStoryAttributesNodes({
102
+ component,
103
+ attributes: ['exportName', 'args'],
104
+ });
105
+ expect(getStoryIdentifiers({
106
+ exportNameNode: exportName,
107
+ nameNode: undefined,
108
+ component,
109
+ })).toEqual({
110
+ exportName: 'Default',
111
+ name: undefined,
112
+ });
113
+ });
114
+ it("extracts both 'exportName' and 'name' attributes", async () => {
115
+ const ast = getSvelteAST({
116
+ code: `
117
+ <script module>
118
+ import { defineMeta } from "@storybook/addon-svelte-csf"
119
+ const { Story } = defineMeta();
120
+ </script>
121
+ <Story exportName="SomeExportName" name="some name" />
122
+ `,
123
+ });
124
+ const nodes = await extractSvelteASTNodes({ ast });
125
+ const { component } = nodes.storyComponents[0];
126
+ const { exportName, name } = extractStoryAttributesNodes({
127
+ component,
128
+ attributes: ['exportName', 'name'],
129
+ });
130
+ expect(getStoryIdentifiers({
131
+ exportNameNode: exportName,
132
+ nameNode: name,
133
+ component,
134
+ })).toEqual({
135
+ exportName: 'SomeExportName',
136
+ name: 'some name',
137
+ });
138
+ });
139
+ it("derives 'exportName' from 'name' attribute when 'exportName' attribute is missing", async () => {
140
+ const ast = getSvelteAST({
141
+ code: `
142
+ <script module>
143
+ import { defineMeta } from "@storybook/addon-svelte-csf"
144
+ const { Story } = defineMeta();
145
+ </script>
146
+ <Story name="some name" />
147
+ `,
148
+ });
149
+ const nodes = await extractSvelteASTNodes({ ast });
150
+ const { component } = nodes.storyComponents[0];
151
+ const { exportName, name } = extractStoryAttributesNodes({
152
+ component,
153
+ attributes: ['exportName', 'name'],
154
+ });
155
+ expect(getStoryIdentifiers({
156
+ exportNameNode: exportName,
157
+ nameNode: name,
158
+ component,
159
+ })).toEqual({
160
+ exportName: 'SomeName',
161
+ name: 'some name',
162
+ });
163
+ });
164
+ it("throws when 'exportName' is not a valid JavaScript variable name", async () => {
165
+ const ast = getSvelteAST({
166
+ code: `
167
+ <script module>
168
+ import { defineMeta } from "@storybook/addon-svelte-csf"
169
+ const { Story } = defineMeta();
170
+ </script>
171
+ <Story exportName="default" />
172
+ `,
173
+ });
174
+ const nodes = await extractSvelteASTNodes({ ast });
175
+ const { component } = nodes.storyComponents[0];
176
+ const { exportName } = extractStoryAttributesNodes({
177
+ component,
178
+ attributes: ['exportName'],
179
+ });
180
+ expect(() => getStoryIdentifiers({
181
+ exportNameNode: exportName,
182
+ nameNode: undefined,
183
+ filename: 'invalid.stories.svelte',
184
+ component,
185
+ })).toThrowErrorMatchingInlineSnapshot(`
186
+ [SB_SVELTE_CSF_PARSER_ANALYSE_STORY_0005 (InvalidStoryExportNameError): Invalid attribute 'exportName' value 'default' found in '<Story />' component inside stories file: file://${process.cwd()}/invalid.stories.svelte
187
+
188
+ 'exportName' value must be a valid JavaScript variable name.
189
+ It must start with a letter, $ or _, followed by letters, numbers, $ or _.
190
+ Reserved words like 'default' are also not allowed (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#reserved_words)
191
+
192
+ More info: https://github.com/storybookjs/addon-svelte-csf/blob/v${StorybookSvelteCSFError.packageVersion}/ERRORS.md#SB_SVELTE_CSF_PARSER_ANALYSE_STORY_0005
193
+ ]
194
+ `);
195
+ });
196
+ });
197
+ describe(getStoriesIdentifiers.name, () => {
198
+ it('extracts multiple <Story /> components identifiers', async () => {
199
+ const ast = getSvelteAST({
200
+ code: `
201
+ <script module>
202
+ import { defineMeta } from "@storybook/addon-svelte-csf"
203
+ const { Story } = defineMeta();
204
+ </script>
205
+
206
+ <Story name="Only name" />
207
+ <Story exportName="OnlyExportName" />
208
+ <Story exportName="BothExportNameAndName" name="Both export name and name" />
209
+ <Story exportName="DifferentExportName" name="ExportName and name, but different" />`,
210
+ });
211
+ const nodes = await extractSvelteASTNodes({ ast });
212
+ expect(getStoriesIdentifiers({ nodes })).toMatchInlineSnapshot(`
213
+ [
214
+ {
215
+ "exportName": "OnlyName",
216
+ "name": "Only name",
217
+ },
218
+ {
219
+ "exportName": "OnlyExportName",
220
+ "name": undefined,
221
+ },
222
+ {
223
+ "exportName": "BothExportNameAndName",
224
+ "name": "Both export name and name",
225
+ },
226
+ {
227
+ "exportName": "DifferentExportName",
228
+ "name": "ExportName and name, but different",
229
+ },
230
+ ]
231
+ `);
232
+ });
233
+ it("throws on identical 'exportName' attributes", async () => {
234
+ const ast = getSvelteAST({
235
+ code: `
236
+ <script module>
237
+ import { defineMeta } from "@storybook/addon-svelte-csf"
238
+ const { Story } = defineMeta();
239
+ </script>
240
+
241
+ <Story exportName="SomeExportName" />
242
+ <Story exportName="OtherExportName" />
243
+ <Story exportName="SomeExportName" />`,
244
+ });
245
+ const nodes = await extractSvelteASTNodes({ ast });
246
+ expect(() => getStoriesIdentifiers({
247
+ nodes,
248
+ filename: 'duplicate-identifiers.stories.svelte',
249
+ })).toThrowErrorMatchingInlineSnapshot(`
250
+ [SB_SVELTE_CSF_PARSER_ANALYSE_STORY_0006 (DuplicateStoryIdentifiersError): Duplicate exportNames found between two '<Story />' definitions in stories file: file://${process.cwd()}/duplicate-identifiers.stories.svelte
251
+
252
+ First instance: <Story name={undefined} exportName="SomeExportName" ... />
253
+ Second instance: <Story name={undefined} exportName="SomeExportName" ... />
254
+
255
+ This can happen when 'exportName' is implicitly derived by 'name'.
256
+ Complex names will be simplified to a PascalCased, valid JavaScript variable name,
257
+ eg. 'Some story name!!' will be converted to 'SomeStoryName'.
258
+ You can fix this collision by providing a unique 'exportName' prop with <Story exportName="SomeUniqueExportName" ... />.
259
+
260
+ More info: https://github.com/storybookjs/addon-svelte-csf/blob/v${StorybookSvelteCSFError.packageVersion}/ERRORS.md#SB_SVELTE_CSF_PARSER_ANALYSE_STORY_0006
261
+ ]
262
+ `);
263
+ });
264
+ it("throws on identical 'exportName' attributes when deriving from 'name' attributes", async () => {
265
+ const ast = getSvelteAST({
266
+ code: `
267
+ <script module>
268
+ import { defineMeta } from "@storybook/addon-svelte-csf"
269
+ const { Story } = defineMeta();
270
+ </script>
271
+
272
+ <Story exportName="SomeStoryName" />
273
+ <Story name="some story name!!!" />`,
274
+ });
275
+ const nodes = await extractSvelteASTNodes({ ast });
276
+ expect(() => getStoriesIdentifiers({
277
+ nodes,
278
+ filename: 'duplicate-identifiers.stories.svelte',
279
+ })).toThrowErrorMatchingInlineSnapshot(`
280
+ [SB_SVELTE_CSF_PARSER_ANALYSE_STORY_0006 (DuplicateStoryIdentifiersError): Duplicate exportNames found between two '<Story />' definitions in stories file: file://${process.cwd()}/duplicate-identifiers.stories.svelte
281
+
282
+ First instance: <Story name={undefined} exportName="SomeStoryName" ... />
283
+ Second instance: <Story name="some story name!!!" exportName="SomeStoryName" ... />
284
+
285
+ This can happen when 'exportName' is implicitly derived by 'name'.
286
+ Complex names will be simplified to a PascalCased, valid JavaScript variable name,
287
+ eg. 'Some story name!!' will be converted to 'SomeStoryName'.
288
+ You can fix this collision by providing a unique 'exportName' prop with <Story exportName="SomeUniqueExportName" ... />.
289
+
290
+ More info: https://github.com/storybookjs/addon-svelte-csf/blob/v${StorybookSvelteCSFError.packageVersion}/ERRORS.md#SB_SVELTE_CSF_PARSER_ANALYSE_STORY_0006
291
+ ]
292
+ `);
293
+ });
294
+ });
@@ -0,0 +1 @@
1
+ export {};