yarn-run-all
Version:
A CLI tool to run multiple npm-scripts in parallel or sequential.
314 lines (283 loc) • 11.9 kB
JavaScript
/**
* @module index
* @author Toru Nagashima
* @copyright 2015 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/
;
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var Promise = require("pinkie-promise");
var shellQuote = require("shell-quote");
var matchTasks = require("./match-tasks");
var readPackageJson = require("./read-package-json");
var runTasksInParallel = require("./run-tasks-in-parallel");
var runTasksInSequencial = require("./run-tasks-in-sequencial");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
var ARGS_PATTERN = /\{(!)?([*@]|\d+)([^}]+)?}/g;
/**
* Converts a given value to an array.
*
* @param {string|string[]|null|undefined} x - A value to convert.
* @returns {string[]} An array.
*/
function toArray(x) {
if (x == null) {
return [];
}
return Array.isArray(x) ? x : [x];
}
/**
* Replaces argument placeholders (such as `{1}`) by arguments.
*
* @param {string[]} patterns - Patterns to replace.
* @param {string[]} args - Arguments to replace.
* @returns {string[]} replaced
*/
function applyArguments(patterns, args) {
var defaults = Object.create(null);
return patterns.map(function (pattern) {
return pattern.replace(ARGS_PATTERN, function (whole, indirectionMark, id, options) {
if (indirectionMark != null) {
throw Error("Invalid Placeholder: " + whole);
}
if (id === "@") {
return shellQuote.quote(args);
}
if (id === "*") {
return shellQuote.quote([args.join(" ")]);
}
var position = parseInt(id, 10);
if (position >= 1 && position <= args.length) {
return shellQuote.quote([args[position - 1]]);
}
// Address default values
if (options != null) {
var prefix = options.slice(0, 2);
if (prefix === ":=") {
defaults[id] = shellQuote.quote([options.slice(2)]);
return defaults[id];
}
if (prefix === ":-") {
return shellQuote.quote([options.slice(2)]);
}
throw Error("Invalid Placeholder: " + whole);
}
if (defaults[id] != null) {
return defaults[id];
}
return "";
});
});
}
/**
* Parse patterns.
* In parsing process, it replaces argument placeholders (such as `{1}`) by arguments.
*
* @param {string|string[]} patternOrPatterns - Patterns to run.
* A pattern is a npm-script name or a Glob-like pattern.
* @param {string[]} args - Arguments to replace placeholders.
* @returns {string[]} Parsed patterns.
*/
function parsePatterns(patternOrPatterns, args) {
var patterns = toArray(patternOrPatterns);
var hasPlaceholder = patterns.some(function (pattern) {
return ARGS_PATTERN.test(pattern);
});
return hasPlaceholder ? applyArguments(patterns, args) : patterns;
}
/**
* Converts a given config object to an `--:=` style option array.
*
* @param {object|null} config -
* A map-like object to overwrite package configs.
* Keys are package names.
* Every value is a map-like object (Pairs of variable name and value).
* @returns {string[]} `--:=` style options.
*/
function toOverwriteOptions(config) {
var options = [];
Object.keys(config).forEach(function (packageName) {
var packageConfig = config[packageName];
Object.keys(packageConfig).forEach(function (variableName) {
var value = packageConfig[variableName];
options.push("--" + packageName + ":" + variableName + "=" + value);
});
});
return options;
}
/**
* Converts a given config object to an `--a=b` style option array.
*
* @param {object|null} config -
* A map-like object to set configs.
* @returns {string[]} `--a=b` style options.
*/
function toConfigOptions(config) {
return Object.keys(config).map(function (key) {
return "--" + key + "=" + config[key];
});
}
/**
* Gets the maximum length.
*
* @param {number} length - The current maximum length.
* @param {string} name - A name.
* @returns {number} The maximum length.
*/
function maxLength(length, name) {
return Math.max(name.length, length);
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
// TODO(mysticatea): https://github.com/eslint/eslint/issues/6097
//eslint-disable-next-line valid-jsdoc
/**
* Runs npm-scripts which are matched with given patterns.
*
* @param {string|string[]} patternOrPatterns - Patterns to run.
* A pattern is a npm-script name or a Glob-like pattern.
* @param {object|undefined} [options] Optional.
* @param {boolean} options.parallel -
* If this is `true`, run scripts in parallel.
* Otherwise, run scripts in sequencial.
* Default is `false`.
* @param {stream.Readable|null} options.stdin -
* A readable stream to send messages to stdin of child process.
* If this is `null`, ignores it.
* If this is `process.stdin`, inherits it.
* Otherwise, makes a pipe.
* Default is `null`.
* @param {stream.Writable|null} options.stdout -
* A writable stream to receive messages from stdout of child process.
* If this is `null`, cannot send.
* If this is `process.stdout`, inherits it.
* Otherwise, makes a pipe.
* Default is `null`.
* @param {stream.Writable|null} options.stderr -
* A writable stream to receive messages from stderr of child process.
* If this is `null`, cannot send.
* If this is `process.stderr`, inherits it.
* Otherwise, makes a pipe.
* Default is `null`.
* @param {string[]} options.taskList -
* Actual name list of npm-scripts.
* This function search npm-script names in this list.
* If this is `null`, this function reads `package.json` of current directly.
* @param {object|null} options.packageConfig -
* A map-like object to overwrite package configs.
* Keys are package names.
* Every value is a map-like object (Pairs of variable name and value).
* e.g. `{"npm-run-all": {"test": 777}}`
* Default is `null`.
* @param {boolean} options.silent -
* The flag to set `silent` to the log level of npm.
* Default is `false`.
* @param {boolean} options.continueOnError -
* The flag to ignore errors.
* Default is `false`.
* @param {boolean} options.printLabel -
* The flag to print task names at the head of each line.
* Default is `false`.
* @param {boolean} options.printName -
* The flag to print task names before running each task.
* Default is `false`.
* @returns {Promise}
* A promise object which becomes fullfilled when all npm-scripts are completed.
*/
module.exports = function npmRunAll(patternOrPatterns) {
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref$parallel = _ref.parallel,
parallel = _ref$parallel === undefined ? false : _ref$parallel,
_ref$stdin = _ref.stdin,
stdin = _ref$stdin === undefined ? null : _ref$stdin,
_ref$stdout = _ref.stdout,
stdout = _ref$stdout === undefined ? null : _ref$stdout,
_ref$stderr = _ref.stderr,
stderr = _ref$stderr === undefined ? null : _ref$stderr,
_ref$taskList = _ref.taskList,
taskList = _ref$taskList === undefined ? null : _ref$taskList,
_ref$config = _ref.config,
config = _ref$config === undefined ? null : _ref$config,
_ref$packageConfig = _ref.packageConfig,
packageConfig = _ref$packageConfig === undefined ? null : _ref$packageConfig,
_ref$silent = _ref.silent,
silent = _ref$silent === undefined ? false : _ref$silent,
_ref$continueOnError = _ref.continueOnError,
continueOnError = _ref$continueOnError === undefined ? false : _ref$continueOnError,
_ref$printLabel = _ref.printLabel,
printLabel = _ref$printLabel === undefined ? false : _ref$printLabel,
_ref$printName = _ref.printName,
printName = _ref$printName === undefined ? false : _ref$printName,
_ref$arguments = _ref.arguments,
args = _ref$arguments === undefined ? [] : _ref$arguments,
_ref$race = _ref.race,
race = _ref$race === undefined ? false : _ref$race,
_ref$yarn = _ref.yarn,
yarn = _ref$yarn === undefined ? false : _ref$yarn;
try {
var _ret = function () {
var patterns = parsePatterns(patternOrPatterns, args);
if (patterns.length === 0) {
return {
v: Promise.resolve(null)
};
}
if (taskList != null && Array.isArray(taskList) === false) {
throw new Error("Invalid options.taskList");
}
var prefixOptions = [];
if (silent) {
prefixOptions.push("--silent");
}
if (packageConfig != null) {
prefixOptions.push.apply(prefixOptions, _toConsumableArray(toOverwriteOptions(packageConfig)));
}
if (config != null) {
prefixOptions.push.apply(prefixOptions, _toConsumableArray(toConfigOptions(config)));
}
return {
v: Promise.resolve(taskList).then(function (taskList) {
// eslint-disable-line no-shadow
if (taskList != null) {
return { taskList: taskList, packageInfo: null };
}
return readPackageJson();
}).then(function (_ref2) {
var taskList = _ref2.taskList,
packageInfo = _ref2.packageInfo;
// eslint-disable-line no-shadow
var tasks = matchTasks(taskList, patterns);
var labelWidth = tasks.reduce(maxLength, 0);
var runTasks = parallel ? runTasksInParallel : runTasksInSequencial;
return runTasks(tasks, {
stdin: stdin,
stdout: stdout,
stderr: stderr,
prefixOptions: prefixOptions,
continueOnError: continueOnError,
labelState: {
enabled: printLabel,
width: labelWidth,
lastPrefix: null,
lastIsLinebreak: true
},
printName: printName,
packageInfo: packageInfo,
race: race,
yarn: yarn
});
})
};
}();
if ((typeof _ret === "undefined" ? "undefined" : _typeof(_ret)) === "object") return _ret.v;
} catch (err) {
return Promise.reject(new Error(err.message));
}
};