semantic-ds-toolkit
Version:
Performance-first semantic layer for modern data stacks - Stable Column Anchors & intelligent inference
292 lines ⢠10.7 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BatchProgressReporter = exports.HealthCheckProgressReporter = exports.InitProgressReporter = exports.InferenceProgressReporter = exports.ProgressReporter = void 0;
exports.createProgressBar = createProgressBar;
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
class ProgressReporter {
steps = [];
currentStep = null;
spinner = null;
startTime = 0;
options;
constructor(options = {}) {
this.options = {
showTimer: true,
showDetails: false,
compact: false,
emoji: true,
...options
};
}
addSteps(steps) {
this.steps = steps.map(step => ({ ...step, status: 'pending' }));
}
start(title) {
this.startTime = Date.now();
if (title) {
console.log(chalk_1.default.blue.bold(`\nš ${title}\n`));
}
this.renderProgress();
}
startStep(stepId, text) {
const step = this.steps.find(s => s.id === stepId);
if (!step)
return;
this.currentStep = stepId;
step.status = 'running';
if (text)
step.text = text;
if (this.spinner) {
this.spinner.stop();
}
const emoji = this.getStatusEmoji('running');
this.spinner = (0, ora_1.default)(`${emoji} ${step.text}`).start();
}
updateStep(stepId, text, details) {
const step = this.steps.find(s => s.id === stepId);
if (!step)
return;
step.text = text;
if (details)
step.details = details;
if (this.currentStep === stepId && this.spinner) {
const emoji = this.getStatusEmoji('running');
this.spinner.text = `${emoji} ${step.text}`;
}
}
completeStep(stepId, text, details) {
const step = this.steps.find(s => s.id === stepId);
if (!step)
return;
step.status = 'completed';
if (text)
step.text = text;
if (details)
step.details = details;
if (this.currentStep === stepId && this.spinner) {
const emoji = this.getStatusEmoji('completed');
this.spinner.succeed(`${emoji} ${step.text}`);
this.spinner = null;
this.currentStep = null;
}
if (this.options.showDetails && details) {
console.log(chalk_1.default.gray(` ${details}`));
}
}
failStep(stepId, error, details) {
const step = this.steps.find(s => s.id === stepId);
if (!step)
return;
step.status = 'failed';
step.details = error;
if (this.currentStep === stepId && this.spinner) {
const emoji = this.getStatusEmoji('failed');
this.spinner.fail(`${emoji} ${step.text} - ${error}`);
this.spinner = null;
this.currentStep = null;
}
if (details) {
console.log(chalk_1.default.red(` ${details}`));
}
}
skipStep(stepId, reason) {
const step = this.steps.find(s => s.id === stepId);
if (!step)
return;
step.status = 'skipped';
if (reason)
step.details = reason;
const emoji = this.getStatusEmoji('skipped');
console.log(chalk_1.default.yellow(`${emoji} ${step.text} - Skipped${reason ? `: ${reason}` : ''}`));
}
complete(title) {
if (this.spinner) {
this.spinner.stop();
}
const elapsed = (Date.now() - this.startTime) / 1000;
const completed = this.steps.filter(s => s.status === 'completed').length;
const failed = this.steps.filter(s => s.status === 'failed').length;
const skipped = this.steps.filter(s => s.status === 'skipped').length;
console.log();
if (title) {
console.log(chalk_1.default.green.bold(`ā
${title}`));
}
console.log(chalk_1.default.cyan(`š Summary:`));
console.log(chalk_1.default.white(` ā
Completed: ${completed}`));
if (failed > 0) {
console.log(chalk_1.default.red(` ā Failed: ${failed}`));
}
if (skipped > 0) {
console.log(chalk_1.default.yellow(` āļø Skipped: ${skipped}`));
}
if (this.options.showTimer) {
console.log(chalk_1.default.gray(` ā±ļø Time: ${elapsed.toFixed(1)}s`));
}
console.log();
}
renderProgress() {
if (this.options.compact)
return;
console.log(chalk_1.default.cyan('š Progress:'));
this.steps.forEach((step, index) => {
const emoji = this.getStatusEmoji(step.status);
const number = `${(index + 1).toString().padStart(2, ' ')}.`;
console.log(chalk_1.default.gray(` ${number} ${emoji} ${step.text}`));
});
console.log();
}
getStatusEmoji(status) {
if (!this.options.emoji) {
const symbols = {
pending: 'ā',
running: 'ā',
completed: 'ā',
failed: 'ā',
skipped: 'ā'
};
return symbols[status];
}
const emojis = {
pending: 'ā³',
running: 'š',
completed: 'ā
',
failed: 'ā',
skipped: 'āļø'
};
return emojis[status];
}
// Utility methods for common workflows
async runWithProgress(stepId, text, fn, successText) {
this.startStep(stepId, text);
try {
const result = await fn();
this.completeStep(stepId, successText || text);
return result;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
this.failStep(stepId, errorMessage);
throw error;
}
}
createSubProgress(parentStepId) {
const subProgress = new ProgressReporter({
...this.options,
compact: true,
showTimer: false
});
// Link sub-progress to parent step
const parentStep = this.steps.find(s => s.id === parentStepId);
if (parentStep) {
parentStep.subSteps = parentStep.subSteps || [];
}
return subProgress;
}
}
exports.ProgressReporter = ProgressReporter;
// Specialized progress reporters for common tasks
class InferenceProgressReporter extends ProgressReporter {
constructor(options = {}) {
super(options);
this.addSteps([
{ id: 'load', text: 'Loading data files' },
{ id: 'analyze', text: 'Analyzing data patterns' },
{ id: 'infer', text: 'Running semantic inference' },
{ id: 'validate', text: 'Validating results' },
{ id: 'save', text: 'Saving semantic mappings' }
]);
}
async loadData(loader) {
return this.runWithProgress('load', 'Loading and parsing data files...', loader, 'Data loaded successfully');
}
async analyzePatterns(analyzer) {
return this.runWithProgress('analyze', 'Analyzing data patterns and structure...', analyzer, 'Pattern analysis complete');
}
async runInference(inferrer) {
return this.runWithProgress('infer', 'Running semantic inference engine...', inferrer, 'Semantic inference complete');
}
async validateResults(validator) {
return this.runWithProgress('validate', 'Validating semantic mappings...', validator, 'Results validated');
}
async saveResults(saver) {
return this.runWithProgress('save', 'Saving semantic mappings...', saver, 'Results saved successfully');
}
}
exports.InferenceProgressReporter = InferenceProgressReporter;
class InitProgressReporter extends ProgressReporter {
constructor(options = {}) {
super(options);
this.addSteps([
{ id: 'validate', text: 'Validating project directory' },
{ id: 'create', text: 'Creating project structure' },
{ id: 'config', text: 'Generating configuration files' },
{ id: 'samples', text: 'Creating sample files' },
{ id: 'deps', text: 'Installing dependencies' }
]);
}
}
exports.InitProgressReporter = InitProgressReporter;
class HealthCheckProgressReporter extends ProgressReporter {
constructor(options = {}) {
super(options);
this.addSteps([
{ id: 'scan', text: 'Scanning project files' },
{ id: 'coverage', text: 'Analyzing semantic coverage' },
{ id: 'performance', text: 'Running performance checks' },
{ id: 'validation', text: 'Validating configuration' },
{ id: 'report', text: 'Generating health report' }
]);
}
}
exports.HealthCheckProgressReporter = HealthCheckProgressReporter;
// Progress bar utilities
class BatchProgressReporter {
total;
current = 0;
spinner;
lastUpdate = 0;
constructor(total, title) {
this.total = total;
this.spinner = (0, ora_1.default)(this.getProgressText()).start();
}
increment(message) {
this.current++;
const now = Date.now();
// Throttle updates to avoid spam
if (now - this.lastUpdate > 100) {
this.spinner.text = this.getProgressText(message);
this.lastUpdate = now;
}
if (this.current >= this.total) {
this.complete();
}
}
complete(message) {
this.spinner.succeed(message || `ā
Processed ${this.total} items`);
}
fail(error) {
this.spinner.fail(`ā Failed: ${error}`);
}
getProgressText(message) {
const percentage = Math.round((this.current / this.total) * 100);
const bar = this.createProgressBar(percentage);
const suffix = message ? ` - ${message}` : '';
return `${bar} ${percentage}% (${this.current}/${this.total})${suffix}`;
}
createProgressBar(percentage) {
const width = 20;
const filled = Math.round((percentage / 100) * width);
const empty = width - filled;
return `[${'ā'.repeat(filled)}${' '.repeat(empty)}]`;
}
}
exports.BatchProgressReporter = BatchProgressReporter;
// Export utility function for quick progress bars
function createProgressBar(total, title) {
return new BatchProgressReporter(total, title);
}
//# sourceMappingURL=progress-reporter.js.map