mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-07 21:31:48 +08:00
This option doesn't appear to do anything at all anymore and as-such should be removed from the codebase. Note: This is a breaking change to the CLI, while the parameter might not have done anything useful, it's removal could break scripts that were trying to set it. I was a little brutal on the test cases here, I think I need to re-add one after some sleep
221 lines
6.4 KiB
TypeScript
221 lines
6.4 KiB
TypeScript
/* eslint-disable no-param-reassign */
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import fse from 'fs-extra';
|
|
import chalk from 'chalk';
|
|
import { satisfies } from '@storybook/semver';
|
|
import stripJsonComments from 'strip-json-comments';
|
|
|
|
import { SupportedFrameworks, SupportedLanguage } from './project_types';
|
|
import { JsPackageManager, PackageJson, PackageJsonWithDepsAndDevDeps } from './js-package-manager';
|
|
|
|
const logger = console;
|
|
|
|
export function getBowerJson() {
|
|
const bowerJsonPath = path.resolve('bower.json');
|
|
if (!fs.existsSync(bowerJsonPath)) {
|
|
return false;
|
|
}
|
|
|
|
const jsonContent = fs.readFileSync(bowerJsonPath, 'utf8');
|
|
return JSON.parse(jsonContent);
|
|
}
|
|
|
|
export function readFileAsJson(jsonPath: string, allowComments?: boolean) {
|
|
const filePath = path.resolve(jsonPath);
|
|
if (!fs.existsSync(filePath)) {
|
|
return false;
|
|
}
|
|
|
|
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
const jsonContent = allowComments ? stripJsonComments(fileContent) : fileContent;
|
|
|
|
try {
|
|
return JSON.parse(jsonContent);
|
|
} catch (e) {
|
|
logger.error(chalk.red(`Invalid json in file: ${filePath}`));
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
export const writeFileAsJson = (jsonPath: string, content: unknown) => {
|
|
const filePath = path.resolve(jsonPath);
|
|
if (!fs.existsSync(filePath)) {
|
|
return false;
|
|
}
|
|
|
|
fs.writeFileSync(filePath, `${JSON.stringify(content, null, 2)}\n`);
|
|
return true;
|
|
};
|
|
|
|
export const commandLog = (message: string) => {
|
|
process.stdout.write(chalk.cyan(' • ') + message);
|
|
|
|
// Need `void` to be able to use this function in a then of a Promise<void>
|
|
return (errorMessage?: string | void, errorInfo?: string) => {
|
|
if (errorMessage) {
|
|
process.stdout.write(`. ${chalk.red('✖')}\n`);
|
|
logger.error(`\n ${chalk.red(errorMessage)}`);
|
|
|
|
if (!errorInfo) {
|
|
return;
|
|
}
|
|
|
|
const newErrorInfo = errorInfo
|
|
.split('\n')
|
|
.map((line) => ` ${chalk.dim(line)}`)
|
|
.join('\n');
|
|
logger.error(`${newErrorInfo}\n`);
|
|
return;
|
|
}
|
|
|
|
process.stdout.write(`. ${chalk.green('✓')}\n`);
|
|
};
|
|
};
|
|
|
|
export function paddedLog(message: string) {
|
|
const newMessage = message
|
|
.split('\n')
|
|
.map((line) => ` ${line}`)
|
|
.join('\n');
|
|
|
|
logger.log(newMessage);
|
|
}
|
|
|
|
export function getChars(char: string, amount: number) {
|
|
let line = '';
|
|
for (let lc = 0; lc < amount; lc += 1) {
|
|
line += char;
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
export function codeLog(codeLines: string[], leftPadAmount?: number) {
|
|
let maxLength = 0;
|
|
const newLines = codeLines.map((line) => {
|
|
maxLength = line.length > maxLength ? line.length : maxLength;
|
|
return line;
|
|
});
|
|
|
|
const finalResult = newLines
|
|
.map((line) => {
|
|
const rightPadAmount = maxLength - line.length;
|
|
let newLine = line + getChars(' ', rightPadAmount);
|
|
newLine = getChars(' ', leftPadAmount || 2) + chalk.inverse(` ${newLine} `);
|
|
return newLine;
|
|
})
|
|
.join('\n');
|
|
|
|
logger.log(finalResult);
|
|
}
|
|
|
|
/**
|
|
* Detect if any babel dependencies need to be added to the project
|
|
* @param {Object} packageJson The current package.json so we can inspect its contents
|
|
* @returns {Array} Contains the packages and versions that need to be installed
|
|
* @example
|
|
* const babelDependencies = await getBabelDependencies(packageManager, npmOptions, packageJson);
|
|
* // you can then spread the result when using installDependencies
|
|
* installDependencies(npmOptions, [
|
|
* `@storybook/react@${storybookVersion}`,
|
|
* ...babelDependencies,
|
|
* ]);
|
|
*/
|
|
export async function getBabelDependencies(
|
|
packageManager: JsPackageManager,
|
|
packageJson: PackageJsonWithDepsAndDevDeps
|
|
) {
|
|
const dependenciesToAdd = [];
|
|
let babelLoaderVersion = '^8.0.0-0';
|
|
|
|
const babelCoreVersion =
|
|
packageJson.dependencies['babel-core'] || packageJson.devDependencies['babel-core'];
|
|
|
|
if (!babelCoreVersion) {
|
|
if (!packageJson.dependencies['@babel/core'] && !packageJson.devDependencies['@babel/core']) {
|
|
const babelCoreInstallVersion = await packageManager.getVersion('@babel/core');
|
|
dependenciesToAdd.push(`@babel/core@${babelCoreInstallVersion}`);
|
|
}
|
|
} else {
|
|
const latestCompatibleBabelVersion = await packageManager.latestVersion(
|
|
'babel-core',
|
|
babelCoreVersion
|
|
);
|
|
// Babel 6
|
|
if (satisfies(latestCompatibleBabelVersion, '^6.0.0')) {
|
|
babelLoaderVersion = '^7.0.0';
|
|
}
|
|
}
|
|
|
|
if (!packageJson.dependencies['babel-loader'] && !packageJson.devDependencies['babel-loader']) {
|
|
const babelLoaderInstallVersion = await packageManager.getVersion(
|
|
'babel-loader',
|
|
babelLoaderVersion
|
|
);
|
|
dependenciesToAdd.push(`babel-loader@${babelLoaderInstallVersion}`);
|
|
}
|
|
|
|
return dependenciesToAdd;
|
|
}
|
|
|
|
export function addToDevDependenciesIfNotPresent(
|
|
packageJson: PackageJson,
|
|
name: string,
|
|
packageVersion: string
|
|
) {
|
|
if (!packageJson.dependencies[name] && !packageJson.devDependencies[name]) {
|
|
packageJson.devDependencies[name] = packageVersion;
|
|
}
|
|
}
|
|
|
|
export function copyTemplate(templateRoot: string) {
|
|
const templateDir = path.resolve(templateRoot, `template-csf/`);
|
|
|
|
if (!fs.existsSync(templateDir)) {
|
|
throw new Error(`Couldn't find template dir`);
|
|
}
|
|
|
|
fse.copySync(templateDir, '.', { overwrite: true });
|
|
}
|
|
|
|
export function copyComponents(framework: SupportedFrameworks, language: SupportedLanguage) {
|
|
const languageFolderMapping: Record<SupportedLanguage, string> = {
|
|
javascript: 'js',
|
|
typescript: 'ts',
|
|
};
|
|
const componentsPath = () => {
|
|
const frameworkPath = `frameworks/${framework}`;
|
|
const languageSpecific = path.resolve(
|
|
__dirname,
|
|
`${frameworkPath}/${languageFolderMapping[language]}`
|
|
);
|
|
if (fse.existsSync(languageSpecific)) {
|
|
return languageSpecific;
|
|
}
|
|
const jsFallback = path.resolve(
|
|
__dirname,
|
|
`${frameworkPath}/${languageFolderMapping.javascript}`
|
|
);
|
|
if (fse.existsSync(jsFallback)) {
|
|
return jsFallback;
|
|
}
|
|
const frameworkRootPath = path.resolve(__dirname, frameworkPath);
|
|
if (fse.existsSync(frameworkRootPath)) {
|
|
return frameworkRootPath;
|
|
}
|
|
throw new Error(`Unsupported framework: ${framework}`);
|
|
};
|
|
|
|
const targetPath = () => {
|
|
if (fse.existsSync('./src')) {
|
|
return './src/stories';
|
|
}
|
|
return './stories';
|
|
};
|
|
|
|
const destinationPath = targetPath();
|
|
fse.copySync(componentsPath(), destinationPath, { overwrite: true });
|
|
fse.copySync(path.resolve(__dirname, 'frameworks/common'), destinationPath, { overwrite: true });
|
|
}
|