diff --git a/code/lib/cli/src/automigrate/fixes/index.ts b/code/lib/cli/src/automigrate/fixes/index.ts index f438b5cc54b2..b5ffdad3b57d 100644 --- a/code/lib/cli/src/automigrate/fixes/index.ts +++ b/code/lib/cli/src/automigrate/fixes/index.ts @@ -1,3 +1,5 @@ +import { Fix } from '../types'; + import { cra5 } from './cra5'; import { webpack5 } from './webpack5'; import { angular12 } from './angular12'; @@ -9,7 +11,7 @@ import { npm7 } from './npm7'; import { sbScripts } from './sb-scripts'; import { newFrameworks } from './new-frameworks'; import { removedGlobalClientAPIs } from './remove-global-client-apis'; -import { Fix } from '../types'; +import { mdx1to2 } from './mdx-1-to-2'; export * from '../types'; @@ -25,4 +27,5 @@ export const fixes: Fix[] = [ sbScripts, newFrameworks, removedGlobalClientAPIs, + mdx1to2, ]; diff --git a/code/lib/cli/src/automigrate/fixes/mdx-1-to-2.test.ts b/code/lib/cli/src/automigrate/fixes/mdx-1-to-2.test.ts new file mode 100644 index 000000000000..ea82440003f6 --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/mdx-1-to-2.test.ts @@ -0,0 +1,50 @@ +/// ; + +import { dedent } from 'ts-dedent'; +import { fixMdxScript } from './mdx-1-to-2'; + +describe('fix', () => { + it('fixes badly-formatted style blocks', () => { + expect( + fixMdxScript(dedent` + + `) + ).toEqual(dedent` + + `); + }); + + it('fixes multiple style blocks', () => { + expect( + fixMdxScript(dedent` + + + `) + ).toMatchInlineSnapshot(` + + + `); + }); +}); diff --git a/code/lib/cli/src/automigrate/fixes/mdx-1-to-2.ts b/code/lib/cli/src/automigrate/fixes/mdx-1-to-2.ts new file mode 100644 index 000000000000..d840d1de207e --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/mdx-1-to-2.ts @@ -0,0 +1,66 @@ +import chalk from 'chalk'; +import { dedent } from 'ts-dedent'; +import { basename } from 'path'; +import fse from 'fs-extra'; +import globby from 'globby'; +import type { Fix } from '../types'; + +const MDX1_SCRIPT_START = /'); +}; + +const logger = console; + +interface Mdx1to2Options { + storiesMdxFiles: string[]; +} + +/** + * Does the user have `.stories.mdx` files? + * + * If so: + * - Assume they might be MDX1 + * - Offer to help migrate to MDX2 + */ +export const mdx1to2: Fix = { + id: 'mdx1to2', + + async check() { + const storiesMdxFiles = await globby('**/*.(story|stories).mdx'); + return storiesMdxFiles.length ? { storiesMdxFiles } : undefined; + }, + + prompt({ storiesMdxFiles }) { + return dedent` + We've found ${chalk.yellow(storiesMdxFiles.length)} '.stories.mdx' files in your project. + + Storybook has upgraded to MDX2 (https://mdxjs.com/blog/v2/), which contains breaking changes from V1. + + We can try to automatically upgrade your MDX files to MDX2 format using some common patterns. + + For a full guide for how to manually upgrade your files, see the MDX2 migration guide: + + ${chalk.cyan('https://mdxjs.com/migrating/v2/#update-mdx-files')} + `; + }, + + async run({ result: { storiesMdxFiles }, dryRun }) { + await Promise.all( + storiesMdxFiles.map(async (fname) => { + const contents = await fse.readFile(fname, 'utf-8'); + const updated = fixMdxScript(contents); + if (updated === contents) { + logger.info(`🆗 Unmodified ${basename(fname)}`); + } else { + logger.info(`✅ Modified ${basename(fname)}`); + if (!dryRun) { + await fse.writeFile(fname, updated); + } + } + }) + ); + }, +};