lix-website/themes/lix/assets/bootstrap/node_modules/signale/signale.js
2024-04-26 22:49:34 -06:00

407 lines
9.9 KiB
JavaScript
Executable file

'use strict';
const util = require('util');
const path = require('path');
const readline = require('readline');
const chalk = require('chalk');
const figures = require('figures');
const pkgConf = require('pkg-conf');
const pkg = require('./package.json');
const defaultTypes = require('./types');
const {green, grey, red, underline, yellow} = chalk;
let isPreviousLogInteractive = false;
const defaults = pkg.options.default;
const namespace = pkg.name;
class Signale {
constructor(options = {}) {
this._interactive = options.interactive || false;
this._config = Object.assign(this.packageConfiguration, options.config);
this._customTypes = Object.assign({}, options.types);
this._disabled = options.disabled || false;
this._scopeName = options.scope || '';
this._timers = options.timers || new Map();
this._types = this._mergeTypes(defaultTypes, this._customTypes);
this._stream = options.stream || process.stdout;
this._longestLabel = this._getLongestLabel();
this._secrets = options.secrets || [];
this._generalLogLevel = this._validateLogLevel(options.logLevel);
Object.keys(this._types).forEach(type => {
this[type] = this._logger.bind(this, type);
});
}
get _now() {
return Date.now();
}
get scopeName() {
return this._scopeName;
}
get currentOptions() {
return Object.assign({}, {
config: this._config,
disabled: this._disabled,
types: this._customTypes,
interactive: this._interactive,
timers: this._timers,
stream: this._stream,
secrets: this._secrets,
logLevel: this._generalLogLevel
});
}
get date() {
return new Date().toLocaleDateString();
}
get timestamp() {
return new Date().toLocaleTimeString();
}
get filename() {
const _ = Error.prepareStackTrace;
Error.prepareStackTrace = (error, stack) => stack;
const {stack} = new Error();
Error.prepareStackTrace = _;
const callers = stack.map(x => x.getFileName());
const firstExternalFilePath = callers.find(x => {
return x !== callers[0];
});
return firstExternalFilePath ? path.basename(firstExternalFilePath) : 'anonymous';
}
get packageConfiguration() {
return pkgConf.sync(namespace, {defaults});
}
get _longestUnderlinedLabel() {
return underline(this._longestLabel);
}
get _logLevels() {
return {
info: 0,
timer: 1,
debug: 2,
warn: 3,
error: 4
};
}
set configuration(configObj) {
this._config = Object.assign(this.packageConfiguration, configObj);
}
_arrayify(x) {
return Array.isArray(x) ? x : [x];
}
_timeSpan(then) {
return (this._now - then);
}
_getLongestLabel() {
const {_types} = this;
const labels = Object.keys(_types).map(x => _types[x].label);
return labels.reduce((x, y) => x.length > y.length ? x : y);
}
_validateLogLevel(level) {
return Object.keys(this._logLevels).includes(level) ? level : 'info';
}
_mergeTypes(standard, custom) {
const types = Object.assign({}, standard);
Object.keys(custom).forEach(type => {
types[type] = Object.assign({}, types[type], custom[type]);
});
return types;
}
_filterSecrets(message) {
const {_secrets} = this;
if (_secrets.length === 0) {
return message;
}
let safeMessage = message;
_secrets.forEach(secret => {
safeMessage = safeMessage.replace(new RegExp(secret, 'g'), '[secure]');
});
return safeMessage;
}
_formatStream(stream) {
return this._arrayify(stream);
}
_formatDate() {
return `[${this.date}]`;
}
_formatFilename() {
return `[${this.filename}]`;
}
_formatScopeName() {
if (Array.isArray(this._scopeName)) {
const scopes = this._scopeName.filter(x => x.length !== 0);
return `${scopes.map(x => `[${x.trim()}]`).join(' ')}`;
}
return `[${this._scopeName}]`;
}
_formatTimestamp() {
return `[${this.timestamp}]`;
}
_formatMessage(str) {
return util.format(...this._arrayify(str));
}
_meta() {
const meta = [];
if (this._config.displayDate) {
meta.push(this._formatDate());
}
if (this._config.displayTimestamp) {
meta.push(this._formatTimestamp());
}
if (this._config.displayFilename) {
meta.push(this._formatFilename());
}
if (this._scopeName.length !== 0 && this._config.displayScope) {
meta.push(this._formatScopeName());
}
if (meta.length !== 0) {
meta.push(`${figures.pointerSmall}`);
return meta.map(item => grey(item));
}
return meta;
}
_hasAdditional({suffix, prefix}, args) {
return (suffix || prefix) ? '' : this._formatMessage(args);
}
_buildSignale(type, ...args) {
let [msg, additional] = [{}, {}];
if (args.length === 1 && typeof (args[0]) === 'object' && args[0] !== null) {
if (args[0] instanceof Error) {
[msg] = args;
} else {
const [{prefix, message, suffix}] = args;
additional = Object.assign({}, {suffix, prefix});
msg = message ? this._formatMessage(message) : this._hasAdditional(additional, args);
}
} else {
msg = this._formatMessage(args);
}
const signale = this._meta();
if (additional.prefix) {
if (this._config.underlinePrefix) {
signale.push(underline(additional.prefix));
} else {
signale.push(additional.prefix);
}
}
if (this._config.displayBadge && type.badge) {
signale.push(chalk[type.color](this._padEnd(type.badge, type.badge.length + 1)));
}
if (this._config.displayLabel && type.label) {
const label = this._config.uppercaseLabel ? type.label.toUpperCase() : type.label;
if (this._config.underlineLabel) {
signale.push(chalk[type.color](this._padEnd(underline(label), this._longestUnderlinedLabel.length + 1)));
} else {
signale.push(chalk[type.color](this._padEnd(label, this._longestLabel.length + 1)));
}
}
if (msg instanceof Error && msg.stack) {
const [name, ...rest] = msg.stack.split('\n');
if (this._config.underlineMessage) {
signale.push(underline(name));
} else {
signale.push(name);
}
signale.push(grey(rest.map(l => l.replace(/^/, '\n')).join('')));
return signale.join(' ');
}
if (this._config.underlineMessage) {
signale.push(underline(msg));
} else {
signale.push(msg);
}
if (additional.suffix) {
if (this._config.underlineSuffix) {
signale.push(underline(additional.suffix));
} else {
signale.push(additional.suffix);
}
}
return signale.join(' ');
}
_write(stream, message) {
if (this._interactive && stream.isTTY && isPreviousLogInteractive) {
readline.moveCursor(stream, 0, -1);
readline.clearLine(stream);
readline.cursorTo(stream, 0);
}
stream.write(message + '\n');
isPreviousLogInteractive = this._interactive;
}
_log(message, streams = this._stream, logLevel) {
if (this.isEnabled() && this._logLevels[logLevel] >= this._logLevels[this._generalLogLevel]) {
this._formatStream(streams).forEach(stream => {
this._write(stream, message);
});
}
}
_logger(type, ...messageObj) {
const {stream, logLevel} = this._types[type];
const message = this._buildSignale(this._types[type], ...messageObj);
this._log(this._filterSecrets(message), stream, this._validateLogLevel(logLevel));
}
_padEnd(str, targetLength) {
str = String(str);
targetLength = parseInt(targetLength, 10) || 0;
if (str.length >= targetLength) {
return str;
}
if (String.prototype.padEnd) {
return str.padEnd(targetLength);
}
targetLength -= str.length;
return str + ' '.repeat(targetLength);
}
addSecrets(secrets) {
if (!Array.isArray(secrets)) {
throw new TypeError('Argument must be an array.');
}
this._secrets.push(...secrets);
}
clearSecrets() {
this._secrets = [];
}
config(configObj) {
this.configuration = configObj;
}
disable() {
this._disabled = true;
}
enable() {
this._disabled = false;
}
isEnabled() {
return !this._disabled;
}
scope(...name) {
if (name.length === 0) {
throw new Error('No scope name was defined.');
}
return new Signale(Object.assign(this.currentOptions, {scope: name}));
}
unscope() {
this._scopeName = '';
}
time(label) {
if (!label) {
label = `timer_${this._timers.size}`;
}
this._timers.set(label, this._now);
const message = this._meta();
message.push(green(this._padEnd(this._types.start.badge, 2)));
if (this._config.underlineLabel) {
message.push(green(this._padEnd(underline(label), this._longestUnderlinedLabel.length + 1)));
} else {
message.push(green(this._padEnd(label, this._longestLabel.length + 1)));
}
message.push('Initialized timer...');
this._log(message.join(' '), this._stream, 'timer');
return label;
}
timeEnd(label) {
if (!label && this._timers.size) {
const is = x => x.includes('timer_');
label = [...this._timers.keys()].reduceRight((x, y) => {
return is(x) ? x : (is(y) ? y : null);
});
}
if (this._timers.has(label)) {
const span = this._timeSpan(this._timers.get(label));
this._timers.delete(label);
const message = this._meta();
message.push(red(this._padEnd(this._types.pause.badge, 2)));
if (this._config.underlineLabel) {
message.push(red(this._padEnd(underline(label), this._longestUnderlinedLabel.length + 1)));
} else {
message.push(red(this._padEnd(label, this._longestLabel.length + 1)));
}
message.push('Timer run for:');
message.push(yellow(span < 1000 ? span + 'ms' : (span / 1000).toFixed(2) + 's'));
this._log(message.join(' '), this._stream, 'timer');
return {label, span};
}
}
}
module.exports = Signale;