@best/console-stream
Version:
Best stdout stream wrapper
180 lines • 6.59 kB
JavaScript
"use strict";
/*
* Copyright (c) 2019, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const utils_1 = require("@best/utils");
const chalk_1 = __importDefault(require("chalk"));
const trim_path_1 = __importDefault(require("./utils/trim-path"));
const count_eod_1 = __importDefault(require("./utils/count-eod"));
const proxy_stream_1 = require("./utils/proxy-stream");
var State;
(function (State) {
State["QUEUED"] = "QUEUED";
State["BUILDING"] = "BUILDING";
State["DONE"] = "DONE";
})(State || (State = {}));
const STATE_ANSI = {
BUILDING: chalk_1.default.reset.inverse.yellow.bold(` ${State.BUILDING} `),
QUEUED: chalk_1.default.reset.inverse.gray.bold(` ${State.QUEUED} `),
DONE: chalk_1.default.reset.inverse.green.bold(` ${State.DONE} `),
};
const INIT_MSG = '\n Building benchmarks... \n\n';
function printState(state) {
return STATE_ANSI[state];
}
function printDisplayName(displayPath, overflow) {
const dirname = overflow ? (0, trim_path_1.default)(path_1.default.dirname(displayPath), overflow) : path_1.default.dirname(displayPath);
const basename = path_1.default.basename(displayPath);
return chalk_1.default.dim(dirname + path_1.default.sep) + chalk_1.default.bold(basename);
}
function printProjectName(projectName) {
return ' ' + chalk_1.default.reset.cyan.dim(`(${projectName})`);
}
class BuildOutputStream {
stdoutColumns;
stdoutWrite;
isInteractive;
_streamBuffer = '';
_state;
_innerLog = '';
_scheduled = null;
_proxiedStream;
constructor(buildConfig, stream, isInteractive) {
this.stdoutColumns = stream.columns || 80;
this.stdoutWrite = stream.write.bind(stream);
this.isInteractive = isInteractive !== undefined ? isInteractive : utils_1.isInteractive;
this._state = this.initState(buildConfig);
this._proxiedStream = (0, proxy_stream_1.proxyStream)(stream, this.isInteractive);
}
initState(buildConfig) {
return buildConfig.reduce((state, { matches, config: { rootDir, projectName } }) => {
matches.forEach((benchmarkAbsPath) => {
state.set(benchmarkAbsPath, {
projectName,
state: State.QUEUED,
displayPath: path_1.default.relative(rootDir, benchmarkAbsPath),
});
});
return state;
}, new Map());
}
clearBufferStream() {
let buffer = this._streamBuffer;
const lines = (0, count_eod_1.default)(buffer);
if (lines) {
buffer = '\r\x1B[K\r\x1B[1A'.repeat(lines);
}
if (this.isInteractive) {
// clear last line
this.stdoutWrite('\x1b[999D\x1b[K');
}
this.stdoutWrite(buffer);
this._streamBuffer = '';
}
writeBufferStream(str) {
this._streamBuffer += str;
this.stdoutWrite(str);
}
updateBenchmarkState(benchmarkPath, state) {
const stateConfig = this._state.get(benchmarkPath);
if (!stateConfig) {
throw new Error(`Unknown benchmark build started (${benchmarkPath})`);
}
stateConfig.state = state;
}
onBenchmarkBuildStart(benchmarkPath) {
this.updateBenchmarkState(benchmarkPath, State.BUILDING);
if (this.isInteractive) {
this.scheduleUpdate();
}
else {
const benchmarkState = this._state.get(benchmarkPath);
if (benchmarkState) {
this.stdoutWrite(this.printBenchmark(benchmarkState));
}
}
}
scheduleUpdate() {
if (!this._scheduled) {
this._scheduled = setTimeout(() => {
this.updateStream();
this._scheduled = null;
}, 10);
}
}
printBenchmark({ state, projectName, displayPath }, streamProxyBuffer) {
const columns = this.stdoutColumns;
const overflow = columns - (state.length + projectName.length + displayPath.length + /* for padding */ 14);
const hasOverflow = overflow < 0;
const ansiState = printState(state);
const ansiProjectName = printProjectName(projectName);
const ansiDisplayname = printDisplayName(displayPath, hasOverflow ? Math.abs(overflow) : 0);
const proxiedBuffer = streamProxyBuffer ? `Buffered console logs:\n ${streamProxyBuffer}` : '';
return `${ansiState} ${ansiProjectName} ${ansiDisplayname}\n${proxiedBuffer}`;
}
updateStream() {
const innerState = this._innerLog;
let buffer = INIT_MSG;
for (const { state, displayPath, projectName } of this._state.values()) {
buffer += this.printBenchmark({ state, displayPath, projectName }, this._proxiedStream.readBuffer());
}
if (innerState) {
buffer += `\n${innerState}\n`;
}
this.clearBufferStream();
this.writeBufferStream(buffer);
}
onBenchmarkBuildEnd(benchmarkPath) {
this.updateBenchmarkState(benchmarkPath, State.DONE);
this._innerLog = '';
if (this.isInteractive) {
this.scheduleUpdate();
}
else {
const benchmarkState = this._state.get(benchmarkPath);
if (benchmarkState) {
this.stdoutWrite(this.printBenchmark(benchmarkState, this._proxiedStream.readBuffer()) + '\n');
}
}
}
log(message) {
this._innerLog = message;
if (this.isInteractive) {
this.scheduleUpdate();
}
else {
this.stdoutWrite(` :: ${message}\n`);
}
}
init() {
if (this.isInteractive) {
this.updateStream();
}
else {
this.stdoutWrite(INIT_MSG);
}
}
finish() {
this._proxiedStream.unproxyStream();
if (this._scheduled) {
clearTimeout(this._scheduled);
this._scheduled = null;
}
if (this.isInteractive) {
this.updateStream();
}
else {
this.stdoutWrite('\n');
}
}
}
exports.default = BuildOutputStream;
//# sourceMappingURL=build-stream.js.map