shelving 1.54.0 → 1.57.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.
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.54.0",
14
+ "version": "1.57.0",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -60,23 +60,23 @@
60
60
  },
61
61
  "devDependencies": {
62
62
  "@google-cloud/firestore": "^5.0.2",
63
- "@types/jest": "^27.4.0",
64
- "@types/react": "^17.0.39",
65
- "@types/react-dom": "^17.0.11",
66
- "@typescript-eslint/eslint-plugin": "^5.12.0",
67
- "@typescript-eslint/parser": "^5.12.0",
68
- "eslint": "^8.9.0",
69
- "eslint-config-prettier": "^8.4.0",
70
- "eslint-plugin-import": "^2.25.4",
63
+ "@types/jest": "^27.4.1",
64
+ "@types/react": "^17.0.44",
65
+ "@types/react-dom": "^17.0.15",
66
+ "@typescript-eslint/eslint-plugin": "^5.20.0",
67
+ "@typescript-eslint/parser": "^5.20.0",
68
+ "eslint": "^8.14.0",
69
+ "eslint-config-prettier": "^8.5.0",
70
+ "eslint-plugin-import": "^2.26.0",
71
71
  "eslint-plugin-prettier": "^4.0.0",
72
- "firebase": "^9.6.7",
72
+ "firebase": "^9.6.11",
73
73
  "jest": "^27.5.1",
74
74
  "jest-ts-webcompat-resolver": "^1.0.0",
75
- "prettier": "^2.5.1",
75
+ "prettier": "^2.6.2",
76
76
  "react": "^17.0.2",
77
77
  "react-dom": "^17.0.2",
78
- "ts-jest": "^27.1.3",
79
- "typescript": "^4.5.5"
78
+ "ts-jest": "^27.1.4",
79
+ "typescript": "^4.6.3"
80
80
  },
