shelving 1.96.2 → 1.97.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 (50) hide show
  1. package/db/ItemReference.d.ts +4 -3
  2. package/db/ItemState.js +5 -5
  3. package/db/QueryReference.d.ts +3 -2
  4. package/db/QueryState.d.ts +1 -1
  5. package/db/QueryState.js +5 -4
  6. package/firestore/client/FirestoreClientProvider.js +2 -1
  7. package/firestore/lite/FirestoreLiteProvider.js +2 -1
  8. package/firestore/server/FirestoreServerProvider.js +2 -1
  9. package/package.json +1 -1
  10. package/provider/CacheProvider.js +2 -2
  11. package/provider/DebugProvider.js +53 -75
  12. package/provider/MemoryProvider.d.ts +16 -17
  13. package/provider/MemoryProvider.js +54 -93
  14. package/provider/ValidationProvider.js +11 -11
  15. package/react/useReduce.js +2 -2
  16. package/react/useState.js +4 -9
  17. package/sequence/DeferredSequence.d.ts +3 -2
  18. package/sequence/DeferredSequence.js +2 -2
  19. package/sequence/LazyDeferredSequence.d.ts +2 -2
  20. package/state/ArrayState.d.ts +2 -1
  21. package/state/ArrayState.js +2 -2
  22. package/state/BooleanState.d.ts +2 -1
  23. package/state/BooleanState.js +2 -2
  24. package/state/DataState.d.ts +2 -2
  25. package/state/DataState.js +2 -2
  26. package/state/DictionaryState.d.ts +2 -1
  27. package/state/DictionaryState.js +2 -2
  28. package/state/State.d.ts +21 -11
  29. package/state/State.js +33 -20
  30. package/util/activity.d.ts +13 -17
  31. package/util/activity.js +3 -17
  32. package/util/array.d.ts +6 -6
  33. package/util/array.js +9 -10
  34. package/util/async.d.ts +14 -22
  35. package/util/async.js +16 -33
  36. package/util/constants.d.ts +4 -2
  37. package/util/constants.js +4 -2
  38. package/util/data.d.ts +0 -2
  39. package/util/function.d.ts +8 -10
  40. package/util/function.js +5 -6
  41. package/util/map.d.ts +2 -2
  42. package/util/map.js +2 -2
  43. package/util/match.d.ts +2 -0
  44. package/util/match.js +6 -0
  45. package/util/null.d.ts +2 -2
  46. package/util/random.d.ts +3 -1
  47. package/util/random.js +9 -1
  48. package/util/sequence.d.ts +6 -5
  49. package/util/sequence.js +14 -14
  50. package/util/undefined.d.ts +5 -5
package/state/State.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { DeferredSequence } from "../sequence/DeferredSequence.js";
2
+ import { NONE } from "../util/constants.js";
2
3
  import { runSequence } from "../util/sequence.js";
3
4
  /**
4
5
  * Stream that retains its most recent value
@@ -7,13 +8,15 @@ import { runSequence } from "../util/sequence.js";
7
8
  * - States can also be in a loading state where they do not have a current value.
8
9
  *
9
10
  * @param initial The initial value for the state, a `Promise` that resolves to the initial value, a source `Subscribable` to subscribe to, or another `State` instance to take the initial value from and subscribe to.
10
- * - To set the state to be loading, use the `State.NOVALUE` constant or a `Promise` value.
11
+ * - To set the state to be loading, use the `NONE` constant or a `Promise` value.
11
12
  * - To set the state to an explicit value, use that value or another `State` instance with a value.
12
13
  * */
