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 {
1212
1313/** retrieve an error message from any value */
1414export function message(error: unknown): string {
15 const message = (error as { message: unknown })?.message ?? error;
15 let message = (error as { message: unknown })?.message ?? error;
1616 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
1822 } catch {}
1923 try {
2024 return String(message);
lib/progress.ts+27-12
......@@ -144,7 +144,7 @@ export interface Node extends Ref, Disposable {
144144 valueFormatter?: (value: number, total: number | null) => string;
145145}
146146
147/** override the default field values of {@link Node} on creation. */
147/** override the default field values of {@linkcode Node} on creation. */
148148export interface StartOptions {
149149 /** number of items already completed. */
150150 value?: number | undefined | null;
......@@ -187,6 +187,11 @@ export interface StartOptions {
187187 messages?: log.Message[];
188188}
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 */
190195export type ValueFormatter = (value: number, total: number | null) => string;
191196
192197/**
......@@ -285,7 +290,7 @@ export class Root<
285290 /**
286291 * end this root, as well as all children nodes. this emits the `end` event
287292 * with the provided value, JSON-serializing it if connected via
288 * `encodeEventStream` or `encodeByteStream`.
293 * {@linkcode encodeEventStream} or {@linkcode encodeByteStream}.
289294 *
290295 * this function is pre-bound so that it can be passed to `then`:
291296 * ```ts
......@@ -311,7 +316,7 @@ export class Root<
311316
312317 /**
313318 * 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.
315320 */
316321 override emit<C extends keyof MergeRootEvents<Result, Map>>(
317322 channel: C,
......@@ -344,6 +349,7 @@ export class Root<
344349 };
345350}
346351
352/** the built in events provided by {@linkcode Root} */
347353export type RootEventMap<Result = void> = {
348354 // this event is the debounced "ready to re-render" event. do not emit.
349355 "change": [rootNodes: readonly ReadOnlyNode[]];
......@@ -601,6 +607,7 @@ export const nullNode: Node = {
601607 log: noop,
602608 debug: noop,
603609 writeMessage: noop,
610 write: noop,
604611 scoped() {
605612 return this;
606613 },
......@@ -628,7 +635,7 @@ function endNode<R, M extends Events.Map>(owner: Root<R, M>, state: Internal) {
628635 state.parent = null;
629636}
630637
631/** Convert the top level `ReadOnlyNode[]` into ANSI text. */
638/** Convert the top level {@linkcode ReadOnlyNode|ReadOnlyNode[]} into ANSI text. */
632639export function formatAnsi(now: number, list: readonly ReadOnlyNode[]): string {
633640 let out = "";
634641 for (const top of list) {
......@@ -739,8 +746,9 @@ export function formatUnicodeBar(progress: number, width: number): string {
739746}
740747
741748/**
742 * configure a `Root` to display its contents to a `log.HeadlessWidgetHost`.
743 * this is used by the global progress instance to output to the terminal
749 * configure a {@linkcode Root} to display its contents to a
750 * {@linkcode log.HeadlessWidgetHost}. this is used by the global progress
751 * instance to output to the terminal.
744752 * ```ts
745753 * const globalProgress = new progress.Root();
746754 * progress.attachToScreen(log);
......@@ -815,7 +823,7 @@ export type StreamEvent = Array<
815823 number | StreamNode | StreamCustomEvent | StreamRootChildren
816824>;
817825const kNode = Symbol("underlyingNode");
818/** see {@linkcode StreamEvent} @internal */
826/** @internal */
819827export interface StreamNode {
820828 k: EncodedKey;
821829 /** text, overwrite */
......@@ -850,12 +858,18 @@ type StreamCustomEvent = [
850858];
851859type StreamRootChildren = number[];
852860
861/** options for both {@linkcode encodeEventStream} and {@linkcode encodeByteStream} */
853862export interface EncodeStreamOptions {
854863 /**
855864 * set the minimum time between packets.
856865 * @default 1000 / 30 (30fps)
857866 */
858867 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 */
859873 serializeStackTraces?: boolean;
860874}
861875
......@@ -951,8 +965,8 @@ export function encodeEventStream<
951965}
952966
953967/**
954 * decodes a stream created by `encodeEventStream` into managed calls to
955 * `target.start`. when cancelling, all the created nodes are destroyed.
968 * decodes a stream created by {@linkcode encodeEventStream} into managed calls
969 * to `target.start`. when cancelling, all the managed nodes are destroyed.
956970 */
957971export function decodeEventStream<
958972 Result = void,
......@@ -1475,8 +1489,8 @@ function writeStreamEvent(
14751489}
14761490
14771491/**
1478 * decodes a stream created by `encodeByteStream` into managed calls to
1479 * `target.start`. when cancelling, all the created nodes are destroyed.
1492 * decodes a stream created by {@linkcode encodeByteStream} into managed calls to
1493 * `target.start`. when cancelling, all the managed nodes are destroyed.
14801494 */
14811495export function decodeByteStream<
14821496 Result = void,
......@@ -1726,7 +1740,8 @@ export class Ema implements EstimationAlgorithm {
17261740type EncodedKey = number & { brand: typeof kNode };
17271741
17281742const globalKeyPool = new KeyPool<number>();
1729export const global: Ref =
1743
1744const global: Ref =
17301745 /** @__PURE__ */ ((root = new Root()) => (attachToScreen(root, log), root))();
17311746
17321747/**
lib/readme.changes.md+37
......@@ -1,5 +1,42 @@
11# 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
340## v3
441
542### breaking
lib/ts.ts+3-2
......@@ -21,8 +21,9 @@ export interface VoidFunction {
2121export interface Dispose extends Disposable, VoidFunction {}
2222
2323/**
24 * using _ = ts.defer(() => { ... });
25 *
24 * ```ts
25 * using _ = ts.defer(() => { ... });
26 * ```
2627 * Additionally, this can be used to construct the convenience type
2728 * `ts.Dispose`
2829 */