From 2f082aadf24befd5d4005e5734216bd23f5af84c Mon Sep 17 00:00:00 2001 From: clover caruso Date: Wed, 4 Feb 2026 03:07:30 -0800 Subject: [PATCH] chore: fix progress docs bugs resolves #66 --- lib/error.ts | 8 ++++++-- lib/progress.ts | 39 +++++++++++++++++++++++++++------------ lib/readme.changes.md | 37 +++++++++++++++++++++++++++++++++++++ lib/ts.ts | 5 +++-- 4 files changed, 73 insertions(+), 16 deletions(-) diff --git a/lib/error.ts b/lib/error.ts index c95cef98a56c63c6a7fa4be74430d92d9cc13ded..026cb489617e0e2ed13fdcfe90aaf91df720e3e6 100644 --- a/lib/error.ts +++ b/lib/error.ts @@ -12,9 +12,13 @@ export interface Error extends globalThis.Error { /** retrieve an error message from any value */ export function message(error: unknown): string { - const message = (error as { message: unknown })?.message ?? error; + let message = (error as { message: unknown })?.message ?? error; try { - return typeof message === "string" ? message : JSON.stringify(message); + message = typeof message === "string" + ? message + // NOTE: typescript standard library lies here (https://github.com/mattpocock/ts-reset/pull/190) + : String(JSON.stringify(message) as string | undefined); + } catch {} try { return String(message); diff --git a/lib/progress.ts b/lib/progress.ts index c2e092fefde026be797479a86583a4c9b2649b71..903e6a529cd2becee57fd11eeaaf52ab602e65a6 100644 --- a/lib/progress.ts +++ b/lib/progress.ts @@ -144,7 +144,7 @@ export interface Node extends Ref, Disposable { valueFormatter?: (value: number, total: number | null) => string; } -/** override the default field values of {@link Node} on creation. */ +/** override the default field values of {@linkcode Node} on creation. */ export interface StartOptions { /** number of items already completed. */ value?: number | undefined | null; @@ -187,6 +187,11 @@ export interface StartOptions { messages?: log.Message[]; } +/** + * value` will be at least zero, total will be `null` or greater than zero. a + * custom value formatter can be passed to {@linkcode start} or mutated on an + * existing node. + */ export type ValueFormatter = (value: number, total: number | null) => string; /** @@ -285,7 +290,7 @@ export class Root< /** * end this root, as well as all children nodes. this emits the `end` event * with the provided value, JSON-serializing it if connected via - * `encodeEventStream` or `encodeByteStream`. + * {@linkcode encodeEventStream} or {@linkcode encodeByteStream}. * * this function is pre-bound so that it can be passed to `then`: * ```ts @@ -311,7 +316,7 @@ export class Root< /** * emit an event on the specified channel. behavior is not defined when manually - * emitting one of `progress`'s built in events. + * emitting one of the built in events. */ override emit>( channel: C, @@ -344,6 +349,7 @@ export class Root< }; } +/** the built in events provided by {@linkcode Root} */ export type RootEventMap = { // this event is the debounced "ready to re-render" event. do not emit. "change": [rootNodes: readonly ReadOnlyNode[]]; @@ -601,6 +607,7 @@ export const nullNode: Node = { log: noop, debug: noop, writeMessage: noop, + write: noop, scoped() { return this; }, @@ -628,7 +635,7 @@ function endNode(owner: Root, state: Internal) { state.parent = null; } -/** Convert the top level `ReadOnlyNode[]` into ANSI text. */ +/** Convert the top level {@linkcode ReadOnlyNode|ReadOnlyNode[]} into ANSI text. */ export function formatAnsi(now: number, list: readonly ReadOnlyNode[]): string { let out = ""; for (const top of list) { @@ -739,8 +746,9 @@ export function formatUnicodeBar(progress: number, width: number): string { } /** - * configure a `Root` to display its contents to a `log.HeadlessWidgetHost`. - * this is used by the global progress instance to output to the terminal + * configure a {@linkcode Root} to display its contents to a + * {@linkcode log.HeadlessWidgetHost}. this is used by the global progress + * instance to output to the terminal. * ```ts * const globalProgress = new progress.Root(); * progress.attachToScreen(log); @@ -815,7 +823,7 @@ export type StreamEvent = Array< number | StreamNode | StreamCustomEvent | StreamRootChildren >; const kNode = Symbol("underlyingNode"); -/** see {@linkcode StreamEvent} @internal */ +/** @internal */ export interface StreamNode { k: EncodedKey; /** text, overwrite */ @@ -850,12 +858,18 @@ type StreamCustomEvent = [ ]; type StreamRootChildren = number[]; +/** options for both {@linkcode encodeEventStream} and {@linkcode encodeByteStream} */ export interface EncodeStreamOptions { /** * set the minimum time between packets. * @default 1000 / 30 (30fps) */ throttleMs?: number; + /** + * `log.ts` is capable of capturing stack traces from all log calls. by + * seeing this to true, those traces will be serialized. disabled by default + * for privacy reasons. + */ serializeStackTraces?: boolean; } @@ -951,8 +965,8 @@ export function encodeEventStream< } /** - * decodes a stream created by `encodeEventStream` into managed calls to - * `target.start`. when cancelling, all the created nodes are destroyed. + * decodes a stream created by {@linkcode encodeEventStream} into managed calls + * to `target.start`. when cancelling, all the managed nodes are destroyed. */ export function decodeEventStream< Result = void, @@ -1475,8 +1489,8 @@ function writeStreamEvent( } /** - * decodes a stream created by `encodeByteStream` into managed calls to - * `target.start`. when cancelling, all the created nodes are destroyed. + * decodes a stream created by {@linkcode encodeByteStream} into managed calls to + * `target.start`. when cancelling, all the managed nodes are destroyed. */ export function decodeByteStream< Result = void, @@ -1726,7 +1740,8 @@ export class Ema implements EstimationAlgorithm { type EncodedKey = number & { brand: typeof kNode }; const globalKeyPool = new KeyPool(); -export const global: Ref = + +const global: Ref = /** @__PURE__ */ ((root = new Root()) => (attachToScreen(root, log), root))(); /** diff --git a/lib/readme.changes.md b/lib/readme.changes.md index b46d16790b07c0e85444452528c1dcc37222e4b3..15b6d89825186302fb21bba6db0250fef73162c0 100644 --- a/lib/readme.changes.md +++ b/lib/readme.changes.md @@ -1,5 +1,42 @@ # notable changes in clover's typescript library +## v4 + +### breaking + +- `log` + - rename `writeLine` to `write` + - rename `HeadlessWidgetHost` to `WidgetHost` + - rename `HeadlessWidgetEnv` to `WidgetHostOptions` + - rename `headlessWidgetHost` to `createWidgetHost` + - rename `replaceGlobalDestination` to `replaceGlobalMessageDestination` + - `WidgetHostOptions` takes a `lockTerminal` function instead of + `writeInteractive`/`writeOutput` directly. the locking function returns an + interface with these functions, which better aligns with how the draw lock + actually works. additionally, this allows writing more accurate tty bindings + for non-node.js runtimes. the reason for these changes is to support + partially written lines, and handle when external sources desire to do the + same. + - in `getDrawLock`, new required argument `mode`, which can be set to `short` + or `long` to affect how synchronization works. releasing the lock requires + you to give some information about where the cursor was moved to. + - messages now do not imply a newline +- `render` is now deprecated with no replacement. in the downstream `sitegen` + project, the entire codebase is moving to Marko after depending on both renderers. + +### features + +- `process.{stdout,stderr}.write` is intercepted to avoid log interweaving with + `log.ts`/`progress.ts`. this is only done when a widget is created (for + example, calling `progress.start`), so patches are not applied when not + needed. if patching globals is undesirable, you can use an alternative widget + host by calling `log.replaceGlobalWidgetHost(log.simpleNodeProcessWidgetHost(process))` + - consequences of this is that `getDrawLock` +- `progress.ts` node gains `node.log.write("word ");` to write a message without + a newline. +- `async.delay` handles timers longer than 23 days. +- `Lru.revive` recieves bug fixes. this function previously didn't really work. + ## v3 ### breaking diff --git a/lib/ts.ts b/lib/ts.ts index 5633d88a53cf88e1c0e6ce7112d01d01803f050a..25f6bfbd4ea0cfe7c79353014db38ac22fbf8a74 100644 --- a/lib/ts.ts +++ b/lib/ts.ts @@ -21,8 +21,9 @@ export interface VoidFunction { export interface Dispose extends Disposable, VoidFunction {} /** - * using _ = ts.defer(() => { ... }); - * + * ```ts + * using _ = ts.defer(() => { ... }); + * ``` * Additionally, this can be used to construct the convenience type * `ts.Dispose` */ -- 2.54.0