@storybook/codemod 7.0.0-alpha.39 → 7.0.0-alpha.40
Sign up to get free protection for your applications and to get access to all the features.
package/README.md
CHANGED
@@ -240,42 +240,6 @@ import { Meta, Story } from '@storybook/addon-docs';
|
|
240
240
|
</Story>
|
241
241
|
```
|
242
242
|
|
243
|
-
### mdx-to-csf
|
244
|
-
|
245
|
-
This converts all your MDX stories into Component Story Format.
|
246
|
-
|
247
|
-
```sh
|
248
|
-
./node_modules/.bin/jscodeshift -t ./node_modules/@storybook/codemod/dist/transforms/mdx-to-csf.js . --ignore-pattern "node_modules|dist" --extensions=mdx
|
249
|
-
```
|
250
|
-
|
251
|
-
For example:
|
252
|
-
|
253
|
-
```js
|
254
|
-
import React from 'react';
|
255
|
-
import Button from './Button';
|
256
|
-
import { Meta, Story } from '@storybook/addon-docs';
|
257
|
-
|
258
|
-
<Meta title='Button' />
|
259
|
-
|
260
|
-
<Story name='basic stories'><Button label='The Button' /></Story>
|
261
|
-
```
|
262
|
-
|
263
|
-
Becomes:
|
264
|
-
|
265
|
-
```js
|
266
|
-
import React from 'react';
|
267
|
-
import Button from './Button';
|
268
|
-
|
269
|
-
export default {
|
270
|
-
title: 'Button',
|
271
|
-
};
|
272
|
-
|
273
|
-
export const basicStory = () => <Button label="The Button" />;
|
274
|
-
basicStory.story = {
|
275
|
-
name: 'basic stories',
|
276
|
-
};
|
277
|
-
```
|
278
|
-
|
279
243
|
### upgrade-hierarchy-separators
|
280
244
|
|
281
245
|
Starting in 5.3, Storybook is moving to using a single path separator, `/`, to specify the story hierarchy. It previously defaulted to `|` for story "roots" (optional) and either `/` or `.` for denoting paths. This codemod updates the old default to the new default.
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@storybook/codemod",
|
3
|
-
"version": "7.0.0-alpha.
|
3
|
+
"version": "7.0.0-alpha.40",
|
4
4
|
"description": "A collection of codemod scripts written with JSCodeshift",
|
5
5
|
"keywords": [
|
6
6
|
"storybook"
|
@@ -38,10 +38,9 @@
|
|
38
38
|
},
|
39
39
|
"dependencies": {
|
40
40
|
"@babel/types": "^7.12.11",
|
41
|
-
"@mdx-js/mdx": "^1.6.22",
|
42
41
|
"@storybook/csf": "0.0.2--canary.49.258942b.0",
|
43
|
-
"@storybook/csf-tools": "7.0.0-alpha.
|
44
|
-
"@storybook/node-logger": "7.0.0-alpha.
|
42
|
+
"@storybook/csf-tools": "7.0.0-alpha.40",
|
43
|
+
"@storybook/node-logger": "7.0.0-alpha.40",
|
45
44
|
"cross-spawn": "^7.0.3",
|
46
45
|
"globby": "^11.0.2",
|
47
46
|
"jscodeshift": "^0.13.1",
|
@@ -64,5 +63,5 @@
|
|
64
63
|
"./src/index.js"
|
65
64
|
]
|
66
65
|
},
|
67
|
-
"gitHead": "
|
66
|
+
"gitHead": "8f6d8629f1ad7e776c39e2c7621f4a0d538aa93c"
|
68
67
|
}
|
@@ -9,6 +9,9 @@ const inputRegExp = /\.input\.js$/;
|
|
9
9
|
|
10
10
|
const fixturesDir = path.resolve(__dirname, '../__testfixtures__');
|
11
11
|
fs.readdirSync(fixturesDir).forEach((transformName) => {
|
12
|
+
// FIXME: delete after https://github.com/storybookjs/storybook/issues/19497
|
13
|
+
if (transformName === 'mdx-to-csf') return;
|
14
|
+
|
12
15
|
const transformFixturesDir = path.join(fixturesDir, transformName);
|
13
16
|
describe(transformName, () =>
|
14
17
|
fs
|
@@ -1,184 +0,0 @@
|
|
1
|
-
// import recast from 'recast';
|
2
|
-
import mdx from '@mdx-js/mdx';
|
3
|
-
import prettier from 'prettier';
|
4
|
-
import { sanitizeName } from '../lib/utils';
|
5
|
-
|
6
|
-
/**
|
7
|
-
* Convert a component's MDX file into module story format
|
8
|
-
*/
|
9
|
-
export default function transformer(file, api) {
|
10
|
-
const j = api.jscodeshift;
|
11
|
-
const code = mdx.sync(file.source, {});
|
12
|
-
const root = j(code);
|
13
|
-
|
14
|
-
function parseJsxAttributes(attributes) {
|
15
|
-
const result = {};
|
16
|
-
attributes.forEach((attr) => {
|
17
|
-
const key = attr.name.name;
|
18
|
-
const val = attr.value.type === 'JSXExpressionContainer' ? attr.value.expression : attr.value;
|
19
|
-
result[key] = val;
|
20
|
-
});
|
21
|
-
return result;
|
22
|
-
}
|
23
|
-
|
24
|
-
function genObjectExpression(attrs) {
|
25
|
-
return j.objectExpression(
|
26
|
-
Object.entries(attrs).map(([key, val]) => j.property('init', j.identifier(key), val))
|
27
|
-
);
|
28
|
-
}
|
29
|
-
|
30
|
-
function convertToStories(path) {
|
31
|
-
const base = j(path);
|
32
|
-
|
33
|
-
const meta = {};
|
34
|
-
const includeStories = [];
|
35
|
-
const storyStatements = [];
|
36
|
-
|
37
|
-
// get rid of all mdxType junk
|
38
|
-
base
|
39
|
-
.find(j.JSXAttribute)
|
40
|
-
.filter((attr) => attr.node.name.name === 'mdxType')
|
41
|
-
.remove();
|
42
|
-
|
43
|
-
// parse <Meta title="..." />
|
44
|
-
base
|
45
|
-
.find(j.JSXElement)
|
46
|
-
.filter((elt) => elt.node.openingElement.name.name === 'Meta')
|
47
|
-
.forEach((elt) => {
|
48
|
-
const attrs = parseJsxAttributes(elt.node.openingElement.attributes);
|
49
|
-
Object.assign(meta, attrs);
|
50
|
-
});
|
51
|
-
|
52
|
-
// parse <Story name="..." />
|
53
|
-
base
|
54
|
-
.find(j.JSXElement)
|
55
|
-
.filter((elt) => elt.node.openingElement.name.name === 'Story')
|
56
|
-
.forEach((elt) => {
|
57
|
-
const attrs = parseJsxAttributes(elt.node.openingElement.attributes);
|
58
|
-
if (attrs.name) {
|
59
|
-
const storyKey = sanitizeName(attrs.name.value);
|
60
|
-
includeStories.push(storyKey);
|
61
|
-
if (storyKey === attrs.name.value) {
|
62
|
-
delete attrs.name;
|
63
|
-
}
|
64
|
-
let body =
|
65
|
-
elt.node.children.find((n) => n.type !== 'JSXText') ||
|
66
|
-
j.literal(elt.node.children[0].value);
|
67
|
-
|
68
|
-
if (body.type === 'JSXExpressionContainer') {
|
69
|
-
body = body.expression;
|
70
|
-
}
|
71
|
-
|
72
|
-
storyStatements.push(
|
73
|
-
j.exportDeclaration(
|
74
|
-
false,
|
75
|
-
j.variableDeclaration('const', [
|
76
|
-
j.variableDeclarator(
|
77
|
-
j.identifier(storyKey),
|
78
|
-
body.type === 'ArrowFunctionExpression'
|
79
|
-
? body
|
80
|
-
: j.arrowFunctionExpression([], body)
|
81
|
-
),
|
82
|
-
])
|
83
|
-
)
|
84
|
-
);
|
85
|
-
if (Object.keys(attrs).length > 0) {
|
86
|
-
storyStatements.push(
|
87
|
-
j.assignmentStatement(
|
88
|
-
'=',
|
89
|
-
j.memberExpression(j.identifier(storyKey), j.identifier('story')),
|
90
|
-
genObjectExpression(attrs)
|
91
|
-
)
|
92
|
-
);
|
93
|
-
}
|
94
|
-
storyStatements.push(j.emptyStatement());
|
95
|
-
}
|
96
|
-
});
|
97
|
-
|
98
|
-
if (root.find(j.ExportNamedDeclaration).size() > 0) {
|
99
|
-
meta.includeStories = j.arrayExpression(includeStories.map((key) => j.literal(key)));
|
100
|
-
}
|
101
|
-
const statements = [
|
102
|
-
j.exportDefaultDeclaration(genObjectExpression(meta)),
|
103
|
-
j.emptyStatement(),
|
104
|
-
...storyStatements,
|
105
|
-
];
|
106
|
-
|
107
|
-
const lastStatement = root.find(j.Statement).at(-1);
|
108
|
-
statements.reverse().forEach((stmt) => {
|
109
|
-
lastStatement.insertAfter(stmt);
|
110
|
-
});
|
111
|
-
base.remove();
|
112
|
-
}
|
113
|
-
|
114
|
-
root.find(j.ExportDefaultDeclaration).forEach(convertToStories);
|
115
|
-
|
116
|
-
// strip out Story/Meta import and MDX junk
|
117
|
-
|
118
|
-
// /* @jsx mdx */
|
119
|
-
root
|
120
|
-
.find(j.ImportDeclaration)
|
121
|
-
.at(0)
|
122
|
-
.replaceWith((exp) => j.importDeclaration(exp.node.specifiers, exp.node.source));
|
123
|
-
|
124
|
-
// import { Story, Meta } from '@storybook/addon-docs';
|
125
|
-
root
|
126
|
-
.find(j.ImportDeclaration)
|
127
|
-
.filter((exp) => exp.node.source.value === '@storybook/addon-docs')
|
128
|
-
.remove();
|
129
|
-
|
130
|
-
// const makeShortcode = ...
|
131
|
-
// const layoutProps = {};
|
132
|
-
// const MDXLayout = 'wrapper';
|
133
|
-
const MDX_DECLS = ['makeShortcode', 'layoutProps', 'MDXLayout'];
|
134
|
-
root
|
135
|
-
.find(j.VariableDeclaration)
|
136
|
-
.filter(
|
137
|
-
(decl) =>
|
138
|
-
decl.node.declarations.length === 1 && MDX_DECLS.includes(decl.node.declarations[0].id.name)
|
139
|
-
)
|
140
|
-
.remove();
|
141
|
-
|
142
|
-
// const Source = makeShortcode('Source');
|
143
|
-
root
|
144
|
-
.find(j.VariableDeclarator)
|
145
|
-
.filter(
|
146
|
-
(expr) =>
|
147
|
-
expr.node.init.type === 'CallExpression' &&
|
148
|
-
expr.node.init.callee.type === 'Identifier' &&
|
149
|
-
expr.node.init.callee.name === 'makeShortcode'
|
150
|
-
)
|
151
|
-
.remove();
|
152
|
-
|
153
|
-
// MDXContent.isMDXComponent = true;
|
154
|
-
root
|
155
|
-
.find(j.AssignmentExpression)
|
156
|
-
.filter(
|
157
|
-
(expr) =>
|
158
|
-
expr.node.left.type === 'MemberExpression' &&
|
159
|
-
expr.node.left.object.type === 'Identifier' &&
|
160
|
-
expr.node.left.object.name === 'MDXContent'
|
161
|
-
)
|
162
|
-
.remove();
|
163
|
-
|
164
|
-
// Add back `import React from 'react';` which is implicit in MDX
|
165
|
-
const react = root.find(j.ImportDeclaration).filter((decl) => decl.node.source.value === 'react');
|
166
|
-
if (react.size() === 0) {
|
167
|
-
root
|
168
|
-
.find(j.Statement)
|
169
|
-
.at(0)
|
170
|
-
.insertBefore(
|
171
|
-
j.importDeclaration([j.importDefaultSpecifier(j.identifier('React'))], j.literal('react'))
|
172
|
-
);
|
173
|
-
}
|
174
|
-
|
175
|
-
const source = root.toSource({ trailingComma: true, quote: 'single', tabWidth: 2 });
|
176
|
-
return prettier.format(source, {
|
177
|
-
parser: 'babel',
|
178
|
-
printWidth: 100,
|
179
|
-
tabWidth: 2,
|
180
|
-
bracketSpacing: true,
|
181
|
-
trailingComma: 'es5',
|
182
|
-
singleQuote: true,
|
183
|
-
});
|
184
|
-
}
|