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);
+ }
+ }
+ })
+ );
+ },
+};