@arrai-innovations/reactive-helpers 20.1.2 → 21.0.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/README.md +22 -893
- package/config/listCrud.js +30 -27
- package/config/objectCrud.js +20 -13
- package/index.js +5 -3
- package/package.json +5 -3
- package/types/config/commonCrud.d.ts +0 -1
- package/types/config/listCrud.d.ts +28 -41
- package/types/config/objectCrud.d.ts +14 -29
- package/types/index.d.ts +5 -4
- package/types/tests/unit/config/listCrud.spec.d.ts +0 -1
- package/types/tests/unit/config/objectCrud.spec.d.ts +0 -1
- package/types/tests/unit/crudPromise.d.ts +42 -15
- package/types/tests/unit/mockOnUnmounted.d.ts +0 -1
- package/types/tests/unit/poll.d.ts +0 -1
- package/types/tests/unit/scopedIt.d.ts +15 -0
- package/types/tests/unit/setup.d.ts +2 -0
- package/types/tests/unit/use/cancellableIntent.spec.d.ts +0 -1
- package/types/tests/unit/use/combineClasses.spec.d.ts +1 -0
- package/types/tests/unit/use/list.spec.d.ts +1 -0
- package/types/tests/unit/use/listCalculated.spec.d.ts +0 -1
- package/types/tests/unit/use/listFilter.spec.d.ts +0 -1
- package/types/tests/unit/use/listInstance.spec.d.ts +0 -1
- package/types/tests/unit/use/listRelated.spec.d.ts +0 -1
- package/types/tests/unit/use/listSearch.spec.d.ts +0 -1
- package/types/tests/unit/use/listSort.spec.d.ts +0 -1
- package/types/tests/unit/use/listSubscription.spec.d.ts +0 -1
- package/types/tests/unit/use/loadingError.spec.d.ts +0 -1
- package/types/tests/unit/use/object.spec.d.ts +1 -0
- package/types/tests/unit/use/objectCalculated.spec.d.ts +1 -0
- package/types/tests/unit/use/objectInstance.spec.d.ts +0 -1
- package/types/tests/unit/use/objectRelated.spec.d.ts +1 -0
- package/types/tests/unit/use/objectSubscription.spec.d.ts +0 -1
- package/types/tests/unit/use/proxyLoadingError.spec.d.ts +0 -1
- package/types/tests/unit/use/search.error.spec.d.ts +1 -0
- package/types/tests/unit/use/search.spec.d.ts +0 -1
- package/types/tests/unit/utils/assignReactiveObject.extra.spec.d.ts +1 -0
- package/types/tests/unit/utils/assignReactiveObject.refs.spec.d.ts +1 -0
- package/types/tests/unit/utils/assignReactiveObject.spec.d.ts +0 -1
- package/types/tests/unit/utils/cancellableFetch.spec.d.ts +1 -0
- package/types/tests/unit/utils/classes.spec.d.ts +0 -1
- package/types/tests/unit/utils/compact.spec.d.ts +1 -0
- package/types/tests/unit/utils/deepUnref.spec.d.ts +1 -0
- package/types/tests/unit/utils/deleteKey.spec.d.ts +0 -1
- package/types/tests/unit/utils/flattenPaths.spec.d.ts +0 -1
- package/types/tests/unit/utils/flattenPathsWithValues.spec.d.ts +1 -0
- package/types/tests/unit/utils/getFakePk.spec.d.ts +1 -0
- package/types/tests/unit/utils/keepAliveTry.spec.d.ts +1 -0
- package/types/tests/unit/utils/keyDiff.spec.d.ts +0 -1
- package/types/tests/unit/utils/set.spec.d.ts +0 -1
- package/types/tests/unit/utils/transformWalk.spec.d.ts +1 -0
- package/types/tests/unit/utils/unwrapNested.spec.d.ts +1 -0
- package/types/tests/unit/utils/watches.spec.d.ts +0 -1
- package/types/use/cancellableIntent.d.ts +121 -48
- package/types/use/combineClasses.d.ts +0 -1
- package/types/use/error.d.ts +48 -0
- package/types/use/list.d.ts +9 -32
- package/types/use/listCalculated.d.ts +107 -49
- package/types/use/listFilter.d.ts +13 -31
- package/types/use/listInstance.d.ts +137 -71
- package/types/use/listRelated.d.ts +106 -43
- package/types/use/listSearch.d.ts +24 -12
- package/types/use/listSort.d.ts +3 -34
- package/types/use/listSubscription.d.ts +40 -57
- package/types/use/loading.d.ts +37 -0
- package/types/use/loadingError.d.ts +5 -100
- package/types/use/object.d.ts +3 -12
- package/types/use/objectCalculated.d.ts +3 -9
- package/types/use/objectInstance.d.ts +59 -47
- package/types/use/objectRelated.d.ts +3 -9
- package/types/use/objectSubscription.d.ts +33 -51
- package/types/use/proxyError.d.ts +27 -0
- package/types/use/proxyLoading.d.ts +15 -0
- package/types/use/proxyLoadingError.d.ts +8 -16
- package/types/use/search.d.ts +2 -3
- package/types/utils/assignReactiveObject.d.ts +0 -1
- package/types/utils/cancellableFetch.d.ts +0 -1
- package/types/utils/cancellablePromise.d.ts +0 -1
- package/types/utils/classes.d.ts +2 -8
- package/types/utils/compact.d.ts +0 -1
- package/types/utils/deepUnref.d.ts +2 -23
- package/types/utils/deleteKey.d.ts +6 -6
- package/types/utils/flattenPaths.d.ts +0 -1
- package/types/utils/flattenPathsWithValues.d.ts +29 -0
- package/types/utils/getFakePk.d.ts +0 -1
- package/types/utils/keepAliveTry.d.ts +0 -1
- package/types/utils/keyDiff.d.ts +9 -10
- package/types/utils/loadingCombine.d.ts +0 -1
- package/types/utils/proxyRunning.d.ts +2 -3
- package/types/utils/refIfReactive.d.ts +0 -1
- package/types/utils/relatedCalculatedHelpers.d.ts +0 -1
- package/types/utils/set.d.ts +0 -1
- package/types/utils/transformWalk.d.ts +0 -1
- package/types/utils/unwrapNested.d.ts +0 -1
- package/types/utils/watches.d.ts +0 -1
- package/use/cancellableIntent.js +185 -100
- package/use/error.js +44 -0
- package/use/list.js +51 -111
- package/use/listCalculated.js +75 -98
- package/use/listFilter.js +91 -186
- package/use/listInstance.js +357 -282
- package/use/listRelated.js +52 -72
- package/use/listSearch.js +49 -86
- package/use/listSort.js +121 -237
- package/use/listSubscription.js +181 -274
- package/use/loading.js +35 -0
- package/use/loadingError.js +7 -81
- package/use/object.js +47 -67
- package/use/objectCalculated.js +103 -65
- package/use/objectInstance.js +253 -241
- package/use/objectRelated.js +48 -30
- package/use/objectSubscription.js +110 -175
- package/use/proxyError.js +48 -0
- package/use/proxyLoading.js +22 -0
- package/use/proxyLoadingError.js +9 -35
- package/use/search.js +4 -2
- package/utils/assignReactiveObject.js +8 -8
- package/utils/classes.js +7 -28
- package/utils/deepUnref.js +15 -2
- package/utils/deleteKey.js +13 -5
- package/utils/flattenPathsWithValues.js +65 -0
- package/utils/keyDiff.js +5 -5
- package/utils/proxyRunning.js +16 -10
- package/types/config/commonCrud.d.ts.map +0 -1
- package/types/config/listCrud.d.ts.map +0 -1
- package/types/config/objectCrud.d.ts.map +0 -1
- package/types/index.d.ts.map +0 -1
- package/types/tests/unit/config/listCrud.spec.d.ts.map +0 -1
- package/types/tests/unit/config/objectCrud.spec.d.ts.map +0 -1
- package/types/tests/unit/crudPromise.d.ts.map +0 -1
- package/types/tests/unit/expectHelpers.d.ts +0 -2
- package/types/tests/unit/expectHelpers.d.ts.map +0 -1
- package/types/tests/unit/mockOnUnmounted.d.ts.map +0 -1
- package/types/tests/unit/poll.d.ts.map +0 -1
- package/types/tests/unit/use/cancellableIntent.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listCalculated.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listFilter.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listInstance.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listRelated.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listSearch.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listSort.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listSubscription.spec.d.ts.map +0 -1
- package/types/tests/unit/use/loadingError.spec.d.ts.map +0 -1
- package/types/tests/unit/use/objectInstance.spec.d.ts.map +0 -1
- package/types/tests/unit/use/objectSubscription.spec.d.ts.map +0 -1
- package/types/tests/unit/use/proxyLoadingError.spec.d.ts.map +0 -1
- package/types/tests/unit/use/search.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/assignReactiveObject.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/classes.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/deleteKey.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/flattenPaths.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/keyDiff.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/set.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/watches.spec.d.ts.map +0 -1
- package/types/use/cancellableIntent.d.ts.map +0 -1
- package/types/use/combineClasses.d.ts.map +0 -1
- package/types/use/list.d.ts.map +0 -1
- package/types/use/listCalculated.d.ts.map +0 -1
- package/types/use/listFilter.d.ts.map +0 -1
- package/types/use/listInstance.d.ts.map +0 -1
- package/types/use/listKeys.d.ts +0 -15
- package/types/use/listKeys.d.ts.map +0 -1
- package/types/use/listRelated.d.ts.map +0 -1
- package/types/use/listSearch.d.ts.map +0 -1
- package/types/use/listSort.d.ts.map +0 -1
- package/types/use/listSubscription.d.ts.map +0 -1
- package/types/use/loadingError.d.ts.map +0 -1
- package/types/use/object.d.ts.map +0 -1
- package/types/use/objectCalculated.d.ts.map +0 -1
- package/types/use/objectInstance.d.ts.map +0 -1
- package/types/use/objectRelated.d.ts.map +0 -1
- package/types/use/objectSubscription.d.ts.map +0 -1
- package/types/use/paginatedListInstance.d.ts +0 -60
- package/types/use/paginatedListInstance.d.ts.map +0 -1
- package/types/use/proxyLoadingError.d.ts.map +0 -1
- package/types/use/search.d.ts.map +0 -1
- package/types/use/watchesRunning.d.ts +0 -63
- package/types/use/watchesRunning.d.ts.map +0 -1
- package/types/utils/assignReactiveObject.d.ts.map +0 -1
- package/types/utils/cancellableFetch.d.ts.map +0 -1
- package/types/utils/cancellablePromise.d.ts.map +0 -1
- package/types/utils/classes.d.ts.map +0 -1
- package/types/utils/compact.d.ts.map +0 -1
- package/types/utils/deepUnref.d.ts.map +0 -1
- package/types/utils/deleteKey.d.ts.map +0 -1
- package/types/utils/flattenPaths.d.ts.map +0 -1
- package/types/utils/getFakePk.d.ts.map +0 -1
- package/types/utils/keepAliveTry.d.ts.map +0 -1
- package/types/utils/keyDiff.d.ts.map +0 -1
- package/types/utils/loadingCombine.d.ts.map +0 -1
- package/types/utils/proxyRunning.d.ts.map +0 -1
- package/types/utils/refIfReactive.d.ts.map +0 -1
- package/types/utils/relatedCalculatedHelpers.d.ts.map +0 -1
- package/types/utils/set.d.ts.map +0 -1
- package/types/utils/transformWalk.d.ts.map +0 -1
- package/types/utils/unwrapNested.d.ts.map +0 -1
- package/types/utils/watches.d.ts.map +0 -1
- package/use/listKeys.js +0 -105
- package/use/paginatedListInstance.js +0 -126
- package/use/watchesRunning.js +0 -69
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get all primitive paths and their corresponding values from an array or object.
|
|
3
|
+
*
|
|
4
|
+
* @module utils/flattenPathsWithValues.js
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Turn an array or object into an array of `[path, value]` pairs (for primitives)
|
|
8
|
+
* and a list of container paths (for arrays and objects).
|
|
9
|
+
*
|
|
10
|
+
* Array indexes are wrapped in square brackets and object keys are prefixed with a period.
|
|
11
|
+
*
|
|
12
|
+
* @param {any[] | object} arrayOrObject - Array or object to flatten.
|
|
13
|
+
* @param {object} [options] - Options.
|
|
14
|
+
* @param {string} [options.currentPath=""] - Current path, for recursion or as a starting point.
|
|
15
|
+
* @param {number} [options.depth=0] - Current depth, for recursion.
|
|
16
|
+
* @param {number} [options.limit=0] - Limit the depth of recursion.
|
|
17
|
+
* @returns {{
|
|
18
|
+
* pathValues: [string, any][],
|
|
19
|
+
* containerPaths: string[]
|
|
20
|
+
* }} - Paths and their corresponding values.
|
|
21
|
+
*/
|
|
22
|
+
export function flattenPathsWithValues(arrayOrObject: any[] | object, { currentPath, depth, limit }?: {
|
|
23
|
+
currentPath?: string;
|
|
24
|
+
depth?: number;
|
|
25
|
+
limit?: number;
|
|
26
|
+
}): {
|
|
27
|
+
pathValues: [string, any][];
|
|
28
|
+
containerPaths: string[];
|
|
29
|
+
};
|
package/types/utils/keyDiff.d.ts
CHANGED
|
@@ -8,23 +8,23 @@
|
|
|
8
8
|
* Result object of keyDiff and keyDiffDeep.
|
|
9
9
|
*
|
|
10
10
|
* @typedef {object} KeyDiffResult
|
|
11
|
-
* @property {Set} [sameKeys] - If sameKeys option is true, return keys that are the same.
|
|
12
|
-
* @property {Set} [removedKeys] - If removedKeys option is true, return keys that are removed.
|
|
13
|
-
* @property {Set} [addedKeys] - If addedKeys option is true, return keys that are added.
|
|
11
|
+
* @property {Set<string>} [sameKeys] - If sameKeys option is true, return keys that are the same.
|
|
12
|
+
* @property {Set<string>} [removedKeys] - If removedKeys option is true, return keys that are removed.
|
|
13
|
+
* @property {Set<string>} [addedKeys] - If addedKeys option is true, return keys that are added.
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
16
|
* Calculate the difference between two arrays of keys, in terms of what keys
|
|
17
17
|
* are the same, what keys are removed, and what keys are added.
|
|
18
18
|
*
|
|
19
|
-
* @param {string[]|Set} newKeys - Keys to consider as new.
|
|
20
|
-
* @param {string[]|Set} oldKeys - Keys to consider as old.
|
|
19
|
+
* @param {string[]|Set<string>} newKeys - Keys to consider as new.
|
|
20
|
+
* @param {string[]|Set<string>} oldKeys - Keys to consider as old.
|
|
21
21
|
* @param {object} [options] - Which differences are returned.
|
|
22
22
|
* @param {boolean} [options.sameKeys=true] - If true, return keys that are the same.
|
|
23
23
|
* @param {boolean} [options.removedKeys=true] - If true, return keys that are removed.
|
|
24
24
|
* @param {boolean} [options.addedKeys=true] - If true, return keys that are added.
|
|
25
25
|
* @returns {KeyDiffResult} - The differences.
|
|
26
26
|
*/
|
|
27
|
-
export function keyDiff(newKeys: string[] | Set<
|
|
27
|
+
export function keyDiff(newKeys: string[] | Set<string>, oldKeys: string[] | Set<string>, { sameKeys, removedKeys, addedKeys }?: {
|
|
28
28
|
sameKeys?: boolean;
|
|
29
29
|
removedKeys?: boolean;
|
|
30
30
|
addedKeys?: boolean;
|
|
@@ -50,14 +50,13 @@ export type KeyDiffResult = {
|
|
|
50
50
|
/**
|
|
51
51
|
* - If sameKeys option is true, return keys that are the same.
|
|
52
52
|
*/
|
|
53
|
-
sameKeys?: Set<
|
|
53
|
+
sameKeys?: Set<string>;
|
|
54
54
|
/**
|
|
55
55
|
* - If removedKeys option is true, return keys that are removed.
|
|
56
56
|
*/
|
|
57
|
-
removedKeys?: Set<
|
|
57
|
+
removedKeys?: Set<string>;
|
|
58
58
|
/**
|
|
59
59
|
* - If addedKeys option is true, return keys that are added.
|
|
60
60
|
*/
|
|
61
|
-
addedKeys?: Set<
|
|
61
|
+
addedKeys?: Set<string>;
|
|
62
62
|
};
|
|
63
|
-
//# sourceMappingURL=keyDiff.d.ts.map
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @param {import("vue").UnwrapNestedRefs<object>} parentState - The parent state.
|
|
5
5
|
* @param {string} parentStateProp - The parent state property.
|
|
6
|
-
* @param {import("vue").Ref<boolean>}
|
|
6
|
+
* @param {import("vue").Ref<boolean>} childRef - The ref to proxy to.
|
|
7
7
|
*/
|
|
8
|
-
export function proxyRunning(parentState: import("vue").UnwrapNestedRefs<object>, parentStateProp: string,
|
|
9
|
-
//# sourceMappingURL=proxyRunning.d.ts.map
|
|
8
|
+
export function proxyRunning(parentState: import("vue").UnwrapNestedRefs<object>, parentStateProp: string, childRef: import("vue").Ref<boolean>): void;
|
|
@@ -2,4 +2,3 @@ export const relatedItemRegex: RegExp;
|
|
|
2
2
|
export const calculatedItemRegex: RegExp;
|
|
3
3
|
export function getObjectRelatedCalculatedByKey(obj: object, relatedObj: object, calculatedObj: object, key: string): [object, string];
|
|
4
4
|
export function getObjectRelatedByKey(obj: object, relatedObj: object, key: string): [object, string];
|
|
5
|
-
//# sourceMappingURL=relatedCalculatedHelpers.d.ts.map
|
package/types/utils/set.d.ts
CHANGED
|
@@ -4,4 +4,3 @@ export function intersection(setA: Set<any>, setB: Set<any>): Set<any>;
|
|
|
4
4
|
export function symmetricDifference(setA: Set<any>, setB: Set<any>): Set<any>;
|
|
5
5
|
export function difference(setA: Set<any>, setB: Set<any>): Set<any>;
|
|
6
6
|
export function equals(setA: Set<any>, setB: Set<any>): boolean;
|
|
7
|
-
//# sourceMappingURL=set.d.ts.map
|
package/types/utils/watches.d.ts
CHANGED
package/use/cancellableIntent.js
CHANGED
|
@@ -1,44 +1,101 @@
|
|
|
1
1
|
import identity from "lodash-es/identity.js";
|
|
2
2
|
import isEmpty from "lodash-es/isEmpty.js";
|
|
3
3
|
import isEqual from "lodash-es/isEqual.js";
|
|
4
|
-
import { computed, effectScope, nextTick, onScopeDispose, reactive, readonly, watch } from "vue";
|
|
5
|
-
import { deepUnref } from "../utils/deepUnref.js";
|
|
4
|
+
import { computed, effectScope, nextTick, onScopeDispose, reactive, readonly, toRef, watch } from "vue";
|
|
6
5
|
import { tryOnActivated, tryOnDeactivated } from "../utils/keepAliveTry.js";
|
|
6
|
+
import { deepUnref } from "vue-deepunref";
|
|
7
|
+
import { useLoadingError } from "./loadingError.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @module use/cancellableIntent.js - A composable function for handling cancellable intents.
|
|
10
11
|
*/
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Custom error class for list subscription errors.
|
|
15
|
+
*/
|
|
16
|
+
export class CancellableIntentError extends Error {
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new CancellableIntentError.
|
|
19
|
+
*
|
|
20
|
+
* @param {string} message - The error message.
|
|
21
|
+
* @param {string} code - The error code.
|
|
22
|
+
*/
|
|
23
|
+
constructor(message, code) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "CancellableIntentError";
|
|
26
|
+
this.code = code;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {number} RunId - A unique identifier for a single execution ("run") of an intent.
|
|
32
|
+
* This is incremented each time `watchArguments` change and the intent re-triggers.
|
|
33
|
+
* Enables distinguishing results or effects from overlapping async runs.
|
|
34
|
+
*/
|
|
35
|
+
|
|
12
36
|
/**
|
|
13
37
|
* @typedef {object} CancellableIntentRawState - The raw state of the cancellable intent.
|
|
14
|
-
* @property {
|
|
15
|
-
* @property {boolean
|
|
16
|
-
* @property {number|undefined} resolvingCount - The number of resolving intents.
|
|
17
|
-
* @property {boolean|undefined} resolving - Whether there are resolving intents.
|
|
18
|
-
* @property {boolean} errored - Whether there was an error.
|
|
19
|
-
* @property {Error|null} error - The error that occurred.
|
|
38
|
+
* @property {import('vue').ComputedRef<boolean>|undefined} active - Whether there are active intents.
|
|
39
|
+
* @property {import('vue').ComputedRef<boolean>|undefined} resolving - Whether there are resolving intents.
|
|
20
40
|
* @property {boolean} clearActiveOnResolved - Whether to clear the active state when the promise resolves.
|
|
41
|
+
* @property {RunId|null} lastRunId - The most recent run ID issued for a triggered intent. Useful for associating async results with their originating trigger.
|
|
42
|
+
* @property {import('vue').DeepReadonly<object>} watchArguments - The watch arguments.
|
|
43
|
+
* @property {import('vue').DeepReadonly<object>} guardArguments - The guard arguments.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {import("vue").Reactive<
|
|
48
|
+
* CancellableIntentRawState &
|
|
49
|
+
* Pick<import('./error.js').ErrorStatus, 'error' | 'errored'>
|
|
50
|
+
* >} CancellableIntentState - The state of the cancellable intent.
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @typedef {() => boolean} IsCurrentRunFn - A function that checks if the current run ID matches the last run ID.
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The common run tracking arguments.
|
|
59
|
+
*
|
|
60
|
+
* @typedef {object} CommonRunTracking
|
|
61
|
+
* @property {RunId} runId - The unique identifier for your run.
|
|
62
|
+
* @property {IsCurrentRunFn} isCurrentRun - A function that checks if the current run ID matches your run ID.
|
|
21
63
|
*/
|
|
22
64
|
|
|
23
65
|
/**
|
|
24
|
-
* @typedef {import(
|
|
66
|
+
* @typedef {(runTracking: CommonRunTracking) => import('../utils/cancellablePromise.js').MaybeCancellablePromise<void>} AwaitableWithCancel - A function that returns a promise that can be cancelled.
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @typedef {import("vue").UnwrapNestedRefs<object>|{[key: string]: import('vue').Ref<any>}} WatchGuardArguments - The reactive object to watch for changes.
|
|
25
71
|
*/
|
|
26
72
|
|
|
27
73
|
/**
|
|
28
74
|
* @typedef {object} CancellableIntentOptions - The options for the cancellable intent.
|
|
29
|
-
* @property {
|
|
30
|
-
* @property {
|
|
31
|
-
* @property {
|
|
75
|
+
* @property {AwaitableWithCancel} awaitableWithCancel - The function that returns a promise that can be cancelled. Receives the run ID as an argument.
|
|
76
|
+
* @property {WatchGuardArguments} [watchArguments={}] - The reactive object to watch for changes.
|
|
77
|
+
* @property {WatchGuardArguments} [guardArguments={}] - The reactive object to watch for truthiness before running the intent.
|
|
32
78
|
* @property {boolean} [clearActiveOnResolved=true] - Whether to clear the active state when the promise resolves.
|
|
33
79
|
*/
|
|
34
80
|
|
|
35
81
|
/**
|
|
36
|
-
*
|
|
82
|
+
* Cancel function signature for cancellable intent.
|
|
83
|
+
*
|
|
84
|
+
* @typedef {Function} CancelFn
|
|
85
|
+
* @param {any} reason - The reason for cancellation.
|
|
86
|
+
* @param {boolean} [forceClearActive=false] - Whether to force clear the active state.
|
|
87
|
+
* @returns {Promise<void>} - A promise that resolves when the cancellation is complete.
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @typedef {object} MyCancellableIntent - The instance of the cancellable intent.
|
|
37
92
|
* @property {CancellableIntentState} state - The state of the cancellable intent.
|
|
38
|
-
* @property {
|
|
39
|
-
* @property {
|
|
40
|
-
|
|
41
|
-
|
|
93
|
+
* @property {() => void} stop - Stop the cancellable intent.
|
|
94
|
+
* @property {CancelFn} cancel - Cancel the cancellable intent.
|
|
95
|
+
*/
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @typedef {MyCancellableIntent & Pick<import('./error.js').ErrorStatus, "clearError">} CancellableIntent - The instance of the cancellable intent.
|
|
42
99
|
*/
|
|
43
100
|
|
|
44
101
|
/**
|
|
@@ -91,73 +148,100 @@ export function useCancellableIntent({
|
|
|
91
148
|
if (typeof awaitableWithCancel !== "function") {
|
|
92
149
|
throw new Error("awaitableWithCancel must be a function");
|
|
93
150
|
}
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
151
|
+
const es = effectScope();
|
|
152
|
+
let myRunId = 0; // each intent has its own namespace of intention session ids
|
|
153
|
+
const internalState = reactive({
|
|
154
|
+
watchArguments,
|
|
155
|
+
guardArguments,
|
|
156
|
+
activeCount: undefined, // the active count doesn't mean much when not using clearActiveOnResolved
|
|
157
|
+
resolvingCount: undefined,
|
|
158
|
+
});
|
|
159
|
+
const loadingError = es.run(() => useLoadingError());
|
|
160
|
+
/** @type {CancellableIntentState} */
|
|
161
|
+
const state = reactive({
|
|
162
|
+
active: es.run(() =>
|
|
163
|
+
computed(() => {
|
|
164
|
+
if (internalState.activeCount === undefined) {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
return internalState.activeCount > 0;
|
|
168
|
+
})
|
|
169
|
+
),
|
|
170
|
+
resolving: es.run(() =>
|
|
171
|
+
computed(() => {
|
|
172
|
+
if (internalState.resolvingCount === undefined) {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
return internalState.resolvingCount > 0;
|
|
176
|
+
})
|
|
177
|
+
),
|
|
178
|
+
errored: loadingError.errored,
|
|
179
|
+
error: loadingError.error,
|
|
180
|
+
clearActiveOnResolved,
|
|
181
|
+
lastRunId: null,
|
|
182
|
+
watchArguments: readonly(internalState.watchArguments),
|
|
183
|
+
guardArguments: readonly(internalState.guardArguments),
|
|
184
|
+
});
|
|
106
185
|
let previousWatchValues = null,
|
|
107
186
|
cancelFunction = null;
|
|
108
187
|
|
|
109
|
-
const es = effectScope();
|
|
110
|
-
|
|
111
|
-
function stop() {
|
|
112
|
-
// effect scopes are stopped automatically in onUnmounted / a parent onScopeDispose; this is for other use cases
|
|
113
|
-
es.stop();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async function cancel(/** @type {any} */ reason) {
|
|
117
|
-
if (cancelFunction) {
|
|
118
|
-
return cancelFunction(reason)
|
|
119
|
-
.catch(console.error)
|
|
120
|
-
.finally(() => {
|
|
121
|
-
if (!state.clearActiveOnResolved) {
|
|
122
|
-
cancelFunction = null;
|
|
123
|
-
state.activeCount--;
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
188
|
const doIntentWatch = () => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
189
|
+
loadingError.clearError();
|
|
190
|
+
if (internalState.activeCount === undefined) {
|
|
191
|
+
internalState.activeCount = 0;
|
|
192
|
+
}
|
|
193
|
+
internalState.activeCount += 1;
|
|
194
|
+
if (internalState.resolvingCount === undefined) {
|
|
195
|
+
internalState.resolvingCount = 0;
|
|
135
196
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
197
|
+
internalState.resolvingCount += 1;
|
|
198
|
+
let thisRunId = ++myRunId;
|
|
199
|
+
state.lastRunId = thisRunId;
|
|
200
|
+
let awaitablePromise;
|
|
201
|
+
try {
|
|
202
|
+
awaitablePromise = awaitableWithCancel({
|
|
203
|
+
runId: thisRunId,
|
|
204
|
+
isCurrentRun: () => thisRunId === state.lastRunId,
|
|
205
|
+
});
|
|
206
|
+
} catch (error) {
|
|
207
|
+
// no need to cancel if we throw even before we get a promise
|
|
208
|
+
loadingError.setError(error);
|
|
209
|
+
internalState.resolvingCount--;
|
|
210
|
+
// even if you don't clear active on resolved, we didn't resolve
|
|
211
|
+
internalState.activeCount--;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!awaitablePromise || typeof awaitablePromise.then !== "function") {
|
|
216
|
+
loadingError.setError(
|
|
217
|
+
new CancellableIntentError(
|
|
218
|
+
"awaitableWithCancel must return a thenable (Promise-like) object",
|
|
219
|
+
"invalid-promise"
|
|
220
|
+
)
|
|
221
|
+
);
|
|
222
|
+
return;
|
|
139
223
|
}
|
|
140
|
-
state.resolvingCount += 1;
|
|
141
|
-
let awaitablePromise = awaitableWithCancel();
|
|
142
224
|
|
|
143
225
|
if (awaitablePromise.cancel) {
|
|
144
226
|
cancelFunction = awaitablePromise.cancel.bind(awaitablePromise);
|
|
227
|
+
} else {
|
|
228
|
+
cancelFunction = null;
|
|
145
229
|
}
|
|
146
230
|
// we don't want to await this, because we want to be able to cancel it
|
|
147
231
|
awaitablePromise
|
|
148
|
-
.
|
|
149
|
-
await cancel("Error in awaitableWithCancel");
|
|
150
|
-
console.error(err);
|
|
151
|
-
state.errored = true;
|
|
152
|
-
state.error = err;
|
|
153
|
-
throw err;
|
|
154
|
-
})
|
|
155
|
-
.finally(() => {
|
|
156
|
-
state.resolvingCount--;
|
|
232
|
+
.then(() => {
|
|
157
233
|
if (state.clearActiveOnResolved) {
|
|
158
234
|
cancelFunction = null;
|
|
159
|
-
|
|
235
|
+
internalState.activeCount--;
|
|
160
236
|
}
|
|
237
|
+
})
|
|
238
|
+
.catch(async (err) => {
|
|
239
|
+
const cancelPromise = instance.cancel("Error in awaitableWithCancel", true);
|
|
240
|
+
loadingError.setError(err);
|
|
241
|
+
await cancelPromise;
|
|
242
|
+
})
|
|
243
|
+
.finally(() => {
|
|
244
|
+
internalState.resolvingCount--;
|
|
161
245
|
});
|
|
162
246
|
};
|
|
163
247
|
|
|
@@ -171,18 +255,18 @@ export function useCancellableIntent({
|
|
|
171
255
|
runningIntentWatch = true;
|
|
172
256
|
// this locked section is to deal with multiple intentWatches running while waiting for cancel to resolve
|
|
173
257
|
try {
|
|
174
|
-
let newWatchValues =
|
|
258
|
+
let newWatchValues = Object.values(deepUnref(internalState.watchArguments));
|
|
175
259
|
if (isEqual(newWatchValues, previousWatchValues)) {
|
|
176
260
|
return;
|
|
177
261
|
}
|
|
178
|
-
await cancel("Intent watch cancelled"); // this can take time so guards and watches can change!
|
|
179
|
-
newWatchValues =
|
|
262
|
+
await instance.cancel("Intent watch cancelled"); // this can take time so guards and watches can change!
|
|
263
|
+
newWatchValues = Object.values(deepUnref(internalState.watchArguments));
|
|
180
264
|
if (isEqual(newWatchValues, previousWatchValues)) {
|
|
181
265
|
return;
|
|
182
266
|
}
|
|
183
267
|
previousWatchValues = newWatchValues;
|
|
184
|
-
const guardValues =
|
|
185
|
-
if (
|
|
268
|
+
const guardValues = Object.values(deepUnref(internalState.guardArguments));
|
|
269
|
+
if (newWatchValues.every(identity)) {
|
|
186
270
|
// if any guards are true, delay the watch.
|
|
187
271
|
if (guardValues && !isEmpty(guardValues) && guardValues.some(identity)) {
|
|
188
272
|
delayedWatch = doIntentWatch;
|
|
@@ -203,7 +287,7 @@ export function useCancellableIntent({
|
|
|
203
287
|
const guardWatch = () => {
|
|
204
288
|
if (delayedWatch) {
|
|
205
289
|
// if all guards are false, run the watch
|
|
206
|
-
if (Object.values(guardArguments).
|
|
290
|
+
if (!Object.values(deepUnref(guardArguments)).some(identity)) {
|
|
207
291
|
const myDelayedWatch = delayedWatch;
|
|
208
292
|
delayedWatch = null;
|
|
209
293
|
myDelayedWatch();
|
|
@@ -214,7 +298,7 @@ export function useCancellableIntent({
|
|
|
214
298
|
const cleanup = () => {
|
|
215
299
|
// cancel the intent when the component is deactivated
|
|
216
300
|
// noinspection JSIgnoredPromiseFromCall
|
|
217
|
-
cancel("Component deactivated");
|
|
301
|
+
instance.cancel("Component deactivated");
|
|
218
302
|
if (state.clearActiveOnResolved) {
|
|
219
303
|
// otherwise it clears when resolved
|
|
220
304
|
cancelFunction = null;
|
|
@@ -223,33 +307,38 @@ export function useCancellableIntent({
|
|
|
223
307
|
previousWatchValues = null;
|
|
224
308
|
};
|
|
225
309
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
310
|
+
/** @type {CancellableIntent} */
|
|
311
|
+
const instance = {
|
|
312
|
+
state,
|
|
313
|
+
// effect scopes are stopped automatically in onUnmounted / a parent onScopeDispose; this is for other use cases
|
|
314
|
+
stop: () => es.stop(),
|
|
315
|
+
cancel: async (/** @type {any} */ reason, forceClearActive = false) => {
|
|
316
|
+
if (cancelFunction) {
|
|
317
|
+
const toCancel = cancelFunction;
|
|
318
|
+
cancelFunction = null;
|
|
319
|
+
if (!state.clearActiveOnResolved || forceClearActive) {
|
|
320
|
+
internalState.activeCount--;
|
|
321
|
+
}
|
|
322
|
+
return toCancel(reason).catch(console.error);
|
|
236
323
|
}
|
|
237
|
-
return
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
|
|
324
|
+
return false;
|
|
325
|
+
},
|
|
326
|
+
clearError: loadingError.clearError,
|
|
327
|
+
};
|
|
328
|
+
es.run(() => {
|
|
329
|
+
watch(toRef(internalState, "watchArguments"), intentWatch, {
|
|
241
330
|
// this can't be immediate because subscribe wants to look at our state, which won't exist yet.
|
|
242
331
|
deep: true,
|
|
243
332
|
});
|
|
244
333
|
|
|
245
|
-
watch((
|
|
334
|
+
watch(toRef(internalState, "guardArguments"), guardWatch, {
|
|
246
335
|
// we can't possibly have a delayed watch immediately
|
|
247
336
|
deep: true,
|
|
248
337
|
});
|
|
249
338
|
|
|
250
339
|
tryOnActivated(() => {
|
|
251
|
-
|
|
252
|
-
|
|
340
|
+
internalState.activeCount = 0;
|
|
341
|
+
internalState.resolvingCount = 0;
|
|
253
342
|
// trigger the intent watch manually to get current watch values
|
|
254
343
|
// noinspection JSIgnoredPromiseFromCall
|
|
255
344
|
intentWatch();
|
|
@@ -257,13 +346,9 @@ export function useCancellableIntent({
|
|
|
257
346
|
tryOnDeactivated(cleanup);
|
|
258
347
|
onScopeDispose(cleanup);
|
|
259
348
|
|
|
349
|
+
// intentWatch can't be immediate because subscribe wants to look at our state, which won't exist yet.
|
|
350
|
+
// but we do want to run immediately-ish
|
|
260
351
|
nextTick().then(intentWatch);
|
|
261
352
|
});
|
|
262
|
-
return
|
|
263
|
-
state,
|
|
264
|
-
watchArguments: readonly(watchArguments),
|
|
265
|
-
guardArguments: readonly(guardArguments),
|
|
266
|
-
stop,
|
|
267
|
-
cancel,
|
|
268
|
-
};
|
|
353
|
+
return instance;
|
|
269
354
|
}
|
package/use/error.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readonly, ref } from "vue";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {() => void} ClearErrorFn
|
|
5
|
+
* @typedef {import("vue").Ref<Error|null>} ErrorRef
|
|
6
|
+
* @typedef {import("vue").Ref<boolean>} ErroredRef
|
|
7
|
+
* @typedef {Readonly<ErrorRef>} ErrorReadonlyRef
|
|
8
|
+
* @typedef {Readonly<ErroredRef>} ErroredReadonlyRef
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The error state API.
|
|
13
|
+
*
|
|
14
|
+
* @typedef {object} ErrorStatus
|
|
15
|
+
* @property {ErrorReadonlyRef} error - The error that occurred.
|
|
16
|
+
* @property {ErroredReadonlyRef} errored - Whether an error has occurred.
|
|
17
|
+
* @property {(error: Error) => void} setError - Set the error state.
|
|
18
|
+
* @property {ClearErrorFn} clearError - Clear the error state.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A composable function for managing error state.
|
|
23
|
+
*
|
|
24
|
+
* @returns {ErrorStatus} - An object containing reactive fields and actions for error state.
|
|
25
|
+
*/
|
|
26
|
+
export function useError() {
|
|
27
|
+
/** @type {ErrorRef} */
|
|
28
|
+
const error = ref(null);
|
|
29
|
+
/** @type {ErroredRef} */
|
|
30
|
+
const errored = ref(false);
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
error: readonly(error),
|
|
34
|
+
errored: readonly(errored),
|
|
35
|
+
setError: (e) => {
|
|
36
|
+
error.value = e;
|
|
37
|
+
errored.value = true;
|
|
38
|
+
},
|
|
39
|
+
clearError: () => {
|
|
40
|
+
error.value = null;
|
|
41
|
+
errored.value = false;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|