@storybook/codemod 7.0.0-alpha.37 → 7.0.0-alpha.39

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. package/dist/index.d.ts +261 -0
  2. package/dist/index.js +1 -0
  3. package/dist/index.mjs +1 -0
  4. package/package.json +24 -15
  5. package/src/index.js +77 -0
  6. package/src/lib/utils.test.js +9 -0
  7. package/{dist/esm/lib/utils.js → src/lib/utils.ts} +10 -11
  8. package/src/transforms/__testfixtures__/add-component-parameters/add-component-parameters.input.js +44 -0
  9. package/src/transforms/__testfixtures__/add-component-parameters/add-component-parameters.output.snapshot +68 -0
  10. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/basic.input.js +25 -0
  11. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/basic.output.snapshot +27 -0
  12. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/overrides.input.js +25 -0
  13. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/overrides.output.snapshot +28 -0
  14. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/variable.input.js +13 -0
  15. package/src/transforms/__testfixtures__/csf-hoist-story-annotations/variable.output.snapshot +17 -0
  16. package/src/transforms/__testfixtures__/csf-to-mdx/basic.input.js +20 -0
  17. package/src/transforms/__testfixtures__/csf-to-mdx/basic.output.snapshot +18 -0
  18. package/src/transforms/__testfixtures__/csf-to-mdx/component-id.input.js +9 -0
  19. package/src/transforms/__testfixtures__/csf-to-mdx/component-id.output.snapshot +10 -0
  20. package/src/transforms/__testfixtures__/csf-to-mdx/decorators.input.js +13 -0
  21. package/src/transforms/__testfixtures__/csf-to-mdx/decorators.output.snapshot +12 -0
  22. package/src/transforms/__testfixtures__/csf-to-mdx/exclude-stories.input.js +23 -0
  23. package/src/transforms/__testfixtures__/csf-to-mdx/exclude-stories.output.snapshot +22 -0
  24. package/src/transforms/__testfixtures__/csf-to-mdx/parameters.input.js +16 -0
  25. package/src/transforms/__testfixtures__/csf-to-mdx/parameters.output.snapshot +17 -0
  26. package/src/transforms/__testfixtures__/csf-to-mdx/story-function.input.js +19 -0
  27. package/src/transforms/__testfixtures__/csf-to-mdx/story-function.output.snapshot +18 -0
  28. package/src/transforms/__testfixtures__/csf-to-mdx/story-parameters.input.js +24 -0
  29. package/src/transforms/__testfixtures__/csf-to-mdx/story-parameters.output.snapshot +22 -0
  30. package/src/transforms/__testfixtures__/mdx-to-csf/basic.input.js +18 -0
  31. package/src/transforms/__testfixtures__/mdx-to-csf/basic.output.snapshot +40 -0
  32. package/src/transforms/__testfixtures__/mdx-to-csf/component-id.input.js +6 -0
  33. package/src/transforms/__testfixtures__/mdx-to-csf/component-id.output.snapshot +17 -0
  34. package/src/transforms/__testfixtures__/mdx-to-csf/decorators.input.js +8 -0
  35. package/src/transforms/__testfixtures__/mdx-to-csf/decorators.output.snapshot +18 -0
  36. package/src/transforms/__testfixtures__/mdx-to-csf/exclude-stories.input.js +19 -0
  37. package/src/transforms/__testfixtures__/mdx-to-csf/exclude-stories.output.snapshot +39 -0
  38. package/src/transforms/__testfixtures__/mdx-to-csf/parameters.input.js +14 -0
  39. package/src/transforms/__testfixtures__/mdx-to-csf/parameters.output.snapshot +23 -0
  40. package/src/transforms/__testfixtures__/mdx-to-csf/plaintext.input.js +3 -0
  41. package/src/transforms/__testfixtures__/mdx-to-csf/plaintext.output.snapshot +11 -0
  42. package/src/transforms/__testfixtures__/mdx-to-csf/story-function.input.js +10 -0
  43. package/src/transforms/__testfixtures__/mdx-to-csf/story-function.output.snapshot +18 -0
  44. package/src/transforms/__testfixtures__/mdx-to-csf/story-parameters.input.js +18 -0
  45. package/src/transforms/__testfixtures__/mdx-to-csf/story-parameters.output.snapshot +32 -0
  46. package/src/transforms/__testfixtures__/mdx-to-csf/story-refs.input.js +22 -0
  47. package/src/transforms/__testfixtures__/mdx-to-csf/story-refs.output.snapshot +34 -0
  48. package/src/transforms/__testfixtures__/move-builtin-addons/default.input.js +2 -0
  49. package/src/transforms/__testfixtures__/move-builtin-addons/default.output.snapshot +8 -0
  50. package/src/transforms/__testfixtures__/move-builtin-addons/with-no-change.input.js +3 -0
  51. package/src/transforms/__testfixtures__/move-builtin-addons/with-no-change.output.snapshot +7 -0
  52. package/src/transforms/__testfixtures__/storiesof-to-csf/basic.input.js +18 -0
  53. package/src/transforms/__testfixtures__/storiesof-to-csf/basic.output.snapshot +45 -0
  54. package/src/transforms/__testfixtures__/storiesof-to-csf/collision.input.js +11 -0
  55. package/src/transforms/__testfixtures__/storiesof-to-csf/collision.output.snapshot +38 -0
  56. package/src/transforms/__testfixtures__/storiesof-to-csf/const.input.js +1 -0
  57. package/src/transforms/__testfixtures__/storiesof-to-csf/const.output.snapshot +13 -0
  58. package/src/transforms/__testfixtures__/storiesof-to-csf/decorators.input.js +9 -0
  59. package/src/transforms/__testfixtures__/storiesof-to-csf/decorators.output.snapshot +18 -0
  60. package/src/transforms/__testfixtures__/storiesof-to-csf/default.input.js +7 -0
  61. package/src/transforms/__testfixtures__/storiesof-to-csf/default.output.snapshot +17 -0
  62. package/src/transforms/__testfixtures__/storiesof-to-csf/digit.input.js +1 -0
  63. package/src/transforms/__testfixtures__/storiesof-to-csf/digit.output.js +5 -0
  64. package/src/transforms/__testfixtures__/storiesof-to-csf/digit.output.snapshot +9 -0
  65. package/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.input.js +11 -0
  66. package/src/transforms/__testfixtures__/storiesof-to-csf/export-destructuring.output.snapshot +23 -0
  67. package/src/transforms/__testfixtures__/storiesof-to-csf/export-function.input.js +12 -0
  68. package/src/transforms/__testfixtures__/storiesof-to-csf/export-function.output.snapshot +23 -0
  69. package/src/transforms/__testfixtures__/storiesof-to-csf/export-names.input.js +14 -0
  70. package/src/transforms/__testfixtures__/storiesof-to-csf/export-names.output.snapshot +26 -0
  71. package/src/transforms/__testfixtures__/storiesof-to-csf/exports.input.js +2 -0
  72. package/src/transforms/__testfixtures__/storiesof-to-csf/exports.output.snapshot +16 -0
  73. package/src/transforms/__testfixtures__/storiesof-to-csf/module.input.js +12 -0
  74. package/src/transforms/__testfixtures__/storiesof-to-csf/module.output.snapshot +16 -0
  75. package/src/transforms/__testfixtures__/storiesof-to-csf/multi.input.js +14 -0
  76. package/src/transforms/__testfixtures__/storiesof-to-csf/multi.output.snapshot +39 -0
  77. package/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.input.js +8 -0
  78. package/src/transforms/__testfixtures__/storiesof-to-csf/parameters-as-var.output.snapshot +20 -0
  79. package/src/transforms/__testfixtures__/storiesof-to-csf/parameters.input.js +10 -0
  80. package/src/transforms/__testfixtures__/storiesof-to-csf/parameters.output.snapshot +23 -0
  81. package/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.input.js +11 -0
  82. package/src/transforms/__testfixtures__/storiesof-to-csf/storiesof-var.output.snapshot +23 -0
  83. package/src/transforms/__testfixtures__/storiesof-to-csf/story-decorators.input.js +11 -0
  84. package/src/transforms/__testfixtures__/storiesof-to-csf/story-decorators.output.snapshot +29 -0
  85. package/src/transforms/__testfixtures__/storiesof-to-csf/story-parameters.input.js +14 -0
  86. package/src/transforms/__testfixtures__/storiesof-to-csf/story-parameters.output.snapshot +32 -0
  87. package/src/transforms/__testfixtures__/update-addon-info/update-addon-info.input.js +198 -0
  88. package/src/transforms/__testfixtures__/update-addon-info/update-addon-info.output.snapshot +198 -0
  89. package/src/transforms/__testfixtures__/update-organisation-name/update-organisation-name.input.js +19 -0
  90. package/src/transforms/__testfixtures__/update-organisation-name/update-organisation-name.output.snapshot +23 -0
  91. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/csf.input.js +3 -0
  92. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/csf.output.snapshot +7 -0
  93. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/dynamic-storiesof.input.js +5 -0
  94. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/dynamic-storiesof.output.snapshot +9 -0
  95. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/storiesof.input.js +8 -0
  96. package/src/transforms/__testfixtures__/upgrade-hierarchy-separators/storiesof.output.snapshot +12 -0
  97. package/src/transforms/__tests__/csf-2-to-3.test.ts +251 -0
  98. package/src/transforms/__tests__/transforms.tests.js +30 -0
  99. package/{dist/esm → src}/transforms/add-component-parameters.js +26 -21
  100. package/src/transforms/csf-2-to-3.ts +183 -0
  101. package/src/transforms/csf-hoist-story-annotations.js +97 -0
  102. package/src/transforms/csf-to-mdx.js +190 -0
  103. package/src/transforms/mdx-to-csf.js +184 -0
  104. package/src/transforms/move-builtin-addons.js +32 -0
  105. package/src/transforms/storiesof-to-csf.js +277 -0
  106. package/{dist/esm → src}/transforms/update-addon-info.js +44 -24
  107. package/{dist/esm → src}/transforms/update-organisation-name.js +19 -22
  108. package/src/transforms/upgrade-hierarchy-separators.js +39 -0
  109. package/tsconfig.json +13 -0
  110. package/dist/cjs/index.js +0 -139
  111. package/dist/cjs/lib/utils.js +0 -45
  112. package/dist/cjs/transforms/add-component-parameters.js +0 -64
  113. package/dist/cjs/transforms/csf-2-to-3.js +0 -180
  114. package/dist/cjs/transforms/csf-hoist-story-annotations.js +0 -93
  115. package/dist/cjs/transforms/csf-to-mdx.js +0 -196
  116. package/dist/cjs/transforms/mdx-to-csf.js +0 -153
  117. package/dist/cjs/transforms/move-builtin-addons.js +0 -55
  118. package/dist/cjs/transforms/storiesof-to-csf.js +0 -300
  119. package/dist/cjs/transforms/update-addon-info.js +0 -101
  120. package/dist/cjs/transforms/update-organisation-name.js +0 -83
  121. package/dist/cjs/transforms/upgrade-hierarchy-separators.js +0 -42
  122. package/dist/esm/index.js +0 -97
  123. package/dist/esm/transforms/csf-2-to-3.js +0 -163
  124. package/dist/esm/transforms/csf-hoist-story-annotations.js +0 -86
  125. package/dist/esm/transforms/csf-to-mdx.js +0 -188
  126. package/dist/esm/transforms/mdx-to-csf.js +0 -139
  127. package/dist/esm/transforms/move-builtin-addons.js +0 -48
  128. package/dist/esm/transforms/storiesof-to-csf.js +0 -287
  129. package/dist/esm/transforms/upgrade-hierarchy-separators.js +0 -35
  130. package/dist/types/lib/utils.d.ts +0 -2
  131. package/dist/types/transforms/csf-2-to-3.d.ts +0 -6
