From f1a2c535f5d773e1e2d69792e2e91af9e7908793 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 13 Jan 2025 14:48:20 +0100 Subject: [PATCH 01/24] Csf Tools: Support CSF4 in enrichCsf for source extraction --- code/core/src/csf-tools/enrichCsf.test.ts | 45 +++++++++++++++++++++++ code/core/src/csf-tools/enrichCsf.ts | 11 +++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/code/core/src/csf-tools/enrichCsf.test.ts b/code/core/src/csf-tools/enrichCsf.test.ts index e8c0ce6250eb..1f7786f9e6f9 100644 --- a/code/core/src/csf-tools/enrichCsf.test.ts +++ b/code/core/src/csf-tools/enrichCsf.test.ts @@ -149,6 +149,51 @@ describe('enrichCsf', () => { }; `); }); + it('csf4', () => { + expect( + enrich( + dedent` + // compiled code + import {config} from "/.storybook/preview.ts"; + const meta = config.meta({ + args: { + label: "Hello world!" + } + }); + export const Story = meta.story({}); + `, + dedent` + // original code + import {config} from "#.storybook/preview.ts"; + const meta = config.meta({ + args: { + label: "Hello world!" + } + }); + export const Story = meta.story({}); + ` + ) + ).toMatchInlineSnapshot(` + // compiled code + import { config } from "/.storybook/preview.ts"; + const meta = config.meta({ + args: { + label: "Hello world!" + } + }); + export const Story = meta.story({}); + Story.annotations.parameters = { + ...Story.annotations.parameters, + docs: { + ...Story.annotations.parameters?.docs, + source: { + originalSource: "meta.story({})", + ...Story.annotations.parameters?.docs?.source + } + } + }; + `); + }); it('multiple stories', () => { expect( enrich( diff --git a/code/core/src/csf-tools/enrichCsf.ts b/code/core/src/csf-tools/enrichCsf.ts index aa4a205e6bf3..1413249090df 100644 --- a/code/core/src/csf-tools/enrichCsf.ts +++ b/code/core/src/csf-tools/enrichCsf.ts @@ -15,11 +15,20 @@ export const enrichCsfStory = ( options?: EnrichCsfOptions ) => { const storyExport = csfSource.getStoryExport(key); + const isCsfFactory = + t.isCallExpression(storyExport) && + t.isMemberExpression(storyExport.callee) && + t.isIdentifier(storyExport.callee.object) && + storyExport.callee.object.name === 'meta'; const source = !options?.disableSource && extractSource(storyExport); const description = !options?.disableDescription && extractDescription(csfSource._storyStatements[key]); const parameters = []; - const originalParameters = t.memberExpression(t.identifier(key), t.identifier('parameters')); + // in csf1/2/3 we use Story.parameters, in csf4 we use Story.annotations.parameters + const baseStoryObject = isCsfFactory + ? t.memberExpression(t.identifier(key), t.identifier('annotations')) + : t.identifier(key); + const originalParameters = t.memberExpression(baseStoryObject, t.identifier('parameters')); parameters.push(t.spreadElement(originalParameters)); const optionalDocs = t.optionalMemberExpression( originalParameters, From 6c27056c9c881c7e681661f42cef5b3884088fa4 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 13 Jan 2025 15:12:32 +0100 Subject: [PATCH 02/24] Apply suggestions from code review Co-authored-by: Michael Shilman --- code/core/src/csf-tools/enrichCsf.test.ts | 2 +- code/core/src/csf-tools/enrichCsf.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/core/src/csf-tools/enrichCsf.test.ts b/code/core/src/csf-tools/enrichCsf.test.ts index 1f7786f9e6f9..e46c908bd658 100644 --- a/code/core/src/csf-tools/enrichCsf.test.ts +++ b/code/core/src/csf-tools/enrichCsf.test.ts @@ -149,7 +149,7 @@ describe('enrichCsf', () => { }; `); }); - it('csf4', () => { + it('csf factories', () => { expect( enrich( dedent` diff --git a/code/core/src/csf-tools/enrichCsf.ts b/code/core/src/csf-tools/enrichCsf.ts index 1413249090df..11b1a239c7ae 100644 --- a/code/core/src/csf-tools/enrichCsf.ts +++ b/code/core/src/csf-tools/enrichCsf.ts @@ -24,7 +24,7 @@ export const enrichCsfStory = ( const description = !options?.disableDescription && extractDescription(csfSource._storyStatements[key]); const parameters = []; - // in csf1/2/3 we use Story.parameters, in csf4 we use Story.annotations.parameters + // in csf 1/2/3 use Story.parameters; CSF factories use Story.annotations.parameters const baseStoryObject = isCsfFactory ? t.memberExpression(t.identifier(key), t.identifier('annotations')) : t.identifier(key); From 659930e1c7a5c50e764525884b3b0606f7602331 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 15 Jan 2025 13:58:14 +0100 Subject: [PATCH 03/24] Use csf-tools in csf factory codemod --- code/core/src/csf-tools/CsfFile.ts | 12 +- .../transforms/__tests__/csf-3-to-4.test.ts | 105 +++---- code/lib/codemod/src/transforms/csf-3-to-4.ts | 274 ++++++++++-------- 3 files changed, 212 insertions(+), 179 deletions(-) diff --git a/code/core/src/csf-tools/CsfFile.ts b/code/core/src/csf-tools/CsfFile.ts index d7ed7fe8eeb9..cfbc9b08f957 100644 --- a/code/core/src/csf-tools/CsfFile.ts +++ b/code/core/src/csf-tools/CsfFile.ts @@ -4,6 +4,7 @@ import { readFile, writeFile } from 'node:fs/promises'; import { BabelFileClass, type GeneratorOptions, + type NodePath, type RecastOptions, babelParse, generate, @@ -255,10 +256,14 @@ export class CsfFile { _storyExports: Record = {}; + _storyPaths: Record> = {}; + _metaStatement: t.Statement | undefined; _metaNode: t.Expression | undefined; + _metaPath: NodePath | undefined; + _metaVariableName: string | undefined; _metaIsFactory: boolean | undefined; @@ -466,10 +471,13 @@ export class CsfFile { self._options.fileName ); } + + self._metaPath = path; }, }, ExportNamedDeclaration: { - enter({ node, parent }) { + enter(path) { + const { node, parent } = path; let declarations; if (t.isVariableDeclaration(node.declaration)) { declarations = node.declaration.declarations.filter((d) => t.isVariableDeclarator(d)); @@ -487,6 +495,7 @@ export class CsfFile { return; } self._storyExports[exportName] = decl; + self._storyPaths[exportName] = path; self._storyStatements[exportName] = node; let name = storyNameFromExport(exportName); if (self._storyAnnotations[exportName]) { @@ -611,6 +620,7 @@ export class CsfFile { } else { self._storyAnnotations[exportName] = {}; self._storyStatements[exportName] = decl; + self._storyPaths[exportName] = path; self._stories[exportName] = { id: 'FIXME', name: exportName, diff --git a/code/lib/codemod/src/transforms/__tests__/csf-3-to-4.test.ts b/code/lib/codemod/src/transforms/__tests__/csf-3-to-4.test.ts index 8cf66dff1ea2..7dcef73c2e53 100644 --- a/code/lib/codemod/src/transforms/__tests__/csf-3-to-4.test.ts +++ b/code/lib/codemod/src/transforms/__tests__/csf-3-to-4.test.ts @@ -21,10 +21,9 @@ describe('csf-3-to-4', () => { export default meta; `) ).resolves.toMatchInlineSnapshot(` - import { config } from "#.storybook/preview"; - const meta = config.meta({ - title: 'Component' - }); + import { config } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); `); }); @@ -34,9 +33,10 @@ describe('csf-3-to-4', () => { export default { title: 'Component' }; `) ).resolves.toMatchInlineSnapshot(` - import { config } from "#.storybook/preview"; + import { config } from '#.storybook/preview'; + const meta = config.meta({ - title: 'Component' + title: 'Component', }); `); }); @@ -48,10 +48,9 @@ describe('csf-3-to-4', () => { export default componentMeta; `) ).resolves.toMatchInlineSnapshot(` - import { config } from "#.storybook/preview"; - const meta = config.meta({ - title: 'Component' - }); + import { config } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); `); }); @@ -66,15 +65,12 @@ describe('csf-3-to-4', () => { }; `) ).resolves.toMatchInlineSnapshot(` - import { config } from "#.storybook/preview"; - const meta = config.meta({ - title: 'Component' - }); + import { config } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); export const A = meta.story({ - args: { - primary: true - }, - render: args => + args: { primary: true }, + render: (args) => , }); `); }); @@ -91,15 +87,12 @@ describe('csf-3-to-4', () => { }; `) ).resolves.toMatchInlineSnapshot(` - import { decorators, config } from "#.storybook/preview"; - const meta = config.meta({ - title: 'Component' - }); + import { config, decorators } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); export const A = meta.story({ - args: { - primary: true - }, - render: args => + args: { primary: true }, + render: (args) => , }); `); }); @@ -119,17 +112,14 @@ describe('csf-3-to-4', () => { `; it('meta satisfies syntax', async () => { await expect(transform(metaSatisfies)).resolves.toMatchInlineSnapshot(` - import { config } from "#.storybook/preview"; - import { Meta, StoryObj as CSF3 } from '@storybook/react'; + import { config } from '#.storybook/preview'; + import { ComponentProps } from './Component'; - const meta = config.meta({ - title: 'Component', - component: Component - }); + + const meta = config.meta({ title: 'Component', component: Component }); + export const A = meta.story({ - args: { - primary: true - } + args: { primary: true }, }); `); }); @@ -147,17 +137,14 @@ describe('csf-3-to-4', () => { `; it('meta as syntax', async () => { await expect(transform(metaAs)).resolves.toMatchInlineSnapshot(` - import { config } from "#.storybook/preview"; - import { Meta, StoryObj as CSF3 } from '@storybook/react'; + import { config } from '#.storybook/preview'; + import { ComponentProps } from './Component'; - const meta = config.meta({ - title: 'Component', - component: Component - }); + + const meta = config.meta({ title: 'Component', component: Component }); + export const A = meta.story({ - args: { - primary: true - } + args: { primary: true }, }); `); }); @@ -175,17 +162,14 @@ describe('csf-3-to-4', () => { `; it('story satisfies syntax', async () => { await expect(transform(storySatisfies)).resolves.toMatchInlineSnapshot(` - import { config } from "#.storybook/preview"; - import { Meta, StoryObj as CSF3 } from '@storybook/react'; + import { config } from '#.storybook/preview'; + import { ComponentProps } from './Component'; - const meta = config.meta({ - title: 'Component', - component: Component - }); + + const meta = config.meta({ title: 'Component', component: Component }); + export const A = meta.story({ - args: { - primary: true - } + args: { primary: true }, }); `); }); @@ -203,17 +187,14 @@ describe('csf-3-to-4', () => { `; it('story as syntax', async () => { await expect(transform(storyAs)).resolves.toMatchInlineSnapshot(` - import { config } from "#.storybook/preview"; - import { Meta, StoryObj as CSF3 } from '@storybook/react'; + import { config } from '#.storybook/preview'; + import { ComponentProps } from './Component'; - const meta = config.meta({ - title: 'Component', - component: Component - }); + + const meta = config.meta({ title: 'Component', component: Component }); + export const A = meta.story({ - args: { - primary: true - } + args: { primary: true }, }); `); }); diff --git a/code/lib/codemod/src/transforms/csf-3-to-4.ts b/code/lib/codemod/src/transforms/csf-3-to-4.ts index 7efe6a430c06..9d8856f25150 100644 --- a/code/lib/codemod/src/transforms/csf-3-to-4.ts +++ b/code/lib/codemod/src/transforms/csf-3-to-4.ts @@ -1,27 +1,24 @@ /* eslint-disable no-underscore-dangle */ -import { isValidPreviewPath, loadCsf } from '@storybook/core/csf-tools'; +import { types as t, traverse } from '@storybook/core/babel'; + +import { isValidPreviewPath, loadCsf, printCsf } from '@storybook/core/csf-tools'; -import type { BabelFile } from '@babel/core'; import * as babel from '@babel/core'; -import { - isIdentifier, - isImportDeclaration, - isImportSpecifier, - isObjectExpression, - isTSAsExpression, - isTSSatisfiesExpression, - isVariableDeclaration, -} from '@babel/types'; import type { FileInfo } from 'jscodeshift'; +import prettier from 'prettier'; + +const logger = console; export default async function transform(info: FileInfo) { const csf = loadCsf(info.source, { makeTitle: (title) => title }); const fileNode = csf._ast; - // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606 - const file: BabelFile = new babel.File( - { filename: info.path }, - { code: info.source, ast: fileNode } - ); + + try { + csf.parse(); + } catch (err) { + logger.log(`Error ${err}, skipping`); + return info.source; + } const metaVariableName = 'meta'; @@ -34,10 +31,10 @@ export default async function transform(info: FileInfo) { let foundConfigImport = false; programNode.body.forEach((node) => { - if (isImportDeclaration(node) && isValidPreviewPath(node.source.value)) { + if (t.isImportDeclaration(node) && isValidPreviewPath(node.source.value)) { const hasConfigSpecifier = node.specifiers.some( (specifier) => - isImportSpecifier(specifier) && isIdentifier(specifier.imported, { name: 'config' }) + t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported, { name: 'config' }) ); if (!hasConfigSpecifier) { @@ -53,110 +50,93 @@ export default async function transform(info: FileInfo) { } }); - let hasMeta = false; + const hasMeta = !!csf._meta; - file.path.traverse({ - // Meta export - ExportDefaultDeclaration: (path) => { - hasMeta = true; - const declaration = path.node.declaration; + Object.entries(csf._storyExports).forEach(([key, decl]) => { + const id = decl.id; + const declarator = decl as babel.types.VariableDeclarator; + let init = t.isVariableDeclarator(declarator) ? declarator.init : undefined; - /** - * Transform inline default export: `export default { title: 'A' };` - * - * Into a meta call: `const meta = config.meta({ title: 'A' });` - */ - if (isObjectExpression(declaration)) { - const metaVariable = babel.types.variableDeclaration('const', [ - babel.types.variableDeclarator( - babel.types.identifier(metaVariableName), - babel.types.callExpression( - babel.types.memberExpression( - babel.types.identifier('config'), - babel.types.identifier('meta') - ), - [declaration] - ) - ), - ]); - - path.replaceWith(metaVariable); - } else if (isIdentifier(declaration)) { - /** - * Transform const declared metas: - * - * `const meta = {}; export default meta;` - * - * Into a meta call: - * - * `const meta = config.meta({ title: 'A' });` - */ - const binding = path.scope.getBinding(declaration.name); - if (binding && binding.path.isVariableDeclarator()) { - const originalName = declaration.name; - - // Always rename the meta variable to 'meta' - binding.path.node.id = babel.types.identifier(metaVariableName); - - let init = binding.path.node.init; - if (isTSSatisfiesExpression(init) || isTSAsExpression(init)) { - init = init.expression; - } - if (isObjectExpression(init)) { - binding.path.node.init = babel.types.callExpression( - babel.types.memberExpression( - babel.types.identifier('config'), - babel.types.identifier('meta') - ), - [init] - ); - } + if (t.isIdentifier(id) && init) { + if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) { + init = init.expression; + } - // Update all references to the original name - path.scope.rename(originalName, metaVariableName); + if (t.isObjectExpression(init)) { + const typeAnnotation = id.typeAnnotation; + // Remove type annotation as it's now inferred + if (typeAnnotation) { + id.typeAnnotation = null; } - // Remove the default export, it's not needed anymore - path.remove(); - } - }, - // Story export - ExportNamedDeclaration: (path) => { - const declaration = path.node.declaration; - - if (!declaration || !isVariableDeclaration(declaration) || !hasMeta) { - return; + // Wrap the object in `meta.story()` + declarator.init = babel.types.callExpression( + babel.types.memberExpression( + babel.types.identifier(metaVariableName), + babel.types.identifier('story') + ), + [init] + ); } + } + }); - declaration.declarations.forEach((decl) => { - const id = decl.id; - let init = decl.init; + // modify meta + if (csf._metaPath) { + const declaration = csf._metaPath.node.declaration; + if (t.isObjectExpression(declaration)) { + const metaVariable = babel.types.variableDeclaration('const', [ + babel.types.variableDeclarator( + babel.types.identifier(metaVariableName), + babel.types.callExpression( + babel.types.memberExpression( + babel.types.identifier('config'), + babel.types.identifier('meta') + ), + [declaration] + ) + ), + ]); + csf._metaPath.replaceWith(metaVariable); + } else if (t.isIdentifier(declaration)) { + /** + * Transform const declared metas: + * + * `const meta = {}; export default meta;` + * + * Into a meta call: + * + * `const meta = config.meta({ title: 'A' });` + */ + const binding = csf._metaPath.scope.getBinding(declaration.name); + if (binding && binding.path.isVariableDeclarator()) { + const originalName = declaration.name; - if (isIdentifier(id) && init) { - if (isTSSatisfiesExpression(init) || isTSAsExpression(init)) { - init = init.expression; - } + // Always rename the meta variable to 'meta' + binding.path.node.id = babel.types.identifier(metaVariableName); - if (isObjectExpression(init)) { - const typeAnnotation = id.typeAnnotation; - // Remove type annotation as it's now inferred - if (typeAnnotation) { - id.typeAnnotation = null; - } - - // Wrap the object in `meta.story()` - decl.init = babel.types.callExpression( - babel.types.memberExpression( - babel.types.identifier(metaVariableName), - babel.types.identifier('story') - ), - [init] - ); - } + let init = binding.path.node.init; + if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) { + init = init.expression; } - }); - }, - }); + if (t.isObjectExpression(init)) { + binding.path.node.init = babel.types.callExpression( + babel.types.memberExpression( + babel.types.identifier('config'), + babel.types.identifier('meta') + ), + [init] + ); + } + + // Update all references to the original name + csf._metaPath.scope.rename(originalName, metaVariableName); + } + + // Remove the default export, it's not needed anymore + csf._metaPath.remove(); + } + } if (hasMeta && !foundConfigImport) { const configImport = babel.types.importDeclaration( @@ -171,9 +151,71 @@ export default async function transform(info: FileInfo) { programNode.body.unshift(configImport); } - // Generate the transformed code - const { code } = babel.transformFromAstSync(fileNode, info.source, { - parserOpts: { sourceType: 'module' }, + function isSpecifierUsed(name: string) { + let isUsed = false; + + // Traverse the AST and check for usage of the name + traverse(programNode, { + Identifier(path) { + if (path.node.name === name) { + isUsed = true; + // Stop traversal early if we've found a match + path.stop(); + } + }, + }); + + return isUsed; + } + + // Remove type imports – now inferred – from @storybook/* packages + const disallowlist = [ + 'Story', + 'StoryFn', + 'StoryObj', + 'Meta', + 'MetaObj', + 'ComponentStory', + 'ComponentMeta', + ]; + + programNode.body = programNode.body.filter((node) => { + if (t.isImportDeclaration(node)) { + const { source, specifiers } = node; + + if (source.value.startsWith('@storybook/')) { + const allowedSpecifiers = specifiers.filter((specifier) => { + if (t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) { + return !disallowlist.includes(specifier.imported.name); + } + // Retain non-specifier imports (e.g., namespace imports) + return true; + }); + + // Remove the entire import if no specifiers are left + if (allowedSpecifiers.length > 0) { + node.specifiers = allowedSpecifiers; + return true; + } + + // Remove the import if no specifiers remain + return false; + } + } + + // Retain all other nodes + return true; }); - return code; + + let output = printCsf(csf).code; + + try { + output = await prettier.format(output, { + ...(await prettier.resolveConfig(info.path)), + filepath: info.path, + }); + } catch (e) { + logger.log(`Failed applying prettier to ${info.path}.`); + } + return output; } From 7db0050290d8b8291c40f1f0d662c2eaea92133f Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 14 Jan 2025 15:01:37 +0100 Subject: [PATCH 04/24] Add defineConfig helper for main.js --- code/core/src/common/defineConfig.ts | 5 +++++ code/core/src/common/index.ts | 1 + code/frameworks/angular/src/types.ts | 5 +++++ code/frameworks/ember/src/types.ts | 5 +++++ code/frameworks/experimental-nextjs-vite/src/types.ts | 5 +++++ code/frameworks/html-vite/src/types.ts | 5 +++++ code/frameworks/html-webpack5/src/types.ts | 5 +++++ code/frameworks/nextjs/src/types.ts | 5 +++++ code/frameworks/preact-vite/src/types.ts | 5 +++++ code/frameworks/preact-webpack5/src/types.ts | 5 +++++ code/frameworks/react-native-web-vite/src/types.ts | 5 +++++ code/frameworks/react-vite/src/types.ts | 5 +++++ code/frameworks/react-webpack5/src/types.ts | 5 +++++ code/frameworks/server-webpack5/src/types.ts | 5 +++++ code/frameworks/svelte-vite/src/types.ts | 5 +++++ code/frameworks/svelte-webpack5/src/types.ts | 5 +++++ code/frameworks/sveltekit/src/types.ts | 5 +++++ code/frameworks/vue3-vite/src/types.ts | 5 +++++ code/frameworks/vue3-webpack5/src/types.ts | 5 +++++ code/frameworks/web-components-vite/src/types.ts | 5 +++++ code/frameworks/web-components-webpack5/src/types.ts | 5 +++++ 21 files changed, 101 insertions(+) create mode 100644 code/core/src/common/defineConfig.ts diff --git a/code/core/src/common/defineConfig.ts b/code/core/src/common/defineConfig.ts new file mode 100644 index 000000000000..08006b683343 --- /dev/null +++ b/code/core/src/common/defineConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from '../types/modules/core-common'; + +export function defineConfig(config: TConfig): TConfig { + return config; +} diff --git a/code/core/src/common/index.ts b/code/core/src/common/index.ts index 6166e285ab05..dcec4e025c53 100644 --- a/code/core/src/common/index.ts +++ b/code/core/src/common/index.ts @@ -42,6 +42,7 @@ export * from './utils/formatter'; export * from './utils/get-story-id'; export * from './utils/posix'; export * from './js-package-manager'; +export * from './defineConfig'; export { versions }; diff --git a/code/frameworks/angular/src/types.ts b/code/frameworks/angular/src/types.ts index a30e2174efd6..1ba889dc90ff 100644 --- a/code/frameworks/angular/src/types.ts +++ b/code/frameworks/angular/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import { CompatibleString } from 'storybook/internal/types'; import { @@ -48,3 +49,7 @@ export interface AngularOptions { enableIvy?: boolean; enableNgcc?: boolean; } + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/ember/src/types.ts b/code/frameworks/ember/src/types.ts index ee6ef8e0fe5b..236840db2f10 100644 --- a/code/frameworks/ember/src/types.ts +++ b/code/frameworks/ember/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -48,3 +49,7 @@ declare global { // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/naming-convention, no-var var __EMBER_GENERATED_DOC_JSON__: any; } + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/experimental-nextjs-vite/src/types.ts b/code/frameworks/experimental-nextjs-vite/src/types.ts index 0221787dccb6..6c04f243b6fc 100644 --- a/code/frameworks/experimental-nextjs-vite/src/types.ts +++ b/code/frameworks/experimental-nextjs-vite/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { BuilderOptions } from '@storybook/builder-vite'; @@ -32,3 +33,7 @@ type StorybookConfigFramework = { /** The interface for Storybook configuration in `main.ts` files. */ export type StorybookConfig = Omit & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/html-vite/src/types.ts b/code/frameworks/html-vite/src/types.ts index 34d1e116e8d7..107ae09ac607 100644 --- a/code/frameworks/html-vite/src/types.ts +++ b/code/frameworks/html-vite/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -36,3 +37,7 @@ export type StorybookConfig = Omit< > & StorybookConfigVite & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/html-webpack5/src/types.ts b/code/frameworks/html-webpack5/src/types.ts index d29860b85762..b53f57f9cc66 100644 --- a/code/frameworks/html-webpack5/src/types.ts +++ b/code/frameworks/html-webpack5/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -43,3 +44,7 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/nextjs/src/types.ts b/code/frameworks/nextjs/src/types.ts index 42148ef8517b..f2a83028fe58 100644 --- a/code/frameworks/nextjs/src/types.ts +++ b/code/frameworks/nextjs/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -48,3 +49,7 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/preact-vite/src/types.ts b/code/frameworks/preact-vite/src/types.ts index 503f7cd5d327..317de3d9732b 100644 --- a/code/frameworks/preact-vite/src/types.ts +++ b/code/frameworks/preact-vite/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -36,3 +37,7 @@ export type StorybookConfig = Omit< > & StorybookConfigVite & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/preact-webpack5/src/types.ts b/code/frameworks/preact-webpack5/src/types.ts index a09f8e3695c1..678294d9ec8f 100644 --- a/code/frameworks/preact-webpack5/src/types.ts +++ b/code/frameworks/preact-webpack5/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -43,3 +44,7 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/react-native-web-vite/src/types.ts b/code/frameworks/react-native-web-vite/src/types.ts index 5558722e03d7..7436accebc84 100644 --- a/code/frameworks/react-native-web-vite/src/types.ts +++ b/code/frameworks/react-native-web-vite/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -30,3 +31,7 @@ export type StorybookConfig = Omit & { options: FrameworkOptions; }; }; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/react-vite/src/types.ts b/code/frameworks/react-vite/src/types.ts index 58cba705bf56..be84bca936ca 100644 --- a/code/frameworks/react-vite/src/types.ts +++ b/code/frameworks/react-vite/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -63,3 +64,7 @@ export type StorybookConfig = Omit< StorybookConfigFramework & { typescript?: Partial; }; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/react-webpack5/src/types.ts b/code/frameworks/react-webpack5/src/types.ts index 6366ca3cd857..006a08cdf667 100644 --- a/code/frameworks/react-webpack5/src/types.ts +++ b/code/frameworks/react-webpack5/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -44,3 +45,7 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/server-webpack5/src/types.ts b/code/frameworks/server-webpack5/src/types.ts index 1040a0fea8bb..fd7c5d91d960 100644 --- a/code/frameworks/server-webpack5/src/types.ts +++ b/code/frameworks/server-webpack5/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -43,3 +44,7 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/svelte-vite/src/types.ts b/code/frameworks/svelte-vite/src/types.ts index d6efce7feaef..908b77101109 100644 --- a/code/frameworks/svelte-vite/src/types.ts +++ b/code/frameworks/svelte-vite/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -36,3 +37,7 @@ export type StorybookConfig = Omit< > & StorybookConfigVite & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/svelte-webpack5/src/types.ts b/code/frameworks/svelte-webpack5/src/types.ts index 2770043e12dd..62381933e4ed 100644 --- a/code/frameworks/svelte-webpack5/src/types.ts +++ b/code/frameworks/svelte-webpack5/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -44,3 +45,7 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/sveltekit/src/types.ts b/code/frameworks/sveltekit/src/types.ts index 975a184f4545..6aef9a709fd3 100644 --- a/code/frameworks/sveltekit/src/types.ts +++ b/code/frameworks/sveltekit/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -63,3 +64,7 @@ export type SvelteKitParameters = Partial<{ enhance: typeof enhance; }; }>; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/vue3-vite/src/types.ts b/code/frameworks/vue3-vite/src/types.ts index d02b791f294b..6ac74e77f10f 100644 --- a/code/frameworks/vue3-vite/src/types.ts +++ b/code/frameworks/vue3-vite/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -99,3 +100,7 @@ export type VueDocgenInfoEntry< ? VueDocgenInfo<'vue-component-meta'>[Exclude] : VueDocgenInfo<'vue-docgen-api'>[Exclude] >; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/vue3-webpack5/src/types.ts b/code/frameworks/vue3-webpack5/src/types.ts index 9d6aa2467884..bd1b1eac450c 100644 --- a/code/frameworks/vue3-webpack5/src/types.ts +++ b/code/frameworks/vue3-webpack5/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -43,3 +44,7 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/web-components-vite/src/types.ts b/code/frameworks/web-components-vite/src/types.ts index cb8328dc9770..8954bf3221df 100644 --- a/code/frameworks/web-components-vite/src/types.ts +++ b/code/frameworks/web-components-vite/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -36,3 +37,7 @@ export type StorybookConfig = Omit< > & StorybookConfigVite & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/web-components-webpack5/src/types.ts b/code/frameworks/web-components-webpack5/src/types.ts index 0cd693b1fd4a..f6d1c9552392 100644 --- a/code/frameworks/web-components-webpack5/src/types.ts +++ b/code/frameworks/web-components-webpack5/src/types.ts @@ -1,3 +1,4 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -43,3 +44,7 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} From ebe6bf9a7a0ee05712550147a6f888bc24e25198 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 14 Jan 2025 16:51:43 +0100 Subject: [PATCH 05/24] move defineConfig to its own import path --- code/frameworks/angular/package.json | 15 +++++++++++++++ .../angular/src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/angular/src/types.ts | 5 ----- code/frameworks/ember/package.json | 15 +++++++++++++++ .../ember/src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/ember/src/types.ts | 5 ----- .../experimental-nextjs-vite/package.json | 7 +++++++ .../src/csf-factory/defineMainConfig.ts | 7 +++++++ .../experimental-nextjs-vite/src/types.ts | 5 ----- code/frameworks/html-vite/package.json | 9 ++++++++- .../html-vite/src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/html-vite/src/types.ts | 5 ----- code/frameworks/html-webpack5/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/html-webpack5/src/types.ts | 5 ----- code/frameworks/nextjs/package.json | 7 +++++++ .../nextjs/src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/nextjs/src/types.ts | 5 ----- code/frameworks/preact-vite/package.json | 6 ++++++ .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/preact-vite/src/types.ts | 5 ----- code/frameworks/preact-webpack5/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/preact-webpack5/src/types.ts | 5 ----- .../frameworks/react-native-web-vite/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ .../frameworks/react-native-web-vite/src/types.ts | 5 ----- code/frameworks/react-vite/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/react-vite/src/types.ts | 5 ----- code/frameworks/react-webpack5/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/react-webpack5/src/types.ts | 5 ----- code/frameworks/server-webpack5/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/server-webpack5/src/types.ts | 5 ----- code/frameworks/svelte-vite/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/svelte-vite/src/types.ts | 5 ----- code/frameworks/svelte-webpack5/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/svelte-webpack5/src/types.ts | 5 ----- code/frameworks/sveltekit/package.json | 9 ++++++++- .../sveltekit/src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/sveltekit/src/types.ts | 5 ----- code/frameworks/vue3-vite/package.json | 9 ++++++++- .../vue3-vite/src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/vue3-vite/src/types.ts | 5 ----- code/frameworks/vue3-webpack5/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/vue3-webpack5/src/types.ts | 5 ----- code/frameworks/web-components-vite/package.json | 7 +++++++ .../src/csf-factory/defineMainConfig.ts | 7 +++++++ code/frameworks/web-components-vite/src/types.ts | 5 ----- .../web-components-webpack5/package.json | 9 ++++++++- .../src/csf-factory/defineMainConfig.ts | 7 +++++++ .../web-components-webpack5/src/types.ts | 5 ----- 57 files changed, 294 insertions(+), 108 deletions(-) create mode 100644 code/frameworks/angular/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/ember/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index 946679a7a129..9623dd81ceb2 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -20,6 +20,21 @@ "url": "https://opencollective.com/storybook" }, "license": "MIT", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "node": "./dist/index.js", + "import": "./dist/index.mjs", + "require": "./dist/index.js" + }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.js", + "require": "./dist/csf-factory/defineMainConfig.js" + }, + "./package.json": "./package.json" + }, "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", diff --git a/code/frameworks/angular/src/csf-factory/defineMainConfig.ts b/code/frameworks/angular/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..3092f2e9d68d --- /dev/null +++ b/code/frameworks/angular/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/angular/src/types.ts b/code/frameworks/angular/src/types.ts index 1ba889dc90ff..a30e2174efd6 100644 --- a/code/frameworks/angular/src/types.ts +++ b/code/frameworks/angular/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import { CompatibleString } from 'storybook/internal/types'; import { @@ -49,7 +48,3 @@ export interface AngularOptions { enableIvy?: boolean; enableNgcc?: boolean; } - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index 9e308f6b5f6d..f9f61961c054 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -16,6 +16,21 @@ "url": "https://opencollective.com/storybook" }, "license": "MIT", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "node": "./dist/index.js", + "import": "./dist/index.mjs", + "require": "./dist/index.js" + }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.js", + "require": "./dist/csf-factory/defineMainConfig.js" + }, + "./package.json": "./package.json" + }, "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", diff --git a/code/frameworks/ember/src/csf-factory/defineMainConfig.ts b/code/frameworks/ember/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/ember/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/ember/src/types.ts b/code/frameworks/ember/src/types.ts index 236840db2f10..ee6ef8e0fe5b 100644 --- a/code/frameworks/ember/src/types.ts +++ b/code/frameworks/ember/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -49,7 +48,3 @@ declare global { // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/naming-convention, no-var var __EMBER_GENERATED_DOC_JSON__: any; } - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/experimental-nextjs-vite/package.json b/code/frameworks/experimental-nextjs-vite/package.json index b5205345ed72..7604bf925799 100644 --- a/code/frameworks/experimental-nextjs-vite/package.json +++ b/code/frameworks/experimental-nextjs-vite/package.json @@ -58,6 +58,12 @@ "import": "./dist/vite-plugin/index.mjs", "require": "./dist/vite-plugin/index.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -134,6 +140,7 @@ "./src/index.ts", "./src/vite-plugin/index.ts", "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts", "./src/preview.tsx", "./src/export-mocks/cache/index.ts", "./src/export-mocks/headers/index.ts", diff --git a/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/experimental-nextjs-vite/src/types.ts b/code/frameworks/experimental-nextjs-vite/src/types.ts index 6c04f243b6fc..0221787dccb6 100644 --- a/code/frameworks/experimental-nextjs-vite/src/types.ts +++ b/code/frameworks/experimental-nextjs-vite/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { BuilderOptions } from '@storybook/builder-vite'; @@ -33,7 +32,3 @@ type StorybookConfigFramework = { /** The interface for Storybook configuration in `main.ts` files. */ export type StorybookConfig = Omit & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index 804987dac1c7..89745dfd9b99 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -67,7 +73,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/html-vite/src/types.ts b/code/frameworks/html-vite/src/types.ts index 107ae09ac607..34d1e116e8d7 100644 --- a/code/frameworks/html-vite/src/types.ts +++ b/code/frameworks/html-vite/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -37,7 +36,3 @@ export type StorybookConfig = Omit< > & StorybookConfigVite & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index 03cd0ce7cfc2..0cbb3b253a46 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -68,7 +74,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/html-webpack5/src/types.ts b/code/frameworks/html-webpack5/src/types.ts index b53f57f9cc66..d29860b85762 100644 --- a/code/frameworks/html-webpack5/src/types.ts +++ b/code/frameworks/html-webpack5/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -44,7 +43,3 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index a440c6b17a17..41dea2891772 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -87,6 +87,12 @@ "import": "./dist/export-mocks/router/index.mjs", "require": "./dist/export-mocks/router/index.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -209,6 +215,7 @@ "./src/image-context.ts", "./src/index.ts", "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts", "./src/preview.tsx", "./src/export-mocks/index.ts", "./src/export-mocks/cache/index.ts", diff --git a/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts b/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/nextjs/src/types.ts b/code/frameworks/nextjs/src/types.ts index f2a83028fe58..42148ef8517b 100644 --- a/code/frameworks/nextjs/src/types.ts +++ b/code/frameworks/nextjs/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -49,7 +48,3 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/preact-vite/package.json b/code/frameworks/preact-vite/package.json index 5b146f3a9bbf..0a2679104192 100644 --- a/code/frameworks/preact-vite/package.json +++ b/code/frameworks/preact-vite/package.json @@ -29,6 +29,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", diff --git a/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/preact-vite/src/types.ts b/code/frameworks/preact-vite/src/types.ts index 317de3d9732b..503f7cd5d327 100644 --- a/code/frameworks/preact-vite/src/types.ts +++ b/code/frameworks/preact-vite/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -37,7 +36,3 @@ export type StorybookConfig = Omit< > & StorybookConfigVite & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/preact-webpack5/package.json b/code/frameworks/preact-webpack5/package.json index 5f0290ffcebc..5064cc3eea6f 100644 --- a/code/frameworks/preact-webpack5/package.json +++ b/code/frameworks/preact-webpack5/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -69,7 +75,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/preact-webpack5/src/types.ts b/code/frameworks/preact-webpack5/src/types.ts index 678294d9ec8f..a09f8e3695c1 100644 --- a/code/frameworks/preact-webpack5/src/types.ts +++ b/code/frameworks/preact-webpack5/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -44,7 +43,3 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/react-native-web-vite/package.json b/code/frameworks/react-native-web-vite/package.json index da31ba3bca39..c8079ec2a22b 100644 --- a/code/frameworks/react-native-web-vite/package.json +++ b/code/frameworks/react-native-web-vite/package.json @@ -35,6 +35,12 @@ "import": "./dist/vite-plugin.mjs", "require": "./dist/vite-plugin.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -86,7 +92,8 @@ "entries": [ "./src/index.ts", "./src/preset.ts", - "./src/vite-plugin.ts" + "./src/vite-plugin.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/react-native-web-vite/src/types.ts b/code/frameworks/react-native-web-vite/src/types.ts index 7436accebc84..5558722e03d7 100644 --- a/code/frameworks/react-native-web-vite/src/types.ts +++ b/code/frameworks/react-native-web-vite/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -31,7 +30,3 @@ export type StorybookConfig = Omit & { options: FrameworkOptions; }; }; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index d871585cf42c..2b8a1696d12d 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -93,7 +99,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/react-vite/src/types.ts b/code/frameworks/react-vite/src/types.ts index be84bca936ca..58cba705bf56 100644 --- a/code/frameworks/react-vite/src/types.ts +++ b/code/frameworks/react-vite/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -64,7 +63,3 @@ export type StorybookConfig = Omit< StorybookConfigFramework & { typescript?: Partial; }; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/react-webpack5/package.json b/code/frameworks/react-webpack5/package.json index c6c05892a81f..0450c35a9999 100644 --- a/code/frameworks/react-webpack5/package.json +++ b/code/frameworks/react-webpack5/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -74,7 +80,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/react-webpack5/src/types.ts b/code/frameworks/react-webpack5/src/types.ts index 006a08cdf667..6366ca3cd857 100644 --- a/code/frameworks/react-webpack5/src/types.ts +++ b/code/frameworks/react-webpack5/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -45,7 +44,3 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/server-webpack5/package.json b/code/frameworks/server-webpack5/package.json index ef6b005495c5..03551f787206 100644 --- a/code/frameworks/server-webpack5/package.json +++ b/code/frameworks/server-webpack5/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -67,7 +73,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/server-webpack5/src/types.ts b/code/frameworks/server-webpack5/src/types.ts index fd7c5d91d960..1040a0fea8bb 100644 --- a/code/frameworks/server-webpack5/src/types.ts +++ b/code/frameworks/server-webpack5/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -44,7 +43,3 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index 5007a4d2ff35..a363bd82c44d 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -78,7 +84,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/svelte-vite/src/types.ts b/code/frameworks/svelte-vite/src/types.ts index 908b77101109..d6efce7feaef 100644 --- a/code/frameworks/svelte-vite/src/types.ts +++ b/code/frameworks/svelte-vite/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -37,7 +36,3 @@ export type StorybookConfig = Omit< > & StorybookConfigVite & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index 78b652a38c07..23251f45ed73 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -70,7 +76,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/svelte-webpack5/src/types.ts b/code/frameworks/svelte-webpack5/src/types.ts index 62381933e4ed..2770043e12dd 100644 --- a/code/frameworks/svelte-webpack5/src/types.ts +++ b/code/frameworks/svelte-webpack5/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -45,7 +44,3 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index 6165990d8b1e..1d2bd99d74cc 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -41,6 +41,12 @@ "require": "./dist/vite-plugin.js", "import": "./dist/vite-plugin.mjs" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -84,7 +90,8 @@ "./src/index.ts", "./src/preview.ts", "./src/preset.ts", - "./src/vite-plugin.ts" + "./src/vite-plugin.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts b/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/sveltekit/src/types.ts b/code/frameworks/sveltekit/src/types.ts index 6aef9a709fd3..975a184f4545 100644 --- a/code/frameworks/sveltekit/src/types.ts +++ b/code/frameworks/sveltekit/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -64,7 +63,3 @@ export type SvelteKitParameters = Partial<{ enhance: typeof enhance; }; }>; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index 8d9b0f427a6a..a71a0a718c1c 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -35,6 +35,12 @@ "require": "./dist/vite-plugin.js", "import": "./dist/vite-plugin.mjs" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -80,7 +86,8 @@ "entries": [ "./src/index.ts", "./src/preset.ts", - "./src/vite-plugin.ts" + "./src/vite-plugin.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/vue3-vite/src/types.ts b/code/frameworks/vue3-vite/src/types.ts index 6ac74e77f10f..d02b791f294b 100644 --- a/code/frameworks/vue3-vite/src/types.ts +++ b/code/frameworks/vue3-vite/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -100,7 +99,3 @@ export type VueDocgenInfoEntry< ? VueDocgenInfo<'vue-component-meta'>[Exclude] : VueDocgenInfo<'vue-docgen-api'>[Exclude] >; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json index b08859e0a714..f01b9eff2869 100644 --- a/code/frameworks/vue3-webpack5/package.json +++ b/code/frameworks/vue3-webpack5/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -71,7 +77,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/vue3-webpack5/src/types.ts b/code/frameworks/vue3-webpack5/src/types.ts index bd1b1eac450c..9d6aa2467884 100644 --- a/code/frameworks/vue3-webpack5/src/types.ts +++ b/code/frameworks/vue3-webpack5/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString } from 'storybook/internal/types'; import type { @@ -44,7 +43,3 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index 92a76784a0aa..18b6483a8c1f 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -30,6 +30,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -66,6 +72,7 @@ }, "bundler": { "entries": [ + "./src/csf-factory/defineMainConfig.ts", "./src/index.ts", "./src/preset.ts" ], diff --git a/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/web-components-vite/src/types.ts b/code/frameworks/web-components-vite/src/types.ts index 8954bf3221df..cb8328dc9770 100644 --- a/code/frameworks/web-components-vite/src/types.ts +++ b/code/frameworks/web-components-vite/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -37,7 +36,3 @@ export type StorybookConfig = Omit< > & StorybookConfigVite & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index aa4281ef433e..656279dc71f7 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -33,6 +33,12 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, + "./main": { + "types": "./dist/csf-factory/defineMainConfig.d.ts", + "node": "./dist/csf-factory/defineMainConfig.js", + "import": "./dist/csf-factory/defineMainConfig.mjs", + "require": "./dist/csf-factory/defineMainConfig.js" + }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -71,7 +77,8 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts" + "./src/preset.ts", + "./src/csf-factory/defineMainConfig.ts" ], "platform": "node" }, diff --git a/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts new file mode 100644 index 000000000000..5039323552fe --- /dev/null +++ b/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts @@ -0,0 +1,7 @@ +import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; + +import type { StorybookConfig } from '../types'; + +export function defineConfig(config: StorybookConfig) { + return commonDefineConfig(config); +} diff --git a/code/frameworks/web-components-webpack5/src/types.ts b/code/frameworks/web-components-webpack5/src/types.ts index f6d1c9552392..0cd693b1fd4a 100644 --- a/code/frameworks/web-components-webpack5/src/types.ts +++ b/code/frameworks/web-components-webpack5/src/types.ts @@ -1,4 +1,3 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { CompatibleString, StorybookConfig as StorybookConfigBase, @@ -44,7 +43,3 @@ export type StorybookConfig = Omit< > & StorybookConfigWebpack & StorybookConfigFramework; - -export function defineConfig(config: StorybookConfig) { - return commonDefineConfig(config); -} From df000bb5cf83833e22abeed03185fcbf46470f4b Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 17 Jan 2025 12:34:39 +0100 Subject: [PATCH 06/24] fix internal type import --- code/core/src/common/defineConfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/core/src/common/defineConfig.ts b/code/core/src/common/defineConfig.ts index 08006b683343..2a16d88aa474 100644 --- a/code/core/src/common/defineConfig.ts +++ b/code/core/src/common/defineConfig.ts @@ -1,4 +1,4 @@ -import type { StorybookConfig } from '../types/modules/core-common'; +import type { StorybookConfig } from '@storybook/core/types'; export function defineConfig(config: TConfig): TConfig { return config; From 5ac85efd5cece91d01db7e9a0f0d25536885a181 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 17 Jan 2025 13:07:42 +0100 Subject: [PATCH 07/24] rename the import and function --- code/frameworks/angular/package.json | 2 +- code/frameworks/angular/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/ember/package.json | 2 +- code/frameworks/ember/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/experimental-nextjs-vite/package.json | 2 +- .../src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/html-vite/package.json | 2 +- code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/html-webpack5/package.json | 2 +- .../html-webpack5/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/preact-vite/package.json | 2 +- code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/preact-webpack5/package.json | 2 +- .../preact-webpack5/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/react-native-web-vite/package.json | 2 +- .../react-native-web-vite/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/react-vite/package.json | 2 +- code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/react-webpack5/package.json | 2 +- .../react-webpack5/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/server-webpack5/package.json | 2 +- .../server-webpack5/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/svelte-vite/package.json | 2 +- code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/svelte-webpack5/package.json | 2 +- .../svelte-webpack5/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/sveltekit/package.json | 2 +- code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/vue3-vite/package.json | 2 +- code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/vue3-webpack5/package.json | 2 +- .../vue3-webpack5/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/web-components-vite/package.json | 2 +- .../web-components-vite/src/csf-factory/defineMainConfig.ts | 2 +- code/frameworks/web-components-webpack5/package.json | 2 +- .../web-components-webpack5/src/csf-factory/defineMainConfig.ts | 2 +- 37 files changed, 37 insertions(+), 37 deletions(-) diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index 9623dd81ceb2..91a2d3da4c11 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -27,7 +27,7 @@ "import": "./dist/index.mjs", "require": "./dist/index.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.js", diff --git a/code/frameworks/angular/src/csf-factory/defineMainConfig.ts b/code/frameworks/angular/src/csf-factory/defineMainConfig.ts index 3092f2e9d68d..24bc05422ac9 100644 --- a/code/frameworks/angular/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/angular/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index f9f61961c054..e9f712956e5c 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -23,7 +23,7 @@ "import": "./dist/index.mjs", "require": "./dist/index.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.js", diff --git a/code/frameworks/ember/src/csf-factory/defineMainConfig.ts b/code/frameworks/ember/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/ember/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/ember/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/experimental-nextjs-vite/package.json b/code/frameworks/experimental-nextjs-vite/package.json index 7604bf925799..4b20e1113092 100644 --- a/code/frameworks/experimental-nextjs-vite/package.json +++ b/code/frameworks/experimental-nextjs-vite/package.json @@ -58,7 +58,7 @@ "import": "./dist/vite-plugin/index.mjs", "require": "./dist/vite-plugin/index.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index 89745dfd9b99..1ce79c846355 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index 0cbb3b253a46..8a7167dd0f54 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts b/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/preact-vite/package.json b/code/frameworks/preact-vite/package.json index 0a2679104192..e639c1c7e0bb 100644 --- a/code/frameworks/preact-vite/package.json +++ b/code/frameworks/preact-vite/package.json @@ -29,7 +29,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/preact-webpack5/package.json b/code/frameworks/preact-webpack5/package.json index 5064cc3eea6f..cd7effb465d0 100644 --- a/code/frameworks/preact-webpack5/package.json +++ b/code/frameworks/preact-webpack5/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/react-native-web-vite/package.json b/code/frameworks/react-native-web-vite/package.json index c8079ec2a22b..8f392bc254dd 100644 --- a/code/frameworks/react-native-web-vite/package.json +++ b/code/frameworks/react-native-web-vite/package.json @@ -35,7 +35,7 @@ "import": "./dist/vite-plugin.mjs", "require": "./dist/vite-plugin.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index 2b8a1696d12d..6228aea36f4c 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/react-webpack5/package.json b/code/frameworks/react-webpack5/package.json index 0450c35a9999..8c26cc0072aa 100644 --- a/code/frameworks/react-webpack5/package.json +++ b/code/frameworks/react-webpack5/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/server-webpack5/package.json b/code/frameworks/server-webpack5/package.json index 03551f787206..1f61cce000ec 100644 --- a/code/frameworks/server-webpack5/package.json +++ b/code/frameworks/server-webpack5/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index a363bd82c44d..b82e3b98b28b 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index 23251f45ed73..f483c25bf7e3 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index 1d2bd99d74cc..b47ab7a26343 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -41,7 +41,7 @@ "require": "./dist/vite-plugin.js", "import": "./dist/vite-plugin.mjs" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts b/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index a71a0a718c1c..2852d303990b 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -35,7 +35,7 @@ "require": "./dist/vite-plugin.js", "import": "./dist/vite-plugin.mjs" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json index f01b9eff2869..973f16e8a820 100644 --- a/code/frameworks/vue3-webpack5/package.json +++ b/code/frameworks/vue3-webpack5/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index 18b6483a8c1f..27b17e55155e 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -30,7 +30,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index 656279dc71f7..2e9b89f3223c 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -33,7 +33,7 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./main": { + "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", "import": "./dist/csf-factory/defineMainConfig.mjs", diff --git a/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts index 5039323552fe..dd999c40b17b 100644 --- a/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts +++ b/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts @@ -2,6 +2,6 @@ import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; import type { StorybookConfig } from '../types'; -export function defineConfig(config: StorybookConfig) { +export function defineMain(config: StorybookConfig) { return commonDefineConfig(config); } From 778405d379296e72d1bc2d52af3bb6de6e9ee33a Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 16 Jan 2025 15:00:20 +0100 Subject: [PATCH 08/24] Move csf factory codemod to automigrations --- .../cli-storybook/src/automigrate/codemod.ts | 81 ++++++++++ .../src/automigrate/fixes}/csf-3-to-4.test.ts | 92 ++++++++++- .../src/automigrate/fixes}/csf-3-to-4.ts | 143 +++++++++--------- .../src/automigrate/fixes/index.ts | 7 +- .../cli-storybook/src/automigrate/index.ts | 31 +++- .../cli-storybook/src/automigrate/types.ts | 22 ++- 6 files changed, 291 insertions(+), 85 deletions(-) create mode 100644 code/lib/cli-storybook/src/automigrate/codemod.ts rename code/lib/{codemod/src/transforms/__tests__ => cli-storybook/src/automigrate/fixes}/csf-3-to-4.test.ts (67%) rename code/lib/{codemod/src/transforms => cli-storybook/src/automigrate/fixes}/csf-3-to-4.ts (57%) diff --git a/code/lib/cli-storybook/src/automigrate/codemod.ts b/code/lib/cli-storybook/src/automigrate/codemod.ts new file mode 100644 index 000000000000..9fb9e7c4cb94 --- /dev/null +++ b/code/lib/cli-storybook/src/automigrate/codemod.ts @@ -0,0 +1,81 @@ +import { promises as fs } from 'fs'; +// eslint-disable-next-line depend/ban-dependencies +import { glob } from 'glob'; +import picocolors from 'picocolors'; + +const logger = console; + +export interface FileInfo { + path: string; + source: string; +} + +/** + * Runs a codemod transformation on files matching the specified glob pattern. + * + * The function processes each file matching the glob pattern, applies the transform function, and + * writes the transformed source back to the file if it has changed. + * + * @example + * + * ``` + * await runCodemod('*.stories.tsx', async (fileInfo) => { + * // Transform the file source return + * return fileInfo.source.replace(/foo/g, 'bar'); + * }); + * ``` + */ +export async function runCodemod( + globPattern: string = '**/*.stories.*', + transform: (source: FileInfo) => Promise, + { dryRun = false }: { dryRun?: boolean } = {} +) { + let modifiedCount = 0; + let unmodifiedCount = 0; + let errorCount = 0; + + try { + const files = await glob(globPattern, { + nodir: true, + follow: true, + ignore: ['node_modules/**', 'dist/**', 'storybook-static/**', 'build/**'], + }); + + await Promise.all( + files.map(async (file) => { + try { + const source = await fs.readFile(file, 'utf-8'); + const fileInfo: FileInfo = { path: file, source }; + const transformedSource = await transform(fileInfo); + + if (transformedSource !== source) { + if (!dryRun) { + await fs.writeFile(file, transformedSource, 'utf-8'); + } + modifiedCount++; + } else { + unmodifiedCount++; + } + } catch (fileError) { + logger.error(`Error processing file ${file}:`, fileError); + errorCount++; + } + }) + ); + } catch (error) { + logger.error('Error applying transform:', error); + errorCount++; + } + + logger.log( + `Summary: ${picocolors.green(`${modifiedCount} transformed`)}, ${picocolors.yellow(`${unmodifiedCount} unmodified`)}, ${picocolors.red(`${errorCount} errors`)}` + ); + + if (dryRun) { + logger.log( + picocolors.bold( + `This was a dry run. Run without --dry-run to apply the transformation to ${modifiedCount} files.` + ) + ); + } +} diff --git a/code/lib/codemod/src/transforms/__tests__/csf-3-to-4.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts similarity index 67% rename from code/lib/codemod/src/transforms/__tests__/csf-3-to-4.test.ts rename to code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts index 7dcef73c2e53..c6f59ded571f 100644 --- a/code/lib/codemod/src/transforms/__tests__/csf-3-to-4.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { dedent } from 'ts-dedent'; -import _transform from '../csf-3-to-4'; +import { csf4Transform } from './csf-3-to-4'; expect.addSnapshotSerializer({ serialize: (val: any) => (typeof val === 'string' ? val : val.toString()), @@ -10,7 +10,7 @@ expect.addSnapshotSerializer({ }); const transform = async (source: string) => - (await _transform({ source, path: 'Component.stories.tsx' })).trim(); + (await csf4Transform({ source, path: 'Component.stories.tsx' })).trim(); describe('csf-3-to-4', () => { describe('javascript', () => { @@ -96,9 +96,95 @@ describe('csf-3-to-4', () => { }); `); }); + + it('if there is an existing local constant called config, rename storybook config import', async () => { + await expect( + transform(dedent` + const componentMeta = { title: 'Component' }; + export default componentMeta; + const config = {}; + export const A = { + args: { primary: true }, + render: (args) => + }; + `) + ).resolves.toMatchInlineSnapshot(` + import { storybookConfig as config } from "#.storybook/preview"; + const meta = storybookConfig.meta({ title: 'Component' }); + const config = {}; + export const A = meta.story({ + args: { primary: true }, + render: (args) => + }); + `); + }); + + it('converts CSF1 into CSF4 with render', async () => { + await expect( + transform(dedent` + const meta = { title: 'Component' }; + export default meta; + export const CSF1Story = () =>
Hello
; + `) + ).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); + export const CSF1Story = meta.story({ + render: () =>
Hello
, + }); + `); + }); }); describe('typescript', () => { + const inlineMetaSatisfies = dedent` + import { Meta, StoryObj as CSF3 } from '@storybook/react'; + import { ComponentProps } from './Component'; + + export default { title: 'Component', component: Component } satisfies Meta; + + export const A: CSF3 = { + args: { primary: true } + }; + `; + it('meta satisfies syntax', async () => { + await expect(transform(inlineMetaSatisfies)).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + import { ComponentProps } from './Component'; + + const meta = config.meta({ title: 'Component', component: Component }); + + export const A = meta.story({ + args: { primary: true }, + }); + `); + }); + + const inlineMetaAs = dedent` + import { Meta, StoryObj as CSF3 } from '@storybook/react'; + import { ComponentProps } from './Component'; + + export default { title: 'Component', component: Component } as Meta; + + export const A: CSF3 = { + args: { primary: true } + }; + `; + it('meta as syntax', async () => { + await expect(transform(inlineMetaAs)).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + import { ComponentProps } from './Component'; + + const meta = config.meta({ title: 'Component', component: Component }); + + export const A = meta.story({ + args: { primary: true }, + }); + `); + }); const metaSatisfies = dedent` import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; @@ -201,6 +287,8 @@ describe('csf-3-to-4', () => { it('should yield the same result to all syntaxes', async () => { const allSnippets = await Promise.all([ + transform(inlineMetaSatisfies), + transform(inlineMetaAs), transform(metaSatisfies), transform(metaAs), transform(storySatisfies), diff --git a/code/lib/codemod/src/transforms/csf-3-to-4.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts similarity index 57% rename from code/lib/codemod/src/transforms/csf-3-to-4.ts rename to code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts index 9d8856f25150..0e2dd9755746 100644 --- a/code/lib/codemod/src/transforms/csf-3-to-4.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts @@ -1,22 +1,19 @@ /* eslint-disable no-underscore-dangle */ -import { types as t, traverse } from '@storybook/core/babel'; +import { types as t } from 'storybook/internal/babel'; +import { isValidPreviewPath, loadCsf, printCsf } from 'storybook/internal/csf-tools'; -import { isValidPreviewPath, loadCsf, printCsf } from '@storybook/core/csf-tools'; +import prompts from 'prompts'; -import * as babel from '@babel/core'; -import type { FileInfo } from 'jscodeshift'; -import prettier from 'prettier'; - -const logger = console; - -export default async function transform(info: FileInfo) { - const csf = loadCsf(info.source, { makeTitle: (title) => title }); - const fileNode = csf._ast; +import type { FileInfo } from '../codemod'; +import { runCodemod } from '../codemod'; +import type { CommandFix } from '../types'; +export async function csf4Transform(info: FileInfo) { + const csf = loadCsf(info.source, { makeTitle: () => 'FIXME' }); try { csf.parse(); } catch (err) { - logger.log(`Error ${err}, skipping`); + logger.log(`Error when parsing ${info.path}, skipping:\n${err}`); return info.source; } @@ -27,9 +24,23 @@ export default async function transform(info: FileInfo) { * * `import { config } from '#.storybook/preview'`; */ - const programNode = fileNode.program; + const programNode = csf._ast.program; let foundConfigImport = false; + // Check if a root-level constant named 'config' exists + const hasRootLevelConfig = programNode.body.some( + (n) => + t.isVariableDeclaration(n) && + n.declarations.some((declaration) => t.isIdentifier(declaration.id, { name: 'config' })) + ); + + const sbConfigImportName = hasRootLevelConfig ? 'storybookConfig' : 'config'; + + const sbConfigImportSpecifier = t.importSpecifier( + t.identifier('config'), + t.identifier(sbConfigImportName) + ); + programNode.body.forEach((node) => { if (t.isImportDeclaration(node) && isValidPreviewPath(node.source.value)) { const hasConfigSpecifier = node.specifiers.some( @@ -38,12 +49,7 @@ export default async function transform(info: FileInfo) { ); if (!hasConfigSpecifier) { - node.specifiers.push( - babel.types.importSpecifier( - babel.types.identifier('config'), - babel.types.identifier('config') - ) - ); + node.specifiers.push(sbConfigImportSpecifier); } foundConfigImport = true; @@ -54,7 +60,7 @@ export default async function transform(info: FileInfo) { Object.entries(csf._storyExports).forEach(([key, decl]) => { const id = decl.id; - const declarator = decl as babel.types.VariableDeclarator; + const declarator = decl as t.VariableDeclarator; let init = t.isVariableDeclarator(declarator) ? declarator.init : undefined; if (t.isIdentifier(id) && init) { @@ -70,29 +76,37 @@ export default async function transform(info: FileInfo) { } // Wrap the object in `meta.story()` - declarator.init = babel.types.callExpression( - babel.types.memberExpression( - babel.types.identifier(metaVariableName), - babel.types.identifier('story') - ), + declarator.init = t.callExpression( + t.memberExpression(t.identifier(metaVariableName), t.identifier('story')), [init] ); + } else if (t.isArrowFunctionExpression(init)) { + // Transform CSF1 to meta.story({ render: }) + const renderProperty = t.objectProperty(t.identifier('render'), init); + + const objectExpression = t.objectExpression([renderProperty]); + + declarator.init = t.callExpression( + t.memberExpression(t.identifier(metaVariableName), t.identifier('story')), + [objectExpression] + ); } } }); // modify meta if (csf._metaPath) { - const declaration = csf._metaPath.node.declaration; + let declaration = csf._metaPath.node.declaration; + if (t.isTSSatisfiesExpression(declaration) || t.isTSAsExpression(declaration)) { + declaration = declaration.expression; + } + if (t.isObjectExpression(declaration)) { - const metaVariable = babel.types.variableDeclaration('const', [ - babel.types.variableDeclarator( - babel.types.identifier(metaVariableName), - babel.types.callExpression( - babel.types.memberExpression( - babel.types.identifier('config'), - babel.types.identifier('meta') - ), + const metaVariable = t.variableDeclaration('const', [ + t.variableDeclarator( + t.identifier(metaVariableName), + t.callExpression( + t.memberExpression(t.identifier(sbConfigImportName), t.identifier('meta')), [declaration] ) ), @@ -113,18 +127,15 @@ export default async function transform(info: FileInfo) { const originalName = declaration.name; // Always rename the meta variable to 'meta' - binding.path.node.id = babel.types.identifier(metaVariableName); + binding.path.node.id = t.identifier(metaVariableName); let init = binding.path.node.init; if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) { init = init.expression; } if (t.isObjectExpression(init)) { - binding.path.node.init = babel.types.callExpression( - babel.types.memberExpression( - babel.types.identifier('config'), - babel.types.identifier('meta') - ), + binding.path.node.init = t.callExpression( + t.memberExpression(t.identifier(sbConfigImportName), t.identifier('meta')), [init] ); } @@ -139,35 +150,13 @@ export default async function transform(info: FileInfo) { } if (hasMeta && !foundConfigImport) { - const configImport = babel.types.importDeclaration( - [ - babel.types.importSpecifier( - babel.types.identifier('config'), - babel.types.identifier('config') - ), - ], - babel.types.stringLiteral('#.storybook/preview') + const configImport = t.importDeclaration( + [sbConfigImportSpecifier], + t.stringLiteral('#.storybook/preview') ); programNode.body.unshift(configImport); } - function isSpecifierUsed(name: string) { - let isUsed = false; - - // Traverse the AST and check for usage of the name - traverse(programNode, { - Identifier(path) { - if (path.node.name === name) { - isUsed = true; - // Stop traversal early if we've found a match - path.stop(); - } - }, - }); - - return isUsed; - } - // Remove type imports – now inferred – from @storybook/* packages const disallowlist = [ 'Story', @@ -210,12 +199,30 @@ export default async function transform(info: FileInfo) { let output = printCsf(csf).code; try { + // eslint-disable-next-line import/no-extraneous-dependencies + const prettier = await import('prettier'); output = await prettier.format(output, { ...(await prettier.resolveConfig(info.path)), filepath: info.path, }); - } catch (e) { - logger.log(`Failed applying prettier to ${info.path}.`); - } + } catch (e) {} return output; } + +const logger = console; + +export const csf3to4: CommandFix = { + id: 'csf-3-to-4', + promptType: 'command', + async run({ dryRun }) { + logger.log('Please enter the glob for your stories to migrate'); + const { glob: globString } = await prompts({ + type: 'text', + name: 'glob', + message: 'glob', + initial: '**/*.stories.*', + }); + + await runCodemod(globString, csf4Transform, { dryRun }); + }, +}; diff --git a/code/lib/cli-storybook/src/automigrate/fixes/index.ts b/code/lib/cli-storybook/src/automigrate/fixes/index.ts index dfd43100665c..acd7d06183d9 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/index.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/index.ts @@ -1,4 +1,4 @@ -import type { Fix } from '../types'; +import type { CommandFix, Fix } from '../types'; import { addonA11yAddonTest } from './addon-a11y-addon-test'; import { addonPostCSS } from './addon-postcss'; import { addonsAPI } from './addons-api'; @@ -8,6 +8,7 @@ import { autodocsTags } from './autodocs-tags'; import { autodocsTrue } from './autodocs-true'; import { builderVite } from './builder-vite'; import { cra5 } from './cra5'; +import { csf3to4 } from './csf-3-to-4'; import { eslintPlugin } from './eslint-plugin'; import { initialGlobals } from './initial-globals'; import { mdx1to3 } from './mdx-1-to-3'; @@ -70,3 +71,7 @@ export const allFixes: Fix[] = [ ]; export const initFixes: Fix[] = [eslintPlugin]; + +// These are specific fixes that only occur when triggered on command, and are hidden otherwise. +// e.g. npx automigrate csf-3-to-4 +export const commandFixes: CommandFix[] = [csf3to4]; diff --git a/code/lib/cli-storybook/src/automigrate/index.ts b/code/lib/cli-storybook/src/automigrate/index.ts index 9d98d97d7013..a25455e38b1a 100644 --- a/code/lib/cli-storybook/src/automigrate/index.ts +++ b/code/lib/cli-storybook/src/automigrate/index.ts @@ -27,7 +27,7 @@ import type { PreCheckFailure, Prompt, } from './fixes'; -import { FixStatus, allFixes } from './fixes'; +import { FixStatus, allFixes, commandFixes } from './fixes'; import { upgradeStorybookRelatedDependencies } from './fixes/upgrade-storybook-related-dependencies'; import { cleanLog } from './helpers/cleanLog'; import { getMigrationSummary } from './helpers/getMigrationSummary'; @@ -60,7 +60,7 @@ const cleanup = () => { }; const logAvailableMigrations = () => { - const availableFixes = allFixes + const availableFixes = [...allFixes, ...commandFixes] .map((f) => picocolors.yellow(f.id)) .map((x) => `- ${x}`) .join('\n'); @@ -82,10 +82,11 @@ export const doAutomigrate = async (options: AutofixOptionsFromCLI) => { getCoercedStorybookVersion(packageManager), ]); - const { configDir: inferredConfigDir, mainConfig: mainConfigPath } = getStorybookInfo( - packageJson, - options.configDir - ); + const { + configDir: inferredConfigDir, + mainConfig: mainConfigPath, + previewConfig: previewConfigPath, + } = getStorybookInfo(packageJson, options.configDir); const configDir = options.configDir || inferredConfigDir || '.storybook'; if (!storybookVersion) { @@ -102,6 +103,7 @@ export const doAutomigrate = async (options: AutofixOptionsFromCLI) => { storybookVersion, beforeVersion: storybookVersion, mainConfigPath, + previewConfigPath, configDir, isUpgrade: false, isLatest: false, @@ -121,6 +123,7 @@ export const automigrate = async ({ list, configDir, mainConfigPath, + previewConfigPath, storybookVersion, beforeVersion, renderer: rendererPackage, @@ -137,6 +140,22 @@ export const automigrate = async ({ return null; } + // if an on-command migration is triggered, run it and bail + const commandFix = commandFixes.find((f) => f.id === fixId); + if (commandFix) { + logger.info(`🔎 Running migration ${picocolors.magenta(fixId)}..`); + + await commandFix.run({ + mainConfigPath, + previewConfigPath, + packageManager, + dryRun, + result: null, + }); + + return null; + } + const selectedFixes: Fix[] = inputFixes || allFixes.filter((fix) => { diff --git a/code/lib/cli-storybook/src/automigrate/types.ts b/code/lib/cli-storybook/src/automigrate/types.ts index 737d8f9018f7..3c62e6343cab 100644 --- a/code/lib/cli-storybook/src/automigrate/types.ts +++ b/code/lib/cli-storybook/src/automigrate/types.ts @@ -16,6 +16,7 @@ export interface RunOptions { result: ResultType; dryRun?: boolean; mainConfigPath: string; + previewConfigPath?: string; skipInstall?: boolean; } @@ -25,8 +26,9 @@ export interface RunOptions { * - Auto: the fix will be applied automatically * - Manual: the user will be prompted to apply the fix * - Notification: the user will be notified about some changes. A fix isn't required, though + * - Command: the fix will only be applied when specified directly by its id */ -export type Prompt = 'auto' | 'manual' | 'notification'; +export type Prompt = 'auto' | 'manual' | 'notification' | 'command'; type BaseFix = { id: string; @@ -46,17 +48,20 @@ type PromptType = | T | ((result: ResultType) => Promise | Prompt); -export type Fix = ( - | { +export type Fix = + | ({ promptType?: PromptType; run: (options: RunOptions) => Promise; - } - | { + } & BaseFix) + | ({ promptType: PromptType; run?: never; - } -) & - BaseFix; + } & BaseFix); + +export type CommandFix = { + promptType: PromptType; + run: (options: RunOptions) => Promise; +} & Omit, 'versionRange' | 'check' | 'prompt'>; export type FixId = string; @@ -69,6 +74,7 @@ export enum PreCheckFailure { export interface AutofixOptions extends Omit { packageManager: JsPackageManager; mainConfigPath: string; + previewConfigPath?: string; /** The version of Storybook before the migration. */ beforeVersion: string; storybookVersion: string; From e68b8f9975a56220b248d0576548e62499e0fdcd Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 16 Jan 2025 17:21:21 +0100 Subject: [PATCH 09/24] address review comments --- code/lib/cli-storybook/package.json | 1 + .../cli-storybook/src/automigrate/codemod.ts | 62 ++++++++++++------- .../src/automigrate/fixes/csf-3-to-4.test.ts | 5 +- .../src/automigrate/fixes/csf-3-to-4.ts | 17 ++--- code/yarn.lock | 17 +++++ 5 files changed, 65 insertions(+), 37 deletions(-) diff --git a/code/lib/cli-storybook/package.json b/code/lib/cli-storybook/package.json index 931146d117ba..7a3a97ed9c3f 100644 --- a/code/lib/cli-storybook/package.json +++ b/code/lib/cli-storybook/package.json @@ -55,6 +55,7 @@ "globby": "^14.0.1", "jscodeshift": "^0.15.1", "leven": "^3.1.0", + "p-limit": "^6.2.0", "prompts": "^2.4.0", "semver": "^7.3.7", "storybook": "workspace:*", diff --git a/code/lib/cli-storybook/src/automigrate/codemod.ts b/code/lib/cli-storybook/src/automigrate/codemod.ts index 9fb9e7c4cb94..00e2cb4db0f1 100644 --- a/code/lib/cli-storybook/src/automigrate/codemod.ts +++ b/code/lib/cli-storybook/src/automigrate/codemod.ts @@ -1,10 +1,15 @@ +import os from 'node:os'; + +import { formatFileContent } from 'storybook/internal/common'; + import { promises as fs } from 'fs'; -// eslint-disable-next-line depend/ban-dependencies -import { glob } from 'glob'; import picocolors from 'picocolors'; +import slash from 'slash'; const logger = console; +export const maxConcurrentTasks = Math.max(1, os.cpus().length - 1); + export interface FileInfo { path: string; source: string; @@ -28,39 +33,52 @@ export interface FileInfo { export async function runCodemod( globPattern: string = '**/*.stories.*', transform: (source: FileInfo) => Promise, - { dryRun = false }: { dryRun?: boolean } = {} + { dryRun = false, skipFormatting = false }: { dryRun?: boolean; skipFormatting?: boolean } = {} ) { let modifiedCount = 0; let unmodifiedCount = 0; let errorCount = 0; try { - const files = await glob(globPattern, { - nodir: true, - follow: true, + // Dynamically import these packages because they are pure ESM modules + // eslint-disable-next-line depend/ban-dependencies + const { globby } = await import('globby'); + + const pLimit = (await import('p-limit')).default; + + // glob only supports forward slashes + const files = await globby(slash(globPattern), { + followSymbolicLinks: true, ignore: ['node_modules/**', 'dist/**', 'storybook-static/**', 'build/**'], }); + const limit = pLimit(maxConcurrentTasks); + await Promise.all( - files.map(async (file) => { - try { - const source = await fs.readFile(file, 'utf-8'); - const fileInfo: FileInfo = { path: file, source }; - const transformedSource = await transform(fileInfo); + files.map((file) => + limit(async () => { + try { + const source = await fs.readFile(file, 'utf-8'); + const fileInfo: FileInfo = { path: file, source }; + const transformedSource = await transform(fileInfo); - if (transformedSource !== source) { - if (!dryRun) { - await fs.writeFile(file, transformedSource, 'utf-8'); + if (transformedSource !== source) { + if (!dryRun) { + const fileContent = skipFormatting + ? transformedSource + : await formatFileContent(file, transformedSource); + await fs.writeFile(file, fileContent, 'utf-8'); + } + modifiedCount++; + } else { + unmodifiedCount++; } - modifiedCount++; - } else { - unmodifiedCount++; + } catch (fileError) { + logger.error(`Error processing file ${file}:`, fileError); + errorCount++; } - } catch (fileError) { - logger.error(`Error processing file ${file}:`, fileError); - errorCount++; - } - }) + }) + ) ); } catch (error) { logger.error('Error applying transform:', error); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts index c6f59ded571f..d6c54e69d967 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts @@ -109,12 +109,13 @@ describe('csf-3-to-4', () => { }; `) ).resolves.toMatchInlineSnapshot(` - import { storybookConfig as config } from "#.storybook/preview"; + import { config as storybookConfig } from '#.storybook/preview'; + const meta = storybookConfig.meta({ title: 'Component' }); const config = {}; export const A = meta.story({ args: { primary: true }, - render: (args) => + render: (args) => , }); `); }); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts index 0e2dd9755746..305d60778dc9 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts @@ -1,5 +1,6 @@ /* eslint-disable no-underscore-dangle */ import { types as t } from 'storybook/internal/babel'; +import { formatFileContent } from 'storybook/internal/common'; import { isValidPreviewPath, loadCsf, printCsf } from 'storybook/internal/csf-tools'; import prompts from 'prompts'; @@ -37,8 +38,8 @@ export async function csf4Transform(info: FileInfo) { const sbConfigImportName = hasRootLevelConfig ? 'storybookConfig' : 'config'; const sbConfigImportSpecifier = t.importSpecifier( - t.identifier('config'), - t.identifier(sbConfigImportName) + t.identifier(sbConfigImportName), + t.identifier('config') ); programNode.body.forEach((node) => { @@ -196,17 +197,7 @@ export async function csf4Transform(info: FileInfo) { return true; }); - let output = printCsf(csf).code; - - try { - // eslint-disable-next-line import/no-extraneous-dependencies - const prettier = await import('prettier'); - output = await prettier.format(output, { - ...(await prettier.resolveConfig(info.path)), - filepath: info.path, - }); - } catch (e) {} - return output; + return printCsf(csf).code; } const logger = console; diff --git a/code/yarn.lock b/code/yarn.lock index 2307a03bf243..4fc46e9e2c86 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6128,6 +6128,7 @@ __metadata: globby: "npm:^14.0.1" jscodeshift: "npm:^0.15.1" leven: "npm:^3.1.0" + p-limit: "npm:^6.2.0" picocolors: "npm:^1.1.0" prompts: "npm:^2.4.0" semver: "npm:^7.3.7" @@ -22691,6 +22692,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^6.2.0": + version: 6.2.0 + resolution: "p-limit@npm:6.2.0" + dependencies: + yocto-queue: "npm:^1.1.1" + checksum: 10c0/448bf55a1776ca1444594d53b3c731e68cdca00d44a6c8df06a2f6e506d5bbd540ebb57b05280f8c8bff992a630ed782a69612473f769a7473495d19e2270166 + languageName: node + linkType: hard + "p-locate@npm:^2.0.0": version: 2.0.0 resolution: "p-locate@npm:2.0.0" @@ -30496,6 +30506,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^1.1.1": + version: 1.1.1 + resolution: "yocto-queue@npm:1.1.1" + checksum: 10c0/cb287fe5e6acfa82690acb43c283de34e945c571a78a939774f6eaba7c285bacdf6c90fbc16ce530060863984c906d2b4c6ceb069c94d1e0a06d5f2b458e2a92 + languageName: node + linkType: hard + "yoctocolors-cjs@npm:^2.1.2": version: 2.1.2 resolution: "yoctocolors-cjs@npm:2.1.2" From 1f79546a6c825c8ea05a6aefa9a3ef2350c60646 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 17 Jan 2025 10:13:20 +0100 Subject: [PATCH 10/24] refactor and use automigrate instead of codemod in sandbox --- .../cli-storybook/src/automigrate/codemod.ts | 31 +- .../src/automigrate/fixes/csf-3-to-4.test.ts | 534 +++++++++--------- .../src/automigrate/fixes/csf-3-to-4.ts | 38 +- scripts/tasks/sandbox-parts.ts | 3 +- scripts/utils/cli-step.ts | 7 + 5 files changed, 326 insertions(+), 287 deletions(-) diff --git a/code/lib/cli-storybook/src/automigrate/codemod.ts b/code/lib/cli-storybook/src/automigrate/codemod.ts index 00e2cb4db0f1..1cb937d73398 100644 --- a/code/lib/cli-storybook/src/automigrate/codemod.ts +++ b/code/lib/cli-storybook/src/automigrate/codemod.ts @@ -13,6 +13,7 @@ export const maxConcurrentTasks = Math.max(1, os.cpus().length - 1); export interface FileInfo { path: string; source: string; + [key: string]: any; } /** @@ -32,25 +33,33 @@ export interface FileInfo { */ export async function runCodemod( globPattern: string = '**/*.stories.*', - transform: (source: FileInfo) => Promise, + transform: (source: FileInfo, ...rest: any) => Promise, { dryRun = false, skipFormatting = false }: { dryRun?: boolean; skipFormatting?: boolean } = {} ) { let modifiedCount = 0; let unmodifiedCount = 0; let errorCount = 0; - try { - // Dynamically import these packages because they are pure ESM modules - // eslint-disable-next-line depend/ban-dependencies - const { globby } = await import('globby'); + // Dynamically import these packages because they are pure ESM modules + // eslint-disable-next-line depend/ban-dependencies + const { globby } = await import('globby'); - const pLimit = (await import('p-limit')).default; + // glob only supports forward slashes + const files = await globby(slash(globPattern), { + followSymbolicLinks: true, + ignore: ['node_modules/**', 'dist/**', 'storybook-static/**', 'build/**'], + }); - // glob only supports forward slashes - const files = await globby(slash(globPattern), { - followSymbolicLinks: true, - ignore: ['node_modules/**', 'dist/**', 'storybook-static/**', 'build/**'], - }); + if (!files.length) { + logger.error( + `No files found for glob pattern "${globPattern}".\nPlease try a different pattern.\n` + ); + // eslint-disable-next-line local-rules/no-uncategorized-errors + throw new Error('No files matched'); + } + + try { + const pLimit = (await import('p-limit')).default; const limit = pLimit(maxConcurrentTasks); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts index d6c54e69d967..6bb4b438a479 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts @@ -1,5 +1,7 @@ import { describe, expect, it } from 'vitest'; +import { formatFileContent } from '@storybook/core/common'; + import { dedent } from 'ts-dedent'; import { csf4Transform } from './csf-3-to-4'; @@ -9,295 +11,299 @@ expect.addSnapshotSerializer({ test: () => true, }); -const transform = async (source: string) => - (await csf4Transform({ source, path: 'Component.stories.tsx' })).trim(); - describe('csf-3-to-4', () => { - describe('javascript', () => { - it('should wrap const declared meta', async () => { - await expect( - transform(dedent` - const meta = { title: 'Component' }; - export default meta; - `) - ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - - const meta = config.meta({ title: 'Component' }); - `); - }); - - it('should transform and wrap inline default exported meta', async () => { - await expect( - transform(dedent` - export default { title: 'Component' }; - `) - ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + describe('stories codemod', () => { + const transform = async (source: string) => + formatFileContent( + 'Component.stories.tsx', + await csf4Transform({ source, path: 'Component.stories.tsx' }) + ); + describe('javascript', () => { + it('should wrap const declared meta', async () => { + await expect( + transform(dedent` + const meta = { title: 'Component' }; + export default meta; + `) + ).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); + `); + }); - const meta = config.meta({ - title: 'Component', - }); - `); - }); + it('should transform and wrap inline default exported meta', async () => { + await expect( + transform(dedent` + export default { title: 'Component' }; + `) + ).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + const meta = config.meta({ + title: 'Component', + }); + `); + }); - it('should rename meta object to meta if it has a different name', async () => { - await expect( - transform(dedent` - const componentMeta = { title: 'Component' }; - export default componentMeta; - `) - ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - - const meta = config.meta({ title: 'Component' }); - `); - }); + it('should rename meta object to meta if it has a different name', async () => { + await expect( + transform(dedent` + const componentMeta = { title: 'Component' }; + export default componentMeta; + `) + ).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); + `); + }); - it('should wrap stories in a meta.story method', async () => { - await expect( - transform(dedent` - const componentMeta = { title: 'Component' }; - export default componentMeta; - export const A = { + it('should wrap stories in a meta.story method', async () => { + await expect( + transform(dedent` + const componentMeta = { title: 'Component' }; + export default componentMeta; + export const A = { + args: { primary: true }, + render: (args) => + }; + `) + ).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); + export const A = meta.story({ args: { primary: true }, - render: (args) => - }; - `) - ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - - const meta = config.meta({ title: 'Component' }); - export const A = meta.story({ - args: { primary: true }, - render: (args) => , - }); - `); - }); + render: (args) => , + }); + `); + }); - it('should respect existing config imports', async () => { - await expect( - transform(dedent` - import { decorators } from "#.storybook/preview"; - const componentMeta = { title: 'Component' }; - export default componentMeta; - export const A = { + it('should respect existing config imports', async () => { + await expect( + transform(dedent` + import { decorators } from "#.storybook/preview"; + const componentMeta = { title: 'Component' }; + export default componentMeta; + export const A = { + args: { primary: true }, + render: (args) => + }; + `) + ).resolves.toMatchInlineSnapshot(` + import { config, decorators } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); + export const A = meta.story({ args: { primary: true }, - render: (args) => - }; - `) - ).resolves.toMatchInlineSnapshot(` - import { config, decorators } from '#.storybook/preview'; - - const meta = config.meta({ title: 'Component' }); - export const A = meta.story({ - args: { primary: true }, - render: (args) => , - }); - `); - }); + render: (args) => , + }); + `); + }); - it('if there is an existing local constant called config, rename storybook config import', async () => { - await expect( - transform(dedent` - const componentMeta = { title: 'Component' }; - export default componentMeta; + it('if there is an existing local constant called config, rename storybook config import', async () => { + await expect( + transform(dedent` + const componentMeta = { title: 'Component' }; + export default componentMeta; + const config = {}; + export const A = { + args: { primary: true }, + render: (args) => + }; + `) + ).resolves.toMatchInlineSnapshot(` + import { config as storybookConfig } from '#.storybook/preview'; + + const meta = storybookConfig.meta({ title: 'Component' }); const config = {}; - export const A = { + export const A = meta.story({ args: { primary: true }, - render: (args) => - }; - `) - ).resolves.toMatchInlineSnapshot(` - import { config as storybookConfig } from '#.storybook/preview'; - - const meta = storybookConfig.meta({ title: 'Component' }); - const config = {}; - export const A = meta.story({ - args: { primary: true }, - render: (args) => , - }); - `); - }); + render: (args) => , + }); + `); + }); - it('converts CSF1 into CSF4 with render', async () => { - await expect( - transform(dedent` - const meta = { title: 'Component' }; - export default meta; - export const CSF1Story = () =>
Hello
; - `) - ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - - const meta = config.meta({ title: 'Component' }); - export const CSF1Story = meta.story({ - render: () =>
Hello
, - }); - `); + it('converts CSF1 into CSF4 with render', async () => { + await expect( + transform(dedent` + const meta = { title: 'Component' }; + export default meta; + export const CSF1Story = () =>
Hello
; + `) + ).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); + export const CSF1Story = meta.story({ + render: () =>
Hello
, + }); + `); + }); }); - }); - - describe('typescript', () => { - const inlineMetaSatisfies = dedent` - import { Meta, StoryObj as CSF3 } from '@storybook/react'; - import { ComponentProps } from './Component'; - - export default { title: 'Component', component: Component } satisfies Meta; - - export const A: CSF3 = { - args: { primary: true } - }; - `; - it('meta satisfies syntax', async () => { - await expect(transform(inlineMetaSatisfies)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + describe('typescript', () => { + const inlineMetaSatisfies = dedent` + import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; + + export default { title: 'Component', component: Component } satisfies Meta; + + export const A: CSF3 = { + args: { primary: true } + }; + `; + it('meta satisfies syntax', async () => { + await expect(transform(inlineMetaSatisfies)).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + import { ComponentProps } from './Component'; + + const meta = config.meta({ title: 'Component', component: Component }); + + export const A = meta.story({ + args: { primary: true }, + }); + `); + }); - const meta = config.meta({ title: 'Component', component: Component }); - - export const A = meta.story({ - args: { primary: true }, - }); - `); - }); - - const inlineMetaAs = dedent` - import { Meta, StoryObj as CSF3 } from '@storybook/react'; - import { ComponentProps } from './Component'; - - export default { title: 'Component', component: Component } as Meta; - - export const A: CSF3 = { - args: { primary: true } - }; - `; - it('meta as syntax', async () => { - await expect(transform(inlineMetaAs)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - + const inlineMetaAs = dedent` + import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; - - const meta = config.meta({ title: 'Component', component: Component }); - - export const A = meta.story({ - args: { primary: true }, - }); - `); - }); - const metaSatisfies = dedent` - import { Meta, StoryObj as CSF3 } from '@storybook/react'; - import { ComponentProps } from './Component'; - - const meta = { title: 'Component', component: Component } satisfies Meta - export default meta; - - export const A: CSF3 = { - args: { primary: true } - }; - `; - it('meta satisfies syntax', async () => { - await expect(transform(metaSatisfies)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - + + export default { title: 'Component', component: Component } as Meta; + + export const A: CSF3 = { + args: { primary: true } + }; + `; + it('meta as syntax', async () => { + await expect(transform(inlineMetaAs)).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + import { ComponentProps } from './Component'; + + const meta = config.meta({ title: 'Component', component: Component }); + + export const A = meta.story({ + args: { primary: true }, + }); + `); + }); + const metaSatisfies = dedent` + import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; + + const meta = { title: 'Component', component: Component } satisfies Meta + export default meta; + + export const A: CSF3 = { + args: { primary: true } + }; + `; + it('meta satisfies syntax', async () => { + await expect(transform(metaSatisfies)).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + import { ComponentProps } from './Component'; + + const meta = config.meta({ title: 'Component', component: Component }); + + export const A = meta.story({ + args: { primary: true }, + }); + `); + }); - const meta = config.meta({ title: 'Component', component: Component }); - - export const A = meta.story({ - args: { primary: true }, - }); - `); - }); - - const metaAs = dedent` - import { Meta, StoryObj as CSF3 } from '@storybook/react'; - import { ComponentProps } from './Component'; - - const meta = { title: 'Component', component: Component } as Meta - export default meta; - - export const A: CSF3 = { - args: { primary: true } - }; - `; - it('meta as syntax', async () => { - await expect(transform(metaAs)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - + const metaAs = dedent` + import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; + + const meta = { title: 'Component', component: Component } as Meta + export default meta; + + export const A: CSF3 = { + args: { primary: true } + }; + `; + it('meta as syntax', async () => { + await expect(transform(metaAs)).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + import { ComponentProps } from './Component'; + + const meta = config.meta({ title: 'Component', component: Component }); + + export const A = meta.story({ + args: { primary: true }, + }); + `); + }); - const meta = config.meta({ title: 'Component', component: Component }); - - export const A = meta.story({ - args: { primary: true }, - }); - `); - }); - - const storySatisfies = dedent` - import { Meta, StoryObj as CSF3 } from '@storybook/react'; - import { ComponentProps } from './Component'; - - const meta = { title: 'Component', component: Component } as Meta - export default meta; - - export const A = { - args: { primary: true } - } satisfies CSF3; - `; - it('story satisfies syntax', async () => { - await expect(transform(storySatisfies)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - + const storySatisfies = dedent` + import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; + + const meta = { title: 'Component', component: Component } as Meta + export default meta; + + export const A = { + args: { primary: true } + } satisfies CSF3; + `; + it('story satisfies syntax', async () => { + await expect(transform(storySatisfies)).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + import { ComponentProps } from './Component'; + + const meta = config.meta({ title: 'Component', component: Component }); + + export const A = meta.story({ + args: { primary: true }, + }); + `); + }); - const meta = config.meta({ title: 'Component', component: Component }); - - export const A = meta.story({ - args: { primary: true }, - }); - `); - }); - - const storyAs = dedent` - import { Meta, StoryObj as CSF3 } from '@storybook/react'; - import { ComponentProps } from './Component'; - - const meta = { title: 'Component', component: Component } as Meta - export default meta; - - export const A = { - args: { primary: true } - } as CSF3; - `; - it('story as syntax', async () => { - await expect(transform(storyAs)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - + const storyAs = dedent` + import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; + + const meta = { title: 'Component', component: Component } as Meta + export default meta; + + export const A = { + args: { primary: true } + } as CSF3; + `; + it('story as syntax', async () => { + await expect(transform(storyAs)).resolves.toMatchInlineSnapshot(` + import { config } from '#.storybook/preview'; + + import { ComponentProps } from './Component'; + + const meta = config.meta({ title: 'Component', component: Component }); + + export const A = meta.story({ + args: { primary: true }, + }); + `); + }); - const meta = config.meta({ title: 'Component', component: Component }); - - export const A = meta.story({ - args: { primary: true }, + it('should yield the same result to all syntaxes', async () => { + const allSnippets = await Promise.all([ + transform(inlineMetaSatisfies), + transform(inlineMetaAs), + transform(metaSatisfies), + transform(metaAs), + transform(storySatisfies), + transform(storyAs), + ]); + + allSnippets.forEach((result) => { + expect(result).toEqual(allSnippets[0]); }); - `); - }); - - it('should yield the same result to all syntaxes', async () => { - const allSnippets = await Promise.all([ - transform(inlineMetaSatisfies), - transform(inlineMetaAs), - transform(metaSatisfies), - transform(metaAs), - transform(storySatisfies), - transform(storyAs), - ]); - - allSnippets.forEach((result) => { - expect(result).toEqual(allSnippets[0]); }); }); }); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts index 305d60778dc9..8121c332224c 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts @@ -1,6 +1,5 @@ /* eslint-disable no-underscore-dangle */ import { types as t } from 'storybook/internal/babel'; -import { formatFileContent } from 'storybook/internal/common'; import { isValidPreviewPath, loadCsf, printCsf } from 'storybook/internal/csf-tools'; import prompts from 'prompts'; @@ -202,18 +201,37 @@ export async function csf4Transform(info: FileInfo) { const logger = console; +async function runStoriesCodemod(dryRun: boolean | undefined) { + try { + let globString = '**/*.stories.*'; + if (!process.env.IN_STORYBOOK_SANDBOX) { + logger.log('Please enter the glob for your stories to migrate'); + globString = ( + await prompts({ + type: 'text', + name: 'glob', + message: 'glob', + initial: globString, + }) + ).glob; + } + logger.log('Applying codemod on your stories...'); + await runCodemod(globString, csf4Transform, { dryRun }); + } catch (err: any) { + console.log('err message', err.message); + if (err.message === 'No files matched') { + console.log('going to run again'); + await runStoriesCodemod(dryRun); + } else { + throw err; + } + } +} + export const csf3to4: CommandFix = { id: 'csf-3-to-4', promptType: 'command', async run({ dryRun }) { - logger.log('Please enter the glob for your stories to migrate'); - const { glob: globString } = await prompts({ - type: 'text', - name: 'glob', - message: 'glob', - initial: '**/*.stories.*', - }); - - await runCodemod(globString, csf4Transform, { dryRun }); + await runStoriesCodemod(dryRun); }, }; diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index 4055d84b7bc7..fe86aeeadd00 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -882,10 +882,9 @@ export const runMigrations: Task['run'] = async ({ sandboxDir, template }, { dry template.expected.framework === '@storybook/react-vite' && !template.skipTasks.includes('vitest-integration') ) { - await executeCLIStep(steps.migrate, { + await executeCLIStep(steps.automigrate, { cwd: sandboxDir, argument: 'csf-3-to-4', - optionValues: { glob: 'src/stories/*.stories.*' }, dryRun, debug, }); diff --git a/scripts/utils/cli-step.ts b/scripts/utils/cli-step.ts index b685eb7b16ee..1432f9b264c7 100644 --- a/scripts/utils/cli-step.ts +++ b/scripts/utils/cli-step.ts @@ -82,6 +82,13 @@ export const steps = { glob: { type: 'string' }, }), }, + automigrate: { + command: 'automigrate', + hasArgument: true, + description: 'Run automigrations', + icon: '🤖', + options: createOptions({}), + }, }; export async function executeCLIStep( From b0972bc374bc85086ed3e2c37cdb033660e1fe67 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 17 Jan 2025 11:07:45 +0100 Subject: [PATCH 11/24] remove entrypoint --- code/lib/codemod/package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index db7317edca1f..81ec7b4b59ee 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -28,7 +28,6 @@ }, "./dist/transforms/add-component-parameters.js": "./dist/transforms/add-component-parameters.js", "./dist/transforms/csf-2-to-3.js": "./dist/transforms/csf-2-to-3.js", - "./dist/transforms/csf-3-to-4.js": "./dist/transforms/csf-3-to-4.js", "./dist/transforms/csf-hoist-story-annotations.js": "./dist/transforms/csf-hoist-story-annotations.js", "./dist/transforms/find-implicit-spies.js": "./dist/transforms/find-implicit-spies.js", "./dist/transforms/move-builtin-addons.js": "./dist/transforms/move-builtin-addons.js", @@ -94,7 +93,6 @@ "./src/transforms/storiesof-to-csf.js", "./src/transforms/mdx-to-csf.ts", "./src/transforms/csf-2-to-3.ts", - "./src/transforms/csf-3-to-4.ts", "./src/transforms/csf-hoist-story-annotations.js", "./src/transforms/find-implicit-spies.ts", "./src/transforms/add-component-parameters.js", From 325a554fd790ebd048b2ca547ac290837a54e024 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 17 Jan 2025 11:47:29 +0100 Subject: [PATCH 12/24] only apply codemod to starter stories in sandbox, rename to csf-factories --- .../{csf-3-to-4.test.ts => csf-factories.test.ts} | 6 +++--- .../fixes/{csf-3-to-4.ts => csf-factories.ts} | 10 +++++----- code/lib/cli-storybook/src/automigrate/fixes/index.ts | 6 +++--- scripts/tasks/sandbox-parts.ts | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) rename code/lib/cli-storybook/src/automigrate/fixes/{csf-3-to-4.test.ts => csf-factories.test.ts} (98%) rename code/lib/cli-storybook/src/automigrate/fixes/{csf-3-to-4.ts => csf-factories.ts} (96%) diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts similarity index 98% rename from code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts rename to code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts index 6bb4b438a479..8584580b1b4d 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts @@ -4,19 +4,19 @@ import { formatFileContent } from '@storybook/core/common'; import { dedent } from 'ts-dedent'; -import { csf4Transform } from './csf-3-to-4'; +import { storyToCsfFactory } from './csf-factories'; expect.addSnapshotSerializer({ serialize: (val: any) => (typeof val === 'string' ? val : val.toString()), test: () => true, }); -describe('csf-3-to-4', () => { +describe('csf-factories', () => { describe('stories codemod', () => { const transform = async (source: string) => formatFileContent( 'Component.stories.tsx', - await csf4Transform({ source, path: 'Component.stories.tsx' }) + await storyToCsfFactory({ source, path: 'Component.stories.tsx' }) ); describe('javascript', () => { it('should wrap const declared meta', async () => { diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts similarity index 96% rename from code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts rename to code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts index 8121c332224c..fbf03531ad6c 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-3-to-4.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts @@ -8,7 +8,7 @@ import type { FileInfo } from '../codemod'; import { runCodemod } from '../codemod'; import type { CommandFix } from '../types'; -export async function csf4Transform(info: FileInfo) { +export async function storyToCsfFactory(info: FileInfo) { const csf = loadCsf(info.source, { makeTitle: () => 'FIXME' }); try { csf.parse(); @@ -203,7 +203,7 @@ const logger = console; async function runStoriesCodemod(dryRun: boolean | undefined) { try { - let globString = '**/*.stories.*'; + let globString = 'src/stories/*.stories.*'; if (!process.env.IN_STORYBOOK_SANDBOX) { logger.log('Please enter the glob for your stories to migrate'); globString = ( @@ -216,7 +216,7 @@ async function runStoriesCodemod(dryRun: boolean | undefined) { ).glob; } logger.log('Applying codemod on your stories...'); - await runCodemod(globString, csf4Transform, { dryRun }); + await runCodemod(globString, storyToCsfFactory, { dryRun }); } catch (err: any) { console.log('err message', err.message); if (err.message === 'No files matched') { @@ -228,8 +228,8 @@ async function runStoriesCodemod(dryRun: boolean | undefined) { } } -export const csf3to4: CommandFix = { - id: 'csf-3-to-4', +export const csfFactories: CommandFix = { + id: 'csf-factories', promptType: 'command', async run({ dryRun }) { await runStoriesCodemod(dryRun); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/index.ts b/code/lib/cli-storybook/src/automigrate/fixes/index.ts index acd7d06183d9..2bf67cc44704 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/index.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/index.ts @@ -8,7 +8,7 @@ import { autodocsTags } from './autodocs-tags'; import { autodocsTrue } from './autodocs-true'; import { builderVite } from './builder-vite'; import { cra5 } from './cra5'; -import { csf3to4 } from './csf-3-to-4'; +import { csfFactories } from './csf-factories'; import { eslintPlugin } from './eslint-plugin'; import { initialGlobals } from './initial-globals'; import { mdx1to3 } from './mdx-1-to-3'; @@ -73,5 +73,5 @@ export const allFixes: Fix[] = [ export const initFixes: Fix[] = [eslintPlugin]; // These are specific fixes that only occur when triggered on command, and are hidden otherwise. -// e.g. npx automigrate csf-3-to-4 -export const commandFixes: CommandFix[] = [csf3to4]; +// e.g. npx storybook automigrate csf-factories +export const commandFixes: CommandFix[] = [csfFactories]; diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index fe86aeeadd00..2a86db4a73c3 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -884,7 +884,7 @@ export const runMigrations: Task['run'] = async ({ sandboxDir, template }, { dry ) { await executeCLIStep(steps.automigrate, { cwd: sandboxDir, - argument: 'csf-3-to-4', + argument: 'csf-factories', dryRun, debug, }); From 9df03e6a07e9d4bb45ed2c2d4cd18af632f2a393 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 17 Jan 2025 13:40:40 +0100 Subject: [PATCH 13/24] fix angular and ember build --- code/frameworks/angular/package.json | 1 + code/frameworks/ember/package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index 91a2d3da4c11..2c71784ede70 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -27,6 +27,7 @@ "import": "./dist/index.mjs", "require": "./dist/index.js" }, + "./preset": "./preset.js", "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index e9f712956e5c..94b6468b39f8 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -23,6 +23,7 @@ "import": "./dist/index.mjs", "require": "./dist/index.js" }, + "./preset": "./preset.js", "./node": { "types": "./dist/csf-factory/defineMainConfig.d.ts", "node": "./dist/csf-factory/defineMainConfig.js", From d4e369539c0bc49dc004070c97f84624343e3e82 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 17 Jan 2025 18:25:51 +0100 Subject: [PATCH 14/24] ConfigFile: Support pnp wrapped names --- code/core/src/csf-tools/ConfigFile.test.ts | 13 +++++++++++++ code/core/src/csf-tools/ConfigFile.ts | 2 ++ 2 files changed, 15 insertions(+) diff --git a/code/core/src/csf-tools/ConfigFile.test.ts b/code/core/src/csf-tools/ConfigFile.test.ts index 18b2365f25ec..fc250ada5786 100644 --- a/code/core/src/csf-tools/ConfigFile.test.ts +++ b/code/core/src/csf-tools/ConfigFile.test.ts @@ -1017,6 +1017,19 @@ describe('ConfigFile', () => { expect(config.getNameFromPath(['otherField'])).toEqual('foo'); }); + it(`supports pnp wrapped names`, () => { + const source = dedent` + import type { StorybookConfig } from '@storybook/react-webpack5'; + + const config: StorybookConfig = { + framework: getAbsolutePath('foo'), + } + export default config; + `; + const config = loadConfig(source).parse(); + expect(config.getNameFromPath(['framework'])).toEqual('foo'); + }); + it(`returns undefined when accessing a field that does not exist`, () => { const source = dedent` import type { StorybookConfig } from '@storybook/react-webpack5'; diff --git a/code/core/src/csf-tools/ConfigFile.ts b/code/core/src/csf-tools/ConfigFile.ts index 60bea05b56dd..12815504a06b 100644 --- a/code/core/src/csf-tools/ConfigFile.ts +++ b/code/core/src/csf-tools/ConfigFile.ts @@ -499,6 +499,8 @@ export class ConfigFile { value = prop.value.value; } }); + } else if (t.isCallExpression(node)) { + value = this._getPnpWrappedValue(node); } if (!value) { From 664819839cf6e12b354a8e5868f005cce5dfc0aa Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 17 Jan 2025 19:01:51 +0100 Subject: [PATCH 15/24] add codemod for main/preview in factory format --- .../automigrate/fixes/csf-factories.test.ts | 126 ++++++++++- .../src/automigrate/fixes/csf-factories.ts | 199 +++++++++++++++++- .../src/automigrate/helpers/mainConfigFile.ts | 1 + .../cli-storybook/src/automigrate/index.ts | 47 +++-- .../cli-storybook/src/automigrate/types.ts | 6 +- 5 files changed, 357 insertions(+), 22 deletions(-) diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts index 8584580b1b4d..880b1b74b704 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts @@ -4,7 +4,7 @@ import { formatFileContent } from '@storybook/core/common'; import { dedent } from 'ts-dedent'; -import { storyToCsfFactory } from './csf-factories'; +import { configToCsfFactory, storyToCsfFactory } from './csf-factories'; expect.addSnapshotSerializer({ serialize: (val: any) => (typeof val === 'string' ? val : val.toString()), @@ -12,6 +12,130 @@ expect.addSnapshotSerializer({ }); describe('csf-factories', () => { + describe('main/preview codemod: general parsing functionality', () => { + const transform = async (source: string) => + ( + await configToCsfFactory( + { source, path: 'main.ts' }, + { configType: 'main', frameworkPackage: '@storybook/react-vite' } + ) + ).trim(); + + it('should wrap defineMain call from inline default export', async () => { + await expect( + transform(dedent` + export default { + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }; + `) + ).resolves.toMatchInlineSnapshot(` + import { defineMain } from '@storybook/react-vite/node'; + + export default defineMain({ + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }); + `); + }); + it('should wrap defineMain call from const declared default export', async () => { + await expect( + transform(dedent` + const config = { + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }; + + export default config; + `) + ).resolves.toMatchInlineSnapshot(` + import { defineMain } from '@storybook/react-vite/node'; + + export default defineMain({ + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }); + `); + }); + it('should wrap defineMain call from const declared default export and default export mix', async () => { + await expect( + transform(dedent` + export const tags = []; + const config = { + framework: '@storybook/react-vite', + }; + + export default config; + `) + ).resolves.toMatchInlineSnapshot(` + import { defineMain } from '@storybook/react-vite/node'; + + const config = { + framework: '@storybook/react-vite', + tags: [], + }; + + export default config; + `); + }); + it('should wrap defineMain call from named exports format', async () => { + await expect( + transform(dedent` + export const stories = ['../src/**/*.stories.@(js|jsx|ts|tsx)']; + export const addons = ['@storybook/addon-essentials']; + export const framework = '@storybook/react-vite'; + `) + ).resolves.toMatchInlineSnapshot(` + import { defineMain } from '@storybook/react-vite/node'; + + export default defineMain({ + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }); + `); + }); + it('should not add additional imports if there is already one', async () => { + const transformed = await transform(dedent` + import { defineMain } from '@storybook/react-vite/node'; + const config = {}; + + export default config; + `); + expect( + transformed.match(/import { defineMain } from '@storybook\/react-vite\/node'/g) + ).toHaveLength(1); + }); + }); + describe('preview specific functionality', () => { + const transform = async (source: string) => + ( + await configToCsfFactory( + { source, path: 'preview.ts' }, + { configType: 'preview', frameworkPackage: '@storybook/react-vite' } + ) + ).trim(); + + it('should contain a named config export', async () => { + await expect( + transform(dedent` + export default { + tags: ['test'], + }; + `) + ).resolves.toMatchInlineSnapshot(` + import { definePreview } from '@storybook/react-vite/browser'; + + export default definePreview({ + tags: ['test'], + }); + `); + }); + }); describe('stories codemod', () => { const transform = async (source: string) => formatFileContent( diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts index fbf03531ad6c..1a946d1b41fe 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts @@ -1,13 +1,190 @@ /* eslint-disable no-underscore-dangle */ import { types as t } from 'storybook/internal/babel'; -import { isValidPreviewPath, loadCsf, printCsf } from 'storybook/internal/csf-tools'; - +import { formatFileContent } from 'storybook/internal/common'; +import { + isValidPreviewPath, + loadConfig, + loadCsf, + printConfig, + printCsf, +} from 'storybook/internal/csf-tools'; + +import picocolors from 'picocolors'; import prompts from 'prompts'; import type { FileInfo } from '../codemod'; import { runCodemod } from '../codemod'; +import { detectRenderer } from '../helpers/detectRenderer'; +import { + getFrameworkPackageName, + getRendererPackageNameFromFramework, +} from '../helpers/mainConfigFile'; import type { CommandFix } from '../types'; +export async function configToCsfFactory( + info: FileInfo, + { configType, frameworkPackage }: { configType?: 'main' | 'preview'; frameworkPackage: string }, + { dryRun = false, skipFormatting = false }: { dryRun?: boolean; skipFormatting?: boolean } = {} +) { + const config = loadConfig(info.source); + try { + config.parse(); + } catch (err) { + logger.log(`Error when parsing ${info.path}, skipping:\n${err}`); + return info.source; + } + + configType = configType || (info.path.includes('preview') ? 'preview' : 'main'); + const methodName = configType === 'main' ? 'defineMain' : 'definePreview'; + + const programNode = config._ast.program; + const hasNamedExports = Object.keys(config._exportDecls).length > 0; + + /** + * Scenario 1: Mixed exports + * + * ``` + * export const tags = []; + * export default { + * parameters: {}, + * }; + * ``` + * + * Transform into: `export default defineMain({ tags: [], parameters: {} })` + */ + if (config._exportsObject && hasNamedExports) { + const exportDecls = config._exportDecls; + + for (const [name, decl] of Object.entries(exportDecls)) { + if (decl.init) { + config._exportsObject.properties.push(t.objectProperty(t.identifier(name), decl.init)); + } + } + + programNode.body = programNode.body.filter((node) => { + if (t.isExportNamedDeclaration(node) && node.declaration) { + if (t.isVariableDeclaration(node.declaration)) { + node.declaration.declarations = node.declaration.declarations.filter( + (decl) => t.isIdentifier(decl.id) && !exportDecls[decl.id.name] + ); + return node.declaration.declarations.length > 0; + } + } + return true; + }); + } else if (config._exportsObject) { + /** + * Scenario 2: Default exports + * + * - Syntax 1: `default export const config = {}; export default config;` + * - Syntax 2: `export default {};` + * + * Transform into: `export default defineMain({})` + */ + const defineConfigCall = t.callExpression(t.identifier(methodName), [config._exportsObject]); + + let exportDefaultNode = null as any as t.ExportDefaultDeclaration; + let declarationNodeIndex = -1; + + programNode.body.forEach((node) => { + // Detect Syntax 1 + if (t.isExportDefaultDeclaration(node) && t.isIdentifier(node.declaration)) { + const declarationName = node.declaration.name; + + declarationNodeIndex = programNode.body.findIndex( + (n) => + t.isVariableDeclaration(n) && + n.declarations.some( + (d) => + t.isIdentifier(d.id) && + d.id.name === declarationName && + t.isObjectExpression(d.init) + ) + ); + + if (declarationNodeIndex !== -1) { + exportDefaultNode = node; + // remove the original declaration as it will become a default export + const declarationNode = programNode.body[declarationNodeIndex]; + if (t.isVariableDeclaration(declarationNode)) { + const id = declarationNode.declarations[0].id; + const variableName = t.isIdentifier(id) && id.name; + + if (variableName) { + programNode.body.splice(declarationNodeIndex, 1); + } + } + } + } else if (t.isExportDefaultDeclaration(node) && t.isObjectExpression(node.declaration)) { + // Detect Syntax 2 + exportDefaultNode = node; + } + }); + + if (exportDefaultNode !== null) { + exportDefaultNode.declaration = defineConfigCall; + } + } else if (hasNamedExports) { + /** + * Scenario 3: Named exports export const foo = {}; export bar = ''; + * + * Transform into: export default defineMain({ foo: {}, bar: '' }); + */ + const exportDecls = config._exportDecls; + const defineConfigProps = []; + + // Collect properties from named exports + for (const [name, decl] of Object.entries(exportDecls)) { + if (decl.init) { + defineConfigProps.push(t.objectProperty(t.identifier(name), decl.init)); + } + } + + // Construct the `define` call + const defineConfigCall = t.callExpression(t.identifier(methodName), [ + t.objectExpression(defineConfigProps), + ]); + + // Remove all related named exports + programNode.body = programNode.body.filter((node) => { + if (t.isExportNamedDeclaration(node) && node.declaration) { + if (t.isVariableDeclaration(node.declaration)) { + node.declaration.declarations = node.declaration.declarations.filter( + (decl) => t.isIdentifier(decl.id) && !exportDecls[decl.id.name] + ); + return node.declaration.declarations.length > 0; + } + } + return true; + }); + + // Add the new export default declaration + programNode.body.push(t.exportDefaultDeclaration(defineConfigCall)); + } + + const configImport = t.importDeclaration( + [t.importSpecifier(t.identifier(methodName), t.identifier(methodName))], + t.stringLiteral(frameworkPackage + `/${configType === 'main' ? 'node' : 'browser'}`) + ); + // only add the import if it doesn't exist yet + if ( + !programNode.body.some( + (node) => t.isImportDeclaration(node) && node.source.value === configImport.source.value + ) + ) { + programNode.body.unshift(configImport); + } + + const output = printConfig(config).code; + + if (dryRun) { + logger.log(`Would write to ${picocolors.yellow(info.path)}:\n${picocolors.green(output)}`); + return info.source; + } + + return skipFormatting ? output : formatFileContent(info.path, output); +} + export async function storyToCsfFactory(info: FileInfo) { const csf = loadCsf(info.source, { makeTitle: () => 'FIXME' }); try { @@ -231,7 +408,23 @@ async function runStoriesCodemod(dryRun: boolean | undefined) { export const csfFactories: CommandFix = { id: 'csf-factories', promptType: 'command', - async run({ dryRun }) { + async run({ dryRun, mainConfig, mainConfigPath, previewConfigPath, packageJson }) { + const frameworkPackageName = getFrameworkPackageName(mainConfig); + + const rendererPackageName = + (await getRendererPackageNameFromFramework(frameworkPackageName as string)) ?? + (await detectRenderer(packageJson)); + + console.log({ rendererPackageName, frameworkPackageName }); + await runStoriesCodemod(dryRun); + logger.log('Applying codemod on your main config...'); + await runCodemod(mainConfigPath, (fileInfo) => + configToCsfFactory(fileInfo, 'main', { dryRun }) + ); + logger.log('Applying codemod on your preview config...'); + await runCodemod(previewConfigPath, (fileInfo) => + configToCsfFactory(fileInfo, 'preview', { dryRun }) + ); }, }; diff --git a/code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts b/code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts index 57aa4bf7ce07..717f92b646b3 100644 --- a/code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts +++ b/code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts @@ -157,6 +157,7 @@ export const getStorybookData = async ({ storybookVersion, mainConfigPath, previewConfigPath, + packageJson, }; }; export type GetStorybookData = typeof getStorybookData; diff --git a/code/lib/cli-storybook/src/automigrate/index.ts b/code/lib/cli-storybook/src/automigrate/index.ts index a25455e38b1a..4dd8e7445895 100644 --- a/code/lib/cli-storybook/src/automigrate/index.ts +++ b/code/lib/cli-storybook/src/automigrate/index.ts @@ -2,13 +2,13 @@ import { createWriteStream } from 'node:fs'; import { rename, rm } from 'node:fs/promises'; import { join } from 'node:path'; +import type { PackageJson } from 'storybook/internal/common'; import { type JsPackageManager, JsPackageManagerFactory, - getCoercedStorybookVersion, - getStorybookInfo, temporaryFile, } from 'storybook/internal/common'; +import type { StorybookConfigRaw } from 'storybook/internal/types'; import boxen from 'boxen'; import picocolors from 'picocolors'; @@ -77,17 +77,17 @@ export const doAutomigrate = async (options: AutofixOptionsFromCLI) => { force: options.packageManager, }); - const [packageJson, storybookVersion] = await Promise.all([ - packageManager.retrievePackageJson(), - getCoercedStorybookVersion(packageManager), - ]); - const { - configDir: inferredConfigDir, - mainConfig: mainConfigPath, - previewConfig: previewConfigPath, - } = getStorybookInfo(packageJson, options.configDir); - const configDir = options.configDir || inferredConfigDir || '.storybook'; + mainConfig, + mainConfigPath, + previewConfigPath, + storybookVersion, + configDir, + packageJson, + } = await getStorybookData({ + configDir: options.configDir, + packageManager, + }); if (!storybookVersion) { throw new Error('Could not determine Storybook version'); @@ -99,10 +99,12 @@ export const doAutomigrate = async (options: AutofixOptionsFromCLI) => { const outcome = await automigrate({ ...options, + packageJson, packageManager, storybookVersion, beforeVersion: storybookVersion, mainConfigPath, + mainConfig, previewConfigPath, configDir, isUpgrade: false, @@ -120,8 +122,10 @@ export const automigrate = async ({ dryRun, yes, packageManager, + packageJson, list, configDir, + mainConfig, mainConfigPath, previewConfigPath, storybookVersion, @@ -149,7 +153,9 @@ export const automigrate = async ({ mainConfigPath, previewConfigPath, packageManager, + packageJson, dryRun, + mainConfig, result: null, }); @@ -185,9 +191,12 @@ export const automigrate = async ({ const { fixResults, fixSummary, preCheckFailure } = await runFixes({ fixes, packageManager, + packageJson, rendererPackage, skipInstall, configDir, + previewConfigPath, + mainConfig, mainConfigPath, storybookVersion, beforeVersion, @@ -233,7 +242,10 @@ export async function runFixes({ skipInstall, configDir, packageManager, + packageJson, + mainConfig, mainConfigPath, + previewConfigPath, storybookVersion, beforeVersion, isUpgrade, @@ -245,7 +257,10 @@ export async function runFixes({ skipInstall?: boolean; configDir: string; packageManager: JsPackageManager; + packageJson: PackageJson; mainConfigPath: string; + previewConfigPath?: string; + mainConfig: StorybookConfigRaw; storybookVersion: string; beforeVersion: string; isUpgrade?: boolean; @@ -262,11 +277,6 @@ export async function runFixes({ let result; try { - const { mainConfig, previewConfigPath } = await getStorybookData({ - configDir, - packageManager, - }); - if ( (isUpgrade && semver.satisfies(beforeVersion, f.versionRange[0], { includePrerelease: true }) && @@ -402,6 +412,9 @@ export async function runFixes({ packageManager, dryRun, mainConfigPath, + previewConfigPath, + packageJson, + mainConfig, skipInstall, }); logger.info(`✅ ran ${picocolors.cyan(f.id)} migration`); diff --git a/code/lib/cli-storybook/src/automigrate/types.ts b/code/lib/cli-storybook/src/automigrate/types.ts index 3c62e6343cab..f4eb22d9e740 100644 --- a/code/lib/cli-storybook/src/automigrate/types.ts +++ b/code/lib/cli-storybook/src/automigrate/types.ts @@ -1,4 +1,4 @@ -import type { JsPackageManager, PackageManagerName } from 'storybook/internal/common'; +import type { JsPackageManager, PackageJson, PackageManagerName } from 'storybook/internal/common'; import type { StorybookConfigRaw } from 'storybook/internal/types'; export interface CheckOptions { @@ -13,10 +13,12 @@ export interface CheckOptions { export interface RunOptions { packageManager: JsPackageManager; + packageJson: PackageJson; result: ResultType; dryRun?: boolean; mainConfigPath: string; previewConfigPath?: string; + mainConfig: StorybookConfigRaw; skipInstall?: boolean; } @@ -73,8 +75,10 @@ export enum PreCheckFailure { export interface AutofixOptions extends Omit { packageManager: JsPackageManager; + packageJson: PackageJson; mainConfigPath: string; previewConfigPath?: string; + mainConfig: StorybookConfigRaw; /** The version of Storybook before the migration. */ beforeVersion: string; storybookVersion: string; From 211fb4b76efcbc52f50147dba64dc6d68e541802 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 20 Jan 2025 13:03:51 +0100 Subject: [PATCH 16/24] add storybook config + addon sync codemod --- code/core/src/csf-tools/ConfigFile.test.ts | 12 + code/core/src/csf-tools/ConfigFile.ts | 15 +- .../src/automigrate/fixes/csf-factories.ts | 430 ------------------ .../src/automigrate/fixes/index.ts | 2 +- .../src/codemod/csf-factories.ts | 75 +++ .../helpers/config-to-csf-factory.test.ts | 174 +++++++ .../codemod/helpers/config-to-csf-factory.ts | 177 +++++++ .../helpers/csf-factories-utils.test.ts | 69 +++ .../codemod/helpers/csf-factories-utils.ts | 101 ++++ .../helpers/get-addon-annotations.test.ts | 25 + .../codemod/helpers/get-addon-annotations.ts | 41 ++ .../helpers/story-to-csf-factory.test.ts} | 282 ++++-------- .../codemod/helpers/story-to-csf-factory.ts | 171 +++++++ scripts/tasks/sandbox-parts.ts | 45 +- scripts/tasks/sandbox.ts | 5 +- 15 files changed, 934 insertions(+), 690 deletions(-) delete mode 100644 code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts create mode 100644 code/lib/cli-storybook/src/codemod/csf-factories.ts create mode 100644 code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts create mode 100644 code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts create mode 100644 code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts create mode 100644 code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts create mode 100644 code/lib/cli-storybook/src/codemod/helpers/get-addon-annotations.test.ts create mode 100644 code/lib/cli-storybook/src/codemod/helpers/get-addon-annotations.ts rename code/lib/cli-storybook/src/{automigrate/fixes/csf-factories.test.ts => codemod/helpers/story-to-csf-factory.test.ts} (53%) create mode 100644 code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts diff --git a/code/core/src/csf-tools/ConfigFile.test.ts b/code/core/src/csf-tools/ConfigFile.test.ts index fc250ada5786..b4c3895538f8 100644 --- a/code/core/src/csf-tools/ConfigFile.test.ts +++ b/code/core/src/csf-tools/ConfigFile.test.ts @@ -245,6 +245,18 @@ describe('ConfigFile', () => { }); describe('factory config', () => { + it('parses correctly', () => { + const source = dedent` + import { defineConfig } from '@storybook/react-vite/browser'; + + const config = defineConfig({ + framework: 'foo', + }); + export default config; + `; + const config = loadConfig(source).parse(); + expect(config.getNameFromPath(['framework'])).toEqual('foo'); + }); it('found scalar', () => { expect( getField( diff --git a/code/core/src/csf-tools/ConfigFile.ts b/code/core/src/csf-tools/ConfigFile.ts index 12815504a06b..7ea42448dfc6 100644 --- a/code/core/src/csf-tools/ConfigFile.ts +++ b/code/core/src/csf-tools/ConfigFile.ts @@ -25,18 +25,8 @@ const getCsfParsingErrorMessage = ({ foundType: string | undefined; node: any | undefined; }) => { - let nodeInfo = ''; - if (node) { - try { - nodeInfo = JSON.stringify(node); - } catch (e) { - // - } - } - return dedent` CSF Parsing error: Expected '${expectedType}' but found '${foundType}' instead in '${node?.type}'. - ${nodeInfo} `; }; @@ -215,6 +205,11 @@ export class ConfigFile { decl = unwrap(decl); + // csf factory + if (t.isCallExpression(decl) && t.isObjectExpression(decl.arguments[0])) { + decl = decl.arguments[0]; + } + if (t.isObjectExpression(decl)) { self._parseExportsObject(decl); } else { diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts b/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts deleted file mode 100644 index 1a946d1b41fe..000000000000 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.ts +++ /dev/null @@ -1,430 +0,0 @@ -/* eslint-disable no-underscore-dangle */ -import { types as t } from 'storybook/internal/babel'; -import { formatFileContent } from 'storybook/internal/common'; -import { - isValidPreviewPath, - loadConfig, - loadCsf, - printConfig, - printCsf, -} from 'storybook/internal/csf-tools'; - -import picocolors from 'picocolors'; -import prompts from 'prompts'; - -import type { FileInfo } from '../codemod'; -import { runCodemod } from '../codemod'; -import { detectRenderer } from '../helpers/detectRenderer'; -import { - getFrameworkPackageName, - getRendererPackageNameFromFramework, -} from '../helpers/mainConfigFile'; -import type { CommandFix } from '../types'; - -export async function configToCsfFactory( - info: FileInfo, - { configType, frameworkPackage }: { configType?: 'main' | 'preview'; frameworkPackage: string }, - { dryRun = false, skipFormatting = false }: { dryRun?: boolean; skipFormatting?: boolean } = {} -) { - const config = loadConfig(info.source); - try { - config.parse(); - } catch (err) { - logger.log(`Error when parsing ${info.path}, skipping:\n${err}`); - return info.source; - } - - configType = configType || (info.path.includes('preview') ? 'preview' : 'main'); - const methodName = configType === 'main' ? 'defineMain' : 'definePreview'; - - const programNode = config._ast.program; - const hasNamedExports = Object.keys(config._exportDecls).length > 0; - - /** - * Scenario 1: Mixed exports - * - * ``` - * export const tags = []; - * export default { - * parameters: {}, - * }; - * ``` - * - * Transform into: `export default defineMain({ tags: [], parameters: {} })` - */ - if (config._exportsObject && hasNamedExports) { - const exportDecls = config._exportDecls; - - for (const [name, decl] of Object.entries(exportDecls)) { - if (decl.init) { - config._exportsObject.properties.push(t.objectProperty(t.identifier(name), decl.init)); - } - } - - programNode.body = programNode.body.filter((node) => { - if (t.isExportNamedDeclaration(node) && node.declaration) { - if (t.isVariableDeclaration(node.declaration)) { - node.declaration.declarations = node.declaration.declarations.filter( - (decl) => t.isIdentifier(decl.id) && !exportDecls[decl.id.name] - ); - return node.declaration.declarations.length > 0; - } - } - return true; - }); - } else if (config._exportsObject) { - /** - * Scenario 2: Default exports - * - * - Syntax 1: `default export const config = {}; export default config;` - * - Syntax 2: `export default {};` - * - * Transform into: `export default defineMain({})` - */ - const defineConfigCall = t.callExpression(t.identifier(methodName), [config._exportsObject]); - - let exportDefaultNode = null as any as t.ExportDefaultDeclaration; - let declarationNodeIndex = -1; - - programNode.body.forEach((node) => { - // Detect Syntax 1 - if (t.isExportDefaultDeclaration(node) && t.isIdentifier(node.declaration)) { - const declarationName = node.declaration.name; - - declarationNodeIndex = programNode.body.findIndex( - (n) => - t.isVariableDeclaration(n) && - n.declarations.some( - (d) => - t.isIdentifier(d.id) && - d.id.name === declarationName && - t.isObjectExpression(d.init) - ) - ); - - if (declarationNodeIndex !== -1) { - exportDefaultNode = node; - // remove the original declaration as it will become a default export - const declarationNode = programNode.body[declarationNodeIndex]; - if (t.isVariableDeclaration(declarationNode)) { - const id = declarationNode.declarations[0].id; - const variableName = t.isIdentifier(id) && id.name; - - if (variableName) { - programNode.body.splice(declarationNodeIndex, 1); - } - } - } - } else if (t.isExportDefaultDeclaration(node) && t.isObjectExpression(node.declaration)) { - // Detect Syntax 2 - exportDefaultNode = node; - } - }); - - if (exportDefaultNode !== null) { - exportDefaultNode.declaration = defineConfigCall; - } - } else if (hasNamedExports) { - /** - * Scenario 3: Named exports export const foo = {}; export bar = ''; - * - * Transform into: export default defineMain({ foo: {}, bar: '' }); - */ - const exportDecls = config._exportDecls; - const defineConfigProps = []; - - // Collect properties from named exports - for (const [name, decl] of Object.entries(exportDecls)) { - if (decl.init) { - defineConfigProps.push(t.objectProperty(t.identifier(name), decl.init)); - } - } - - // Construct the `define` call - const defineConfigCall = t.callExpression(t.identifier(methodName), [ - t.objectExpression(defineConfigProps), - ]); - - // Remove all related named exports - programNode.body = programNode.body.filter((node) => { - if (t.isExportNamedDeclaration(node) && node.declaration) { - if (t.isVariableDeclaration(node.declaration)) { - node.declaration.declarations = node.declaration.declarations.filter( - (decl) => t.isIdentifier(decl.id) && !exportDecls[decl.id.name] - ); - return node.declaration.declarations.length > 0; - } - } - return true; - }); - - // Add the new export default declaration - programNode.body.push(t.exportDefaultDeclaration(defineConfigCall)); - } - - const configImport = t.importDeclaration( - [t.importSpecifier(t.identifier(methodName), t.identifier(methodName))], - t.stringLiteral(frameworkPackage + `/${configType === 'main' ? 'node' : 'browser'}`) - ); - // only add the import if it doesn't exist yet - if ( - !programNode.body.some( - (node) => t.isImportDeclaration(node) && node.source.value === configImport.source.value - ) - ) { - programNode.body.unshift(configImport); - } - - const output = printConfig(config).code; - - if (dryRun) { - logger.log(`Would write to ${picocolors.yellow(info.path)}:\n${picocolors.green(output)}`); - return info.source; - } - - return skipFormatting ? output : formatFileContent(info.path, output); -} - -export async function storyToCsfFactory(info: FileInfo) { - const csf = loadCsf(info.source, { makeTitle: () => 'FIXME' }); - try { - csf.parse(); - } catch (err) { - logger.log(`Error when parsing ${info.path}, skipping:\n${err}`); - return info.source; - } - - const metaVariableName = 'meta'; - - /** - * Add the preview import if it doesn't exist yet: - * - * `import { config } from '#.storybook/preview'`; - */ - const programNode = csf._ast.program; - let foundConfigImport = false; - - // Check if a root-level constant named 'config' exists - const hasRootLevelConfig = programNode.body.some( - (n) => - t.isVariableDeclaration(n) && - n.declarations.some((declaration) => t.isIdentifier(declaration.id, { name: 'config' })) - ); - - const sbConfigImportName = hasRootLevelConfig ? 'storybookConfig' : 'config'; - - const sbConfigImportSpecifier = t.importSpecifier( - t.identifier(sbConfigImportName), - t.identifier('config') - ); - - programNode.body.forEach((node) => { - if (t.isImportDeclaration(node) && isValidPreviewPath(node.source.value)) { - const hasConfigSpecifier = node.specifiers.some( - (specifier) => - t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported, { name: 'config' }) - ); - - if (!hasConfigSpecifier) { - node.specifiers.push(sbConfigImportSpecifier); - } - - foundConfigImport = true; - } - }); - - const hasMeta = !!csf._meta; - - Object.entries(csf._storyExports).forEach(([key, decl]) => { - const id = decl.id; - const declarator = decl as t.VariableDeclarator; - let init = t.isVariableDeclarator(declarator) ? declarator.init : undefined; - - if (t.isIdentifier(id) && init) { - if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) { - init = init.expression; - } - - if (t.isObjectExpression(init)) { - const typeAnnotation = id.typeAnnotation; - // Remove type annotation as it's now inferred - if (typeAnnotation) { - id.typeAnnotation = null; - } - - // Wrap the object in `meta.story()` - declarator.init = t.callExpression( - t.memberExpression(t.identifier(metaVariableName), t.identifier('story')), - [init] - ); - } else if (t.isArrowFunctionExpression(init)) { - // Transform CSF1 to meta.story({ render: }) - const renderProperty = t.objectProperty(t.identifier('render'), init); - - const objectExpression = t.objectExpression([renderProperty]); - - declarator.init = t.callExpression( - t.memberExpression(t.identifier(metaVariableName), t.identifier('story')), - [objectExpression] - ); - } - } - }); - - // modify meta - if (csf._metaPath) { - let declaration = csf._metaPath.node.declaration; - if (t.isTSSatisfiesExpression(declaration) || t.isTSAsExpression(declaration)) { - declaration = declaration.expression; - } - - if (t.isObjectExpression(declaration)) { - const metaVariable = t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier(metaVariableName), - t.callExpression( - t.memberExpression(t.identifier(sbConfigImportName), t.identifier('meta')), - [declaration] - ) - ), - ]); - csf._metaPath.replaceWith(metaVariable); - } else if (t.isIdentifier(declaration)) { - /** - * Transform const declared metas: - * - * `const meta = {}; export default meta;` - * - * Into a meta call: - * - * `const meta = config.meta({ title: 'A' });` - */ - const binding = csf._metaPath.scope.getBinding(declaration.name); - if (binding && binding.path.isVariableDeclarator()) { - const originalName = declaration.name; - - // Always rename the meta variable to 'meta' - binding.path.node.id = t.identifier(metaVariableName); - - let init = binding.path.node.init; - if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) { - init = init.expression; - } - if (t.isObjectExpression(init)) { - binding.path.node.init = t.callExpression( - t.memberExpression(t.identifier(sbConfigImportName), t.identifier('meta')), - [init] - ); - } - - // Update all references to the original name - csf._metaPath.scope.rename(originalName, metaVariableName); - } - - // Remove the default export, it's not needed anymore - csf._metaPath.remove(); - } - } - - if (hasMeta && !foundConfigImport) { - const configImport = t.importDeclaration( - [sbConfigImportSpecifier], - t.stringLiteral('#.storybook/preview') - ); - programNode.body.unshift(configImport); - } - - // Remove type imports – now inferred – from @storybook/* packages - const disallowlist = [ - 'Story', - 'StoryFn', - 'StoryObj', - 'Meta', - 'MetaObj', - 'ComponentStory', - 'ComponentMeta', - ]; - - programNode.body = programNode.body.filter((node) => { - if (t.isImportDeclaration(node)) { - const { source, specifiers } = node; - - if (source.value.startsWith('@storybook/')) { - const allowedSpecifiers = specifiers.filter((specifier) => { - if (t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) { - return !disallowlist.includes(specifier.imported.name); - } - // Retain non-specifier imports (e.g., namespace imports) - return true; - }); - - // Remove the entire import if no specifiers are left - if (allowedSpecifiers.length > 0) { - node.specifiers = allowedSpecifiers; - return true; - } - - // Remove the import if no specifiers remain - return false; - } - } - - // Retain all other nodes - return true; - }); - - return printCsf(csf).code; -} - -const logger = console; - -async function runStoriesCodemod(dryRun: boolean | undefined) { - try { - let globString = 'src/stories/*.stories.*'; - if (!process.env.IN_STORYBOOK_SANDBOX) { - logger.log('Please enter the glob for your stories to migrate'); - globString = ( - await prompts({ - type: 'text', - name: 'glob', - message: 'glob', - initial: globString, - }) - ).glob; - } - logger.log('Applying codemod on your stories...'); - await runCodemod(globString, storyToCsfFactory, { dryRun }); - } catch (err: any) { - console.log('err message', err.message); - if (err.message === 'No files matched') { - console.log('going to run again'); - await runStoriesCodemod(dryRun); - } else { - throw err; - } - } -} - -export const csfFactories: CommandFix = { - id: 'csf-factories', - promptType: 'command', - async run({ dryRun, mainConfig, mainConfigPath, previewConfigPath, packageJson }) { - const frameworkPackageName = getFrameworkPackageName(mainConfig); - - const rendererPackageName = - (await getRendererPackageNameFromFramework(frameworkPackageName as string)) ?? - (await detectRenderer(packageJson)); - - console.log({ rendererPackageName, frameworkPackageName }); - - await runStoriesCodemod(dryRun); - logger.log('Applying codemod on your main config...'); - await runCodemod(mainConfigPath, (fileInfo) => - configToCsfFactory(fileInfo, 'main', { dryRun }) - ); - logger.log('Applying codemod on your preview config...'); - await runCodemod(previewConfigPath, (fileInfo) => - configToCsfFactory(fileInfo, 'preview', { dryRun }) - ); - }, -}; diff --git a/code/lib/cli-storybook/src/automigrate/fixes/index.ts b/code/lib/cli-storybook/src/automigrate/fixes/index.ts index 2bf67cc44704..c66b0106ce5d 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/index.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/index.ts @@ -1,3 +1,4 @@ +import { csfFactories } from '../../codemod/csf-factories'; import type { CommandFix, Fix } from '../types'; import { addonA11yAddonTest } from './addon-a11y-addon-test'; import { addonPostCSS } from './addon-postcss'; @@ -8,7 +9,6 @@ import { autodocsTags } from './autodocs-tags'; import { autodocsTrue } from './autodocs-true'; import { builderVite } from './builder-vite'; import { cra5 } from './cra5'; -import { csfFactories } from './csf-factories'; import { eslintPlugin } from './eslint-plugin'; import { initialGlobals } from './initial-globals'; import { mdx1to3 } from './mdx-1-to-3'; diff --git a/code/lib/cli-storybook/src/codemod/csf-factories.ts b/code/lib/cli-storybook/src/codemod/csf-factories.ts new file mode 100644 index 000000000000..963aa3649152 --- /dev/null +++ b/code/lib/cli-storybook/src/codemod/csf-factories.ts @@ -0,0 +1,75 @@ +import prompts from 'prompts'; + +import { runCodemod } from '../automigrate/codemod'; +import { getFrameworkPackageName } from '../automigrate/helpers/mainConfigFile'; +import type { CommandFix } from '../automigrate/types'; +import { configToCsfFactory } from './helpers/config-to-csf-factory'; +import { syncStorybookAddons } from './helpers/csf-factories-utils'; +import { storyToCsfFactory } from './helpers/story-to-csf-factory'; + +export const logger = console; + +async function runStoriesCodemod(dryRun: boolean | undefined) { + try { + let globString = 'src/stories/*.stories.*'; + if (!process.env.IN_STORYBOOK_SANDBOX) { + logger.log('Please enter the glob for your stories to migrate'); + globString = ( + await prompts({ + type: 'text', + name: 'glob', + message: 'glob', + initial: globString, + }) + ).glob; + } + await runCodemod(globString, storyToCsfFactory, { dryRun }); + } catch (err: any) { + console.log('err message', err.message); + if (err.message === 'No files matched') { + console.log('going to run again'); + await runStoriesCodemod(dryRun); + } else { + throw err; + } + } +} + +export const csfFactories: CommandFix = { + id: 'csf-factories', + promptType: 'command', + async run({ + dryRun, + mainConfig, + mainConfigPath, + previewConfigPath, + packageJson, + packageManager, + }) { + logger.log(`Adding imports map in ${packageManager.packageJsonPath()}`); + packageJson.imports = { + ...packageJson.imports, + // @ts-expect-error we need to upgrade type-fest + '#*': ['./*', './*.ts', './*.tsx', './*.js', './*.jsx'], + }; + await packageManager.writePackageJson(packageJson); + + logger.log('Applying codemod on your stories...'); + await runStoriesCodemod(dryRun); + + logger.log('Applying codemod on your main config...'); + const frameworkPackage = + getFrameworkPackageName(mainConfig) || '@storybook/your-framework-here'; + await runCodemod(mainConfigPath, (fileInfo) => + configToCsfFactory(fileInfo, { configType: 'main', frameworkPackage }, { dryRun }) + ); + + logger.log('Applying codemod on your preview config...'); + await runCodemod(previewConfigPath, (fileInfo) => + configToCsfFactory(fileInfo, { configType: 'preview', frameworkPackage }, { dryRun }) + ); + + logger.log('Synchronizing addons between main and preview config...'); + await syncStorybookAddons(mainConfig, previewConfigPath!); + }, +}; diff --git a/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts b/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts new file mode 100644 index 000000000000..847368f71e15 --- /dev/null +++ b/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts @@ -0,0 +1,174 @@ +import { describe, expect, it } from 'vitest'; + +import { dedent } from 'ts-dedent'; + +import { configToCsfFactory } from './config-to-csf-factory'; + +expect.addSnapshotSerializer({ + serialize: (val: any) => (typeof val === 'string' ? val : val.toString()), + test: () => true, +}); + +describe('main/preview codemod: general parsing functionality', () => { + const transform = async (source: string) => + ( + await configToCsfFactory( + { source, path: 'main.ts' }, + { configType: 'main', frameworkPackage: '@storybook/react-vite' } + ) + ).trim(); + + it('should wrap defineMain call from inline default export', async () => { + await expect( + transform(dedent` + export default { + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }; + `) + ).resolves.toMatchInlineSnapshot(` + import { defineMain } from '@storybook/react-vite/node'; + + export default defineMain({ + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }); + `); + }); + it('should wrap defineMain call from const declared default export', async () => { + await expect( + transform(dedent` + const config = { + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }; + + export default config; + `) + ).resolves.toMatchInlineSnapshot(` + import { defineMain } from '@storybook/react-vite/node'; + + export default defineMain({ + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }); + `); + }); + it('should wrap defineMain call from const declared default export and default export mix', async () => { + await expect( + transform(dedent` + export const tags = []; + const config = { + framework: '@storybook/react-vite', + }; + + export default config; + `) + ).resolves.toMatchInlineSnapshot(` + import { defineMain } from '@storybook/react-vite/node'; + + const config = { + framework: '@storybook/react-vite', + tags: [], + }; + + export default config; + `); + }); + it('should wrap defineMain call from named exports format', async () => { + await expect( + transform(dedent` + export const stories = ['../src/**/*.stories.@(js|jsx|ts|tsx)']; + export const addons = ['@storybook/addon-essentials']; + export const framework = '@storybook/react-vite'; + `) + ).resolves.toMatchInlineSnapshot(` + import { defineMain } from '@storybook/react-vite/node'; + + export default defineMain({ + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-essentials'], + framework: '@storybook/react-vite', + }); + `); + }); + it('should not add additional imports if there is already one', async () => { + const transformed = await transform(dedent` + import { defineMain } from '@storybook/react-vite/node'; + const config = {}; + + export default config; + `); + expect( + transformed.match(/import { defineMain } from '@storybook\/react-vite\/node'/g) + ).toHaveLength(1); + }); + + it('should remove legacy main config type imports', async () => { + await expect( + transform(dedent` + import type { StorybookConfig } from '@storybook/react' + + const config: StorybookConfig = { + stories: [] + }; + export default config; + `) + ).resolves.toMatchInlineSnapshot(` + import { defineMain } from '@storybook/react-vite/node'; + + export default defineMain({ + stories: [], + }); + `); + }); +}); + +describe('preview specific functionality', () => { + const transform = async (source: string) => + ( + await configToCsfFactory( + { source, path: 'preview.ts' }, + { configType: 'preview', frameworkPackage: '@storybook/react-vite' } + ) + ).trim(); + + it('should contain a named config export', async () => { + await expect( + transform(dedent` + export default { + tags: ['test'], + }; + `) + ).resolves.toMatchInlineSnapshot(` + import { definePreview } from '@storybook/react-vite/browser'; + + export default definePreview({ + tags: ['test'], + }); + `); + }); + + it('should remove legacy preview type imports', async () => { + await expect( + transform(dedent` + import type { Preview } from '@storybook/react' + + const preview: Preview = { + tags: [] + }; + export default preview; + `) + ).resolves.toMatchInlineSnapshot(` + import { definePreview } from '@storybook/react-vite/browser'; + + export default definePreview({ + tags: [], + }); + `); + }); +}); diff --git a/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts b/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts new file mode 100644 index 000000000000..ea5bf4f5e93c --- /dev/null +++ b/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts @@ -0,0 +1,177 @@ +/* eslint-disable no-underscore-dangle */ +import { types as t } from 'storybook/internal/babel'; +import { formatFileContent } from 'storybook/internal/common'; +import { loadConfig, printConfig } from 'storybook/internal/csf-tools'; + +import picocolors from 'picocolors'; + +import type { FileInfo } from '../../automigrate/codemod'; +import { logger } from '../csf-factories'; +import { cleanupTypeImports } from './csf-factories-utils'; + +export async function configToCsfFactory( + info: FileInfo, + { configType, frameworkPackage }: { configType: 'main' | 'preview'; frameworkPackage: string }, + { dryRun = false, skipFormatting = false }: { dryRun?: boolean; skipFormatting?: boolean } = {} +) { + const config = loadConfig(info.source); + try { + config.parse(); + } catch (err) { + logger.log(`Error when parsing ${info.path}, skipping:\n${err}`); + return info.source; + } + + const methodName = configType === 'main' ? 'defineMain' : 'definePreview'; + + const programNode = config._ast.program; + const hasNamedExports = Object.keys(config._exportDecls).length > 0; + + /** + * Scenario 1: Mixed exports + * + * ``` + * export const tags = []; + * export default { + * parameters: {}, + * }; + * ``` + * + * Transform into: `export default defineMain({ tags: [], parameters: {} })` + */ + if (config._exportsObject && hasNamedExports) { + const exportDecls = config._exportDecls; + + for (const [name, decl] of Object.entries(exportDecls)) { + if (decl.init) { + config._exportsObject.properties.push(t.objectProperty(t.identifier(name), decl.init)); + } + } + + programNode.body = programNode.body.filter((node) => { + if (t.isExportNamedDeclaration(node) && node.declaration) { + if (t.isVariableDeclaration(node.declaration)) { + node.declaration.declarations = node.declaration.declarations.filter( + (decl) => t.isIdentifier(decl.id) && !exportDecls[decl.id.name] + ); + return node.declaration.declarations.length > 0; + } + } + return true; + }); + } else if (config._exportsObject) { + /** + * Scenario 2: Default exports + * + * - Syntax 1: `default export const config = {}; export default config;` + * - Syntax 2: `export default {};` + * + * Transform into: `export default defineMain({})` + */ + const defineConfigCall = t.callExpression(t.identifier(methodName), [config._exportsObject]); + + let exportDefaultNode = null as any as t.ExportDefaultDeclaration; + let declarationNodeIndex = -1; + + programNode.body.forEach((node) => { + // Detect Syntax 1 + if (t.isExportDefaultDeclaration(node) && t.isIdentifier(node.declaration)) { + const declarationName = node.declaration.name; + + declarationNodeIndex = programNode.body.findIndex( + (n) => + t.isVariableDeclaration(n) && + n.declarations.some( + (d) => + t.isIdentifier(d.id) && + d.id.name === declarationName && + t.isObjectExpression(d.init) + ) + ); + + if (declarationNodeIndex !== -1) { + exportDefaultNode = node; + // remove the original declaration as it will become a default export + const declarationNode = programNode.body[declarationNodeIndex]; + if (t.isVariableDeclaration(declarationNode)) { + const id = declarationNode.declarations[0].id; + const variableName = t.isIdentifier(id) && id.name; + + if (variableName) { + programNode.body.splice(declarationNodeIndex, 1); + } + } + } + } else if (t.isExportDefaultDeclaration(node) && t.isObjectExpression(node.declaration)) { + // Detect Syntax 2 + exportDefaultNode = node; + } + }); + + if (exportDefaultNode !== null) { + exportDefaultNode.declaration = defineConfigCall; + } + } else if (hasNamedExports) { + /** + * Scenario 3: Named exports export const foo = {}; export bar = ''; + * + * Transform into: export default defineMain({ foo: {}, bar: '' }); + */ + const exportDecls = config._exportDecls; + const defineConfigProps = []; + + // Collect properties from named exports + for (const [name, decl] of Object.entries(exportDecls)) { + if (decl.init) { + defineConfigProps.push(t.objectProperty(t.identifier(name), decl.init)); + } + } + + // Construct the `define` call + const defineConfigCall = t.callExpression(t.identifier(methodName), [ + t.objectExpression(defineConfigProps), + ]); + + // Remove all related named exports + programNode.body = programNode.body.filter((node) => { + if (t.isExportNamedDeclaration(node) && node.declaration) { + if (t.isVariableDeclaration(node.declaration)) { + node.declaration.declarations = node.declaration.declarations.filter( + (decl) => t.isIdentifier(decl.id) && !exportDecls[decl.id.name] + ); + return node.declaration.declarations.length > 0; + } + } + return true; + }); + + // Add the new export default declaration + programNode.body.push(t.exportDefaultDeclaration(defineConfigCall)); + } + + const configImport = t.importDeclaration( + [t.importSpecifier(t.identifier(methodName), t.identifier(methodName))], + t.stringLiteral(frameworkPackage + `/${configType === 'main' ? 'node' : 'browser'}`) + ); + // only add the import if it doesn't exist yet + if ( + !programNode.body.some( + (node) => t.isImportDeclaration(node) && node.source.value === configImport.source.value + ) + ) { + programNode.body.unshift(configImport); + } + + // Remove type imports – now inferred – from @storybook/* packages + const disallowList = ['StorybookConfig', 'Preview']; + programNode.body = cleanupTypeImports(programNode, disallowList); + + const output = printConfig(config).code; + + if (dryRun) { + logger.log(`Would write to ${picocolors.yellow(info.path)}:\n${picocolors.green(output)}`); + return info.source; + } + + return skipFormatting ? output : formatFileContent(info.path, output); +} diff --git a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts new file mode 100644 index 000000000000..27e065c86455 --- /dev/null +++ b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts @@ -0,0 +1,69 @@ +import type { Mock } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + +import type { StorybookConfigRaw } from '@storybook/types'; + +import { loadConfig, printConfig } from '@storybook/core/csf-tools'; + +import { dedent } from 'ts-dedent'; + +import { getSyncedStorybookAddons } from './csf-factories-utils'; +import { getAddonAnnotations } from './get-addon-annotations'; + +vi.mock('./get-addon-annotations'); + +expect.addSnapshotSerializer({ + serialize: (val: any) => (typeof val === 'string' ? dedent(val) : dedent(val.toString())), + test: () => true, +}); + +describe('getSyncedStorybookAddons', () => { + const mainConfig: StorybookConfigRaw = { + stories: [], + addons: ['custom-addon', '@storybook/addon-a11y'], + }; + it('should sync addons between main and preview', async () => { + const preview = loadConfig(` + import * as myAddonAnnotations from "custom-addon/preview"; + import { definePreview } from "@storybook/react-vite/browser"; + + export default definePreview({ + addons: [myAddonAnnotations], + }); + `).parse(); + + (getAddonAnnotations as Mock).mockImplementation(() => { + return { importName: 'addonA11yAnnotations', importPath: '@storybook/addon-a11y/preview' }; + }); + + const result = await getSyncedStorybookAddons(mainConfig, preview); + expect(printConfig(result).code).toMatchInlineSnapshot(` + import * as addonA11yAnnotations from "@storybook/addon-a11y/preview"; + import * as myAddonAnnotations from "custom-addon/preview"; + import { definePreview } from "@storybook/react-vite/browser"; + + export default definePreview({ + addons: [myAddonAnnotations, addonA11yAnnotations], + }); + `); + }); + it('should not modify the code if all addons are already synced', async () => { + const originalCode = ` + import * as addonA11yAnnotations from "@storybook/addon-a11y/preview"; + import * as myAddonAnnotations from "custom-addon/preview"; + import { definePreview } from "@storybook/react-vite/browser"; + + export default definePreview({ + addons: [myAddonAnnotations, addonA11yAnnotations], + }); + `; + const preview = loadConfig(originalCode).parse(); + + (getAddonAnnotations as Mock).mockImplementation(() => { + return { importName: 'addonA11yAnnotations', importPath: '@storybook/addon-a11y/preview' }; + }); + + const result = await getSyncedStorybookAddons(mainConfig, preview); + expect(printConfig(result).code).toEqual(originalCode); + }); +}); diff --git a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts new file mode 100644 index 000000000000..7a89afabdecf --- /dev/null +++ b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts @@ -0,0 +1,101 @@ +/* eslint-disable no-underscore-dangle */ +import path from 'node:path'; + +import { types as t } from 'storybook/internal/babel'; +import { type ConfigFile, readConfig, writeConfig } from 'storybook/internal/csf-tools'; + +import type { StorybookConfigRaw } from '@storybook/types'; + +import { getAddonNames } from '../../automigrate/helpers/mainConfigFile'; +import { logger } from '../csf-factories'; +import { getAddonAnnotations } from './get-addon-annotations'; + +export function cleanupTypeImports(programNode: t.Program, disallowList: string[]) { + return programNode.body.filter((node) => { + if (t.isImportDeclaration(node)) { + const { source, specifiers } = node; + + if (source.value.startsWith('@storybook/')) { + const allowedSpecifiers = specifiers.filter((specifier) => { + if (t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) { + return !disallowList.includes(specifier.imported.name); + } + // Retain non-specifier imports (e.g., namespace imports) + return true; + }); + + // Remove the entire import if no specifiers are left + if (allowedSpecifiers.length > 0) { + node.specifiers = allowedSpecifiers; + return true; + } + + // Remove the import if no specifiers remain + return false; + } + } + + // Retain all other nodes + return true; + }); +} + +export async function syncStorybookAddons( + mainConfig: StorybookConfigRaw, + previewConfigPath: string +) { + const previewConfig = await readConfig(previewConfigPath!); + const modifiedConfig = await getSyncedStorybookAddons(mainConfig, previewConfig); + + await writeConfig(modifiedConfig); +} + +export async function getSyncedStorybookAddons( + mainConfig: StorybookConfigRaw, + previewConfig: ConfigFile +): Promise { + const program = previewConfig._ast.program; + const isCsfFactoryPreview = !!program.body.find((node) => { + return ( + t.isImportDeclaration(node) && + node.source.value.includes('@storybook') && + node.source.value.endsWith('/browser') && + node.specifiers.some((specifier) => { + return ( + t.isImportSpecifier(specifier) && + t.isIdentifier(specifier.imported) && + specifier.imported.name === 'definePreview' + ); + }) + ); + }); + + if (!isCsfFactoryPreview) { + logger.log('Skipping syncStorybookAddons as the preview config is not a csf factory'); + return previewConfig; + } + + const addons = getAddonNames(mainConfig); + + /** + * This goes through all mainConfig.addons, read their package.json and check whether they have an + * exports map called preview, if so add to the array + */ + addons.forEach(async (addon) => { + const annotations = await getAddonAnnotations(addon); + if (annotations) { + previewConfig.setImport({ namespace: annotations.importName }, annotations.importPath); + const existingAddons = previewConfig.getFieldNode(['addons']); + if ( + t.isArrayExpression(existingAddons) && + !existingAddons.elements.some( + (element) => t.isIdentifier(element) && element.name === annotations.importName + ) + ) { + previewConfig.appendNodeToArray(['addons'], t.identifier(annotations.importName)); + } + } + }); + + return previewConfig; +} diff --git a/code/lib/cli-storybook/src/codemod/helpers/get-addon-annotations.test.ts b/code/lib/cli-storybook/src/codemod/helpers/get-addon-annotations.test.ts new file mode 100644 index 000000000000..c523b2cf74f2 --- /dev/null +++ b/code/lib/cli-storybook/src/codemod/helpers/get-addon-annotations.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from 'vitest'; + +import { getAnnotationsName } from './get-addon-annotations'; + +describe('getAnnotationsName', () => { + it('should handle @storybook namespace and camel case conversion', () => { + expect(getAnnotationsName('@storybook/addon-essentials')).toBe('addonEssentialsAnnotations'); + }); + + it('should handle other namespaces and camel case conversion', () => { + expect(getAnnotationsName('@kudos-components/testing/module')).toBe( + 'kudosComponentsTestingModuleAnnotations' + ); + }); + + it('should handle strings without namespaces', () => { + expect(getAnnotationsName('plain-text/example')).toBe('plainTextExampleAnnotations'); + }); + + it('should handle strings with multiple special characters', () => { + expect(getAnnotationsName('@storybook/multi-part/example-test')).toBe( + 'multiPartExampleTestAnnotations' + ); + }); +}); diff --git a/code/lib/cli-storybook/src/codemod/helpers/get-addon-annotations.ts b/code/lib/cli-storybook/src/codemod/helpers/get-addon-annotations.ts new file mode 100644 index 000000000000..e9d562326915 --- /dev/null +++ b/code/lib/cli-storybook/src/codemod/helpers/get-addon-annotations.ts @@ -0,0 +1,41 @@ +import path from 'node:path'; + +/** + * Get the name of the annotations object for a given addon. + * + * Input: '@storybook/addon-essentials' + * + * Output: 'addonEssentialsAnnotations' + */ +export function getAnnotationsName(addonName: string): string { + // remove @storybook namespace, split by special characters, convert to camelCase + const cleanedUpName = addonName + .replace(/^@storybook\//, '') + .split(/[^a-zA-Z0-9]+/) + .map((word, index) => + index === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() + ) + .join('') + .replace(/^./, (char) => char.toLowerCase()); + + return `${cleanedUpName}Annotations`; +} + +export async function getAddonAnnotations(addon: string) { + try { + const data = { + importPath: `${addon}/preview`, + importName: getAnnotationsName(addon), + }; + // TODO: current workaround needed only for essentials, fix this once we change the preview entry-point for that package + if (addon === '@storybook/addon-essentials') { + data.importPath = '@storybook/addon-essentials/entry-preview'; + } else { + require.resolve(path.join(addon, 'preview')); + } + + return data; + } catch (err) {} + + return null; +} diff --git a/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts similarity index 53% rename from code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts rename to code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts index 880b1b74b704..3a98dbeece0b 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/csf-factories.test.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts @@ -4,188 +4,63 @@ import { formatFileContent } from '@storybook/core/common'; import { dedent } from 'ts-dedent'; -import { configToCsfFactory, storyToCsfFactory } from './csf-factories'; +import { storyToCsfFactory } from './story-to-csf-factory'; expect.addSnapshotSerializer({ serialize: (val: any) => (typeof val === 'string' ? val : val.toString()), test: () => true, }); -describe('csf-factories', () => { - describe('main/preview codemod: general parsing functionality', () => { - const transform = async (source: string) => - ( - await configToCsfFactory( - { source, path: 'main.ts' }, - { configType: 'main', frameworkPackage: '@storybook/react-vite' } - ) - ).trim(); - - it('should wrap defineMain call from inline default export', async () => { +describe('stories codemod', () => { + const transform = async (source: string) => + formatFileContent( + 'Component.stories.tsx', + await storyToCsfFactory({ source, path: 'Component.stories.tsx' }) + ); + describe('javascript', () => { + it('should wrap const declared meta', async () => { await expect( transform(dedent` - export default { - stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: ['@storybook/addon-essentials'], - framework: '@storybook/react-vite', - }; - `) - ).resolves.toMatchInlineSnapshot(` - import { defineMain } from '@storybook/react-vite/node'; - - export default defineMain({ - stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: ['@storybook/addon-essentials'], - framework: '@storybook/react-vite', - }); - `); - }); - it('should wrap defineMain call from const declared default export', async () => { - await expect( - transform(dedent` - const config = { - stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: ['@storybook/addon-essentials'], - framework: '@storybook/react-vite', - }; - - export default config; - `) - ).resolves.toMatchInlineSnapshot(` - import { defineMain } from '@storybook/react-vite/node'; - - export default defineMain({ - stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: ['@storybook/addon-essentials'], - framework: '@storybook/react-vite', - }); - `); - }); - it('should wrap defineMain call from const declared default export and default export mix', async () => { - await expect( - transform(dedent` - export const tags = []; - const config = { - framework: '@storybook/react-vite', - }; - - export default config; - `) - ).resolves.toMatchInlineSnapshot(` - import { defineMain } from '@storybook/react-vite/node'; - - const config = { - framework: '@storybook/react-vite', - tags: [], - }; - - export default config; - `); - }); - it('should wrap defineMain call from named exports format', async () => { - await expect( - transform(dedent` - export const stories = ['../src/**/*.stories.@(js|jsx|ts|tsx)']; - export const addons = ['@storybook/addon-essentials']; - export const framework = '@storybook/react-vite'; - `) - ).resolves.toMatchInlineSnapshot(` - import { defineMain } from '@storybook/react-vite/node'; - - export default defineMain({ - stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: ['@storybook/addon-essentials'], - framework: '@storybook/react-vite', - }); - `); - }); - it('should not add additional imports if there is already one', async () => { - const transformed = await transform(dedent` - import { defineMain } from '@storybook/react-vite/node'; - const config = {}; - - export default config; - `); - expect( - transformed.match(/import { defineMain } from '@storybook\/react-vite\/node'/g) - ).toHaveLength(1); - }); - }); - describe('preview specific functionality', () => { - const transform = async (source: string) => - ( - await configToCsfFactory( - { source, path: 'preview.ts' }, - { configType: 'preview', frameworkPackage: '@storybook/react-vite' } - ) - ).trim(); - - it('should contain a named config export', async () => { - await expect( - transform(dedent` - export default { - tags: ['test'], - }; - `) - ).resolves.toMatchInlineSnapshot(` - import { definePreview } from '@storybook/react-vite/browser'; - - export default definePreview({ - tags: ['test'], - }); - `); - }); - }); - describe('stories codemod', () => { - const transform = async (source: string) => - formatFileContent( - 'Component.stories.tsx', - await storyToCsfFactory({ source, path: 'Component.stories.tsx' }) - ); - describe('javascript', () => { - it('should wrap const declared meta', async () => { - await expect( - transform(dedent` const meta = { title: 'Component' }; export default meta; `) - ).resolves.toMatchInlineSnapshot(` + ).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; const meta = config.meta({ title: 'Component' }); `); - }); + }); - it('should transform and wrap inline default exported meta', async () => { - await expect( - transform(dedent` + it('should transform and wrap inline default exported meta', async () => { + await expect( + transform(dedent` export default { title: 'Component' }; `) - ).resolves.toMatchInlineSnapshot(` + ).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; const meta = config.meta({ title: 'Component', }); `); - }); + }); - it('should rename meta object to meta if it has a different name', async () => { - await expect( - transform(dedent` + it('should rename meta object to meta if it has a different name', async () => { + await expect( + transform(dedent` const componentMeta = { title: 'Component' }; export default componentMeta; `) - ).resolves.toMatchInlineSnapshot(` + ).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; const meta = config.meta({ title: 'Component' }); `); - }); + }); - it('should wrap stories in a meta.story method', async () => { - await expect( - transform(dedent` + it('should wrap stories in a meta.story method', async () => { + await expect( + transform(dedent` const componentMeta = { title: 'Component' }; export default componentMeta; export const A = { @@ -193,7 +68,7 @@ describe('csf-factories', () => { render: (args) => }; `) - ).resolves.toMatchInlineSnapshot(` + ).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; const meta = config.meta({ title: 'Component' }); @@ -202,11 +77,11 @@ describe('csf-factories', () => { render: (args) => , }); `); - }); + }); - it('should respect existing config imports', async () => { - await expect( - transform(dedent` + it('should respect existing config imports', async () => { + await expect( + transform(dedent` import { decorators } from "#.storybook/preview"; const componentMeta = { title: 'Component' }; export default componentMeta; @@ -215,7 +90,7 @@ describe('csf-factories', () => { render: (args) => }; `) - ).resolves.toMatchInlineSnapshot(` + ).resolves.toMatchInlineSnapshot(` import { config, decorators } from '#.storybook/preview'; const meta = config.meta({ title: 'Component' }); @@ -224,11 +99,11 @@ describe('csf-factories', () => { render: (args) => , }); `); - }); + }); - it('if there is an existing local constant called config, rename storybook config import', async () => { - await expect( - transform(dedent` + it('if there is an existing local constant called config, rename storybook config import', async () => { + await expect( + transform(dedent` const componentMeta = { title: 'Component' }; export default componentMeta; const config = {}; @@ -237,7 +112,7 @@ describe('csf-factories', () => { render: (args) => }; `) - ).resolves.toMatchInlineSnapshot(` + ).resolves.toMatchInlineSnapshot(` import { config as storybookConfig } from '#.storybook/preview'; const meta = storybookConfig.meta({ title: 'Component' }); @@ -247,16 +122,16 @@ describe('csf-factories', () => { render: (args) => , }); `); - }); + }); - it('converts CSF1 into CSF4 with render', async () => { - await expect( - transform(dedent` + it('converts CSF1 into CSF4 with render', async () => { + await expect( + transform(dedent` const meta = { title: 'Component' }; export default meta; export const CSF1Story = () =>
Hello
; `) - ).resolves.toMatchInlineSnapshot(` + ).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; const meta = config.meta({ title: 'Component' }); @@ -264,11 +139,11 @@ describe('csf-factories', () => { render: () =>
Hello
, }); `); - }); }); + }); - describe('typescript', () => { - const inlineMetaSatisfies = dedent` + describe('typescript', () => { + const inlineMetaSatisfies = dedent` import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; @@ -278,8 +153,8 @@ describe('csf-factories', () => { args: { primary: true } }; `; - it('meta satisfies syntax', async () => { - await expect(transform(inlineMetaSatisfies)).resolves.toMatchInlineSnapshot(` + it('meta satisfies syntax', async () => { + await expect(transform(inlineMetaSatisfies)).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; import { ComponentProps } from './Component'; @@ -290,9 +165,9 @@ describe('csf-factories', () => { args: { primary: true }, }); `); - }); + }); - const inlineMetaAs = dedent` + const inlineMetaAs = dedent` import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; @@ -302,8 +177,8 @@ describe('csf-factories', () => { args: { primary: true } }; `; - it('meta as syntax', async () => { - await expect(transform(inlineMetaAs)).resolves.toMatchInlineSnapshot(` + it('meta as syntax', async () => { + await expect(transform(inlineMetaAs)).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; import { ComponentProps } from './Component'; @@ -314,8 +189,8 @@ describe('csf-factories', () => { args: { primary: true }, }); `); - }); - const metaSatisfies = dedent` + }); + const metaSatisfies = dedent` import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; @@ -326,8 +201,8 @@ describe('csf-factories', () => { args: { primary: true } }; `; - it('meta satisfies syntax', async () => { - await expect(transform(metaSatisfies)).resolves.toMatchInlineSnapshot(` + it('meta satisfies syntax', async () => { + await expect(transform(metaSatisfies)).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; import { ComponentProps } from './Component'; @@ -338,9 +213,9 @@ describe('csf-factories', () => { args: { primary: true }, }); `); - }); + }); - const metaAs = dedent` + const metaAs = dedent` import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; @@ -351,8 +226,8 @@ describe('csf-factories', () => { args: { primary: true } }; `; - it('meta as syntax', async () => { - await expect(transform(metaAs)).resolves.toMatchInlineSnapshot(` + it('meta as syntax', async () => { + await expect(transform(metaAs)).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; import { ComponentProps } from './Component'; @@ -363,9 +238,9 @@ describe('csf-factories', () => { args: { primary: true }, }); `); - }); + }); - const storySatisfies = dedent` + const storySatisfies = dedent` import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; @@ -376,8 +251,8 @@ describe('csf-factories', () => { args: { primary: true } } satisfies CSF3; `; - it('story satisfies syntax', async () => { - await expect(transform(storySatisfies)).resolves.toMatchInlineSnapshot(` + it('story satisfies syntax', async () => { + await expect(transform(storySatisfies)).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; import { ComponentProps } from './Component'; @@ -388,9 +263,9 @@ describe('csf-factories', () => { args: { primary: true }, }); `); - }); + }); - const storyAs = dedent` + const storyAs = dedent` import { Meta, StoryObj as CSF3 } from '@storybook/react'; import { ComponentProps } from './Component'; @@ -401,8 +276,8 @@ describe('csf-factories', () => { args: { primary: true } } as CSF3; `; - it('story as syntax', async () => { - await expect(transform(storyAs)).resolves.toMatchInlineSnapshot(` + it('story as syntax', async () => { + await expect(transform(storyAs)).resolves.toMatchInlineSnapshot(` import { config } from '#.storybook/preview'; import { ComponentProps } from './Component'; @@ -413,21 +288,20 @@ describe('csf-factories', () => { args: { primary: true }, }); `); - }); + }); - it('should yield the same result to all syntaxes', async () => { - const allSnippets = await Promise.all([ - transform(inlineMetaSatisfies), - transform(inlineMetaAs), - transform(metaSatisfies), - transform(metaAs), - transform(storySatisfies), - transform(storyAs), - ]); - - allSnippets.forEach((result) => { - expect(result).toEqual(allSnippets[0]); - }); + it('should yield the same result to all syntaxes', async () => { + const allSnippets = await Promise.all([ + transform(inlineMetaSatisfies), + transform(inlineMetaAs), + transform(metaSatisfies), + transform(metaAs), + transform(storySatisfies), + transform(storyAs), + ]); + + allSnippets.forEach((result) => { + expect(result).toEqual(allSnippets[0]); }); }); }); diff --git a/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts new file mode 100644 index 000000000000..c359b8dfa997 --- /dev/null +++ b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts @@ -0,0 +1,171 @@ +/* eslint-disable no-underscore-dangle */ +import { types as t } from 'storybook/internal/babel'; +import { isValidPreviewPath, loadCsf, printCsf } from 'storybook/internal/csf-tools'; + +import type { FileInfo } from '../../automigrate/codemod'; +import { logger } from '../csf-factories'; +import { cleanupTypeImports } from './csf-factories-utils'; + +export async function storyToCsfFactory(info: FileInfo) { + const csf = loadCsf(info.source, { makeTitle: () => 'FIXME' }); + try { + csf.parse(); + } catch (err) { + logger.log(`Error when parsing ${info.path}, skipping:\n${err}`); + return info.source; + } + + const metaVariableName = 'meta'; + + /** + * Add the preview import if it doesn't exist yet: + * + * `import { config } from '#.storybook/preview'`; + */ + const programNode = csf._ast.program; + let foundConfigImport = false; + + // Check if a root-level constant named 'config' exists + const hasRootLevelConfig = programNode.body.some( + (n) => + t.isVariableDeclaration(n) && + n.declarations.some((declaration) => t.isIdentifier(declaration.id, { name: 'config' })) + ); + + const sbConfigImportName = hasRootLevelConfig ? 'storybookConfig' : 'config'; + + const sbConfigImportSpecifier = t.importSpecifier( + t.identifier(sbConfigImportName), + t.identifier('config') + ); + + programNode.body.forEach((node) => { + if (t.isImportDeclaration(node) && isValidPreviewPath(node.source.value)) { + const hasConfigSpecifier = node.specifiers.some( + (specifier) => + t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported, { name: 'config' }) + ); + + if (!hasConfigSpecifier) { + node.specifiers.push(sbConfigImportSpecifier); + } + + foundConfigImport = true; + } + }); + + const hasMeta = !!csf._meta; + + Object.entries(csf._storyExports).forEach(([key, decl]) => { + const id = decl.id; + const declarator = decl as t.VariableDeclarator; + let init = t.isVariableDeclarator(declarator) ? declarator.init : undefined; + + if (t.isIdentifier(id) && init) { + if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) { + init = init.expression; + } + + if (t.isObjectExpression(init)) { + const typeAnnotation = id.typeAnnotation; + // Remove type annotation as it's now inferred + if (typeAnnotation) { + id.typeAnnotation = null; + } + + // Wrap the object in `meta.story()` + declarator.init = t.callExpression( + t.memberExpression(t.identifier(metaVariableName), t.identifier('story')), + [init] + ); + } else if (t.isArrowFunctionExpression(init)) { + // Transform CSF1 to meta.story({ render: }) + const renderProperty = t.objectProperty(t.identifier('render'), init); + + const objectExpression = t.objectExpression([renderProperty]); + + declarator.init = t.callExpression( + t.memberExpression(t.identifier(metaVariableName), t.identifier('story')), + [objectExpression] + ); + } + } + }); + + // modify meta + if (csf._metaPath) { + let declaration = csf._metaPath.node.declaration; + if (t.isTSSatisfiesExpression(declaration) || t.isTSAsExpression(declaration)) { + declaration = declaration.expression; + } + + if (t.isObjectExpression(declaration)) { + const metaVariable = t.variableDeclaration('const', [ + t.variableDeclarator( + t.identifier(metaVariableName), + t.callExpression( + t.memberExpression(t.identifier(sbConfigImportName), t.identifier('meta')), + [declaration] + ) + ), + ]); + csf._metaPath.replaceWith(metaVariable); + } else if (t.isIdentifier(declaration)) { + /** + * Transform const declared metas: + * + * `const meta = {}; export default meta;` + * + * Into a meta call: + * + * `const meta = config.meta({ title: 'A' });` + */ + const binding = csf._metaPath.scope.getBinding(declaration.name); + if (binding && binding.path.isVariableDeclarator()) { + const originalName = declaration.name; + + // Always rename the meta variable to 'meta' + binding.path.node.id = t.identifier(metaVariableName); + + let init = binding.path.node.init; + if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) { + init = init.expression; + } + if (t.isObjectExpression(init)) { + binding.path.node.init = t.callExpression( + t.memberExpression(t.identifier(sbConfigImportName), t.identifier('meta')), + [init] + ); + } + + // Update all references to the original name + csf._metaPath.scope.rename(originalName, metaVariableName); + } + + // Remove the default export, it's not needed anymore + csf._metaPath.remove(); + } + } + + if (hasMeta && !foundConfigImport) { + const configImport = t.importDeclaration( + [sbConfigImportSpecifier], + t.stringLiteral('#.storybook/preview') + ); + programNode.body.unshift(configImport); + } + + // Remove type imports – now inferred – from @storybook/* packages + const disallowList = [ + 'Story', + 'StoryFn', + 'StoryObj', + 'Meta', + 'MetaObj', + 'ComponentStory', + 'ComponentMeta', + ]; + programNode.body = cleanupTypeImports(programNode, disallowList); + + return printCsf(csf).code; +} diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index 2a86db4a73c3..be12a4ede276 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -819,55 +819,14 @@ export const extendPreview: Task['run'] = async ({ template, sandboxDir }) => { template.expected.framework === '@storybook/react-vite' && !template.skipTasks.includes('vitest-integration') ) { - // add CSF4 style config - previewConfig.setImport(['defineConfig'], '@storybook/react/preview'); - // and all of the addons/previewAnnotations that are needed previewConfig.setImport(null, '../src/stories/components'); - previewConfig.setImport( - { namespace: 'addonEssentialsAnnotations' }, - '@storybook/addon-essentials/entry-preview' - ); - previewConfig.setImport({ namespace: 'addonA11yAnnotations' }, '@storybook/addon-a11y/preview'); - previewConfig.setImport( - { namespace: 'addonActionsAnnotations' }, - '@storybook/addon-actions/preview' - ); - previewConfig.setImport( - { namespace: 'addonTestAnnotations' }, - '@storybook/experimental-addon-test/preview' - ); previewConfig.setImport({ namespace: 'coreAnnotations' }, '../template-stories/core/preview'); previewConfig.setImport( { namespace: 'toolbarAnnotations' }, '../template-stories/addons/toolbars/preview' ); - - previewConfig.setBodyDeclaration( - t.exportNamedDeclaration( - t.variableDeclaration('const', [ - t.variableDeclarator( - t.identifier('config'), - t.callExpression(t.identifier('defineConfig'), [ - t.objectExpression([ - t.spreadElement(t.identifier('preview')), - t.objectProperty( - t.identifier('addons'), - t.arrayExpression([ - t.identifier('addonEssentialsAnnotations'), - t.identifier('addonA11yAnnotations'), - t.identifier('addonActionsAnnotations'), - t.identifier('addonTestAnnotations'), - t.identifier('coreAnnotations'), - t.identifier('toolbarAnnotations'), - ]) - ), - ]), - ]) - ), - ]), - [] - ) - ); + previewConfig.appendNodeToArray(['addons'], t.identifier('coreAnnotations')); + previewConfig.appendNodeToArray(['addons'], t.identifier('toolbarAnnotations')); } if (template.expected.builder.includes('vite')) { diff --git a/scripts/tasks/sandbox.ts b/scripts/tasks/sandbox.ts index ef79e3d4c32f..7bca37085843 100644 --- a/scripts/tasks/sandbox.ts +++ b/scripts/tasks/sandbox.ts @@ -2,6 +2,7 @@ import dirSize from 'fast-folder-size'; // eslint-disable-next-line depend/ban-dependencies import { pathExists, remove } from 'fs-extra'; import { join } from 'path'; +import prompts from 'prompts'; import { promisify } from 'util'; import { now, saveBench } from '../bench/utils'; @@ -144,12 +145,12 @@ export const sandbox: Task = { await extendMain(details, options); - await extendPreview(details, options); - await setImportMap(details.sandboxDir); await runMigrations(details, options); + await extendPreview(details, options); + logger.info(`✅ Storybook sandbox created at ${details.sandboxDir}`); }, }; From 310ebf2243b3b8030a9074c1a085dbe0866c22ad Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 20 Jan 2025 13:07:45 +0100 Subject: [PATCH 17/24] sync main and preview in sb add --- code/lib/cli-storybook/src/add.ts | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/code/lib/cli-storybook/src/add.ts b/code/lib/cli-storybook/src/add.ts index 8ba600883e7e..2fb796d7793b 100644 --- a/code/lib/cli-storybook/src/add.ts +++ b/code/lib/cli-storybook/src/add.ts @@ -10,6 +10,8 @@ import { } from 'storybook/internal/common'; import { readConfig, writeConfig } from 'storybook/internal/csf-tools'; +import type { StorybookConfigRaw } from '@storybook/types'; + import prompts from 'prompts'; import SemVer from 'semver'; import { dedent } from 'ts-dedent'; @@ -18,6 +20,8 @@ import { getRequireWrapperName, wrapValueWithRequireWrapper, } from './automigrate/fixes/wrap-require-utils'; +import { getStorybookData } from './automigrate/helpers/mainConfigFile'; +import { syncStorybookAddons } from './codemod/helpers/csf-factories-utils'; import { postinstallAddon } from './postinstallAddon'; export interface PostinstallOptions { @@ -53,7 +57,7 @@ const requireMain = (configDir: string) => { return serverRequire(mainFile) ?? {}; }; -const checkInstalled = (addonName: string, main: any) => { +const checkInstalled = (addonName: string, main: StorybookConfigRaw) => { const existingAddon = main.addons?.find((entry: string | { name: string }) => { const name = typeof entry === 'string' ? entry : entry.name; return name?.endsWith(addonName); @@ -91,12 +95,11 @@ export async function add( const [addonName, inputVersion] = getVersionSpecifier(addon); const packageManager = JsPackageManagerFactory.getPackageManager({ force: pkgMgr }); - const packageJson = await packageManager.retrievePackageJson(); - const { mainConfig, configDir: inferredConfigDir } = getStorybookInfo( - packageJson, - userSpecifiedConfigDir - ); - const configDir = userSpecifiedConfigDir || inferredConfigDir || '.storybook'; + const { mainConfig, mainConfigPath, configDir, previewConfigPath, storybookVersion } = + await getStorybookData({ + packageManager, + configDir: userSpecifiedConfigDir, + }); if (typeof configDir === 'undefined') { throw new Error(dedent` @@ -104,16 +107,16 @@ export async function add( `); } - if (!mainConfig) { + if (!mainConfigPath) { logger.error('Unable to find Storybook main.js config'); return; } let shouldAddToMain = true; - if (checkInstalled(addonName, requireMain(configDir))) { + if (checkInstalled(addonName, mainConfig)) { shouldAddToMain = false; if (!yes) { - logger.log(`The Storybook addon "${addonName}" is already present in ${mainConfig}.`); + logger.log(`The Storybook addon "${addonName}" is already present in ${mainConfigPath}.`); const { shouldForceInstall } = await prompts({ type: 'confirm', name: 'shouldForceInstall', @@ -126,11 +129,9 @@ export async function add( } } - const main = await readConfig(mainConfig); + const main = await readConfig(mainConfigPath); logger.log(`Verifying ${addonName}`); - const storybookVersion = await getCoercedStorybookVersion(packageManager); - let version = inputVersion; if (!version && isCoreAddon(addonName) && storybookVersion) { @@ -154,7 +155,7 @@ export async function add( await packageManager.addDependencies({ installAsDevDependencies: true }, [addonWithVersion]); if (shouldAddToMain) { - logger.log(`Adding '${addon}' to the "addons" field in ${mainConfig}`); + logger.log(`Adding '${addon}' to the "addons" field in ${mainConfigPath}`); const mainConfigAddons = main.getFieldNode(['addons']); if (mainConfigAddons && getRequireWrapperName(main) !== null) { @@ -168,6 +169,8 @@ export async function add( await writeConfig(main); } + await syncStorybookAddons(mainConfig, previewConfigPath!); + if (!skipPostinstall && isCoreAddon(addonName)) { await postinstallAddon(addonName, { packageManager: packageManager.type, configDir, yes }); } From 5c3752a7da58609901599f3745f6523f22dd28a8 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 20 Jan 2025 15:50:48 +0100 Subject: [PATCH 18/24] move defineMainConfig definition to the index level --- code/core/src/common/defineConfig.ts | 5 ----- code/core/src/common/index.ts | 1 - code/frameworks/angular/package.json | 6 ------ .../angular/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/angular/src/defineMainConfig.ts | 5 +++++ code/frameworks/angular/src/index.ts | 1 + code/frameworks/ember/package.json | 6 ------ .../frameworks/ember/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/ember/src/defineMainConfig.ts | 5 +++++ code/frameworks/ember/src/index.ts | 1 + code/frameworks/experimental-nextjs-vite/package.json | 7 ------- .../src/csf-factory/defineMainConfig.ts | 7 ------- .../experimental-nextjs-vite/src/defineMainConfig.ts | 5 +++++ code/frameworks/experimental-nextjs-vite/src/index.ts | 1 + code/frameworks/html-vite/package.json | 9 +-------- .../html-vite/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/html-vite/src/defineMainConfig.ts | 5 +++++ code/frameworks/html-vite/src/index.ts | 1 + code/frameworks/html-webpack5/package.json | 9 +-------- .../html-webpack5/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/html-webpack5/src/defineMainConfig.ts | 5 +++++ code/frameworks/html-webpack5/src/index.ts | 1 + code/frameworks/nextjs/package.json | 7 ------- .../nextjs/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/nextjs/src/defineMainConfig.ts | 5 +++++ code/frameworks/nextjs/src/index.ts | 1 + code/frameworks/preact-vite/package.json | 6 ------ .../preact-vite/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/preact-vite/src/defineMainConfig.ts | 5 +++++ code/frameworks/preact-vite/src/index.ts | 1 + code/frameworks/preact-webpack5/package.json | 9 +-------- .../preact-webpack5/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/preact-webpack5/src/defineMainConfig.ts | 5 +++++ code/frameworks/preact-webpack5/src/index.ts | 1 + code/frameworks/react-native-web-vite/package.json | 9 +-------- .../src/csf-factory/defineMainConfig.ts | 7 ------- .../react-native-web-vite/src/defineMainConfig.ts | 5 +++++ code/frameworks/react-native-web-vite/src/index.ts | 1 + code/frameworks/react-vite/package.json | 9 +-------- .../react-vite/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/react-vite/src/defineMainConfig.ts | 5 +++++ code/frameworks/react-vite/src/index.ts | 1 + code/frameworks/react-webpack5/package.json | 9 +-------- .../react-webpack5/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/react-webpack5/src/defineMainConfig.ts | 5 +++++ code/frameworks/react-webpack5/src/index.ts | 1 + code/frameworks/server-webpack5/package.json | 9 +-------- .../server-webpack5/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/server-webpack5/src/defineMainConfig.ts | 5 +++++ code/frameworks/server-webpack5/src/index.ts | 1 + code/frameworks/svelte-vite/package.json | 9 +-------- .../svelte-vite/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/svelte-vite/src/defineMainConfig.ts | 5 +++++ code/frameworks/svelte-vite/src/index.ts | 1 + code/frameworks/svelte-webpack5/package.json | 9 +-------- .../svelte-webpack5/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/svelte-webpack5/src/defineMainConfig.ts | 5 +++++ code/frameworks/svelte-webpack5/src/index.ts | 1 + code/frameworks/sveltekit/package.json | 9 +-------- .../sveltekit/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/sveltekit/src/defineMainConfig.ts | 5 +++++ code/frameworks/sveltekit/src/index.ts | 1 + code/frameworks/vue3-vite/package.json | 9 +-------- .../vue3-vite/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/vue3-vite/src/defineMainConfig.ts | 5 +++++ code/frameworks/vue3-vite/src/index.ts | 1 + code/frameworks/vue3-webpack5/package.json | 9 +-------- .../vue3-webpack5/src/csf-factory/defineMainConfig.ts | 7 ------- code/frameworks/vue3-webpack5/src/defineMainConfig.ts | 5 +++++ code/frameworks/vue3-webpack5/src/index.ts | 1 + code/frameworks/web-components-vite/package.json | 7 ------- .../src/csf-factory/defineMainConfig.ts | 7 ------- .../web-components-vite/src/defineMainConfig.ts | 5 +++++ code/frameworks/web-components-vite/src/index.ts | 1 + code/frameworks/web-components-webpack5/package.json | 9 +-------- .../src/csf-factory/defineMainConfig.ts | 7 ------- .../web-components-webpack5/src/defineMainConfig.ts | 5 +++++ code/frameworks/web-components-webpack5/src/index.ts | 1 + .../src/codemod/helpers/csf-factories-utils.ts | 1 + 79 files changed, 128 insertions(+), 282 deletions(-) delete mode 100644 code/core/src/common/defineConfig.ts delete mode 100644 code/frameworks/angular/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/angular/src/defineMainConfig.ts delete mode 100644 code/frameworks/ember/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/ember/src/defineMainConfig.ts delete mode 100644 code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/experimental-nextjs-vite/src/defineMainConfig.ts delete mode 100644 code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/html-vite/src/defineMainConfig.ts delete mode 100644 code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/html-webpack5/src/defineMainConfig.ts delete mode 100644 code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/nextjs/src/defineMainConfig.ts delete mode 100644 code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/preact-vite/src/defineMainConfig.ts delete mode 100644 code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/preact-webpack5/src/defineMainConfig.ts delete mode 100644 code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/react-native-web-vite/src/defineMainConfig.ts delete mode 100644 code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/react-vite/src/defineMainConfig.ts delete mode 100644 code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/react-webpack5/src/defineMainConfig.ts delete mode 100644 code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/server-webpack5/src/defineMainConfig.ts delete mode 100644 code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/svelte-vite/src/defineMainConfig.ts delete mode 100644 code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/svelte-webpack5/src/defineMainConfig.ts delete mode 100644 code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/sveltekit/src/defineMainConfig.ts delete mode 100644 code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/vue3-vite/src/defineMainConfig.ts delete mode 100644 code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/vue3-webpack5/src/defineMainConfig.ts delete mode 100644 code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/web-components-vite/src/defineMainConfig.ts delete mode 100644 code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts create mode 100644 code/frameworks/web-components-webpack5/src/defineMainConfig.ts diff --git a/code/core/src/common/defineConfig.ts b/code/core/src/common/defineConfig.ts deleted file mode 100644 index 2a16d88aa474..000000000000 --- a/code/core/src/common/defineConfig.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { StorybookConfig } from '@storybook/core/types'; - -export function defineConfig(config: TConfig): TConfig { - return config; -} diff --git a/code/core/src/common/index.ts b/code/core/src/common/index.ts index dcec4e025c53..6166e285ab05 100644 --- a/code/core/src/common/index.ts +++ b/code/core/src/common/index.ts @@ -42,7 +42,6 @@ export * from './utils/formatter'; export * from './utils/get-story-id'; export * from './utils/posix'; export * from './js-package-manager'; -export * from './defineConfig'; export { versions }; diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index 2c71784ede70..bc7162bad711 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -28,12 +28,6 @@ "require": "./dist/index.js" }, "./preset": "./preset.js", - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.js", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", diff --git a/code/frameworks/angular/src/csf-factory/defineMainConfig.ts b/code/frameworks/angular/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index 24bc05422ac9..000000000000 --- a/code/frameworks/angular/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/angular/src/defineMainConfig.ts b/code/frameworks/angular/src/defineMainConfig.ts new file mode 100644 index 000000000000..e0bb43b41ff9 --- /dev/null +++ b/code/frameworks/angular/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/angular/src/index.ts b/code/frameworks/angular/src/index.ts index 92f1fac0da0f..d57916a453f4 100644 --- a/code/frameworks/angular/src/index.ts +++ b/code/frameworks/angular/src/index.ts @@ -1,5 +1,6 @@ export * from './client/index'; export * from './types'; +export * from './defineMainConfig'; /* * ATTENTION: diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index 94b6468b39f8..f4b021d13e8e 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -24,12 +24,6 @@ "require": "./dist/index.js" }, "./preset": "./preset.js", - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.js", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", diff --git a/code/frameworks/ember/src/csf-factory/defineMainConfig.ts b/code/frameworks/ember/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/ember/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/ember/src/defineMainConfig.ts b/code/frameworks/ember/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/ember/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/ember/src/index.ts b/code/frameworks/ember/src/index.ts index b821bec98227..bdebdaee4b44 100644 --- a/code/frameworks/ember/src/index.ts +++ b/code/frameworks/ember/src/index.ts @@ -1,6 +1,7 @@ /// export * from './types'; +export * from './defineMainConfig'; // optimization: stop HMR propagation in webpack diff --git a/code/frameworks/experimental-nextjs-vite/package.json b/code/frameworks/experimental-nextjs-vite/package.json index 4b20e1113092..b5205345ed72 100644 --- a/code/frameworks/experimental-nextjs-vite/package.json +++ b/code/frameworks/experimental-nextjs-vite/package.json @@ -58,12 +58,6 @@ "import": "./dist/vite-plugin/index.mjs", "require": "./dist/vite-plugin/index.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -140,7 +134,6 @@ "./src/index.ts", "./src/vite-plugin/index.ts", "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts", "./src/preview.tsx", "./src/export-mocks/cache/index.ts", "./src/export-mocks/headers/index.ts", diff --git a/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/experimental-nextjs-vite/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/experimental-nextjs-vite/src/defineMainConfig.ts b/code/frameworks/experimental-nextjs-vite/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/experimental-nextjs-vite/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/experimental-nextjs-vite/src/index.ts b/code/frameworks/experimental-nextjs-vite/src/index.ts index 32476387c88c..af5050bce57f 100644 --- a/code/frameworks/experimental-nextjs-vite/src/index.ts +++ b/code/frameworks/experimental-nextjs-vite/src/index.ts @@ -1,6 +1,7 @@ import type vitePluginStorybookNextJs from 'vite-plugin-storybook-nextjs'; export * from './types'; +export * from './defineMainConfig'; export * from './portable-stories'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index 1ce79c846355..804987dac1c7 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -73,8 +67,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/html-vite/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/html-vite/src/defineMainConfig.ts b/code/frameworks/html-vite/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/html-vite/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/html-vite/src/index.ts b/code/frameworks/html-vite/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/html-vite/src/index.ts +++ b/code/frameworks/html-vite/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index 8a7167dd0f54..03cd0ce7cfc2 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -74,8 +68,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/html-webpack5/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/html-webpack5/src/defineMainConfig.ts b/code/frameworks/html-webpack5/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/html-webpack5/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/html-webpack5/src/index.ts b/code/frameworks/html-webpack5/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/html-webpack5/src/index.ts +++ b/code/frameworks/html-webpack5/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index 41dea2891772..a440c6b17a17 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -87,12 +87,6 @@ "import": "./dist/export-mocks/router/index.mjs", "require": "./dist/export-mocks/router/index.js" }, - "./main": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -215,7 +209,6 @@ "./src/image-context.ts", "./src/index.ts", "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts", "./src/preview.tsx", "./src/export-mocks/index.ts", "./src/export-mocks/cache/index.ts", diff --git a/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts b/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/nextjs/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/nextjs/src/defineMainConfig.ts b/code/frameworks/nextjs/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/nextjs/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/nextjs/src/index.ts b/code/frameworks/nextjs/src/index.ts index a904f93ec89d..4e3e0a0ec393 100644 --- a/code/frameworks/nextjs/src/index.ts +++ b/code/frameworks/nextjs/src/index.ts @@ -1,2 +1,3 @@ export * from './types'; +export * from './defineMainConfig'; export * from './portable-stories'; diff --git a/code/frameworks/preact-vite/package.json b/code/frameworks/preact-vite/package.json index e639c1c7e0bb..5b146f3a9bbf 100644 --- a/code/frameworks/preact-vite/package.json +++ b/code/frameworks/preact-vite/package.json @@ -29,12 +29,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", diff --git a/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/preact-vite/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/preact-vite/src/defineMainConfig.ts b/code/frameworks/preact-vite/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/preact-vite/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/preact-vite/src/index.ts b/code/frameworks/preact-vite/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/preact-vite/src/index.ts +++ b/code/frameworks/preact-vite/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/preact-webpack5/package.json b/code/frameworks/preact-webpack5/package.json index cd7effb465d0..5f0290ffcebc 100644 --- a/code/frameworks/preact-webpack5/package.json +++ b/code/frameworks/preact-webpack5/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -75,8 +69,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/preact-webpack5/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/preact-webpack5/src/defineMainConfig.ts b/code/frameworks/preact-webpack5/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/preact-webpack5/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/preact-webpack5/src/index.ts b/code/frameworks/preact-webpack5/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/preact-webpack5/src/index.ts +++ b/code/frameworks/preact-webpack5/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/react-native-web-vite/package.json b/code/frameworks/react-native-web-vite/package.json index 8f392bc254dd..da31ba3bca39 100644 --- a/code/frameworks/react-native-web-vite/package.json +++ b/code/frameworks/react-native-web-vite/package.json @@ -35,12 +35,6 @@ "import": "./dist/vite-plugin.mjs", "require": "./dist/vite-plugin.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -92,8 +86,7 @@ "entries": [ "./src/index.ts", "./src/preset.ts", - "./src/vite-plugin.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/vite-plugin.ts" ], "platform": "node" }, diff --git a/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/react-native-web-vite/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/react-native-web-vite/src/defineMainConfig.ts b/code/frameworks/react-native-web-vite/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/react-native-web-vite/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/react-native-web-vite/src/index.ts b/code/frameworks/react-native-web-vite/src/index.ts index 1855ad61a70b..c316aff16a2c 100644 --- a/code/frameworks/react-native-web-vite/src/index.ts +++ b/code/frameworks/react-native-web-vite/src/index.ts @@ -1 +1,2 @@ export type { FrameworkOptions, StorybookConfig } from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index 6228aea36f4c..d871585cf42c 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -99,8 +93,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/react-vite/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/react-vite/src/defineMainConfig.ts b/code/frameworks/react-vite/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/react-vite/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/react-vite/src/index.ts b/code/frameworks/react-vite/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/react-vite/src/index.ts +++ b/code/frameworks/react-vite/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/react-webpack5/package.json b/code/frameworks/react-webpack5/package.json index 8c26cc0072aa..c6c05892a81f 100644 --- a/code/frameworks/react-webpack5/package.json +++ b/code/frameworks/react-webpack5/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -80,8 +74,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/react-webpack5/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/react-webpack5/src/defineMainConfig.ts b/code/frameworks/react-webpack5/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/react-webpack5/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/react-webpack5/src/index.ts b/code/frameworks/react-webpack5/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/react-webpack5/src/index.ts +++ b/code/frameworks/react-webpack5/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/server-webpack5/package.json b/code/frameworks/server-webpack5/package.json index 1f61cce000ec..ef6b005495c5 100644 --- a/code/frameworks/server-webpack5/package.json +++ b/code/frameworks/server-webpack5/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -73,8 +67,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/server-webpack5/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/server-webpack5/src/defineMainConfig.ts b/code/frameworks/server-webpack5/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/server-webpack5/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/server-webpack5/src/index.ts b/code/frameworks/server-webpack5/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/server-webpack5/src/index.ts +++ b/code/frameworks/server-webpack5/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index b82e3b98b28b..5007a4d2ff35 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -84,8 +78,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/svelte-vite/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/svelte-vite/src/defineMainConfig.ts b/code/frameworks/svelte-vite/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/svelte-vite/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/svelte-vite/src/index.ts b/code/frameworks/svelte-vite/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/svelte-vite/src/index.ts +++ b/code/frameworks/svelte-vite/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index f483c25bf7e3..78b652a38c07 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -76,8 +70,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/svelte-webpack5/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/svelte-webpack5/src/defineMainConfig.ts b/code/frameworks/svelte-webpack5/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/svelte-webpack5/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/svelte-webpack5/src/index.ts b/code/frameworks/svelte-webpack5/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/svelte-webpack5/src/index.ts +++ b/code/frameworks/svelte-webpack5/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index b47ab7a26343..6165990d8b1e 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -41,12 +41,6 @@ "require": "./dist/vite-plugin.js", "import": "./dist/vite-plugin.mjs" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -90,8 +84,7 @@ "./src/index.ts", "./src/preview.ts", "./src/preset.ts", - "./src/vite-plugin.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/vite-plugin.ts" ], "platform": "node" }, diff --git a/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts b/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/sveltekit/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/sveltekit/src/defineMainConfig.ts b/code/frameworks/sveltekit/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/sveltekit/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/sveltekit/src/index.ts b/code/frameworks/sveltekit/src/index.ts index a904f93ec89d..4e3e0a0ec393 100644 --- a/code/frameworks/sveltekit/src/index.ts +++ b/code/frameworks/sveltekit/src/index.ts @@ -1,2 +1,3 @@ export * from './types'; +export * from './defineMainConfig'; export * from './portable-stories'; diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index 2852d303990b..8d9b0f427a6a 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -35,12 +35,6 @@ "require": "./dist/vite-plugin.js", "import": "./dist/vite-plugin.mjs" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -86,8 +80,7 @@ "entries": [ "./src/index.ts", "./src/preset.ts", - "./src/vite-plugin.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/vite-plugin.ts" ], "platform": "node" }, diff --git a/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/vue3-vite/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/vue3-vite/src/defineMainConfig.ts b/code/frameworks/vue3-vite/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/vue3-vite/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/vue3-vite/src/index.ts b/code/frameworks/vue3-vite/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/vue3-vite/src/index.ts +++ b/code/frameworks/vue3-vite/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json index 973f16e8a820..b08859e0a714 100644 --- a/code/frameworks/vue3-webpack5/package.json +++ b/code/frameworks/vue3-webpack5/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -77,8 +71,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/vue3-webpack5/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/vue3-webpack5/src/defineMainConfig.ts b/code/frameworks/vue3-webpack5/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/vue3-webpack5/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/vue3-webpack5/src/index.ts b/code/frameworks/vue3-webpack5/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/vue3-webpack5/src/index.ts +++ b/code/frameworks/vue3-webpack5/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index 27b17e55155e..92a76784a0aa 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -30,12 +30,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -72,7 +66,6 @@ }, "bundler": { "entries": [ - "./src/csf-factory/defineMainConfig.ts", "./src/index.ts", "./src/preset.ts" ], diff --git a/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts b/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/web-components-vite/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/web-components-vite/src/defineMainConfig.ts b/code/frameworks/web-components-vite/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/web-components-vite/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/web-components-vite/src/index.ts b/code/frameworks/web-components-vite/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/web-components-vite/src/index.ts +++ b/code/frameworks/web-components-vite/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index 2e9b89f3223c..aa4281ef433e 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -33,12 +33,6 @@ "types": "./dist/preset.d.ts", "require": "./dist/preset.js" }, - "./node": { - "types": "./dist/csf-factory/defineMainConfig.d.ts", - "node": "./dist/csf-factory/defineMainConfig.js", - "import": "./dist/csf-factory/defineMainConfig.mjs", - "require": "./dist/csf-factory/defineMainConfig.js" - }, "./package.json": "./package.json" }, "main": "dist/index.js", @@ -77,8 +71,7 @@ "bundler": { "entries": [ "./src/index.ts", - "./src/preset.ts", - "./src/csf-factory/defineMainConfig.ts" + "./src/preset.ts" ], "platform": "node" }, diff --git a/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts b/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts deleted file mode 100644 index dd999c40b17b..000000000000 --- a/code/frameworks/web-components-webpack5/src/csf-factory/defineMainConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig as commonDefineConfig } from 'storybook/internal/common'; - -import type { StorybookConfig } from '../types'; - -export function defineMain(config: StorybookConfig) { - return commonDefineConfig(config); -} diff --git a/code/frameworks/web-components-webpack5/src/defineMainConfig.ts b/code/frameworks/web-components-webpack5/src/defineMainConfig.ts new file mode 100644 index 000000000000..29be946269ac --- /dev/null +++ b/code/frameworks/web-components-webpack5/src/defineMainConfig.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from './types'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/code/frameworks/web-components-webpack5/src/index.ts b/code/frameworks/web-components-webpack5/src/index.ts index fcb073fefcd6..bb8ba9918a0d 100644 --- a/code/frameworks/web-components-webpack5/src/index.ts +++ b/code/frameworks/web-components-webpack5/src/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './defineMainConfig'; diff --git a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts index 7a89afabdecf..42bbc3b75abe 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts @@ -83,6 +83,7 @@ export async function getSyncedStorybookAddons( */ addons.forEach(async (addon) => { const annotations = await getAddonAnnotations(addon); + console.log(); if (annotations) { previewConfig.setImport({ namespace: annotations.importName }, annotations.importPath); const existingAddons = previewConfig.getFieldNode(['addons']); From 04d9f58cbda25029dce44081a2846c2af2c91bab Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 20 Jan 2025 17:47:56 +0100 Subject: [PATCH 19/24] modify preview/main config format in codemods/csf file --- code/.storybook/main.ts | 6 +- code/.storybook/preview.tsx | 4 +- code/core/src/csf-tools/ConfigFile.test.ts | 61 +++--- code/core/src/csf-tools/ConfigFile.ts | 2 +- .../template/stories/csf4.stories.tsx | 5 +- .../helpers/config-to-csf-factory.test.ts | 16 +- .../codemod/helpers/config-to-csf-factory.ts | 40 +++- .../helpers/csf-factories-utils.test.ts | 31 ++- .../codemod/helpers/csf-factories-utils.ts | 13 +- .../helpers/story-to-csf-factory.test.ts | 190 ++++++++++-------- .../codemod/helpers/story-to-csf-factory.ts | 18 +- .../src/__test__/Button.csf4.stories.tsx | 4 +- .../react/src/csf-factories.test.tsx | 4 +- code/renderers/react/src/preview.tsx | 2 +- 14 files changed, 236 insertions(+), 160 deletions(-) diff --git a/code/.storybook/main.ts b/code/.storybook/main.ts index 48109681b6b0..371aa942f5f3 100644 --- a/code/.storybook/main.ts +++ b/code/.storybook/main.ts @@ -1,12 +1,12 @@ import { join } from 'node:path'; -import type { StorybookConfig } from '../frameworks/react-vite'; +import { defineMain } from '../frameworks/react-vite'; const componentsPath = join(__dirname, '../core/src/components'); const managerApiPath = join(__dirname, '../core/src/manager-api'); const imageContextPath = join(__dirname, '..//frameworks/nextjs/src/image-context.ts'); -const config: StorybookConfig = { +const config = defineMain({ stories: [ './*.stories.@(js|jsx|ts|tsx)', { @@ -169,6 +169,6 @@ const config: StorybookConfig = { } satisfies typeof viteConfig); }, // logLevel: 'debug', -}; +}); export default config; diff --git a/code/.storybook/preview.tsx b/code/.storybook/preview.tsx index 2437d15e4a39..a4f48da6580f 100644 --- a/code/.storybook/preview.tsx +++ b/code/.storybook/preview.tsx @@ -18,7 +18,7 @@ import { import { DocsContext } from '@storybook/blocks'; import { global } from '@storybook/global'; import type { Decorator, Loader, ReactRenderer } from '@storybook/react'; -import { defineConfig } from '@storybook/react/preview'; +import { definePreview } from '@storybook/react/preview'; // TODO add empty preview // import * as storysource from '@storybook/addon-storysource'; @@ -375,7 +375,7 @@ const parameters = { }, }; -export const config = defineConfig({ +export const config = definePreview({ addons: [addonThemes, essentials, a11y, addonsPreview, templatePreview], parameters, decorators, diff --git a/code/core/src/csf-tools/ConfigFile.test.ts b/code/core/src/csf-tools/ConfigFile.test.ts index b4c3895538f8..e6739e8a27ec 100644 --- a/code/core/src/csf-tools/ConfigFile.test.ts +++ b/code/core/src/csf-tools/ConfigFile.test.ts @@ -247,9 +247,9 @@ describe('ConfigFile', () => { describe('factory config', () => { it('parses correctly', () => { const source = dedent` - import { defineConfig } from '@storybook/react-vite/browser'; + import { definePreview } from '@storybook/react-vite/preview'; - const config = defineConfig({ + const config = definePreview({ framework: 'foo', }); export default config; @@ -262,20 +262,20 @@ describe('ConfigFile', () => { getField( ['core', 'builder'], dedent` - import { defineConfig } from '@storybook/react-vite/preview'; - export const foo = defineConfig({ core: { builder: 'webpack5' } }); + import { definePreview } from '@storybook/react-vite/preview'; + export const foo = definePreview({ core: { builder: 'webpack5' } }); ` ) ).toEqual('webpack5'); }); - it('tags', () => { + it.only('tags', () => { expect( getField( ['tags'], dedent` - import { defineConfig } from '@storybook/react-vite/preview'; + import { definePreview } from '@storybook/react-vite/preview'; const parameters = {}; - export const config = defineConfig({ + export const config = definePreview({ parameters, tags: ['test', 'vitest', '!a11ytest'], }); @@ -528,21 +528,21 @@ describe('ConfigFile', () => { ['core', 'builder'], 'webpack5', dedent` - import { defineConfig } from '@storybook/react-vite/preview'; - export const foo = defineConfig({ + import { definePreview } from '@storybook/react-vite/preview'; + export const foo = definePreview({ addons: [], }); ` ) ).toMatchInlineSnapshot(` - import { defineConfig } from '@storybook/react-vite/preview'; - export const foo = defineConfig({ + import { definePreview } from '@storybook/react-vite/preview'; + export const foo = definePreview({ addons: [], - - core: { - builder: 'webpack5' - } }); + + export const core = { + builder: 'webpack5' + }; `); }); it('missing field', () => { @@ -551,20 +551,21 @@ describe('ConfigFile', () => { ['core', 'builder'], 'webpack5', dedent` - import { defineConfig } from '@storybook/react-vite/preview'; - export const foo = defineConfig({ + import { definePreview } from '@storybook/react-vite/preview'; + export const foo = definePreview({ core: { foo: 'bar' }, }); ` ) ).toMatchInlineSnapshot(` - import { defineConfig } from '@storybook/react-vite/preview'; - export const foo = defineConfig({ - core: { - foo: 'bar', - builder: 'webpack5' - }, + import { definePreview } from '@storybook/react-vite/preview'; + export const foo = definePreview({ + core: { foo: 'bar' }, }); + + export const core = { + builder: 'webpack5' + }; `); }); it('found scalar', () => { @@ -573,17 +574,21 @@ describe('ConfigFile', () => { ['core', 'builder'], 'webpack5', dedent` - import { defineConfig } from '@storybook/react-vite/preview'; - export const foo = defineConfig({ + import { definePreview } from '@storybook/react-vite/preview'; + export const foo = definePreview({ core: { builder: 'webpack4' }, }); ` ) ).toMatchInlineSnapshot(` - import { defineConfig } from '@storybook/react-vite/preview'; - export const foo = defineConfig({ - core: { builder: 'webpack5' }, + import { definePreview } from '@storybook/react-vite/preview'; + export const foo = definePreview({ + core: { builder: 'webpack4' }, }); + + export const core = { + builder: 'webpack5' + }; `); }); }); diff --git a/code/core/src/csf-tools/ConfigFile.ts b/code/core/src/csf-tools/ConfigFile.ts index 7ea42448dfc6..d1aecfb7ae63 100644 --- a/code/core/src/csf-tools/ConfigFile.ts +++ b/code/core/src/csf-tools/ConfigFile.ts @@ -318,7 +318,7 @@ export class ConfigFile { enter: ({ node }) => { if ( t.isIdentifier(node.callee) && - node.callee.name === 'defineConfig' && + node.callee.name === 'definePreview' && node.arguments.length === 1 && t.isObjectExpression(node.arguments[0]) ) { diff --git a/code/frameworks/react-vite/template/stories/csf4.stories.tsx b/code/frameworks/react-vite/template/stories/csf4.stories.tsx index 012c356881c6..4bb4a60cbf35 100644 --- a/code/frameworks/react-vite/template/stories/csf4.stories.tsx +++ b/code/frameworks/react-vite/template/stories/csf4.stories.tsx @@ -1,6 +1,5 @@ -import React from 'react'; - -import { config } from '#.storybook/preview'; +// @ts-expect-error this will be part of the package.json of the sandbox +import config from '#.storybook/preview'; const meta = config.meta({ component: globalThis.Components.Button, diff --git a/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts b/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts index 847368f71e15..ee0a31900810 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts @@ -28,7 +28,7 @@ describe('main/preview codemod: general parsing functionality', () => { }; `) ).resolves.toMatchInlineSnapshot(` - import { defineMain } from '@storybook/react-vite/node'; + import { defineMain } from '@storybook/react-vite'; export default defineMain({ stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], @@ -49,7 +49,7 @@ describe('main/preview codemod: general parsing functionality', () => { export default config; `) ).resolves.toMatchInlineSnapshot(` - import { defineMain } from '@storybook/react-vite/node'; + import { defineMain } from '@storybook/react-vite'; export default defineMain({ stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], @@ -69,7 +69,7 @@ describe('main/preview codemod: general parsing functionality', () => { export default config; `) ).resolves.toMatchInlineSnapshot(` - import { defineMain } from '@storybook/react-vite/node'; + import { defineMain } from '@storybook/react-vite'; const config = { framework: '@storybook/react-vite', @@ -87,7 +87,7 @@ describe('main/preview codemod: general parsing functionality', () => { export const framework = '@storybook/react-vite'; `) ).resolves.toMatchInlineSnapshot(` - import { defineMain } from '@storybook/react-vite/node'; + import { defineMain } from '@storybook/react-vite'; export default defineMain({ stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], @@ -111,7 +111,7 @@ describe('main/preview codemod: general parsing functionality', () => { it('should remove legacy main config type imports', async () => { await expect( transform(dedent` - import type { StorybookConfig } from '@storybook/react' + import { type StorybookConfig } from '@storybook/react-vite' const config: StorybookConfig = { stories: [] @@ -119,7 +119,7 @@ describe('main/preview codemod: general parsing functionality', () => { export default config; `) ).resolves.toMatchInlineSnapshot(` - import { defineMain } from '@storybook/react-vite/node'; + import { defineMain } from '@storybook/react-vite'; export default defineMain({ stories: [], @@ -145,7 +145,7 @@ describe('preview specific functionality', () => { }; `) ).resolves.toMatchInlineSnapshot(` - import { definePreview } from '@storybook/react-vite/browser'; + import { definePreview } from '@storybook/react/preview'; export default definePreview({ tags: ['test'], @@ -164,7 +164,7 @@ describe('preview specific functionality', () => { export default preview; `) ).resolves.toMatchInlineSnapshot(` - import { definePreview } from '@storybook/react-vite/browser'; + import { definePreview } from '@storybook/react/preview'; export default definePreview({ tags: [], diff --git a/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts b/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts index ea5bf4f5e93c..65bc136af80c 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts @@ -23,6 +23,12 @@ export async function configToCsfFactory( } const methodName = configType === 'main' ? 'defineMain' : 'definePreview'; + // TODO: remove this later, it's just a quick workaround for preview imports + // while it is part of @storybook/react and not @storybook/react-vite + frameworkPackage = + configType === 'preview' && frameworkPackage === '@storybook/react-vite' + ? '@storybook/react' + : frameworkPackage; const programNode = config._ast.program; const hasNamedExports = Object.keys(config._exportDecls).length > 0; @@ -151,14 +157,34 @@ export async function configToCsfFactory( const configImport = t.importDeclaration( [t.importSpecifier(t.identifier(methodName), t.identifier(methodName))], - t.stringLiteral(frameworkPackage + `/${configType === 'main' ? 'node' : 'browser'}`) + t.stringLiteral(frameworkPackage + `${configType === 'preview' ? '/preview' : ''}`) ); - // only add the import if it doesn't exist yet - if ( - !programNode.body.some( - (node) => t.isImportDeclaration(node) && node.source.value === configImport.source.value - ) - ) { + + // Check whether @storybook/framework import already exists + const existingImport = programNode.body.find( + (node) => + t.isImportDeclaration(node) && + node.source.value === configImport.source.value && + !node.importKind + ); + + if (existingImport && t.isImportDeclaration(existingImport)) { + // If it does, check whether defineMain/definePreview is already imported + // and only add it if it's not + const hasMethodName = existingImport.specifiers.some( + (specifier) => + t.isImportSpecifier(specifier) && + t.isIdentifier(specifier.imported) && + specifier.imported.name === methodName + ); + + if (!hasMethodName) { + existingImport.specifiers.push( + t.importSpecifier(t.identifier(methodName), t.identifier(methodName)) + ); + } + } else { + // if not, add import { defineMain } from '@storybook/framework' programNode.body.unshift(configImport); } diff --git a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts index 27e065c86455..1eeb7f6282f7 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts @@ -25,7 +25,7 @@ describe('getSyncedStorybookAddons', () => { it('should sync addons between main and preview', async () => { const preview = loadConfig(` import * as myAddonAnnotations from "custom-addon/preview"; - import { definePreview } from "@storybook/react-vite/browser"; + import { definePreview } from "@storybook/react/preview"; export default definePreview({ addons: [myAddonAnnotations], @@ -40,18 +40,43 @@ describe('getSyncedStorybookAddons', () => { expect(printConfig(result).code).toMatchInlineSnapshot(` import * as addonA11yAnnotations from "@storybook/addon-a11y/preview"; import * as myAddonAnnotations from "custom-addon/preview"; - import { definePreview } from "@storybook/react-vite/browser"; + import { definePreview } from "@storybook/react/preview"; export default definePreview({ addons: [myAddonAnnotations, addonA11yAnnotations], }); `); }); + it.only('should add addons if the preview has no addons field', async () => { + const originalCode = ` + import { definePreview } from "@storybook/react/preview"; + + export default definePreview({ + tags: [] + }); + `; + const preview = loadConfig(originalCode).parse(); + + (getAddonAnnotations as Mock).mockImplementation(() => { + return { importName: 'addonA11yAnnotations', importPath: '@storybook/addon-a11y/preview' }; + }); + + const result = await getSyncedStorybookAddons(mainConfig, preview); + expect(printConfig(result).code).toMatchInlineSnapshot(` + import * as addonA11yAnnotations from "@storybook/addon-a11y/preview"; + import { definePreview } from "@storybook/react/preview"; + + export default definePreview({ + tags: [], + addons: [addonA11yAnnotations] + }); + `); + }); it('should not modify the code if all addons are already synced', async () => { const originalCode = ` import * as addonA11yAnnotations from "@storybook/addon-a11y/preview"; import * as myAddonAnnotations from "custom-addon/preview"; - import { definePreview } from "@storybook/react-vite/browser"; + import { definePreview } from "@storybook/react/preview"; export default definePreview({ addons: [myAddonAnnotations, addonA11yAnnotations], diff --git a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts index 42bbc3b75abe..c01ade0954c3 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts @@ -59,7 +59,7 @@ export async function getSyncedStorybookAddons( return ( t.isImportDeclaration(node) && node.source.value.includes('@storybook') && - node.source.value.endsWith('/browser') && + node.source.value.endsWith('/preview') && node.specifiers.some((specifier) => { return ( t.isImportSpecifier(specifier) && @@ -83,15 +83,16 @@ export async function getSyncedStorybookAddons( */ addons.forEach(async (addon) => { const annotations = await getAddonAnnotations(addon); - console.log(); if (annotations) { previewConfig.setImport({ namespace: annotations.importName }, annotations.importPath); const existingAddons = previewConfig.getFieldNode(['addons']); + if ( - t.isArrayExpression(existingAddons) && - !existingAddons.elements.some( - (element) => t.isIdentifier(element) && element.name === annotations.importName - ) + !existingAddons || + (t.isArrayExpression(existingAddons) && + !existingAddons.elements.some( + (element) => t.isIdentifier(element) && element.name === annotations.importName + )) ) { previewConfig.appendNodeToArray(['addons'], t.identifier(annotations.importName)); } diff --git a/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts index 3a98dbeece0b..ea19c007f7f8 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts @@ -25,10 +25,10 @@ describe('stories codemod', () => { export default meta; `) ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - const meta = config.meta({ title: 'Component' }); - `); + const meta = config.meta({ title: 'Component' }); + `); }); it('should transform and wrap inline default exported meta', async () => { @@ -37,12 +37,12 @@ describe('stories codemod', () => { export default { title: 'Component' }; `) ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - const meta = config.meta({ - title: 'Component', - }); - `); + const meta = config.meta({ + title: 'Component', + }); + `); }); it('should rename meta object to meta if it has a different name', async () => { @@ -52,10 +52,10 @@ describe('stories codemod', () => { export default componentMeta; `) ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - const meta = config.meta({ title: 'Component' }); - `); + const meta = config.meta({ title: 'Component' }); + `); }); it('should wrap stories in a meta.story method', async () => { @@ -69,14 +69,14 @@ describe('stories codemod', () => { }; `) ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; - - const meta = config.meta({ title: 'Component' }); - export const A = meta.story({ - args: { primary: true }, - render: (args) => , - }); - `); + import config from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); + export const A = meta.story({ + args: { primary: true }, + render: (args) => , + }); + `); }); it('should respect existing config imports', async () => { @@ -91,14 +91,36 @@ describe('stories codemod', () => { }; `) ).resolves.toMatchInlineSnapshot(` - import { config, decorators } from '#.storybook/preview'; - - const meta = config.meta({ title: 'Component' }); - export const A = meta.story({ - args: { primary: true }, - render: (args) => , - }); - `); + import config, { decorators } from '#.storybook/preview'; + + const meta = config.meta({ title: 'Component' }); + export const A = meta.story({ + args: { primary: true }, + render: (args) => , + }); + `); + }); + + it('should reuse existing default config import name', async () => { + await expect( + transform(dedent` + import previewConfig from "#.storybook/preview"; + const componentMeta = { title: 'Component' }; + export default componentMeta; + export const A = { + args: { primary: true }, + render: (args) => + }; + `) + ).resolves.toMatchInlineSnapshot(` + import previewConfig from '#.storybook/preview'; + + const meta = previewConfig.meta({ title: 'Component' }); + export const A = meta.story({ + args: { primary: true }, + render: (args) => , + }); + `); }); it('if there is an existing local constant called config, rename storybook config import', async () => { @@ -113,15 +135,15 @@ describe('stories codemod', () => { }; `) ).resolves.toMatchInlineSnapshot(` - import { config as storybookConfig } from '#.storybook/preview'; - - const meta = storybookConfig.meta({ title: 'Component' }); - const config = {}; - export const A = meta.story({ - args: { primary: true }, - render: (args) => , - }); - `); + import storybookConfig from '#.storybook/preview'; + + const meta = storybookConfig.meta({ title: 'Component' }); + const config = {}; + export const A = meta.story({ + args: { primary: true }, + render: (args) => , + }); + `); }); it('converts CSF1 into CSF4 with render', async () => { @@ -132,13 +154,13 @@ describe('stories codemod', () => { export const CSF1Story = () =>
Hello
; `) ).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - const meta = config.meta({ title: 'Component' }); - export const CSF1Story = meta.story({ - render: () =>
Hello
, - }); - `); + const meta = config.meta({ title: 'Component' }); + export const CSF1Story = meta.story({ + render: () =>
Hello
, + }); + `); }); }); @@ -155,16 +177,16 @@ describe('stories codemod', () => { `; it('meta satisfies syntax', async () => { await expect(transform(inlineMetaSatisfies)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - import { ComponentProps } from './Component'; + import { ComponentProps } from './Component'; - const meta = config.meta({ title: 'Component', component: Component }); + const meta = config.meta({ title: 'Component', component: Component }); - export const A = meta.story({ - args: { primary: true }, - }); - `); + export const A = meta.story({ + args: { primary: true }, + }); + `); }); const inlineMetaAs = dedent` @@ -179,16 +201,16 @@ describe('stories codemod', () => { `; it('meta as syntax', async () => { await expect(transform(inlineMetaAs)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - import { ComponentProps } from './Component'; + import { ComponentProps } from './Component'; - const meta = config.meta({ title: 'Component', component: Component }); + const meta = config.meta({ title: 'Component', component: Component }); - export const A = meta.story({ - args: { primary: true }, - }); - `); + export const A = meta.story({ + args: { primary: true }, + }); + `); }); const metaSatisfies = dedent` import { Meta, StoryObj as CSF3 } from '@storybook/react'; @@ -203,16 +225,16 @@ describe('stories codemod', () => { `; it('meta satisfies syntax', async () => { await expect(transform(metaSatisfies)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - import { ComponentProps } from './Component'; + import { ComponentProps } from './Component'; - const meta = config.meta({ title: 'Component', component: Component }); + const meta = config.meta({ title: 'Component', component: Component }); - export const A = meta.story({ - args: { primary: true }, - }); - `); + export const A = meta.story({ + args: { primary: true }, + }); + `); }); const metaAs = dedent` @@ -228,16 +250,16 @@ describe('stories codemod', () => { `; it('meta as syntax', async () => { await expect(transform(metaAs)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - import { ComponentProps } from './Component'; + import { ComponentProps } from './Component'; - const meta = config.meta({ title: 'Component', component: Component }); + const meta = config.meta({ title: 'Component', component: Component }); - export const A = meta.story({ - args: { primary: true }, - }); - `); + export const A = meta.story({ + args: { primary: true }, + }); + `); }); const storySatisfies = dedent` @@ -253,16 +275,16 @@ describe('stories codemod', () => { `; it('story satisfies syntax', async () => { await expect(transform(storySatisfies)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - import { ComponentProps } from './Component'; + import { ComponentProps } from './Component'; - const meta = config.meta({ title: 'Component', component: Component }); + const meta = config.meta({ title: 'Component', component: Component }); - export const A = meta.story({ - args: { primary: true }, - }); - `); + export const A = meta.story({ + args: { primary: true }, + }); + `); }); const storyAs = dedent` @@ -278,16 +300,16 @@ describe('stories codemod', () => { `; it('story as syntax', async () => { await expect(transform(storyAs)).resolves.toMatchInlineSnapshot(` - import { config } from '#.storybook/preview'; + import config from '#.storybook/preview'; - import { ComponentProps } from './Component'; + import { ComponentProps } from './Component'; - const meta = config.meta({ title: 'Component', component: Component }); + const meta = config.meta({ title: 'Component', component: Component }); - export const A = meta.story({ - args: { primary: true }, - }); - `); + export const A = meta.story({ + args: { primary: true }, + }); + `); }); it('should yield the same result to all syntaxes', async () => { diff --git a/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts index c359b8dfa997..acf02ee8274f 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts @@ -32,22 +32,20 @@ export async function storyToCsfFactory(info: FileInfo) { n.declarations.some((declaration) => t.isIdentifier(declaration.id, { name: 'config' })) ); - const sbConfigImportName = hasRootLevelConfig ? 'storybookConfig' : 'config'; + let sbConfigImportName = hasRootLevelConfig ? 'storybookConfig' : 'config'; - const sbConfigImportSpecifier = t.importSpecifier( - t.identifier(sbConfigImportName), - t.identifier('config') - ); + const sbConfigImportSpecifier = t.importDefaultSpecifier(t.identifier(sbConfigImportName)); programNode.body.forEach((node) => { if (t.isImportDeclaration(node) && isValidPreviewPath(node.source.value)) { - const hasConfigSpecifier = node.specifiers.some( - (specifier) => - t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported, { name: 'config' }) + const defaultImportSpecifier = node.specifiers.find((specifier) => + t.isImportDefaultSpecifier(specifier) ); - if (!hasConfigSpecifier) { + if (!defaultImportSpecifier) { node.specifiers.push(sbConfigImportSpecifier); + } else if (defaultImportSpecifier.local.name !== sbConfigImportName) { + sbConfigImportName = defaultImportSpecifier.local.name; } foundConfigImport = true; @@ -149,7 +147,7 @@ export async function storyToCsfFactory(info: FileInfo) { if (hasMeta && !foundConfigImport) { const configImport = t.importDeclaration( - [sbConfigImportSpecifier], + [t.importDefaultSpecifier(t.identifier(sbConfigImportName))], t.stringLiteral('#.storybook/preview') ); programNode.body.unshift(configImport); diff --git a/code/renderers/react/src/__test__/Button.csf4.stories.tsx b/code/renderers/react/src/__test__/Button.csf4.stories.tsx index 6a57e1d5a909..067e481a3d6a 100644 --- a/code/renderers/react/src/__test__/Button.csf4.stories.tsx +++ b/code/renderers/react/src/__test__/Button.csf4.stories.tsx @@ -5,10 +5,10 @@ import { expect, fn, mocked, userEvent, within } from '@storybook/test'; import { action } from '@storybook/addon-actions'; -import { defineConfig } from '../preview'; +import { definePreview } from '../preview'; import { Button } from './Button'; -const config = defineConfig({ args: { children: 'TODO: THIS IS NOT WORKING YET' } }); +const config = definePreview({}); const meta = config.meta({ id: 'button-component', diff --git a/code/renderers/react/src/csf-factories.test.tsx b/code/renderers/react/src/csf-factories.test.tsx index 12ea20a79ce2..2bceb23a53c6 100644 --- a/code/renderers/react/src/csf-factories.test.tsx +++ b/code/renderers/react/src/csf-factories.test.tsx @@ -1,10 +1,10 @@ import { expect, test } from 'vitest'; import { Button } from './__test__/Button'; -import { defineConfig } from './preview'; +import { definePreview } from './preview'; test('csf factories', () => { - const config = defineConfig({ + const config = definePreview({ addons: [ { decorators: [], diff --git a/code/renderers/react/src/preview.tsx b/code/renderers/react/src/preview.tsx index 55489ef5bdab..9230029d907c 100644 --- a/code/renderers/react/src/preview.tsx +++ b/code/renderers/react/src/preview.tsx @@ -17,7 +17,7 @@ import * as reactAnnotations from './entry-preview'; import * as reactDocsAnnotations from './entry-preview-docs'; import type { ReactRenderer } from './types'; -export function defineConfig(config: PreviewConfigData) { +export function definePreview(config: PreviewConfigData) { return new PreviewConfig({ ...config, addons: [reactAnnotations, reactDocsAnnotations, ...(config.addons ?? [])], From 71fefdaba67ce1e4aa343c0630f4fbdebaec21cb Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 20 Jan 2025 18:35:24 +0100 Subject: [PATCH 20/24] add fixes, fix types, fix tests --- code/lib/cli-storybook/src/add.test.ts | 2 ++ code/lib/cli-storybook/src/add.ts | 2 -- .../missing-storybook-dependencies.test.ts | 2 ++ .../src/automigrate/index.test.ts | 2 ++ .../codemod/helpers/csf-factories-utils.ts | 2 -- .../helpers/story-to-csf-factory.test.ts | 22 +++++++++++++++++++ .../codemod/helpers/story-to-csf-factory.ts | 19 ++++++++++++++++ code/lib/cli-storybook/src/migrate.ts | 17 +++++++------- code/lib/cli-storybook/src/upgrade.ts | 21 +++++++++--------- scripts/tasks/sandbox-parts.ts | 1 - 10 files changed, 65 insertions(+), 25 deletions(-) diff --git a/code/lib/cli-storybook/src/add.test.ts b/code/lib/cli-storybook/src/add.test.ts index 1bbf88275afc..0d5241b033bc 100644 --- a/code/lib/cli-storybook/src/add.test.ts +++ b/code/lib/cli-storybook/src/add.test.ts @@ -47,10 +47,12 @@ vi.mock('./postinstallAddon', () => { vi.mock('./automigrate/fixes/wrap-require-utils', () => { return MockWrapRequireUtils; }); +vi.mock('./codemod/helpers/csf-factories-utils'); vi.mock('storybook/internal/common', () => { return { getStorybookInfo: vi.fn(() => ({ mainConfig: {}, configDir: '' })), serverRequire: vi.fn(() => ({})), + loadMainConfig: vi.fn(() => ({})), JsPackageManagerFactory: { getPackageManager: vi.fn(() => MockedPackageManager), }, diff --git a/code/lib/cli-storybook/src/add.ts b/code/lib/cli-storybook/src/add.ts index 2fb796d7793b..02b8fc366a4e 100644 --- a/code/lib/cli-storybook/src/add.ts +++ b/code/lib/cli-storybook/src/add.ts @@ -3,8 +3,6 @@ import { isAbsolute, join } from 'node:path'; import { JsPackageManagerFactory, type PackageManagerName, - getCoercedStorybookVersion, - getStorybookInfo, serverRequire, versions, } from 'storybook/internal/common'; diff --git a/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.test.ts index 2729cfb1da16..b39926413778 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.test.ts @@ -109,6 +109,8 @@ describe('missingStorybookDependencies', () => { await missingStorybookDependencies.run!({ result: { packageUsage }, dryRun, + packageJson: {}, + mainConfig: { stories: [] }, packageManager: mockPackageManager as JsPackageManager, mainConfigPath: 'path/to/main-config.js', }); diff --git a/code/lib/cli-storybook/src/automigrate/index.test.ts b/code/lib/cli-storybook/src/automigrate/index.test.ts index 9bc05affbacc..1ca806a22c91 100644 --- a/code/lib/cli-storybook/src/automigrate/index.test.ts +++ b/code/lib/cli-storybook/src/automigrate/index.test.ts @@ -89,6 +89,8 @@ const runFixWrapper = async ({ fixes, dryRun, yes, + packageJson: {}, + mainConfig: { stories: [] }, rendererPackage, skipInstall, configDir, diff --git a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts index c01ade0954c3..c12ef4fc4e31 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts @@ -1,6 +1,4 @@ /* eslint-disable no-underscore-dangle */ -import path from 'node:path'; - import { types as t } from 'storybook/internal/babel'; import { type ConfigFile, readConfig, writeConfig } from 'storybook/internal/csf-tools'; diff --git a/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts index ea19c007f7f8..3064115ca976 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts @@ -326,5 +326,27 @@ describe('stories codemod', () => { expect(result).toEqual(allSnippets[0]); }); }); + + it('should remove unused Story types', async () => { + await expect( + transform( + `import { Meta, StoryObj as CSF3 } from '@storybook/react'; + import { ComponentProps } from './Component'; + + export default {}; + type Story = StoryObj; + + export const A: Story = {};` + ) + ).resolves.toMatchInlineSnapshot(` + import config from '#.storybook/preview'; + + import { ComponentProps } from './Component'; + + const meta = config.meta({}); + + export const A = meta.story({}); + `); + }); }); }); diff --git a/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts index acf02ee8274f..f374eea9df80 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts @@ -165,5 +165,24 @@ export async function storyToCsfFactory(info: FileInfo) { ]; programNode.body = cleanupTypeImports(programNode, disallowList); + // Remove unused type aliases e.g. `type Story = StoryObj;` + programNode.body.forEach((node, index) => { + if (t.isTSTypeAliasDeclaration(node)) { + const isUsed = programNode.body.some((otherNode) => { + if (t.isVariableDeclaration(otherNode)) { + return otherNode.declarations.some( + (declaration) => + t.isIdentifier(declaration.init) && declaration.init.name === node.id.name + ); + } + return false; + }); + + if (!isUsed) { + programNode.body.splice(index, 1); + } + } + }); + return printCsf(csf).code; } diff --git a/code/lib/cli-storybook/src/migrate.ts b/code/lib/cli-storybook/src/migrate.ts index e985971b5a05..9075a9d9e8b2 100644 --- a/code/lib/cli-storybook/src/migrate.ts +++ b/code/lib/cli-storybook/src/migrate.ts @@ -9,6 +9,7 @@ import { listCodemods, runCodemod } from '@storybook/codemod'; import { runFixes } from './automigrate'; import { mdxToCSF } from './automigrate/fixes/mdx-to-csf'; +import { getStorybookData } from './automigrate/helpers/mainConfigFile'; const logger = console; @@ -33,15 +34,11 @@ export async function migrate( if (migration === 'mdx-to-csf' && !dryRun) { const packageManager = JsPackageManagerFactory.getPackageManager(); - const [packageJson, storybookVersion] = await Promise.all([ - packageManager.retrievePackageJson(), - getCoercedStorybookVersion(packageManager), - ]); - const { configDir: inferredConfigDir, mainConfig: mainConfigPath } = getStorybookInfo( - packageJson, - userSpecifiedConfigDir - ); - const configDir = userSpecifiedConfigDir || inferredConfigDir || '.storybook'; + const { configDir, mainConfig, mainConfigPath, storybookVersion, packageJson } = + await getStorybookData({ + packageManager, + configDir: userSpecifiedConfigDir, + }); // GUARDS if (!storybookVersion) { @@ -57,6 +54,8 @@ export async function migrate( configDir, mainConfigPath, packageManager, + mainConfig, + packageJson, storybookVersion, beforeVersion: storybookVersion, isUpgrade: false, diff --git a/code/lib/cli-storybook/src/upgrade.ts b/code/lib/cli-storybook/src/upgrade.ts index 6657fb0ee691..5a8bd0a4efb0 100644 --- a/code/lib/cli-storybook/src/upgrade.ts +++ b/code/lib/cli-storybook/src/upgrade.ts @@ -24,6 +24,7 @@ import semver, { clean, eq, lt, prerelease } from 'semver'; import { dedent } from 'ts-dedent'; import { autoblock } from './autoblock/index'; +import { getStorybookData } from './automigrate/helpers/mainConfigFile'; import { automigrate } from './automigrate/index'; type Package = { @@ -157,10 +158,7 @@ export const doUpgrade = async ({ logger.warn(new UpgradeStorybookToSameVersionError({ beforeVersion }).message); } - const [latestCLIVersionOnNPM, packageJson] = await Promise.all([ - packageManager.latestVersion('storybook'), - packageManager.retrievePackageJson(), - ]); + const latestCLIVersionOnNPM = await packageManager.latestVersion('storybook'); const isCLIOutdated = lt(currentCLIVersion, latestCLIVersionOnNPM); const isCLIExactLatest = currentCLIVersion === latestCLIVersionOnNPM; @@ -198,13 +196,11 @@ export const doUpgrade = async ({ let results; - const { configDir: inferredConfigDir, mainConfig: mainConfigPath } = getStorybookInfo( - packageJson, - userSpecifiedConfigDir - ); - const configDir = userSpecifiedConfigDir || inferredConfigDir || '.storybook'; - - const mainConfig = await loadMainConfig({ configDir }); + const { configDir, mainConfig, mainConfigPath, previewConfigPath, packageJson } = + await getStorybookData({ + packageManager, + configDir: userSpecifiedConfigDir, + }); // GUARDS if (!beforeVersion) { @@ -277,7 +273,10 @@ export const doUpgrade = async ({ dryRun, yes, packageManager, + packageJson, + mainConfig, configDir, + previewConfigPath, mainConfigPath, beforeVersion, storybookVersion: currentCLIVersion, diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index be12a4ede276..f26599d99073 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -858,7 +858,6 @@ export async function setImportMap(cwd: string) { storybook: './template-stories/core/utils.mock.ts', default: './template-stories/core/utils.ts', }, - '#*': ['./*', './*.ts', './*.tsx'], }; await writeJson(join(cwd, 'package.json'), packageJson, { spaces: 2 }); From 69941ca2083de9cd2ccb8437f95634e8f5640eea Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 20 Jan 2025 18:41:30 +0100 Subject: [PATCH 21/24] fix portable stories test --- scripts/tasks/sandbox-parts.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index f26599d99073..9c5a40bf2771 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -426,10 +426,10 @@ export async function setupVitest(details: TemplateDetails, options: PassedOptio setupFilePath, dedent`import { beforeAll } from 'vitest' import { setProjectAnnotations } from '${storybookPackage}' - import * as projectAnnotations from './preview' + import projectAnnotations from './preview' // setProjectAnnotations still kept to support non-CSF4 story tests - const annotations = setProjectAnnotations(projectAnnotations.config.annotations) + const annotations = setProjectAnnotations(projectAnnotations.annotations) beforeAll(annotations.beforeAll) ` ); From 5b4cd434189a283544bb9660e3c00d2c2a0acb83 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 20 Jan 2025 19:39:55 +0100 Subject: [PATCH 22/24] fix build --- .../src/automigrate/index.test.ts | 20 ++++++++++--------- .../helpers/csf-factories-utils.test.ts | 2 +- .../codemod/helpers/csf-factories-utils.ts | 4 +++- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/code/lib/cli-storybook/src/automigrate/index.test.ts b/code/lib/cli-storybook/src/automigrate/index.test.ts index 1ca806a22c91..32a4a512cbc4 100644 --- a/code/lib/cli-storybook/src/automigrate/index.test.ts +++ b/code/lib/cli-storybook/src/automigrate/index.test.ts @@ -136,15 +136,17 @@ describe('runFixes', () => { expect(fixResults).toEqual({ 'fix-1': 'succeeded', }); - expect(run1).toHaveBeenCalledWith({ - dryRun, - mainConfigPath, - packageManager, - result: { - some: 'result', - }, - skipInstall, - }); + expect(run1).toHaveBeenCalledWith( + expect.objectContaining({ + dryRun, + mainConfigPath, + packageManager, + result: { + some: 'result', + }, + skipInstall, + }) + ); }); it('should fail if an error is thrown', async () => { diff --git a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts index 1eeb7f6282f7..4c7167b6b209 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts @@ -47,7 +47,7 @@ describe('getSyncedStorybookAddons', () => { }); `); }); - it.only('should add addons if the preview has no addons field', async () => { + it('should add addons if the preview has no addons field', async () => { const originalCode = ` import { definePreview } from "@storybook/react/preview"; diff --git a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts index c12ef4fc4e31..7995479f9159 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts @@ -35,7 +35,9 @@ export function cleanupTypeImports(programNode: t.Program, disallowList: string[ // Retain all other nodes return true; - }); + // @TODO adding any for now, unsure how to fix the following error: + // error TS4058: Return type of exported function has or is using name 'BlockStatement' from external module "/code/core/dist/babel/index" but cannot be named + }) as any; } export async function syncStorybookAddons( From 80c80acdebf1b1a461ca39e69cade330fe1d1aa6 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 20 Jan 2025 21:49:21 +0100 Subject: [PATCH 23/24] fix lint --- code/core/src/csf-tools/ConfigFile.test.ts | 2 +- .../src/codemod/helpers/csf-factories-utils.test.ts | 4 ++-- scripts/tasks/sandbox.ts | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/code/core/src/csf-tools/ConfigFile.test.ts b/code/core/src/csf-tools/ConfigFile.test.ts index e6739e8a27ec..f7b349669feb 100644 --- a/code/core/src/csf-tools/ConfigFile.test.ts +++ b/code/core/src/csf-tools/ConfigFile.test.ts @@ -268,7 +268,7 @@ describe('ConfigFile', () => { ) ).toEqual('webpack5'); }); - it.only('tags', () => { + it('tags', () => { expect( getField( ['tags'], diff --git a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts index 4c7167b6b209..af79e7442dac 100644 --- a/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts +++ b/code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts @@ -48,7 +48,7 @@ describe('getSyncedStorybookAddons', () => { `); }); it('should add addons if the preview has no addons field', async () => { - const originalCode = ` + const originalCode = dedent` import { definePreview } from "@storybook/react/preview"; export default definePreview({ @@ -73,7 +73,7 @@ describe('getSyncedStorybookAddons', () => { `); }); it('should not modify the code if all addons are already synced', async () => { - const originalCode = ` + const originalCode = dedent` import * as addonA11yAnnotations from "@storybook/addon-a11y/preview"; import * as myAddonAnnotations from "custom-addon/preview"; import { definePreview } from "@storybook/react/preview"; diff --git a/scripts/tasks/sandbox.ts b/scripts/tasks/sandbox.ts index 7bca37085843..33a3282d44d2 100644 --- a/scripts/tasks/sandbox.ts +++ b/scripts/tasks/sandbox.ts @@ -2,7 +2,6 @@ import dirSize from 'fast-folder-size'; // eslint-disable-next-line depend/ban-dependencies import { pathExists, remove } from 'fs-extra'; import { join } from 'path'; -import prompts from 'prompts'; import { promisify } from 'util'; import { now, saveBench } from '../bench/utils'; From 2ec88ee8c1ffb7d7460f059c7b8f36e98ef13f2e Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 21 Jan 2025 08:13:54 +0100 Subject: [PATCH 24/24] update snapshots --- code/core/src/csf-tools/ConfigFile.test.ts | 23 +++++++++------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/code/core/src/csf-tools/ConfigFile.test.ts b/code/core/src/csf-tools/ConfigFile.test.ts index f7b349669feb..6661cfb37622 100644 --- a/code/core/src/csf-tools/ConfigFile.test.ts +++ b/code/core/src/csf-tools/ConfigFile.test.ts @@ -538,11 +538,11 @@ describe('ConfigFile', () => { import { definePreview } from '@storybook/react-vite/preview'; export const foo = definePreview({ addons: [], - }); - export const core = { - builder: 'webpack5' - }; + core: { + builder: 'webpack5' + } + }); `); }); it('missing field', () => { @@ -560,12 +560,11 @@ describe('ConfigFile', () => { ).toMatchInlineSnapshot(` import { definePreview } from '@storybook/react-vite/preview'; export const foo = definePreview({ - core: { foo: 'bar' }, + core: { + foo: 'bar', + builder: 'webpack5' + }, }); - - export const core = { - builder: 'webpack5' - }; `); }); it('found scalar', () => { @@ -583,12 +582,8 @@ describe('ConfigFile', () => { ).toMatchInlineSnapshot(` import { definePreview } from '@storybook/react-vite/preview'; export const foo = definePreview({ - core: { builder: 'webpack4' }, + core: { builder: 'webpack5' }, }); - - export const core = { - builder: 'webpack5' - }; `); }); });