Skip to content

Commit

Permalink
Merge pull request #22562 from storybookjs/main-prerelease
Browse files Browse the repository at this point in the history
7.0.12 patch release
  • Loading branch information
shilman authored May 15, 2023
2 parents 33d314e + 7ed4d26 commit 6b9e2bc
Show file tree
Hide file tree
Showing 46 changed files with 682 additions and 357 deletions.
4 changes: 2 additions & 2 deletions code/frameworks/angular/src/client/docs/sourceDecorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export const sourceDecorator = (

useEffect(() => {
if (toEmit) {
const { id, args } = context;
channel.emit(SNIPPET_RENDERED, { id, args, source: toEmit, format: 'angular' });
const { id, unmappedArgs } = context;
channel.emit(SNIPPET_RENDERED, { id, args: unmappedArgs, source: toEmit, format: 'angular' });
}
});

Expand Down
1 change: 1 addition & 0 deletions code/lib/cli/src/automigrate/fixes/eslint-plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('eslint-plugin fix', () => {
await expect(
checkEslint({
packageJson,
hasEslint: false,
})
).resolves.toBeFalsy();
});
Expand Down
37 changes: 9 additions & 28 deletions code/lib/cli/src/automigrate/fixes/eslint-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import chalk from 'chalk';
import { dedent } from 'ts-dedent';
import { readConfig, writeConfig } from '@storybook/csf-tools';
import { readFile, readJson, writeJson } from 'fs-extra';
import detectIndent from 'detect-indent';

import { findEslintFile, SUPPORTED_ESLINT_EXTENSIONS } from '../helpers/getEslintInfo';
import {
configureEslintPlugin,
extractEslintInfo,
findEslintFile,
SUPPORTED_ESLINT_EXTENSIONS,
} from '../helpers/eslintPlugin';

import type { Fix } from '../types';

Expand All @@ -25,12 +27,9 @@ export const eslintPlugin: Fix<EslintPluginRunOptions> = {
id: 'eslintPlugin',

async check({ packageManager }) {
const allDependencies = await packageManager.getAllDependencies();
const { hasEslint, isStorybookPluginInstalled } = await extractEslintInfo(packageManager);

const eslintPluginStorybook = allDependencies['eslint-plugin-storybook'];
const eslintDependency = allDependencies.eslint;

if (eslintPluginStorybook || !eslintDependency) {
if (isStorybookPluginInstalled || !hasEslint) {
return null;
}

Expand Down Expand Up @@ -82,26 +81,8 @@ export const eslintPlugin: Fix<EslintPluginRunOptions> = {
return;
}

logger.info(`✅ Adding Storybook plugin to ${eslintFile}`);
if (!dryRun) {
if (eslintFile.endsWith('json')) {
const eslintConfig = (await readJson(eslintFile)) as { extends?: string[] };
const existingConfigValue = Array.isArray(eslintConfig.extends)
? eslintConfig.extends
: [eslintConfig.extends];
eslintConfig.extends = [...(existingConfigValue || []), 'plugin:storybook/recommended'];

const eslintFileContents = await readFile(eslintFile, 'utf8');
const spaces = detectIndent(eslintFileContents).amount || 2;
await writeJson(eslintFile, eslintConfig, { spaces });
} else {
const eslint = await readConfig(eslintFile);
const extendsConfig = eslint.getFieldValue(['extends']) || [];
const existingConfigValue = Array.isArray(extendsConfig) ? extendsConfig : [extendsConfig];
eslint.setFieldValue(['extends'], [...existingConfigValue, 'plugin:storybook/recommended']);

await writeConfig(eslint);
}
await configureEslintPlugin(eslintFile, packageManager);
}
},
};
11 changes: 5 additions & 6 deletions code/lib/cli/src/automigrate/fixes/missing-babelrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,19 @@ export const missingBabelRc: Fix<MissingBabelRcOptions> = {
If your project does not have a babel configuration file, we can generate one that's equivalent to the 6.x defaults for you. Keep in mind that this can affect your project if it uses babel, and you may need to make additional changes based on your projects needs.
We can create a ${chalk.blue(
'.babelrc.json'
)} file with some basic configuration and add any necessary package devDependencies.
${chalk.bold(
'Note:'
)} This automatic setup doesn't work in a monorepo, see the babel documentation for how to setup babel manually:
)} After installing the necessary presets, if it does not work in a monorepo, see the babel documentation for reference:
${chalk.yellow('https://babeljs.io/docs')}
We can create a ${chalk.blue(
'.babelrc.json'
)} file with some basic configuration and add any necessary package devDependencies.
Please see the migration guide for more information:
${chalk.yellow(
'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#babel-mode-v7-exclusively'
)}
`;
},
async run() {
Expand Down
99 changes: 99 additions & 0 deletions code/lib/cli/src/automigrate/helpers/eslintPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import fse, { readFile, readJson, writeJson } from 'fs-extra';

import { dedent } from 'ts-dedent';
import detectIndent from 'detect-indent';
import { readConfig, writeConfig } from '@storybook/csf-tools';
import prompts from 'prompts';
import chalk from 'chalk';
import type { JsPackageManager } from '../../js-package-manager';
import { paddedLog } from '../../helpers';

export const SUPPORTED_ESLINT_EXTENSIONS = ['js', 'cjs', 'json'];
const UNSUPPORTED_ESLINT_EXTENSIONS = ['yaml', 'yml'];

export const findEslintFile = () => {
const filePrefix = '.eslintrc';
const unsupportedExtension = UNSUPPORTED_ESLINT_EXTENSIONS.find((ext: string) =>
fse.existsSync(`${filePrefix}.${ext}`)
);

if (unsupportedExtension) {
throw new Error(unsupportedExtension);
}

const extension = SUPPORTED_ESLINT_EXTENSIONS.find((ext: string) =>
fse.existsSync(`${filePrefix}.${ext}`)
);
return extension ? `${filePrefix}.${extension}` : null;
};

export async function extractEslintInfo(packageManager: JsPackageManager): Promise<{
hasEslint: boolean;
isStorybookPluginInstalled: boolean;
eslintConfigFile: string | null;
}> {
const allDependencies = await packageManager.getAllDependencies();
const packageJson = await packageManager.retrievePackageJson();
let eslintConfigFile: string | null = null;

try {
eslintConfigFile = findEslintFile();
} catch (err) {
//
}

const isStorybookPluginInstalled = !!allDependencies['eslint-plugin-storybook'];
const hasEslint = allDependencies.eslint || eslintConfigFile || packageJson.eslintConfig;
return { hasEslint, isStorybookPluginInstalled, eslintConfigFile };
}

export async function configureEslintPlugin(eslintFile: string, packageManager: JsPackageManager) {
if (eslintFile) {
paddedLog(`Configuring Storybook ESLint plugin at ${eslintFile}`);
if (eslintFile.endsWith('json')) {
const eslintConfig = (await readJson(eslintFile)) as { extends?: string[] };
const existingConfigValue = Array.isArray(eslintConfig.extends)
? eslintConfig.extends
: [eslintConfig.extends];
eslintConfig.extends = [...(existingConfigValue || []), 'plugin:storybook/recommended'];

const eslintFileContents = await readFile(eslintFile, 'utf8');
const spaces = detectIndent(eslintFileContents).amount || 2;
await writeJson(eslintFile, eslintConfig, { spaces });
} else {
const eslint = await readConfig(eslintFile);
const extendsConfig = eslint.getFieldValue(['extends']) || [];
const existingConfigValue = Array.isArray(extendsConfig) ? extendsConfig : [extendsConfig];
eslint.setFieldValue(['extends'], [...existingConfigValue, 'plugin:storybook/recommended']);

await writeConfig(eslint);
}
} else {
paddedLog(`Configuring eslint-plugin-storybook in your package.json`);
const packageJson = await packageManager.retrievePackageJson();
await packageManager.writePackageJson({
...packageJson,
eslintConfig: {
...packageJson.eslintConfig,
extends: [...(packageJson.eslintConfig?.extends || []), 'plugin:storybook/recommended'],
},
});
}
}

export const suggestESLintPlugin = async (): Promise<boolean> => {
const { shouldInstall } = await prompts({
type: 'confirm',
name: 'shouldInstall',
message: dedent`
We have detected that you're using ESLint. Storybook provides a plugin that gives the best experience with Storybook and helps follow best practices: ${chalk.yellow(
'https://github.com/storybookjs/eslint-plugin-storybook#readme'
)}
Would you like to install it?
`,
initial: true,
});

return shouldInstall;
};
20 changes: 0 additions & 20 deletions code/lib/cli/src/automigrate/helpers/getEslintInfo.ts

This file was deleted.

103 changes: 55 additions & 48 deletions code/lib/cli/src/babel-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,63 @@ import { writeFile, pathExists } from 'fs-extra';
import { logger } from '@storybook/node-logger';
import path from 'path';
import prompts from 'prompts';
import chalk from 'chalk';
import { JsPackageManagerFactory } from './js-package-manager';

export const generateStorybookBabelConfigInCWD = async () => {
const target = process.cwd();
return generateStorybookBabelConfig({ target });
};

export const getBabelPresets = ({ typescript, jsx }: { typescript: boolean; jsx: boolean }) => {
const dependencies = ['@babel/preset-env'];

if (typescript) {
dependencies.push('@babel/preset-typescript');
}

if (jsx) {
dependencies.push('@babel/preset-react');
}

return dependencies;
};

export const writeBabelConfigFile = async ({
location,
typescript,
jsx,
}: {
location?: string;
typescript: boolean;
jsx: boolean;
}) => {
const fileLocation = location || path.join(process.cwd(), '.babelrc.json');

const presets: (string | [string, any])[] = [['@babel/preset-env', { targets: { chrome: 100 } }]];

if (typescript) {
presets.push('@babel/preset-typescript');
}

if (jsx) {
presets.push('@babel/preset-react');
}

const contents = JSON.stringify(
{
sourceType: 'unambiguous',
presets,
plugins: [],
},
null,
2
);

await writeFile(fileLocation, contents);
};

export const generateStorybookBabelConfig = async ({ target }: { target: string }) => {
logger.info(`Generating the storybook default babel config at ${target}`);
logger.info(`Generating the Storybook default babel config at ${target}`);

const fileName = '.babelrc.json';
const location = path.join(target, fileName);
Expand All @@ -31,12 +79,6 @@ export const generateStorybookBabelConfig = async ({ target }: { target: string
}
}

logger.info(
`The config will contain ${chalk.yellow(
'@babel/preset-env'
)} and you will be prompted for additional presets, if you wish to add them depending on your project needs.`
);

const { typescript, jsx } = await prompts([
{
type: 'confirm',
Expand All @@ -52,48 +94,13 @@ export const generateStorybookBabelConfig = async ({ target }: { target: string
},
]);

const added = ['@babel/preset-env'];
const presets: (string | [string, any])[] = [['@babel/preset-env', { targets: { chrome: 100 } }]];

if (typescript) {
added.push('@babel/preset-typescript');
presets.push('@babel/preset-typescript');
}

if (jsx) {
added.push('@babel/preset-react');
presets.push('@babel/preset-react');
}

const contents = JSON.stringify(
{
sourceType: 'unambiguous',
presets,
plugins: [],
},
null,
2
);
const dependencies = getBabelPresets({ typescript, jsx });

logger.info(`Writing file to ${location}`);
await writeFile(location, contents);
await writeBabelConfigFile({ location, typescript, jsx });

const { runInstall } = await prompts({
type: 'confirm',
initial: true,
name: 'runInstall',
message: `Shall we install the required dependencies now? (${added.join(', ')})`,
});
const packageManager = JsPackageManagerFactory.getPackageManager();

if (runInstall) {
logger.info(`Installing dependencies...`);

const packageManager = JsPackageManagerFactory.getPackageManager();

await packageManager.addDependencies({ installAsDevDependencies: true }, added);
} else {
logger.info(
`⚠️ Please remember to install the required dependencies yourself: (${added.join(', ')})`
);
}
logger.info(`Installing dependencies (${dependencies.join(', ')})`);
await packageManager.addDependencies({ installAsDevDependencies: true }, dependencies);
};
3 changes: 1 addition & 2 deletions code/lib/cli/src/generators/REACT_SCRIPTS/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => {
extraAddons,
extraPackages,
staticDir: fs.existsSync(path.resolve('./public')) ? 'public' : undefined,
addBabel: false,
addESLint: true,
skipBabel: true,
extraMain,
});
};
Expand Down
Loading

0 comments on commit 6b9e2bc

Please sign in to comment.