Spaces:
Runtime error
Runtime error
File size: 5,682 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | import { stringify as csvStringify } from "csv-stringify/sync";
const MASK_RE = /sk-[A-Za-z0-9]{4,}/g;
export const EXIT_CODES = Object.freeze({
SUCCESS: 0,
ERROR: 1,
INVALID_ARG: 2,
SERVER_OFFLINE: 3,
AUTH: 4,
RATE_LIMIT: 5,
TIMEOUT: 124,
});
export function maskSecret(value) {
if (typeof value !== "string") return value;
return value.replace(MASK_RE, (m) => `${m.slice(0, 5)}***${m.slice(-4)}`);
}
function toRows(data) {
if (Array.isArray(data)) return data;
if (data !== null && typeof data === "object") return data.items ? data.items : [data];
return [{ value: data }];
}
function pickFormat(opts) {
if (opts.output) return opts.output;
if (opts.json) return "json";
if (!process.stdout.isTTY) return "json";
return "table";
}
function inferSchema(sample) {
return Object.keys(sample).map((k) => ({ key: k, header: k }));
}
function formatCell(v, col) {
if (v == null) return "";
if (col.formatter) return col.formatter(v);
return String(v);
}
const CYAN = "\x1b[36m";
const RESET = "\x1b[0m";
/** Strip ANSI escape sequences so we can measure the visible width of a string. */
const stripAnsi = (s) => s.replace(/\x1b\[[\d;]*m/g, "");
/** Truncate a string to `max` visible chars, appending "…" if trimmed.
* ANSI escape codes are excluded from the width count and never split. */
function truncateCell(str, max) {
const visible = stripAnsi(str);
if (visible.length <= max) return str;
// Rebuild the string char-by-char, counting only visible chars, stopping at max-1.
let count = 0;
let result = "";
let i = 0;
while (i < str.length) {
// Detect an ANSI escape sequence starting at position i.
if (str[i] === "\x1b" && str[i + 1] === "[") {
const end = str.indexOf("m", i + 2);
if (end !== -1) {
// Include the full escape sequence without counting it as visible width.
result += str.slice(i, end + 1);
i = end + 1;
continue;
}
}
if (count >= max - 1) break;
result += str[i];
count++;
i++;
}
// Ensure the reset code is always appended so ANSI color never bleeds.
if (str.includes("\x1b[")) {
result += RESET;
}
return result + "…";
}
/** Pad a string to exactly `width` visible chars (left-aligned).
* ANSI escape codes are excluded from the padding calculation. */
function padCell(str, width) {
const visible = stripAnsi(str);
return str + " ".repeat(Math.max(0, width - visible.length));
}
function renderTable(rows, schema, opts = {}) {
if (rows.length === 0) {
process.stdout.write("(empty)\n");
return;
}
const cols = schema || inferSchema(rows[0]);
const quiet = opts.quiet === true;
// Compute column widths: max(header.length, max visible cell length), capped by explicit c.width.
const colWidths = cols.map((c) => {
const headerLen = c.header.length;
const maxData = rows.reduce(
(m, row) => Math.max(m, stripAnsi(formatCell(row[c.key], c)).length),
0,
);
const natural = Math.max(headerLen, maxData);
return c.width ? Math.max(c.width, 1) : natural;
});
const separator = colWidths.map((w) => "-".repeat(w + 2)).join("-+-");
const renderRow = (cells, cyan) => {
const parts = cells.map((cell, i) => {
const truncated = truncateCell(cell, colWidths[i]);
const padded = padCell(truncated, colWidths[i]);
return cyan ? ` ${CYAN}${padded}${RESET} ` : ` ${padded} `;
});
return `|${parts.join("|")}|`;
};
const lines = [];
if (!quiet) {
lines.push(separator);
lines.push(renderRow(cols.map((c) => c.header), true));
}
lines.push(separator);
for (const row of rows) {
lines.push(renderRow(cols.map((c) => formatCell(row[c.key], c)), false));
}
lines.push(separator);
process.stdout.write(lines.join("\n") + "\n");
}
function renderCsv(rows, schema) {
if (rows.length === 0) {
process.stdout.write("\n");
return;
}
const cols = schema || inferSchema(rows[0]);
const headers = cols.map((c) => c.header);
const records = rows.map((r) => cols.map((c) => formatCell(r[c.key], c)));
process.stdout.write(csvStringify([headers, ...records]));
}
function renderJsonl(rows) {
for (const row of rows) process.stdout.write(JSON.stringify(row) + "\n");
}
/**
* Emit structured data to stdout in the requested format.
* @param {unknown} data - Array of objects or single object
* @param {object} opts - Options: { output, json, quiet }
* @param {Array|null} schema - Column definitions: [{ key, header, width?, formatter? }]
*/
export function emit(data, opts = {}, schema = null) {
const format = pickFormat(opts);
const rows = toRows(data);
switch (format) {
case "json":
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
break;
case "jsonl":
renderJsonl(rows);
break;
case "csv":
renderCsv(rows, schema);
break;
default:
renderTable(rows, schema, opts);
}
}
export function printHeading(title, quiet = false) {
if (quiet) return;
process.stderr.write(`\n\x1b[1m\x1b[36m${title}\x1b[0m\n\n`);
}
export function printSuccess(message, quiet = false) {
if (quiet) return;
process.stderr.write(`\x1b[32m✔ ${message}\x1b[0m\n`);
}
export function printInfo(message, quiet = false) {
if (quiet) return;
process.stderr.write(`\x1b[2m${message}\x1b[0m\n`);
}
export function printWarning(message) {
process.stderr.write(`\x1b[33m⚠ ${message}\x1b[0m\n`);
}
export function printError(message) {
process.stderr.write(`\x1b[31m✖ ${message}\x1b[0m\n`);
}
export function exitWith(code, message) {
if (message) printError(message);
process.exit(code);
}
|