@storybook/codemod 7.0.0-alpha.7 → 7.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +0 -36
  2. package/dist/index.d.ts +261 -0
  3. package/dist/index.js +1 -0
  4. package/dist/index.mjs +1 -0
  5. package/jest.config.js +7 -0
  6. package/package.json +32 -29
  7. package/src/index.js +77 -0
  8. package/src/lib/utils.test.js +9 -0
  9. package/{dist/esm/lib/utils.js → src/lib/utils.ts} +10 -11
  10. package/src/transforms/__testfixtures__/add-component-parameters/add-component-parameters.input.js +44 -0
  11. package/src/transforms/__testfixtures__/add-component-parameters/add-component-parameters.output.snapshot +68 -0
  12. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/basic.input.js +25 -0
  13. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/basic.output.snapshot +27 -0
  14. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/overrides.input.js +25 -0
  15. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/overrides.output.snapshot +28 -0
  16. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/variable.input.js +13 -0
  17. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/variable.output.snapshot +17 -0
  18. package/src/transforms/__testfixtures__/csf-to-mdx/basic.input.js +20 -0
  19. package/src/transforms/__testfixtures__/csf-to-mdx/basic.output.snapshot +18 -0
  20. package/src/transforms/__testfixtures__/csf-to-mdx/component-id.input.js +9 -0
  21. package/src/transforms/__testfixtures__/csf-to-mdx/component-id.output.snapshot +10 -0
  22. package/src/transforms/__testfixtures__/csf-to-mdx/decorators.input.js +13 -0
  23. package/src/transforms/__testfixtures__/csf-to-mdx/decorators.output.snapshot +12 -0
  24. package/src/transforms/__testfixtures__/csf-to-mdx/exclude-stories.input.js +23 -0
  25. package/src/transforms/__testfixtures__/csf-to-mdx/exclude-stories.output.snapshot +22 -0
  26. package/src/transforms/__testfixtures__/csf-to-mdx/parameters.input.js +16 -0
  27. package/src/transforms/__testfixtures__/csf-to-mdx/parameters.output.snapshot +17 -0
  28. package/src/transforms/__testfixtures__/csf-to-mdx/story-function.input.js +19 -0
  29. package/src/transforms/__testfixtures__/csf-to-mdx/story-function.output.snapshot +18 -0
  30. package/src/transforms/__testfixtures__/csf-to-mdx/story-parameters.input.js +24 -0
  31. package/src/transforms/__testfixtures__/csf-to-mdx/story-parameters.output.snapshot +22 -0
  32. package/src/transforms/__testfixtures__/mdx-to-csf/basic.input.js +18 -0
  33. package/src/transforms/__testfixtures__/mdx-to-csf/basic.output.snapshot +40 -0
  34. package/src/transforms/__testfixtures__/mdx-to-csf/component-id.input.js +6 -0
  35. package/src/transforms/__testfixtures__/mdx-to-csf/component-id.output.snapshot +17 -0
  36. package/src/transforms/__testfixtures__/mdx-to-csf/decorators.input.js +8 -0
  37. package/src/transforms/__testfixtures__/mdx-to-csf/decorators.output.snapshot +18 -0
  38. package/src/transforms/__testfixtures__/mdx-to-csf/exclude-stories.input.js +19 -0
  39. package/src/transforms/__testfixtures__/mdx-to-csf/exclude-stories.output.snapshot +39 -0
  40. package/src/transforms/__testfixtures__/mdx-to-csf/parameters.input.js +14 -0
  41. package/src/transforms/__testfixtures__/mdx-to-csf/parameters.output.snapshot +23 -0
  42. package/src/transforms/__testfixtures__/mdx-to-csf/plaintext.input.js +3 -0
  43. package/src/transforms/__testfixtures__/mdx-to-csf/plaintext.output.snapshot +11 -0
  44. package/src/transforms/__testfixtures__/mdx-to-csf/story-function.input.js +10 -0
  45. package/src/transforms/__testfixtures__/mdx-to-csf/story-function.output.snapshot +18 -0
  46. package/src/transforms/__testfixtures__/mdx-to-csf/story-parameters.input.js +18 -0
  47. package/src/transforms/__testfixtures__/mdx-to-csf/story-parameters.output.snapshot +32 -0
  48. package/src/transforms/__testfixtures__/mdx-to-csf/story-refs.input.js +22 -0
  49. package/src/transforms/__testfixtures__/mdx-to-csf/story-refs.output.snapshot +34 -0
  50. package/src/transforms/__testfixtures__/move-builtin-addons/default.input.js +2 -0
  51. package/src/transforms/__testfixtures__/move-builtin-addons/default.output.snapshot +8 -0
  52. package/src/transforms/__testfixtures__/move-builtin-addons/with-no-change.input.js +3 -0
  53. package/src/transforms/__testfixtures__/move-builtin-addons/with-no-change.output.snapshot +7 -0
  54. package/src/transforms/__testfixtures__/storiesof-to-csf/basic.input.js +18 -0
  55. package/src/transforms/__testfixtures__/storiesof-to-csf/basic.output.snapshot +45 -0
  56. package/src/transforms/__testfixtures__/storiesof-to-csf/collision.input.js +11 -0
  57. package/src/transforms/__testfixtures__/storiesof-to-csf/collision.output.snapshot +38 -0
  58. package/src/transforms/__testfixtures__/storiesof-to-csf/const.input.js +1 -0
  59. package/src/transforms/__testfixtures__/storiesof-to-csf/const.output.snapshot +13 -0
  60. package/src/transforms/__testfixtures__/storiesof-to-csf/decorators.input.js +9 -0
  61. package/src/transforms/__testfixtures__/storiesof-to-csf/decorators.output.snapshot +18 -0
  62. package/src/transforms/__testfixtures__/storiesof-to-csf/default.input.js +7 -0
  63. package/src/transforms/__testfixtures__/storiesof-to-csf/default.output.snapshot +17 -0
  64. package/src/transforms/__testfixtures__/storiesof-to-csf/digit.input.js +1 -0
  65. package/src/transforms/__testfixtures__/storiesof-to-csf/digit.output.js +5 -0
  66. package/src/transforms/__testfixtures__/storiesof-to-csf/digit.output.snapshot +9 -0
  67. package/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.input.js +11 -0
  68. package/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.output.snapshot +23 -0
  69. package/src/transforms/__testfixtures__/storiesof-to-csf/export-function.input.js +12 -0
  70. package/src/transforms/__testfixtures__/storiesof-to-csf/export-function.output.snapshot +23 -0
  71. package/src/transforms/__testfixtures__/storiesof-to-csf/export-names.input.js +14 -0
  72. package/src/transforms/__testfixtures__/storiesof-to-csf/export-names.output.snapshot +26 -0
  73. package/src/transforms/__testfixtures__/storiesof-to-csf/exports.input.js +2 -0
  74. package/src/transforms/__testfixtures__/storiesof-to-csf/exports.output.snapshot +16 -0
  75. package/src/transforms/__testfixtures__/storiesof-to-csf/module.input.js +12 -0
  76. package/src/transforms/__testfixtures__/storiesof-to-csf/module.output.snapshot +16 -0
  77. package/src/transforms/__testfixtures__/storiesof-to-csf/multi.input.js +14 -0
  78. package/src/transforms/__testfixtures__/storiesof-to-csf/multi.output.snapshot +39 -0
  79. package/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.input.js +8 -0
  80. package/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.output.snapshot +20 -0
  81. package/src/transforms/__testfixtures__/storiesof-to-csf/parameters.input.js +10 -0
  82. package/src/transforms/__testfixtures__/storiesof-to-csf/parameters.output.snapshot +23 -0
  83. package/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.input.js +11 -0
  84. package/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.output.snapshot +23 -0
  85. package/src/transforms/__testfixtures__/storiesof-to-csf/story-decorators.input.js +11 -0
  86. package/src/transforms/__testfixtures__/storiesof-to-csf/story-decorators.output.snapshot +29 -0
  87. package/src/transforms/__testfixtures__/storiesof-to-csf/story-parameters.input.js +14 -0
  88. package/src/transforms/__testfixtures__/storiesof-to-csf/story-parameters.output.snapshot +32 -0
  89. package/src/transforms/__testfixtures__/update-addon-info/update-addon-info.input.js +198 -0
  90. package/src/transforms/__testfixtures__/update-addon-info/update-addon-info.output.snapshot +198 -0
  91. package/src/transforms/__testfixtures__/update-organisation-name/update-organisation-name.input.js +19 -0
  92. package/src/transforms/__testfixtures__/update-organisation-name/update-organisation-name.output.snapshot +23 -0
  93. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/csf.input.js +3 -0
  94. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/csf.output.snapshot +7 -0
  95. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/dynamic-storiesof.input.js +5 -0
  96. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/dynamic-storiesof.output.snapshot +9 -0
  97. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/storiesof.input.js +8 -0
  98. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/storiesof.output.snapshot +12 -0
  99. package/src/transforms/__tests__/csf-2-to-3.test.ts +250 -0
  100. package/src/transforms/__tests__/transforms.tests.js +32 -0
  101. package/{dist/esm → src}/transforms/add-component-parameters.js +26 -21
  102. package/src/transforms/csf-2-to-3.ts +184 -0
  103. package/src/transforms/csf-hoist-story-annotations.js +97 -0
  104. package/src/transforms/csf-to-mdx.js +190 -0
  105. package/src/transforms/move-builtin-addons.js +32 -0
  106. package/src/transforms/storiesof-to-csf.js +277 -0
  107. package/{dist/esm → src}/transforms/update-addon-info.js +44 -24
  108. package/{dist/esm → src}/transforms/update-organisation-name.js +21 -24
  109. package/src/transforms/upgrade-hierarchy-separators.js +39 -0
  110. package/tsconfig.json +7 -0
  111. package/LICENSE +0 -21
  112. package/dist/cjs/index.js +0 -142
  113. package/dist/cjs/lib/utils.js +0 -45
  114. package/dist/cjs/transforms/add-component-parameters.js +0 -64
  115. package/dist/cjs/transforms/csf-2-to-3.js +0 -180
  116. package/dist/cjs/transforms/csf-hoist-story-annotations.js +0 -93
  117. package/dist/cjs/transforms/csf-to-mdx.js +0 -196
  118. package/dist/cjs/transforms/mdx-to-csf.js +0 -153
  119. package/dist/cjs/transforms/move-builtin-addons.js +0 -57
  120. package/dist/cjs/transforms/storiesof-to-csf.js +0 -300
  121. package/dist/cjs/transforms/update-addon-info.js +0 -101
  122. package/dist/cjs/transforms/update-organisation-name.js +0 -83
  123. package/dist/cjs/transforms/upgrade-hierarchy-separators.js +0 -42
  124. package/dist/esm/index.js +0 -99
  125. package/dist/esm/transforms/csf-2-to-3.js +0 -163
  126. package/dist/esm/transforms/csf-hoist-story-annotations.js +0 -86
  127. package/dist/esm/transforms/csf-to-mdx.js +0 -188
  128. package/dist/esm/transforms/mdx-to-csf.js +0 -139
  129. package/dist/esm/transforms/move-builtin-addons.js +0 -50
  130. package/dist/esm/transforms/storiesof-to-csf.js +0 -287
  131. package/dist/esm/transforms/upgrade-hierarchy-separators.js +0 -35
  132. package/dist/types/lib/utils.d.ts +0 -2
  133. package/dist/types/transforms/csf-2-to-3.d.ts +0 -6
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.
@@ -0,0 +1,261 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { promisify } from 'util';
4
+ import globby from 'globby';
5
+ import { sync } from 'cross-spawn';
6
+
7
+ declare function jscodeshiftToPrettierParser(parser?: string): string;
8
+
9
+ const packageNames = {
10
+ '@kadira/react-storybook-decorator-centered': '@storybook/addon-centered',
11
+ '@kadira/storybook-addons': '@storybook/preview-api',
12
+ '@kadira/storybook-addon-actions': '@storybook/addon-actions',
13
+ '@kadira/storybook-addon-comments': '@storybook/addon-comments',
14
+ '@kadira/storybook-addon-graphql': '@storybook/addon-graphql',
15
+ '@kadira/storybook-addon-info': '@storybook/addon-info',
16
+ '@kadira/storybook-addon-knobs': '@storybook/addon-knobs',
17
+ '@kadira/storybook-addon-links': '@storybook/addon-links',
18
+ '@kadira/storybook-addon-notes': '@storybook/addon-notes',
19
+ '@kadira/storybook-addon-options': '@storybook/addon-options',
20
+ '@kadira/storybook-channels': '@storybook/channels',
21
+ '@kadira/storybook-channel-postmsg': '@storybook/channel-postmessage',
22
+ '@kadira/storybook-channel-websocket': '@storybook/channel-websocket',
23
+ '@kadira/storybook-ui': '@storybook/manager',
24
+ '@kadira/react-native-storybook': '@storybook/react-native',
25
+ '@kadira/react-storybook': '@storybook/react',
26
+ '@kadira/getstorybook': '@storybook/cli',
27
+ '@kadira/storybook': '@storybook/react',
28
+ storyshots: '@storybook/addon-storyshots',
29
+ getstorybook: '@storybook/cli',
30
+ };
31
+
32
+ function transformer$1(file, api) {
33
+ const j = api.jscodeshift;
34
+
35
+ const packageNamesKeys = Object.keys(packageNames);
36
+
37
+ /**
38
+ * Checks whether the node value matches a Storybook package
39
+ * @param {string} the import declaration node
40
+ * @returns {string} whether the node value matches a Storybook package
41
+ */
42
+ const getMatch = (oldpart) => packageNamesKeys.find((newpart) => oldpart.match(newpart));
43
+
44
+ /**
45
+ * Returns the name of the Storybook packages with the organisation name,
46
+ * replacing the old `@kadira/` prefix.
47
+ * @param {string} oldPackageName the name of the old package
48
+ * @return {string} the new package name
49
+ * @example
50
+ * // returns '@storybook/storybook'
51
+ * getNewPackageName('@kadira/storybook')
52
+ */
53
+ const getNewPackageName = (oldPackageName) => {
54
+ const match = getMatch(oldPackageName);
55
+
56
+ if (match) {
57
+ const replacement = packageNames[match];
58
+ return oldPackageName.replace(match, replacement);
59
+ }
60
+ return oldPackageName;
61
+ };
62
+
63
+ /**
64
+ * updatePackageName - updates the source name of the Storybook packages
65
+ * @param {ImportDeclaration} declaration the import declaration
66
+ * @returns {ImportDeclaration.Node} the import declaration node
67
+ */
68
+ const updatePackageName = (declaration) => {
69
+ // eslint-disable-next-line no-param-reassign
70
+ declaration.node.source.value = getNewPackageName(declaration.node.source.value);
71
+
72
+ return declaration.node;
73
+ };
74
+
75
+ return j(file.source)
76
+ .find(j.ImportDeclaration)
77
+ .replaceWith(updatePackageName)
78
+ .toSource({ quote: 'single' });
79
+ }
80
+
81
+ /**
82
+ * Takes the deprecated addon-info API, addWithInfo, and
83
+ * converts to the new withInfo API.
84
+ *
85
+ * Example of deprecated addWithInfo API:
86
+ *
87
+ * storiesOf('Button')
88
+ * .addWithInfo(
89
+ * 'story name',
90
+ * 'Story description.',
91
+ * () => (
92
+ * <Button label="The Button" />
93
+ * )
94
+ * )
95
+ *
96
+ * Converts to the new withInfo API:
97
+ *
98
+ * storiesOf('Button')
99
+ * .add('story name', withInfo(
100
+ * 'Story description.'
101
+ * )(() => (
102
+ * <Button label="The Button" />
103
+ * )))
104
+ */
105
+ function transformer(file, api) {
106
+ const j = api.jscodeshift;
107
+ const root = j(file.source);
108
+
109
+ /**
110
+ * Returns a list of parameters for the withInfo function. The contents
111
+ * of this list is either the second argument from the original
112
+ * addWithInfo function, if no additional options were used, or a
113
+ * combined object of all the options from the original function.
114
+ * @param {list} args - original addWithInfo function parameters
115
+ * @return {list} the modified list of parameters for the new function
116
+ */
117
+ const getOptions = (args) => {
118
+ if (args[3] === undefined) {
119
+ if (args[2] === undefined) {
120
+ // when the optional description string is not supplied for addWithInfo, use story name
121
+ return [args[0]];
122
+ }
123
+ return [args[1]];
124
+ }
125
+ return [
126
+ j.objectExpression([
127
+ j.property('init', j.identifier('text'), args[1]),
128
+ ...args[3].properties,
129
+ ]),
130
+ ];
131
+ };
132
+
133
+ /**
134
+ * Constructs the new withInfo function from the parameters of the
135
+ * original addWithInfo function.
136
+ * @param {CallExpression} addWithInfoExpression - original function
137
+ * @returns {CallExpression} the new withInfo function
138
+ */
139
+ const withInfo = (addWithInfoExpression) => {
140
+ const { node } = addWithInfoExpression;
141
+ const args = node.arguments;
142
+
143
+ // if optional description string is not supplied, the story component becomes second arg
144
+ const storyComponent = args[2] ? args[2] : args[1];
145
+
146
+ node.callee.property.name = 'add';
147
+ node.arguments = [
148
+ args[0],
149
+ j.callExpression(j.callExpression(j.identifier('withInfo'), getOptions(args)), [
150
+ storyComponent,
151
+ ]),
152
+ ];
153
+
154
+ return node;
155
+ };
156
+
157
+ /**
158
+ * Checks for - import { withInfo } from "@storybook/addon-info";
159
+ * Adds the import if necessary.
160
+ */
161
+ const checkWithInfoImport = () => {
162
+ const importExists = root
163
+ .find(j.ImportDeclaration)
164
+ .filter((imp) => imp.node.source.value === '@storybook/addon-info')
165
+ .size();
166
+
167
+ if (importExists) return;
168
+
169
+ root
170
+ .find(j.ImportDeclaration)
171
+ .at(-1)
172
+ .insertAfter(
173
+ j.importDeclaration(
174
+ [j.importSpecifier(j.identifier('withInfo'))],
175
+ j.literal('@storybook/addon-info')
176
+ )
177
+ );
178
+ };
179
+
180
+ const addWithInfoExpressions = root.find(j.CallExpression, {
181
+ callee: {
182
+ property: {
183
+ name: 'addWithInfo',
184
+ },
185
+ },
186
+ });
187
+
188
+ if (addWithInfoExpressions.size()) {
189
+ checkWithInfoImport();
190
+ addWithInfoExpressions.replaceWith(withInfo);
191
+ }
192
+
193
+ return root.toSource();
194
+ }
195
+
196
+ /* eslint import/prefer-default-export: "off" */
197
+
198
+ const TRANSFORM_DIR = `${__dirname}/transforms`;
199
+
200
+ function listCodemods() {
201
+ return fs
202
+ .readdirSync(TRANSFORM_DIR)
203
+ .filter((fname) => fname.endsWith('.js'))
204
+ .map((fname) => fname.slice(0, -3));
205
+ }
206
+
207
+ const renameAsync = promisify(fs.rename);
208
+
209
+ async function renameFile(file, from, to, { logger }) {
210
+ const newFile = file.replace(from, to);
211
+ logger.log(`Rename: ${file} ${newFile}`);
212
+ return renameAsync(file, newFile);
213
+ }
214
+
215
+ async function runCodemod(codemod, { glob, logger, dryRun, rename, parser }) {
216
+ const codemods = listCodemods();
217
+ if (!codemods.includes(codemod)) {
218
+ throw new Error(`Unknown codemod ${codemod}. Run --list for options.`);
219
+ }
220
+
221
+ let renameParts = null;
222
+ if (rename) {
223
+ renameParts = rename.split(':');
224
+ if (renameParts.length !== 2) {
225
+ throw new Error(`Codemod rename: expected format "from:to", got "${rename}"`);
226
+ }
227
+ }
228
+
229
+ // jscodeshift/prettier know how to handle .ts/.tsx extensions,
230
+ // so if the user uses one of those globs, we can auto-infer
231
+ let inferredParser = parser;
232
+ if (!parser) {
233
+ const extension = path.extname(glob).slice(1);
234
+ const knownParser = jscodeshiftToPrettierParser(extension);
235
+ if (knownParser !== 'babel') inferredParser = extension;
236
+ }
237
+
238
+ const files = await globby([glob, '!**/node_modules', '!**/dist']);
239
+ logger.log(`=> Applying ${codemod}: ${files.length} files`);
240
+ if (!dryRun) {
241
+ const parserArgs = inferredParser ? ['--parser', inferredParser] : [];
242
+ sync(
243
+ 'npx',
244
+ ['jscodeshift', '-t', `${TRANSFORM_DIR}/${codemod}.js`, ...parserArgs, ...files],
245
+ {
246
+ stdio: 'inherit',
247
+ shell: true,
248
+ }
249
+ );
250
+ }
251
+
252
+ if (renameParts) {
253
+ const [from, to] = renameParts;
254
+ logger.log(`=> Renaming ${rename}: ${files.length} files`);
255
+ await Promise.all(
256
+ files.map((file) => renameFile(file, new RegExp(`${from}$`), to, { logger }))
257
+ );
258
+ }
259
+ }
260
+
261
+ export { listCodemods, packageNames, runCodemod, transformer as updateAddonInfo, transformer$1 as updateOrganisationName };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ var R=Object.create;var l=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var A=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var S=(o,r)=>{for(var t in r)l(o,t,{get:r[t],enumerable:!0})},h=(o,r,t,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of v(r))!C.call(o,n)&&n!==t&&l(o,n,{get:()=>r[n],enumerable:!(a=N(r,n))||a.enumerable});return o};var p=(o,r,t)=>(t=o!=null?R(A(o)):{},h(r||!o||!o.__esModule?l(t,"default",{value:o,enumerable:!0}):t,o)),W=o=>h(l({},"__esModule",{value:!0}),o);var z={};S(z,{listCodemods:()=>E,packageNames:()=>m,runCodemod:()=>q,updateAddonInfo:()=>b,updateOrganisationName:()=>y});module.exports=W(z);var u=p(require("fs")),x=p(require("path")),w=require("util"),$=p(require("globby")),I=require("cross-spawn");var _=p(require("lodash/camelCase")),D=p(require("lodash/upperFirst"));function g(o){let r={babylon:"babel",flow:"flow",ts:"typescript",tsx:"typescript"};return o&&r[o]||"babel"}var m={"@kadira/react-storybook-decorator-centered":"@storybook/addon-centered","@kadira/storybook-addons":"@storybook/preview-api","@kadira/storybook-addon-actions":"@storybook/addon-actions","@kadira/storybook-addon-comments":"@storybook/addon-comments","@kadira/storybook-addon-graphql":"@storybook/addon-graphql","@kadira/storybook-addon-info":"@storybook/addon-info","@kadira/storybook-addon-knobs":"@storybook/addon-knobs","@kadira/storybook-addon-links":"@storybook/addon-links","@kadira/storybook-addon-notes":"@storybook/addon-notes","@kadira/storybook-addon-options":"@storybook/addon-options","@kadira/storybook-channels":"@storybook/channels","@kadira/storybook-channel-postmsg":"@storybook/channel-postmessage","@kadira/storybook-channel-websocket":"@storybook/channel-websocket","@kadira/storybook-ui":"@storybook/manager","@kadira/react-native-storybook":"@storybook/react-native","@kadira/react-storybook":"@storybook/react","@kadira/getstorybook":"@storybook/cli","@kadira/storybook":"@storybook/react",storyshots:"@storybook/addon-storyshots",getstorybook:"@storybook/cli"};function y(o,r){let t=r.jscodeshift,a=Object.keys(m),n=s=>a.find(e=>s.match(e)),c=s=>{let e=n(s);if(e){let i=m[e];return s.replace(e,i)}return s},f=s=>(s.node.source.value=c(s.node.source.value),s.node);return t(o.source).find(t.ImportDeclaration).replaceWith(f).toSource({quote:"single"})}function b(o,r){let t=r.jscodeshift,a=t(o.source),n=e=>e[3]===void 0?e[2]===void 0?[e[0]]:[e[1]]:[t.objectExpression([t.property("init",t.identifier("text"),e[1]),...e[3].properties])],c=e=>{let{node:i}=e,d=i.arguments,k=d[2]?d[2]:d[1];return i.callee.property.name="add",i.arguments=[d[0],t.callExpression(t.callExpression(t.identifier("withInfo"),n(d)),[k])],i},f=()=>{a.find(t.ImportDeclaration).filter(i=>i.node.source.value==="@storybook/addon-info").size()||a.find(t.ImportDeclaration).at(-1).insertAfter(t.importDeclaration([t.importSpecifier(t.identifier("withInfo"))],t.literal("@storybook/addon-info")))},s=a.find(t.CallExpression,{callee:{property:{name:"addWithInfo"}}});return s.size()&&(f(),s.replaceWith(c)),a.toSource()}var j=`${__dirname}/transforms`;function E(){return u.default.readdirSync(j).filter(o=>o.endsWith(".js")).map(o=>o.slice(0,-3))}var F=(0,w.promisify)(u.default.rename);async function O(o,r,t,{logger:a}){let n=o.replace(r,t);return a.log(`Rename: ${o} ${n}`),F(o,n)}async function q(o,{glob:r,logger:t,dryRun:a,rename:n,parser:c}){if(!E().includes(o))throw new Error(`Unknown codemod ${o}. Run --list for options.`);let s=null;if(n&&(s=n.split(":"),s.length!==2))throw new Error(`Codemod rename: expected format "from:to", got "${n}"`);let e=c;if(!c){let d=x.default.extname(r).slice(1);g(d)!=="babel"&&(e=d)}let i=await(0,$.default)([r,"!**/node_modules","!**/dist"]);if(t.log(`=> Applying ${o}: ${i.length} files`),!a){let d=e?["--parser",e]:[];(0,I.sync)("npx",["jscodeshift","-t",`${j}/${o}.js`,...d,...i],{stdio:"inherit",shell:!0})}if(s){let[d,k]=s;t.log(`=> Renaming ${n}: ${i.length} files`),await Promise.all(i.map(P=>O(P,new RegExp(`${d}$`),k,{logger:t})))}}0&&(module.exports={listCodemods,packageNames,runCodemod,updateAddonInfo,updateOrganisationName});
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ import fs from"fs";import path from"path";import{promisify}from"util";import globby from"globby";import{sync as spawnSync}from"cross-spawn";import camelCase from"lodash/camelCase";import upperFirst from"lodash/upperFirst";function jscodeshiftToPrettierParser(parser){let parserMap={babylon:"babel",flow:"flow",ts:"typescript",tsx:"typescript"};return parser&&parserMap[parser]||"babel"}var packageNames={"@kadira/react-storybook-decorator-centered":"@storybook/addon-centered","@kadira/storybook-addons":"@storybook/preview-api","@kadira/storybook-addon-actions":"@storybook/addon-actions","@kadira/storybook-addon-comments":"@storybook/addon-comments","@kadira/storybook-addon-graphql":"@storybook/addon-graphql","@kadira/storybook-addon-info":"@storybook/addon-info","@kadira/storybook-addon-knobs":"@storybook/addon-knobs","@kadira/storybook-addon-links":"@storybook/addon-links","@kadira/storybook-addon-notes":"@storybook/addon-notes","@kadira/storybook-addon-options":"@storybook/addon-options","@kadira/storybook-channels":"@storybook/channels","@kadira/storybook-channel-postmsg":"@storybook/channel-postmessage","@kadira/storybook-channel-websocket":"@storybook/channel-websocket","@kadira/storybook-ui":"@storybook/manager","@kadira/react-native-storybook":"@storybook/react-native","@kadira/react-storybook":"@storybook/react","@kadira/getstorybook":"@storybook/cli","@kadira/storybook":"@storybook/react",storyshots:"@storybook/addon-storyshots",getstorybook:"@storybook/cli"};function transformer(file,api){let j=api.jscodeshift,packageNamesKeys=Object.keys(packageNames),getMatch=oldpart=>packageNamesKeys.find(newpart=>oldpart.match(newpart)),getNewPackageName=oldPackageName=>{let match=getMatch(oldPackageName);if(match){let replacement=packageNames[match];return oldPackageName.replace(match,replacement)}return oldPackageName},updatePackageName=declaration=>(declaration.node.source.value=getNewPackageName(declaration.node.source.value),declaration.node);return j(file.source).find(j.ImportDeclaration).replaceWith(updatePackageName).toSource({quote:"single"})}function transformer2(file,api){let j=api.jscodeshift,root=j(file.source),getOptions=args=>args[3]===void 0?args[2]===void 0?[args[0]]:[args[1]]:[j.objectExpression([j.property("init",j.identifier("text"),args[1]),...args[3].properties])],withInfo=addWithInfoExpression=>{let{node}=addWithInfoExpression,args=node.arguments,storyComponent=args[2]?args[2]:args[1];return node.callee.property.name="add",node.arguments=[args[0],j.callExpression(j.callExpression(j.identifier("withInfo"),getOptions(args)),[storyComponent])],node},checkWithInfoImport=()=>{root.find(j.ImportDeclaration).filter(imp=>imp.node.source.value==="@storybook/addon-info").size()||root.find(j.ImportDeclaration).at(-1).insertAfter(j.importDeclaration([j.importSpecifier(j.identifier("withInfo"))],j.literal("@storybook/addon-info")))},addWithInfoExpressions=root.find(j.CallExpression,{callee:{property:{name:"addWithInfo"}}});return addWithInfoExpressions.size()&&(checkWithInfoImport(),addWithInfoExpressions.replaceWith(withInfo)),root.toSource()}var TRANSFORM_DIR=`${__dirname}/transforms`;function listCodemods(){return fs.readdirSync(TRANSFORM_DIR).filter(fname=>fname.endsWith(".js")).map(fname=>fname.slice(0,-3))}var renameAsync=promisify(fs.rename);async function renameFile(file,from,to,{logger}){let newFile=file.replace(from,to);return logger.log(`Rename: ${file} ${newFile}`),renameAsync(file,newFile)}async function runCodemod(codemod,{glob,logger,dryRun,rename,parser}){if(!listCodemods().includes(codemod))throw new Error(`Unknown codemod ${codemod}. Run --list for options.`);let renameParts=null;if(rename&&(renameParts=rename.split(":"),renameParts.length!==2))throw new Error(`Codemod rename: expected format "from:to", got "${rename}"`);let inferredParser=parser;if(!parser){let extension=path.extname(glob).slice(1);jscodeshiftToPrettierParser(extension)!=="babel"&&(inferredParser=extension)}let files=await globby([glob,"!**/node_modules","!**/dist"]);if(logger.log(`=> Applying ${codemod}: ${files.length} files`),!dryRun){let parserArgs=inferredParser?["--parser",inferredParser]:[];spawnSync("npx",["jscodeshift","-t",`${TRANSFORM_DIR}/${codemod}.js`,...parserArgs,...files],{stdio:"inherit",shell:!0})}if(renameParts){let[from,to]=renameParts;logger.log(`=> Renaming ${rename}: ${files.length} files`),await Promise.all(files.map(file=>renameFile(file,new RegExp(`${from}$`),to,{logger})))}}export{listCodemods,packageNames,runCodemod,transformer2 as updateAddonInfo,transformer as updateOrganisationName};
package/jest.config.js ADDED
@@ -0,0 +1,7 @@
1
+ const path = require('path');
2
+ const baseConfig = require('../../jest.config.node');
3
+
4
+ module.exports = {
5
+ ...baseConfig,
6
+ displayName: __dirname.split(path.sep).slice(-2).join(path.posix.sep),
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/codemod",
3
- "version": "7.0.0-alpha.7",
3
+ "version": "7.0.0-beta.0",
4
4
  "description": "A collection of codemod scripts written with JSCodeshift",
5
5
  "keywords": [
6
6
  "storybook"
@@ -20,46 +20,49 @@
20
20
  },
21
21
  "license": "MIT",
22
22
  "sideEffects": false,
23
- "main": "dist/cjs/index.js",
24
- "module": "dist/esm/index.js",
25
- "jsnext:main": "src/index.js",
26
- "typesVersions": {
27
- "<3.8": {
28
- "*": [
29
- "ts3.4/*"
30
- ]
31
- }
23
+ "exports": {
24
+ ".": {
25
+ "require": "./dist/index.js",
26
+ "import": "./dist/index.mjs",
27
+ "types": "./dist/index.d.ts"
28
+ },
29
+ "./package.json": "./package.json"
32
30
  },
33
- "files": [
34
- "dist/**/*",
35
- "README.md",
36
- "*.js",
37
- "*.d.ts",
38
- "!__testfixtures__"
39
- ],
31
+ "main": "dist/index.js",
32
+ "module": "dist/index.mjs",
33
+ "jsnext:main": "src/index.js",
34
+ "types": "dist/index.d.ts",
40
35
  "scripts": {
41
- "prepare": "node ../../scripts/prepare.js"
36
+ "check": "../../../scripts/node_modules/.bin/tsc --noEmit",
37
+ "prep": "../../../scripts/prepare/bundle.ts"
42
38
  },
43
39
  "dependencies": {
44
- "@babel/types": "^7.12.11",
45
- "@mdx-js/mdx": "^1.6.22",
46
- "@storybook/csf": "0.0.2--canary.4566f4d.1",
47
- "@storybook/csf-tools": "7.0.0-alpha.7",
48
- "@storybook/node-logger": "7.0.0-alpha.7",
49
- "core-js": "^3.8.2",
40
+ "@babel/types": "^7.20.2",
41
+ "@storybook/csf": "next",
42
+ "@storybook/csf-tools": "7.0.0-beta.0",
43
+ "@storybook/node-logger": "7.0.0-beta.0",
44
+ "@storybook/types": "7.0.0-beta.0",
50
45
  "cross-spawn": "^7.0.3",
51
46
  "globby": "^11.0.2",
52
47
  "jscodeshift": "^0.13.1",
53
48
  "lodash": "^4.17.21",
54
- "prettier": ">=2.2.1 <=2.3.0",
55
- "recast": "^0.19.0"
49
+ "prettier": "^2.8.0",
50
+ "recast": "^0.19.0",
51
+ "util": "^0.12.4"
56
52
  },
57
53
  "devDependencies": {
58
- "jest": "^26.6.3",
59
- "jest-specific-snapshot": "^4.0.0"
54
+ "jest": "^29.3.1",
55
+ "jest-specific-snapshot": "^7.0.0",
56
+ "typescript": "~4.9.3"
60
57
  },
61
58
  "publishConfig": {
62
59
  "access": "public"
63
60
  },
64
- "gitHead": "d334cabd251cd0ed8b845a87707dc84f007d4074"
61
+ "bundler": {
62
+ "platform": "node",
63
+ "entries": [
64
+ "./src/index.js"
65
+ ]
66
+ },
67
+ "gitHead": "2e4ddde6a0a291266d91fe6a5ecda767bf119e70"
65
68
  }
package/src/index.js ADDED
@@ -0,0 +1,77 @@
1
+ /* eslint import/prefer-default-export: "off" */
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { promisify } from 'util';
5
+ import globby from 'globby';
6
+ import { sync as spawnSync } from 'cross-spawn';
7
+ import { jscodeshiftToPrettierParser } from './lib/utils';
8
+
9
+ export {
10
+ default as updateOrganisationName,
11
+ packageNames,
12
+ } from './transforms/update-organisation-name';
13
+
14
+ export { default as updateAddonInfo } from './transforms/update-addon-info';
15
+
16
+ const TRANSFORM_DIR = `${__dirname}/transforms`;
17
+
18
+ export function listCodemods() {
19
+ return fs
20
+ .readdirSync(TRANSFORM_DIR)
21
+ .filter((fname) => fname.endsWith('.js'))
22
+ .map((fname) => fname.slice(0, -3));
23
+ }
24
+
25
+ const renameAsync = promisify(fs.rename);
26
+
27
+ async function renameFile(file, from, to, { logger }) {
28
+ const newFile = file.replace(from, to);
29
+ logger.log(`Rename: ${file} ${newFile}`);
30
+ return renameAsync(file, newFile);
31
+ }
32
+
33
+ export async function runCodemod(codemod, { glob, logger, dryRun, rename, parser }) {
34
+ const codemods = listCodemods();
35
+ if (!codemods.includes(codemod)) {
36
+ throw new Error(`Unknown codemod ${codemod}. Run --list for options.`);
37
+ }
38
+
39
+ let renameParts = null;
40
+ if (rename) {
41
+ renameParts = rename.split(':');
42
+ if (renameParts.length !== 2) {
43
+ throw new Error(`Codemod rename: expected format "from:to", got "${rename}"`);
44
+ }
45
+ }
46
+
47
+ // jscodeshift/prettier know how to handle .ts/.tsx extensions,
48
+ // so if the user uses one of those globs, we can auto-infer
49
+ let inferredParser = parser;
50
+ if (!parser) {
51
+ const extension = path.extname(glob).slice(1);
52
+ const knownParser = jscodeshiftToPrettierParser(extension);
53
+ if (knownParser !== 'babel') inferredParser = extension;
54
+ }
55
+
56
+ const files = await globby([glob, '!**/node_modules', '!**/dist']);
57
+ logger.log(`=> Applying ${codemod}: ${files.length} files`);
58
+ if (!dryRun) {
59
+ const parserArgs = inferredParser ? ['--parser', inferredParser] : [];
60
+ spawnSync(
61
+ 'npx',
62
+ ['jscodeshift', '-t', `${TRANSFORM_DIR}/${codemod}.js`, ...parserArgs, ...files],
63
+ {
64
+ stdio: 'inherit',
65
+ shell: true,
66
+ }
67
+ );
68
+ }
69
+
70
+ if (renameParts) {
71
+ const [from, to] = renameParts;
72
+ logger.log(`=> Renaming ${rename}: ${files.length} files`);
73
+ await Promise.all(
74
+ files.map((file) => renameFile(file, new RegExp(`${from}$`), to, { logger }))
75
+ );
76
+ }
77
+ }
@@ -0,0 +1,9 @@
1
+ import { sanitizeName } from './utils';
2
+
3
+ it('should sanitize names', () => {
4
+ expect(sanitizeName('basic')).toMatchInlineSnapshot(`"Basic"`);
5
+ expect(sanitizeName('with space')).toMatchInlineSnapshot(`"WithSpace"`);
6
+ expect(sanitizeName('default')).toMatchInlineSnapshot(`"Default"`);
7
+ expect(sanitizeName('w/punctuation')).toMatchInlineSnapshot(`"WPunctuation"`);
8
+ expect(sanitizeName('5')).toMatchInlineSnapshot(`"_5"`);
9
+ });
@@ -1,30 +1,29 @@
1
1
  import camelCase from 'lodash/camelCase';
2
2
  import upperFirst from 'lodash/upperFirst';
3
- export var sanitizeName = function (name) {
4
- var key = upperFirst(camelCase(name)); // prepend _ if name starts with a digit
5
3
 
4
+ export const sanitizeName = (name: string) => {
5
+ let key = upperFirst(camelCase(name));
6
+ // prepend _ if name starts with a digit
6
7
  if (/^\d/.test(key)) {
7
8
  key = `_${key}`;
8
- } // prepend _ if name starts with a digit
9
-
10
-
9
+ }
10
+ // prepend _ if name starts with a digit
11
11
  if (/^\d/.test(key)) {
12
12
  key = `_${key}`;
13
13
  }
14
-
15
14
  return key;
16
15
  };
17
- export function jscodeshiftToPrettierParser(parser) {
18
- var parserMap = {
16
+
17
+ export function jscodeshiftToPrettierParser(parser?: string) {
18
+ const parserMap: Record<string, string> = {
19
19
  babylon: 'babel',
20
20
  flow: 'flow',
21
21
  ts: 'typescript',
22
- tsx: 'typescript'
22
+ tsx: 'typescript',
23
23
  };
24
24
 
25
25
  if (!parser) {
26
26
  return 'babel';
27
27
  }
28
-
29
28
  return parserMap[parser] || 'babel';
30
- }
29
+ }
@@ -0,0 +1,44 @@
1
+ /* eslint-disable */
2
+ import React from 'react';
3
+ import Button from './Button';
4
+
5
+ import { storiesOf, configure } from '@storybook/react';
6
+ import { action } from '@storybook/addon-actions';
7
+
8
+ storiesOf('Button', module).add('basic', () => <Button label="The Button" />);
9
+
10
+ storiesOf('Button').add('no module', () => <Button label="The Button" />);
11
+
12
+ storiesOf('Button', module).add('with story parameters', () => <Button label="The Button" />, {
13
+ header: false,
14
+ inline: true,
15
+ });
16
+
17
+ storiesOf('Button', module)
18
+ .addParameters({ foo: 1 })
19
+ .add('with kind parameters', () => <Button label="The Button" />);
20
+
21
+ storiesOf('Button', module)
22
+ .addParameters({ component: Button })
23
+ .add('with existing component parameters', () => <Button label="The Button" />);
24
+
25
+ storiesOf('Button', module).add('complex story', () => (
26
+ <div>
27
+ <Button label="The Button" onClick={action('onClick')} />
28
+ <br />
29
+ </div>
30
+ ));
31
+
32
+ storiesOf('Root|Some/Button', module).add('with path', () => <Button label="The Button" />);
33
+
34
+ storiesOf('Some.Button', module).add('with dot-path', () => <Button label="The Button" />);
35
+
36
+ storiesOf('Some.Button', module)
37
+ .addDecorator(withKnobs)
38
+ .add('with decorator', () => <Button label="The Button" />);
39
+
40
+ // This isn't a valid story, but it tests the `import { comp } from ...` case
41
+ storiesOf('action', module).add('non-default component export', () => <action />);
42
+
43
+ // This shouldn't get modified since the story name doesn't match
44
+ storiesOf('something', module).add('non-matching story', () => <Button label="The Button" />);
@@ -0,0 +1,68 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`add-component-parameters transforms correctly using "add-component-parameters.input.js" data 1`] = `
4
+ "/* eslint-disable */
5
+ import React from 'react';
6
+ import Button from './Button';
7
+
8
+ import { storiesOf, configure } from '@storybook/react';
9
+ import { action } from '@storybook/addon-actions';
10
+
11
+ storiesOf('Button', module).addParameters({
12
+ component: Button
13
+ }).add('basic', () => <Button label=\\"The Button\\" />);
14
+
15
+ storiesOf('Button').addParameters({
16
+ component: Button
17
+ }).add('no module', () => <Button label=\\"The Button\\" />);
18
+
19
+ storiesOf('Button', module).addParameters({
20
+ component: Button
21
+ }).add('with story parameters', () => <Button label=\\"The Button\\" />, {
22
+ header: false,
23
+ inline: true,
24
+ });
25
+
26
+ storiesOf('Button', module).addParameters({
27
+ component: Button
28
+ })
29
+ .addParameters({ foo: 1 })
30
+ .add('with kind parameters', () => <Button label=\\"The Button\\" />);
31
+
32
+ storiesOf('Button', module).addParameters({
33
+ component: Button
34
+ })
35
+ .addParameters({ component: Button })
36
+ .add('with existing component parameters', () => <Button label=\\"The Button\\" />);
37
+
38
+ storiesOf('Button', module).addParameters({
39
+ component: Button
40
+ }).add('complex story', () => (
41
+ <div>
42
+ <Button label=\\"The Button\\" onClick={action('onClick')} />
43
+ <br />
44
+ </div>
45
+ ));
46
+
47
+ storiesOf('Root|Some/Button', module).addParameters({
48
+ component: Button
49
+ }).add('with path', () => <Button label=\\"The Button\\" />);
50
+
51
+ storiesOf('Some.Button', module).addParameters({
52
+ component: Button
53
+ }).add('with dot-path', () => <Button label=\\"The Button\\" />);
54
+
55
+ storiesOf('Some.Button', module).addParameters({
56
+ component: Button
57
+ })
58
+ .addDecorator(withKnobs)
59
+ .add('with decorator', () => <Button label=\\"The Button\\" />);
60
+
61
+ // This isn't a valid story, but it tests the \`import { comp } from ...\` case
62
+ storiesOf('action', module).addParameters({
63
+ component: action
64
+ }).add('non-default component export', () => <action />);
65
+
66
+ // This shouldn't get modified since the story name doesn't match
67
+ storiesOf('something', module).add('non-matching story', () => <Button label=\\"The Button\\" />);"
68
+ `;