81
81
  "peerDependencies": {
82
82
  "@google-cloud/firestore": ">=4.0.0",
package/react/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export * from "./usePureMemo.js";
1
+ export * from "./useLazy.js";
2
+ export * from "./useInstance.js";
2
3
  export * from "./usePureEffect.js";
3
4
  export * from "./usePureState.js";
4
5
  export * from "./useSubscribe.js";
package/react/index.js CHANGED
@@ -1,4 +1,5 @@
1
- export * from "./usePureMemo.js";
1
+ export * from "./useLazy.js";
2
+ export * from "./useInstance.js";
2
3
  export * from "./usePureEffect.js";
3
4
  export * from "./usePureState.js";
4
5
  export * from "./useSubscribe.js";
@@ -1,16 +1,16 @@
1
1
  import { useState } from "react";
2
2
  import { CacheProvider, throwAsync, NOERROR, findSourceProvider, NOVALUE, callAsync, getDocumentData, isAsync } from "../index.js";
3
3
  import { usePureEffect } from "./usePureEffect.js";
4
- import { usePureMemo } from "./usePureMemo.js";
4
+ import { useLazy } from "./useLazy.js";
5
5
  import { usePureState } from "./usePureState.js";
6
6
  export function useAsyncDocument(ref, maxAge = 1000) {
7
7
  // Create a memoed version of `ref`
8
- const memoRef = usePureMemo(ref, ref === null || ref === void 0 ? void 0 : ref.toString());
8
+ const memoRef = useLazy(ref, ref === null || ref === void 0 ? void 0 : ref.toString());
9
9
  // Create two states to hold the value and error.
10
- const [value, setNext] = usePureState(getCachedResult, memoRef);
10
+ const [value, setNext] = usePureState(_getCachedResult, memoRef);
11
11
  const [error, setError] = useState(NOERROR);
12
12
  // Register effect.
13
- usePureEffect(subscribeEffect, memoRef, maxAge, setNext, setError);
13
+ usePureEffect(_subscribeEffect, memoRef, maxAge, setNext, setError);
14
14
  // Always return undefined if there's no ref.
15
15
  if (!ref)
16
16
  return undefined;
@@ -31,14 +31,14 @@ export function useAsyncDocument(ref, maxAge = 1000) {
31
31
  return result;
32
32
  }
33
33
  /** Get the initial result for a reference from the cache. */
34
- function getCachedResult(ref) {
34
+ function _getCachedResult(ref) {
35
35
  if (!ref)
36
36
  return undefined;
37
37
  const provider = findSourceProvider(ref.db.provider, CacheProvider);
38
38
  return provider.isCached(ref) ? provider.cache.get(ref) : NOVALUE;
39
39
  }
40
40
  /** Effect that subscribes a component to the cache for a reference. */
41
- function subscribeEffect(ref, maxAge, setNext, setError) {
41
+ function _subscribeEffect(ref, maxAge, setNext, setError) {
42
42
  if (ref) {
43
43
  const provider = findSourceProvider(ref.db.provider, CacheProvider);
44
44
  const stopCache = provider.cache.subscribe(ref, { next: setNext, error: setError });
@@ -0,0 +1,10 @@
1
+ import { Arguments } from "../index.js";
2
+ /**
3
+ * Use a (memoized) class instance.
4
+ *
5
+ * @param Class The class constructor to create an instance of.
6
+ *
7
+ * @param ...args Set of arguments that specify whether the returned value is refreshed or not.
8
+ * - This array of values is passed into the class constructor as its parameters.
9
+ */
10
+ export declare function useInstance<T, A extends Arguments>(Class: new (...a: A) => T, ...args: A): T;
@@ -0,0 +1,22 @@
1
+ import { useRef } from "react";
2
+ import { isArrayEqual } from "../index.js";
3
+ /**
4
+ * Use a (memoized) class instance.
5
+ *
6
+ * @param Class The class constructor to create an instance of.
7
+ *
8
+ * @param ...args Set of arguments that specify whether the returned value is refreshed or not.
9
+ * - This array of values is passed into the class constructor as its parameters.
10
+ */
11
+ export function useInstance(Class, ...args) {
12
+ var _a;
13
+ const internals = ((_a = useRef()).current || (_a.current = {
14
+ value: new Class(...args),
15
+ args,
16
+ }));
17
+ if (!isArrayEqual(args, internals.args)) {
18
+ internals.value = new Class(...args);
19
+ internals.args = args;
20
+ }
21
+ return internals.value;
22
+ }
@@ -0,0 +1,14 @@
1
+ import { Arguments } from "../index.js";
2
+ /**
3
+ * Use a lazy value.
4
+ *
5
+ * Similar to React's `useMemo()` except...
6
+ * - Calls the initialiser function with `args` as its parameters.
7
+ * - Allows `initial` to be an initialiser function _or_ a plain value.
8
+ *
9
+ * @param value The plain value to memoise, or an initialiser function that returns that value.
10
+ * @param ...args Set of arguments that specify whether the returned value is refreshed or not.
11
+ * - This array of values is passed into the initialiser function as its parameters.
12
+ */
13
+ export declare function useLazy<T, A extends Arguments>(value: (...args: A) => T, ...args: A): T;
14
+ export declare function useLazy<T>(value: T, ...args: Arguments): T;
@@ -1,6 +1,6 @@
1
1
  import { useRef } from "react";
2
2
  import { isArrayEqual, getLazy } from "../index.js";
3
- export function usePureMemo(value, ...args) {
3
+ export function useLazy(value, ...args) {
4
4
  var _a;
5
5
  const internals = ((_a = useRef()).current || (_a.current = {
6
6
  value: getLazy(value, ...args),
@@ -1,16 +1,16 @@
1
1
  import { Pagination } from "../index.js";
2
2
  import { useSubscribe } from "./useSubscribe.js";
3
- import { usePureMemo } from "./usePureMemo.js";
3
+ import { useLazy } from "./useLazy.js";
4
4
  /**
5
5
  * Use a `Pagination` for a collection.
6
6
  * - Doesn't persist the state, so if the component or anything beneath it throws the currently paginated results will be lost.
7
7
  */
8
8
  export function usePagination(ref, initial) {
9
- const pagination = usePureMemo(createPagination, usePureMemo(ref, [ref.toString()]), initial);
9
+ const pagination = useLazy(_createPagination, useLazy(ref, [ref.toString()]), initial);
10
10
  useSubscribe(pagination);
11
11
  return pagination;
12
12
  }
13
- function createPagination(ref, initial) {
13
+ function _createPagination(ref, initial) {
14
14
  const pagination = new Pagination(ref);
15
15
  if (initial)
16
16
  pagination.next(initial);
@@ -3,11 +3,7 @@ import { Arguments, Unsubscriber } from "../index.js";
3
3
  * Version of React's `useEffect()` that allows the use of a pure (side-effect free) function.
4
4
  *
5
5
  * @param effect The function that powers the effect.
6
- * - When called, receives the set of `args` as its arguments.
7
- *
8
6
  * @param ...args Set of arguments that specify whether the effect is re-run or not.
9
- * - This array of values is passed _into_ the function as its parameters.
10
- * - This means you can create the function once (outside the component) rather than creating it on every render.
11
- * - This improves performance (though probably only noticeable on functions that render 1,000s of times).
7
+ * - This array of values is passed into the effect function as its parameters.
12
8
  */
13
9
  export declare function usePureEffect<A extends Arguments>(effect: (...a: A) => Unsubscriber | void, ...args: A): void;
@@ -1,14 +1,10 @@
1
- import { useRef, useEffect as useReactEffect } from "react";
1
+ import { useRef, useEffect } from "react";
2
2
  /**
3
3
  * Version of React's `useEffect()` that allows the use of a pure (side-effect free) function.
4
4
  *
5
5
  * @param effect The function that powers the effect.
6
- * - When called, receives the set of `args` as its arguments.
7
- *
8
6
  * @param ...args Set of arguments that specify whether the effect is re-run or not.
9
- * - This array of values is passed _into_ the function as its parameters.
10
- * - This means you can create the function once (outside the component) rather than creating it on every render.
11
- * - This improves performance (though probably only noticeable on functions that render 1,000s of times).
7
+ * - This array of values is passed into the effect function as its parameters.
12
8
  */
13
9
  export function usePureEffect(effect, ...args) {
14
10
  var _a;
@@ -19,5 +15,5 @@ export function usePureEffect(effect, ...args) {
19
15
  }));
20
16
  internals.args = args;
21
17
  internals.effect = effect;
22
- useReactEffect(internals.memoed, args);
18
+ useEffect(internals.memoed, args);
23
19
  }
@@ -3,16 +3,9 @@ import { Arguments } from "../index.js";
3
3
  * Version of React's `useState()` that allows the use of a pure (side-effect free) function.
4
4
  * - Unlike `useState()` the initialiser will be re-run and the state will be regenerated if `args` changes.
5
5
  *
6
- * @param initial The initial value of the state, or an initialiser function or class constructor that returns that value.
7
- * - If this is a plain value, that value is returned.
8
- * - If this is a function, it is called and its returned value is returned.
9
- * - If this is a class constructor, a new instance of that class is instantiated and returned.
10
- *
6
+ * @param initial The initial value of the state, or an initialiser function that returns that value.
11
7
  * @param ...args Set of arguments that specify whether the returned value is refreshed or not.
12
- * - This array of values is passed into the function or class constructor as its parameters.
13
- * - This means you can create the function once (outside the component) rather than creating it on every render.
14
- * - This improves performance (though probably only noticeable on functions that render 1,000s of times).
8
+ * - This array of values is passed into the initialiser function as its parameters.
15
9
  */
16
10
  export declare function usePureState<T, A extends Arguments>(initial: (...args: A) => T, ...args: A): readonly [T, (next: T) => void];
17
- export declare function usePureState<T, A extends Arguments>(initial: new (...args: A) => T, ...args: A): readonly [T, (next: T) => void];
18
11
  export declare function usePureState<T>(initial: T, ...args: Arguments): readonly [T, (next: T) => void];
@@ -8,8 +8,8 @@ export function usePureState(initial, ...args) {
8
8
  getLazy(initial, ...args),
9
9
  (v) => {
10
10
  if (internals.state[0] !== v) {
11
+ internals.state = [v, internals.state[1]];
11
12
  setState(v);
12
- internals.state[0] = v;
13
13
  }
14
14
  },
15
15
  ],
package/react/useQuery.js CHANGED
@@ -1,18 +1,18 @@
1
1
  import { useState } from "react";
2
2
  import { CacheProvider, NOERROR, findSourceProvider, NOVALUE, getMap, callAsync, getQueryData, throwAsync, ResultsObserver, getQueryResult, isAsync, } from "../index.js";
3
3
  import { usePureEffect } from "./usePureEffect.js";
4
- import { usePureMemo } from "./usePureMemo.js";
4
+ import { useLazy } from "./useLazy.js";
5
5
  import { usePureState } from "./usePureState.js";
6
6
  export function useAsyncQuery(ref, maxAge = 1000) {
7
7
  // Create a memoed version of `ref`
8
- const memoRef = usePureMemo(ref, ref === null || ref === void 0 ? void 0 : ref.toString());
8
+ const memoRef = useLazy(ref, ref === null || ref === void 0 ? void 0 : ref.toString());
9
9
  // Create two states to hold the value and error.
10
- const [value, setNext] = usePureState(getCachedResults, memoRef);
10
+ const [value, setNext] = usePureState(_getCachedResults, memoRef);
11
11
  const [error, setError] = useState(NOERROR);
12
12
  if (error !== NOERROR)
13
13
  throw error; // If there's an error throw it.
14
14
  // Register effects.
15
- usePureEffect(subscribeEffect, memoRef, maxAge, setNext, setError);
15
+ usePureEffect(_subscribeEffect, memoRef, maxAge, setNext, setError);
16
16
  // Always return undefined if there's no ref.
17
17
  if (!ref)
18
18
  return undefined;
@@ -30,14 +30,14 @@ export function useAsyncQuery(ref, maxAge = 1000) {
30
30
  return results;
31
31
  }
32
32
  /** Get the initial results for a reference from the cache. */
33
- function getCachedResults(ref) {
33
+ function _getCachedResults(ref) {
34
34
  if (!ref)
35
35
  return undefined;
36
36
  const provider = findSourceProvider(ref.db.provider, CacheProvider);
37
37
  return provider.isCached(ref) ? getMap(provider.cache.getQuery(ref)) : NOVALUE;
38
38
  }
39
39
  /** Effect that subscribes a component to the cache for a reference. */
40
- function subscribeEffect(ref, maxAge, setNext, setError) {
40
+ function _subscribeEffect(ref, maxAge, setNext, setError) {
41
41
  if (ref) {
42
42
  const provider = findSourceProvider(ref.db.provider, CacheProvider);
43
43
  const observer = new ResultsObserver({ next: setNext, error: setError });
@@ -9,26 +9,26 @@ export class ArrayState extends State {
9
9
  }
10
10
  /** Get the length of the current value of this state. */
11
11
  get length() {
12
- return this.value.length;
12
+ return this._value.length;
13
13
  }
14
14
  /** Add an item to this array. */
15
15
  add(item) {
16
- this.next(withItem(this.value, item));
16
+ this.next(withItem(this._value, item));
17
17
  }
18
18
  /** Remove an item from this array. */
19
19
  delete(item) {
20
- this.next(withoutItem(this.value, item));
20
+ this.next(withoutItem(this._value, item));
21
21
  }
22
22
  /** Swap an item in this array with a different item. */
23
23
  swap(oldItem, newItem) {
24
- this.next(swapItem(this.value, oldItem, newItem));
24
+ this.next(swapItem(this._value, oldItem, newItem));
25
25
  }
26
26
  /** Toggle an item in this array. */
27
27
  toggle(item) {
28
- this.next(toggleItem(this.value, item));
28
+ this.next(toggleItem(this._value, item));
29
29
  }
30
30
  /** Iterate over the items. */
31
31
  [Symbol.iterator]() {
32
- return this.value.values();
32
+ return this._value.values();
33
33
  }
34
34
  }
@@ -0,0 +1,7 @@
1
+ import { State } from "./State.js";
2
+ /** State that stores a boolean and has additional methods to help with that. */
3
+ export declare class BooleanState extends State<boolean> {
4
+ _value: boolean;
5
+ /** Toggle the current boolean value. */
6
+ toggle(): void;
7
+ }
@@ -0,0 +1,13 @@
1
+ import { State } from "./State.js";
2
+ /** State that stores a boolean and has additional methods to help with that. */
3
+ export class BooleanState extends State {
4
+ constructor() {
5
+ super(...arguments);
6
+ // Set default value to be false.
7
+ this._value = false;
8
+ }
9
+ /** Toggle the current boolean value. */
10
+ toggle() {
11
+ this.next(this._value ? false : true);
12
+ }
13
+ }
@@ -1,12 +1,11 @@
1
- import type { Observer } from "../util/index.js";
1
+ import { Observer } from "../util/index.js";
2
2
  import { State } from "./State.js";
3
3
  /**
4
4
  * State that tidies up after itself by completing itself after all its subscribers unsubscribe.
5
5
  * @param delay How long to wait (in ms) before the source subscription is stopped.
6
6
  */
7
7
  export declare class LazyState<T> extends State<T> {
8
- private _delay;
9
- private _timeout?;
10
- constructor(delay?: number);
8
+ private _timeout;
9
+ constructor(delay?: number | null);
11
10
  _removeObserver(observer: Observer<T>): void;
12
11
  }
@@ -1,24 +1,23 @@
1
+ import { Timeout } from "../util/index.js";
1
2
  import { State } from "./State.js";
2
3
  /**
3
4
  * State that tidies up after itself by completing itself after all its subscribers unsubscribe.
4
5
  * @param delay How long to wait (in ms) before the source subscription is stopped.
5
6
  */
6
7
  export class LazyState extends State {
7
- constructor(delay = 0) {
8
+ constructor(delay = null) {
8
9
  super();
9
- this._delay = delay;
10
+ this._timeout = delay ? new Timeout(delay) : null;
10
11
  }
11
12
  // Override to stop the source subscription when the last subscriber unsubscribes.
12
13
  _removeObserver(observer) {
13
14
  super._removeObserver(observer);
14
- if (this._delay) {
15
+ if (this._timeout) {
15
16
  // Maybe stop in a bit (if there are still no subscribers).
16
- if (this._timeout)
17
- clearTimeout(this._timeout);
18
- this._timeout = setTimeout(() => {
17
+ this._timeout.set(() => {
19
18
  if (!this._observers.size && !this.closed)
20
19
  this.complete();
21
- }, this._delay);
20
+ });
22
21
  }
23
22
  else {
24
23
  // Stop now.
@@ -0,0 +1,14 @@
1
+ import { Entry, ImmutableObject } from "../util/index.js";
2
+ import { State } from "./State.js";
3
+ /** State that stores a map-like object and has additional methods to help with that. */
4
+ export declare class ObjectState<T> extends State<ImmutableObject<T>> implements Iterable<Entry<T>> {
5
+ _value: {};
6
+ /** Get the length of the current value of this state. */
7
+ get length(): number;
8
+ /** Remove a named entry from this object. */
9
+ delete(key: string): void;
10
+ /** Set a named entry in this object with a different value. */
11
+ set(key: string, value: T): void;
12
+ /** Iterate over the items. */
13
+ [Symbol.iterator](): Iterator<Entry<T>, void>;
14
+ }
@@ -0,0 +1,26 @@
1
+ import { withEntry, withoutEntry } from "../util/index.js";
2
+ import { State } from "./State.js";
3
+ /** State that stores a map-like object and has additional methods to help with that. */
4
+ export class ObjectState extends State {
5
+ constructor() {
6
+ super(...arguments);
7
+ // Set default value to be empty object.
8
+ this._value = {};
9
+ }
10
+ /** Get the length of the current value of this state. */
11
+ get length() {
12
+ return Object.keys(this._value).length;
13
+ }
14
+ /** Remove a named entry from this object. */
15
+ delete(key) {
16
+ this.next(withoutEntry(this._value, key));
17
+ }
18
+ /** Set a named entry in this object with a different value. */
19
+ set(key, value) {
20
+ this.next(withEntry(this._value, key, value));
21
+ }
22
+ /** Iterate over the items. */
23
+ [Symbol.iterator]() {
24
+ return Object.entries(this._value)[Symbol.iterator]();
25
+ }
26
+ }
package/stream/index.d.ts CHANGED
@@ -3,5 +3,7 @@ export * from "./LazyStream.js";
3
3
  export * from "./LastStream.js";
4
4
  export * from "./State.js";
5
5
  export * from "./LazyState.js";
6
+ export * from "./BooleanState.js";
6
7
  export * from "./ArrayState.js";
8
+ export * from "./ObjectState.js";
7
9
  export * from "./DataState.js";
package/stream/index.js CHANGED
@@ -3,5 +3,7 @@ export * from "./LazyStream.js";
3
3
  export * from "./LastStream.js";
4
4
  export * from "./State.js";
5
5
  export * from "./LazyState.js";
6
+ export * from "./BooleanState.js";
6
7
  export * from "./ArrayState.js";
8
+ export * from "./ObjectState.js";
7
9
  export * from "./DataState.js";
package/util/async.d.ts CHANGED
@@ -59,7 +59,3 @@ export declare class Signal extends AbstractPromise<typeof DONE> {
59
59
  /** Send this signal now. */
60
60
  done(): void;
61
61
  }
62
- /** Resolve to `DONE` after a specified delay. */
63
- export declare class Timeout extends AbstractPromise<typeof DONE> {
64
- constructor(ms: number);
65
- }
package/util/async.js CHANGED
@@ -95,10 +95,3 @@ export class Signal extends AbstractPromise {
95
95
  this._resolve(DONE);
96
96
  }
97
97
  }
98
- /** Resolve to `DONE` after a specified delay. */
99
- export class Timeout extends AbstractPromise {
100
- constructor(ms) {
101
- super();
102
- setTimeout(this._resolve, ms, DONE);
103
- }
104
- }
package/util/index.d.ts CHANGED
@@ -31,6 +31,7 @@ export * from "./serialise.js";
31
31
  export * from "./sort.js";
32
32
  export * from "./string.js";
33
33
  export * from "./template.js";
34
+ export * from "./timeout.js";
34
35
  export * from "./transform.js";
35
36
  export * from "./undefined.js";
36
37
  export * from "./units.js";
package/util/index.js CHANGED
@@ -31,6 +31,7 @@ export * from "./serialise.js";
31
31
  export * from "./sort.js";
32
32
  export * from "./string.js";
33
33
  export * from "./template.js";
34
+ export * from "./timeout.js";
34
35
  export * from "./transform.js";
35
36
  export * from "./undefined.js";
36
37
  export * from "./units.js";
package/util/lazy.d.ts CHANGED
@@ -1,21 +1,18 @@
1
1
  import { Arguments } from "./function.js";
2
- import { Constructor } from "./class.js";
3
2
  /**
4
3
  * Lazy value: a plain value, or an initialiser function that returns that value.
5
4
  * @param ...args Any arguments the lazy value needs if it's a function.
6
5
  */
7
- export declare type Lazy<T, A extends Arguments = []> = ((...args: A) => T) | Constructor<T, A> | T;
6
+ export declare type Lazy<T, A extends Arguments = []> = ((...args: A) => T) | T;
8
7
  /**
9
8
  * Initialise a lazy value.
10
9
  *
11
10
  * @param value The lazy value to resolve.
12
11
  * - If this is a plain value, that value is returned.
13
12
  * - If this is a function, it is called and its returned value is returned.
14
- * - If this is a class constructor, a new instance of that class is instantiated and returned.
15
13
  *
16
14
  * @param ...args Any additional arguments the initialiser needs.
17
15
  * - This array of values is passed into the function or class constructor as its parameters.
18
16
  */
19
17
  export declare function getLazy<T, A extends Arguments>(value: (...args: A) => T, ...args: A): T;
20
- export declare function getLazy<T, A extends Arguments>(value: new (...args: A) => T, ...args: A): T;
21
18
  export declare function getLazy<T, A extends Arguments>(value: Lazy<T, A>, ...args: A): T;
package/util/lazy.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { isFunction } from "./function.js";
2
- import { isConstructor } from "./class.js";
3
2
  export function getLazy(value, ...args) {
4
- return isConstructor(value) ? new value(...args) : isFunction(value) ? value(...args) : value;
3
+ return isFunction(value) ? value(...args) : value;
5
4
  }
@@ -1,7 +1,7 @@
1
1
  import { Lazy } from "./lazy.js";
2
2
  import { ImmutableObject } from "./object.js";
3
3
  /** Template values in `{ placeholder: value }` format. */
4
- export declare type TemplateValues = ImmutableObject<string>;
4
+ declare type TemplateValues = ImmutableObject<string>;
5
5
  /** Things that can be converted to the value for a named placeholder. */
6
6
  declare type PlaceholderValues = string | ((name: string) => string) | string[] | TemplateValues;
7
7
  /**
@@ -14,14 +14,12 @@ export declare const getPlaceholders: (template: string) => readonly string[];
14
14
  /**
15
15
  * Turn ":year-:month" and "2016-06..." etc into `{ year: "2016"... }`
16
16
  *
17
- * @param lazyTemplates Either a single template string, or an arr../function of template strings.
17
+ * @param lazyTemplates Either a single template string, or an iterator that returns multiple template template strings.
18
18
  * - Template strings can include placeholders (e.g. `:name-${country}/{city}`).
19
19
  * @param target The string containing values, e.g. `Dave-UK/Manchester`
20
20
  * @return An object containing values, e.g. `{ name: "Dave", country: "UK", city: "Manchester" }`, or undefined if target didn't match the template.
21
21
  */
22
- export declare const matchTemplate: (lazyTemplates: Lazy<string | string[] | Iterable<string> | Generator<string>, [
23
- string
24
- ]>, target: string) => TemplateValues | undefined;
22
+ export declare function matchTemplate(lazyTemplates: Lazy<string | Iterable<string>, [string]>, target: string): TemplateValues | undefined;
25
23
  /**
26
24
  * Turn ":year-:month" and `{ year: "2016"... }` etc into "2016-06..." etc.
27
25
  *
package/util/template.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { getNameProp } from "./data.js";
1
2
  import { getLazy } from "./lazy.js";
2
3
  import { isObject } from "./object.js";
3
4
  // RegExp to find named variables in several formats e.g. `:a`, `${b}`, `{{c}}` or `{d}`
@@ -7,7 +8,7 @@ const R_NAME = /[a-z0-9]+/i;
7
8
  // Empty template.
8
9
  const EMPTY_TEMPLATE = Object.create(null);
9
10
  // Cache of templates.
10
- const cache = Object.create(null);
11
+ const TEMPLATE_CACHE = Object.create(null);
11
12
  /**
12
13
  * Split up a template into an array of separator → placeholder → separator → placeholder → separator
13
14
  * - Odd numbered chunks are separators.
@@ -16,8 +17,8 @@ const cache = Object.create(null);
16
17
  * @param template The template including template placeholders, e.g. `:name-${country}/{city}`
17
18
  * @returns Array of strings alternating separator and placeholder.
18
19
  */
19
- const splitTemplate = (template) => (cache[template] || (cache[template] = _splitTemplate(template)));
20
- const _splitTemplate = (template) => {
20
+ const splitTemplate = (template) => (TEMPLATE_CACHE[template] || (TEMPLATE_CACHE[template] = _split(template)));
21
+ const _split = (template) => {
21
22
  var _a;
22
23
  const matches = template.split(R_PLACEHOLDERS);
23
24
  let asterisks = 0;
@@ -39,34 +40,32 @@ const _splitTemplate = (template) => {
39
40
  * @param template The template including template placeholders, e.g. `:name-${country}/{city}`
40
41
  * @returns Array of clean string names of found placeholders, e.g. `["name", "country", "city"]`
41
42
  */
42
- export const getPlaceholders = (template) => splitTemplate(template).map(getTemplateName);
43
- const getTemplateName = (chunk) => chunk.name;
43
+ export const getPlaceholders = (template) => splitTemplate(template).map(getNameProp);
44
44
  /**
45
45
  * Turn ":year-:month" and "2016-06..." etc into `{ year: "2016"... }`
46
46
  *
47
- * @param lazyTemplates Either a single template string, or an arr../function of template strings.
47
+ * @param lazyTemplates Either a single template string, or an iterator that returns multiple template template strings.
48
48
  * - Template strings can include placeholders (e.g. `:name-${country}/{city}`).
49
49
  * @param target The string containing values, e.g. `Dave-UK/Manchester`
50
50
  * @return An object containing values, e.g. `{ name: "Dave", country: "UK", city: "Manchester" }`, or undefined if target didn't match the template.
51
51
  */
52
- export const matchTemplate = (lazyTemplates, target) => {
52
+ export function matchTemplate(lazyTemplates, target) {
53
53
  const templates = getLazy(lazyTemplates, target);
54
54
  if (typeof templates === "string") {
55
- const values = matchInternal(templates, target);
55
+ const values = _match(templates, target);
56
56
  if (values)
57
57
  return values;
58
58
  }
59
59
  else {
60
60
  for (const template of templates) {
61
- const values = matchInternal(template, target);
61
+ const values = _match(template, target);
62
62
  if (values)
63
63
  return values;
64
64
  }
65
65
  }
66
66
  return undefined;
67
- };
68
- // Internal match function (called several times).
69
- const matchInternal = (template, target) => {
67
+ }
68
+ function _match(template, target) {
70
69
  // Get separators and placeholders from template.
71
70
  const chunks = splitTemplate(template);
72
71
  const firstChunk = chunks[0];
@@ -92,7 +91,7 @@ const matchInternal = (template, target) => {
92
91
  if (startIndex < target.length)
93
92
  return undefined; // Target doesn't match template because last chunk post didn't reach the end.
94
93
  return values;
95
- };
94
+ }
96
95
  /**
97
96
  * Turn ":year-:month" and `{ year: "2016"... }` etc into "2016-06..." etc.
98
97
  *
@@ -108,10 +107,10 @@ export const renderTemplate = (template, value) => {
108
107
  return template;
109
108
  let output = template;
110
109
  for (const { name, placeholder } of chunks)
111
- output = output.replace(placeholder, getValue(name, value));
110
+ output = output.replace(placeholder, _replace(name, value));
112
111
  return output;
113
112
  };
114
- const getValue = (name, value) => {
113
+ const _replace = (name, value) => {
115
114
  if (typeof value === "string")
116
115
  return value;
117
116
  if (typeof value === "function")
@@ -121,5 +120,5 @@ const getValue = (name, value) => {
121
120
  if (typeof v === "string")
122
121
  return v;
123
122
  }
124
- throw new ReferenceError(`shelving/template: values.${name}: Must be defined`);
123
+ throw new ReferenceError(`renderTemplate(): values.${name}: Must be defined`);
125
124
  };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Create a new Timeout.
3
+ *
4
+ * Wrapper for `setTimeout()` that...
5
+ * - Keeps track of the reference returned from `setTimeout()`
6
+ * - Clears the any existing timeout when a new timeout is set.
7
+ * - Allows a default delay to be set that is applied to all new timeouts that don't have a delay set.
8
+ *
9
+ * @param ms The default delay for any created timeouts (in ms).
10
+ */
11
+ export declare class Timeout {
12
+ private _ms;
13
+ private _timeout;
14
+ constructor(ms?: number);
15
+ /**
16
+ * Cancel any existing timeout and set a new one.
17
+ * @param callback
18
+ * @param ms The delay for this timeout (in ms).
19
+ */
20
+ set(callback: () => void, ms?: number): void;
21
+ /** Cancel any existing timeout.. */
22
+ clear(): void;
23
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Create a new Timeout.
3
+ *
4
+ * Wrapper for `setTimeout()` that...
5
+ * - Keeps track of the reference returned from `setTimeout()`
6
+ * - Clears the any existing timeout when a new timeout is set.
7
+ * - Allows a default delay to be set that is applied to all new timeouts that don't have a delay set.
8
+ *
9
+ * @param ms The default delay for any created timeouts (in ms).
10
+ */
11
+ export class Timeout {
12
+ constructor(ms = 0) {
13
+ this._timeout = undefined;
14
+ this._ms = ms;
15
+ }
16
+ /**
17
+ * Cancel any existing timeout and set a new one.
18
+ * @param callback
19
+ * @param ms The delay for this timeout (in ms).
20
+ */
21
+ set(callback, ms = this._ms) {
22
+ this.clear();
23
+ this._timeout = setTimeout(callback, ms);
24
+ }
25
+ /** Cancel any existing timeout.. */
26
+ clear() {
27
+ if (this._timeout)
28
+ this._timeout = void clearTimeout(this._timeout);
29
+ }
30
+ }
@@ -1,19 +0,0 @@
1
- import { Arguments } from "../index.js";
2
- /**
3
- * Version of React's `useMemo()` that allows the use of a pure (side-effect free) function.
4
- * - Also allows the first parameter to be a plain value that is memoised as long as `args` doesn't change.
5
- * - Also allows the first parameter to be a class constructor that will create a new instance of that class.
6
- *
7
- * @param value The value to memoise, or an initialiser function or class constructor that returns that value.
8
- * - If this is a plain value, that value is returned.
9
- * - If this is a function, it is called and its returned value is returned.
10
- * - If this is a class constructor, a new instance of that class is instantiated and returned.
11
- *
12
- * @param ...args Set of arguments that specify whether the returned value is refreshed or not.
13
- * - This array of values is passed into the function or class constructor as its parameters.
14
- * - This means you can create the function once (outside the component) rather than creating it on every render.
15
- * - This improves performance (though probably only noticeable on functions that render 1,000s of times).
16
- */
17
- export declare function usePureMemo<T, A extends Arguments>(value: (...args: A) => T, ...args: A): T;
18
- export declare function usePureMemo<T, A extends Arguments>(value: new (...args: A) => T, ...args: A): T;
19
- export declare function usePureMemo<T>(value: T, ...args: Arguments): T;