@adriangalilea/utils 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,66 @@
1
+ /**
2
+ * `cli` — terminal presentation: aligned tables, key/value blocks, trees, a
3
+ * semantic palette. Separate from `format` (which is universal value formatting,
4
+ * for every layer) — this is terminal-scoped output.
5
+ *
6
+ * Colors come from `universal/log` and auto-disable on non-TTY / NO_COLOR, so a
7
+ * `table()` renders colored in a terminal and as plain aligned text in a pipe,
8
+ * log file, or a bot's monospace block — correct everywhere.
9
+ *
10
+ * Alignment is ANSI-aware: padding is computed on the *visible* width (escape
11
+ * codes stripped), so colored cells line up.
12
+ *
13
+ * @example
14
+ * import { table, kv, ui, indent } from '@adriangalilea/utils/cli'
15
+ *
16
+ * console.log(table(
17
+ * [['Ada', ui.accent('ada@x.com'), ui.muted('work')],
18
+ * ['Bo', ui.accent('bo@y.com'), ui.muted('home')]],
19
+ * { head: ['name', 'email', 'label'] },
20
+ * ))
21
+ */
22
+ /** Visible width of a string — ANSI escape codes stripped, counted by code point. */
23
+ export declare const width: (s: string) => number;
24
+ /** Truncate to `n` visible chars with an ellipsis. Assumes `s` is unstyled. */
25
+ export declare const truncate: (s: string, n: number) => string;
26
+ /** Semantic palette — use these, not raw colors, so intent stays consistent. */
27
+ export declare const ui: {
28
+ head: (s: string) => string;
29
+ accent: (s: string) => string;
30
+ muted: (s: string) => string;
31
+ ok: (s: string) => string;
32
+ warn: (s: string) => string;
33
+ bad: (s: string) => string;
34
+ /** ids / refs — de-emphasized monospace-ish */
35
+ ref: (s: string) => string;
36
+ };
37
+ export interface TableOpts {
38
+ /** Column headers (bolded). */
39
+ head?: string[];
40
+ /** Per-column alignment; default all left. */
41
+ align?: ("l" | "r")[];
42
+ /** Spaces between columns (default 2). */
43
+ gap?: number;
44
+ /** Left indent for the whole table (default 0). */
45
+ indent?: number;
46
+ }
47
+ /**
48
+ * Render rows as aligned columns. Cells may be pre-colored — widths use visible
49
+ * length so colored columns still line up. The last left-aligned column isn't
50
+ * right-padded (no trailing whitespace).
51
+ */
52
+ export declare function table(rows: string[][], opts?: TableOpts): string;
53
+ /** Key/value block (aligned keys), e.g. for a detail view. */
54
+ export declare function kv(pairs: [string, string][], opts?: {
55
+ indent?: number;
56
+ gap?: number;
57
+ }): string;
58
+ /** Indent every line of a (possibly multi-line) string by `n` spaces. */
59
+ export declare const indent: (s: string, n: number) => string;
60
+ /** A labeled node with child lines drawn under it. */
61
+ export declare function tree(label: string, children: string[], opts?: {
62
+ indent?: number;
63
+ }): string;
64
+ /** A small inline badge, e.g. `badge('golden', ui.ok)`. */
65
+ export declare const badge: (text: string, style?: (s: string) => string) => string;
66
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAOH,qFAAqF;AACrF,eAAO,MAAM,KAAK,GAAI,GAAG,MAAM,KAAG,MAA4C,CAAC;AAE/E,+EAA+E;AAC/E,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MACsB,CAAC;AAOvE,gFAAgF;AAChF,eAAO,MAAM,EAAE;cACJ,MAAM;gBACJ,MAAM;eACP,MAAM;YACT,MAAM;cACJ,MAAM;aACP,MAAM;IACf,+CAA+C;aACtC,MAAM;CACf,CAAC;AAEF,MAAM,WAAW,SAAS;IACzB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC;IACtB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAE,SAAc,GAAG,MAAM,CAwBpE;AAED,8DAA8D;AAC9D,wBAAgB,EAAE,CACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EACzB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1C,MAAM,CAOR;AAED,yEAAyE;AACzE,eAAO,MAAM,MAAM,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAIjC,CAAC;AAEd,sDAAsD;AACtD,wBAAgB,IAAI,CACnB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5B,MAAM,CAGR;AAED,2DAA2D;AAC3D,eAAO,MAAM,KAAK,GACjB,MAAM,MAAM,EACZ,QAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAiB,KACrC,MAAqB,CAAC"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * `cli` — terminal presentation: aligned tables, key/value blocks, trees, a
3
+ * semantic palette. Separate from `format` (which is universal value formatting,
4
+ * for every layer) — this is terminal-scoped output.
5
+ *
6
+ * Colors come from `universal/log` and auto-disable on non-TTY / NO_COLOR, so a
7
+ * `table()` renders colored in a terminal and as plain aligned text in a pipe,
8
+ * log file, or a bot's monospace block — correct everywhere.
9
+ *
10
+ * Alignment is ANSI-aware: padding is computed on the *visible* width (escape
11
+ * codes stripped), so colored cells line up.
12
+ *
13
+ * @example
14
+ * import { table, kv, ui, indent } from '@adriangalilea/utils/cli'
15
+ *
16
+ * console.log(table(
17
+ * [['Ada', ui.accent('ada@x.com'), ui.muted('work')],
18
+ * ['Bo', ui.accent('bo@y.com'), ui.muted('home')]],
19
+ * { head: ['name', 'email', 'label'] },
20
+ * ))
21
+ */
22
+ import { bold, cyan, dim, gray, green, red, yellow } from "../universal/log.js";
23
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: matching ANSI escapes is the point
24
+ const ANSI_RE = /\x1b\[[0-9;]*m/g;
25
+ /** Visible width of a string — ANSI escape codes stripped, counted by code point. */
26
+ export const width = (s) => [...s.replace(ANSI_RE, "")].length;
27
+ /** Truncate to `n` visible chars with an ellipsis. Assumes `s` is unstyled. */
28
+ export const truncate = (s, n) => width(s) > n ? `${[...s].slice(0, Math.max(0, n - 1)).join("")}…` : s;
29
+ const padEndV = (s, n) => s + " ".repeat(Math.max(0, n - width(s)));
30
+ const padStartV = (s, n) => " ".repeat(Math.max(0, n - width(s))) + s;
31
+ /** Semantic palette — use these, not raw colors, so intent stays consistent. */
32
+ export const ui = {
33
+ head: (s) => bold(s),
34
+ accent: (s) => cyan(s),
35
+ muted: (s) => dim(s),
36
+ ok: (s) => green(s),
37
+ warn: (s) => yellow(s),
38
+ bad: (s) => red(s),
39
+ /** ids / refs — de-emphasized monospace-ish */
40
+ ref: (s) => gray(s),
41
+ };
42
+ /**
43
+ * Render rows as aligned columns. Cells may be pre-colored — widths use visible
44
+ * length so colored columns still line up. The last left-aligned column isn't
45
+ * right-padded (no trailing whitespace).
46
+ */
47
+ export function table(rows, opts = {}) {
48
+ const gap = " ".repeat(opts.gap ?? 2);
49
+ const lead = " ".repeat(opts.indent ?? 0);
50
+ const body = opts.head ? [opts.head, ...rows] : rows;
51
+ const cols = Math.max(0, ...body.map((r) => r.length));
52
+ const w = Array.from({ length: cols }, (_, c) => Math.max(0, ...body.map((r) => width(r[c] ?? ""))));
53
+ const line = (r) => {
54
+ const cells = Array.from({ length: cols }, (_, c) => {
55
+ const cell = r[c] ?? "";
56
+ const isLast = c === cols - 1;
57
+ const right = opts.align?.[c] === "r";
58
+ if (right)
59
+ return padStartV(cell, w[c]);
60
+ return isLast ? cell : padEndV(cell, w[c]);
61
+ });
62
+ return lead + cells.join(gap).replace(/\s+$/, "");
63
+ };
64
+ const out = [];
65
+ if (opts.head)
66
+ out.push(line(opts.head.map((h) => ui.head(h))));
67
+ for (const r of rows)
68
+ out.push(line(r));
69
+ return out.join("\n");
70
+ }
71
+ /** Key/value block (aligned keys), e.g. for a detail view. */
72
+ export function kv(pairs, opts = {}) {
73
+ const lead = " ".repeat(opts.indent ?? 0);
74
+ const gap = " ".repeat(opts.gap ?? 2);
75
+ const w = Math.max(0, ...pairs.map(([k]) => width(k)));
76
+ return pairs
77
+ .map(([k, v]) => `${lead}${ui.muted(padEndV(k, w))}${gap}${v}`)
78
+ .join("\n");
79
+ }
80
+ /** Indent every line of a (possibly multi-line) string by `n` spaces. */
81
+ export const indent = (s, n) => s
82
+ .split("\n")
83
+ .map((l) => " ".repeat(n) + l)
84
+ .join("\n");
85
+ /** A labeled node with child lines drawn under it. */
86
+ export function tree(label, children, opts = {}) {
87
+ const lead = " ".repeat(opts.indent ?? 0);
88
+ return [lead + label, ...children.map((c) => `${lead} ${c}`)].join("\n");
89
+ }
90
+ /** A small inline badge, e.g. `badge('golden', ui.ok)`. */
91
+ export const badge = (text, style = ui.muted) => style(text);
92
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adriangalilea/utils",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "TypeScript utilities - logger, currency, formatter, GramIO bot plugins, and more",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -24,6 +24,10 @@
24
24
  "types": "./dist/universal/format.d.ts",
25
25
  "default": "./dist/universal/format.js"
26
26
  },
27
+ "./cli": {
28
+ "types": "./dist/cli/index.d.ts",
29
+ "default": "./dist/cli/index.js"
30
+ },
27
31
  "./currency": {
28
32
  "types": "./dist/universal/currency/index.d.ts",
29
33
  "default": "./dist/universal/currency/index.js"