import { basename, dirname } from 'path';
import { cwd, stdout } from 'process';
import { eastAsianWidth } from 'get-east-asian-width';
import chalkPipe, { chalk } from 'chalk-pipe';
// src/core/PrintError.ts
// src/helpers/get-address.ts
function getAddress(text) {
let index = 0;
let start = -1;
let end = -1;
while (index >= 0) {
const nextIndex = text.slice(Math.max(0, index)).indexOf("(");
index = nextIndex > 0 ? nextIndex + index + 1 : -1;
if (nextIndex > 0) {
start = index;
}
}
if (start === -1)
return "";
index = text.slice(Math.max(0, start)).indexOf(")");
if (index === -1)
return "";
end = index + start;
return text.slice(start, end);
}
var get_address_default = getAddress;
// src/helpers/is-rgb.ts
function isRgb(value) {
const rgbRegular = /^\(\d{1,3},\d{1,3},\d{1,3}\)$/;
const validRgb = rgbRegular.test(value.replace(/\s/g, ""));
if (!validRgb)
return false;
const numberRegular = /\d{1,3}/g;
const numberMatch = value.match(numberRegular);
return Boolean(numberMatch?.every((item) => Number(item) <= 255));
}
var is_rgb_default = isRgb;
// src/helpers/is-bg-rgb.ts
function isBgRgb(value) {
if (!value.startsWith("bg"))
return false;
const rgbValue = value.slice(2).replace(/\s/g, "");
return is_rgb_default(rgbValue);
}
var is_bg_rgb_default = isBgRgb;
// src/helpers/is-string.ts
function isString(value) {
return typeof value === "string";
}
var is_string_default = isString;
// src/helpers/normalize-number.ts
function normalizeNumber(value) {
return is_string_default(value) ? Number.parseInt(value, 10) : value ?? Number.NaN;
}
var normalize_number_default = normalizeNumber;
// src/helpers/normalize-path.ts
function normalizePath(path) {
return path.replace(/\\{1,2}/g, "/");
}
var normalize_path_default = normalizePath;
// src/helpers/normalize-rgb.ts
function normalizeRgb(color, prefix = "") {
const length = color.startsWith(prefix) ? prefix.length : 0;
const rgb = color.replace(/[\s()]/g, "").slice(Math.max(0, length));
const [r, g, b] = rgb.split(",").map(Number);
return [r, g, b];
}
var normalize_rgb_default = normalizeRgb;
// src/helpers/normalize-track.ts
function normalizeTrack(string_, start, end) {
return string_.slice(Math.max(0, start), Math.max(0, end)).trim();
}
var normalize_track_default = normalizeTrack;
var PaletteError = class extends Error {
/**
* Constructs a new PaletteError instance.
* @constructor
* @param {(string | Error)} message - The error message or an Error object.
*/
constructor(message) {
super(is_string_default(message) ? message : message?.message || "");
this.name = this.constructor.name;
}
/**
* Returns a Chalk instance with specified styles applied.
* @param {string} styles - The styles to apply.
* @param {ChalkInstance} chain - The Chalk instance to chain with.
* @returns {ChalkInstance} A Chalk instance with the specified styles.
*/
palette(styles, chain = chalk) {
if (!is_string_default(styles)) {
styles = "";
}
const list = styles.split(".").map((style) => {
const _isRgb = is_rgb_default(style);
const _isBgRgb = is_bg_rgb_default(style);
if (!_isRgb && !_isBgRgb)
return style;
const rgb = normalize_rgb_default(style, "bg");
chain = _isRgb ? chain.rgb(...rgb) : chain.bgRgb(...rgb);
return void 0;
}).filter(Boolean);
return chalkPipe(list.join("."), chain);
}
/**
* Adds padding around the provided content.
* @param {string} content - The content to pad.
* @returns {string} The padded content.
*/
padding(content) {
return ` ${content} `;
}
/**
* Generates a formatted message with optional styles.
* @param {string} styles - The styles to apply.
* @returns {string} The formatted message.
*/
info(styles) {
if (!is_string_default(styles)) {
styles = "";
}
const title = this.padding(this.name);
const stylish = this.palette(styles);
return ` ${stylish(title)} ${this.message}`;
}
};
// src/core/TraceError.ts
var TraceError = class extends PaletteError {
/**
* Extracts trace information from the error stack.
* @returns {TraceOption[]} An array of trace options.
*/
trace() {
const track = [];
if (!this.stack)
return track;
for (const line of this.stack.split("\n")) {
const text = line.trim();
if (text === "")
continue;
const result = this.parse(text);
if (result && this.funnel(result)) {
track.push(result);
}
}
return track;
}
/**
* Filters out trace options with addresses starting with 'node:'.
* @private
* @param {TraceOption} option - The trace option to check.
* @returns {boolean} Returns true if the option should be included.
*/
funnel(option) {
return !option.address?.startsWith("node:");
}
/**
* Parses a single line of the error stack trace.
* @private
* @param {string} text - The line of stack trace text.
* @returns {TraceOption | undefined} A trace option object, or undefined if parsing fails.
*/
parse(text) {
const original = text;
if (!text.startsWith("at "))
return;
text = text.replace(/^at /, "");
if (text === "Error (<anonymous>)" || text === "Error (<anonymous>:null:null)") {
return void 0;
}
const isEval = text.startsWith("eval");
let name;
let address;
let filepath;
let directory;
let file;
let line;
let col;
let packageName = "[current]";
const addressMatch = get_address_default(text);
if (addressMatch) {
address = addressMatch.trim();
name = isEval ? "eval" : text.slice(0, Math.max(0, text.length - address.length - 2)).trim();
} else {
address = text;
name = "anonymous";
}
address = normalize_path_default(address);
const lineMatch = /:(\d+):(\d+)\)?$/.exec(address);
if (lineMatch) {
line = normalize_number_default(lineMatch[1]);
col = normalize_number_default(lineMatch[2]);
filepath = normalize_track_default(address, 0, address.length - lineMatch[0].length);
}
if (filepath) {
file = basename(filepath);
directory = dirname(filepath);
file = normalize_path_default(file);
directory = normalize_path_default(directory);
}
if (directory) {
const match = /node_modules\/([^/]+)(?!.*node_modules.*)/.exec(directory);
if (match)
packageName = match[1];
}
return {
original,
name,
address,
file,
line,
col,
packageName
};
}
};
// src/core/PrintError.ts
var PrintError = class extends TraceError {
/**
* Constructs a new PrintError instance.
* @constructor
* @param {(string | Error)} message - The error message or an Error object.
* @param {string} styles - The styles to apply to the error message.
*/
constructor(message, styles) {
super(message);
const track = this.trace();
const prefix = this.opening();
const suffix = this.closing(styles);
this.stack = [prefix, "", this.print(track), "", suffix].join("\n");
}
/**
* Creates the opening part of the error stack trace.
* @private
* @param {number} [defaultLength] - The default length to use if the title length is not provided.
* @returns {string} The opening part of the error stack trace.
*/
opening(defaultLength) {
let title = this.padding(this.message);
const length = this.length(title);
const width = this.calc((defaultLength ?? length) + 2);
let halfWidth = Math.floor(width / 2);
const isAlternate = halfWidth <= 0;
if (isAlternate) {
title = this.padding("Error Message");
halfWidth = Math.floor((width + length - 15) / 2);
}
const prefixString = this.divide(halfWidth);
const prefix = this.highlight("red", prefixString);
const suffixString = this.divide(halfWidth);
const suffix = this.highlight("red", suffixString);
let output = `${prefix}${this.highlight("cyanBright", title)}${suffix}]`;
if (isAlternate) {
output += `
${this.message}`;
const divider = this.divide((this.column() ?? 32) - 2);
output += `
${this.highlight("grey", `[${divider}]`)}`;
}
return output;
}
/**
* Formats the trace information for printing.
* @private
* @param {TraceOption[]} track - The array of trace options.
* @returns {string} The formatted trace information.
*/
print(track) {
const root = basename(cwd());
const { length } = track;
return track.map((item, index) => {
const titleStylish = this.palette("yellowBright");
const title = titleStylish(`${item.file}:${item.line}`);
const summary = `- ${title} ${item.name}`;
const current = item.packageName.replace("[current]", root);
const startIndex = item.address.indexOf(current);
const shorthandAddress = item.address.slice(Math.max(0, startIndex));
const descStylish = this.palette("gray");
let description = descStylish(shorthandAddress.replace(current, `(${current})`));
const isLatest = index === length - 1;
if (!isLatest) {
description += "\n";
}
return [summary, ` ${description}`].join("\n");
}).filter(Boolean).join("\n");
}
/**
* Creates the closing part of the error stack trace.
* @private
* @param {string} [styles] - The styles to apply to the error name.
* @param {number} [defaultLength] - The default length to use if the title length is not provided.
* @returns {string} The closing part of the error stack trace.
*/
closing(styles, defaultLength) {
let title = this.padding(this.name);
const length = this.length(title);
let width = this.calc((defaultLength ?? length) + 3);
if (width <= 0) {
title = this.padding("Exception");
width += length - 9;
}
const prefix = this.highlight("red", this.divide(width));
const suffix = this.highlight("red", this.divide(1));
const stylish = this.palette(styles);
return `[${prefix}${stylish(title)}${suffix}`;
}
/**
* Calculates the display length of a string, considering East Asian Width rules.
* @private
* @param {string} content - The string content whose display length is to be calculated.
* @returns {number} The total display length of the string, accounting for wide and narrow characters.
*/
length(content) {
let result = 0;
for (const char of content) {
const codePoint = char.codePointAt(0);
if (typeof codePoint !== "number")
continue;
result += eastAsianWidth(codePoint);
}
return result;
}
/**
* Calculates the width of the terminal.
* @private
* @param {number} length - The length of the content.
* @param {number} [defaultLength=32] - The default length to use if the terminal width cannot be determined.
* @returns {number} The calculated width.
*/
calc(length, defaultLength = 32) {
const columns = this.column();
return (columns ?? defaultLength) - length;
}
/**
* Retrieves the current width of the terminal in columns.
* @private
* @returns {number | undefined} The number of columns in the terminal, or `undefined` if the terminal width cannot be determined.
*/
column() {
return stdout?.columns;
}
/**
* Applies a highlight color to the content.
* @private
* @param {string} color - The color to apply.
* @param {string} content - The content to highlight.
* @returns {string} The highlighted content.
*/
highlight(color, content) {
const stylish = this.palette(color);
return stylish(content);
}
/**
* Creates a string of a specified length filled with a separator character.
* @private
* @param {number} length - The length of the string.
* @param {string} [separator='-'] - The character to repeat.
* @returns {string} The string filled with the separator character.
*/
divide(length, separator = "-") {
const ls = Array.from({ length }).map(() => separator);
return ls.join("");
}
};
// src/core/Exception.ts
var Exception = class extends PrintError {
/**
* Constructs a new Exception instance.
* @constructor
* @param {(string | Error)} [message] - The error message or an Error object.
* @param {string} [styles] - The styles to apply to the error message.
*/
constructor(message, styles) {
super(message ?? "", styles);
}
/**
* Returns a string representation of the Exception.
* @returns {string} A string containing the name and message of the Exception.
*/
toString() {
return `${this.name}: ${this.message}`;
}
};
var Exception_default = Exception;
export { Exception_default as default };