@storybook/codemod 7.0.0-rc.1 → 7.0.0-rc.3

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.
@@ -49,7 +49,7 @@ Defaulting to 2020, but this will stop working in the future.`)),options.ecmaVer
49
49
  `),map3)):attributesOnOneLine&&(value+=tracker.move(" "+attributesOnOneLine)),attributesOnTheirOwnLine&&(value+=tracker.move(`
50
50
  `)),selfClosing&&(value+=tracker.move((tightSelfClosing||attributesOnTheirOwnLine?"":" ")+"/")),value+=tracker.move(">"),node3.children&&node3.children.length>0&&(node3.type==="mdxJsxFlowElement"?(tracker.shift(2),value+=tracker.move(`
51
51
  `),value+=tracker.move(indentLines(containerFlow(node3,context,tracker.current()),map3)),value+=tracker.move(`
52
- `)):value+=tracker.move(containerPhrasing(node3,context,{...tracker.current(),before:"<",after:">"}))),selfClosing||(value+=tracker.move("</"+(node3.name||"")+">")),exit2(),value}function map3(line,_,blank){return(blank?"":" ")+line}function peekElement(){return"<"}}var mdxjsEsmFromMarkdown={enter:{mdxjsEsm:enterMdxjsEsm},exit:{mdxjsEsm:exitMdxjsEsm,mdxjsEsmData:exitMdxjsEsmData}},mdxjsEsmToMarkdown={handlers:{mdxjsEsm:handleMdxjsEsm}};function enterMdxjsEsm(token){this.enter({type:"mdxjsEsm",value:""},token),this.buffer()}function exitMdxjsEsm(token){let value=this.resume(),node3=this.exit(token),estree=token.estree;node3.value=value,estree&&(node3.data={estree})}function exitMdxjsEsmData(token){this.config.enter.data.call(this,token),this.config.exit.data.call(this,token)}function handleMdxjsEsm(node3){return node3.value||""}function mdxFromMarkdown(){return[mdxExpressionFromMarkdown,mdxJsxFromMarkdown(),mdxjsEsmFromMarkdown]}function mdxToMarkdown(options){return{extensions:[mdxExpressionToMarkdown,mdxJsxToMarkdown(options),mdxjsEsmToMarkdown]}}function remarkMdx(options){let data2=this.data();add("micromarkExtensions",mdxjs(options)),add("fromMarkdownExtensions",mdxFromMarkdown()),add("toMarkdownExtensions",mdxToMarkdown(options));function add(field,value){(data2[field]?data2[field]:data2[field]=[]).push(value)}}var t=__toESM(require("@babel/types")),babel=__toESM(require("@babel/core")),recast=__toESM(require("recast")),path=__toESM(require("path")),import_prettier=__toESM(require("prettier")),fs=__toESM(require("fs")),import_camelCase=__toESM(require("lodash/camelCase")),mdxProcessor=remark().use(remarkMdx);function jscodeshift(info){let parsed=path.parse(info.path),baseName=path.join(parsed.dir,parsed.name.replace(".mdx","").replace(".stories","").replace(".story",""));for(;fs.existsSync(`${baseName}.stories.js`);)baseName+="_";let result=transform(info.source,path.basename(baseName));if(result==null)return;let[mdx,csf]=result;return fs.writeFileSync(`${baseName}.stories.js`,csf),mdx}function transform(source,baseName){let root2=mdxProcessor.parse(source),storyNamespaceName=nameToValidExport(`${baseName}Stories`),metaAttributes=[],storiesMap=new Map;visit(root2,["mdxjsEsm"],node3=>{node3.value=node3.value.replaceAll("@storybook/addon-docs/blocks","@storybook/blocks").replaceAll("@storybook/addon-docs","@storybook/blocks")});let file=getEsmAst(root2);addStoriesImport(root2,baseName,storyNamespaceName),visit(root2,["mdxJsxFlowElement","mdxJsxTextElement"],(node3,index4,parent)=>{if(is(node3,{name:"Meta"})&&(metaAttributes.push(...node3.attributes),node3.attributes=[{type:"mdxJsxAttribute",name:"of",value:{type:"mdxJsxAttributeValueExpression",value:storyNamespaceName}}]),is(node3,{name:"Story"})){let nameAttribute=node3.attributes.find(it=>it.type==="mdxJsxAttribute"&&it.name==="name"),idAttribute=node3.attributes.find(it=>it.type==="mdxJsxAttribute"&&it.name==="id"),storyAttribute=node3.attributes.find(it=>it.type==="mdxJsxAttribute"&&it.name==="story");if(typeof(nameAttribute==null?void 0:nameAttribute.value)=="string"){let name2=nameToValidExport(nameAttribute.value);for(;variableNameExists(name2);)name2+="_";storiesMap.set(name2,{type:"value",attributes:node3.attributes,children:node3.children}),node3.attributes=[{type:"mdxJsxAttribute",name:"of",value:{type:"mdxJsxAttributeValueExpression",value:`${storyNamespaceName}.${name2}`}}],node3.children=[]}else if(idAttribute!=null&&idAttribute.value){let newNode={type:"mdxFlowExpression",value:`/* ${mdxProcessor.stringify({type:"root",children:[node3]}).trim()} is deprecated, please migrate it to <Story of={referenceToStory} /> */`};return storiesMap.set(idAttribute.value,{type:"id"}),parent.children.splice(index4,0,newNode),[SKIP,index4+2]}else if((storyAttribute==null?void 0:storyAttribute.type)==="mdxJsxAttribute"&&typeof storyAttribute.value=="object"&&storyAttribute.value.type==="mdxJsxAttributeValueExpression"){let name2=storyAttribute.value.value;node3.attributes=[{type:"mdxJsxAttribute",name:"of",value:{type:"mdxJsxAttributeValueExpression",value:`${storyNamespaceName}.${name2}`}}],node3.children=[],storiesMap.set(name2,{type:"reference"})}else return parent.children.splice(index4,1),[SKIP,index4]}});let metaProperties=metaAttributes.flatMap(attribute=>attribute.type==="mdxJsxAttribute"?typeof attribute.value=="string"?[t.objectProperty(t.identifier(attribute.name),t.stringLiteral(attribute.value))]:[t.objectProperty(t.identifier(attribute.name),(0,import_csf_tools.babelParseExpression)(attribute.value.value))]:[]);if(file.path.traverse({ImportDeclaration(path2){path2.node.source.value==="@storybook/blocks"&&path2.remove()},ExportNamedDeclaration(path2){path2.replaceWith(path2.node.declaration)}}),storiesMap.size===0)return null;let newStatements=[t.exportDefaultDeclaration(t.objectExpression(metaProperties))];function mapChildrenToRender(children){let child=children[0];if(!child)return;if(child.type==="text")return t.arrowFunctionExpression([],t.stringLiteral(child.value));if(child.type==="mdxFlowExpression"||child.type==="mdxTextExpression"){let expression2=(0,import_csf_tools.babelParseExpression)(child.value);return/\.bind\(.*\)/.test(child.value)||t.isIdentifier(expression2)||t.isArrowFunctionExpression(expression2)?expression2:t.arrowFunctionExpression([],expression2)}let expression=(0,import_csf_tools.babelParseExpression)(mdxProcessor.stringify({type:"root",children:[child]}));return t.arrowFunctionExpression([],expression)}function variableNameExists(name2){let found=!1;return file.path.traverse({VariableDeclarator:path2=>{let lVal=path2.node.id;t.isIdentifier(lVal)&&lVal.name===name2&&(found=!0)}}),found}newStatements.push(...[...storiesMap].flatMap(([key,value])=>{if(value.type==="id")return[];if(value.type==="reference")return[t.exportNamedDeclaration(null,[t.exportSpecifier(t.identifier(key),t.identifier(key))])];let renderProperty=mapChildrenToRender(value.children),newObject=t.objectExpression([...renderProperty?[t.objectProperty(t.identifier("render"),mapChildrenToRender(value.children))]:[],...value.attributes.flatMap(attribute=>attribute.type==="mdxJsxAttribute"?typeof attribute.value=="string"?[t.objectProperty(t.identifier(attribute.name),t.stringLiteral(attribute.value))]:[t.objectProperty(t.identifier(attribute.name),(0,import_csf_tools.babelParseExpression)(attribute.value.value))]:[])]);return[t.exportNamedDeclaration(t.variableDeclaration("const",[t.variableDeclarator(t.identifier(key),newObject)]))]})),file.path.node.body=[...file.path.node.body,...newStatements];let newMdx=mdxProcessor.stringify(root2),output=recast.print(file.path.node).code,prettierConfig=import_prettier.default.resolveConfig.sync(".",{editorconfig:!0})||{printWidth:100,tabWidth:2,bracketSpacing:!0,trailingComma:"es5",singleQuote:!0};return output=import_prettier.default.format(output,{...prettierConfig,filepath:"file.jsx"}),[newMdx,output]}function getEsmAst(root2){let esm=[];visit(root2,["mdxjsEsm"],node3=>{esm.push(node3.value)});let esmSource=`${esm.join(`
52
+ `)):value+=tracker.move(containerPhrasing(node3,context,{...tracker.current(),before:"<",after:">"}))),selfClosing||(value+=tracker.move("</"+(node3.name||"")+">")),exit2(),value}function map3(line,_,blank){return(blank?"":" ")+line}function peekElement(){return"<"}}var mdxjsEsmFromMarkdown={enter:{mdxjsEsm:enterMdxjsEsm},exit:{mdxjsEsm:exitMdxjsEsm,mdxjsEsmData:exitMdxjsEsmData}},mdxjsEsmToMarkdown={handlers:{mdxjsEsm:handleMdxjsEsm}};function enterMdxjsEsm(token){this.enter({type:"mdxjsEsm",value:""},token),this.buffer()}function exitMdxjsEsm(token){let value=this.resume(),node3=this.exit(token),estree=token.estree;node3.value=value,estree&&(node3.data={estree})}function exitMdxjsEsmData(token){this.config.enter.data.call(this,token),this.config.exit.data.call(this,token)}function handleMdxjsEsm(node3){return node3.value||""}function mdxFromMarkdown(){return[mdxExpressionFromMarkdown,mdxJsxFromMarkdown(),mdxjsEsmFromMarkdown]}function mdxToMarkdown(options){return{extensions:[mdxExpressionToMarkdown,mdxJsxToMarkdown(options),mdxjsEsmToMarkdown]}}function remarkMdx(options){let data2=this.data();add("micromarkExtensions",mdxjs(options)),add("fromMarkdownExtensions",mdxFromMarkdown()),add("toMarkdownExtensions",mdxToMarkdown(options));function add(field,value){(data2[field]?data2[field]:data2[field]=[]).push(value)}}var t=__toESM(require("@babel/types")),babel=__toESM(require("@babel/core")),recast=__toESM(require("recast")),path=__toESM(require("path")),import_prettier=__toESM(require("prettier")),fs=__toESM(require("fs")),import_camelCase=__toESM(require("lodash/camelCase")),mdxProcessor=remark().use(remarkMdx);function jscodeshift(info){let parsed=path.parse(info.path),baseName=path.join(parsed.dir,parsed.name.replace(".mdx","").replace(".stories","").replace(".story",""));for(;fs.existsSync(`${baseName}.stories.js`);)baseName+="_";let result=transform(info.source,path.basename(baseName)),[mdx,csf]=result;return csf!=null&&fs.writeFileSync(`${baseName}.stories.js`,csf),mdx}function transform(source,baseName){let root2=mdxProcessor.parse(source),storyNamespaceName=nameToValidExport(`${baseName}Stories`),metaAttributes=[],storiesMap=new Map;visit(root2,["mdxjsEsm"],node3=>{node3.value=node3.value.replaceAll("@storybook/addon-docs/blocks","@storybook/blocks").replaceAll("@storybook/addon-docs","@storybook/blocks")});let file=getEsmAst(root2);visit(root2,["mdxJsxFlowElement","mdxJsxTextElement"],(node3,index4,parent)=>{if(is(node3,{name:"Meta"})&&(metaAttributes.push(...node3.attributes),node3.attributes=[{type:"mdxJsxAttribute",name:"of",value:{type:"mdxJsxAttributeValueExpression",value:storyNamespaceName}}]),is(node3,{name:"Story"})){let nameAttribute=node3.attributes.find(it=>it.type==="mdxJsxAttribute"&&it.name==="name"),idAttribute=node3.attributes.find(it=>it.type==="mdxJsxAttribute"&&it.name==="id"),storyAttribute=node3.attributes.find(it=>it.type==="mdxJsxAttribute"&&it.name==="story");if(typeof(nameAttribute==null?void 0:nameAttribute.value)=="string"){let name2=nameToValidExport(nameAttribute.value);for(;variableNameExists(name2);)name2+="_";storiesMap.set(name2,{type:"value",attributes:node3.attributes,children:node3.children}),node3.attributes=[{type:"mdxJsxAttribute",name:"of",value:{type:"mdxJsxAttributeValueExpression",value:`${storyNamespaceName}.${name2}`}}],node3.children=[]}else if(idAttribute!=null&&idAttribute.value){let newNode={type:"mdxFlowExpression",value:`/* ${mdxProcessor.stringify({type:"root",children:[node3]}).trim()} is deprecated, please migrate it to <Story of={referenceToStory} /> see: https://storybook.js.org/migration-guides/7.0 */`};return storiesMap.set(idAttribute.value,{type:"id"}),parent.children.splice(index4,0,newNode),[SKIP,index4+2]}else if((storyAttribute==null?void 0:storyAttribute.type)==="mdxJsxAttribute"&&typeof storyAttribute.value=="object"&&storyAttribute.value.type==="mdxJsxAttributeValueExpression"){let name2=storyAttribute.value.value;node3.attributes=[{type:"mdxJsxAttribute",name:"of",value:{type:"mdxJsxAttributeValueExpression",value:`${storyNamespaceName}.${name2}`}}],node3.children=[],storiesMap.set(name2,{type:"reference"})}else return parent.children.splice(index4,1),[SKIP,index4]}});let metaProperties=metaAttributes.flatMap(attribute=>attribute.type==="mdxJsxAttribute"?typeof attribute.value=="string"?[t.objectProperty(t.identifier(attribute.name),t.stringLiteral(attribute.value))]:[t.objectProperty(t.identifier(attribute.name),(0,import_csf_tools.babelParseExpression)(attribute.value.value))]:[]);if(file.path.traverse({ImportDeclaration(path2){path2.node.source.value==="@storybook/blocks"&&path2.remove()},ExportNamedDeclaration(path2){path2.replaceWith(path2.node.declaration)}}),storiesMap.size===0&&metaAttributes.length===0)return[mdxProcessor.stringify(root2),null];addStoriesImport(root2,baseName,storyNamespaceName);let newStatements=[t.exportDefaultDeclaration(t.objectExpression(metaProperties))];function mapChildrenToRender(children){let child=children[0];if(!child)return;if(child.type==="text")return t.arrowFunctionExpression([],t.stringLiteral(child.value));if(child.type==="mdxFlowExpression"||child.type==="mdxTextExpression"){let expression2=(0,import_csf_tools.babelParseExpression)(child.value);return/\.bind\(.*\)/.test(child.value)||t.isIdentifier(expression2)||t.isArrowFunctionExpression(expression2)?expression2:t.arrowFunctionExpression([],expression2)}let expression=(0,import_csf_tools.babelParseExpression)(mdxProcessor.stringify({type:"root",children:[child]}));return t.arrowFunctionExpression([],expression)}function variableNameExists(name2){let found=!1;return file.path.traverse({VariableDeclarator:path2=>{let lVal=path2.node.id;t.isIdentifier(lVal)&&lVal.name===name2&&(found=!0)}}),found}newStatements.push(...[...storiesMap].flatMap(([key,value])=>{if(value.type==="id")return[];if(value.type==="reference")return[t.exportNamedDeclaration(null,[t.exportSpecifier(t.identifier(key),t.identifier(key))])];let renderProperty=mapChildrenToRender(value.children),newObject=t.objectExpression([...renderProperty?[t.objectProperty(t.identifier("render"),mapChildrenToRender(value.children))]:[],...value.attributes.flatMap(attribute=>attribute.type==="mdxJsxAttribute"?typeof attribute.value=="string"?[t.objectProperty(t.identifier(attribute.name),t.stringLiteral(attribute.value))]:[t.objectProperty(t.identifier(attribute.name),(0,import_csf_tools.babelParseExpression)(attribute.value.value))]:[])]);return[t.exportNamedDeclaration(t.variableDeclaration("const",[t.variableDeclarator(t.identifier(key),newObject)]))]})),file.path.node.body=[...file.path.node.body,...newStatements];let newMdx=mdxProcessor.stringify(root2),output=recast.print(file.path.node).code,prettierConfig=import_prettier.default.resolveConfig.sync(".",{editorconfig:!0})||{printWidth:100,tabWidth:2,bracketSpacing:!0,trailingComma:"es5",singleQuote:!0};return output=import_prettier.default.format(output,{...prettierConfig,filepath:"file.jsx"}),[newMdx,output]}function getEsmAst(root2){let esm=[];visit(root2,["mdxjsEsm"],node3=>{esm.push(node3.value)});let esmSource=`${esm.join(`
53
53
 
54
54
  `)}`;return new babel.File({filename:"info.path"},{code:esmSource,ast:(0,import_csf_tools.babelParse)(esmSource)})}function addStoriesImport(root2,baseName,storyNamespaceName){let found=!1;visit(root2,["mdxjsEsm"],node3=>{found||(node3.value+=`
55
55
  import * as ${storyNamespaceName} from './${baseName}.stories';`,found=!0)})}function nameToValidExport(name2){let[first,...rest]=Array.from((0,import_camelCase.default)(name2));return`${first.match(/[a-zA-Z_$]/)?first.toUpperCase():`$${first}`}${rest.join("")}`}0&&(module.exports={nameToValidExport,transform});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/codemod",
3
- "version": "7.0.0-rc.1",
3
+ "version": "7.0.0-rc.3",
4
4
  "description": "A collection of codemod scripts written with JSCodeshift",
5
5
  "keywords": [
6
6
  "storybook"
@@ -49,9 +49,9 @@
49
49
  "@babel/preset-env": "~7.20.2",
50
50
  "@babel/types": "~7.21.2",
51
51
  "@storybook/csf": "next",
52
- "@storybook/csf-tools": "7.0.0-rc.1",
53
- "@storybook/node-logger": "7.0.0-rc.1",
54
- "@storybook/types": "7.0.0-rc.1",
52
+ "@storybook/csf-tools": "7.0.0-rc.3",
53
+ "@storybook/node-logger": "7.0.0-rc.3",
54
+ "@storybook/types": "7.0.0-rc.3",
55
55
  "cross-spawn": "^7.0.3",
56
56
  "globby": "^11.0.2",
57
57
  "jscodeshift": "^0.14.0",
@@ -97,5 +97,5 @@
97
97
  "cjs"
98
98
  ]
99
99
  },
100
- "gitHead": "115d69123dc7c4dfab9538d2b273cb0fcc372852"
100
+ "gitHead": "94e99533b214c24691cc9edb3a026d04f20154b6"
101
101
  }
@@ -15,22 +15,39 @@ beforeEach(() => {
15
15
  fs.existsSync.mockImplementation(() => false);
16
16
  });
17
17
 
18
+ test('update import even when no stories can be extracted', () => {
19
+ const input = dedent`
20
+ import { Heading } from '@storybook/addon-docs';
21
+
22
+ <Heading />
23
+ `;
24
+
25
+ const mdx = jscodeshift({ source: input, path: 'Foobar.stories.mdx' });
26
+
27
+ expect(mdx).toMatchInlineSnapshot(`
28
+ import { Heading } from '@storybook/blocks';
29
+
30
+ <Heading />
31
+
32
+ `);
33
+ });
34
+
18
35
  test('drop invalid story nodes', () => {
19
36
  const input = dedent`
20
- import { Meta } from '@storybook/addon-docs';
37
+ import { Meta, Story } from '@storybook/addon-docs';
21
38
 
22
39
  <Meta title="Foobar" />
23
40
 
24
41
  <Story>No name!</Story>
25
42
 
26
- <Story name="Primary">Story</Story>
27
-
43
+ <Story name="Primary">Story</Story>
28
44
  `;
29
45
 
30
46
  const mdx = jscodeshift({ source: input, path: 'Foobar.stories.mdx' });
31
47
 
32
48
  expect(mdx).toMatchInlineSnapshot(`
33
- import { Meta } from '@storybook/addon-docs';
49
+ import { Meta, Story } from '@storybook/blocks';
50
+ import * as FoobarStories from './Foobar.stories';
34
51
 
35
52
  <Meta of={FoobarStories} />
36
53
 
@@ -96,7 +113,7 @@ test('Comment out story nodes with id', () => {
96
113
 
97
114
  <Meta of={FoobarStories} />
98
115
 
99
- {/* <Story id="button--primary" /> is deprecated, please migrate it to <Story of={referenceToStory} /> */}
116
+ {/* <Story id="button--primary" /> is deprecated, please migrate it to <Story of={referenceToStory} /> see: https://storybook.js.org/migration-guides/7.0 */}
100
117
 
101
118
  <Story id="button--primary" />
102
119
 
@@ -1,4 +1,4 @@
1
- /* eslint-disable no-param-reassign,@typescript-eslint/no-shadow,consistent-return */
1
+ /* eslint-disable no-param-reassign,@typescript-eslint/no-shadow */
2
2
  import type { FileInfo } from 'jscodeshift';
3
3
  import { babelParse, babelParseExpression } from '@storybook/csf-tools';
4
4
  import { remark } from 'remark';
@@ -40,14 +40,11 @@ export default function jscodeshift(info: FileInfo) {
40
40
 
41
41
  const result = transform(info.source, path.basename(baseName));
42
42
 
43
- if (result == null) {
44
- // We can not make a valid migration.
45
- return;
46
- }
47
-
48
43
  const [mdx, csf] = result;
49
44
 
50
- fs.writeFileSync(`${baseName}.stories.js`, csf);
45
+ if (csf != null) {
46
+ fs.writeFileSync(`${baseName}.stories.js`, csf);
47
+ }
51
48
 
52
49
  return mdx;
53
50
  }
@@ -80,7 +77,6 @@ export function transform(source: string, baseName: string): [mdx: string, csf:
80
77
  });
81
78
 
82
79
  const file = getEsmAst(root);
83
- addStoriesImport(root, baseName, storyNamespaceName);
84
80
 
85
81
  visit(
86
82
  root,
@@ -135,7 +131,7 @@ export function transform(source: string, baseName: string): [mdx: string, csf:
135
131
  const nodeString = mdxProcessor.stringify({ type: 'root', children: [node] }).trim();
136
132
  const newNode: MdxFlowExpression = {
137
133
  type: 'mdxFlowExpression',
138
- value: `/* ${nodeString} is deprecated, please migrate it to <Story of={referenceToStory} /> */`,
134
+ value: `/* ${nodeString} is deprecated, please migrate it to <Story of={referenceToStory} /> see: https://storybook.js.org/migration-guides/7.0 */`,
139
135
  };
140
136
  storiesMap.set(idAttribute.value as string, { type: 'id' });
141
137
  parent.children.splice(index, 0, newNode);
@@ -201,11 +197,13 @@ export function transform(source: string, baseName: string): [mdx: string, csf:
201
197
  },
202
198
  });
203
199
 
204
- if (storiesMap.size === 0) {
200
+ if (storiesMap.size === 0 && metaAttributes.length === 0) {
205
201
  // A CSF file must have at least one story, so skip migrating if this is the case.
206
- return null;
202
+ return [mdxProcessor.stringify(root), null];
207
203
  }
208
204
 
205
+ addStoriesImport(root, baseName, storyNamespaceName);
206
+
209
207
  const newStatements: t.Statement[] = [
210
208
  t.exportDefaultDeclaration(t.objectExpression(metaProperties)),
211
209
  ];