Skip to content

Commit e6663f2

Browse files
Merge pull request #32543 from storybookjs/yann/csf-factories-codemod-more-ts-support
CSF: Enhance config-to-csf-factory to support type wrappers
2 parents 5a3dbff + bc4185b commit e6663f2

File tree

2 files changed

+80
-22
lines changed

2 files changed

+80
-22
lines changed

code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ describe('preview specific functionality', () => {
242242
});
243243
`);
244244
});
245-
it('should work', async () => {
245+
it('should wrap definePreview for mixed annotations and default export', async () => {
246246
await expect(
247247
transform(dedent`
248248
export const decorators = [1]
@@ -259,4 +259,61 @@ describe('preview specific functionality', () => {
259259
});
260260
`);
261261
});
262+
263+
it('should wrap definePreview for const defined preview with type annotations', async () => {
264+
await expect(
265+
transform(dedent`
266+
import { type Preview } from '@storybook/react-vite';
267+
268+
const preview = {
269+
decorators: [],
270+
271+
parameters: {
272+
options: {}
273+
}
274+
} satisfies Preview;
275+
276+
export default preview;
277+
278+
`)
279+
).resolves.toMatchInlineSnapshot(`
280+
import { definePreview } from '@storybook/react-vite';
281+
282+
export default definePreview({
283+
decorators: [],
284+
285+
parameters: {
286+
options: {},
287+
},
288+
});
289+
`);
290+
});
291+
292+
it('should wrap definePreview for mixed annotations and default const export', async () => {
293+
await expect(
294+
transform(dedent`
295+
import { type Preview } from '@storybook/react-vite';
296+
export const decorators = []
297+
const preview = {
298+
299+
parameters: {
300+
options: {}
301+
}
302+
} satisfies Preview;
303+
304+
export default preview;
305+
306+
`)
307+
).resolves.toMatchInlineSnapshot(`
308+
import { definePreview } from '@storybook/react-vite';
309+
310+
export default definePreview({
311+
decorators: [],
312+
313+
parameters: {
314+
options: {},
315+
},
316+
});
317+
`);
318+
});
262319
});

code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@ export async function configToCsfFactory(
3232
const defineConfigProps = getConfigProperties(exportDecls, { configType });
3333
const hasNamedExports = defineConfigProps.length > 0;
3434

35+
function findDeclarationNodeIndex(declarationName: string): number {
36+
return programNode.body.findIndex(
37+
(n) =>
38+
t.isVariableDeclaration(n) &&
39+
n.declarations.some((d) => {
40+
let declaration = d.init;
41+
// unwrap TS type annotations
42+
if (t.isTSAsExpression(declaration) || t.isTSSatisfiesExpression(declaration)) {
43+
declaration = declaration.expression;
44+
}
45+
return (
46+
t.isIdentifier(d.id) &&
47+
d.id.name === declarationName &&
48+
t.isObjectExpression(declaration)
49+
);
50+
})
51+
);
52+
}
53+
3554
/**
3655
* Scenario 1: Mixed exports
3756
*
@@ -60,16 +79,7 @@ export async function configToCsfFactory(
6079
if (t.isExportDefaultDeclaration(node) && t.isIdentifier(node.declaration)) {
6180
const declarationName = node.declaration.name;
6281

63-
declarationNodeIndex = programNode.body.findIndex(
64-
(n) =>
65-
t.isVariableDeclaration(n) &&
66-
n.declarations.some(
67-
(d) =>
68-
t.isIdentifier(d.id) &&
69-
d.id.name === declarationName &&
70-
t.isObjectExpression(d.init)
71-
)
72-
);
82+
declarationNodeIndex = findDeclarationNodeIndex(declarationName);
7383

7484
if (declarationNodeIndex !== -1) {
7585
exportDefaultNode = node;
@@ -97,7 +107,7 @@ export async function configToCsfFactory(
97107
/**
98108
* Scenario 2: Default exports
99109
*
100-
* - Syntax 1: `default export const config = {}; export default config;`
110+
* - Syntax 1: `const config = {}; export default config;`
101111
* - Syntax 2: `export default {};`
102112
*
103113
* Transform into: `export default defineMain({})`
@@ -112,16 +122,7 @@ export async function configToCsfFactory(
112122
if (t.isExportDefaultDeclaration(node) && t.isIdentifier(node.declaration)) {
113123
const declarationName = node.declaration.name;
114124

115-
declarationNodeIndex = programNode.body.findIndex(
116-
(n) =>
117-
t.isVariableDeclaration(n) &&
118-
n.declarations.some(
119-
(d) =>
120-
t.isIdentifier(d.id) &&
121-
d.id.name === declarationName &&
122-
t.isObjectExpression(d.init)
123-
)
124-
);
125+
declarationNodeIndex = findDeclarationNodeIndex(declarationName);
125126

126127
if (declarationNodeIndex !== -1) {
127128
exportDefaultNode = node;

0 commit comments

Comments
 (0)