@@ -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/addons',
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/ui',
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 A=Object.getOwnPropertyNames;var C=Object.getPrototypeOf,S=Object.prototype.hasOwnProperty;var W=(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 A(r))!S.call(o,n)&&n!==t&&l(o,n,{get:()=>r[n],enumerable:!(a=N(r,n))||a.enumerable});return o};var f=(o,r,t)=>(t=o!=null?R(C(o)):{},h(r||!o||!o.__esModule?l(t,"default",{value:o,enumerable:!0}):t,o)),_=o=>h(l({},"__esModule",{value:!0}),o);var z={};W(z,{listCodemods:()=>E,packageNames:()=>m,runCodemod:()=>q,updateAddonInfo:()=>b,updateOrganisationName:()=>y});module.exports=_(z);var u=f(require("fs")),x=f(require("path")),w=require("util"),$=f(require("globby")),I=require("cross-spawn");var v=f(require("lodash/camelCase")),D=f(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/addons","@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/ui","@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},p=s=>(s.node.source.value=c(s.node.source.value),s.node);return t(o.source).find(t.ImportDeclaration).replaceWith(p).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},p=()=>{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()&&(p(),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 u from"fs";import x from"path";import{promisify as w}from"util";import $ from"globby";import{sync as I}from"cross-spawn";import N from"lodash/camelCase";import C from"lodash/upperFirst";function m(t){let i={babylon:"babel",flow:"flow",ts:"typescript",tsx:"typescript"};return t&&i[t]||"babel"}var l={"@kadira/react-storybook-decorator-centered":"@storybook/addon-centered","@kadira/storybook-addons":"@storybook/addons","@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/ui","@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(t,i){let o=i.jscodeshift,d=Object.keys(l),a=e=>d.find(r=>e.match(r)),c=e=>{let r=a(e);if(r){let n=l[r];return e.replace(r,n)}return e},f=e=>(e.node.source.value=c(e.node.source.value),e.node);return o(t.source).find(o.ImportDeclaration).replaceWith(f).toSource({quote:"single"})}function b(t,i){let o=i.jscodeshift,d=o(t.source),a=r=>r[3]===void 0?r[2]===void 0?[r[0]]:[r[1]]:[o.objectExpression([o.property("init",o.identifier("text"),r[1]),...r[3].properties])],c=r=>{let{node:n}=r,s=n.arguments,p=s[2]?s[2]:s[1];return n.callee.property.name="add",n.arguments=[s[0],o.callExpression(o.callExpression(o.identifier("withInfo"),a(s)),[p])],n},f=()=>{d.find(o.ImportDeclaration).filter(n=>n.node.source.value==="@storybook/addon-info").size()||d.find(o.ImportDeclaration).at(-1).insertAfter(o.importDeclaration([o.importSpecifier(o.identifier("withInfo"))],o.literal("@storybook/addon-info")))},e=d.find(o.CallExpression,{callee:{property:{name:"addWithInfo"}}});return e.size()&&(f(),e.replaceWith(c)),d.toSource()}var h=`${__dirname}/transforms`;function j(){return u.readdirSync(h).filter(t=>t.endsWith(".js")).map(t=>t.slice(0,-3))}var E=w(u.rename);async function P(t,i,o,{logger:d}){let a=t.replace(i,o);return d.log(`Rename: ${t} ${a}`),E(t,a)}async function M(t,{glob:i,logger:o,dryRun:d,rename:a,parser:c}){if(!j().includes(t))throw new Error(`Unknown codemod ${t}. Run --list for options.`);let e=null;if(a&&(e=a.split(":"),e.length!==2))throw new Error(`Codemod rename: expected format "from:to", got "${a}"`);let r=c;if(!c){let s=x.extname(i).slice(1);m(s)!=="babel"&&(r=s)}let n=await $([i,"!**/node_modules","!**/dist"]);if(o.log(`=> Applying ${t}: ${n.length} files`),!d){let s=r?["--parser",r]:[];I("npx",["jscodeshift","-t",`${h}/${t}.js`,...s,...n],{stdio:"inherit",shell:!0})}if(e){let[s,p]=e;o.log(`=> Renaming ${a}: ${n.length} files`),await Promise.all(n.map(g=>P(g,new RegExp(`${s}$`),p,{logger:o})))}}export{j as listCodemods,l as packageNames,M as runCodemod,b as updateAddonInfo,y as updateOrganisationName};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/codemod",
3
- "version": "7.0.0-alpha.37",
3
+ "version": "7.0.0-alpha.39",
4
4
  "description": "A collection of codemod scripts written with JSCodeshift",
5
5
  "keywords": [
6
6
  "storybook"
@@ -20,32 +20,35 @@
20
20
  },
21
21
  "license": "MIT",
22
22
  "sideEffects": false,
23
- "main": "dist/cjs/index.js",
24
- "module": "dist/esm/index.js",
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"
30
+ },
31
+ "main": "dist/index.js",
32
+ "module": "dist/index.mjs",
25
33
  "jsnext:main": "src/index.js",
26
- "files": [
27
- "dist/**/*",
28
- "README.md",
29
- "*.js",
30
- "*.d.ts",
31
- "!__testfixtures__"
32
- ],
34
+ "types": "dist/index.d.ts",
33
35
  "scripts": {
34
36
  "check": "../../../scripts/node_modules/.bin/tsc --noEmit",
35
- "prep": "node ../../../scripts/prepare.js"
37
+ "prep": "../../../scripts/prepare/bundle.ts"
36
38
  },
37
39
  "dependencies": {
38
40
  "@babel/types": "^7.12.11",
39
41
  "@mdx-js/mdx": "^1.6.22",
40
42
  "@storybook/csf": "0.0.2--canary.49.258942b.0",
41
- "@storybook/csf-tools": "7.0.0-alpha.37",
42
- "@storybook/node-logger": "7.0.0-alpha.37",
43
+ "@storybook/csf-tools": "7.0.0-alpha.39",
44
+ "@storybook/node-logger": "7.0.0-alpha.39",
43
45
  "cross-spawn": "^7.0.3",
44
46
  "globby": "^11.0.2",
45
47
  "jscodeshift": "^0.13.1",
46
48
  "lodash": "^4.17.21",
47
49
  "prettier": ">=2.2.1 <=2.3.0",
48
- "recast": "^0.19.0"
50
+ "recast": "^0.19.0",
51
+ "util": "^0.12.4"
49
52
  },
50
53
  "devDependencies": {
51
54
  "jest": "^26.6.3",
@@ -55,5 +58,11 @@
55
58
  "publishConfig": {
56
59
  "access": "public"
57
60
  },
58
- "gitHead": "82667a655108283aafc828427f00bb3590a334e5"
61
+ "bundler": {
62
+ "platform": "node",
63
+ "entries": [
64
+ "./src/index.js"
65
+ ]
66
+ },
67
+ "gitHead": "47386bd49d141ea70daac41ab3e4d52749fc5da9"
59
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
+ `;
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import Button from './Button';
3
+ import { action } from '@storybook/addon-actions';
4
+
5
+ export default {
6
+ title: 'Button',
7
+ };
8
+
9
+ export const story1 = () => <Button label="Story 1" />;
10
+
11
+ export const story2 = () => <Button label="Story 2" onClick={action('click')} />;
12
+ story2.story = { name: 'second story' };
13
+
14
+ export const story3 = () => (
15
+ <div>
16
+ <Button label="The Button" onClick={action('onClick')} />
17
+ <br />
18
+ </div>
19
+ );
20
+ const baz = 17;
21
+ story3.story = {
22
+ name: 'complex story',
23
+ parameters: { foo: { bar: baz } },
24
+ decorators: [(storyFn) => <bar>{storyFn}</bar>],
25
+ };
@@ -0,0 +1,27 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`csf-hoist-story-annotations transforms correctly using "basic.input.js" data 1`] = `
4
+ "import React from 'react';
5
+ import Button from './Button';
6
+ import { action } from '@storybook/addon-actions';
7
+
8
+ export default {
9
+ title: 'Button',
10
+ };
11
+
12
+ export const story1 = () => <Button label=\\"Story 1\\" />;
13
+
14
+ export const story2 = () => <Button label=\\"Story 2\\" onClick={action('click')} />;
15
+ story2.storyName = 'second story';
16
+
17
+ export const story3 = () => (
18
+ <div>
19
+ <Button label=\\"The Button\\" onClick={action('onClick')} />
20
+ <br />
21
+ </div>
22
+ );
23
+ const baz = 17;
24
+ story3.storyName = 'complex story';
25
+ story3.parameters = { foo: { bar: baz } };
26
+ story3.decorators = [(storyFn) => <bar>{storyFn}</bar>];"
27
+ `;
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import Button from './Button';
3
+ import { action } from '@storybook/addon-actions';
4
+
5
+ export default {
6
+ title: 'Button',
7
+ };
8
+
9
+ export const story1 = () => <Button label="Story 1" />;
10
+
11
+ export const story2 = () => <Button label="Story 2" onClick={action('click')} />;
12
+ story2.story = { name: 'second story' };
13
+ story2.story.parameters = { foo: 'bar' };
14
+
15
+ export const story3 = () => (
16
+ <div>
17
+ <Button label="The Button" onClick={action('onClick')} />
18
+ <br />
19
+ </div>
20
+ );
21
+ const baz = 17;
22
+ story3.story = {};
23
+ story3.story.name = 'complex story';
24
+ story3.story.parameters = { foo: { bar: baz } };
25
+ story3.story.decorators = [(storyFn) => <bar>{storyFn}</bar>];