@storybook/codemod 11.0.0-alpha.7 → 11.0.0-alpha.8

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.
@@ -0,0 +1,105 @@
1
+ import CJS_COMPAT_NODE_URL_77qkz8uuglf from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_77qkz8uuglf from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_77qkz8uuglf from "node:module";
4
+
5
+ var __filename = CJS_COMPAT_NODE_URL_77qkz8uuglf.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_77qkz8uuglf.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_77qkz8uuglf.createRequire(import.meta.url);
8
+
9
+ // ------------------------------------------------------------
10
+ // end of CJS compatibility banner, injected by Storybook's esbuild configuration
11
+ // ------------------------------------------------------------
12
+
13
+ // src/transforms/upgrade-deprecated-types.ts
14
+ import {
15
+ SourceEditor,
16
+ removeFromList,
17
+ specifierList,
18
+ storyShapeError,
19
+ walk
20
+ } from "storybook/internal/csf-tools";
21
+ import { logger } from "storybook/internal/node-logger";
22
+ import prettier from "prettier";
23
+ var deprecatedTypes = [
24
+ "ComponentStory",
25
+ "ComponentStoryFn",
26
+ "ComponentStoryObj",
27
+ "ComponentMeta",
28
+ "Story"
29
+ ];
30
+ function migrateType(oldType) {
31
+ return oldType === "Story" || oldType === "ComponentStory" ? "StoryFn" : oldType.replace("Component", "");
32
+ }
33
+ async function transform(info) {
34
+ let editor = new SourceEditor(info.source, info.path);
35
+ upgradeDeprecatedTypes(editor);
36
+ let output = editor.toString();
37
+ try {
38
+ output = await prettier.format(output, {
39
+ ...await prettier.resolveConfig(info.path),
40
+ filepath: info.path
41
+ });
42
+ } catch {
43
+ logger.log(`Failed applying prettier to ${info.path}.`);
44
+ }
45
+ return output;
46
+ }
47
+ var parser = "tsx", importedName = (specifier) => specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier" ? specifier.imported.name : void 0;
48
+ function upgradeDeprecatedTypes(editor) {
49
+ let importedNamespaces = /* @__PURE__ */ new Set(), typeReferencesToUpdate = /* @__PURE__ */ new Set(), existingImports = [];
50
+ for (let statement of editor.program.body) {
51
+ if (statement.type !== "ImportDeclaration")
52
+ continue;
53
+ let { specifiers } = statement;
54
+ if (existingImports.push(
55
+ ...specifiers.map((specifier) => ({
56
+ name: specifier.local.name,
57
+ isAlias: importedName(specifier) !== specifier.local.name,
58
+ node: specifier
59
+ }))
60
+ ), !statement.source.value.startsWith("@storybook"))
61
+ continue;
62
+ let removed = [];
63
+ for (let specifier of specifiers) {
64
+ specifier.type === "ImportNamespaceSpecifier" && importedNamespaces.add(specifier.local.name);
65
+ let imported = importedName(specifier);
66
+ if (specifier.type !== "ImportSpecifier" || !imported || !deprecatedTypes.includes(imported))
67
+ continue;
68
+ imported === specifier.local.name && typeReferencesToUpdate.add(specifier.local.name);
69
+ let newType = migrateType(imported);
70
+ if (!existingImports.some((it) => it.name === newType)) {
71
+ existingImports.push({ name: newType, isAlias: !1, node: specifier }), editor.edits.overwrite(specifier.imported.start, specifier.imported.end, newType);
72
+ continue;
73
+ }
74
+ let existingImport = existingImports.find((it) => it.name === newType && it.isAlias);
75
+ if (existingImport)
76
+ throw storyShapeError(
77
+ `This codemod does not support local imports that are called the same as a storybook import.
78
+ Rename this local import and try again.`,
79
+ existingImport.node,
80
+ editor
81
+ );
82
+ removed.push(specifier);
83
+ }
84
+ removed.length > 0 && removeFromList(editor, specifierList(editor, statement), removed);
85
+ }
86
+ walk(editor.program, (node) => {
87
+ if (node.type !== "TSTypeReference")
88
+ return;
89
+ let { typeName } = node;
90
+ typeName.type === "Identifier" ? typeReferencesToUpdate.has(typeName.name) && editor.edits.overwrite(typeName.start, typeName.end, migrateType(typeName.name)) : (
91
+ // For example SB.StoryObj
92
+ typeName.type === "TSQualifiedName" && typeName.left.type === "Identifier" && importedNamespaces.has(typeName.left.name) && deprecatedTypes.includes(typeName.right.name) && editor.edits.overwrite(
93
+ typeName.right.start,
94
+ typeName.right.end,
95
+ migrateType(typeName.right.name)
96
+ )
97
+ );
98
+ }), editor.commit();
99
+ }
100
+
101
+ export {
102
+ transform,
103
+ parser,
104
+ upgradeDeprecatedTypes
105
+ };
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import CJS_COMPAT_NODE_URL_ppo5qkb13mm from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_ppo5qkb13mm from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_ppo5qkb13mm from "node:module";
1
+ import CJS_COMPAT_NODE_URL_77qkz8uuglf from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_77qkz8uuglf from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_77qkz8uuglf from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_ppo5qkb13mm.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_ppo5qkb13mm.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_ppo5qkb13mm.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_77qkz8uuglf.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_77qkz8uuglf.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_77qkz8uuglf.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
@@ -1,115 +1,107 @@
1
- import CJS_COMPAT_NODE_URL_ppo5qkb13mm from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_ppo5qkb13mm from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_ppo5qkb13mm from "node:module";
1
+ import CJS_COMPAT_NODE_URL_77qkz8uuglf from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_77qkz8uuglf from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_77qkz8uuglf from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_ppo5qkb13mm.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_ppo5qkb13mm.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_ppo5qkb13mm.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_77qkz8uuglf.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_77qkz8uuglf.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_77qkz8uuglf.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
11
11
  // ------------------------------------------------------------
