@nomicfoundation/hardhat-utils
Advanced tools
| export type TableRow = string[]; | ||
| export interface TableDivider { | ||
| type: "divider"; | ||
| } | ||
| export type TableItem = TableRow | TableDivider; | ||
| export declare const divider: TableDivider; | ||
| /** | ||
| * Formats an array of rows and dividers into a table string. | ||
| * | ||
| * @param items An array of table rows (string arrays) and dividers. | ||
| * Dividers are objects with type: "divider" and will be rendered as table dividers. | ||
| * @returns The formatted table as a string, ready to be rendered. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * formatTable([ | ||
| * ["Name", "Age"], | ||
| * divider, | ||
| * ["Alice", "30"], | ||
| * ["Bob", "25"], | ||
| * divider, | ||
| * ["Average", "27.5"] | ||
| * ]); | ||
| * | ||
| * // => | ||
| * // | Name | Age | | ||
| * // | ------- | ---- | | ||
| * // | Alice | 30 | | ||
| * // | Bob | 25 | | ||
| * // | ------- | ---- | | ||
| * // | Average | 27.5 | | ||
| * ``` | ||
| */ | ||
| export declare function formatTable(items: TableItem[]): string; | ||
| export interface TableTitleV2 { | ||
| type: "title"; | ||
| text: string; | ||
| } | ||
| export interface TableSectionHeaderV2 { | ||
| type: "section-header"; | ||
| text: string; | ||
| } | ||
| export interface TableHeaderV2 { | ||
| type: "header"; | ||
| cells: string[]; | ||
| } | ||
| export interface TableRowV2 { | ||
| type: "row"; | ||
| cells: string[]; | ||
| } | ||
| export type TableItemV2 = TableTitleV2 | TableSectionHeaderV2 | TableHeaderV2 | TableRowV2; | ||
| /** | ||
| * Formats an array of titles, section headers, headers, and rows into a table | ||
| * string with box-drawing characters. | ||
| * | ||
| * Features: | ||
| * - Titles are centered in a standalone box with double borders (╔═╗) | ||
| * - Section headers group related content with automatic closing | ||
| * - Headers and rows can have different numbers of cells | ||
| * - Rows with fewer cells than max columns are handled with special rendering | ||
| * | ||
| * @param items An array of table items (titles, section headers, headers, and rows). | ||
| * Sections are automatically closed when a new section-header or title appears, or | ||
| * at the end of the table. | ||
| * @returns The formatted table as a string, ready to be rendered. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * formatTableV2([ | ||
| * { type: "title", text: "My Table" }, | ||
| * { type: "section-header", text: "User Data" }, | ||
| * { type: "header", cells: ["Name", "Age", "City"] }, | ||
| * { type: "row", cells: ["Alice", "30", "NYC"] }, | ||
| * { type: "row", cells: ["Bob", "25", "LA"] }, | ||
| * { type: "section-header", text: "Summary" }, | ||
| * { type: "header", cells: ["Total", "Count"] }, | ||
| * { type: "row", cells: ["55", "2"] } | ||
| * ]); | ||
| * | ||
| * // => | ||
| * // ╔═══════════════════╗ | ||
| * // ║ My Table ║ | ||
| * // ╚═══════════════════╝ | ||
| * // ╔═══════════════════╗ | ||
| * // ║ User Data ║ | ||
| * // ╟───────┬─────┬─────╢ | ||
| * // ║ Name │ Age │ City║ | ||
| * // ╟───────┼─────┼─────╢ | ||
| * // ║ Alice │ 30 │ NYC ║ | ||
| * // ╟───────┼─────┼─────╢ | ||
| * // ║ Bob │ 25 │ LA ║ | ||
| * // ╚═══════╧═════╧═════╝ | ||
| * // ╔═══════════════════╗ | ||
| * // ║ Summary ║ | ||
| * // ╟───────┬───────────╢ | ||
| * // ║ Total │ Count ║ | ||
| * // ╟───────┼───────────╢ | ||
| * // ║ 55 │ 2 ║ | ||
| * // ╚═══════╧═══════════╝ | ||
| * ``` | ||
| */ | ||
| export declare function formatTableV2(items: TableItemV2[]): string; | ||
| //# sourceMappingURL=format.d.ts.map |
| {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/format.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC;AAChC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;CACjB;AACD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,YAAY,CAAC;AAEhD,eAAO,MAAM,OAAO,EAAE,YAAkC,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,CA8CtD;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,oBAAoB,GACpB,aAAa,GACb,UAAU,CAAC;AAEf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAgG1D"} |
| import { getColumnWidths, getContentWidth, getHeadingWidth, getStringWidth, renderContentLine, renderHeaderOpen, renderRowSeparator, renderSectionClose, } from "./internal/format.js"; | ||
| export const divider = { type: "divider" }; | ||
| /** | ||
| * Formats an array of rows and dividers into a table string. | ||
| * | ||
| * @param items An array of table rows (string arrays) and dividers. | ||
| * Dividers are objects with type: "divider" and will be rendered as table dividers. | ||
| * @returns The formatted table as a string, ready to be rendered. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * formatTable([ | ||
| * ["Name", "Age"], | ||
| * divider, | ||
| * ["Alice", "30"], | ||
| * ["Bob", "25"], | ||
| * divider, | ||
| * ["Average", "27.5"] | ||
| * ]); | ||
| * | ||
| * // => | ||
| * // | Name | Age | | ||
| * // | ------- | ---- | | ||
| * // | Alice | 30 | | ||
| * // | Bob | 25 | | ||
| * // | ------- | ---- | | ||
| * // | Average | 27.5 | | ||
| * ``` | ||
| */ | ||
| export function formatTable(items) { | ||
| const widths = []; | ||
| const dataRows = []; | ||
| for (const item of items) { | ||
| if (Array.isArray(item)) { | ||
| dataRows.push([...item]); | ||
| } | ||
| } | ||
| // Calculate maximum width for each column | ||
| for (const row of dataRows) { | ||
| for (let i = 0; i < row.length; i++) { | ||
| while (i >= widths.length) { | ||
| widths.push(0); | ||
| } | ||
| widths[i] = Math.max(widths[i], getStringWidth(row[i])); | ||
| } | ||
| } | ||
| const dividerRow = widths.map((width) => "-".repeat(width)); | ||
| const outputRows = []; | ||
| for (const item of items) { | ||
| if (Array.isArray(item)) { | ||
| const row = [...item]; | ||
| // Pad the row to match the number of columns | ||
| while (row.length < widths.length) { | ||
| row.push(""); | ||
| } | ||
| outputRows.push(row); | ||
| } | ||
| else { | ||
| outputRows.push([...dividerRow]); | ||
| } | ||
| } | ||
| outputRows.forEach((row) => { | ||
| for (let i = 0; i < row.length; i++) { | ||
| const displayWidth = getStringWidth(row[i]); | ||
| const actualLength = row[i].length; | ||
| // Adjust padding to account for difference between display width and actual length | ||
| row[i] = row[i].padEnd(widths[i] + actualLength - displayWidth); | ||
| } | ||
| }); | ||
| return outputRows.map((row) => `| ${row.join(" | ")} |`).join("\n"); | ||
| } | ||
| /** | ||
| * Formats an array of titles, section headers, headers, and rows into a table | ||
| * string with box-drawing characters. | ||
| * | ||
| * Features: | ||
| * - Titles are centered in a standalone box with double borders (╔═╗) | ||
| * - Section headers group related content with automatic closing | ||
| * - Headers and rows can have different numbers of cells | ||
| * - Rows with fewer cells than max columns are handled with special rendering | ||
| * | ||
| * @param items An array of table items (titles, section headers, headers, and rows). | ||
| * Sections are automatically closed when a new section-header or title appears, or | ||
| * at the end of the table. | ||
| * @returns The formatted table as a string, ready to be rendered. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * formatTableV2([ | ||
| * { type: "title", text: "My Table" }, | ||
| * { type: "section-header", text: "User Data" }, | ||
| * { type: "header", cells: ["Name", "Age", "City"] }, | ||
| * { type: "row", cells: ["Alice", "30", "NYC"] }, | ||
| * { type: "row", cells: ["Bob", "25", "LA"] }, | ||
| * { type: "section-header", text: "Summary" }, | ||
| * { type: "header", cells: ["Total", "Count"] }, | ||
| * { type: "row", cells: ["55", "2"] } | ||
| * ]); | ||
| * | ||
| * // => | ||
| * // ╔═══════════════════╗ | ||
| * // ║ My Table ║ | ||
| * // ╚═══════════════════╝ | ||
| * // ╔═══════════════════╗ | ||
| * // ║ User Data ║ | ||
| * // ╟───────┬─────┬─────╢ | ||
| * // ║ Name │ Age │ City║ | ||
| * // ╟───────┼─────┼─────╢ | ||
| * // ║ Alice │ 30 │ NYC ║ | ||
| * // ╟───────┼─────┼─────╢ | ||
| * // ║ Bob │ 25 │ LA ║ | ||
| * // ╚═══════╧═════╧═════╝ | ||
| * // ╔═══════════════════╗ | ||
| * // ║ Summary ║ | ||
| * // ╟───────┬───────────╢ | ||
| * // ║ Total │ Count ║ | ||
| * // ╟───────┼───────────╢ | ||
| * // ║ 55 │ 2 ║ | ||
| * // ╚═══════╧═══════════╝ | ||
| * ``` | ||
| */ | ||
| export function formatTableV2(items) { | ||
| if (items.length === 0) { | ||
| return ""; | ||
| } | ||
| const columnWidths = getColumnWidths(items); | ||
| const contentWidth = getContentWidth(columnWidths); | ||
| const headingWidth = getHeadingWidth(items); | ||
| // If heading is wider than content, expand last column to fit | ||
| if (headingWidth > contentWidth && columnWidths.length > 0) { | ||
| const extraSpace = headingWidth - contentWidth; | ||
| columnWidths[columnWidths.length - 1] += extraSpace; | ||
| } | ||
| const tableWidth = Math.max(contentWidth, headingWidth); | ||
| const lines = []; | ||
| let previousCellCount = 0; // Keep track of previous row/header cell count | ||
| let inSection = false; | ||
| for (let i = 0; i < items.length; i++) { | ||
| const [previous, current] = [items[i - 1], items[i]]; | ||
| if (current.type === "title") { | ||
| if (inSection) { | ||
| lines.push(renderSectionClose(columnWidths, previousCellCount)); | ||
| inSection = false; | ||
| } | ||
| lines.push("╔" + "═".repeat(tableWidth) + "╗"); | ||
| const titleDisplayWidth = getStringWidth(current.text); | ||
| const titleActualLength = current.text.length; | ||
| const centeredTitle = current.text | ||
| .padStart((tableWidth + titleDisplayWidth) / 2 + | ||
| (titleActualLength - titleDisplayWidth)) | ||
| .padEnd(tableWidth + (titleActualLength - titleDisplayWidth)); | ||
| lines.push("║" + centeredTitle + "║"); | ||
| lines.push("╚" + "═".repeat(tableWidth) + "╝"); | ||
| } | ||
| else if (current.type === "section-header") { | ||
| if (inSection) { | ||
| lines.push(renderSectionClose(columnWidths, previousCellCount)); | ||
| } | ||
| lines.push("╔" + "═".repeat(tableWidth) + "╗"); | ||
| const headerDisplayWidth = getStringWidth(current.text); | ||
| const headerActualLength = current.text.length; | ||
| const paddedHeader = current.text.padEnd(tableWidth - 2 + (headerActualLength - headerDisplayWidth)); | ||
| lines.push("║ " + paddedHeader + " ║"); | ||
| inSection = true; | ||
| } | ||
| else if (current.type === "header") { | ||
| const currentCellCount = current.cells.length; | ||
| const innerJoiner = previous !== undefined && previous.type === "section-header" | ||
| ? "┬" | ||
| : "┼"; | ||
| const needsTransition = previous !== undefined && | ||
| previous.type !== "section-header" && | ||
| currentCellCount < previousCellCount; | ||
| lines.push(renderHeaderOpen(columnWidths, currentCellCount, innerJoiner, needsTransition)); | ||
| lines.push(renderContentLine(current.cells, columnWidths, currentCellCount)); | ||
| previousCellCount = currentCellCount; | ||
| } | ||
| else if (current.type === "row") { | ||
| const currentCellCount = current.cells.length; | ||
| // Only add separator if previous wasn't a row | ||
| if (previous === undefined || previous.type !== "row") { | ||
| lines.push(renderRowSeparator(columnWidths, currentCellCount)); | ||
| } | ||
| lines.push(renderContentLine(current.cells, columnWidths, currentCellCount)); | ||
| previousCellCount = currentCellCount; | ||
| } | ||
| } | ||
| if (inSection) { | ||
| lines.push(renderSectionClose(columnWidths, previousCellCount)); | ||
| } | ||
| return lines.join("\n"); | ||
| } | ||
| //# sourceMappingURL=format.js.map |
| {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAQ9B,MAAM,CAAC,MAAM,OAAO,GAAiB,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,WAAW,CAAC,KAAkB;IAC5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAe,EAAE,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC1B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjB,CAAC;YACD,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5D,MAAM,UAAU,GAAe,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;YACtB,6CAA6C;YAC7C,OAAO,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,YAAY,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,YAAY,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACnC,mFAAmF;YACnF,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC;QAClE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,UAAU,aAAa,CAAC,KAAoB;IAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAE5C,8DAA8D;IAC9D,IAAI,YAAY,GAAG,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3D,MAAM,UAAU,GAAG,YAAY,GAAG,YAAY,CAAC;QAC/C,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,UAAU,CAAC;IACtD,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAExD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,iBAAiB,GAAG,CAAC,CAAC,CAAC,+CAA+C;IAC1E,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAErD,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC7B,IAAI,SAAS,EAAE,CAAC;gBACd,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC;gBAChE,SAAS,GAAG,KAAK,CAAC;YACpB,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC;YAC/C,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACvD,MAAM,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;YAC9C,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI;iBAC/B,QAAQ,CACP,CAAC,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC;gBAClC,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,CAC1C;iBACA,MAAM,CAAC,UAAU,GAAG,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,CAAC,CAAC;YAChE,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,aAAa,GAAG,GAAG,CAAC,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC;QACjD,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YAC7C,IAAI,SAAS,EAAE,CAAC;gBACd,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC;YAClE,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC;YAC/C,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACxD,MAAM,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;YAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CACtC,UAAU,GAAG,CAAC,GAAG,CAAC,kBAAkB,GAAG,kBAAkB,CAAC,CAC3D,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,YAAY,GAAG,IAAI,CAAC,CAAC;YACvC,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrC,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;YAC9C,MAAM,WAAW,GACf,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,gBAAgB;gBAC1D,CAAC,CAAC,GAAG;gBACL,CAAC,CAAC,GAAG,CAAC;YACV,MAAM,eAAe,GACnB,QAAQ,KAAK,SAAS;gBACtB,QAAQ,CAAC,IAAI,KAAK,gBAAgB;gBAClC,gBAAgB,GAAG,iBAAiB,CAAC;YAEvC,KAAK,CAAC,IAAI,CACR,gBAAgB,CACd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,eAAe,CAChB,CACF,CAAC;YACF,KAAK,CAAC,IAAI,CACR,iBAAiB,CAAC,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,gBAAgB,CAAC,CACjE,CAAC;YACF,iBAAiB,GAAG,gBAAgB,CAAC;QACvC,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAClC,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;YAE9C,8CAA8C;YAC9C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACtD,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC;YACjE,CAAC;YACD,KAAK,CAAC,IAAI,CACR,iBAAiB,CAAC,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,gBAAgB,CAAC,CACjE,CAAC;YACF,iBAAiB,GAAG,gBAAgB,CAAC;QACvC,CAAC;IACH,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"} |
| import type { TableItemV2 } from "../format.js"; | ||
| /** | ||
| * Calculate the display width of a string by removing ANSI escape codes. | ||
| * | ||
| * NOTE: This implementation only removes basic ANSI color/style codes and may | ||
| * not handle all escape sequences (e.g., cursor movement, complex control | ||
| * sequences). | ||
| */ | ||
| export declare function getStringWidth(str: string): number; | ||
| /** | ||
| * Calculates the minimum width needed by each column in the table | ||
| * to fit its content (accounting for ANSI color codes). | ||
| */ | ||
| export declare function getColumnWidths(items: TableItemV2[]): number[]; | ||
| /** | ||
| * Calculates the inner width needed to fit the rows and headers | ||
| * (excludes borders, which are added during rendering). | ||
| * | ||
| * Each column is padded by 1 space on each side, and columns are | ||
| * separated by " │ " (3 spaces). | ||
| */ | ||
| export declare function getContentWidth(columnWidths: number[]): number; | ||
| /** | ||
| * Calculates the inner width needed to fit titles and section headers | ||
| * (excludes borders, which are added during rendering). | ||
| * | ||
| * Each title/header is padded by 1 space on each side. | ||
| * Accounts for ANSI color codes. | ||
| */ | ||
| export declare function getHeadingWidth(items: TableItemV2[]): number; | ||
| /** | ||
| * Calculates the width needed for unused columns when a row/header has fewer | ||
| * cells than the total column count (e.g., if table has 6 columns but row | ||
| * only has 2 cells, calculates space for the remaining 4 columns). | ||
| */ | ||
| export declare function getUnusedColumnsWidth(columnWidths: number[], previousCellCount: number): number; | ||
| /** | ||
| * Renders a horizontal rule segment by repeating a character for each column | ||
| * with padding, joined by a separator (e.g., "─────┼─────┼─────"). | ||
| */ | ||
| export declare function renderRuleSegment(columnWidths: number[], char: string, joiner: string): string; | ||
| /** | ||
| * Renders a complete horizontal rule with left and right borders | ||
| * (e.g., "╟─────┼─────┼─────╢"). | ||
| */ | ||
| export declare function renderHorizontalRule(leftBorder: string, columnWidths: number[], char: string, joiner: string, rightBorder: string): string; | ||
| /** | ||
| * Renders a content line containing cells from either a header or row. | ||
| * | ||
| * Handles two cases: | ||
| * - Full width: When all columns are used, cells are separated by " │ " and | ||
| * line ends with " ║" (e.g., "║ cell1 │ cell2 │ cell3 ║") | ||
| * - Short line: When fewer columns are used, active cells are followed by | ||
| * " │ " and empty space, ending with "║" (e.g., "║ cell1 │ cell2 │ ║") | ||
| * | ||
| * Accounts for ANSI color codes when padding cells. | ||
| */ | ||
| export declare function renderContentLine(cells: string[], columnWidths: number[], currentCellCount: number): string; | ||
| /** | ||
| * Renders the horizontal rule that appears above a header row. | ||
| * | ||
| * Handles three cases: | ||
| * - Transition rule: When going from more columns to fewer, shows ┴ marks | ||
| * where columns collapse (e.g., "╟───┼───┼───┴───┴───╢") | ||
| * - Full width: When header uses all columns (e.g., "╟───┬───┬───╢" or "╟───┼───┼───╢") | ||
| * - Short header: When header uses fewer columns than max (e.g., "╟───┬─────────╢") | ||
| * | ||
| * The innerJoiner determines the separator character: ┬ after section-header, ┼ otherwise. | ||
| */ | ||
| export declare function renderHeaderOpen(columnWidths: number[], currentCellCount: number, innerJoiner: string, needsTransition: boolean): string; | ||
| /** | ||
| * Renders the horizontal rule that appears above a row. | ||
| * | ||
| * Handles two cases: | ||
| * - Full width: When row uses all columns, renders with ┼ joiners and | ||
| * ends with ╢ (e.g., "╟───┼───┼───╢") | ||
| * - Short row: When row uses fewer columns, renders active columns with | ||
| * ┼ joiners, ends with ┤, then fills remaining space and ends with ║ | ||
| * (e.g., "╟───┼───┤ ║") | ||
| */ | ||
| export declare function renderRowSeparator(columnWidths: number[], currentCellCount: number): string; | ||
| /** | ||
| * Renders the section's bottom border, placing ╧ marks under column | ||
| * separators where the last row/header had cells (e.g., if the last row | ||
| * looked like "║ a │ b │ ║", the bottom border would be | ||
| * "╚═══╧═══╧═══════╝"). | ||
| */ | ||
| export declare function renderSectionClose(columnWidths: number[], previousCellCount: number): string; | ||
| //# sourceMappingURL=format.d.ts.map |
| {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/internal/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,EAAE,CAY9D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,CAM9D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAQ5D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EAAE,EACtB,iBAAiB,EAAE,MAAM,GACxB,MAAM,CAGR;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EAAE,EACtB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EAAE,EACtB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,MAAM,CAIR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,YAAY,EAAE,MAAM,EAAE,EACtB,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAmCR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EAAE,EACtB,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,OAAO,GACvB,MAAM,CA2BR;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EAAE,EACtB,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAkBR;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EAAE,EACtB,iBAAiB,EAAE,MAAM,GACxB,MAAM,CAcR"} |
| /** | ||
| * Calculate the display width of a string by removing ANSI escape codes. | ||
| * | ||
| * NOTE: This implementation only removes basic ANSI color/style codes and may | ||
| * not handle all escape sequences (e.g., cursor movement, complex control | ||
| * sequences). | ||
| */ | ||
| export function getStringWidth(str) { | ||
| // Remove ANSI escape codes if present | ||
| const stripped = str.replace(/\u001b\[[0-9;]*m/g, ""); | ||
| return stripped.length; | ||
| } | ||
| /** | ||
| * Calculates the minimum width needed by each column in the table | ||
| * to fit its content (accounting for ANSI color codes). | ||
| */ | ||
| export function getColumnWidths(items) { | ||
| const columnWidths = []; | ||
| for (const item of items) { | ||
| if (item.type === "row" || item.type === "header") { | ||
| item.cells.forEach((cell, i) => { | ||
| columnWidths[i] = Math.max(columnWidths[i] ?? 0, getStringWidth(cell)); | ||
| }); | ||
| } | ||
| } | ||
| return columnWidths; | ||
| } | ||
| /** | ||
| * Calculates the inner width needed to fit the rows and headers | ||
| * (excludes borders, which are added during rendering). | ||
| * | ||
| * Each column is padded by 1 space on each side, and columns are | ||
| * separated by " │ " (3 spaces). | ||
| */ | ||
| export function getContentWidth(columnWidths) { | ||
| return (columnWidths.reduce((sum, w) => sum + w, 0) + | ||
| (columnWidths.length - 1) * 3 + | ||
| 2); | ||
| } | ||
| /** | ||
| * Calculates the inner width needed to fit titles and section headers | ||
| * (excludes borders, which are added during rendering). | ||
| * | ||
| * Each title/header is padded by 1 space on each side. | ||
| * Accounts for ANSI color codes. | ||
| */ | ||
| export function getHeadingWidth(items) { | ||
| let headingWidth = 0; | ||
| for (const item of items) { | ||
| if (item.type === "section-header" || item.type === "title") { | ||
| headingWidth = Math.max(headingWidth, getStringWidth(item.text) + 2); | ||
| } | ||
| } | ||
| return headingWidth; | ||
| } | ||
| /** | ||
| * Calculates the width needed for unused columns when a row/header has fewer | ||
| * cells than the total column count (e.g., if table has 6 columns but row | ||
| * only has 2 cells, calculates space for the remaining 4 columns). | ||
| */ | ||
| export function getUnusedColumnsWidth(columnWidths, previousCellCount) { | ||
| const remainingWidths = columnWidths.slice(previousCellCount); | ||
| return remainingWidths.reduce((sum, w) => sum + w + 3, 0) - 3; | ||
| } | ||
| /** | ||
| * Renders a horizontal rule segment by repeating a character for each column | ||
| * with padding, joined by a separator (e.g., "─────┼─────┼─────"). | ||
| */ | ||
| export function renderRuleSegment(columnWidths, char, joiner) { | ||
| return columnWidths.map((w) => char.repeat(w + 2)).join(joiner); | ||
| } | ||
| /** | ||
| * Renders a complete horizontal rule with left and right borders | ||
| * (e.g., "╟─────┼─────┼─────╢"). | ||
| */ | ||
| export function renderHorizontalRule(leftBorder, columnWidths, char, joiner, rightBorder) { | ||
| return (leftBorder + renderRuleSegment(columnWidths, char, joiner) + rightBorder); | ||
| } | ||
| /** | ||
| * Renders a content line containing cells from either a header or row. | ||
| * | ||
| * Handles two cases: | ||
| * - Full width: When all columns are used, cells are separated by " │ " and | ||
| * line ends with " ║" (e.g., "║ cell1 │ cell2 │ cell3 ║") | ||
| * - Short line: When fewer columns are used, active cells are followed by | ||
| * " │ " and empty space, ending with "║" (e.g., "║ cell1 │ cell2 │ ║") | ||
| * | ||
| * Accounts for ANSI color codes when padding cells. | ||
| */ | ||
| export function renderContentLine(cells, columnWidths, currentCellCount) { | ||
| if (currentCellCount === columnWidths.length) { | ||
| return ("║ " + | ||
| cells | ||
| .map((cell, j) => { | ||
| const displayWidth = getStringWidth(cell); | ||
| const actualLength = cell.length; | ||
| // Adjust padding to account for ANSI escape codes | ||
| return cell.padEnd(columnWidths[j] + actualLength - displayWidth); | ||
| }) | ||
| .join(" │ ") + | ||
| " ║"); | ||
| } | ||
| else { | ||
| const usedWidths = columnWidths.slice(0, currentCellCount); | ||
| const remainingWidth = getUnusedColumnsWidth(columnWidths, currentCellCount); | ||
| return ("║ " + | ||
| cells | ||
| .map((cell, j) => { | ||
| const displayWidth = getStringWidth(cell); | ||
| const actualLength = cell.length; | ||
| // Adjust padding to account for ANSI escape codes | ||
| return cell.padEnd(usedWidths[j] + actualLength - displayWidth); | ||
| }) | ||
| .join(" │ ") + | ||
| " │ " + | ||
| " ".repeat(remainingWidth + 1) + | ||
| "║"); | ||
| } | ||
| } | ||
| /** | ||
| * Renders the horizontal rule that appears above a header row. | ||
| * | ||
| * Handles three cases: | ||
| * - Transition rule: When going from more columns to fewer, shows ┴ marks | ||
| * where columns collapse (e.g., "╟───┼───┼───┴───┴───╢") | ||
| * - Full width: When header uses all columns (e.g., "╟───┬───┬───╢" or "╟───┼───┼───╢") | ||
| * - Short header: When header uses fewer columns than max (e.g., "╟───┬─────────╢") | ||
| * | ||
| * The innerJoiner determines the separator character: ┬ after section-header, ┼ otherwise. | ||
| */ | ||
| export function renderHeaderOpen(columnWidths, currentCellCount, innerJoiner, needsTransition) { | ||
| if (needsTransition) { | ||
| const usedWidths = columnWidths.slice(0, currentCellCount); | ||
| const collapsingWidths = columnWidths.slice(currentCellCount); | ||
| return ("╟" + | ||
| renderRuleSegment(usedWidths, "─", "┼") + | ||
| "┼" + | ||
| renderRuleSegment(collapsingWidths, "─", "┴") + | ||
| "╢"); | ||
| } | ||
| else if (currentCellCount === columnWidths.length) { | ||
| return renderHorizontalRule("╟", columnWidths, "─", innerJoiner, "╢"); | ||
| } | ||
| else { | ||
| const usedWidths = columnWidths.slice(0, currentCellCount); | ||
| const remainingWidth = getUnusedColumnsWidth(columnWidths, currentCellCount); | ||
| return ("╟" + | ||
| renderRuleSegment(usedWidths, "─", innerJoiner) + | ||
| innerJoiner + | ||
| "─".repeat(remainingWidth + 2) + | ||
| "╢"); | ||
| } | ||
| } | ||
| /** | ||
| * Renders the horizontal rule that appears above a row. | ||
| * | ||
| * Handles two cases: | ||
| * - Full width: When row uses all columns, renders with ┼ joiners and | ||
| * ends with ╢ (e.g., "╟───┼───┼───╢") | ||
| * - Short row: When row uses fewer columns, renders active columns with | ||
| * ┼ joiners, ends with ┤, then fills remaining space and ends with ║ | ||
| * (e.g., "╟───┼───┤ ║") | ||
| */ | ||
| export function renderRowSeparator(columnWidths, currentCellCount) { | ||
| if (currentCellCount === columnWidths.length) { | ||
| return renderHorizontalRule("╟", columnWidths, "─", "┼", "╢"); | ||
| } | ||
| else { | ||
| // Short row - ends with ┤ instead of ╢ | ||
| const usedWidths = columnWidths.slice(0, currentCellCount); | ||
| const remainingWidth = getUnusedColumnsWidth(columnWidths, currentCellCount); | ||
| return ("╟" + | ||
| renderRuleSegment(usedWidths, "─", "┼") + | ||
| "┤" + | ||
| " ".repeat(remainingWidth + 2) + | ||
| "║"); | ||
| } | ||
| } | ||
| /** | ||
| * Renders the section's bottom border, placing ╧ marks under column | ||
| * separators where the last row/header had cells (e.g., if the last row | ||
| * looked like "║ a │ b │ ║", the bottom border would be | ||
| * "╚═══╧═══╧═══════╝"). | ||
| */ | ||
| export function renderSectionClose(columnWidths, previousCellCount) { | ||
| if (previousCellCount === columnWidths.length) { | ||
| return renderHorizontalRule("╚", columnWidths, "═", "╧", "╝"); | ||
| } | ||
| else { | ||
| const usedWidths = columnWidths.slice(0, previousCellCount); | ||
| const unusedWidth = getUnusedColumnsWidth(columnWidths, previousCellCount); | ||
| return ("╚" + | ||
| renderRuleSegment(usedWidths, "═", "╧") + | ||
| "╧" + | ||
| renderRuleSegment([unusedWidth], "═", "") + | ||
| "╝"); | ||
| } | ||
| } | ||
| //# sourceMappingURL=format.js.map |
| {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/internal/format.ts"],"names":[],"mappings":"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"} |
| export declare function panicErrorCodeToReason(errorCode: bigint): string | undefined; | ||
| //# sourceMappingURL=panic-errors.d.ts.map |
| {"version":3,"file":"panic-errors.d.ts","sourceRoot":"","sources":["../../../src/internal/panic-errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAsB5E"} |
| export function panicErrorCodeToReason(errorCode) { | ||
| // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- we are only covering some of the integer range | ||
| switch (errorCode) { | ||
| case 0x1n: | ||
| return "Assertion error"; | ||
| case 0x11n: | ||
| return "Arithmetic operation overflowed outside of an unchecked block"; | ||
| case 0x12n: | ||
| return "Division or modulo division by zero"; | ||
| case 0x21n: | ||
| return "Tried to convert a value into an enum, but the value was too big or negative"; | ||
| case 0x22n: | ||
| return "Incorrectly encoded storage byte array"; | ||
| case 0x31n: | ||
| return ".pop() was called on an empty array"; | ||
| case 0x32n: | ||
| return "Array accessed at an out-of-bounds or negative index"; | ||
| case 0x41n: | ||
| return "Too much memory was allocated, or an array was created that is too large"; | ||
| case 0x51n: | ||
| return "Called a zero-initialized variable of internal function type"; | ||
| } | ||
| } | ||
| //# sourceMappingURL=panic-errors.js.map |
| {"version":3,"file":"panic-errors.js","sourceRoot":"","sources":["../../../src/internal/panic-errors.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACtD,4HAA4H;IAC5H,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,IAAI;YACP,OAAO,iBAAiB,CAAC;QAC3B,KAAK,KAAK;YACR,OAAO,+DAA+D,CAAC;QACzE,KAAK,KAAK;YACR,OAAO,qCAAqC,CAAC;QAC/C,KAAK,KAAK;YACR,OAAO,8EAA8E,CAAC;QACxF,KAAK,KAAK;YACR,OAAO,wCAAwC,CAAC;QAClD,KAAK,KAAK;YACR,OAAO,qCAAqC,CAAC;QAC/C,KAAK,KAAK;YACR,OAAO,sDAAsD,CAAC;QAChE,KAAK,KAAK;YACR,OAAO,0EAA0E,CAAC;QACpF,KAAK,KAAK;YACR,OAAO,8DAA8D,CAAC;IAC1E,CAAC;AACH,CAAC"} |
+267
| import { | ||
| getColumnWidths, | ||
| getContentWidth, | ||
| getHeadingWidth, | ||
| getStringWidth, | ||
| renderContentLine, | ||
| renderHeaderOpen, | ||
| renderRowSeparator, | ||
| renderSectionClose, | ||
| } from "./internal/format.js"; | ||
| export type TableRow = string[]; | ||
| export interface TableDivider { | ||
| type: "divider"; | ||
| } | ||
| export type TableItem = TableRow | TableDivider; | ||
| export const divider: TableDivider = { type: "divider" }; | ||
| /** | ||
| * Formats an array of rows and dividers into a table string. | ||
| * | ||
| * @param items An array of table rows (string arrays) and dividers. | ||
| * Dividers are objects with type: "divider" and will be rendered as table dividers. | ||
| * @returns The formatted table as a string, ready to be rendered. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * formatTable([ | ||
| * ["Name", "Age"], | ||
| * divider, | ||
| * ["Alice", "30"], | ||
| * ["Bob", "25"], | ||
| * divider, | ||
| * ["Average", "27.5"] | ||
| * ]); | ||
| * | ||
| * // => | ||
| * // | Name | Age | | ||
| * // | ------- | ---- | | ||
| * // | Alice | 30 | | ||
| * // | Bob | 25 | | ||
| * // | ------- | ---- | | ||
| * // | Average | 27.5 | | ||
| * ``` | ||
| */ | ||
| export function formatTable(items: TableItem[]): string { | ||
| const widths: number[] = []; | ||
| const dataRows: string[][] = []; | ||
| for (const item of items) { | ||
| if (Array.isArray(item)) { | ||
| dataRows.push([...item]); | ||
| } | ||
| } | ||
| // Calculate maximum width for each column | ||
| for (const row of dataRows) { | ||
| for (let i = 0; i < row.length; i++) { | ||
| while (i >= widths.length) { | ||
| widths.push(0); | ||
| } | ||
| widths[i] = Math.max(widths[i], getStringWidth(row[i])); | ||
| } | ||
| } | ||
| const dividerRow = widths.map((width) => "-".repeat(width)); | ||
| const outputRows: string[][] = []; | ||
| for (const item of items) { | ||
| if (Array.isArray(item)) { | ||
| const row = [...item]; | ||
| // Pad the row to match the number of columns | ||
| while (row.length < widths.length) { | ||
| row.push(""); | ||
| } | ||
| outputRows.push(row); | ||
| } else { | ||
| outputRows.push([...dividerRow]); | ||
| } | ||
| } | ||
| outputRows.forEach((row) => { | ||
| for (let i = 0; i < row.length; i++) { | ||
| const displayWidth = getStringWidth(row[i]); | ||
| const actualLength = row[i].length; | ||
| // Adjust padding to account for difference between display width and actual length | ||
| row[i] = row[i].padEnd(widths[i] + actualLength - displayWidth); | ||
| } | ||
| }); | ||
| return outputRows.map((row) => `| ${row.join(" | ")} |`).join("\n"); | ||
| } | ||
| export interface TableTitleV2 { | ||
| type: "title"; | ||
| text: string; | ||
| } | ||
| export interface TableSectionHeaderV2 { | ||
| type: "section-header"; | ||
| text: string; | ||
| } | ||
| export interface TableHeaderV2 { | ||
| type: "header"; | ||
| cells: string[]; | ||
| } | ||
| export interface TableRowV2 { | ||
| type: "row"; | ||
| cells: string[]; | ||
| } | ||
| export type TableItemV2 = | ||
| | TableTitleV2 | ||
| | TableSectionHeaderV2 | ||
| | TableHeaderV2 | ||
| | TableRowV2; | ||
| /** | ||
| * Formats an array of titles, section headers, headers, and rows into a table | ||
| * string with box-drawing characters. | ||
| * | ||
| * Features: | ||
| * - Titles are centered in a standalone box with double borders (╔═╗) | ||
| * - Section headers group related content with automatic closing | ||
| * - Headers and rows can have different numbers of cells | ||
| * - Rows with fewer cells than max columns are handled with special rendering | ||
| * | ||
| * @param items An array of table items (titles, section headers, headers, and rows). | ||
| * Sections are automatically closed when a new section-header or title appears, or | ||
| * at the end of the table. | ||
| * @returns The formatted table as a string, ready to be rendered. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * formatTableV2([ | ||
| * { type: "title", text: "My Table" }, | ||
| * { type: "section-header", text: "User Data" }, | ||
| * { type: "header", cells: ["Name", "Age", "City"] }, | ||
| * { type: "row", cells: ["Alice", "30", "NYC"] }, | ||
| * { type: "row", cells: ["Bob", "25", "LA"] }, | ||
| * { type: "section-header", text: "Summary" }, | ||
| * { type: "header", cells: ["Total", "Count"] }, | ||
| * { type: "row", cells: ["55", "2"] } | ||
| * ]); | ||
| * | ||
| * // => | ||
| * // ╔═══════════════════╗ | ||
| * // ║ My Table ║ | ||
| * // ╚═══════════════════╝ | ||
| * // ╔═══════════════════╗ | ||
| * // ║ User Data ║ | ||
| * // ╟───────┬─────┬─────╢ | ||
| * // ║ Name │ Age │ City║ | ||
| * // ╟───────┼─────┼─────╢ | ||
| * // ║ Alice │ 30 │ NYC ║ | ||
| * // ╟───────┼─────┼─────╢ | ||
| * // ║ Bob │ 25 │ LA ║ | ||
| * // ╚═══════╧═════╧═════╝ | ||
| * // ╔═══════════════════╗ | ||
| * // ║ Summary ║ | ||
| * // ╟───────┬───────────╢ | ||
| * // ║ Total │ Count ║ | ||
| * // ╟───────┼───────────╢ | ||
| * // ║ 55 │ 2 ║ | ||
| * // ╚═══════╧═══════════╝ | ||
| * ``` | ||
| */ | ||
| export function formatTableV2(items: TableItemV2[]): string { | ||
| if (items.length === 0) { | ||
| return ""; | ||
| } | ||
| const columnWidths = getColumnWidths(items); | ||
| const contentWidth = getContentWidth(columnWidths); | ||
| const headingWidth = getHeadingWidth(items); | ||
| // If heading is wider than content, expand last column to fit | ||
| if (headingWidth > contentWidth && columnWidths.length > 0) { | ||
| const extraSpace = headingWidth - contentWidth; | ||
| columnWidths[columnWidths.length - 1] += extraSpace; | ||
| } | ||
| const tableWidth = Math.max(contentWidth, headingWidth); | ||
| const lines: string[] = []; | ||
| let previousCellCount = 0; // Keep track of previous row/header cell count | ||
| let inSection = false; | ||
| for (let i = 0; i < items.length; i++) { | ||
| const [previous, current] = [items[i - 1], items[i]]; | ||
| if (current.type === "title") { | ||
| if (inSection) { | ||
| lines.push(renderSectionClose(columnWidths, previousCellCount)); | ||
| inSection = false; | ||
| } | ||
| lines.push("╔" + "═".repeat(tableWidth) + "╗"); | ||
| const titleDisplayWidth = getStringWidth(current.text); | ||
| const titleActualLength = current.text.length; | ||
| const centeredTitle = current.text | ||
| .padStart( | ||
| (tableWidth + titleDisplayWidth) / 2 + | ||
| (titleActualLength - titleDisplayWidth), | ||
| ) | ||
| .padEnd(tableWidth + (titleActualLength - titleDisplayWidth)); | ||
| lines.push("║" + centeredTitle + "║"); | ||
| lines.push("╚" + "═".repeat(tableWidth) + "╝"); | ||
| } else if (current.type === "section-header") { | ||
| if (inSection) { | ||
| lines.push(renderSectionClose(columnWidths, previousCellCount)); | ||
| } | ||
| lines.push("╔" + "═".repeat(tableWidth) + "╗"); | ||
| const headerDisplayWidth = getStringWidth(current.text); | ||
| const headerActualLength = current.text.length; | ||
| const paddedHeader = current.text.padEnd( | ||
| tableWidth - 2 + (headerActualLength - headerDisplayWidth), | ||
| ); | ||
| lines.push("║ " + paddedHeader + " ║"); | ||
| inSection = true; | ||
| } else if (current.type === "header") { | ||
| const currentCellCount = current.cells.length; | ||
| const innerJoiner = | ||
| previous !== undefined && previous.type === "section-header" | ||
| ? "┬" | ||
| : "┼"; | ||
| const needsTransition = | ||
| previous !== undefined && | ||
| previous.type !== "section-header" && | ||
| currentCellCount < previousCellCount; | ||
| lines.push( | ||
| renderHeaderOpen( | ||
| columnWidths, | ||
| currentCellCount, | ||
| innerJoiner, | ||
| needsTransition, | ||
| ), | ||
| ); | ||
| lines.push( | ||
| renderContentLine(current.cells, columnWidths, currentCellCount), | ||
| ); | ||
| previousCellCount = currentCellCount; | ||
| } else if (current.type === "row") { | ||
| const currentCellCount = current.cells.length; | ||
| // Only add separator if previous wasn't a row | ||
| if (previous === undefined || previous.type !== "row") { | ||
| lines.push(renderRowSeparator(columnWidths, currentCellCount)); | ||
| } | ||
| lines.push( | ||
| renderContentLine(current.cells, columnWidths, currentCellCount), | ||
| ); | ||
| previousCellCount = currentCellCount; | ||
| } | ||
| } | ||
| if (inSection) { | ||
| lines.push(renderSectionClose(columnWidths, previousCellCount)); | ||
| } | ||
| return lines.join("\n"); | ||
| } |
| import type { TableItemV2 } from "../format.js"; | ||
| /** | ||
| * Calculate the display width of a string by removing ANSI escape codes. | ||
| * | ||
| * NOTE: This implementation only removes basic ANSI color/style codes and may | ||
| * not handle all escape sequences (e.g., cursor movement, complex control | ||
| * sequences). | ||
| */ | ||
| export function getStringWidth(str: string): number { | ||
| // Remove ANSI escape codes if present | ||
| const stripped = str.replace(/\u001b\[[0-9;]*m/g, ""); | ||
| return stripped.length; | ||
| } | ||
| /** | ||
| * Calculates the minimum width needed by each column in the table | ||
| * to fit its content (accounting for ANSI color codes). | ||
| */ | ||
| export function getColumnWidths(items: TableItemV2[]): number[] { | ||
| const columnWidths: number[] = []; | ||
| for (const item of items) { | ||
| if (item.type === "row" || item.type === "header") { | ||
| item.cells.forEach((cell, i) => { | ||
| columnWidths[i] = Math.max(columnWidths[i] ?? 0, getStringWidth(cell)); | ||
| }); | ||
| } | ||
| } | ||
| return columnWidths; | ||
| } | ||
| /** | ||
| * Calculates the inner width needed to fit the rows and headers | ||
| * (excludes borders, which are added during rendering). | ||
| * | ||
| * Each column is padded by 1 space on each side, and columns are | ||
| * separated by " │ " (3 spaces). | ||
| */ | ||
| export function getContentWidth(columnWidths: number[]): number { | ||
| return ( | ||
| columnWidths.reduce((sum, w) => sum + w, 0) + | ||
| (columnWidths.length - 1) * 3 + | ||
| 2 | ||
| ); | ||
| } | ||
| /** | ||
| * Calculates the inner width needed to fit titles and section headers | ||
| * (excludes borders, which are added during rendering). | ||
| * | ||
| * Each title/header is padded by 1 space on each side. | ||
| * Accounts for ANSI color codes. | ||
| */ | ||
| export function getHeadingWidth(items: TableItemV2[]): number { | ||
| let headingWidth = 0; | ||
| for (const item of items) { | ||
| if (item.type === "section-header" || item.type === "title") { | ||
| headingWidth = Math.max(headingWidth, getStringWidth(item.text) + 2); | ||
| } | ||
| } | ||
| return headingWidth; | ||
| } | ||
| /** | ||
| * Calculates the width needed for unused columns when a row/header has fewer | ||
| * cells than the total column count (e.g., if table has 6 columns but row | ||
| * only has 2 cells, calculates space for the remaining 4 columns). | ||
| */ | ||
| export function getUnusedColumnsWidth( | ||
| columnWidths: number[], | ||
| previousCellCount: number, | ||
| ): number { | ||
| const remainingWidths = columnWidths.slice(previousCellCount); | ||
| return remainingWidths.reduce((sum, w) => sum + w + 3, 0) - 3; | ||
| } | ||
| /** | ||
| * Renders a horizontal rule segment by repeating a character for each column | ||
| * with padding, joined by a separator (e.g., "─────┼─────┼─────"). | ||
| */ | ||
| export function renderRuleSegment( | ||
| columnWidths: number[], | ||
| char: string, | ||
| joiner: string, | ||
| ): string { | ||
| return columnWidths.map((w) => char.repeat(w + 2)).join(joiner); | ||
| } | ||
| /** | ||
| * Renders a complete horizontal rule with left and right borders | ||
| * (e.g., "╟─────┼─────┼─────╢"). | ||
| */ | ||
| export function renderHorizontalRule( | ||
| leftBorder: string, | ||
| columnWidths: number[], | ||
| char: string, | ||
| joiner: string, | ||
| rightBorder: string, | ||
| ): string { | ||
| return ( | ||
| leftBorder + renderRuleSegment(columnWidths, char, joiner) + rightBorder | ||
| ); | ||
| } | ||
| /** | ||
| * Renders a content line containing cells from either a header or row. | ||
| * | ||
| * Handles two cases: | ||
| * - Full width: When all columns are used, cells are separated by " │ " and | ||
| * line ends with " ║" (e.g., "║ cell1 │ cell2 │ cell3 ║") | ||
| * - Short line: When fewer columns are used, active cells are followed by | ||
| * " │ " and empty space, ending with "║" (e.g., "║ cell1 │ cell2 │ ║") | ||
| * | ||
| * Accounts for ANSI color codes when padding cells. | ||
| */ | ||
| export function renderContentLine( | ||
| cells: string[], | ||
| columnWidths: number[], | ||
| currentCellCount: number, | ||
| ): string { | ||
| if (currentCellCount === columnWidths.length) { | ||
| return ( | ||
| "║ " + | ||
| cells | ||
| .map((cell, j) => { | ||
| const displayWidth = getStringWidth(cell); | ||
| const actualLength = cell.length; | ||
| // Adjust padding to account for ANSI escape codes | ||
| return cell.padEnd(columnWidths[j] + actualLength - displayWidth); | ||
| }) | ||
| .join(" │ ") + | ||
| " ║" | ||
| ); | ||
| } else { | ||
| const usedWidths = columnWidths.slice(0, currentCellCount); | ||
| const remainingWidth = getUnusedColumnsWidth( | ||
| columnWidths, | ||
| currentCellCount, | ||
| ); | ||
| return ( | ||
| "║ " + | ||
| cells | ||
| .map((cell, j) => { | ||
| const displayWidth = getStringWidth(cell); | ||
| const actualLength = cell.length; | ||
| // Adjust padding to account for ANSI escape codes | ||
| return cell.padEnd(usedWidths[j] + actualLength - displayWidth); | ||
| }) | ||
| .join(" │ ") + | ||
| " │ " + | ||
| " ".repeat(remainingWidth + 1) + | ||
| "║" | ||
| ); | ||
| } | ||
| } | ||
| /** | ||
| * Renders the horizontal rule that appears above a header row. | ||
| * | ||
| * Handles three cases: | ||
| * - Transition rule: When going from more columns to fewer, shows ┴ marks | ||
| * where columns collapse (e.g., "╟───┼───┼───┴───┴───╢") | ||
| * - Full width: When header uses all columns (e.g., "╟───┬───┬───╢" or "╟───┼───┼───╢") | ||
| * - Short header: When header uses fewer columns than max (e.g., "╟───┬─────────╢") | ||
| * | ||
| * The innerJoiner determines the separator character: ┬ after section-header, ┼ otherwise. | ||
| */ | ||
| export function renderHeaderOpen( | ||
| columnWidths: number[], | ||
| currentCellCount: number, | ||
| innerJoiner: string, | ||
| needsTransition: boolean, | ||
| ): string { | ||
| if (needsTransition) { | ||
| const usedWidths = columnWidths.slice(0, currentCellCount); | ||
| const collapsingWidths = columnWidths.slice(currentCellCount); | ||
| return ( | ||
| "╟" + | ||
| renderRuleSegment(usedWidths, "─", "┼") + | ||
| "┼" + | ||
| renderRuleSegment(collapsingWidths, "─", "┴") + | ||
| "╢" | ||
| ); | ||
| } else if (currentCellCount === columnWidths.length) { | ||
| return renderHorizontalRule("╟", columnWidths, "─", innerJoiner, "╢"); | ||
| } else { | ||
| const usedWidths = columnWidths.slice(0, currentCellCount); | ||
| const remainingWidth = getUnusedColumnsWidth( | ||
| columnWidths, | ||
| currentCellCount, | ||
| ); | ||
| return ( | ||
| "╟" + | ||
| renderRuleSegment(usedWidths, "─", innerJoiner) + | ||
| innerJoiner + | ||
| "─".repeat(remainingWidth + 2) + | ||
| "╢" | ||
| ); | ||
| } | ||
| } | ||
| /** | ||
| * Renders the horizontal rule that appears above a row. | ||
| * | ||
| * Handles two cases: | ||
| * - Full width: When row uses all columns, renders with ┼ joiners and | ||
| * ends with ╢ (e.g., "╟───┼───┼───╢") | ||
| * - Short row: When row uses fewer columns, renders active columns with | ||
| * ┼ joiners, ends with ┤, then fills remaining space and ends with ║ | ||
| * (e.g., "╟───┼───┤ ║") | ||
| */ | ||
| export function renderRowSeparator( | ||
| columnWidths: number[], | ||
| currentCellCount: number, | ||
| ): string { | ||
| if (currentCellCount === columnWidths.length) { | ||
| return renderHorizontalRule("╟", columnWidths, "─", "┼", "╢"); | ||
| } else { | ||
| // Short row - ends with ┤ instead of ╢ | ||
| const usedWidths = columnWidths.slice(0, currentCellCount); | ||
| const remainingWidth = getUnusedColumnsWidth( | ||
| columnWidths, | ||
| currentCellCount, | ||
| ); | ||
| return ( | ||
| "╟" + | ||
| renderRuleSegment(usedWidths, "─", "┼") + | ||
| "┤" + | ||
| " ".repeat(remainingWidth + 2) + | ||
| "║" | ||
| ); | ||
| } | ||
| } | ||
| /** | ||
| * Renders the section's bottom border, placing ╧ marks under column | ||
| * separators where the last row/header had cells (e.g., if the last row | ||
| * looked like "║ a │ b │ ║", the bottom border would be | ||
| * "╚═══╧═══╧═══════╝"). | ||
| */ | ||
| export function renderSectionClose( | ||
| columnWidths: number[], | ||
| previousCellCount: number, | ||
| ): string { | ||
| if (previousCellCount === columnWidths.length) { | ||
| return renderHorizontalRule("╚", columnWidths, "═", "╧", "╝"); | ||
| } else { | ||
| const usedWidths = columnWidths.slice(0, previousCellCount); | ||
| const unusedWidth = getUnusedColumnsWidth(columnWidths, previousCellCount); | ||
| return ( | ||
| "╚" + | ||
| renderRuleSegment(usedWidths, "═", "╧") + | ||
| "╧" + | ||
| renderRuleSegment([unusedWidth], "═", "") + | ||
| "╝" | ||
| ); | ||
| } | ||
| } |
| export function panicErrorCodeToReason(errorCode: bigint): string | undefined { | ||
| // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- we are only covering some of the integer range | ||
| switch (errorCode) { | ||
| case 0x1n: | ||
| return "Assertion error"; | ||
| case 0x11n: | ||
| return "Arithmetic operation overflowed outside of an unchecked block"; | ||
| case 0x12n: | ||
| return "Division or modulo division by zero"; | ||
| case 0x21n: | ||
| return "Tried to convert a value into an enum, but the value was too big or negative"; | ||
| case 0x22n: | ||
| return "Incorrectly encoded storage byte array"; | ||
| case 0x31n: | ||
| return ".pop() was called on an empty array"; | ||
| case 0x32n: | ||
| return "Array accessed at an out-of-bounds or negative index"; | ||
| case 0x41n: | ||
| return "Too much memory was allocated, or an array was created that is too large"; | ||
| case 0x51n: | ||
| return "Called a zero-initialized variable of internal function type"; | ||
| } | ||
| } |
+6
-0
| # @nomicfoundation/hardhat-utils | ||
| ## 3.0.4 | ||
| ### Patch Changes | ||
| - d1969e7: Added support for showing gas statistics after running nodejs tests ([#7472](https://github.com/NomicFoundation/hardhat/issues/7428)). | ||
| ## 3.0.3 | ||
@@ -4,0 +10,0 @@ |
@@ -0,2 +1,15 @@ | ||
| /** | ||
| * Converts a Solidity panic error code into a human-readable revert message. | ||
| * | ||
| * Solidity defines a set of standardized panic codes (0x01, 0x11, etc.) | ||
| * that represent specific runtime errors (e.g. arithmetic overflow). | ||
| * This function looks up the corresponding reason string and formats it | ||
| * into a message similar to what clients like Hardhat or ethers.js display. | ||
| * | ||
| * @param errorCode The panic error code returned by the EVM as a bigint. | ||
| * @returns A formatted message string: | ||
| * - `"reverted with panic code <hex> (<reason>)"` if the code is recognized. | ||
| * - `"reverted with unknown panic code <hex>"` if the code is not recognized. | ||
| */ | ||
| export declare function panicErrorCodeToMessage(errorCode: bigint): string; | ||
| //# sourceMappingURL=panic-errors.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"panic-errors.d.ts","sourceRoot":"","sources":["../../src/panic-errors.ts"],"names":[],"mappings":"AAEA,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQjE"} | ||
| {"version":3,"file":"panic-errors.d.ts","sourceRoot":"","sources":["../../src/panic-errors.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQjE"} |
+14
-23
| import { numberToHexString } from "./hex.js"; | ||
| import { panicErrorCodeToReason } from "./internal/panic-errors.js"; | ||
| /** | ||
| * Converts a Solidity panic error code into a human-readable revert message. | ||
| * | ||
| * Solidity defines a set of standardized panic codes (0x01, 0x11, etc.) | ||
| * that represent specific runtime errors (e.g. arithmetic overflow). | ||
| * This function looks up the corresponding reason string and formats it | ||
| * into a message similar to what clients like Hardhat or ethers.js display. | ||
| * | ||
| * @param errorCode The panic error code returned by the EVM as a bigint. | ||
| * @returns A formatted message string: | ||
| * - `"reverted with panic code <hex> (<reason>)"` if the code is recognized. | ||
| * - `"reverted with unknown panic code <hex>"` if the code is not recognized. | ||
| */ | ||
| export function panicErrorCodeToMessage(errorCode) { | ||
@@ -9,25 +23,2 @@ const reason = panicErrorCodeToReason(errorCode); | ||
| } | ||
| function panicErrorCodeToReason(errorCode) { | ||
| // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- we are only covering some of the integer range | ||
| switch (errorCode) { | ||
| case 0x1n: | ||
| return "Assertion error"; | ||
| case 0x11n: | ||
| return "Arithmetic operation overflowed outside of an unchecked block"; | ||
| case 0x12n: | ||
| return "Division or modulo division by zero"; | ||
| case 0x21n: | ||
| return "Tried to convert a value into an enum, but the value was too big or negative"; | ||
| case 0x22n: | ||
| return "Incorrectly encoded storage byte array"; | ||
| case 0x31n: | ||
| return ".pop() was called on an empty array"; | ||
| case 0x32n: | ||
| return "Array accessed at an out-of-bounds or negative index"; | ||
| case 0x41n: | ||
| return "Too much memory was allocated, or an array was created that is too large"; | ||
| case 0x51n: | ||
| return "Called a zero-initialized variable of internal function type"; | ||
| } | ||
| } | ||
| //# sourceMappingURL=panic-errors.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"panic-errors.js","sourceRoot":"","sources":["../../src/panic-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,UAAU,uBAAuB,CAAC,SAAiB;IACvD,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAEjD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,4BAA4B,iBAAiB,CAAC,SAAS,CAAC,KAAK,MAAM,GAAG,CAAC;IAChF,CAAC;IAED,OAAO,oCAAoC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,SAAS,sBAAsB,CAAC,SAAiB;IAC/C,4HAA4H;IAC5H,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,IAAI;YACP,OAAO,iBAAiB,CAAC;QAC3B,KAAK,KAAK;YACR,OAAO,+DAA+D,CAAC;QACzE,KAAK,KAAK;YACR,OAAO,qCAAqC,CAAC;QAC/C,KAAK,KAAK;YACR,OAAO,8EAA8E,CAAC;QACxF,KAAK,KAAK;YACR,OAAO,wCAAwC,CAAC;QAClD,KAAK,KAAK;YACR,OAAO,qCAAqC,CAAC;QAC/C,KAAK,KAAK;YACR,OAAO,sDAAsD,CAAC;QAChE,KAAK,KAAK;YACR,OAAO,0EAA0E,CAAC;QACpF,KAAK,KAAK;YACR,OAAO,8DAA8D,CAAC;IAC1E,CAAC;AACH,CAAC"} | ||
| {"version":3,"file":"panic-errors.js","sourceRoot":"","sources":["../../src/panic-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEpE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAiB;IACvD,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAEjD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,4BAA4B,iBAAiB,CAAC,SAAS,CAAC,KAAK,MAAM,GAAG,CAAC;IAChF,CAAC;IAED,OAAO,oCAAoC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;AAC5E,CAAC"} |
+2
-1
| { | ||
| "name": "@nomicfoundation/hardhat-utils", | ||
| "version": "3.0.3", | ||
| "version": "3.0.4", | ||
| "description": "Utilities for Hardhat and its plugins", | ||
@@ -26,2 +26,3 @@ "homepage": "https://github.com/nomicfoundation/hardhat/tree/v-next/v-next/hardhat-utils", | ||
| "./eth": "./dist/src/eth.js", | ||
| "./format": "./dist/src/format.js", | ||
| "./fs": "./dist/src/fs.js", | ||
@@ -28,0 +29,0 @@ "./global-dir": "./dist/src/global-dir.js", |
+14
-24
| import { numberToHexString } from "./hex.js"; | ||
| import { panicErrorCodeToReason } from "./internal/panic-errors.js"; | ||
| /** | ||
| * Converts a Solidity panic error code into a human-readable revert message. | ||
| * | ||
| * Solidity defines a set of standardized panic codes (0x01, 0x11, etc.) | ||
| * that represent specific runtime errors (e.g. arithmetic overflow). | ||
| * This function looks up the corresponding reason string and formats it | ||
| * into a message similar to what clients like Hardhat or ethers.js display. | ||
| * | ||
| * @param errorCode The panic error code returned by the EVM as a bigint. | ||
| * @returns A formatted message string: | ||
| * - `"reverted with panic code <hex> (<reason>)"` if the code is recognized. | ||
| * - `"reverted with unknown panic code <hex>"` if the code is not recognized. | ||
| */ | ||
| export function panicErrorCodeToMessage(errorCode: bigint): string { | ||
@@ -12,25 +26,1 @@ const reason = panicErrorCodeToReason(errorCode); | ||
| } | ||
| function panicErrorCodeToReason(errorCode: bigint): string | undefined { | ||
| // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- we are only covering some of the integer range | ||
| switch (errorCode) { | ||
| case 0x1n: | ||
| return "Assertion error"; | ||
| case 0x11n: | ||
| return "Arithmetic operation overflowed outside of an unchecked block"; | ||
| case 0x12n: | ||
| return "Division or modulo division by zero"; | ||
| case 0x21n: | ||
| return "Tried to convert a value into an enum, but the value was too big or negative"; | ||
| case 0x22n: | ||
| return "Incorrectly encoded storage byte array"; | ||
| case 0x31n: | ||
| return ".pop() was called on an empty array"; | ||
| case 0x32n: | ||
| return "Array accessed at an out-of-bounds or negative index"; | ||
| case 0x41n: | ||
| return "Too much memory was allocated, or an array was created that is too large"; | ||
| case 0x51n: | ||
| return "Called a zero-initialized variable of internal function type"; | ||
| } | ||
| } |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 7 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 7 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
438102
14.58%204
7.94%8631
14.74%0
-100%