UNPKG

@storybook/codemod

Version:

A collection of codemod scripts written with JSCodeshift

113 lines (109 loc) 4.58 kB
import CJS_COMPAT_NODE_URL_9n6kaelwkiq from 'node:url'; import CJS_COMPAT_NODE_PATH_9n6kaelwkiq from 'node:path'; import CJS_COMPAT_NODE_MODULE_9n6kaelwkiq from "node:module"; var __filename = CJS_COMPAT_NODE_URL_9n6kaelwkiq.fileURLToPath(import.meta.url); var __dirname = CJS_COMPAT_NODE_PATH_9n6kaelwkiq.dirname(__filename); var require = CJS_COMPAT_NODE_MODULE_9n6kaelwkiq.createRequire(import.meta.url); // ------------------------------------------------------------ // end of CJS compatibility banner, injected by Storybook's esbuild configuration // ------------------------------------------------------------ // src/transforms/find-implicit-spies.ts import { core as babel, types as t } from "storybook/internal/babel"; import { loadCsf } from "storybook/internal/csf-tools"; function findImplicitSpies(path, file, keys) { path.traverse({ Identifier: (identifier) => { !keys.includes(identifier.node.name) && /^on[A-Z].*/.test(identifier.node.name) && console.warn(identifier.buildCodeFrameError(`${file} Possible implicit spy found`).message); } }); } function getAnnotationKeys(file, storyName, annotationName) { let argKeys = []; return file.path.traverse({ // CSF2 play function Story.args = AssignmentExpression: (path) => { let left = path.get("left"); if (!left.isMemberExpression()) return; let object = left.get("object"); if (!(object.isIdentifier() && object.node.name === storyName)) return; let property = left.get("property"), right = path.get("right"); property.isIdentifier() && property.node.name === annotationName && right.isObjectExpression() && argKeys.push( ...right.node.properties.flatMap( (value) => t.isObjectProperty(value) && t.isIdentifier(value.key) ? [value.key.name] : [] ) ); }, // CSF3 const Story = {args: () => {} }; VariableDeclarator: (path) => { let id = path.get("id"), init = path.get("init"); if (!(id.isIdentifier() && id.node.name === storyName) || !init.isObjectExpression()) return; let args = init.get("properties").flatMap((it) => it.isObjectProperty() ? [it] : []).find((it) => { let argKey = it.get("key"); return argKey.isIdentifier() && argKey.node.name === annotationName; }); if (!args) return; let argsValue = args.get("value"); !argsValue || !argsValue.isObjectExpression() || argKeys.push( ...argsValue.node.properties.flatMap( (value) => t.isObjectProperty(value) && t.isIdentifier(value.key) ? [value.key.name] : [] ) ); } }), argKeys; } var getObjectExpressionKeys = (node) => t.isObjectExpression(node) ? node.properties.flatMap( (value) => t.isObjectProperty(value) && t.isIdentifier(value.key) ? [value.key.name] : [] ) : []; async function transform(info) { let csf = loadCsf(info.source, { makeTitle: (title) => title }), fileNode = csf._ast, file = new babel.File( { filename: info.path }, { code: info.source, ast: fileNode } ); csf.parse(); let metaKeys = [ ...getObjectExpressionKeys(csf._metaAnnotations.args), ...getObjectExpressionKeys(csf._metaAnnotations.argTypes) ]; Object.values(csf.stories).forEach(({ name }) => { if (!name) return; let allKeys = [ ...metaKeys, ...getAnnotationKeys(file, name, "args"), ...getAnnotationKeys(file, name, "argTypes") ]; file.path.traverse({ // CSF2 play function Story.play = AssignmentExpression: (path) => { let left = path.get("left"); if (!left.isMemberExpression()) return; let object = left.get("object"); if (!(object.isIdentifier() && object.node.name === name)) return; let property = left.get("property"); property.isIdentifier() && property.node.name === "play" && findImplicitSpies(path, info.path, allKeys); }, // CSF3 play function: const Story = {play: () => {} }; VariableDeclarator: (path) => { let id = path.get("id"), init = path.get("init"); if (!(id.isIdentifier() && id.node.name === name) || !init.isObjectExpression()) return; let play = init.get("properties").flatMap((it) => it.isObjectProperty() ? [it] : []).find((it) => { let argKey = it.get("key"); return argKey.isIdentifier() && argKey.node.name === "play"; }); play && findImplicitSpies(play, info.path, allKeys); } }); }); } var parser = "tsx"; export { transform as default, parser };