diff --git a/code/lib/cli/src/automigrate/fixes/autodocs-tags.test.ts b/code/lib/cli/src/automigrate/fixes/autodocs-tags.test.ts new file mode 100644 index 000000000000..3c96d7b7bc1d --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/autodocs-tags.test.ts @@ -0,0 +1,74 @@ +import { describe, expect, it } from 'vitest'; +import type { StorybookConfig } from '@storybook/types'; +import { autodocsTags } from './autodocs-tags'; + +const check = async ({ + main: mainConfig, + storybookVersion = '7.0.0', + previewConfigPath, +}: { + main: Partial & Record; + storybookVersion?: string; + previewConfigPath?: string; +}) => { + return autodocsTags.check({ + packageManager: {} as any, + configDir: '', + mainConfig: mainConfig as any, + storybookVersion, + previewConfigPath, + }); +}; + +it('with no docs setting', async () => { + await expect( + check({ + main: {}, + }) + ).resolves.toBeFalsy(); +}); + +describe('docs.autodocs = true', () => { + it('errors with no preview.js', async () => { + await expect( + check({ + main: { + docs: { autodocs: true }, + }, + }) + ).rejects.toThrowError(); + }); + + it('continues with preview.js', async () => { + await expect( + check({ + main: { + docs: { autodocs: true }, + }, + previewConfigPath: '.storybook/preview.js', + }) + ).resolves.toBeTruthy(); + }); +}); + +describe('docs.autodocs != true', () => { + it('docs.autodocs = false', async () => { + await expect( + check({ + main: { + docs: { autodocs: false }, + }, + }) + ).resolves.toBeTruthy(); + }); + + it('docs.autodocs = "tag"', async () => { + await expect( + check({ + main: { + docs: { autodocs: 'tag' }, + }, + }) + ).resolves.toBeTruthy(); + }); +}); diff --git a/code/lib/cli/src/automigrate/fixes/autodocs-tags.ts b/code/lib/cli/src/automigrate/fixes/autodocs-tags.ts new file mode 100644 index 000000000000..531bcc0ec69d --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/autodocs-tags.ts @@ -0,0 +1,90 @@ +import { dedent } from 'ts-dedent'; +import chalk from 'chalk'; +import type { DocsOptions } from '@storybook/types'; +import { readConfig, writeConfig } from '@storybook/csf-tools'; +import { updateMainConfig } from '../helpers/mainConfigFile'; +import type { Fix } from '../types'; + +const logger = console; + +const MIGRATION = + 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mainjs-docsautodocs-is-deprecated'; + +interface Options { + autodocs: DocsOptions['autodocs']; + mainConfigPath?: string; + previewConfigPath?: string; +} + +/** + */ +export const autodocsTags: Fix = { + id: 'autodocs-tags', + versionRange: ['*.*.*', '>=8.0.*'], + async check({ mainConfig, mainConfigPath, previewConfigPath }) { + const autodocs = mainConfig?.docs?.autodocs; + if (autodocs === undefined) return null; + + if (autodocs === true && !previewConfigPath) { + throw Error(dedent` + ❌ Failed to remove the deprecated ${chalk.cyan('docs.autodocs')} setting from ${chalk.cyan( + mainConfigPath + )}. + + There is no preview config file in which to add the ${chalk.cyan('autodocs')} tag. + + Please perform the migration by hand: ${chalk.yellow(MIGRATION)} + `); + return null; + } + + return { autodocs, mainConfigPath, previewConfigPath }; + }, + + prompt({ autodocs, mainConfigPath, previewConfigPath }) { + let falseMessage = '', + trueMessage = ''; + + if (autodocs === false) { + falseMessage = dedent` + + + There is no ${chalk.cyan('docs.autodocs = false')} equivalent. + You'll need to check your stories to ensure none are tagged with ${chalk.cyan('autodocs')}. + `; + } else if (autodocs === true) { + trueMessage = ` and update ${chalk.cyan(previewConfigPath)}`; + } + + return dedent` + The ${chalk.cyan('docs.autodocs')} setting in ${chalk.cyan( + mainConfigPath + )} is deprecated.${falseMessage} + + Learn more: ${chalk.yellow(MIGRATION)} + + Remove ${chalk.cyan('docs.autodocs')}${trueMessage}? + `; + }, + + async run({ dryRun, mainConfigPath, result }) { + if (!dryRun) { + if (result.autodocs === true) { + logger.info(`✅ Adding "autodocs" tag to ${result.previewConfigPath}`); + const previewConfig = await readConfig(result.previewConfigPath!); + const tags = previewConfig.getFieldNode(['tags']); + if (tags) { + previewConfig.appendValueToArray(['tags'], 'autodocs'); + } else { + previewConfig.setFieldValue(['tags'], ['autodocs']); + } + await writeConfig(previewConfig); + } + + await updateMainConfig({ mainConfigPath, dryRun: !!dryRun }, async (main) => { + logger.info(`✅ Removing "docs.autodocs" from ${mainConfigPath}`); + main.removeField(['docs', 'autodocs']); + }); + } + }, +}; diff --git a/code/lib/cli/src/automigrate/fixes/index.ts b/code/lib/cli/src/automigrate/fixes/index.ts index 72f3eb9a605d..1c12a596fb24 100644 --- a/code/lib/cli/src/automigrate/fixes/index.ts +++ b/code/lib/cli/src/automigrate/fixes/index.ts @@ -28,6 +28,7 @@ import { mdx1to3 } from './mdx-1-to-3'; import { addonPostCSS } from './addon-postcss'; import { vta } from './vta'; import { upgradeStorybookRelatedDependencies } from './upgrade-storybook-related-dependencies'; +import { autodocsTags } from './autodocs-tags'; export * from '../types'; @@ -60,6 +61,7 @@ export const allFixes: Fix[] = [ mdx1to3, upgradeStorybookRelatedDependencies, vta, + autodocsTags, ]; export const initFixes: Fix[] = [eslintPlugin]; diff --git a/code/lib/preview-api/src/modules/store/csf/prepareStory.ts b/code/lib/preview-api/src/modules/store/csf/prepareStory.ts index 6183274669fe..ce99cef8f1e0 100644 --- a/code/lib/preview-api/src/modules/store/csf/prepareStory.ts +++ b/code/lib/preview-api/src/modules/store/csf/prepareStory.ts @@ -1,6 +1,4 @@ /* eslint-disable @typescript-eslint/no-loop-func,no-underscore-dangle */ -import { dedent } from 'ts-dedent'; - import { global } from '@storybook/global'; import type { Args, @@ -23,7 +21,6 @@ import type { } from '@storybook/types'; import { type CleanupCallback, includeConditionalArg, combineTags } from '@storybook/csf'; import { global as globalThis } from '@storybook/global'; -import { once } from '@storybook/client-logger'; import { applyHooks } from '../../addons'; import { combineParameters } from '../parameters'; @@ -159,13 +156,6 @@ function preparePartialAnnotations( // will have a limited cost. If this proves misguided, we can refactor it. const defaultTags = ['dev', 'test']; - if (typeof globalThis.DOCS_OPTIONS?.autodocs !== 'undefined') { - once.warn(dedent` - The \`docs.autodocs\` setting in '.storybook/main.js' is deprecated. Use \`tags: ['autodocs']\` in \`.storybook/preview.js\` instead. - - For more info see: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mainjs-docsautodocs-is-deprecated - `); - } const extraTags = globalThis.DOCS_OPTIONS?.autodocs === true ? ['autodocs'] : []; const tags = combineTags(