@0disoft/laqu
Advanced tools
@@ -48,5 +48,3 @@ import { type LaquEvent } from "./events.js"; | ||
| private readonly theme; | ||
| private readonly columns; | ||
| private readonly maxRows; | ||
| constructor(theme: CompiledTheme, columns: number, maxRows: number); | ||
| constructor(theme: CompiledTheme, _columns?: number, _maxRows?: number); | ||
| render(snapshot: RuntimeSnapshot): Frame; | ||
@@ -53,0 +51,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEjF,OAAO,KAAK,EAAa,eAAe,EAA4B,MAAM,iBAAiB,CAAC;AAE5F,MAAM,MAAM,KAAK,GACb;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAA;CAAE,GAChE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9B,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK,CAAC;IACzC,QAAQ,CAAC,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK,CAAC;CAC7C;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;CAC/C;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB,CAkCzE;AAED,qBAAa,gBAAiB,YAAW,QAAQ;;IAI7C,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAFP,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM;IAGlC,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK;CAWzC;AAED,qBAAa,gBAAiB,YAAW,QAAQ;;IAK7C,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAFP,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM;IAGlC,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK;CAuBzC;AAED,qBAAa,iBAAkB,YAAW,QAAQ;;IAKhD,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK;IA0BxC,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK;CAS3C;AAkBD,qBAAa,YAAa,YAAW,QAAQ;IAC3C,MAAM,IAAI,KAAK;CAGhB"} | ||
| {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEjF,OAAO,KAAK,EAAa,eAAe,EAA4B,MAAM,iBAAiB,CAAC;AAE5F,MAAM,MAAM,KAAK,GACb;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAA;CAAE,GAChE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9B,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK,CAAC;IACzC,QAAQ,CAAC,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK,CAAC;CAC7C;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;CAC/C;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB,CAkCzE;AAED,qBAAa,gBAAiB,YAAW,QAAQ;;IAI7C,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAFP,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM;IAGlC,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK;CAWzC;AAED,qBAAa,gBAAiB,YAAW,QAAQ;;IAK7C,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,aAAa,EACrC,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM;IAGnB,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK;CAoBzC;AAED,qBAAa,iBAAkB,YAAW,QAAQ;;IAKhD,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK;IAsBxC,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK;CAS3C;AAkBD,qBAAa,YAAa,YAAW,QAAQ;IAC3C,MAAM,IAAI,KAAK;CAGhB"} |
+15
-17
@@ -17,3 +17,3 @@ import { logEvent, summaryEvent, taskEvent } from "./events.js"; | ||
| return { | ||
| renderer: new PlainLogRenderer(options.theme, options.columns, options.maxRows), | ||
| renderer: new PlainLogRenderer(options.theme), | ||
| live: false, | ||
@@ -32,3 +32,3 @@ jsonSerialization: "none", | ||
| return { | ||
| renderer: new PlainLogRenderer(options.theme, options.columns, options.maxRows), | ||
| renderer: new PlainLogRenderer(options.theme), | ||
| live: false, | ||
@@ -61,10 +61,6 @@ jsonSerialization: "none", | ||
| theme; | ||
| columns; | ||
| maxRows; | ||
| #seenTaskStates = new Map(); | ||
| #seenLogSequence = 0; | ||
| constructor(theme, columns, maxRows) { | ||
| constructor(theme, _columns, _maxRows) { | ||
| this.theme = theme; | ||
| this.columns = columns; | ||
| this.maxRows = maxRows; | ||
| } | ||
@@ -74,8 +70,8 @@ render(snapshot) { | ||
| const newLogs = logsAfterSequence(snapshot.logs, this.#seenLogSequence); | ||
| lines.push(...renderLogLines(newLogs, this.theme, this.columns)); | ||
| lines.push(...newLogs.map((log) => sanitizeText(log.message))); | ||
| this.#seenLogSequence = lastLogSequence(snapshot.logs, this.#seenLogSequence); | ||
| const rows = flattenTasks(snapshot.tasks).slice(0, this.maxRows); | ||
| const rows = flattenTasks(snapshot.tasks); | ||
| pruneSeenTaskStates(this.#seenTaskStates, rows); | ||
| for (const row of rows) { | ||
| const state = `${row.status}:${row.message ?? ""}:${row.detail ?? ""}:${progressText(row, this.theme)}`; | ||
| const state = taskStateKey(row); | ||
| if (this.#seenTaskStates.get(row.id) === state) { | ||
@@ -85,3 +81,3 @@ continue; | ||
| this.#seenTaskStates.set(row.id, state); | ||
| lines.push(renderTaskRow(row, this.theme, this.columns)); | ||
| lines.push(renderTaskRow(row, this.theme)); | ||
| } | ||
@@ -104,5 +100,3 @@ return lines.length === 0 ? { kind: "none" } : { kind: "plain", lines }; | ||
| for (const task of tasks) { | ||
| const ratio = task.aggregate.kind === "ratio" ? task.aggregate.ratio : undefined; | ||
| const overrun = task.aggregate.kind === "ratio" ? task.aggregate.overrun : undefined; | ||
| const state = `${task.status}:${task.message ?? ""}:${task.detail ?? ""}:${task.aggregate.kind}:${ratio ?? ""}:${overrun ?? ""}`; | ||
| const state = taskStateKey(task); | ||
| if (this.#seenTaskStates.get(task.id) === state) { | ||
@@ -193,6 +187,10 @@ continue; | ||
| ]); | ||
| return truncateToColumns(`${row}${detail}`, columns, { | ||
| overflowMarker: theme.tokens.overflowMarker, | ||
| }); | ||
| const rendered = `${row}${detail}`; | ||
| return columns === undefined | ||
| ? rendered | ||
| : truncateToColumns(rendered, columns, { overflowMarker: theme.tokens.overflowMarker }); | ||
| } | ||
| function taskStateKey(task) { | ||
| return JSON.stringify([task.status, task.message, task.detail, task.progress, task.aggregate]); | ||
| } | ||
| function statusSymbol(task, theme) { | ||
@@ -199,0 +197,0 @@ switch (task.status) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAEV,eAAe,EAEf,cAAc,EAKf,MAAM,YAAY,CAAC;AASpB,wBAAgB,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,eAAe,CAExE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,cAAmB,GAAG,eAAe,CAuCnF;AA2iBD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,KAAK,CAW9D"} | ||
| {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAEV,eAAe,EAEf,cAAc,EAKf,MAAM,YAAY,CAAC;AASpB,wBAAgB,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,eAAe,CAExE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,cAAmB,GAAG,eAAe,CAuCnF;AA8jBD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,KAAK,CAW9D"} |
+28
-10
@@ -60,2 +60,4 @@ import { AsyncLocalStorage } from "node:async_hooks"; | ||
| #closeRequestedByScopedTask = false; | ||
| #scopedTasksDrained; | ||
| #resolveScopedTasksDrained; | ||
| constructor(store, coordinator, policy, liveStreamLease) { | ||
@@ -98,2 +100,7 @@ this.store = store; | ||
| this.#activeScopedTasks -= 1; | ||
| if (this.#activeScopedTasks === 0) { | ||
| this.#resolveScopedTasksDrained?.(); | ||
| this.#resolveScopedTasksDrained = undefined; | ||
| this.#scopedTasksDrained = undefined; | ||
| } | ||
| await this.flush(); | ||
@@ -126,5 +133,14 @@ if (this.#shouldRunDeferredScopedClose()) { | ||
| } | ||
| this.#closePromise ??= this.#closeOnce(); | ||
| this.#closePromise ??= this.#closeAfterScopedTasks(); | ||
| await this.#closePromise; | ||
| } | ||
| async #closeAfterScopedTasks() { | ||
| if (this.#activeScopedTasks > 0) { | ||
| this.#scopedTasksDrained ??= new Promise((resolve) => { | ||
| this.#resolveScopedTasksDrained = resolve; | ||
| }); | ||
| await this.#scopedTasksDrained; | ||
| } | ||
| await this.#closeOnce(); | ||
| } | ||
| manageProcessLifecycle() { | ||
@@ -505,3 +521,8 @@ this.#processLifecycle ??= new ProcessLifecycleLease(() => { | ||
| if (error instanceof Error) { | ||
| return error.message; | ||
| try { | ||
| return typeof error.message === "string" ? error.message : "Error"; | ||
| } | ||
| catch { | ||
| return "Error"; | ||
| } | ||
| } | ||
@@ -511,4 +532,6 @@ if (typeof error === "string") { | ||
| } | ||
| if (error === null || | ||
| typeof error === "number" || | ||
| if (error === null) { | ||
| return "Non-Error thrown"; | ||
| } | ||
| if (typeof error === "number" || | ||
| typeof error === "boolean" || | ||
@@ -519,8 +542,3 @@ typeof error === "bigint" || | ||
| } | ||
| try { | ||
| return JSON.stringify(error) ?? String(error); | ||
| } | ||
| catch { | ||
| return String(error); | ||
| } | ||
| return "Non-Error thrown"; | ||
| } | ||
@@ -527,0 +545,0 @@ export function unknownToRejectionError(reason) { |
@@ -393,2 +393,6 @@ export class TaskStore { | ||
| } | ||
| if (options.ratio !== undefined && | ||
| (options.total !== undefined || options.completed !== undefined)) { | ||
| throw new TypeError("task options must not mix ratio with total or completed progress"); | ||
| } | ||
| if (options.signal !== undefined) { | ||
@@ -395,0 +399,0 @@ const signal = options.signal; |
+5
-1
@@ -124,3 +124,7 @@ // CSI, OSC, and common one-byte ESC sequences. | ||
| function normalizedTabSize(tabSize) { | ||
| return Math.max(1, tabSize ?? 8); | ||
| const value = tabSize ?? 8; | ||
| if (!Number.isSafeInteger(value) || value <= 0) { | ||
| throw new TypeError("tabSize must be a safe positive integer"); | ||
| } | ||
| return value; | ||
| } | ||
@@ -127,0 +131,0 @@ function tabWidthAtColumn(column, tabSize) { |
+1
-1
| { | ||
| "name": "@0disoft/laqu", | ||
| "version": "1.0.7", | ||
| "version": "1.0.8", | ||
| "description": "Reliable terminal progress and live CLI rendering primitives for TypeScript.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
+4
-3
@@ -111,2 +111,3 @@ # laqu | ||
| - CI, pipe, dumb terminal, and non-TTY output fall back to plain append rendering unless a different policy is requested. | ||
| - plain append rendering preserves every task state transition and full sanitized log text; `maxRows` and terminal-width truncation apply only to live rendering. | ||
| - JSON/NDJSON progress events do not go to stdout unless the caller explicitly passes a separate status stream that points there. | ||
@@ -208,7 +209,7 @@ | ||
| GitHub Actions publishes npm releases from maintainer-created version tags. The tag must match `package.json` exactly, for example `v1.0.7` for version `1.0.7`. | ||
| GitHub Actions publishes npm releases from maintainer-created version tags. The tag must match `package.json` exactly, for example `v1.0.8` for version `1.0.8`. | ||
| ```sh | ||
| git tag -a v1.0.7 -m "v1.0.7" | ||
| git push origin main v1.0.7 | ||
| git tag -a v1.0.8 -m "v1.0.8" | ||
| git push origin main v1.0.8 | ||
| ``` | ||
@@ -215,0 +216,0 @@ |
111060
0.69%2415
0.92%218
0.46%