autrace
Version:
Account Update analyser for MINA
184 lines • 7.75 kB
JavaScript
export class ASCIITreeVisualizer {
constructor() {
this.INDENT = ' ';
this.TRUNCATE_LENGTH = 50;
this.HASH_PREVIEW_LENGTH = 8;
this.COLORS = {
reset: '\x1b[0m',
green: '\x1b[32m',
red: '\x1b[31m',
blue: '\x1b[34m',
yellow: '\x1b[33m',
purple: '\x1b[35m',
gray: '\x1b[90m',
white: '\x1b[37m',
bold: '\x1b[1m'
};
this.SYMBOLS = {
added: '+',
removed: '-',
modified: '•',
arrow: '→',
bullet: '∙',
branch: '├',
leaf: '└',
vertical: '│',
};
this.stringifyWithBigInt = (obj) => {
try {
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'bigint') {
return value.toString();
}
if (value instanceof Error) {
return value.message;
}
return value;
});
}
catch (error) {
return '[Error: Unable to stringify]';
}
};
}
formatValue(value) {
if (value === null || value === undefined) {
return 'null';
}
if (Array.isArray(value)) {
try {
return `[${value.map(v => this.formatValue(v)).join(', ')}]`;
}
catch (error) {
return '[Error: Invalid Array]';
}
}
if (typeof value === 'object') {
try {
if (value === null) {
return 'null';
}
if ('_value' in value) {
return String(value._value);
}
// Handle special cases
if (value.hash) {
return `{hash: "${value.hash.substring(0, this.HASH_PREVIEW_LENGTH)}..."}`;
}
const str = this.stringifyWithBigInt(value);
return this.truncateString(str);
}
catch (error) {
return '[Error: Invalid Object]';
}
}
try {
const str = String(value);
return this.truncateString(str);
}
catch (error) {
return '[Error: Invalid Value]';
}
}
truncateString(str) {
if (str.length <= this.TRUNCATE_LENGTH) {
return str;
}
if (str.startsWith('B62')) {
return `${str.substring(0, this.HASH_PREVIEW_LENGTH)}...`;
}
return `${str.substring(0, this.TRUNCATE_LENGTH - 3)}...`;
}
visualizeChanges(changes) {
let result = '';
const hasAdded = Array.isArray(changes.added) && changes.added.length > 0;
const hasUpdated = Array.isArray(changes.updated) && changes.updated.length > 0;
const hasRemoved = Array.isArray(changes.removed) && changes.removed.length > 0;
if (hasAdded) {
result += `${this.COLORS.green}${this.SYMBOLS.branch} Added:${this.COLORS.reset}\n`;
changes.added.forEach((item, i) => {
const isLast = i === changes.added.length - 1;
const prefix = isLast ? this.SYMBOLS.leaf : this.SYMBOLS.branch;
result += `${this.COLORS.green}${prefix} ${this.SYMBOLS.added} ${item.path}${this.COLORS.reset}\n`;
if (item.node) {
const addPrefix = isLast ? this.SYMBOLS.leaf : this.SYMBOLS.branch;
result += `${this.COLORS.green} ${addPrefix} ${this.stringifyWithBigInt(item.node)} ${this.COLORS.reset}\n`;
}
});
}
if (hasUpdated) {
if (hasAdded)
result += '\n';
result += `${this.COLORS.yellow}${this.SYMBOLS.branch} Modified:${this.COLORS.reset}\n`;
changes.updated.forEach((mod, i) => {
const isLast = i === changes.updated.length - 1;
const prefix = isLast ? this.SYMBOLS.leaf : this.SYMBOLS.branch;
result += `${this.COLORS.yellow}${prefix} ${this.SYMBOLS.modified} ${mod.path}${this.COLORS.reset}\n`;
if (Array.isArray(mod.changes)) {
mod.changes.forEach((change, j) => {
const changePrefix = j === mod.changes.length - 1 ? this.SYMBOLS.leaf : this.SYMBOLS.branch;
result += `${this.COLORS.gray} ${changePrefix} ${change.field}: ${this.COLORS.reset}` +
`${this.formatValue(change.oldValue)} ${this.SYMBOLS.arrow} ${this.formatValue(change.newValue)}\n`;
});
}
});
}
if (hasRemoved) {
if (hasAdded || hasUpdated)
result += '\n';
result += `${this.COLORS.red}${this.SYMBOLS.branch} Removed:${this.COLORS.reset}\n`;
changes.removed.forEach((item, i) => {
const isLast = i === changes.removed.length - 1;
const prefix = isLast ? this.SYMBOLS.leaf : this.SYMBOLS.branch;
result += `${this.COLORS.red}${prefix} ${this.SYMBOLS.removed} ${item.path}${this.COLORS.reset}\n`;
if (item.node) {
const removePrefix = isLast ? this.SYMBOLS.leaf : this.SYMBOLS.branch;
result += `${this.COLORS.red} ${removePrefix} ${this.stringifyWithBigInt(item.node)} ${this.COLORS.reset}\n`;
}
});
}
return result;
}
visualizeChangeSummary(snapshots) {
if (!Array.isArray(snapshots) || snapshots.length === 0) {
return this.formatHeader('No changes to visualize');
}
let result = this.formatHeader('Transaction Evolution Summary');
snapshots.forEach((snapshot, index) => {
if (!snapshot)
return;
const timestamp = snapshot.timestamp || Date.now();
const operation = snapshot.operation || 'UNKNOWN';
result += this.formatPhase(operation, timestamp);
if (index === 0) {
const accountUpdates = Array.isArray(snapshot.tree) ? snapshot.tree.length : 0;
result += `${this.COLORS.gray}${this.SYMBOLS.bullet} Created transaction with ${accountUpdates} account updates${this.COLORS.reset}\n`;
}
else if (snapshot.changes) {
const hasChanges = Object.values(snapshot.changes).some(arr => Array.isArray(arr) && arr.length > 0);
if (hasChanges) {
result += this.visualizeChanges(snapshot.changes);
}
else {
result += `${this.COLORS.gray}${this.SYMBOLS.bullet} No changes${this.COLORS.reset}\n`;
}
}
result += '\n';
});
return result;
}
formatHeader(text) {
const line = '═'.repeat(text.length + 4);
return `${this.COLORS.blue}╔${line}╗\n║ ${text} ║\n╚${line}╝${this.COLORS.reset}\n`;
}
formatPhase(phase, timestamp) {
try {
const date = new Date(timestamp).toLocaleTimeString();
return `${this.COLORS.bold}${this.COLORS.purple}▶ ${phase.toUpperCase()} ${this.COLORS.gray}(${date})${this.COLORS.reset}\n`;
}
catch (error) {
return `${this.COLORS.bold}${this.COLORS.purple}▶ ${phase.toUpperCase()} ${this.COLORS.gray}(Invalid timestamp)${this.COLORS.reset}\n`;
}
}
}
//# sourceMappingURL=AsciiVisualiser.js.map