@storybook/cli
Version:
Storybook's CLI - easiest method of adding storybook to your projects
273 lines (219 loc) • 8.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getPackageDetails = getPackageDetails;
exports.JsPackageManager = void 0;
require("core-js/modules/es.promise.js");
var _chalk = _interopRequireDefault(require("chalk"));
var _semver = require("@storybook/semver");
var _crossSpawn = require("cross-spawn");
var _helpers = require("../helpers");
var _PackageJsonHelper = require("./PackageJsonHelper");
var _versions = _interopRequireDefault(require("../versions.json"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const logger = console;
/**
* Extract package name and version from input
*
* @param pkg A string like `@storybook/cli`, `react` or `react@^16`
* @return A tuple of 2 elements: [packageName, packageVersion]
*/
function getPackageDetails(pkg) {
const idx = pkg.lastIndexOf('@'); // If the only `@` is the first character, it is a scoped package
// If it isn't in the string, it will be -1
if (idx <= 0) {
return [pkg, undefined];
}
const packageName = pkg.slice(0, idx);
const packageVersion = pkg.slice(idx + 1);
return [packageName, packageVersion];
}
class JsPackageManager {
constructor() {
this.type = void 0;
}
/**
* Install dependencies listed in `package.json`
*/
installDependencies() {
let done = (0, _helpers.commandLog)('Preparing to install dependencies');
done();
logger.log();
logger.log();
done = (0, _helpers.commandLog)('Installing dependencies');
try {
this.runInstall();
} catch (e) {
done('An error occurred while installing dependencies.');
process.exit(1);
}
done();
}
/**
* Read the `package.json` file available in the directory the command was call from
* If there is no `package.json` it will create one.
*/
retrievePackageJson() {
let packageJson = (0, _PackageJsonHelper.readPackageJson)();
if (!packageJson) {
// It will create a new package.json file
this.initPackageJson(); // read the newly created package.json file
packageJson = (0, _PackageJsonHelper.readPackageJson)() || {};
}
return Object.assign({}, packageJson, {
dependencies: Object.assign({}, packageJson.dependencies),
devDependencies: Object.assign({}, packageJson.devDependencies)
});
}
/**
* Add dependencies to a project using `yarn add` or `npm install`.
*
* @param {Object} options contains `skipInstall`, `packageJson` and `installAsDevDependencies` which we use to determine how we install packages.
* @param {Array} dependencies contains a list of packages to add.
* @example
* addDependencies(options, [
* `@storybook/react@${storybookVersion}`,
* `@storybook/addon-actions@${actionsVersion}`,
* `@storybook/addon-links@${linksVersion}`,
* `@storybook/addons@${addonsVersion}`,
* ]);
*/
addDependencies(options, dependencies) {
const {
skipInstall
} = options;
if (skipInstall) {
const {
packageJson
} = options;
const dependenciesMap = dependencies.reduce((acc, dep) => {
const [packageName, packageVersion] = getPackageDetails(dep);
return Object.assign({}, acc, {
[packageName]: packageVersion
});
}, {});
if (options.installAsDevDependencies) {
packageJson.devDependencies = Object.assign({}, packageJson.devDependencies, dependenciesMap);
} else {
packageJson.dependencies = Object.assign({}, packageJson.dependencies, dependenciesMap);
}
(0, _PackageJsonHelper.writePackageJson)(packageJson);
} else {
try {
this.runAddDeps(dependencies, options.installAsDevDependencies);
} catch (e) {
logger.error('An error occurred while installing dependencies.');
logger.log(e.message);
process.exit(1);
}
}
}
/**
* Return an array of strings matching following format: `<package_name>@<package_latest_version>`
*
* @param packages
*/
getVersionedPackages(...packages) {
return Promise.all(packages.map(async pkg => {
const [packageName, packageVersion] = getPackageDetails(pkg);
return `${packageName}@${await this.getVersion(packageName, packageVersion)}`;
}));
}
/**
* Return an array of string standing for the latest version of the input packages.
* To be able to identify which version goes with which package the order of the input array is keep.
*
* @param packageNames
*/
getVersions(...packageNames) {
return Promise.all(packageNames.map(packageName => this.getVersion(packageName)));
}
/**
* Return the latest version of the input package available on npmjs registry.
* If constraint are provided it return the latest version matching the constraints.
*
* For `@storybook/*` packages the latest version is retrieved from `cli/src/versions.json` file directly
*
* @param packageName The name of the package
* @param constraint A valid semver constraint, example: '1.x || >=2.5.0 || 5.0.0 - 7.2.3'
*/
async getVersion(packageName, constraint) {
let current;
if (/@storybook/.test(packageName)) {
// @ts-ignore
current = _versions.default[packageName];
}
let latest;
try {
latest = await this.latestVersion(packageName, constraint);
} catch (e) {
if (current) {
logger.warn(`\n ${_chalk.default.yellow(e.message)}`);
return current;
}
logger.error(`\n ${_chalk.default.red(e.message)}`);
process.exit(1);
}
const versionToUse = current && (!constraint || (0, _semver.satisfies)(current, constraint)) && (0, _semver.gt)(current, latest) ? current : latest;
return `^${versionToUse}`;
}
/**
* Get the latest version of the package available on npmjs.com.
* If constraint is set then it returns a version satisfying it, otherwise the latest version available is returned.
*
* @param packageName Name of the package
* @param constraint Version range to use to constraint the returned version
*/
async latestVersion(packageName, constraint) {
if (!constraint) {
return this.runGetVersions(packageName, false);
}
const versions = await this.runGetVersions(packageName, true); // Get the latest version satisfying the constraint
return versions.reverse().find(version => (0, _semver.satisfies)(version, constraint));
}
addStorybookCommandInScripts(options) {
var _options$port;
const sbPort = (_options$port = options === null || options === void 0 ? void 0 : options.port) !== null && _options$port !== void 0 ? _options$port : 6006;
const storybookCmd = options !== null && options !== void 0 && options.staticFolder ? `start-storybook -p ${sbPort} -s ${options.staticFolder}` : `start-storybook -p ${sbPort}`;
const buildStorybookCmd = options !== null && options !== void 0 && options.staticFolder ? `build-storybook -s ${options.staticFolder}` : `build-storybook`;
const preCommand = options !== null && options !== void 0 && options.preCommand ? this.getRunCommand(options.preCommand) : undefined;
this.addScripts({
storybook: [preCommand, storybookCmd].filter(Boolean).join(' && '),
'build-storybook': [preCommand, buildStorybookCmd].filter(Boolean).join(' && ')
});
}
addESLintConfig() {
var _packageJson$eslintCo;
const packageJson = this.retrievePackageJson();
(0, _PackageJsonHelper.writePackageJson)(Object.assign({}, packageJson, {
eslintConfig: Object.assign({}, packageJson.eslintConfig, {
overrides: [...(((_packageJson$eslintCo = packageJson.eslintConfig) === null || _packageJson$eslintCo === void 0 ? void 0 : _packageJson$eslintCo.overrides) || []), {
files: ['**/*.stories.*'],
rules: {
'import/no-anonymous-default-export': 'off'
}
}]
})
}));
}
addScripts(scripts) {
const packageJson = this.retrievePackageJson();
(0, _PackageJsonHelper.writePackageJson)(Object.assign({}, packageJson, {
scripts: Object.assign({}, packageJson.scripts, scripts)
}));
}
executeCommand(command, args, stdio) {
var _commandResult$stdout;
const commandResult = (0, _crossSpawn.sync)(command, args, {
stdio: stdio !== null && stdio !== void 0 ? stdio : 'pipe',
encoding: 'utf-8'
});
if (commandResult.status !== 0) {
var _commandResult$stderr;
throw new Error((_commandResult$stderr = commandResult.stderr) !== null && _commandResult$stderr !== void 0 ? _commandResult$stderr : '');
}
return (_commandResult$stdout = commandResult.stdout) !== null && _commandResult$stdout !== void 0 ? _commandResult$stdout : '';
}
}
exports.JsPackageManager = JsPackageManager;