diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.input.js b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.input.js new file mode 100644 index 000000000000..1c4f5faa706e --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.input.js @@ -0,0 +1,11 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import ComponentRow from './ComponentRow'; +import * as SpecRowStories from './SpecRow.stories'; + +export const { actions } = SpecRowStories; + +storiesOf('ComponentRow', module).add('pending', () => ( + +)); diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.output.snapshot b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.output.snapshot new file mode 100644 index 000000000000..5225069c4651 --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.output.snapshot @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`storiesof-to-csf transforms correctly using "export-destructuring.input.js" data 1`] = ` +"/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import ComponentRow from './ComponentRow'; +import * as SpecRowStories from './SpecRow.stories'; + +export const { actions } = SpecRowStories; + +export default { + title: 'ComponentRow', + excludeStories: ['actions'], +}; + +export const Pending = () => ( + +); + +Pending.story = { + name: 'pending', +};" +`; diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-function.input.js b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-function.input.js new file mode 100644 index 000000000000..94149593ab91 --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-function.input.js @@ -0,0 +1,12 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import ComponentItem from './ComponentItem'; + +export function someHelper() { + return 5; +} + +storiesOf('ComponentItem', module) + .addDecorator(storyFn =>
{storyFn()}
) + .add('loading', () => ); diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-function.output.snapshot b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-function.output.snapshot new file mode 100644 index 000000000000..a190c7cfc9fa --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-function.output.snapshot @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`storiesof-to-csf transforms correctly using "export-function.input.js" data 1`] = ` +"/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import ComponentItem from './ComponentItem'; + +export function someHelper() { + return 5; +} + +export default { + title: 'ComponentItem', + decorators: [storyFn =>
{storyFn()}
], + excludeStories: ['someHelper'], +}; + +export const Loading = () => ; + +Loading.story = { + name: 'loading', +};" +`; diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-names.input.js b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-names.input.js new file mode 100644 index 000000000000..c87d8695b8ee --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-names.input.js @@ -0,0 +1,14 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import FlexCenter from './FlexCenter'; +import { specs, urls } from './LiveView.stories'; +import { ignoredRegions } from './IgnoredRegions.stories'; + +export { specs, urls, ignoredRegions }; + +storiesOf('FlexCenter', module).add('2:1', () => ( + +
2:1
+
+)); diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-names.output.snapshot b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-names.output.snapshot new file mode 100644 index 000000000000..95ddc5056ced --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/export-names.output.snapshot @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`storiesof-to-csf transforms correctly using "export-names.input.js" data 1`] = ` +"/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import FlexCenter from './FlexCenter'; +import { specs, urls } from './LiveView.stories'; +import { ignoredRegions } from './IgnoredRegions.stories'; + +export { specs, urls, ignoredRegions }; + +export default { + title: 'FlexCenter', + excludeStories: ['specs', 'urls', 'ignoredRegions'], +}; + +export const _21 = () => ( + +
2:1
+
+); + +_21.story = { + name: '2:1', +};" +`; diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.input.js b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.input.js new file mode 100644 index 000000000000..6d8dcc497032 --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.input.js @@ -0,0 +1,8 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import Canvas from './Canvas'; + +const CHROMATIC_DELAY = { chromatic: { delay: 500 } }; + +storiesOf('Canvas', module).add('loading', () => , CHROMATIC_DELAY); diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.output.snapshot b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.output.snapshot new file mode 100644 index 000000000000..b0489d3c5f3d --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.output.snapshot @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`storiesof-to-csf transforms correctly using "parameters-as-var.input.js" data 1`] = ` +"/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import Canvas from './Canvas'; + +const CHROMATIC_DELAY = { chromatic: { delay: 500 } }; + +export default { + title: 'Canvas', +}; + +export const Loading = () => ; + +Loading.story = { + name: 'loading', + parameters: CHROMATIC_DELAY, +};" +`; diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.input.js b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.input.js new file mode 100644 index 000000000000..3a66045ea7b9 --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.input.js @@ -0,0 +1,11 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import Hero from './Hero'; + +const chapter = storiesOf('Webapp screens/Marketing/LandingScreen/Hero', module).add( + 'default', + () => +); + +chapter.add('loading', () => ); diff --git a/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.output.snapshot b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.output.snapshot new file mode 100644 index 000000000000..4c0889c9137a --- /dev/null +++ b/lib/codemod/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.output.snapshot @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`storiesof-to-csf transforms correctly using "storiesof-var.input.js" data 1`] = ` +"/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import Hero from './Hero'; + +export default { + title: 'Webapp screens/Marketing/LandingScreen/Hero', +}; + +export const Default = () => ; + +Default.story = { + name: 'default', +}; + +export const Loading = () => ; + +Loading.story = { + name: 'loading', +};" +`; diff --git a/lib/codemod/src/transforms/storiesof-to-csf.js b/lib/codemod/src/transforms/storiesof-to-csf.js index d27842a1a855..482cf6819a73 100644 --- a/lib/codemod/src/transforms/storiesof-to-csf.js +++ b/lib/codemod/src/transforms/storiesof-to-csf.js @@ -32,6 +32,9 @@ export default function transformer(file, api, options) { if (!parameters) { return {}; } + if (!parameters.properties) { + return { storyParams: parameters }; + } let storyDecorators = parameters.properties.find(p => p.key.name === 'decorators'); if (!storyDecorators) { return { storyParams: parameters }; @@ -177,9 +180,11 @@ export default function transformer(file, api, options) { } }); + const stmt = path.parent.node.type === 'VariableDeclarator' ? path.parent.parent : path.parent; + statements.reverse(); - statements.forEach(s => path.parent.insertAfter(s)); - base.remove(); + statements.forEach(s => stmt.insertAfter(s)); + j(stmt).remove(); } // Save the original storiesOf @@ -202,9 +207,26 @@ export default function transformer(file, api, options) { // Exclude all the original named exports const originalExports = []; - root - .find(j.ExportNamedDeclaration) - .forEach(exp => originalExports.push(exp.node.declaration.declarations[0].id.name)); + root.find(j.ExportNamedDeclaration).forEach(exp => { + const { declaration, specifiers } = exp.node; + if (declaration) { + const { id, declarations } = declaration; + if (declarations) { + declarations.forEach(decl => { + const { name, properties } = decl.id; + if (name) { + originalExports.push(name); + } else if (properties) { + properties.forEach(prop => originalExports.push(prop.key.name)); + } + }); + } else if (id) { + originalExports.push(id.name); + } + } else if (specifiers) { + specifiers.forEach(spec => originalExports.push(spec.exported.name)); + } + }); // each top-level add expression corresponds to the last "add" of the chain. // replace it with the entire export statements @@ -212,7 +234,7 @@ export default function transformer(file, api, options) { .find(j.CallExpression) .filter(add => add.node.callee.property && add.node.callee.property.name === 'add') .filter(add => add.node.arguments.length >= 2 && add.node.arguments[0].type === 'Literal') - .filter(add => add.parentPath.node.type === 'ExpressionStatement') + .filter(add => ['ExpressionStatement', 'VariableDeclarator'].includes(add.parentPath.node.type)) .forEach(path => convertToModuleExports(path, originalExports)); // remove storiesOf import