UNPKG

@storybook/codemod

Version:

A collection of codemod scripts written with JSCodeshift

98 lines (93 loc) 4.17 kB
import CJS_COMPAT_NODE_URL_94b6aurt4b from 'node:url'; import CJS_COMPAT_NODE_PATH_94b6aurt4b from 'node:path'; import CJS_COMPAT_NODE_MODULE_94b6aurt4b from "node:module"; var __filename = CJS_COMPAT_NODE_URL_94b6aurt4b.fileURLToPath(import.meta.url); var __dirname = CJS_COMPAT_NODE_PATH_94b6aurt4b.dirname(__filename); var require = CJS_COMPAT_NODE_MODULE_94b6aurt4b.createRequire(import.meta.url); // ------------------------------------------------------------ // end of CJS compatibility banner, injected by Storybook's esbuild configuration // ------------------------------------------------------------ // src/transforms/upgrade-deprecated-types.ts import { core as babel, types as t } from "storybook/internal/babel"; import { loadCsf, printCsf } from "storybook/internal/csf-tools"; import { logger } from "storybook/internal/node-logger"; import prettier from "prettier"; var deprecatedTypes = [ "ComponentStory", "ComponentStoryFn", "ComponentStoryObj", "ComponentMeta", "Story" ]; function migrateType(oldType) { return oldType === "Story" || oldType === "ComponentStory" ? "StoryFn" : oldType.replace("Component", ""); } async function transform(info, api, options) { let csf = loadCsf(info.source, { makeTitle: (title) => title }), fileNode = csf._ast, file = new babel.File( { filename: info.path }, { code: info.source, ast: fileNode } ); upgradeDeprecatedTypes(file); let output = printCsf(csf).code; try { output = await prettier.format(output, { ...await prettier.resolveConfig(info.path), filepath: info.path }); } catch { logger.log(`Failed applying prettier to ${info.path}.`); } return output; } var parser = "tsx"; function upgradeDeprecatedTypes(file) { let importedNamespaces = /* @__PURE__ */ new Set(), typeReferencesToUpdate = /* @__PURE__ */ new Set(), existingImports = []; file.path.traverse({ ImportDeclaration: (path) => { existingImports.push( ...path.get("specifiers").map((specifier) => ({ name: specifier.node.local.name, isAlias: !(specifier.isImportSpecifier() && t.isIdentifier(specifier.node.imported) && specifier.node.local.name === specifier.node.imported.name), path: specifier })) ), path.node.source.value.startsWith("@storybook") && path.get("specifiers").forEach((specifier) => { if (specifier.isImportNamespaceSpecifier() && importedNamespaces.add(specifier.node.local.name), !specifier.isImportSpecifier()) return; let imported = specifier.get("imported"); if (imported.isIdentifier() && deprecatedTypes.includes(imported.node.name)) { imported.node.name === specifier.node.local.name && typeReferencesToUpdate.add(specifier.node.local.name); let newType = migrateType(imported.node.name); if (!existingImports.some((it) => it.name === newType)) imported.replaceWith(t.identifier(newType)), existingImports.push({ name: newType, isAlias: !1, path: specifier }); else { let existingImport = existingImports.find((it) => it.name === newType && it.isAlias); if (existingImport) throw existingImport.path.buildCodeFrameError( `This codemod does not support local imports that are called the same as a storybook import. Rename this local import and try again.` ); specifier.remove(); } } }); } }), file.path.traverse({ TSTypeReference: (path) => { let typeName = path.get("typeName"); if (typeName.isIdentifier()) typeReferencesToUpdate.has(typeName.node.name) && typeName.replaceWith(t.identifier(migrateType(typeName.node.name))); else if (typeName.isTSQualifiedName()) { let namespace = typeName.get("left"); if (namespace.isIdentifier() && importedNamespaces.has(namespace.node.name)) { let right = typeName.get("right"); deprecatedTypes.includes(right.node.name) && right.replaceWith(t.identifier(migrateType(right.node.name))); } } } }); } export { transform, parser, upgradeDeprecatedTypes };