@storybook/codemod 11.0.0-alpha.6 → 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.
- package/dist/_node-chunks/chunk-5VYHV7J4.js +105 -0
- package/dist/index.js +6 -6
- package/dist/transforms/csf-2-to-3.js +120 -146
- package/dist/transforms/find-implicit-spies.js +34 -81
- package/dist/transforms/upgrade-deprecated-types.js +7 -7
- package/dist/transforms/upgrade-hierarchy-separators.js +6 -6
- package/package.json +2 -2
- package/dist/_node-chunks/chunk-U2DCYCQL.js +0 -97
|
@@ -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
|
|
2
|
-
import
|
|
3
|
-
import
|
|
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 =
|
|
6
|
-
var __dirname =
|
|
7
|
-
var require =
|
|
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,102 +1,107 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
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 =
|
|
6
|
-
var __dirname =
|
|
7
|
-
var require =
|
|
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-
|
|
14
|
+
} from "../_node-chunks/chunk-5VYHV7J4.js";
|
|
15
15
|
|
|
16
16
|
// src/transforms/csf-2-to-3.ts
|
|
17
|
-
import {
|
|
18
|
-
|
|
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
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (
|
|
26
|
-
|
|
29
|
+
var renameAnnotation = (annotation) => annotation === "storyName" ? "name" : annotation, annotationProperties = (annotations) => {
|
|
30
|
+
let fields = /* @__PURE__ */ new Map();
|
|
31
|
+
for (let [annotation, value] of Object.entries(annotations)) {
|
|
32
|
+
if (annotation === "story" && value.type === "ObjectExpression") {
|
|
33
|
+
for (let prop of value.properties)
|
|
34
|
+
prop.type === "Property" && prop.key.type === "Identifier" && fields.set(prop.key.name, prop.value);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
fields.set(annotation, value);
|
|
27
38
|
}
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
return [...fields].map(
|
|
40
|
+
([annotation, value]) => `${renameAnnotation(annotation)}: ${placeableTextOf(value)}`
|
|
41
|
+
);
|
|
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") {
|
|
31
44
|
let { openingElement } = storyFn.body;
|
|
32
|
-
if (openingElement.selfClosing &&
|
|
45
|
+
if (openingElement.selfClosing && openingElement.name.type === "JSXIdentifier" && openingElement.attributes.length === 1) {
|
|
33
46
|
let attr = openingElement.attributes[0], param = storyFn.params[0];
|
|
34
|
-
if (
|
|
47
|
+
if (attr.type === "JSXSpreadAttribute" && attr.argument.type === "Identifier" && param.type === "Identifier" && param.name === attr.argument.name && csf._meta.component === openingElement.name.name)
|
|
35
48
|
return !0;
|
|
36
49
|
}
|
|
37
50
|
}
|
|
38
51
|
return !1;
|
|
39
|
-
}, isSimpleCSFStory = (init, annotations) => annotations.length === 0 &&
|
|
40
|
-
function removeUnusedTemplates(
|
|
41
|
-
|
|
52
|
+
}, isSimpleCSFStory = (init, annotations) => annotations.length === 0 && init.type === "ArrowFunctionExpression" && init.params.length === 0;
|
|
53
|
+
function removeUnusedTemplates(editor, templates) {
|
|
54
|
+
templates.forEach((template) => {
|
|
42
55
|
let references = [];
|
|
43
|
-
|
|
44
|
-
Identifier
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
});
|
|
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();
|
|
52
65
|
}
|
|
53
|
-
async function transform(info
|
|
54
|
-
|
|
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 });
|
|
55
70
|
try {
|
|
56
71
|
csf.parse();
|
|
57
72
|
} catch (err) {
|
|
58
73
|
return logger.log(`Error ${err}, skipping`), info.source;
|
|
59
74
|
}
|
|
60
|
-
let
|
|
61
|
-
{ filename: info.path },
|
|
62
|
-
{ code: info.source, ast: csf._ast }
|
|
63
|
-
), importHelper = new StorybookImportHelper(file, info), objectExports = {};
|
|
75
|
+
let editor = csf.editor, importHelper = new StorybookImportHelper(editor), templates = Object.keys(csf._templates), objectExports = /* @__PURE__ */ new Set();
|
|
64
76
|
Object.entries(csf._storyExports).forEach(([key, decl]) => {
|
|
65
|
-
let annotations =
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
let storyFn = template ? t.identifier(template) : init, renderAnnotation = isReactGlobalRenderFn(
|
|
81
|
-
csf,
|
|
82
|
-
template ? csf._templates[template] : storyFn
|
|
83
|
-
) ? [] : [t.objectProperty(t.identifier("render"), storyFn)];
|
|
84
|
-
objectExports[key] = t.exportNamedDeclaration(
|
|
85
|
-
t.variableDeclaration("const", [
|
|
86
|
-
t.variableDeclarator(
|
|
87
|
-
importHelper.updateTypeTo(id, "StoryObj"),
|
|
88
|
-
t.objectExpression([...renderAnnotation, ...annotations])
|
|
89
|
-
)
|
|
90
|
-
])
|
|
91
|
-
);
|
|
77
|
+
let annotations = annotationProperties(csf._storyAnnotations[key]);
|
|
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;
|
|
92
89
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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);
|
|
100
105
|
let output = printCsf(csf).code;
|
|
101
106
|
try {
|
|
102
107
|
output = await prettier.format(output, {
|
|
@@ -108,87 +113,56 @@ async function transform(info, api, options) {
|
|
|
108
113
|
}
|
|
109
114
|
return output;
|
|
110
115
|
}
|
|
111
|
-
var
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
Replace the namespace import with named imports and try again.`
|
|
125
|
-
);
|
|
126
|
-
if (!specifier.isImportSpecifier())
|
|
127
|
-
return !1;
|
|
128
|
-
let imported = specifier.get("imported");
|
|
129
|
-
return Array.isArray(imported) ? imported.some((importedSpecifier) => importedSpecifier.isIdentifier() ? [
|
|
130
|
-
"Story",
|
|
131
|
-
"StoryFn",
|
|
132
|
-
"StoryObj",
|
|
133
|
-
"Meta",
|
|
134
|
-
"ComponentStory",
|
|
135
|
-
"ComponentStoryFn",
|
|
136
|
-
"ComponentStoryObj",
|
|
137
|
-
"ComponentMeta"
|
|
138
|
-
].includes(importedSpecifier.node.name) : !1) : imported.isIdentifier() ? [
|
|
139
|
-
"Story",
|
|
140
|
-
"StoryFn",
|
|
141
|
-
"StoryObj",
|
|
142
|
-
"Meta",
|
|
143
|
-
"ComponentStory",
|
|
144
|
-
"ComponentStoryFn",
|
|
145
|
-
"ComponentStoryObj",
|
|
146
|
-
"ComponentMeta"
|
|
147
|
-
].includes(imported.node.name) : !1;
|
|
148
|
-
}) && found.push(path);
|
|
149
|
-
}
|
|
150
|
-
}), found;
|
|
151
|
-
};
|
|
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 = [];
|
|
152
129
|
this.getOrAddImport = (type) => {
|
|
153
|
-
let sbImport = this.sbImportDeclarations.find((
|
|
130
|
+
let sbImport = this.sbImportDeclarations.find((it) => it.importKind === "type") ?? this.sbImportDeclarations[0];
|
|
154
131
|
if (sbImport == null)
|
|
155
132
|
return;
|
|
156
|
-
let
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return imported.isIdentifier() ? imported.node.name === type : !1;
|
|
161
|
-
});
|
|
162
|
-
return importSpecifier ? importSpecifier.node.local.name : (specifiers[0].insertBefore(t.importSpecifier(t.identifier(type), t.identifier(type))), type);
|
|
163
|
-
};
|
|
164
|
-
this.removeDeprecatedStoryImport = () => {
|
|
165
|
-
this.sbImportDeclarations.flatMap((it) => it.get("specifiers")).filter((specifier) => {
|
|
166
|
-
if (!specifier.isImportSpecifier())
|
|
167
|
-
return !1;
|
|
168
|
-
let imported = specifier.get("imported");
|
|
169
|
-
return imported.isIdentifier() ? imported.node.name === "Story" : !1;
|
|
170
|
-
}).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);
|
|
171
137
|
};
|
|
172
|
-
this.getAllLocalImports = () =>
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
id.typeAnnotation.typeAnnotation.typeParameters
|
|
184
|
-
)
|
|
185
|
-
)
|
|
186
|
-
};
|
|
187
|
-
}
|
|
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 ?? "");
|
|
188
149
|
}
|
|
189
|
-
return id;
|
|
190
150
|
};
|
|
191
|
-
this.sbImportDeclarations =
|
|
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
|
+
);
|
|
192
166
|
}
|
|
193
167
|
}, parser = "tsx";
|
|
194
168
|
export {
|
|
@@ -1,73 +1,44 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
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 =
|
|
6
|
-
var __dirname =
|
|
7
|
-
var require =
|
|
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 {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
}),
|
|
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
|
|
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
|
-
...
|
|
80
|
-
...
|
|
50
|
+
...findAnnotations(editor.program, name, "args").flatMap(getObjectExpressionKeys),
|
|
51
|
+
...findAnnotations(editor.program, name, "argTypes").flatMap(getObjectExpressionKeys)
|
|
81
52
|
];
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
|
2
|
-
import
|
|
3
|
-
import
|
|
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 =
|
|
6
|
-
var __dirname =
|
|
7
|
-
var require =
|
|
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-
|
|
16
|
+
} from "../_node-chunks/chunk-5VYHV7J4.js";
|
|
17
17
|
export {
|
|
18
18
|
transform as default,
|
|
19
19
|
parser,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
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 =
|
|
6
|
-
var __dirname =
|
|
7
|
-
var require =
|
|
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.
|
|
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.
|
|
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_twc5b3qu43j from 'node:url';
|
|
2
|
-
import CJS_COMPAT_NODE_PATH_twc5b3qu43j from 'node:path';
|
|
3
|
-
import CJS_COMPAT_NODE_MODULE_twc5b3qu43j from "node:module";
|
|
4
|
-
|
|
5
|
-
var __filename = CJS_COMPAT_NODE_URL_twc5b3qu43j.fileURLToPath(import.meta.url);
|
|
6
|
-
var __dirname = CJS_COMPAT_NODE_PATH_twc5b3qu43j.dirname(__filename);
|
|
7
|
-
var require = CJS_COMPAT_NODE_MODULE_twc5b3qu43j.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
|
-
};
|