shelving 1.97.0 → 1.98.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.
Files changed (45) hide show
  1. package/db/ItemReference.d.ts +2 -3
  2. package/db/ItemState.d.ts +2 -2
  3. package/db/ItemState.js +2 -2
  4. package/db/QueryReference.d.ts +2 -3
  5. package/db/QueryState.d.ts +2 -2
  6. package/db/QueryState.js +2 -2
  7. package/firestore/client/FirestoreClientProvider.js +5 -5
  8. package/firestore/server/FirestoreServerProvider.js +5 -5
  9. package/iterate/AbstractGenerator.d.ts +1 -1
  10. package/iterate/AbstractGenerator.js +3 -10
  11. package/package.json +1 -1
  12. package/react/useState.js +2 -2
  13. package/sequence/AbstractSequence.d.ts +1 -1
  14. package/sequence/AbstractSequence.js +3 -10
  15. package/sequence/DeferredSequence.d.ts +10 -9
  16. package/sequence/DeferredSequence.js +9 -8
  17. package/sequence/SwitchingDeferredSequence.d.ts +8 -0
  18. package/sequence/SwitchingDeferredSequence.js +13 -0
  19. package/sequence/SwitchingSequence.d.ts +10 -0
  20. package/sequence/SwitchingSequence.js +52 -0
  21. package/sequence/index.d.ts +2 -2
  22. package/sequence/index.js +2 -2
  23. package/state/State.d.ts +3 -4
  24. package/util/async.d.ts +5 -5
  25. package/util/callback.d.ts +22 -0
  26. package/util/callback.js +26 -0
  27. package/util/class.d.ts +0 -25
  28. package/util/class.js +0 -61
  29. package/util/error.d.ts +2 -2
  30. package/util/function.d.ts +0 -16
  31. package/util/function.js +0 -27
  32. package/util/index.d.ts +1 -1
  33. package/util/index.js +1 -1
  34. package/util/sequence.d.ts +3 -4
  35. package/util/sequence.js +2 -2
  36. package/util/switch.d.ts +33 -0
  37. package/util/switch.js +49 -0
  38. package/util/timeout.d.ts +3 -4
  39. package/util/timeout.js +3 -8
  40. package/sequence/LazyDeferredSequence.d.ts +0 -9
  41. package/sequence/LazyDeferredSequence.js +0 -14
  42. package/sequence/RegisteringSequence.d.ts +0 -9
  43. package/sequence/RegisteringSequence.js +0 -51
  44. package/util/activity.d.ts +0 -34
  45. package/util/activity.js +0 -50
@@ -1,9 +1,8 @@
1
1
  import type { DeleteChange, SetChange, UpdateChange } from "./Change.js";
2
2
  import type { AsyncProvider, Provider } from "../provider/Provider.js";
3
- import type { Stop } from "../util/activity.js";
4
3
  import type { ImmutableArray } from "../util/array.js";
4
+ import type { Callback, ErrorCallback, StopCallback } from "../util/callback.js";
5
5
  import type { Data } from "../util/data.js";
6
- import type { Dispatch, Handler } from "../util/function.js";
7
6
  import type { Query } from "../util/query.js";
8
7
  import type { Updates } from "../util/update.js";
9
8
  /** Item data with a string ID that uniquely identifies it. */
@@ -62,7 +61,7 @@ declare abstract class AbstractItemReference<T extends Data = Data> implements A
62
61
  getDelete(): DeleteChange;
63
62
  toString(): string;
64
63
  /** Subscribe to this item. */
65
- subscribe(onNext?: Dispatch<ItemValue<T>>, onError?: Handler): Stop;
64
+ subscribe(onNext?: Callback<ItemValue<T>>, onError?: ErrorCallback): StopCallback;
66
65
  [Symbol.asyncIterator](): AsyncIterator<ItemValue<T>>;
67
66
  }
68
67
  /** Reference to an item in a synchronous database. */
package/db/ItemState.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { AsyncItemReference, ItemData, ItemReference, ItemValue } from "./ItemReference.js";
2
+ import type { StopCallback } from "../util/callback.js";
2
3
  import type { Data } from "../util/data.js";
3
- import type { Dispatch } from "../util/function.js";
4
4
  import { BooleanState } from "../state/BooleanState.js";
5
5
  import { State } from "../state/State.js";
6
6
  /** Hold the current state of a item. */
@@ -18,5 +18,5 @@ export declare class ItemState<T extends Data = Data> extends State<ItemValue<T>
18
18
  /** Refresh this state if data in the cache is older than `maxAge` (in milliseconds). */
19
19
  refreshStale(maxAge: number): void;
20
20
  /** Subscribe this state to the source provider. */
21
- connectSource(): Dispatch;
21
+ connectSource(): StopCallback;
22
22
  }
package/db/ItemState.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CacheProvider } from "../provider/CacheProvider.js";
2
- import { LazyDeferredSequence } from "../sequence/LazyDeferredSequence.js";
2
+ import { SwitchingDeferredSequence } from "../sequence/SwitchingDeferredSequence.js";
3
3
  import { BooleanState } from "../state/BooleanState.js";
4
4
  import { State } from "../state/State.js";
5
5
  import { getRequired } from "../util/null.js";
