Skip to content

Commit

Permalink
Codemod: Convert module format to MDX (#7418)
Browse files Browse the repository at this point in the history
Codemod: Convert module format to MDX
  • Loading branch information
shilman committed Jul 15, 2019
2 parents 728c099 + 07eeedb commit c33c4c2
Show file tree
Hide file tree
Showing 31 changed files with 424 additions and 5 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Expand Up @@ -7,6 +7,7 @@ docs/public
storybook-static
built-storybooks
lib/cli/test
lib/codemod/src/transforms/__testfixtures__
scripts/storage
*.bundle.js
*.js.map
Expand Down
47 changes: 43 additions & 4 deletions lib/codemod/README.md
Expand Up @@ -151,12 +151,14 @@ Heuristics:
- The storiesOf "kind" name must be Button
- Button must be imported in the file

### convert-to-module-format
### convert-storiesof-to-module

This converts all of your "old-style" `storiesOf` stories into component module format, which uses standard ES6 modules.

> NOTE: The output of this transformation may require manual editing after running the transformation. `storiesOf` format allows multiple "kinds" (components) to be declared per file, but module format only allows a single component per file. Therefore, if you use this feature in your input stories, you will need to split up the resulting outputs by hand. You'll see a warning at the console if you need to hand edit.
```sh
./node_modules/.bin/jscodeshift -t ./node_modules/@storybook/codemod/dist/transforms/convert-to-module-format.js . --ignore-pattern "node_modules|dist"
./node_modules/.bin/jscodeshift -t ./node_modules/@storybook/codemod/dist/transforms/convert-storiesof-to-module.js . --ignore-pattern "node_modules|dist"
```

For example:
Expand All @@ -183,18 +185,55 @@ export default {
export const story = () => <Button label="Story 1" />;

export const story2 = () => <Button label="Story 2" onClick={action('click')} />;
story2.title = 'second story';
story2.story = { name: 'second story' };

export const story3 = () => (
<div>
<Button label="The Button" onClick={action('onClick')} />
<br />
</div>
);
story3.title = 'complex story';
story3.story = { name: 'complex story' };
```

Heuristics:

- If a file has any default export, it will be skipped
- If a file has multiple `storiesOf` declarations, it will convert each one seperately. This generates invalid ES6, but you can edit the file by hand to split it into multiple files (or whatever is appropriate).

### convert-module-to-mdx

This converts all of your component module stories into MDX format, which integrates story examples and long-form documentation.

> NOTE: The output of this transformation may require manual editing after running the transformation. MDX is finnicky about the top-level statements it allows. For example, [variables should be defined with exports](https://mdxjs.com/getting-started/#defining-variables-with-exports), meaning `const foo = 5;` should be rewritten as `export const foo = 5;`. We don't do this transformation automatically, since you may prefer to refactor your stories.
```sh
./node_modules/.bin/jscodeshift -t ./node_modules/@storybook/codemod/dist/transforms/convert-to-module-format.js . --ignore-pattern "node_modules|dist"
```

```js
export default {
title: 'Button',
};

export const story = () => <Button label="Story 1" />;

export const story2 = () => <Button label="Story 2" onClick={action('click')} />;
story2.story = { name: 'second story' };
```

Becomes:

```md
import { Meta, Story } from '@storybook/addon-docs/blocks';

# Button

<Meta title='Button'>

<Story name='story'><Button label="Story 1" /></Story>

<Story name='second story'>
<Button label="Story 2" onClick={action('click')} />
</Story>
```
1 change: 1 addition & 0 deletions lib/codemod/package.json
Expand Up @@ -28,6 +28,7 @@
"jscodeshift": "^0.6.3",
"lodash": "^4.17.11",
"prettier": "^1.16.4",
"recast": "^0.16.1",
"regenerator-runtime": "^0.12.1"
},
"publishConfig": {
Expand Down
@@ -0,0 +1,20 @@
import React from 'react';
import Button from './Button';
import { action } from '@storybook/addon-actions';

export default {
title: 'Button',
};

export const story1 = () => <Button label="Story 1" />;

export const story2 = () => <Button label="Story 2" onClick={action('click')} />;
story2.story = { name: 'second story' };

export const story3 = () => (
<div>
<Button label="The Button" onClick={action('onClick')} />
<br />
</div>
);
story3.story = { name: 'complex story' };
@@ -0,0 +1,15 @@
import React from 'react';
import Button from './Button';
import { action } from '@storybook/addon-actions';
import { Meta, Story } from '@storybook/addon-docs/blocks';

<Meta title='Button' />

<Story name='story1'><Button label='Story 1' /></Story>

<Story name='second story'><Button label='Story 2' onClick={action('click')} /></Story>

<Story name='complex story'><div>
<Button label='The Button' onClick={action('onClick')} />
<br />
</div></Story>
@@ -0,0 +1,10 @@
import React from 'react';
import Button from './Button';

export default {
title: 'Some.Button',
decorators: [withKnobs, storyFn => <div className="foo">{storyFn}</div>],
};

export const story1 = () => <Button label="The Button" />;
story1.story = { name: 'with decorator' };
@@ -0,0 +1,9 @@
import React from 'react';
import Button from './Button';
import { Meta, Story } from '@storybook/addon-docs/blocks';

<Meta
title='Some.Button'
decorators={[withKnobs, storyFn => <div className='foo'>{storyFn}</div>]} />

<Story name='with decorator'><Button label='The Button' /></Story>
@@ -0,0 +1,23 @@
import React from 'react';
import Button from './Button';
import { action } from '@storybook/addon-actions';

export default {
title: 'Button',
excludeStories: /.*Data$/,
};

export const rowData = { col1: 'a', col2: 2 };

export const story1 = () => <Button label="Story 1" />;

export const story2 = () => <Button label="Story 2" onClick={action('click')} />;
story2.story = { name: 'second story' };

export const story3 = () => (
<div>
<Button label="The Button" onClick={action('onClick')} />
<br />
</div>
);
story3.story = { name: 'complex story' };
@@ -0,0 +1,19 @@
import React from 'react';
import Button from './Button';
import { action } from '@storybook/addon-actions';
import { Meta, Story } from '@storybook/addon-docs/blocks';

<Meta title='Button' />

export const rowData = {
col1: 'a',
col2: 2,
};
<Story name='story1'><Button label='Story 1' /></Story>

<Story name='second story'><Button label='Story 2' onClick={action('click')} /></Story>

<Story name='complex story'><div>
<Button label='The Button' onClick={action('onClick')} />
<br />
</div></Story>
@@ -0,0 +1,17 @@
import React from 'react';
import Button from './Button';

import { storiesOf } from '@storybook/react';

export default {
title: 'Button',

parameters: {
component: Button,
foo: 1,
bar: 2,
},
};

export const story1 = () => <Button label="The Button" />;
story1.story = { name: 'with kind parameters' };
@@ -0,0 +1,14 @@
import React from 'react';
import Button from './Button';
import { storiesOf } from '@storybook/react';
import { Meta, Story } from '@storybook/addon-docs/blocks';

<Meta
title='Button'
parameters={{
component: Button,
foo: 1,
bar: 2,
}} />

<Story name='with kind parameters'><Button label='The Button' /></Story>
@@ -0,0 +1,24 @@
import React from 'react';
import Button from './Button';

import { storiesOf } from '@storybook/react';

export default {
title: 'Button',
};

export const story1 = () => <Button label="The Button" />;
story1.story = {
name: 'with story parameters',
parameters: {
header: false,
inline: true,
},
};

export const foo = () => <Button label="Foo" />;
foo.story = {
parameters: {
bar: 1,
},
};
@@ -0,0 +1,19 @@
import React from 'react';
import Button from './Button';
import { storiesOf } from '@storybook/react';
import { Meta, Story } from '@storybook/addon-docs/blocks';

<Meta title='Button' />

<Story
name='with story parameters'
parameters={{
header: false,
inline: true,
}}><Button label='The Button' /></Story>

<Story
name='foo'
parameters={{
bar: 1,
}}><Button label='Foo' /></Story>
@@ -0,0 +1,7 @@
import { defineTest } from 'jscodeshift/dist/testUtils';

const testNames = ['basic', 'decorators', 'parameters', 'story-parameters', 'exclude-stories'];

testNames.forEach(testName => {
defineTest(__dirname, `convert-module-to-mdx`, null, `convert-module-to-mdx/${testName}`);
});
Expand Up @@ -13,5 +13,10 @@ const testNames = [
];

testNames.forEach(testName => {
defineTest(__dirname, `convert-to-module-format`, null, `convert-to-module-format/${testName}`);
defineTest(
__dirname,
`convert-storiesof-to-module`,
null,
`convert-storiesof-to-module/${testName}`
);
});

1 comment on commit c33c4c2

@vercel
Copy link

@vercel vercel bot commented on c33c4c2 Jul 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.