authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-02-04 03:07:30-08:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-03-21 18:03:28-07:00
log2f082aadf24befd5d4005e5734216bd23f5af84c
tree06fa07d7a8f5c95dff2162859eee6b4183423d42
parent6145522a83caa33ce59165003358338da313a290
signature Signed by SSH key SHA256:xbd+BjjhyBfwk7GVoURf9Yx0gzDerHbvYv7SddNWmAs

chore: fix progress docs bugs

resolves #66

4 files changed, 73 insertions(+), 16 deletions(-)

lib/error.ts+6-2
...@@ -12,9 +12,13 @@ export interface Error extends globalThis.Error {...@@ -12,9 +12,13 @@ export interface Error extends globalThis.Error {
1212
13/** retrieve an error message from any value */13/** retrieve an error message from any value */
14export function message(error: unknown): string {14export function message(error: unknown): string {
15 const message = (error as { message: unknown })?.message ?? error;15 let message = (error as { message: unknown })?.message ?? error;
16 try {16 try {
17 return typeof message === "string" ? message : JSON.stringify(message);17 message = typeof message === "string"
18 ? message
19 // NOTE: typescript standard library lies here (https://github.com/mattpocock/ts-reset/pull/190)
20 : String(JSON.stringify(message) as string | undefined);
21
18 } catch {}22 } catch {}
19 try {23 try {
20 return String(message);24 return String(message);
lib/progress.ts+27-12
...@@ -144,7 +144,7 @@ export interface Node extends Ref, Disposable {...@@ -144,7 +144,7 @@ export interface Node extends Ref, Disposable {
144 valueFormatter?: (value: number, total: number | null) => string;144 valueFormatter?: (value: number, total: number | null) => string;
145}145}
146146
147/** override the default field values of {@link Node} on creation. */147/** override the default field values of {@linkcode Node} on creation. */
148export interface StartOptions {148export interface StartOptions {
149 /** number of items already completed. */149 /** number of items already completed. */
150 value?: number | undefined | null;150 value?: number | undefined | null;
...@@ -187,6 +187,11 @@ export interface StartOptions {...@@ -187,6 +187,11 @@ export interface StartOptions {
187 messages?: log.Message[];187 messages?: log.Message[];
188}188}
189189
190/**
191 * value` will be at least zero, total will be `null` or greater than zero. a
192 * custom value formatter can be passed to {@linkcode start} or mutated on an
193 * existing node.
194 */
190export type ValueFormatter = (value: number, total: number | null) => string;195export type ValueFormatter = (value: number, total: number | null) => string;
191196
192/**197/**
...@@ -285,7 +290,7 @@ export class Root<...@@ -285,7 +290,7 @@ export class Root<
285 /**290 /**
286 * end this root, as well as all children nodes. this emits the `end` event291 * end this root, as well as all children nodes. this emits the `end` event
287 * with the provided value, JSON-serializing it if connected via292 * with the provided value, JSON-serializing it if connected via
288 * `encodeEventStream` or `encodeByteStream`.293 * {@linkcode encodeEventStream} or {@linkcode encodeByteStream}.
289 *294 *
290 * this function is pre-bound so that it can be passed to `then`:295 * this function is pre-bound so that it can be passed to `then`:
291 * ```ts296 * ```ts
...@@ -311,7 +316,7 @@ export class Root<...@@ -311,7 +316,7 @@ export class Root<
311316
312 /**317 /**
313 * emit an event on the specified channel. behavior is not defined when manually318 * emit an event on the specified channel. behavior is not defined when manually
314 * emitting one of `progress`'s built in events.319 * emitting one of the built in events.
315 */320 */
316 override emit<C extends keyof MergeRootEvents<Result, Map>>(321 override emit<C extends keyof MergeRootEvents<Result, Map>>(
317 channel: C,322 channel: C,
...@@ -344,6 +349,7 @@ export class Root<...@@ -344,6 +349,7 @@ export class Root<
344 };349 };
345}350}
346351
352/** the built in events provided by {@linkcode Root} */
347export type RootEventMap<Result = void> = {353export type RootEventMap<Result = void> = {
348 // this event is the debounced "ready to re-render" event. do not emit.354 // this event is the debounced "ready to re-render" event. do not emit.
349 "change": [rootNodes: readonly ReadOnlyNode[]];355 "change": [rootNodes: readonly ReadOnlyNode[]];
...@@ -601,6 +607,7 @@ export const nullNode: Node = {...@@ -601,6 +607,7 @@ export const nullNode: Node = {
601 log: noop,607 log: noop,
602 debug: noop,608 debug: noop,
603 writeMessage: noop,609 writeMessage: noop,
610 write: noop,
604 scoped() {611 scoped() {
605 return this;612 return this;
606 },613 },
...@@ -628,7 +635,7 @@ function endNode<R, M extends Events.Map>(owner: Root<R, M>, state: Internal) {...@@ -628,7 +635,7 @@ function endNode<R, M extends Events.Map>(owner: Root<R, M>, state: Internal) {
628 state.parent = null;635 state.parent = null;
629}636}
630637
631/** Convert the top level `ReadOnlyNode[]` into ANSI text. */638/** Convert the top level {@linkcode ReadOnlyNode|ReadOnlyNode[]} into ANSI text. */
632export function formatAnsi(now: number, list: readonly ReadOnlyNode[]): string {639export function formatAnsi(now: number, list: readonly ReadOnlyNode[]): string {
633 let out = "";640 let out = "";
634 for (const top of list) {641 for (const top of list) {
...@@ -739,8 +746,9 @@ export function formatUnicodeBar(progress: number, width: number): string {...@@ -739,8 +746,9 @@ export function formatUnicodeBar(progress: number, width: number): string {
739}746}
740747
741/**748/**
742 * configure a `Root` to display its contents to a `log.HeadlessWidgetHost`.749 * configure a {@linkcode Root} to display its contents to a
743 * this is used by the global progress instance to output to the terminal750 * {@linkcode log.HeadlessWidgetHost}. this is used by the global progress
751 * instance to output to the terminal.
744 * ```ts752 * ```ts
745 * const globalProgress = new progress.Root();753 * const globalProgress = new progress.Root();
746 * progress.attachToScreen(log);754 * progress.attachToScreen(log);
...@@ -815,7 +823,7 @@ export type StreamEvent = Array<...@@ -815,7 +823,7 @@ export type StreamEvent = Array<
815 number | StreamNode | StreamCustomEvent | StreamRootChildren823 number | StreamNode | StreamCustomEvent | StreamRootChildren
816>;824>;
817const kNode = Symbol("underlyingNode");825const kNode = Symbol("underlyingNode");
818/** see {@linkcode StreamEvent} @internal */826/** @internal */
819export interface StreamNode {827export interface StreamNode {
820 k: EncodedKey;828 k: EncodedKey;
821 /** text, overwrite */829 /** text, overwrite */
...@@ -850,12 +858,18 @@ type StreamCustomEvent = [...@@ -850,12 +858,18 @@ type StreamCustomEvent = [
850];858];
851type StreamRootChildren = number[];859type StreamRootChildren = number[];
852860
861/** options for both {@linkcode encodeEventStream} and {@linkcode encodeByteStream} */
853export interface EncodeStreamOptions {862export interface EncodeStreamOptions {
854 /**863 /**
855 * set the minimum time between packets.864 * set the minimum time between packets.
856 * @default 1000 / 30 (30fps)865 * @default 1000 / 30 (30fps)
857 */866 */
858 throttleMs?: number;867 throttleMs?: number;
868 /**
869 * `log.ts` is capable of capturing stack traces from all log calls. by
870 * seeing this to true, those traces will be serialized. disabled by default
871 * for privacy reasons.
872 */
859 serializeStackTraces?: boolean;873 serializeStackTraces?: boolean;
860}874}
861875
...@@ -951,8 +965,8 @@ export function encodeEventStream<...@@ -951,8 +965,8 @@ export function encodeEventStream<
951}965}
952966
953/**967/**
954 * decodes a stream created by `encodeEventStream` into managed calls to968 * decodes a stream created by {@linkcode encodeEventStream} into managed calls
955 * `target.start`. when cancelling, all the created nodes are destroyed.969 * to `target.start`. when cancelling, all the managed nodes are destroyed.
956 */970 */
957export function decodeEventStream<971export function decodeEventStream<
958 Result = void,972 Result = void,
...@@ -1475,8 +1489,8 @@ function writeStreamEvent(...@@ -1475,8 +1489,8 @@ function writeStreamEvent(
1475}1489}
14761490
1477/**1491/**
1478 * decodes a stream created by `encodeByteStream` into managed calls to1492 * decodes a stream created by {@linkcode encodeByteStream} into managed calls to
1479 * `target.start`. when cancelling, all the created nodes are destroyed.1493 * `target.start`. when cancelling, all the managed nodes are destroyed.
1480 */1494 */
1481export function decodeByteStream<1495export function decodeByteStream<
1482 Result = void,1496 Result = void,
...@@ -1726,7 +1740,8 @@ export class Ema implements EstimationAlgorithm {...@@ -1726,7 +1740,8 @@ export class Ema implements EstimationAlgorithm {
1726type EncodedKey = number & { brand: typeof kNode };1740type EncodedKey = number & { brand: typeof kNode };
17271741
1728const globalKeyPool = new KeyPool<number>();1742const globalKeyPool = new KeyPool<number>();
1729export const global: Ref =1743
1744const global: Ref =
1730 /** @__PURE__ */ ((root = new Root()) => (attachToScreen(root, log), root))();1745 /** @__PURE__ */ ((root = new Root()) => (attachToScreen(root, log), root))();
17311746
1732/**1747/**
lib/readme.changes.md+37
...@@ -1,5 +1,42 @@...@@ -1,5 +1,42 @@
1# notable changes in clover's typescript library1# notable changes in clover's typescript library
22
3## v4
4
5### breaking
6
7- `log`
8 - rename `writeLine` to `write`
9 - rename `HeadlessWidgetHost` to `WidgetHost`
10 - rename `HeadlessWidgetEnv` to `WidgetHostOptions`
11 - rename `headlessWidgetHost` to `createWidgetHost`
12 - rename `replaceGlobalDestination` to `replaceGlobalMessageDestination`
13 - `WidgetHostOptions` takes a `lockTerminal` function instead of
14 `writeInteractive`/`writeOutput` directly. the locking function returns an
15 interface with these functions, which better aligns with how the draw lock
16 actually works. additionally, this allows writing more accurate tty bindings
17 for non-node.js runtimes. the reason for these changes is to support
18 partially written lines, and handle when external sources desire to do the
19 same.
20 - in `getDrawLock`, new required argument `mode`, which can be set to `short`
21 or `long` to affect how synchronization works. releasing the lock requires
22 you to give some information about where the cursor was moved to.
23 - messages now do not imply a newline
24- `render` is now deprecated with no replacement. in the downstream `sitegen`
25 project, the entire codebase is moving to Marko after depending on both renderers.
26
27### features
28
29- `process.{stdout,stderr}.write` is intercepted to avoid log interweaving with
30 `log.ts`/`progress.ts`. this is only done when a widget is created (for
31 example, calling `progress.start`), so patches are not applied when not
32 needed. if patching globals is undesirable, you can use an alternative widget
33 host by calling `log.replaceGlobalWidgetHost(log.simpleNodeProcessWidgetHost(process))`
34 - consequences of this is that `getDrawLock`
35- `progress.ts` node gains `node.log.write("word ");` to write a message without
36 a newline.
37- `async.delay` handles timers longer than 23 days.
38- `Lru.revive` recieves bug fixes. this function previously didn't really work.
39
3## v340## v3
441
5### breaking42### breaking
lib/ts.ts+3-2
...@@ -21,8 +21,9 @@ export interface VoidFunction {...@@ -21,8 +21,9 @@ export interface VoidFunction {
21export interface Dispose extends Disposable, VoidFunction {}21export interface Dispose extends Disposable, VoidFunction {}
2222
23/**23/**
24 * using _ = ts.defer(() => { ... });24 * ```ts
25 *25 * using _ = ts.defer(() => { ... });
26 * ```
26 * Additionally, this can be used to construct the convenience type27 * Additionally, this can be used to construct the convenience type
27 * `ts.Dispose`28 * `ts.Dispose`
28 */29 */