@@ -19,7 +19,7 @@ export class ItemState extends State {
19
19
  const { provider, collection, id } = ref;
20
20
  const table = (_a = getOptionalSource(CacheProvider, provider)) === null || _a === void 0 ? void 0 : _a.memory.getTable(collection);
21
21
  const time = table ? table.getQueryTime(ref) : null;
22
- const next = table ? new LazyDeferredSequence(() => this.from(table.getCachedItemSequence(id), () => typeof table.getItemTime(id) === "number")) : undefined;
22
+ const next = table ? new SwitchingDeferredSequence(sequence => sequence.from(table.getCachedItemSequence(id))) : undefined;
23
23
  super(table && typeof time === "number" ? { value: table.getItem(id), time, next } : { next });
24
24
  this.busy = new BooleanState();
25
25
  /** Refresh this state from the source provider. */
@@ -1,8 +1,7 @@
1
1
  import type { ItemArray, ItemData, ItemQuery, ItemValue } from "./ItemReference.js";
2
2
  import type { AsyncProvider, Provider } from "../provider/Provider.js";
3
- import type { Stop } from "../util/activity.js";
3
+ import type { Callback, ErrorCallback, StopCallback } from "../util/callback.js";
4
4
  import type { Data } from "../util/data.js";
5
- import type { Dispatch, Handler } from "../util/function.js";
6
5
  import type { Updates } from "../util/update.js";
7
6
  /** Reference to a set of items in a sync or async provider. */
8
7
  declare abstract class AbstractQueryReference<T extends Data = Data> implements AsyncIterable<ItemArray<T>> {
@@ -63,7 +62,7 @@ declare abstract class AbstractQueryReference<T extends Data = Data> implements
63
62
  abstract delete(): number | PromiseLike<number>;
64
63
  toString(): string;
65
64
  /** Subscribe to this item. */
66
- subscribe(onNext?: Dispatch<ItemArray<T>>, onError?: Handler): Stop;
65
+ subscribe(onNext?: Callback<ItemArray<T>>, onError?: ErrorCallback): StopCallback;
67
66
  [Symbol.asyncIterator](): AsyncIterator<ItemArray<T>>;
68
67
  }
69
68
  /** Reference to a set of items in a provider. */
@@ -1,6 +1,6 @@
1
1
  import type { ItemArray, ItemData, ItemValue } from "./ItemReference.js";
2
2
  import type { AsyncQueryReference, QueryReference } from "./QueryReference.js";
3
- import type { Stop } from "../util/activity.js";
3
+ import type { StopCallback } from "../util/callback.js";
4
4
  import type { Data } from "../util/data.js";
5
5
  import { BooleanState } from "../state/BooleanState.js";
6
6
  import { State } from "../state/State.js";
@@ -31,7 +31,7 @@ export declare class QueryState<T extends Data = Data> extends State<ItemArray<T
31
31
  /** Refresh this state if data in the cache is older than `maxAge` (in milliseconds). */
32
32
  refreshStale(maxAge: number): void;
33
33
  /** Subscribe this state to the source provider. */
34
- connectSource(): Stop;
34
+ connectSource(): StopCallback;
35
35
  /**
36
36
  * Load more items after the last once.
37
37
  * - Promise that needs to be handled.
package/db/QueryState.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CacheProvider } from "../provider/CacheProvider.js";
2
- import { LazyDeferredSequence } from "../sequence/LazyDeferredSequence.js";
2
+ import { SwitchingDeferredSequence } from "../sequence/SwitchingDeferredSequence.js";
3
3
  import { BooleanState } from "../state/BooleanState.js";
4
4
  import { State } from "../state/State.js";
5
5
  import { getOptionalFirstItem, getOptionalLastItem } from "../util/array.js";
@@ -41,7 +41,7 @@ export class QueryState extends State {
41
41
  const { provider, collection, query } = ref;
42
42
  const table = (_a = getOptionalSource(CacheProvider, provider)) === null || _a === void 0 ? void 0 : _a.memory.getTable(collection);
43
43
  const time = table ? table.getQueryTime(ref) : null;
44
- const next = table ? new LazyDeferredSequence(() => this.from(table.getCachedQuerySequence(ref))) : undefined;
44
+ const next = table ? new SwitchingDeferredSequence(sequence => sequence.from(table.getCachedQuerySequence(ref))) : undefined;
45
45
  super(table && typeof time === "number" ? { value: table.getQuery(ref), time, next } : { next });
46
46
  this.busy = new BooleanState();
47
47
  this._hasMore = false;
@@ -1,5 +1,5 @@
1
1
  import { addDoc, collection, deleteDoc, doc, documentId, getDoc, getDocs, increment, limit, onSnapshot, orderBy, query, setDoc, updateDoc, where } from "firebase/firestore";
2
- import { LazyDeferredSequence } from "../../sequence/LazyDeferredSequence.js";
2
+ import { SwitchingDeferredSequence } from "../../sequence/SwitchingDeferredSequence.js";
3
3
  import { getObject } from "../../util/object.js";
4
4
  import { getFilters, getLimit, getOrders } from "../../util/query.js";
5
5
  import { mapItems } from "../../util/transform.js";
@@ -60,9 +60,9 @@ export class FirestoreClientProvider {
60
60
  return _getItemValue(await getDoc(doc(this._firestore, c, id)));
61
61
  }
62
62
  getItemSequence(c, id) {
63
- return new LazyDeferredSequence(({ resolve, reject }) => onSnapshot(doc(this._firestore, c, id), //
63
+ return new SwitchingDeferredSequence(sequence => onSnapshot(doc(this._firestore, c, id), //
64
64
  //
65
- snapshot => resolve(_getItemValue(snapshot)), reject));
65
+ snapshot => sequence.resolve(_getItemValue(snapshot)), reason => sequence.reject(reason)));
66
66
  }
67
67
  async addItem(c, data) {
68
68
  const reference = await addDoc(collection(this._firestore, c), data);
@@ -81,9 +81,9 @@ export class FirestoreClientProvider {
81
81
  return _getItems(await getDocs(_getQuery(this._firestore, c, q)));
82
82
  }
83
83
  getQuerySequence(c, q) {
84
- return new LazyDeferredSequence(({ resolve, reject }) => onSnapshot(_getQuery(this._firestore, c, q), //
84
+ return new SwitchingDeferredSequence(sequence => onSnapshot(_getQuery(this._firestore, c, q), //
85
85
  //
86
- snapshot => resolve(_getItems(snapshot)), reject));
86
+ snapshot => sequence.resolve(_getItems(snapshot)), reason => sequence.reject(reason)));
87
87
  }
88
88
  async setQuery(c, q, data) {
89
89
  const snapshot = await getDocs(_getQuery(this._firestore, c, q));
@@ -1,5 +1,5 @@
1
1
  import { FieldPath, FieldValue, Firestore } from "@google-cloud/firestore";
2
- import { LazyDeferredSequence } from "../../sequence/LazyDeferredSequence.js";
2
+ import { SwitchingDeferredSequence } from "../../sequence/SwitchingDeferredSequence.js";
3
3
  import { getObject } from "../../util/object.js";
4
4
  import { getFilters, getLimit, getOrders } from "../../util/query.js";
5
5
  import { mapItems } from "../../util/transform.js";
@@ -58,8 +58,8 @@ export class FirestoreServerProvider {
58
58
  }
59
59
  getItemSequence(c, id) {
60
60
  const ref = this._firestore.collection(c).doc(id);
61
- return new LazyDeferredSequence(({ resolve, reject }) => ref.onSnapshot(snapshot => resolve(_getItemValue(snapshot)), //
62
- reject));
61
+ return new SwitchingDeferredSequence(sequence => ref.onSnapshot(snapshot => sequence.resolve(_getItemValue(snapshot)), //
62
+ sequence.reject));
63
63
  }
64
64
  async addItem(c, data) {
65
65
  return (await this._firestore.collection(c).add(data)).id;
@@ -78,8 +78,8 @@ export class FirestoreServerProvider {
78
78
  }
79
79
  getQuerySequence(c, q) {
80
80
  const ref = _getQuery(this._firestore, c, q);
81
- return new LazyDeferredSequence(({ resolve, reject }) => ref.onSnapshot(snapshot => resolve(_getItemArray(snapshot)), //
82
- reject));
81
+ return new SwitchingDeferredSequence(sequence => ref.onSnapshot(snapshot => sequence.resolve(_getItemArray(snapshot)), //
82
+ sequence.reject));
83
83
  }
84
84
  async setQuery(c, q, data) {
85
85
  return await bulkWrite(this._firestore, c, q, (w, s) => void w.set(s.ref, data));
@@ -1,6 +1,6 @@
1
1
  /** Abstract generator designed to be extended that implements the full generator protocol. */
2
2
  export declare abstract class AbstractGenerator<T, R, N> implements Generator<T, R, N> {
3
- readonly [Symbol.toStringTag]: string;
3
+ readonly [Symbol.toStringTag] = "Generator";
4
4
  abstract next(value: N): IteratorResult<T, R>;
5
5
  throw(thrown: Error | unknown): IteratorResult<T, R>;
6
6
  return(value: R): IteratorResult<T, R>;
@@ -1,13 +1,9 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
1
  var _a;
8
- import { setPrototype } from "../util/class.js";
9
2
  /** Abstract generator designed to be extended that implements the full generator protocol. */
10
3
  export class AbstractGenerator {
4
+ constructor() {
5
+ this[_a] = "Generator";
6
+ }
11
7
  throw(thrown) {
12
8
  // Default behaviour for a generator is to throw the error back out of the iterator and not continue.
13
9
  throw thrown;
@@ -21,6 +17,3 @@ export class AbstractGenerator {
21
17
  return this;
22
18
  }
23
19
  }
24
- __decorate([
25
- setPrototype(Symbol.toStringTag, "Generator")
26
- ], AbstractGenerator.prototype, _a, void 0);
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.97.0",
14
+ "version": "1.98.0",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
package/react/useState.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState as useReactState } from "react";
2
- import { dispatch } from "../util/function.js";
2
+ import { call } from "../util/callback.js";
3
3
  import { mapArray } from "../util/transform.js";
4
4
  import { isDefined } from "../util/undefined.js";
5
5
  export function useState(...states) {
@@ -7,7 +7,7 @@ export function useState(...states) {
7
7
  useEffect(() => {
8
8
  const rerender = () => setValue({});
9
9
  const stops = mapArray(states, _startState, rerender);
10
- return () => stops.filter(isDefined).forEach(dispatch);
10
+ return () => stops.filter(isDefined).forEach(call);
11
11
  }, states);
12
12
  return states.length <= 1 ? states[0] : states;
13
13
  }
@@ -1,6 +1,6 @@
1
1
  /** Sequence of values designed to be extended that implements the full async generator protocol. */
2
2
  export declare abstract class AbstractSequence<T, R> implements AsyncGenerator<T, R, void> {
3
- readonly [Symbol.toStringTag]: string;
3
+ readonly [Symbol.toStringTag] = "Sequence";
4
4
  abstract next(): Promise<IteratorResult<T, R>>;
5
5
  return(returnValue: R | PromiseLike<R>): Promise<IteratorResult<T, R>>;
6
6
  throw(reason: Error | unknown): Promise<IteratorResult<T, R>>;
@@ -1,13 +1,9 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
1
  var _a;
8
- import { setPrototype } from "../util/class.js";
9
2
  /** Sequence of values designed to be extended that implements the full async generator protocol. */
10
3
  export class AbstractSequence {
4
+ constructor() {
5
+ this[_a] = "Sequence";
6
+ }
11
7
  async return(returnValue) {
12
8
  // Default behaviour for a generator is to return `done: true` and the input value.
13
9
  return { done: true, value: await returnValue };
@@ -21,6 +17,3 @@ export class AbstractSequence {
21
17
  return this;
22
18
  }
23
19
  }
24
- __decorate([
25
- setPrototype(Symbol.toStringTag, "Sequence")
26
- ], AbstractSequence.prototype, _a, void 0);
@@ -1,24 +1,25 @@
1
- import type { Stop } from "../util/activity.js";
2
- import type { Dispatch, Handler } from "../util/function.js";
1
+ import type { Deferred } from "../util/async.js";
2
+ import type { Callback, ErrorCallback, StopCallback } from "../util/callback.js";
3
3
  import { AbstractSequence } from "./AbstractSequence.js";
4
4
  /**
5
- * Deferred sequence of values.
5
+ * Deferred sequence of values that can be async iterated and new values can be published.
6
6
  * - Implements `AsyncIterable` so values can be iterated over using `for await...of`
7
7
  * - Implements `Promise` so the next value can be awaited.
8
+ * - Implements `Deferred` so next values can be resolved or rejected.
8
9
  */
9
- export declare class DeferredSequence<T = void, R = void> extends AbstractSequence<T, R> implements Promise<T> {
10
+ export declare class DeferredSequence<T = void, R = void> extends AbstractSequence<T, R> implements Deferred<T>, Promise<T> {
10
11
  /**
11
12
  * Next deferred to be rejected/resolved, or `undefined` if we haven't requested one yet..
12
13
  * - Only create the deferred on demand, because we don't want to reject a deferred that isn't used to or it would throw an unhandled promise error.
13
14
  */
14
15
  private _deferred;
15
16
  /** Get the next promise to be deferred/rejected. */
16
- get value(): Promise<T>;
17
+ get promise(): Promise<T>;
17
18
  /** Resolve the current deferred in the sequence. */
18
- readonly resolve: (value: T) => void;
19
+ readonly resolve: Callback<T>;
19
20
  private _nextValue;
20
21
  /** Reject the current deferred in the sequence. */
21
- readonly reject: (reason: Error | unknown) => void;
22
+ readonly reject: ErrorCallback;
22
23
  private _nextReason;
23
24
  /** Fulfill the current deferred by resolving or rejecting it. */
24
25
  private readonly _fulfill;
@@ -29,7 +30,7 @@ export declare class DeferredSequence<T = void, R = void> extends AbstractSequen
29
30
  /** Resolve the current deferred from a sequence of values. */
30
31
  through(sequence: AsyncIterable<T>): AsyncIterable<T>;
31
32
  /** Pull values from a source sequence until the returned stop function is called. */
32
- from(source: AsyncIterable<T>, onError?: Handler): Stop;
33
+ from(source: AsyncIterable<T>, onError?: ErrorCallback): StopCallback;
33
34
  /** Subscrbe to the value of the sequence with a callback until the returned stop function is called. */
34
- to(onNext: Dispatch<T>, onError?: Handler): Stop;
35
+ to(onNext: Callback<T>, onError?: ErrorCallback): StopCallback;
35
36
  }
@@ -4,22 +4,23 @@ import { AbstractSequence } from "./AbstractSequence.js";
4
4
  /** Used when the deferred sequence has no value or reason queued. */
5
5
  const _NOVALUE = Symbol("shelving/DeferredSequence.NOVALUE");
6
6
  /**
7
- * Deferred sequence of values.
7
+ * Deferred sequence of values that can be async iterated and new values can be published.
8
8
  * - Implements `AsyncIterable` so values can be iterated over using `for await...of`
9
9
  * - Implements `Promise` so the next value can be awaited.
10
+ * - Implements `Deferred` so next values can be resolved or rejected.
10
11
  */
11
12
  export class DeferredSequence extends AbstractSequence {
12
13
  constructor() {
13
14
  super(...arguments);
14
15
  /** Resolve the current deferred in the sequence. */
15
- this.resolve = (value) => {
16
+ this.resolve = value => {
16
17
  this._nextValue = value;
17
18
  this._nextReason = _NOVALUE;
18
19
  queueMicrotask(this._fulfill);
19
20
  };
20
21
  this._nextValue = _NOVALUE;
21
22
  /** Reject the current deferred in the sequence. */
22
- this.reject = (reason) => {
23
+ this.reject = reason => {
23
24
  this._nextValue = _NOVALUE;
24
25
  this._nextReason = reason;
25
26
  queueMicrotask(this._fulfill);
@@ -40,22 +41,22 @@ export class DeferredSequence extends AbstractSequence {
40
41
  };
41
42
  }
42
43
  /** Get the next promise to be deferred/rejected. */
43
- get value() {
44
+ get promise() {
44
45
  return (this._deferred || (this._deferred = getDeferred())).promise;
45
46
  }
46
47
  // Implement `AsyncIterator`
47
48
  async next() {
48
- return { value: await this.value };
49
+ return { value: await this.promise };
49
50
  }
50
51
  // Implement `Promise`
51
52
  then(onNext, onError) {
52
- return this.value.then(onNext, onError);
53
+ return this.promise.then(onNext, onError);
53
54
  }
54
55
  catch(onError) {
55
- return this.value.catch(onError);
56
+ return this.promise.catch(onError);
56
57
  }
57
58
  finally(onFinally) {
58
- return this.value.finally(onFinally);
59
+ return this.promise.finally(onFinally);
59
60
  }
60
61
  /** Resolve the current deferred from a sequence of values. */
61
62
  async *through(sequence) {
@@ -0,0 +1,8 @@
1
+ import type { StartCallback } from "../util/callback.js";
2
+ import { DeferredSequence } from "./DeferredSequence.js";
3
+ /** Deferred sequence of values that switches on when it has iterators that are iterating, and off when all iterators are done. */
4
+ export declare class SwitchingDeferredSequence<T = void, R = void> extends DeferredSequence<T, R> {
5
+ private readonly _switch;
6
+ constructor(start: StartCallback<DeferredSequence<T, R>>);
7
+ [Symbol.asyncIterator](): AsyncGenerator<T, R, void>;
8
+ }
@@ -0,0 +1,13 @@
1
+ import { SwitchingSet } from "../util/switch.js";
2
+ import { DeferredSequence } from "./DeferredSequence.js";
3
+ import { SwitchingSequence } from "./SwitchingSequence.js";
4
+ /** Deferred sequence of values that switches on when it has iterators that are iterating, and off when all iterators are done. */
5
+ export class SwitchingDeferredSequence extends DeferredSequence {
6
+ constructor(start) {
7
+ super();
8
+ this._switch = new SwitchingSet(() => start(this));
9
+ }
10
+ [Symbol.asyncIterator]() {
11
+ return new SwitchingSequence(this, this._switch);
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ import type { PossibleSwitch } from "../util/switch.js";
2
+ import { ThroughSequence } from "./ThroughSequence.js";
3
+ /** Async generator that switches on when it has iterators that are iterating, and off when all iterators are done. */
4
+ export declare class SwitchingSequence<T, R> extends ThroughSequence<T, R> implements ThroughSequence<T, R> {
5
+ private readonly _switch;
6
+ constructor(source: AsyncIterator<T, R>, switchable: PossibleSwitch<AsyncIterator<T, R>>);
7
+ next(): Promise<IteratorResult<T, R>>;
8
+ return(value: R | PromiseLike<R>): Promise<IteratorResult<T, R>>;
9
+ throw(reason: Error | unknown): Promise<IteratorResult<T, R>>;
10
+ }
@@ -0,0 +1,52 @@
1
+ import { getSwitch } from "../util/switch.js";
2
+ import { ThroughSequence } from "./ThroughSequence.js";
3
+ /** Async generator that switches on when it has iterators that are iterating, and off when all iterators are done. */
4
+ export class SwitchingSequence extends ThroughSequence {
5
+ constructor(source, switchable) {
6
+ super(source);
7
+ this._switch = getSwitch(switchable);
8
+ }
9
+ async next() {
10
+ this._switch.start(this); // Register this in anticipation that it'll continue iterating.
11
+ try {
12
+ const result = await super.next();
13
+ if (result.done)
14
+ this._switch.stop(this); // Deregister this.
15
+ else
16
+ this._switch.start(this); // Register this.
17
+ return result;
18
+ }
19
+ catch (caught) {
20
+ this._switch.stop(this);
21
+ throw caught;
22
+ }
23
+ }
24
+ async return(value) {
25
+ try {
26
+ const result = await super.return(value);
27
+ if (result.done)
28
+ this._switch.stop(this); // Deregister this.
29
+ else
30
+ this._switch.start(this); // Stop this.
31
+ return result;
32
+ }
33
+ catch (caught) {
34
+ this._switch.stop(this);
35
+ throw caught;
36
+ }
37
+ }
38
+ async throw(reason) {
39
+ try {
40
+ const result = await super.throw(reason);
41
+ if (result.done)
42
+ this._switch.stop(this); // Deregister this.
43
+ else
44
+ this._switch.start(this); // Start this.
45
+ return result;
46
+ }
47
+ catch (caught) {
48
+ this._switch.stop(this);
49
+ throw caught;
50
+ }
51
+ }
52
+ }
@@ -1,6 +1,6 @@
1
1
  export * from "./AbstractSequence.js";
2
2
  export * from "./DeferredSequence.js";
3
3
  export * from "./InspectSequence.js";
4
- export * from "./RegisteringSequence.js";
5
- export * from "./LazyDeferredSequence.js";
4
+ export * from "./SwitchingSequence.js";
5
+ export * from "./SwitchingDeferredSequence.js";
6
6
  export * from "./ThroughSequence.js";
package/sequence/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export * from "./AbstractSequence.js";
2
2
  export * from "./DeferredSequence.js";
3
3
  export * from "./InspectSequence.js";
4
- export * from "./RegisteringSequence.js";
5
- export * from "./LazyDeferredSequence.js";
4
+ export * from "./SwitchingSequence.js";
5
+ export * from "./SwitchingDeferredSequence.js";
6
6
  export * from "./ThroughSequence.js";
package/state/State.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import type { Stop } from "../util/activity.js";
2
- import type { Dispatch, Handler } from "../util/function.js";
1
+ import type { Callback, ErrorCallback, StopCallback } from "../util/callback.js";
3
2
  import type { Validatable } from "../util/validate.js";
4
3
  import { DeferredSequence } from "../sequence/DeferredSequence.js";
5
4
  /** Any `State` instance. */
@@ -45,9 +44,9 @@ export declare class State<T> implements AsyncIterable<T>, Validatable<T> {
45
44
  /** Set the value of the state as values are pulled from a sequence. */
46
45
  through(sequence: AsyncIterable<T>): AsyncIterable<T>;
47
46
  /** Pull values from a source sequence until the returned stop function is called. */
48
- from(source: AsyncIterable<T>, onError?: Handler): Stop;
47
+ from(source: AsyncIterable<T>, onError?: ErrorCallback): StopCallback;
49
48
  /** Push values to another state or callback to this state until the returned stop function is called. */
50
- to(target: Dispatch<T>, onError?: Handler): Stop;
49
+ to(target: Callback<T>, onError?: ErrorCallback): StopCallback;
51
50
  [Symbol.asyncIterator](): AsyncIterator<T>;
52
51
  /** Validate data set on this state. */
53
52
  validate(value: T): T;
package/util/async.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Dispatch, Handler } from "./function.js";
1
+ import type { Callback, ErrorCallback } from "./callback.js";
2
2
  /** Is a value an asynchronous value implementing a `then()` function. */
3
3
  export declare const isAsync: <T>(value: T | PromiseLike<T>) => value is PromiseLike<T>;
4
4
  /** Is a value a synchronous value. */
@@ -21,16 +21,16 @@ export declare function runMicrotasks(): Promise<void>;
21
21
  export declare abstract class AbstractPromise<T> extends Promise<T> {
22
22
  static get [Symbol.species](): PromiseConstructor;
23
23
  /** Resolve this promise with a value. */
24
- protected readonly _resolve: Dispatch<T>;
24
+ protected readonly _resolve: Callback<T>;
25
25
  /** Reject this promise with a reason. */
26
- protected readonly _reject: Handler;
26
+ protected readonly _reject: ErrorCallback;
27
27
  constructor();
28
28
  }
29
29
  /** Deferred allows you to access the internal resolve/reject callbacks of a `Promise` */
30
30
  export type Deferred<T> = {
31
31
  promise: Promise<T>;
32
- resolve: Dispatch<T>;
33
- reject: Handler;
32
+ resolve: Callback<T>;
33
+ reject: ErrorCallback;
34
34
  };
35
35
  /**
36
36
  * Get a deferred to access the `resolve()` and `reject()` functions of a promise.
@@ -0,0 +1,22 @@
1
+ /** Callback function that receives a dispatched value. */
2
+ export type Callback<T = void> = (value: T) => void;
3
+ /** Callback function that receives a dispatched value. */
4
+ export type AsyncCallback<T = void> = (value: T) => void | PromiseLike<void>;
5
+ /** Callback function that handles an error. */
6
+ export type ErrorCallback = (reason: Error | unknown) => void;
7
+ /** Callback function that starts something (and returns an optional stop callback). */
8
+ export type StartCallback<T> = (value: T) => StopCallback;
9
+ /** Callback function that stops something. */
10
+ export type StopCallback = () => void;
11
+ /** Safely call a callback function (possibly with a value). */
12
+ export declare function call(callback: () => void | PromiseLike<void>): void;
13
+ export declare function call<T>(callback: (value: T) => void | PromiseLike<void>, value: T): void;
14
+ /** Return a callback function that safely calls a callback function (possibly with a value). */
15
+ export declare function called<T>(dispatcher: AsyncCallback<T>): Callback<T>;
16
+ /** Safely call a callback method (possibly wth a value). */
17
+ export declare function callMethod<M extends string | symbol>(obj: {
18
+ [K in M]: () => void | PromiseLike<void>;
19
+ }, key: M): void;
20
+ export declare function callMethod<T, M extends string | symbol>(obj: {
21
+ [K in M]: (value: T) => void | PromiseLike<void>;
22
+ }, key: M, value: T): void;
@@ -0,0 +1,26 @@
1
+ import { isAsync } from "./async.js";
2
+ import { logError } from "./error.js";
3
+ export function call(callback, value) {
4
+ try {
5
+ const result = callback(value);
6
+ if (isAsync(result))
7
+ result.then(undefined, logError);
8
+ }
9
+ catch (thrown) {
10
+ logError(thrown);
11
+ }
12
+ }
13
+ /** Return a callback function that safely calls a callback function (possibly with a value). */
14
+ export function called(dispatcher) {
15
+ return (value) => call(dispatcher, value);
16
+ }
17
+ export function callMethod(obj, key, value) {
18
+ try {
19
+ const result = obj[key](value);
20
+ if (isAsync(result))
21
+ result.then(undefined, logError);
22
+ }
23
+ catch (thrown) {
24
+ logError(thrown);
25
+ }
26
+ }
package/util/class.d.ts CHANGED
@@ -5,34 +5,9 @@ export type Constructor<T, A extends Arguments> = new (...args: A) => T;
5
5
  export type AnyConstructor = new (...args: any) => any;
6
6
  /** Class prototype that can be used with `instanceof` (string name, as per `Function`, and a prototype field matching the object). */
7
7
  export type Class<T> = new (...args: any) => T;
8
- export declare const abc: Class<String>;
9
8
  /** Is a given value a class constructor? */
10
9
  export declare const isConstructor: <T extends AnyConstructor>(value: unknown) => value is T;
11
10
  /** Is a value an instance of a class? */
12
11
  export declare const isInstance: <T>(value: unknown, type: Class<T>) => value is T;
13
12
  /** Assert that a value is an instance of something. */
14
13
  export declare function assertInstance<T>(value: T | unknown, type: Class<T>): asserts value is T;
15
- /** Decorator to bind a class method lazily on first access. */
16
- export declare function bindMethod<O, T, A>(target: O, key: string, { value: method }: TypedPropertyDescriptor<(...args: A[]) => T>): TypedPropertyDescriptor<(...args: A[]) => T>;
17
- /**
18
- * Decorator to cache the result of a class method.
19
- * - Use this if a method computes an expensive value and you want to use it multiple times.
20
- * - Gets the method's result the first time the property is accessed, then saves that returned value in the object forever.
21
- */
22
- export declare function cacheMethod<O, T, A extends Arguments>(target: O, key: string, { value: method }: TypedPropertyDescriptor<(this: O, ...args: A) => T>): TypedPropertyDescriptor<(this: O, ...args: A) => T>;
23
- /**
24
- * Decorator to cache the result of a class property getter.
25
- * - Gets the result the first time the property is accessed, then saves that returned value in the object forever.
26
- */
27
- export declare function cacheGetter<T>(target: Object, key: string, { get }: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T>;
28
- /**
29
- * Decorator to set a property on an class's prototype not the class itself.
30
- *
31
- * @example
32
- * class MyClass {
33
- * @setPrototype("myProp", "myValue!") readonly myProp!: string;
34
- * }
35
- */
36
- export declare function setPrototype<K extends PropertyKey, T>(key: K, value: T): (prototype: {
37
- [J in K]: T;
38
- }, k: K) => void;
package/util/class.js CHANGED
@@ -1,8 +1,5 @@
1
- /* eslint-disable @typescript-eslint/ban-types */
2
1
  import { AssertionError } from "../error/AssertionError.js";
3
2
  import { debug } from "./debug.js";
4
- import { assertFunction } from "./function.js";
5
- export const abc = String;
6
3
  /** Is a given value a class constructor? */
7
4
  export const isConstructor = (value) => typeof value === "function" && value.toString().startsWith("class");
8
5
  /** Is a value an instance of a class? */
@@ -12,61 +9,3 @@ export function assertInstance(value, type) {
12
9
  if (!(value instanceof type))
13
10
  throw new AssertionError(`Must be instance of ${debug(type)}`, value);
14
11
  }
15
- /** Decorator to bind a class method lazily on first access. */
16
- export function bindMethod(target, key, { value: method }) {
17
- assertFunction(method);
18
- return {
19
- configurable: true,
20
- get() {
21
- const bound = method.bind(target);
22
- Object.defineProperty(target, key, { value: bound, configurable: false, writable: false, enumerable: false });
23
- return bound;
24
- },
25
- };
26
- }
27
- /**
28
- * Decorator to cache the result of a class method.
29
- * - Use this if a method computes an expensive value and you want to use it multiple times.
30
- * - Gets the method's result the first time the property is accessed, then saves that returned value in the object forever.
31
- */
32
- export function cacheMethod(target, key, { value: method }) {
33
- assertFunction(method);
34
- return {
35
- configurable: true,
36
- get() {
37
- return (...args) => {
38
- const value = method.call(target, ...args);
39
- Object.defineProperty(target, key, { value: () => value, configurable: false, writable: false, enumerable: false });
40
- return value;
41
- };
42
- },
43
- };
44
- }
45
- /**
46
- * Decorator to cache the result of a class property getter.
47
- * - Gets the result the first time the property is accessed, then saves that returned value in the object forever.
48
- */
49
- export function cacheGetter(target, key, { get }) {
50
- assertFunction(get);
51
- return {
52
- configurable: true,
53
- get() {
54
- const value = get.call(this);
55
- Object.defineProperty(this, key, { value, configurable: false, writable: false, enumerable: false });
56
- return value;
57
- },
58
- };
59
- }
60
- /**
61
- * Decorator to set a property on an class's prototype not the class itself.
62
- *
63
- * @example
64
- * class MyClass {
65
- * @setPrototype("myProp", "myValue!") readonly myProp!: string;
66
- * }
67
- */
68
- export function setPrototype(key, value) {
69
- return (prototype) => {
70
- prototype[key] = value;
71
- };
72
- }
package/util/error.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Handle an error by logging it to the console. */
2
- import type { Handler } from "./function.js";
3
- export declare const logError: Handler;
2
+ import type { ErrorCallback } from "./callback.js";
3
+ export declare const logError: ErrorCallback;
@@ -12,19 +12,3 @@ export type Arguments = readonly unknown[];
12
12
  export declare const PASSTHROUGH: <T>(value: T) => T;
13
13
  /** Function that does nothing with its arguments and always returns void. */
14
14
  export declare const BLACKHOLE: (...args: Arguments) => void | undefined;
15
- /** Function that receives a dispatched value. */
16
- export type Dispatch<T = void> = (value: T) => void;
17
- /** Function that receives a dispatched value. */
18
- export type AsyncDispatch<T = void> = (value: T) => void | PromiseLike<void>;
19
- /** Safely dispatch a value to a dispatcher function. */
20
- export declare function dispatch(func: () => void | PromiseLike<void>): void;
21
- export declare function dispatch<T>(func: (value: T) => void | PromiseLike<void>, value: T): void;
22
- export declare function dispatch<T>(func: AsyncDispatch<T>, value: T): void;
23
- /** Return a function that dispatches a value to a dispatcher function. */
24
- export declare function dispatched<T>(dispatcher: Dispatch<T>): Dispatch<T>;
25
- /** Safely dispatch a value to a dispatcher method on an object. */
26
- export declare function dispatchMethod<T, M extends string | symbol>(obj: {
27
- [K in M]: AsyncDispatch<T>;
28
- }, key: M, value: T): void;
29
- /** Function that handles an error. */
30
- export type Handler = (reason: Error | unknown) => void;
package/util/function.js CHANGED
@@ -1,6 +1,4 @@
1
1
  import { AssertionError } from "../error/AssertionError.js";
2
- import { isAsync } from "./async.js";
3
- import { logError } from "./error.js";
4
2
  /** Is a value a function? */
5
3
  export const isFunction = (value) => typeof value === "function";
6
4
  /** Assert that a value is a function. */
@@ -12,28 +10,3 @@ export function assertFunction(value) {
12
10
  export const PASSTHROUGH = (value) => value;
13
11
  /** Function that does nothing with its arguments and always returns void. */
14
12
  export const BLACKHOLE = () => undefined;
15
- export function dispatch(func, value) {
16
- try {
17
- const result = func(value);
18
- if (isAsync(result))
19
- result.then(undefined, logError);
20
- }
21
- catch (thrown) {
22
- logError(thrown);
23
- }
24
- }
25
- /** Return a function that dispatches a value to a dispatcher function. */
26
- export function dispatched(dispatcher) {
27
- return (value) => dispatch(dispatcher, value);
28
- }
29
- /** Safely dispatch a value to a dispatcher method on an object. */
30
- export function dispatchMethod(obj, key, value) {
31
- try {
32
- const result = obj[key](value);
33
- if (isAsync(result))
34
- result.then(BLACKHOLE, logError);
35
- }
36
- catch (thrown) {
37
- logError(thrown);
38
- }
39
- }
package/util/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from "./activity.js";
2
1
  export * from "./array.js";
3
2
  export * from "./assert.js";
4
3
  export * from "./async.js";
@@ -35,6 +34,7 @@ export * from "./serialise.js";
35
34
  export * from "./sort.js";
36
35
  export * from "./source.js";
37
36
  export * from "./string.js";
37
+ export * from "./switch.js";
38
38
  export * from "./template.js";
39
39
  export * from "./time.js";
40
40
  export * from "./timeout.js";
package/util/index.js CHANGED
@@ -1,4 +1,3 @@
1
- export * from "./activity.js";
2
1
  export * from "./array.js";
3
2
  export * from "./assert.js";
4
3
  export * from "./async.js";
@@ -35,6 +34,7 @@ export * from "./serialise.js";
35
34
  export * from "./sort.js";
36
35
  export * from "./source.js";
37
36
  export * from "./string.js";
37
+ export * from "./switch.js";
38
38
  export * from "./template.js";
39
39
  export * from "./time.js";
40
40
  export * from "./timeout.js";
@@ -1,5 +1,4 @@
1
- import type { Stop } from "./activity.js";
2
- import type { AsyncDispatch, Dispatch, Handler } from "./function.js";
1
+ import type { AsyncCallback, Callback, ErrorCallback, StopCallback } from "./callback.js";
3
2
  import { STOP } from "./constants.js";
4
3
  /**
5
4
  * Is a value an async iterable object?
@@ -12,8 +11,8 @@ export declare function repeatUntil<T>(source: AsyncIterable<T>, ...signals: [Pr
12
11
  /** Infinite sequence that yields every X milliseconds (yields a count of the number of iterations). */
13
12
  export declare function repeatDelay(ms: number): AsyncIterable<number>;
14
13
  /** Dispatch items in a sequence to a (possibly async) callback. */
15
- export declare function dispatchSequence<T>(sequence: AsyncIterable<T>, onNext: AsyncDispatch<T>): AsyncIterable<T>;
14
+ export declare function dispatchSequence<T>(sequence: AsyncIterable<T>, onNext: AsyncCallback<T>): AsyncIterable<T>;
16
15
  /** Get the first value from an async iterator. **/
17
16
  export declare function getNextValue<T>(sequence: AsyncIterable<T>): Promise<T>;
18
17
  /** Pull values from a sequence until the returned function is called. */
19
- export declare function runSequence<T>(sequence: AsyncIterable<T>, onNext?: Dispatch<T>, onError?: Handler): Stop;
18
+ export declare function runSequence<T>(sequence: AsyncIterable<T>, onNext?: Callback<T>, onError?: ErrorCallback): StopCallback;
package/util/sequence.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { RequiredError } from "../error/RequiredError.js";
2
2
  import { getDeferred, getDelay } from "./async.js";
3
+ import { call } from "./callback.js";
3
4
  import { STOP } from "./constants.js";
4
5
  import { logError } from "./error.js";
5
- import { dispatch } from "./function.js";
6
6
  /**
7
7
  * Is a value an async iterable object?
8
8
  * - Any object with a `Symbol.iterator` property is iterable.
@@ -38,7 +38,7 @@ export async function* repeatDelay(ms) {
38
38
  /** Dispatch items in a sequence to a (possibly async) callback. */
39
39
  export async function* dispatchSequence(sequence, onNext) {
40
40
  for await (const item of sequence) {
41
- dispatch(onNext, item);
41
+ call(onNext, item);
42
42
  yield item;
43
43
  }
44
44
  }
@@ -0,0 +1,33 @@
1
+ import type { StartCallback } from "./callback.js";
2
+ /** Something that can be started or stopped. */
3
+ export interface Switch<T> {
4
+ /** Start the thing. */
5
+ start(value: T): void;
6
+ /** Stop the thing. */
7
+ stop(value: T): void;
8
+ }
9
+ /** Something that can become an `Switch` */
10
+ export type PossibleSwitch<T> = StartCallback<T> | Switch<T>;
11
+ /**
12
+ * Wrap a `StartCallback` and create a `Switch`
13
+ * - Ensures that the start and stop callbacks are only called once.
14
+ */
15
+ export declare class StartSwitch<T> implements Switch<T> {
16
+ private readonly _start;
17
+ private _stop;
18
+ constructor(start: StartCallback<T>);
19
+ start(v: T): void;
20
+ stop(): void;
21
+ }
22
+ /** Turn a possible switch into a switch. */
23
+ export declare const getSwitch: <T>(v: PossibleSwitch<T>) => Switch<T>;
24
+ /** Set of items that starts a switch when it has items and stops it when it has no items. */
25
+ export declare class SwitchingSet<T> extends Set<T> implements Switch<T> {
26
+ private readonly _switch;
27
+ constructor(input: PossibleSwitch<Set<T>>);
28
+ add(value: T): this;
29
+ delete(value: T): boolean;
30
+ clear(): void;
31
+ start(value: T): void;
32
+ stop(value: T): void;
33
+ }
package/util/switch.js ADDED
@@ -0,0 +1,49 @@
1
+ import { isFunction } from "./function.js";
2
+ /**
3
+ * Wrap a `StartCallback` and create a `Switch`
4
+ * - Ensures that the start and stop callbacks are only called once.
5
+ */
6
+ export class StartSwitch {
7
+ constructor(start) {
8
+ this._stop = undefined;
9
+ this._start = start;
10
+ }
11
+ start(v) {
12
+ this._stop || (this._stop = this._start(v));
13
+ }
14
+ stop() {
15
+ if (this._stop)
16
+ this._stop = void this._stop();
17
+ }
18
+ }
19
+ /** Turn a possible switch into a switch. */
20
+ export const getSwitch = (v) => (isFunction(v) ? new StartSwitch(v) : v);
21
+ /** Set of items that starts a switch when it has items and stops it when it has no items. */
22
+ export class SwitchingSet extends Set {
23
+ constructor(input) {
24
+ super();
25
+ this._switch = getSwitch(input);
26
+ }
27
+ add(value) {
28
+ super.add(value);
29
+ this._switch.start(this);
30
+ return this;
31
+ }
32
+ delete(value) {
33
+ const deleted = super.delete(value);
34
+ if (!this.size)
35
+ this._switch.stop(this);
36
+ return deleted;
37
+ }
38
+ clear() {
39
+ this.clear();
40
+ this._switch.stop(this);
41
+ }
42
+ // Implement `Switch`
43
+ start(value) {
44
+ this.add(value);
45
+ }
46
+ stop(value) {
47
+ this.delete(value);
48
+ }
49
+ }
package/util/timeout.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Dispatch } from "./function.js";
1
+ import type { Callback } from "./callback.js";
2
2
  /**
3
3
  * Create a new Timeout.
4
4
  *
@@ -13,7 +13,7 @@ export declare class Timeout {
13
13
  private _callback;
14
14
  private _ms;
15
15
  private _timeout;
16
- constructor(callback?: Dispatch | null, ms?: number);
16
+ constructor(callback?: Callback | undefined, ms?: number);
17
17
  /** Is a timeout currently set? */
18
18
  get exists(): boolean;
19
19
  /**
@@ -21,8 +21,7 @@ export declare class Timeout {
21
21
  * @param callback
22
22
  * @param ms The delay for this timeout (in ms).
23
23
  */
24
- set(callback?: Dispatch | null, ms?: number): void;
25
- private _run;
24
+ set(callback?: Callback | undefined, ms?: number): void;
26
25
  /** Cancel any existing timeout.. */
27
26
  clear(): void;
28
27
  }
package/util/timeout.js CHANGED
@@ -9,13 +9,8 @@
9
9
  * @param ms The default delay for any created timeouts (in ms).
10
10
  */
11
11
  export class Timeout {
12
- constructor(callback = null, ms = 0) {
13
- this._timeout = null;
14
- this._run = () => {
15
- this._timeout = null;
16
- if (this._callback)
17
- this._callback();
18
- };
12
+ constructor(callback = undefined, ms = 0) {
13
+ this._timeout = undefined;
19
14
  this._callback = callback;
20
15
  this._ms = ms;
21
16
  }
@@ -37,7 +32,7 @@ export class Timeout {
37
32
  clear() {
38
33
  const timeout = this._timeout;
39
34
  if (timeout) {
40
- this._timeout = null;
35
+ this._timeout = undefined;
41
36
  clearTimeout(timeout);
42
37
  }
43
38
  }
@@ -1,9 +0,0 @@
1
- import type { Start } from "../util/activity.js";
2
- import { DeferredSequence } from "./DeferredSequence.js";
3
- /** Deferred sequence of values that lazily calls a start function when it has iterators that are iterating, and stops the activity when all iterators are done. */
4
- export declare class LazyDeferredSequence<T = void, R = void> extends DeferredSequence<T, R> {
5
- /** Store a list of iterators currently iterating over this iterable. */
6
- private readonly _iterators;
7
- constructor(start: Start<DeferredSequence<T, R>>);
8
- [Symbol.asyncIterator](): AsyncGenerator<T, R, void>;
9
- }
@@ -1,14 +0,0 @@
1
- import { LazySet } from "../util/activity.js";
2
- import { DeferredSequence } from "./DeferredSequence.js";
3
- import { RegisteringSequence } from "./RegisteringSequence.js";
4
- /** Deferred sequence of values that lazily calls a start function when it has iterators that are iterating, and stops the activity when all iterators are done. */
5
- export class LazyDeferredSequence extends DeferredSequence {
6
- constructor(start) {
7
- super();
8
- this._iterators = new LazySet(() => start(this));
9
- }
10
- // Implement `AsyncIterable`
11
- [Symbol.asyncIterator]() {
12
- return new RegisteringSequence(this, this._iterators);
13
- }
14
- }
@@ -1,9 +0,0 @@
1
- import { ThroughSequence } from "./ThroughSequence.js";
2
- /** Async generator that registers itself with a `Set` when it's iterating, and deregisters itself again when it stops. */
3
- export declare class RegisteringSequence<T, R> extends ThroughSequence<T, R> {
4
- private _set;
5
- constructor(source: AsyncIterator<T, R>, set: Set<AsyncIterator<T, R>>);
6
- next(): Promise<IteratorResult<T, R>>;
7
- return(value: R | PromiseLike<R>): Promise<IteratorResult<T, R>>;
8
- throw(reason: Error | unknown): Promise<IteratorResult<T, R>>;
9
- }
@@ -1,51 +0,0 @@
1
- import { ThroughSequence } from "./ThroughSequence.js";
2
- /** Async generator that registers itself with a `Set` when it's iterating, and deregisters itself again when it stops. */
3
- export class RegisteringSequence extends ThroughSequence {
4
- constructor(source, set) {
5
- super(source);
6
- this._set = set;
7
- }
8
- async next() {
9
- this._set.add(this); // Register this in anticipation that it'll continue iterating.
10
- try {
11
- const result = await super.next();
12
- if (result.done)
13
- this._set.delete(this); // Deregister this.
14
- else
15
- this._set.add(this); // Register this.
16
- return result;
17
- }
18
- catch (caught) {
19
- this._set.delete(this);
20
- throw caught;
21
- }
22
- }
23
- async return(value) {
24
- try {
25
- const result = await super.return(value);
26
- if (result.done)
27
- this._set.delete(this); // Deregister this.
28
- else
29
- this._set.add(this); // Register this.
30
- return result;
31
- }
32
- catch (caught) {
33
- this._set.delete(this);
34
- throw caught;
35
- }
36
- }
37
- async throw(reason) {
38
- try {
39
- const result = await super.throw(reason);
40
- if (result.done)
41
- this._set.delete(this); // Deregister this.
42
- else
43
- this._set.add(this); // Register this.
44
- return result;
45
- }
46
- catch (caught) {
47
- this._set.delete(this);
48
- throw caught;
49
- }
50
- }
51
- }
@@ -1,34 +0,0 @@
1
- import type { Dispatch } from "./function.js";
2
- /** Function that starts something. */
3
- export type Start<T = void> = (value: T) => Stop | void;
4
- /** Function that stops something. */
5
- export type Stop = Dispatch;
6
- /** Something that can be started and stopped. */
7
- export interface Activity<T = void> {
8
- /** Start this activity. */
9
- start(value: T): void;
10
- /** Stop this activity. */
11
- stop(): void;
12
- }
13
- /** Wrap a `Start` function to create an `Activity` object. */
14
- export declare class StartActivity<T = void> implements Activity<T> {
15
- private readonly _start;
16
- private _stop;
17
- constructor(start: Start<T>);
18
- start(value: T): void;
19
- stop(): void;
20
- }
21
- /** Set of items that starts/stops an `Activity` when it has items. */
22
- export declare class LazySet<T> extends Set<T> {
23
- private readonly _activity;
24
- constructor(start: Start<Set<T>>);
25
- add(value: T): this;
26
- delete(value: T): boolean;
27
- }
28
- /** Map of items that starts/stops an `Activity` when it has items. */
29
- export declare class LazyMap<K, T> extends Map<K, T> {
30
- private readonly _activity;
31
- constructor(start: Start<Map<K, T>>);
32
- set(key: K, value: T): this;
33
- delete(key: K): boolean;
34
- }
package/util/activity.js DELETED
@@ -1,50 +0,0 @@
1
- import { BLACKHOLE } from "./function.js";
2
- /** Wrap a `Start` function to create an `Activity` object. */
3
- export class StartActivity {
4
- constructor(start) {
5
- this._start = start;
6
- }
7
- start(value) {
8
- this._stop || (this._stop = this._start(value) || BLACKHOLE);
9
- }
10
- stop() {
11
- if (this._stop)
12
- this._stop = void this._stop();
13
- }
14
- }
15
- /** Set of items that starts/stops an `Activity` when it has items. */
16
- export class LazySet extends Set {
17
- constructor(start) {
18
- super();
19
- this._activity = new StartActivity(start);
20
- }
21
- add(value) {
22
- super.add(value);
23
- this._activity.start(this);
24
- return this;
25
- }
26
- delete(value) {
27
- const deleted = super.delete(value);
28
- if (!this.size)
29
- this._activity.stop();
30
- return deleted;
31
- }
32
- }
33
- /** Map of items that starts/stops an `Activity` when it has items. */
34
- export class LazyMap extends Map {
35
- constructor(start) {
36
- super();
37
- this._activity = new StartActivity(start);
38
- }
39
- set(key, value) {
40
- super.set(key, value);
41
- this._activity.start(this);
42
- return this;
43
- }
44
- delete(key) {
45
- const deleted = super.delete(key);
46
- if (!this.size)
47
- this._activity.stop();
48
- return deleted;
49
- }
50
- }