13
- class State {
14
- /** Most recently dispatched value (or throw `Promise` that resolves to the next value). */
14
+ export class State {
15
+ /** Current value of the state (or throw a promise that resolves when this state receives its next value or error). */
15
16
  get value() {
16
- if (this._value === State.NOVALUE)
17
+ if (this._reason !== undefined)
18
+ throw this._reason;
19
+ if (this._value === NONE)
17
20
  throw this.next;
18
21
  return this._value;
19
22
  }
@@ -21,34 +24,47 @@ class State {
21
24
  get time() {
22
25
  return this._time;
23
26
  }
27
+ /** Is there a current value, or is it still loading. */
28
+ get loading() {
29
+ return this._value === NONE;
30
+ }
24
31
  /** How old this state's value is (in milliseconds). */
25
32
  get age() {
26
33
  const time = this.time;
27
- return time !== null ? Date.now() - time : Infinity;
34
+ return typeof time === "number" ? Date.now() - time : Infinity;
35
+ }
36
+ /** Current error of this state (or `undefined` if there is no reason). */
37
+ get reason() {
38
+ return this._reason;
28
39
  }
29
40
  /** State is initiated with an initial state. */
30
- constructor(initial = State.NOVALUE, next = new DeferredSequence()) {
31
- this._value = State.NOVALUE;
32
- this._time = null;
33
- if (initial !== State.NOVALUE) {
34
- this._value = this.validate(initial);
35
- this._time = Date.now();
41
+ constructor(options = {}) {
42
+ this._value = NONE;
43
+ this._time = undefined;
44
+ this._reason = undefined;
45
+ if ("value" in options) {
46
+ this._value = this.validate(options.value);
47
+ this._time = options.time || Date.now();
36
48
  }
37
- this.next = next;
38
- }
39
- /** Is there a current value, or is it still loading. */
40
- get loading() {
41
- return this._value === State.NOVALUE;
49
+ this.next = options.next || new DeferredSequence();
42
50
  }
43
51
  /** Set the value of the state. */
44
52
  set(next) {
45
53
  const value = this.validate(next);
46
- if (value !== this._value) {
54
+ if (value !== this._value || this._reason !== undefined) {
55
+ this._reason = undefined;
47
56
  this._value = value;
48
57
  this._time = Date.now();
49
58
  this.next.resolve(value);
50
59
  }
51
60
  }
61
+ /** Set the error reason of the state (will be */
62
+ error(reason) {
63
+ this._reason = reason;
64
+ if (reason !== undefined) {
65
+ this.next.reject(reason);
66
+ }
67
+ }
52
68
  /** Set the value of the state as values are pulled from a sequence. */
53
69
  async *through(sequence) {
54
70
  for await (const value of sequence) {
@@ -77,8 +93,5 @@ class State {
77
93
  return value;
78
94
  }
79
95
  }
80
- /** The `NOVALUE` symbol indicates no value has been received by a `State` instance. */
81
- State.NOVALUE = Symbol("shelving/State.NOVALUE");
82
- export { State };
83
96
  /** Is an unknown value a `State` instance. */
84
97
  export const isState = (value) => value instanceof State;
@@ -1,38 +1,34 @@
1
- import type { Arguments, Dispatch, Handler, Start } from "./function.js";
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;
2
6
  /** Something that can be started and stopped. */
3
- export interface Activity<A extends Arguments = []> {
7
+ export interface Activity<T = void> {
4
8
  /** Start this activity. */
5
- start(...args: A): void;
9
+ start(value: T): void;
6
10
  /** Stop this activity. */
7
11
  stop(): void;
8
12
  }
9
- /** Wrap a `Start` to create an `Activity` */
10
- export declare class StartActivity<A extends Arguments = []> implements Activity<A> {
13
+ /** Wrap a `Start` function to create an `Activity` object. */
14
+ export declare class StartActivity<T = void> implements Activity<T> {
11
15
  private readonly _start;
12
16
  private _stop;
13
- constructor(start: Start<A>);
14
- start(...args: A): void;
15
- stop(): void;
16
- }
17
- /** Wrap an `AsyncIterable` to create an `Activity` */
18
- export declare class SequenceActivity<T> implements Activity<[Dispatch<[T]>, Handler]> {
19
- private readonly _sequence;
20
- private _stop;
21
- constructor(sequence: AsyncIterable<T>);
22
- start(onNext?: Dispatch<[T]>, onError?: Handler): void;
17
+ constructor(start: Start<T>);
18
+ start(value: T): void;
23
19
  stop(): void;
24
20
  }
25
21
  /** Set of items that starts/stops an `Activity` when it has items. */
26
22
  export declare class LazySet<T> extends Set<T> {
27
23
  private readonly _activity;
28
- constructor(start: Start<[Set<T>]>);
24
+ constructor(start: Start<Set<T>>);
29
25
  add(value: T): this;
30
26
  delete(value: T): boolean;
31
27
  }
32
28
  /** Map of items that starts/stops an `Activity` when it has items. */
33
29
  export declare class LazyMap<K, T> extends Map<K, T> {
34
30
  private readonly _activity;
35
- constructor(start: Start<[Map<K, T>]>);
31
+ constructor(start: Start<Map<K, T>>);
36
32
  set(key: K, value: T): this;
37
33
  delete(key: K): boolean;
38
34
  }
package/util/activity.js CHANGED
@@ -1,25 +1,11 @@
1
1
  import { BLACKHOLE } from "./function.js";
2
- import { runSequence } from "./sequence.js";
3
- /** Wrap a `Start` to create an `Activity` */
2
+ /** Wrap a `Start` function to create an `Activity` object. */
4
3
  export class StartActivity {
5
4
  constructor(start) {
6
5
  this._start = start;
7
6
  }
8
- start(...args) {
9
- this._stop || (this._stop = this._start(...args) || BLACKHOLE);
10
- }
11
- stop() {
12
- if (this._stop)
13
- this._stop = void this._stop();
14
- }
15
- }
16
- /** Wrap an `AsyncIterable` to create an `Activity` */
17
- export class SequenceActivity {
18
- constructor(sequence) {
19
- this._sequence = sequence;
20
- }
21
- start(onNext, onError) {
22
- this._stop || (this._stop = runSequence(this._sequence, onNext, onError));
7
+ start(value) {
8
+ this._stop || (this._stop = this._start(value) || BLACKHOLE);
23
9
  }
24
10
  stop() {
25
11
  if (this._stop)
package/util/array.d.ts CHANGED
@@ -30,18 +30,18 @@ export declare function omitArrayItems<T>(input: ImmutableArray<T> | Iterable<T>
30
30
  export declare const clearArray: <T>(input: ImmutableArray<T>) => ImmutableArray<T>;
31
31
  /** Toggle an item in and out of an array (immutably) and return a new array with or without the specified items (or the same array if no changes were made). */
32
32
  export declare function toggleArrayItems<T>(input: ImmutableArray<T>, ...items: T[]): ImmutableArray<T>;
33
- /** Get the first item from an array or iterable, or `null` if it didn't exist. */
34
- export declare function getOptionalFirstItem<T>(items: PossibleArray<T>): T | null;
33
+ /** Get the first item from an array or iterable, or `undefined` if it didn't exist. */
34
+ export declare function getOptionalFirstItem<T>(items: PossibleArray<T>): T | undefined;
35
35
  /** Get the first item from an array or iterable. */
36
36
  export declare function getFirstItem<T>(items: PossibleArray<T>): T;
37
- /** Get the last item from an array or iterable, or `null` if it didn't exist. */
38
- export declare function getOptionalLastItem<T>(items: PossibleArray<T>): T | null;
37
+ /** Get the last item from an array or iterable, or `undefined` if it didn't exist. */
38
+ export declare function getOptionalLastItem<T>(items: PossibleArray<T>): T | undefined;
39
39
  /** Get the last item from an array or iterable. */
40
40
  export declare function getLastItem<T>(items: PossibleArray<T>): T;
41
41
  /** Get the next item in an array or iterable. */
42
- export declare function getNextItem<T>(items: PossibleArray<T>, value: T): T | null;
42
+ export declare function getOptionalNextItem<T>(items: PossibleArray<T>, value: T): T | undefined;
43
43
  /** Get the previous item in an array or iterable. */
44
- export declare function getPrevItem<T>(items: PossibleArray<T>, value: T): T | null;
44
+ export declare function getOptionalPrevItem<T>(items: PossibleArray<T>, value: T): T | undefined;
45
45
  /** Return a shuffled version of an array or iterable. */
46
46
  export declare function shuffleArray<T>(input: PossibleArray<T>): ImmutableArray<T>;
47
47
  /** Add an item to an array (by reference) and return the set item. */
package/util/array.js CHANGED
@@ -41,33 +41,34 @@ export function toggleArrayItems(input, ...items) {
41
41
  const output = input.filter(_doesNotInclude, items);
42
42
  return extras.length ? [...output, ...extras] : output.length !== input.length ? output : input;
43
43
  }
44
- /** Get the first item from an array or iterable, or `null` if it didn't exist. */
44
+ /** Get the first item from an array or iterable, or `undefined` if it didn't exist. */
45
45
  export function getOptionalFirstItem(items) {
46
46
  const arr = getArray(items);
47
- return 0 in arr ? arr[0] : null;
47
+ return 0 in arr ? arr[0] : undefined;
48
48
  }
49
49
  /** Get the first item from an array or iterable. */
50
50
  export function getFirstItem(items) {
51
51
  const item = getOptionalFirstItem(items);
52
- if (item === null)
52
+ if (item === undefined)
53
53
  throw new RequiredError("First item is required");
54
54
  return item;
55
55
  }
56
- /** Get the last item from an array or iterable, or `null` if it didn't exist. */
56
+ /** Get the last item from an array or iterable, or `undefined` if it didn't exist. */
57
57
  export function getOptionalLastItem(items) {
58
58
  const arr = getArray(items);
59
59
  const j = arr.length - 1;
60
- return j in arr ? arr[j] : null;
60
+ if (j in arr)
61
+ return arr[j];
61
62
  }
62
63
  /** Get the last item from an array or iterable. */
63
64
  export function getLastItem(items) {
64
65
  const item = getOptionalLastItem(items);
65
- if (item === null)
66
+ if (item === undefined)
66
67
  throw new RequiredError("Last item is required");
67
68
  return item;
68
69
  }
69
70
  /** Get the next item in an array or iterable. */
70
- export function getNextItem(items, value) {
71
+ export function getOptionalNextItem(items, value) {
71
72
  const arr = getArray(items);
72
73
  const i = arr.indexOf(value);
73
74
  if (i >= 0) {
@@ -75,10 +76,9 @@ export function getNextItem(items, value) {
75
76
  if (j in arr)
76
77
  return arr[j];
77
78
  }
78
- return null;
79
79
  }
80
80
  /** Get the previous item in an array or iterable. */
81
- export function getPrevItem(items, value) {
81
+ export function getOptionalPrevItem(items, value) {
82
82
  const arr = getArray(items);
83
83
  const i = arr.indexOf(value);
84
84
  if (i >= 1) {
@@ -86,7 +86,6 @@ export function getPrevItem(items, value) {
86
86
  if (j in arr)
87
87
  return arr[j];
88
88
  }
89
- return null;
90
89
  }
91
90
  /** Return a shuffled version of an array or iterable. */
92
91
  export function shuffleArray(input) {
package/util/async.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import type { Dispatch, Handler } from "./function.js";
2
- import { SIGNAL } from "./constants.js";
3
2
  /** Is a value an asynchronous value implementing a `then()` function. */
4
3
  export declare const isAsync: <T>(value: T | PromiseLike<T>) => value is PromiseLike<T>;
5
4
  /** Is a value a synchronous value. */
@@ -22,28 +21,21 @@ export declare function runMicrotasks(): Promise<void>;
22
21
  export declare abstract class AbstractPromise<T> extends Promise<T> {
23
22
  static get [Symbol.species](): PromiseConstructor;
24
23
  /** Resolve this promise with a value. */
25
- protected readonly _resolve: Dispatch<[T]>;
24
+ protected readonly _resolve: Dispatch<T>;
26
25
  /** Reject this promise with a reason. */
27
26
  protected readonly _reject: Handler;
28
27
  constructor();
29
28
  }
30
- /** Type of `Promise` with its `resolve()` and `reject()` methods exposed publicly. */
31
- export declare class Deferred<T = void> extends Promise<T> {
32
- static get [Symbol.species](): PromiseConstructor;
33
- /** Resolve this deferred with a value. */
34
- readonly resolve: Dispatch<[T]>;
35
- /** Reject this deferred with a reason. */
36
- readonly reject: Handler;
37
- constructor();
38
- }
39
- /** Promise that resolves after a specified delay in milliseconds. */
40
- export declare class Delay extends AbstractPromise<void> {
41
- constructor(ms: number);
42
- }
43
- /** Resolve to `SIGNAL` on a specific signal. */
44
- export declare class Signal extends AbstractPromise<typeof Signal.SIGNAL> {
45
- /** The `SIGNAL` symbol indicates a signal. */
46
- static SIGNAL: typeof SIGNAL;
47
- /** Send this signal now. */
48
- readonly send: () => void;
49
- }
29
+ /** Deferred allows you to access the internal resolve/reject callbacks of a `Promise` */
30
+ export type Deferred<T> = {
31
+ promise: Promise<T>;
32
+ resolve: Dispatch<T>;
33
+ reject: Handler;
34
+ };
35
+ /**
36
+ * Get a deferred to access the `resolve()` and `reject()` functions of a promise.
37
+ * - See https://github.com/tc39/proposal-promise-with-resolvers/
38
+ */
39
+ export declare function getDeferred<T = unknown>(): Deferred<T>;
40
+ /** Get a promise that automatically resolves after a delay. */
41
+ export declare function getDelay(ms: number): Promise<void>;
package/util/async.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { AssertionError } from "../error/AssertionError.js";
2
- import { SIGNAL } from "./constants.js";
3
2
  /** Is a value an asynchronous value implementing a `then()` function. */
4
3
  export const isAsync = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
5
4
  /** Is a value a synchronous value. */
@@ -52,39 +51,23 @@ export class AbstractPromise extends Promise {
52
51
  this._reject = _reject; // eslint-disable-line @typescript-eslint/no-non-null-assertion
53
52
  }
54
53
  }
55
- /** Type of `Promise` with its `resolve()` and `reject()` methods exposed publicly. */
56
- export class Deferred extends Promise {
57
- // Make `this.then()` create a `Promise` not a `Deferred`
58
- // Done with a getter because some implementations implement this with a getter and we need to override it.
59
- static get [Symbol.species]() {
60
- return Promise;
61
- }
62
- constructor() {
63
- let resolve;
64
- let reject;
65
- super((x, y) => {
54
+ /**
55
+ * Get a deferred to access the `resolve()` and `reject()` functions of a promise.
56
+ * - See https://github.com/tc39/proposal-promise-with-resolvers/
57
+ */
58
+ export function getDeferred() {
59
+ let resolve;
60
+ let reject;
61
+ return {
62
+ promise: new Promise((x, y) => {
66
63
  resolve = x;
67
64
  reject = y;
68
- });
69
- this.resolve = resolve; // eslint-disable-line @typescript-eslint/no-non-null-assertion
70
- this.reject = reject; // eslint-disable-line @typescript-eslint/no-non-null-assertion
71
- }
65
+ }),
66
+ resolve: resolve,
67
+ reject: reject, // eslint-disable-line @typescript-eslint/no-non-null-assertion
68
+ };
72
69
  }
73
- /** Promise that resolves after a specified delay in milliseconds. */
74
- export class Delay extends AbstractPromise {
75
- constructor(ms) {
76
- super();
77
- setTimeout(this._resolve, ms);
78
- }
79
- }
80
- /** Resolve to `SIGNAL` on a specific signal. */
81
- class Signal extends AbstractPromise {
82
- constructor() {
83
- super(...arguments);
84
- /** Send this signal now. */
85
- this.send = () => this._resolve(Signal.SIGNAL);
86
- }
70
+ /** Get a promise that automatically resolves after a delay. */
71
+ export function getDelay(ms) {
72
+ return new Promise(resolve => setTimeout(resolve, ms));
87
73
  }
88
- /** The `SIGNAL` symbol indicates a signal. */
89
- Signal.SIGNAL = SIGNAL;
90
- export { Signal };
@@ -30,5 +30,7 @@ export declare const NBSP = "\u00A0";
30
30
  export declare const THINSP = "\u2009";
31
31
  /** Non-breaking narrow space (goes between numbers and their corresponding units). */
32
32
  export declare const NNBSP = "\u202F";
33
- /** The `SIGNAL` symbol indicates a signal. */
34
- export declare const SIGNAL: unique symbol;
33
+ /** The `STOP` symbol indicates something should stop. */
34
+ export declare const STOP: unique symbol;
35
+ /** The `NONE` symbol indicates something is nothing. */
36
+ export declare const NONE: unique symbol;
package/util/constants.js CHANGED
@@ -30,5 +30,7 @@ export const NBSP = "\xA0";
30
30
  export const THINSP = "\u2009";
31
31
  /** Non-breaking narrow space (goes between numbers and their corresponding units). */
32
32
  export const NNBSP = "\u202F";
33
- /** The `SIGNAL` symbol indicates a signal. */
34
- export const SIGNAL = Symbol("shelving/SIGNAL");
33
+ /** The `STOP` symbol indicates something should stop. */
34
+ export const STOP = Symbol("shelving/STOP");
35
+ /** The `NONE` symbol indicates something is nothing. */
36
+ export const NONE = Symbol("shelving/NONE");
package/util/data.d.ts CHANGED
@@ -13,8 +13,6 @@ export type DataValue<T extends Data> = T[keyof T & string];
13
13
  export type DataProp<T extends Data> = {
14
14
  readonly [K in DataKey<T>]: readonly [K, T[K]];
15
15
  }[DataKey<T>];
16
- /** Data or `null` to indicate the data doesn't exist. */
17
- export type OptionalData<T extends Data> = T | null;
18
16
  /** Set of named data objects. */
19
17
  export type Datas = {
20
18
  readonly [K in string]: Data;
@@ -13,20 +13,18 @@ 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
15
  /** Function that receives a dispatched value. */
16
- export type Dispatch<T extends Arguments = []> = (...value: T) => void;
16
+ export type Dispatch<T = void> = (value: T) => void;
17
17
  /** Function that receives a dispatched value. */
18
- export type AsyncDispatch<T extends Arguments = []> = (...value: T) => void | PromiseLike<void>;
18
+ export type AsyncDispatch<T = void> = (value: T) => void | PromiseLike<void>;
19
19
  /** Safely dispatch a value to a dispatcher function. */
20
- export declare function dispatch<A extends Arguments>(func: AsyncDispatch<A>, ...value: A): void;
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;
21
23
  /** Return a function that dispatches a value to a dispatcher function. */
22
- export declare function dispatched<A extends Arguments>(dispatcher: AsyncDispatch<A>): Dispatch<A>;
24
+ export declare function dispatched<T>(dispatcher: Dispatch<T>): Dispatch<T>;
23
25
  /** Safely dispatch a value to a dispatcher method on an object. */
24
- export declare function dispatchMethod<T extends Arguments, M extends string | symbol>(obj: {
26
+ export declare function dispatchMethod<T, M extends string | symbol>(obj: {
25
27
  [K in M]: AsyncDispatch<T>;
26
- }, key: M, ...value: T): void;
27
- /** Function that starts something. */
28
- export type Start<A extends Arguments = []> = (...args: A) => Stop | void;
29
- /** Function that stops something. */
30
- export type Stop = Dispatch;
28
+ }, key: M, value: T): void;
31
29
  /** Function that handles an error. */
32
30
  export type Handler = (reason: Error | unknown) => void;
package/util/function.js CHANGED
@@ -12,10 +12,9 @@ export function assertFunction(value) {
12
12
  export const PASSTHROUGH = (value) => value;
13
13
  /** Function that does nothing with its arguments and always returns void. */
14
14
  export const BLACKHOLE = () => undefined;
15
- /** Safely dispatch a value to a dispatcher function. */
16
- export function dispatch(func, ...value) {
15
+ export function dispatch(func, value) {
17
16
  try {
18
- const result = func(...value);
17
+ const result = func(value);
19
18
  if (isAsync(result))
20
19
  result.then(undefined, logError);
21
20
  }
@@ -25,12 +24,12 @@ export function dispatch(func, ...value) {
25
24
  }
26
25
  /** Return a function that dispatches a value to a dispatcher function. */
27
26
  export function dispatched(dispatcher) {
28
- return (...args) => dispatch(dispatcher, ...args);
27
+ return (value) => dispatch(dispatcher, value);
29
28
  }
30
29
  /** Safely dispatch a value to a dispatcher method on an object. */
31
- export function dispatchMethod(obj, key, ...value) {
30
+ export function dispatchMethod(obj, key, value) {
32
31
  try {
33
- const result = obj[key](...value);
32
+ const result = obj[key](value);
34
33
  if (isAsync(result))
35
34
  result.then(BLACKHOLE, logError);
36
35
  }
package/util/map.d.ts CHANGED
@@ -38,5 +38,5 @@ export declare function setMapItems<K, T>(map: MutableMap<K, T>, items: Iterable
38
38
  export declare function removeMapItems<K, T>(map: MutableMap<K, T>, ...keys: K[]): void;
39
39
  /** Get an item in a map or throw an error if it doesn't exist. */
40
40
  export declare function getMapItem<K, T>(map: ImmutableMap<K, T>, key: K): T;
41
- /** Get an item in a map or `null` if it doesn't exist. */
42
- export declare function getOptionalMapItem<K, T>(map: ImmutableMap<K, T>, key: K): T | null;
41
+ /** Get an item in a map or `undefined` if it doesn't exist. */
42
+ export declare function getOptionalMapItem<K, T>(map: ImmutableMap<K, T>, key: K): T | undefined;
package/util/map.js CHANGED
@@ -40,7 +40,7 @@ export function getMapItem(map, key) {
40
40
  throw new RequiredError(`Map item is required`);
41
41
  return map.get(key);
42
42
  }
43
- /** Get an item in a map or `null` if it doesn't exist. */
43
+ /** Get an item in a map or `undefined` if it doesn't exist. */
44
44
  export function getOptionalMapItem(map, key) {
45
- return map.has(key) ? map.get(key) : null;
45
+ return map.get(key);
46
46
  }
package/util/match.d.ts CHANGED
@@ -6,3 +6,5 @@ export type Match<A extends Arguments = unknown[]> = (...args: A) => boolean;
6
6
  export declare function filterItems<T, A extends Arguments = []>(items: Iterable<T>, match: Match<[T, ...A]>, ...args: A): Iterable<T>;
7
7
  /** Filter an array (immutably) using a matcher. */
8
8
  export declare function filterArray<T, A extends Arguments = []>(input: ImmutableArray<T>, match: Match<[T, ...A]>, ...args: A): ImmutableArray<T>;
9
+ /** Filter a sequence of values using a matcher. */
10
+ export declare function filterSequence<T, A extends Arguments = []>(sequence: AsyncIterable<T>, match: Match, ...args: A): AsyncIterable<T>;
package/util/match.js CHANGED
@@ -11,3 +11,9 @@ export function filterArray(input, match, ...args) {
11
11
  const output = Array.from(filterItems(input, match, ...args));
12
12
  return output.length === input.length ? input : output;
13
13
  }
14
+ /** Filter a sequence of values using a matcher. */
15
+ export async function* filterSequence(sequence, match, ...args) {
16
+ for await (const item of sequence)
17
+ if (match(item, ...args))
18
+ yield item;
19
+ }
package/util/null.d.ts CHANGED
@@ -13,9 +13,9 @@ export declare function assertNotNull<T>(value: Nullable<T>): asserts value is T
13
13
  /** Get the not-nullish version of value. */
14
14
  export declare function getNotNull<T>(value: Nullable<T>): T;
15
15
  /** Nullish is the value or `null` or `undefined` */
16
- export type Nullish<T> = T | null | undefined;
16
+ export type Nullish<T> = T | null | undefined | void;
17
17
  /** Is a value nullish? */
18
- export declare const isNullish: <T>(value: Nullish<T>) => value is null | undefined;
18
+ export declare const isNullish: <T>(value: Nullish<T>) => value is void | null | undefined;
19
19
  /** Assert that a value is not nullish. */
20
20
  export declare function assertNullish<T>(value: Nullish<T>): asserts value is T;
21
21
  /** Is a value not nullish? */
package/util/random.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { ImmutableArray } from "./array.js";
2
2
  /** Generate a random integer between two numbers. */
3
- export declare const getRandom: (min: number, max: number) => number;
3
+ export declare const getRandom: (min?: number, max?: number) => number;
4
+ /** Get a random number that is anything except an existing number. */
5
+ export declare function getRandomExcept(existing: number, min?: number, max?: number): number;
4
6
  /**
5
7
  * Make a random key, e.g. `xs23r34hhsdx` or `e4m29klrugef`
6
8
  * - Not designed to be cryptographically random!
package/util/random.js CHANGED
@@ -1,6 +1,14 @@
1
1
  import { getDefined } from "./undefined.js";
2
2
  /** Generate a random integer between two numbers. */
3
- export const getRandom = (min, max) => Math.round(Math.random() * (max - min) + min);
3
+ export const getRandom = (min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => Math.round(Math.random() * (max - min) + min);
4
+ /** Get a random number that is anything except an existing number. */
5
+ export function getRandomExcept(existing, min, max) {
6
+ let num;
7
+ do
8
+ num = getRandom(min, max);
9
+ while (num === existing);
10
+ return num;
11
+ }
4
12
  /**
5
13
  * Make a random key, e.g. `xs23r34hhsdx` or `e4m29klrugef`
6
14
  * - Not designed to be cryptographically random!
@@ -1,5 +1,6 @@
1
- import type { AsyncDispatch, Dispatch, Handler, Stop } from "./function.js";
2
- import { SIGNAL } from "./constants.js";
1
+ import type { Stop } from "./activity.js";
2
+ import type { AsyncDispatch, Dispatch, Handler } from "./function.js";
3
+ import { STOP } from "./constants.js";
3
4
  /**
4
5
  * Is a value an async iterable object?
5
6
  * - Any object with a `Symbol.iterator` property is iterable.
@@ -7,12 +8,12 @@ import { SIGNAL } from "./constants.js";
7
8
  */
8
9
  export declare const isAsyncIterable: <T extends AsyncIterable<unknown>>(value: unknown) => value is T;
9
10
  /** Infinite sequence that yields until a `SIGNAL` is received. */
10
- export declare function repeatUntil<T>(source: AsyncIterable<T>, ...signals: [Promise<typeof SIGNAL>, ...Promise<typeof SIGNAL>[]]): AsyncIterable<T>;
11
+ export declare function repeatUntil<T>(source: AsyncIterable<T>, ...signals: [Promise<typeof STOP>, ...Promise<typeof STOP>[]]): AsyncIterable<T>;
11
12
  /** Infinite sequence that yields every X milliseconds (yields a count of the number of iterations). */
12
13
  export declare function repeatDelay(ms: number): AsyncIterable<number>;
13
14
  /** Dispatch items in a sequence to a (possibly async) callback. */
14
- export declare function dispatchSequence<T>(sequence: AsyncIterable<T>, onNext: AsyncDispatch<[T]>): AsyncIterable<T>;
15
+ export declare function dispatchSequence<T>(sequence: AsyncIterable<T>, onNext: AsyncDispatch<T>): AsyncIterable<T>;
15
16
  /** Get the first value from an async iterator. **/
16
17
  export declare function getNextValue<T>(sequence: AsyncIterable<T>): Promise<T>;
17
18
  /** Pull values from a sequence until the returned function is called. */
18
- export declare function runSequence<T>(sequence: AsyncIterable<T>, onNext?: Dispatch<[T]>, onError?: Handler): Stop;
19
+ export declare function runSequence<T>(sequence: AsyncIterable<T>, onNext?: Dispatch<T>, onError?: Handler): Stop;
package/util/sequence.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { RequiredError } from "../error/RequiredError.js";
2
- import { Delay, Signal } from "./async.js";
3
- import { SIGNAL } from "./constants.js";
2
+ import { getDeferred, getDelay } from "./async.js";
3
+ import { STOP } from "./constants.js";
4
4
  import { logError } from "./error.js";
5
5
  import { dispatch } from "./function.js";
6
6
  /**
@@ -15,9 +15,9 @@ export async function* repeatUntil(source, ...signals) {
15
15
  const iterator = source[Symbol.asyncIterator]();
16
16
  while (true) {
17
17
  const result = await Promise.race([iterator.next(), ...signals]);
18
- if (result === SIGNAL) {
18
+ if (result === STOP) {
19
19
  await ((_a = iterator.return) === null || _a === void 0 ? void 0 : _a.call(iterator)); // Make sure we call `return()` on the iterator because it might do cleanup.
20
- return SIGNAL;
20
+ return STOP;
21
21
  }
22
22
  else if (result.done) {
23
23
  return result.value;
@@ -31,7 +31,7 @@ export async function* repeatUntil(source, ...signals) {
31
31
  export async function* repeatDelay(ms) {
32
32
  let count = 1;
33
33
  while (true) {
34
- await new Delay(ms);
34
+ await getDelay(ms);
35
35
  yield count++;
36
36
  }
37
37
  }
@@ -44,21 +44,21 @@ export async function* dispatchSequence(sequence, onNext) {
44
44
  }
45
45
  /** Get the first value from an async iterator. **/
46
46
  export async function getNextValue(sequence) {
47
- for await (const value of sequence)
48
- return value;
47
+ for await (const item of sequence)
48
+ return item;
49
49
  throw new RequiredError("First value is required");
50
50
  }
51
51
  /** Pull values from a sequence until the returned function is called. */
52
52
  export function runSequence(sequence, onNext, onError = logError) {
53
- const stop = new Signal();
54
- _runSequence(sequence[Symbol.asyncIterator](), stop, onNext, onError).catch(onError).catch(logError);
55
- return stop.send;
53
+ const { promise, resolve } = getDeferred();
54
+ _runSequence(sequence[Symbol.asyncIterator](), promise, onNext, onError).catch(onError).catch(logError);
55
+ return () => resolve(STOP);
56
56
  }
57
- async function _runSequence(iterator, stop, onNext, onError) {
57
+ async function _runSequence(iterator, stopped, onNext, onError) {
58
58
  var _a;
59
59
  try {
60
- const result = await Promise.race([stop, iterator.next()]);
61
- if (result === Signal.SIGNAL || result.done) {
60
+ const result = await Promise.race([stopped, iterator.next()]);
61
+ if (result === STOP || result.done) {
62
62
  // Stop iteration because the stop signal was sent or the iterator is done.
63
63
  return (_a = iterator.return) === null || _a === void 0 ? void 0 : _a.call(iterator); // Make sure we call `return()` on the iterator because it might do cleanup.
64
64
  }
@@ -72,5 +72,5 @@ async function _runSequence(iterator, stop, onNext, onError) {
72
72
  onError(thrown);
73
73
  }
74
74
  // Continue iteration.
75
- return _runSequence(iterator, stop, onNext, onError);
75
+ return _runSequence(iterator, stopped, onNext, onError);
76
76
  }