@push.rocks/smartlog
Version:
A minimalistic, distributed, and extensible logging tool supporting centralized log management.
345 lines • 24.6 kB
JavaScript
import * as plugins from './smartlog-source-interactive.plugins.js';
/**
* Utility to detect if the environment is interactive
* Checks for TTY capability and common CI environment variables
*/
const isInteractive = () => {
try {
return Boolean(
// Check TTY capability
process.stdout && process.stdout.isTTY &&
// Additional checks for non-interactive environments
!('CI' in process.env) &&
!process.env.GITHUB_ACTIONS &&
!process.env.JENKINS_URL &&
!process.env.GITLAB_CI &&
!process.env.TRAVIS &&
!process.env.CIRCLECI &&
process.env.TERM !== 'dumb');
}
catch (e) {
// If any error occurs (e.g., in browser environments without process),
// assume a non-interactive environment to be safe
return false;
}
};
// Helper to log messages in non-interactive mode
const logMessage = (message, prefix = '') => {
if (prefix) {
console.log(`${prefix} ${message}`);
}
else {
console.log(message);
}
};
// Spinner frames and styles
const spinnerFrames = {
dots: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
line: ['|', '/', '-', '\\'],
star: ['✶', '✸', '✹', '✺', '✹', '✷'],
simple: ['-', '\\', '|', '/']
};
// Color names mapping to ANSI color codes
const colors = {
black: '\u001b[30m',
red: '\u001b[31m',
green: '\u001b[32m',
yellow: '\u001b[33m',
blue: '\u001b[34m',
magenta: '\u001b[35m',
cyan: '\u001b[36m',
white: '\u001b[37m',
gray: '\u001b[90m',
reset: '\u001b[0m'
};
/**
* A class for creating interactive spinners
* Automatically handles non-interactive environments
*/
export class SmartlogSourceInteractive {
constructor() {
this.textContent = 'loading';
this.currentFrame = 0;
this.interval = null;
this.started = false;
this.spinnerStyle = 'dots';
this.color = 'cyan';
this.frameInterval = 80;
this.frames = spinnerFrames[this.spinnerStyle];
this.interactive = isInteractive();
}
/**
* Sets the text for the spinner and starts it if not already started
*/
text(textArg) {
this.textContent = textArg;
if (!this.interactive) {
// In non-interactive mode, just log the message with a loading indicator
logMessage(textArg, '[Loading]');
this.started = true;
return;
}
if (!this.started) {
this.started = true;
this.start();
}
else {
this.renderFrame();
}
}
/**
* Starts the spinner animation
*/
start() {
if (!this.interactive) {
return; // No animation in non-interactive mode
}
if (this.interval) {
clearInterval(this.interval);
}
this.renderFrame();
this.interval = setInterval(() => {
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
this.renderFrame();
}, this.frameInterval);
}
/**
* Renders the current frame of the spinner
*/
renderFrame() {
if (!this.started || !this.interactive)
return;
const frame = this.frames[this.currentFrame];
const colorCode = colors[this.color];
const resetCode = colors.reset;
// Only use ANSI escape codes in interactive mode
process.stdout.write('\r\x1b[2K'); // Clear the current line
process.stdout.write(`${colorCode}${frame}${resetCode} ${this.textContent}`);
}
/**
* Stops the spinner
*/
stop() {
// Always clear the interval even in non-interactive mode
// This prevents memory leaks in tests and long-running applications
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
}
if (!this.interactive) {
return; // No need to clear the line in non-interactive mode
}
process.stdout.write('\r\x1b[2K'); // Clear the current line
}
/**
* Marks the spinner as successful and optionally displays a success message
*/
finishSuccess(textArg) {
const message = textArg || this.textContent;
// Always stop the spinner first to clean up intervals
this.stop();
if (!this.interactive) {
logMessage(message, '[Success]');
}
else {
const successSymbol = colors.green + '✓' + colors.reset;
process.stdout.write(`${successSymbol} ${message}\n`);
}
this.started = false;
}
/**
* Marks the spinner as failed and optionally displays a failure message
*/
finishFail(textArg) {
const message = textArg || this.textContent;
// Always stop the spinner first to clean up intervals
this.stop();
if (!this.interactive) {
logMessage(message, '[Failed]');
}
else {
const failSymbol = colors.red + '✗' + colors.reset;
process.stdout.write(`${failSymbol} ${message}\n`);
}
this.started = false;
}
/**
* Marks the current spinner as successful and starts a new one
*/
successAndNext(textArg) {
this.finishSuccess();
this.text(textArg);
}
/**
* Marks the current spinner as failed and starts a new one
*/
failAndNext(textArg) {
this.finishFail();
this.text(textArg);
}
/**
* Sets the spinner style
*/
setSpinnerStyle(style) {
this.spinnerStyle = style;
this.frames = spinnerFrames[style];
return this;
}
/**
* Sets the spinner color
*/
setColor(colorName) {
if (colorName in colors) {
this.color = colorName;
}
return this;
}
/**
* Sets the animation speed in milliseconds
*/
setSpeed(ms) {
this.frameInterval = ms;
if (this.started) {
this.stop();
this.start();
}
return this;
}
/**
* Gets the current started state
*/
isStarted() {
return this.started;
}
}
export class SmartlogProgressBar {
constructor(options) {
this.current = 0;
this.color = 'green';
this.startTime = null;
this.lastRenderTime = 0;
this.lastLoggedPercent = 0;
this.logThreshold = 10; // Log every 10% in non-interactive mode
this.total = options.total;
this.width = options.width || 30;
this.completeChar = options.complete || '█';
this.incomplete = options.incomplete || '░';
this.renderThrottle = options.renderThrottle || 16;
this.clear = options.clear !== undefined ? options.clear : false;
this.showEta = options.showEta !== undefined ? options.showEta : true;
this.showPercent = options.showPercent !== undefined ? options.showPercent : true;
this.showCount = options.showCount !== undefined ? options.showCount : true;
this.interactive = isInteractive();
}
/**
* Update the progress bar to a specific value
*/
update(value) {
if (this.startTime === null) {
this.startTime = Date.now();
}
this.current = Math.min(value, this.total);
if (!this.interactive) {
// In non-interactive mode, log progress at certain thresholds
const percent = Math.floor((this.current / this.total) * 100);
const currentThreshold = Math.floor(percent / this.logThreshold) * this.logThreshold;
if (currentThreshold > this.lastLoggedPercent || percent === 100) {
this.lastLoggedPercent = currentThreshold;
logMessage(`Progress: ${percent}% (${this.current}/${this.total})`);
}
return this;
}
// Throttle rendering to avoid excessive updates in interactive mode
const now = Date.now();
if (now - this.lastRenderTime < this.renderThrottle) {
return this;
}
this.lastRenderTime = now;
this.render();
return this;
}
/**
* Increment the progress bar by a value
*/
increment(value = 1) {
return this.update(this.current + value);
}
/**
* Mark the progress bar as complete
*/
complete() {
this.update(this.total);
if (!this.interactive) {
logMessage(`Completed: 100% (${this.total}/${this.total})`);
return this;
}
if (this.clear) {
process.stdout.write('\r\x1b[2K');
}
else {
process.stdout.write('\n');
}
return this;
}
/**
* Set the color of the progress bar
*/
setColor(colorName) {
if (colorName in colors) {
this.color = colorName;
}
return this;
}
/**
* Render the progress bar
*/
render() {
if (!this.interactive) {
return; // Don't render in non-interactive mode
}
// Calculate percent complete
const percent = Math.floor((this.current / this.total) * 100);
const completeLength = Math.round((this.current / this.total) * this.width);
const incompleteLength = this.width - completeLength;
// Build the progress bar
const completePart = colors[this.color] + this.completeChar.repeat(completeLength) + colors.reset;
const incompletePart = this.incomplete.repeat(incompleteLength);
const progressBar = `[${completePart}${incompletePart}]`;
// Calculate ETA if needed
let etaStr = '';
if (this.showEta && this.startTime !== null && this.current > 0) {
const elapsed = (Date.now() - this.startTime) / 1000;
const rate = this.current / elapsed;
const remaining = Math.max(0, this.total - this.current);
const eta = Math.round(remaining / rate);
const mins = Math.floor(eta / 60);
const secs = eta % 60;
etaStr = ` eta: ${mins}m${secs}s`;
}
// Build additional information
const percentStr = this.showPercent ? ` ${percent}%` : '';
const countStr = this.showCount ? ` ${this.current}/${this.total}` : '';
// Clear the line and render
process.stdout.write('\r\x1b[2K');
process.stdout.write(`${progressBar}${percentStr}${countStr}${etaStr}`);
}
}
// For backward compatibility with 'source-ora' module
export class SmartlogSourceOra extends SmartlogSourceInteractive {
// Add a stub for the oraInstance property for backward compatibility
get oraInstance() {
// Use public methods instead of accessing private properties
const instance = this;
return {
get text() { return ''; }, // We can't access private textContent directly
start: () => instance.text(''), // This starts the spinner
stop: () => instance.stop(),
succeed: (text) => instance.finishSuccess(text),
fail: (text) => instance.finishFail(text)
};
}
set oraInstance(value) {
// No-op, just for compatibility
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19zb3VyY2VfaW50ZXJhY3RpdmUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQ0FBMEMsQ0FBQztBQUVwRTs7O0dBR0c7QUFDSCxNQUFNLGFBQWEsR0FBRyxHQUFHLEVBQUU7SUFDekIsSUFBSSxDQUFDO1FBQ0gsT0FBTyxPQUFPO1FBQ1osdUJBQXVCO1FBQ3ZCLE9BQU8sQ0FBQyxNQUFNLElBQUksT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLO1lBRXRDLHFEQUFxRDtZQUNyRCxDQUFDLENBQUMsSUFBSSxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUM7WUFDdEIsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWM7WUFDM0IsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVc7WUFDeEIsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVM7WUFDdEIsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU07WUFDbkIsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVE7WUFDckIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUM1QixDQUFDO0lBQ0osQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDWCx1RUFBdUU7UUFDdkUsa0RBQWtEO1FBQ2xELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztBQUNILENBQUMsQ0FBQztBQUVGLGlEQUFpRDtBQUNqRCxNQUFNLFVBQVUsR0FBRyxDQUFDLE9BQWUsRUFBRSxNQUFNLEdBQUcsRUFBRSxFQUFFLEVBQUU7SUFDbEQsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUNYLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLElBQUksT0FBTyxFQUFFLENBQUMsQ0FBQztJQUN0QyxDQUFDO1NBQU0sQ0FBQztRQUNOLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxD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