12
12
  import {
13
13
  upgradeDeprecatedTypes
14
- } from "../_node-chunks/chunk-I4FB73AT.js";
14
+ } from "../_node-chunks/chunk-5VYHV7J4.js";
15
15
 
16
16
  // src/transforms/csf-2-to-3.ts
17
- import { core as babel, types as t } from "storybook/internal/babel";
18
- import { loadCsf, printCsf } from "storybook/internal/csf-tools";
17
+ import {
18
+ declaratorList,
19
+ loadCsf,
20
+ placeableTextOf,
21
+ printCsf,
22
+ removeFromList,
23
+ removeStatement,
24
+ walk
25
+ } from "storybook/internal/csf-tools";
19
26
  import { logger } from "storybook/internal/node-logger";
20
27
  import prettier from "prettier";
21
28
  import invariant from "tiny-invariant";
22
- var { isIdentifier, isTSTypeAnnotation, isTSTypeReference } = t, renameAnnotation = (annotation) => annotation === "storyName" ? "name" : annotation, annotationProperties = (annotations) => {
29
+ var renameAnnotation = (annotation) => annotation === "storyName" ? "name" : annotation, annotationProperties = (annotations) => {
23
30
  let fields = /* @__PURE__ */ new Map();
24
31
  for (let [annotation, value] of Object.entries(annotations)) {
25
- if (annotation === "story" && t.isObjectExpression(value)) {
32
+ if (annotation === "story" && value.type === "ObjectExpression") {
26
33
  for (let prop of value.properties)
27
- t.isObjectProperty(prop) && t.isIdentifier(prop.key) && fields.set(prop.key.name, prop.value);
34
+ prop.type === "Property" && prop.key.type === "Identifier" && fields.set(prop.key.name, prop.value);
28
35
  continue;
29
36
  }
30
37
  fields.set(annotation, value);
31
38
  }
32
39
  return [...fields].map(
33
- ([annotation, value]) => t.objectProperty(t.identifier(renameAnnotation(annotation)), value)
40
+ ([annotation, value]) => `${renameAnnotation(annotation)}: ${placeableTextOf(value)}`
34
41
  );
35
- }, getTemplateBindVariable = (init) => t.isCallExpression(init) && t.isMemberExpression(init.callee) && t.isIdentifier(init.callee.object) && t.isIdentifier(init.callee.property) && init.callee.property.name === "bind" && (init.arguments.length === 0 || init.arguments.length === 1 && t.isObjectExpression(init.arguments[0]) && init.arguments[0].properties.length === 0) ? init.callee.object.name : null, isStoryAnnotation = (stmt, objectExports) => t.isExpressionStatement(stmt) && t.isAssignmentExpression(stmt.expression) && t.isMemberExpression(stmt.expression.left) && t.isIdentifier(stmt.expression.left.object) && objectExports[stmt.expression.left.object.name], getNewExport = (stmt, objectExports) => {
36
- if (t.isExportNamedDeclaration(stmt) && t.isVariableDeclaration(stmt.declaration) && stmt.declaration.declarations.length === 1) {
37
- let decl = stmt.declaration.declarations[0];
38
- if (t.isVariableDeclarator(decl) && t.isIdentifier(decl.id))
39
- return objectExports[decl.id.name];
40
- }
41
- return null;
42
- }, isReactGlobalRenderFn = (csf, storyFn) => {
43
- if (csf._meta?.component && t.isArrowFunctionExpression(storyFn) && storyFn.params.length === 1 && t.isJSXElement(storyFn.body)) {
42
+ }, getTemplateBindVariable = (init) => init.type === "CallExpression" && init.callee.type === "MemberExpression" && init.callee.object.type === "Identifier" && init.callee.property.type === "Identifier" && init.callee.property.name === "bind" && (init.arguments.length === 0 || init.arguments.length === 1 && init.arguments[0].type === "ObjectExpression" && init.arguments[0].properties.length === 0) ? init.callee.object.name : null, isStoryAnnotation = (stmt, objectExports) => stmt.type === "ExpressionStatement" && stmt.expression.type === "AssignmentExpression" && stmt.expression.left.type === "MemberExpression" && stmt.expression.left.object.type === "Identifier" && objectExports.has(stmt.expression.left.object.name), isSingleConstExport = (stmt) => stmt?.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" && stmt.declaration.declarations.length === 1, isReactGlobalRenderFn = (csf, storyFn) => {
43
+ if (csf._meta?.component && storyFn?.type === "ArrowFunctionExpression" && storyFn.params.length === 1 && storyFn.body.type === "JSXElement") {
44
44
  let { openingElement } = storyFn.body;
45
- if (openingElement.selfClosing && t.isJSXIdentifier(openingElement.name) && openingElement.attributes.length === 1) {
45
+ if (openingElement.selfClosing && openingElement.name.type === "JSXIdentifier" && openingElement.attributes.length === 1) {
46
46
  let attr = openingElement.attributes[0], param = storyFn.params[0];
47
- if (t.isJSXSpreadAttribute(attr) && t.isIdentifier(attr.argument) && t.isIdentifier(param) && param.name === attr.argument.name && csf._meta.component === openingElement.name.name)
47
+ if (attr.type === "JSXSpreadAttribute" && attr.argument.type === "Identifier" && param.type === "Identifier" && param.name === attr.argument.name && csf._meta.component === openingElement.name.name)
48
48
  return !0;
49
49
  }
50
50
  }
51
51
  return !1;
52
- }, isSimpleCSFStory = (init, annotations) => annotations.length === 0 && t.isArrowFunctionExpression(init) && init.params.length === 0;
53
- function removeUnusedTemplates(csf) {
54
- Object.entries(csf._templates).forEach(([template, templateExpression]) => {
52
+ }, isSimpleCSFStory = (init, annotations) => annotations.length === 0 && init.type === "ArrowFunctionExpression" && init.params.length === 0;
53
+ function removeUnusedTemplates(editor, templates) {
54
+ templates.forEach((template) => {
55
55
  let references = [];
56
- if (babel.traverse(csf._ast, {
57
- Identifier: (path) => {
58
- path.node.name === template && references.push(path);
59
- }
60
- }), references.length === 1) {
61
- let reference = references[0];
62
- reference.parentPath?.isVariableDeclarator() && reference.parentPath.node.init === templateExpression && reference.parentPath.remove();
63
- }
64
- });
56
+ walk(editor.program, (node, parent) => {
57
+ (node.type === "Identifier" || node.type === "JSXIdentifier") && node.name === template && references.push({ node, parent });
58
+ });
59
+ let [reference] = references;
60
+ if (references.length !== 1 || reference.parent?.type !== "VariableDeclarator" || reference.parent.id !== reference.node || !reference.parent.init)
61
+ return;
62
+ let declarator = reference.parent, declaration = editor.parentOf(declarator);
63
+ declaration.declarations.length === 1 ? removeStatement(editor, declaration) : removeFromList(editor, declaratorList(editor, declaration), [declarator]);
64
+ }), editor.commit();
65
65
  }
66
- async function transform(info, api, options) {
67
- let makeTitle = (userTitle) => userTitle || "FIXME", csf = loadCsf(info.source, { makeTitle });
66
+ async function transform(info) {
67
+ if (info.path.endsWith(".svelte"))
68
+ return info.source;
69
+ let makeTitle = (userTitle) => userTitle || "FIXME", csf = loadCsf(info.source, { makeTitle, fileName: info.path });
68
70
  try {
69
71
  csf.parse();
70
72
  } catch (err) {
71
73
  return logger.log(`Error ${err}, skipping`), info.source;
72
74
  }
73
- let file = new babel.File(
74
- { filename: info.path },
75
- { code: info.source, ast: csf._ast }
76
- ), importHelper = new StorybookImportHelper(file, info), objectExports = {};
75
+ let editor = csf.editor, importHelper = new StorybookImportHelper(editor), templates = Object.keys(csf._templates), objectExports = /* @__PURE__ */ new Set();
77
76
  Object.entries(csf._storyExports).forEach(([key, decl]) => {
78
77
  let annotations = annotationProperties(csf._storyAnnotations[key]);
79
- if (t.isVariableDeclarator(decl)) {
80
- let { init, id } = decl;
81
- invariant(init, "Inital value should be declared");
82
- let template = getTemplateBindVariable(init);
83
- if (!t.isArrowFunctionExpression(init) && !template)
84
- return;
85
- if (isSimpleCSFStory(init, annotations)) {
86
- objectExports[key] = t.exportNamedDeclaration(
87
- t.variableDeclaration("const", [
88
- t.variableDeclarator(importHelper.updateTypeTo(id, "StoryFn"), init)
89
- ])
90
- );
91
- return;
92
- }
93
- let storyFn = template ? t.identifier(template) : init, renderAnnotation = isReactGlobalRenderFn(
94
- csf,
95
- template ? csf._templates[template] : storyFn
96
- ) ? [] : [t.objectProperty(t.identifier("render"), storyFn)];
97
- objectExports[key] = t.exportNamedDeclaration(
98
- t.variableDeclaration("const", [
99
- t.variableDeclarator(
100
- importHelper.updateTypeTo(id, "StoryObj"),
101
- t.objectExpression([...renderAnnotation, ...annotations])
102
- )
103
- ])
104
- );
78
+ if (decl.type !== "VariableDeclarator")
79
+ return;
80
+ let { init, id } = decl;
81
+ invariant(init, "Inital value should be declared");
82
+ let template = getTemplateBindVariable(init);
83
+ if (init.type !== "ArrowFunctionExpression" && !template)
84
+ return;
85
+ let replaceExport = isSingleConstExport(csf._storyStatements[key]);
86
+ if (isSimpleCSFStory(init, annotations)) {
87
+ importHelper.updateTypeTo(id, "StoryFn", replaceExport);
88
+ return;
105
89
  }
106
- }), csf._ast.program.body = csf._ast.program.body.reduce((acc, stmt) => {
107
- let statement = stmt;
108
- if (isStoryAnnotation(statement, objectExports))
109
- return acc;
110
- let newExport = getNewExport(statement, objectExports);
111
- return newExport ? (acc.push(newExport), acc) : (acc.push(statement), acc);
112
- }, []), upgradeDeprecatedTypes(file), importHelper.removeDeprecatedStoryImport(), removeUnusedTemplates(csf);
90
+ if (importHelper.updateTypeTo(id, "StoryObj", replaceExport), !replaceExport)
91
+ return;
92
+ objectExports.add(key);
93
+ let properties = [...isReactGlobalRenderFn(csf, template ? csf._templates[template] : init) ? [] : [`render: ${template ?? editor.source(init)}`], ...annotations];
94
+ editor.edits.overwrite(
95
+ init.start,
96
+ init.end,
97
+ properties.length === 0 ? "{}" : `{
98
+ ${properties.map((it) => ` ${it},
99
+ `).join("")}}`
100
+ );
101
+ });
102
+ for (let statement of editor.program.body)
103
+ isStoryAnnotation(statement, objectExports) && removeStatement(editor, statement);
104
+ editor.commit(), upgradeDeprecatedTypes(editor), removeUnusedTemplates(editor, templates);
113
105
  let output = printCsf(csf).code;
114
106
  try {
115
107
  output = await prettier.format(output, {
@@ -121,87 +113,56 @@ async function transform(info, api, options) {
121
113
  }
122
114
  return output;
123
115
  }
124
- var StorybookImportHelper = class {
125
- constructor(file, info) {
126
- this.getAllSbImportDeclarations = (file) => {
127
- let found = [];
128
- return file.path.traverse({
129
- ImportDeclaration: (path) => {
130
- let source = path.node.source.value;
131
- if (source.startsWith("@storybook/csf") || !source.startsWith("@storybook"))
132
- return;
133
- path.get("specifiers").some((specifier) => {
134
- if (specifier.isImportNamespaceSpecifier())
135
- throw new Error(
136
- `This codemod does not support namespace imports for a ${path.node.source.value} package.
137
- Replace the namespace import with named imports and try again.`
138
- );
139
- if (!specifier.isImportSpecifier())
140
- return !1;
141
- let imported = specifier.get("imported");
142
- return Array.isArray(imported) ? imported.some((importedSpecifier) => importedSpecifier.isIdentifier() ? [
143
- "Story",
144
- "StoryFn",
145
- "StoryObj",
146
- "Meta",
147
- "ComponentStory",
148
- "ComponentStoryFn",
149
- "ComponentStoryObj",
150
- "ComponentMeta"
151
- ].includes(importedSpecifier.node.name) : !1) : imported.isIdentifier() ? [
152
- "Story",
153
- "StoryFn",
154
- "StoryObj",
155
- "Meta",
156
- "ComponentStory",
157
- "ComponentStoryFn",
158
- "ComponentStoryObj",
159
- "ComponentMeta"
160
- ].includes(imported.node.name) : !1;
161
- }) && found.push(path);
162
- }
163
- }), found;
164
- };
116
+ var storyTypes = [
117
+ "Story",
118
+ "StoryFn",
119
+ "StoryObj",
120
+ "Meta",
121
+ "ComponentStory",
122
+ "ComponentStoryFn",
123
+ "ComponentStoryObj",
124
+ "ComponentMeta"
125
+ ], StorybookImportHelper = class {
126
+ constructor(editor) {
127
+ this.editor = editor;
128
+ this.addedImports = [];
165
129
  this.getOrAddImport = (type) => {
166
- let sbImport = this.sbImportDeclarations.find((path) => path.node.importKind === "type") ?? this.sbImportDeclarations[0];
130
+ let sbImport = this.sbImportDeclarations.find((it) => it.importKind === "type") ?? this.sbImportDeclarations[0];
167
131
  if (sbImport == null)
168
132
  return;
169
- let specifiers = sbImport.get("specifiers"), importSpecifier = specifiers.find((specifier) => {
170
- if (!specifier.isImportSpecifier())
171
- return !1;
172
- let imported = specifier.get("imported");
173
- return imported.isIdentifier() ? imported.node.name === type : !1;
174
- });
175
- return importSpecifier ? importSpecifier.node.local.name : (specifiers[0].insertBefore(t.importSpecifier(t.identifier(type), t.identifier(type))), type);
176
- };
177
- this.removeDeprecatedStoryImport = () => {
178
- this.sbImportDeclarations.flatMap((it) => it.get("specifiers")).filter((specifier) => {
179
- if (!specifier.isImportSpecifier())
180
- return !1;
181
- let imported = specifier.get("imported");
182
- return imported.isIdentifier() ? imported.node.name === "Story" : !1;
183
- }).forEach((path) => path.remove());
133
+ let importSpecifier = sbImport.specifiers.find(
134
+ (specifier) => specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier" && specifier.imported.name === type
135
+ );
136
+ return importSpecifier ? importSpecifier.local.name : (this.addedImports.includes(type) || (this.addedImports.push(type), this.editor.edits.appendLeft(sbImport.specifiers[0].start, `${type}, `)), type);
184
137
  };
185
- this.getAllLocalImports = () => this.sbImportDeclarations.flatMap((it) => it.get("specifiers")).map((it) => it.node.local.name);
186
- this.updateTypeTo = (id, type) => {
187
- if (isIdentifier(id) && isTSTypeAnnotation(id.typeAnnotation) && isTSTypeReference(id.typeAnnotation.typeAnnotation) && isIdentifier(id.typeAnnotation.typeAnnotation.typeName)) {
188
- let { name } = id.typeAnnotation.typeAnnotation.typeName;
189
- if (this.getAllLocalImports().includes(name)) {
190
- let localTypeImport = this.getOrAddImport(type);
191
- return {
192
- ...id,
193
- typeAnnotation: t.tsTypeAnnotation(
194
- t.tsTypeReference(
195
- t.identifier(localTypeImport ?? ""),
196
- id.typeAnnotation.typeAnnotation.typeParameters
197
- )
198
- )
199
- };
200
- }
138
+ this.getAllLocalImports = () => [
139
+ ...this.sbImportDeclarations.flatMap((it) => it.specifiers).map((it) => it.local.name),
140
+ ...this.addedImports
141
+ ];
142
+ this.updateTypeTo = (id, type, apply) => {
143
+ if (id.type !== "Identifier")
144
+ return;
145
+ let annotation = id.typeAnnotation?.typeAnnotation;
146
+ if (annotation?.type === "TSTypeReference" && annotation.typeName.type === "Identifier" && this.getAllLocalImports().includes(annotation.typeName.name) && apply) {
147
+ let localTypeImport = this.getOrAddImport(type), { typeName } = annotation;
148
+ this.editor.edits.overwrite(typeName.start, typeName.end, localTypeImport ?? "");
201
149
  }
202
- return id;
203
150
  };
204
- this.sbImportDeclarations = this.getAllSbImportDeclarations(file);
151
+ this.sbImportDeclarations = editor.program.body.filter(
152
+ (statement) => {
153
+ if (statement.type !== "ImportDeclaration")
154
+ return !1;
155
+ let source = statement.source.value;
156
+ return source.startsWith("@storybook/csf") || !source.startsWith("@storybook") ? !1 : statement.specifiers.some((specifier) => {
157
+ if (specifier.type === "ImportNamespaceSpecifier")
158
+ throw new Error(
159
+ `This codemod does not support namespace imports for a ${source} package.
160
+ Replace the namespace import with named imports and try again.`
161
+ );
162
+ return specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier" && storyTypes.includes(specifier.imported.name);
163
+ });
164
+ }
165
+ );
205
166
  }
206
167
  }, parser = "tsx";
207
168
  export {
@@ -1,73 +1,44 @@
1
- import CJS_COMPAT_NODE_URL_ppo5qkb13mm from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_ppo5qkb13mm from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_ppo5qkb13mm from "node:module";
1
+ import CJS_COMPAT_NODE_URL_77qkz8uuglf from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_77qkz8uuglf from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_77qkz8uuglf from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_ppo5qkb13mm.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_ppo5qkb13mm.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_ppo5qkb13mm.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_77qkz8uuglf.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_77qkz8uuglf.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_77qkz8uuglf.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
11
11
  // ------------------------------------------------------------
12
12
 
13
13
  // src/transforms/find-implicit-spies.ts
14
- import { core as babel, types as t } from "storybook/internal/babel";
15
- import { loadCsf } from "storybook/internal/csf-tools";
16
- function findImplicitSpies(path, file, keys) {
17
- path.traverse({
18
- Identifier: (identifier) => {
19
- !keys.includes(identifier.node.name) && /^on[A-Z].*/.test(identifier.node.name) && console.warn(identifier.buildCodeFrameError(`${file} Possible implicit spy found`).message);
20
- }
14
+ import {
15
+ loadCsf,
16
+ storyShapeError,
17
+ walk
18
+ } from "storybook/internal/csf-tools";
19
+ function findImplicitSpies(editor, node, keys) {
20
+ walk(node, (identifier) => {
21
+ identifier.type === "Identifier" && !keys.includes(identifier.name) && /^on[A-Z].*/.test(identifier.name) && console.warn(storyShapeError("Possible implicit spy found", identifier, editor).message);
21
22
  });
22
23
  }
23
- function getAnnotationKeys(file, storyName, annotationName) {
24
- let argKeys = [];
25
- return file.path.traverse({
26
- // CSF2 play function Story.args =
27
- AssignmentExpression: (path) => {
28
- let left = path.get("left");
29
- if (!left.isMemberExpression())
30
- return;
31
- let object = left.get("object");
32
- if (!(object.isIdentifier() && object.node.name === storyName))
33
- return;
34
- let property = left.get("property"), right = path.get("right");
35
- property.isIdentifier() && property.node.name === annotationName && right.isObjectExpression() && argKeys.push(
36
- ...right.node.properties.flatMap(
37
- (value) => t.isObjectProperty(value) && t.isIdentifier(value.key) ? [value.key.name] : []
38
- )
39
- );
40
- },
41
- // CSF3 const Story = {args: () => {} };
42
- VariableDeclarator: (path) => {
43
- let id = path.get("id"), init = path.get("init");
44
- if (!(id.isIdentifier() && id.node.name === storyName) || !init.isObjectExpression())
45
- return;
46
- let args = init.get("properties").flatMap((it) => it.isObjectProperty() ? [it] : []).find((it) => {
47
- let argKey = it.get("key");
48
- return argKey.isIdentifier() && argKey.node.name === annotationName;
49
- });
50
- if (!args)
51
- return;
52
- let argsValue = args.get("value");
53
- !argsValue || !argsValue.isObjectExpression() || argKeys.push(
54
- ...argsValue.node.properties.flatMap(
55
- (value) => t.isObjectProperty(value) && t.isIdentifier(value.key) ? [value.key.name] : []
56
- )
57
- );
24
+ var getObjectExpressionKeys = (node) => node?.type === "ObjectExpression" ? node.properties.flatMap(
25
+ (value) => value.type === "Property" && !value.method && value.key.type === "Identifier" ? [value.key.name] : []
26
+ ) : [], findProperty = (object, name) => object.properties.find(
27
+ (it) => it.type === "Property" && !it.method && it.key.type === "Identifier" && it.key.name === name
28
+ );
29
+ function findAnnotations(program, storyName, annotationName) {
30
+ let values = [];
31
+ return walk(program, (node) => {
32
+ if (node.type === "AssignmentExpression" && node.left.type === "MemberExpression" && node.left.object.type === "Identifier" && node.left.object.name === storyName && node.left.property.type === "Identifier" && node.left.property.name === annotationName && values.push(node.right), node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.id.name === storyName && node.init?.type === "ObjectExpression") {
33
+ let property = findProperty(node.init, annotationName);
34
+ property && values.push(property.value);
58
35
  }
59
- }), argKeys;
36
+ }), values;
60
37
  }
61
- var getObjectExpressionKeys = (node) => t.isObjectExpression(node) ? node.properties.flatMap(
62
- (value) => t.isObjectProperty(value) && t.isIdentifier(value.key) ? [value.key.name] : []
63
- ) : [];
64
38
  async function transform(info) {
65
- let csf = loadCsf(info.source, { makeTitle: (title) => title }), fileNode = csf._ast, file = new babel.File(
66
- { filename: info.path },
67
- { code: info.source, ast: fileNode }
68
- );
39
+ let csf = loadCsf(info.source, { makeTitle: (title) => title, fileName: info.path });
69
40
  csf.parse();
70
- let metaKeys = [
41
+ let editor = csf.editor, metaKeys = [
71
42
  ...getObjectExpressionKeys(csf._metaAnnotations.args),
72
43
  ...getObjectExpressionKeys(csf._metaAnnotations.argTypes)
73
44
  ];
@@ -76,31 +47,13 @@ async function transform(info) {
76
47
  return;
77
48
  let allKeys = [
78
49
  ...metaKeys,
79
- ...getAnnotationKeys(file, name, "args"),
80
- ...getAnnotationKeys(file, name, "argTypes")
50
+ ...findAnnotations(editor.program, name, "args").flatMap(getObjectExpressionKeys),
51
+ ...findAnnotations(editor.program, name, "argTypes").flatMap(getObjectExpressionKeys)
81
52
  ];
82
- file.path.traverse({
83
- // CSF2 play function Story.play =
84
- AssignmentExpression: (path) => {
85
- let left = path.get("left");
86
- if (!left.isMemberExpression())
87
- return;
88
- let object = left.get("object");
89
- if (!(object.isIdentifier() && object.node.name === name))
90
- return;
91
- let property = left.get("property");
92
- property.isIdentifier() && property.node.name === "play" && findImplicitSpies(path, info.path, allKeys);
93
- },
94
- // CSF3 play function: const Story = {play: () => {} };
95
- VariableDeclarator: (path) => {
96
- let id = path.get("id"), init = path.get("init");
97
- if (!(id.isIdentifier() && id.node.name === name) || !init.isObjectExpression())
98
- return;
99
- let play = init.get("properties").flatMap((it) => it.isObjectProperty() ? [it] : []).find((it) => {
100
- let argKey = it.get("key");
101
- return argKey.isIdentifier() && argKey.node.name === "play";
102
- });
103
- play && findImplicitSpies(play, info.path, allKeys);
53
+ walk(editor.program, (node) => {
54
+ if (node.type === "AssignmentExpression" && node.left.type === "MemberExpression" && node.left.object.type === "Identifier" && node.left.object.name === name && node.left.property.type === "Identifier" && node.left.property.name === "play" && findImplicitSpies(editor, node, allKeys), node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.id.name === name && node.init?.type === "ObjectExpression") {
55
+ let play = findProperty(node.init, "play");
56
+ play && findImplicitSpies(editor, play, allKeys);
104
57
  }
105
58
  });
106
59
  });
@@ -1,10 +1,10 @@
1
- import CJS_COMPAT_NODE_URL_ppo5qkb13mm from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_ppo5qkb13mm from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_ppo5qkb13mm from "node:module";
1
+ import CJS_COMPAT_NODE_URL_77qkz8uuglf from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_77qkz8uuglf from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_77qkz8uuglf from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_ppo5qkb13mm.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_ppo5qkb13mm.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_ppo5qkb13mm.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_77qkz8uuglf.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_77qkz8uuglf.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_77qkz8uuglf.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
@@ -13,7 +13,7 @@ import {
13
13
  parser,
14
14
  transform,
15
15
  upgradeDeprecatedTypes
16
- } from "../_node-chunks/chunk-I4FB73AT.js";
16
+ } from "../_node-chunks/chunk-5VYHV7J4.js";
17
17
  export {
18
18
  transform as default,
19
19
  parser,
@@ -1,10 +1,10 @@
1
- import CJS_COMPAT_NODE_URL_ppo5qkb13mm from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_ppo5qkb13mm from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_ppo5qkb13mm from "node:module";
1
+ import CJS_COMPAT_NODE_URL_77qkz8uuglf from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_77qkz8uuglf from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_77qkz8uuglf from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_ppo5qkb13mm.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_ppo5qkb13mm.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_ppo5qkb13mm.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_77qkz8uuglf.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_77qkz8uuglf.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_77qkz8uuglf.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/codemod",
3
- "version": "11.0.0-alpha.7",
3
+ "version": "11.0.0-alpha.8",
4
4
  "description": "A collection of codemod scripts written with JSCodeshift",
5
5
  "keywords": [
6
6
  "storybook"
@@ -46,7 +46,7 @@
46
46
  "es-toolkit": "^1.43.0",
47
47
  "jscodeshift": "^17.4.0",
48
48
  "prettier": "^3.7.1",
49
- "storybook": "11.0.0-alpha.7",
49
+ "storybook": "11.0.0-alpha.8",
50
50
  "tiny-invariant": "^1.3.1",
51
51
  "tinyglobby": "^0.2.13"
52
52
  },
@@ -1,97 +0,0 @@
1
- import CJS_COMPAT_NODE_URL_ppo5qkb13mm from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_ppo5qkb13mm from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_ppo5qkb13mm from "node:module";
4
-
5
- var __filename = CJS_COMPAT_NODE_URL_ppo5qkb13mm.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_ppo5qkb13mm.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_ppo5qkb13mm.createRequire(import.meta.url);
8
-
9
- // ------------------------------------------------------------
10
- // end of CJS compatibility banner, injected by Storybook's esbuild configuration
11
- // ------------------------------------------------------------
12
-
13
- // src/transforms/upgrade-deprecated-types.ts
14
- import { core as babel, types as t } from "storybook/internal/babel";
15
- import { loadCsf, printCsf } from "storybook/internal/csf-tools";
16
- import { logger } from "storybook/internal/node-logger";
17
- import prettier from "prettier";
18
- var deprecatedTypes = [
19
- "ComponentStory",
20
- "ComponentStoryFn",
21
- "ComponentStoryObj",
22
- "ComponentMeta",
23
- "Story"
24
- ];
25
- function migrateType(oldType) {
26
- return oldType === "Story" || oldType === "ComponentStory" ? "StoryFn" : oldType.replace("Component", "");
27
- }
28
- async function transform(info, api, options) {
29
- let csf = loadCsf(info.source, { makeTitle: (title) => title }), fileNode = csf._ast, file = new babel.File(
30
- { filename: info.path },
31
- { code: info.source, ast: fileNode }
32
- );
33
- upgradeDeprecatedTypes(file);
34
- let output = printCsf(csf).code;
35
- try {
36
- output = await prettier.format(output, {
37
- ...await prettier.resolveConfig(info.path),
38
- filepath: info.path
39
- });
40
- } catch {
41
- logger.log(`Failed applying prettier to ${info.path}.`);
42
- }
43
- return output;
44
- }
45
- var parser = "tsx";
46
- function upgradeDeprecatedTypes(file) {
47
- let importedNamespaces = /* @__PURE__ */ new Set(), typeReferencesToUpdate = /* @__PURE__ */ new Set(), existingImports = [];
48
- file.path.traverse({
49
- ImportDeclaration: (path) => {
50
- existingImports.push(
51
- ...path.get("specifiers").map((specifier) => ({
52
- name: specifier.node.local.name,
53
- isAlias: !(specifier.isImportSpecifier() && t.isIdentifier(specifier.node.imported) && specifier.node.local.name === specifier.node.imported.name),
54
- path: specifier
55
- }))
56
- ), path.node.source.value.startsWith("@storybook") && path.get("specifiers").forEach((specifier) => {
57
- if (specifier.isImportNamespaceSpecifier() && importedNamespaces.add(specifier.node.local.name), !specifier.isImportSpecifier())
58
- return;
59
- let imported = specifier.get("imported");
60
- if (imported.isIdentifier() && deprecatedTypes.includes(imported.node.name)) {
61
- imported.node.name === specifier.node.local.name && typeReferencesToUpdate.add(specifier.node.local.name);
62
- let newType = migrateType(imported.node.name);
63
- if (!existingImports.some((it) => it.name === newType))
64
- imported.replaceWith(t.identifier(newType)), existingImports.push({ name: newType, isAlias: !1, path: specifier });
65
- else {
66
- let existingImport = existingImports.find((it) => it.name === newType && it.isAlias);
67
- if (existingImport)
68
- throw existingImport.path.buildCodeFrameError(
69
- `This codemod does not support local imports that are called the same as a storybook import.
70
- Rename this local import and try again.`
71
- );
72
- specifier.remove();
73
- }
74
- }
75
- });
76
- }
77
- }), file.path.traverse({
78
- TSTypeReference: (path) => {
79
- let typeName = path.get("typeName");
80
- if (typeName.isIdentifier())
81
- typeReferencesToUpdate.has(typeName.node.name) && typeName.replaceWith(t.identifier(migrateType(typeName.node.name)));
82
- else if (typeName.isTSQualifiedName()) {
83
- let namespace = typeName.get("left");
84
- if (namespace.isIdentifier() && importedNamespaces.has(namespace.node.name)) {
85
- let right = typeName.get("right");
86
- deprecatedTypes.includes(right.node.name) && right.replaceWith(t.identifier(migrateType(right.node.name)));
87
- }
88
- }
89
- }
90
- });
91
- }
92
-
93
- export {
94
- transform,
95
- parser,
96
- upgradeDeprecatedTypes
97
- };