@coat/cli
Version:
TODO: See #3
107 lines (102 loc) • 3.98 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.runMultipleScripts = runMultipleScripts;
var _chalk = _interopRequireDefault(require("chalk"));
var _execa = _interopRequireDefault(require("execa"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Returns a listener function that prefixes
* all lines with a certain label and writes
* the result to the passed stream.
*
* The stream should not be asynchrounous, and this
* function is currently only able to handle process.stdout
* and process.stdin safely.
*
* The implementation of this function is leaned heavily
* on concurrently's prefixing mechanism.
* See: https://github.com/kimmobrunfeldt/concurrently/blob/master/src/logger.js#L85
*
* @param stream The write stream, typically process.stdout or process.stderr
* @param prefix The label that will be prepended to each line
*/
function createStreamPrefixHandler(stream, prefix) {
// The first line of a data chunk should
// only be prefixed, if the last character
// of the previous chunk ended with a new line.
//
// To prefix the first chunk correctly, lastChar
// is initially set to a new line
let lastChar = "\n";
return data => {
// replace some ANSI code that would impact clearing lines
// See concurrently issue #70:
// https://github.com/kimmobrunfeldt/concurrently/pull/70
const text = data.toString().replace(/\u2026/g, "...");
const lines = text
// Split the current chunk by new lines to
// modify each line individually
.split("\n").map((line, index, array) => {
if (
// Prefix all lines except the first and the
// last line - which is an empty line for
// each chunk
index > 0 && index < array.length - 1 ||
// The first line should only be prefixed
// if the last character of the previous chunk
// was a new line
index === 0 && lastChar === "\n") {
// Color the prefix label using chalk
return (0, _chalk.default)`{dim ${prefix} - }${line}`;
}
// If no prefix is added, the line is returned
// unmodified
return line;
});
// Set the saved lastChar value to the last
// character of the current text chunk to determine
// whether the next chunk's first line needs to be prefixed
lastChar = text[text.length - 1];
// Write all lines to the stream.
//
// Although stream.write is an asynchrounous method,
// using it with process.stdout and process.stderr is
// synchrounous and does not need to be awaited.
stream.write(lines.join("\n"));
};
}
async function runMultipleScripts(cwd, scripts, args) {
// Promise.all is used here to create a
// fail fast behavior that exits once the first
// script run fails
await Promise.all(scripts.map(async script => {
var _task$stdout, _task$stderr;
// Run scripts in silent mode to surpress
// any npm specific output
const npmArgs = ["run", "--silent", script];
if (args !== null && args !== void 0 && args.length) {
// Add two dashes ("--") in order for npm run
// to pick up the arguments
npmArgs.push("--", ...args);
}
const task = (0, _execa.default)("npm", npmArgs, {
cwd,
// Setting FORCE_COLOR to true
// helps to preserve colored
// output in a lot of scenarios,
// even though stdio are piped
// for these tasks
env: {
FORCE_COLOR: "true"
}
});
// Attach stream handlers that prefix
// the outputs to stdout and stderr with
// the script's name
(_task$stdout = task.stdout) === null || _task$stdout === void 0 ? void 0 : _task$stdout.on("data", createStreamPrefixHandler(process.stdout, script));
(_task$stderr = task.stderr) === null || _task$stderr === void 0 ? void 0 : _task$stderr.on("data", createStreamPrefixHandler(process.stderr, script));
await task;
}));
}