@arrai-innovations/reactive-helpers 8.0.1 → 8.0.4

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.
@@ -4,8 +4,8 @@ module.exports = {
4
4
  env: {
5
5
  node: true,
6
6
  },
7
-
8
- extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
7
+ plugins: ["jsdoc"],
8
+ extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier", "plugin:jsdoc/recommended-error"],
9
9
 
10
10
  parserOptions: {
11
11
  parser: "babel-eslint",
@@ -22,5 +22,6 @@ module.exports = {
22
22
  asyncArrow: "always",
23
23
  },
24
24
  ],
25
+ "jsdoc/require-jsdoc": "off", // let's ease into this
25
26
  },
26
27
  };
package/.jsdoc2md.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "files": ["use/**/*.js", "utils/**/*.js"],
3
+ "plugin": "@godaddy/dmd"
4
+ }
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  ![ESLint](https://docs.arrai-dev.com/reactive-helpers/artifacts/main/eslint.svg)
6
6
  ![Prettier](https://docs.arrai-dev.com/reactive-helpers/artifacts/main/prettier.svg)
7
7
 
8
- VueJS 3 utility composition functions to help manipulate objects and lists.
8
+ Vue.js 3 utility composition functions to help manipulate objects and lists.
9
9
 
10
10
  <!-- prettier-ignore-start -->
11
11
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
@@ -14,6 +14,7 @@ VueJS 3 utility composition functions to help manipulate objects and lists.
14
14
  - [Install](#install)
15
15
  - [Usage](#usage)
16
16
  - [Import](#import)
17
+ - [JSDocs](#jsdocs)
17
18
  - [List](#list)
18
19
  - [Instance](#instance)
19
20
  - [Subscription](#subscription)
@@ -46,8 +47,18 @@ $ npm install @arrai-innovations/reactive-helpers
46
47
  ```js
47
48
  // base import contains all exports
48
49
  import { useListInstance, useObjectInstance } from "@arrai-innovations/reactive-helpers";
50
+ // you can also import individual modules
51
+ import { useListInstance } from "@arrai-innovations/reactive-helpers/use/listInstance";
52
+ // or the module categories
53
+ import { useObjectInstance } from "@arrai-innovations/reactive-helpers/use";
49
54
  ```
50
55
 
56
+ See the [JSDocs](./docs.md) for list of available modules and imports.
57
+
58
+ ### JSDocs
59
+
60
+ [View the JSDocs](./docs.md)
61
+
51
62
  ### List
52
63
 
53
64
  #### Instance
package/docs.md ADDED
@@ -0,0 +1,350 @@
1
+ ## Modules
2
+
3
+ | Module | Description |
4
+ | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
5
+ | [utils/assignReactiveObject] | Reactive object assignment utilities |
6
+ | [utils/debugMessage] | Configurable logging of debug messages at runtime. |
7
+ | [utils/flattenPaths] | Get all paths from an array or object. |
8
+ | [utils/keyDiff] | Calculate the difference between objects in terms of what keys are the same, what keys are removed, and what keys are added. |
9
+ | [utils/lifecycleDebug] | Debug lifecycle hooks |
10
+ | [utils/transformWalk] | Object walking utility. |
11
+
12
+ ## utils/assignReactiveObject
13
+
14
+ Reactive object assignment utilities
15
+
16
+ - [utils/assignReactiveObject]
17
+ - [~addReactiveObject(target, source, \[exclude\], \[addedKeys\])]
18
+ - [~updateReactiveObject(target, source, \[exclude\], \[sameKeys\])]
19
+ - [~addOrUpdateReactiveObject(target, source, \[exclude\], \[addedKeys\], \[sameKeys\])]
20
+ - [~trimReactiveObject(target, source, \[exclude\], \[removedKeys\])]
21
+ - [~assignReactiveObject(target, source, \[exclude\])]
22
+ - [~assignReactiveObjectDeep(target, source, \[exclude\])]
23
+ - [~addOrUpdateReactiveObjectDeep(target, source, \[exclude\])]
24
+ - [~ValidTargetOrSource]
25
+
26
+ ### utils/assignReactiveObject~addReactiveObject(target, source, \[exclude\], \[addedKeys\])
27
+
28
+ Adds to a target the missing keys from a source. `addedKeys` can be precalculated to avoid recalculation.
29
+
30
+ **Kind**: inner method of [`utils/assignReactiveObject`]
31
+ **Returns**: `boolean` - True if any keys were added, false otherwise.
32
+ **Throws**:
33
+
34
+ - `AssignReactiveObjectError` If either target or source are not ultimately objects or arrays.
35
+
36
+ | Param | Type | Description |
37
+ | ------------- | --------------------- | ---------------------------------------------------------------------------------------- |
38
+ | target | `ValidTargetOrSource` | The object receiving values. |
39
+ | source | `ValidTargetOrSource` | The object providing values. |
40
+ | \[exclude\] | `Array` | Keys to exclude from the addition. |
41
+ | \[addedKeys\] | `Array` | Precaulcated array of keys to add, if available. Otherwise, the keys will be calculated. |
42
+
43
+ ### utils/assignReactiveObject~updateReactiveObject(target, source, \[exclude\], \[sameKeys\])
44
+
45
+ Updates a target with mutually shared keys from a source. `sameKeys` can be precalculated to avoid recalculation.
46
+
47
+ **Kind**: inner method of [`utils/assignReactiveObject`]
48
+ **Returns**: `boolean` - True if any keys were updated, false otherwise.
49
+ **Throws**:
50
+
51
+ - `AssignReactiveObjectError` If either target or source are not ultimately objects or arrays.
52
+
53
+ | Param | Type | Description |
54
+ | ------------ | --------------------- | ------------------------------------------------------------------------------------------- |
55
+ | target | `ValidTargetOrSource` | The object receiving values. |
56
+ | source | `ValidTargetOrSource` | The object providing values. |
57
+ | \[exclude\] | `Array` | Keys to exclude from the update. |
58
+ | \[sameKeys\] | `Array` | Precaulcated array of keys to update, if available. Otherwise, the keys will be calculated. |
59
+
60
+ ### utils/assignReactiveObject~addOrUpdateReactiveObject(target, source, \[exclude\], \[addedKeys\], \[sameKeys\])
61
+
62
+ Adds to a target the missing keys from a source, and updates a target with mutually shared keys from a source.
63
+
64
+ **Kind**: inner method of [`utils/assignReactiveObject`]
65
+ **Returns**: `boolean` - True if any keys were added or updated, false otherwise.
66
+
67
+ | Param | Type | Description |
68
+ | ------------- | --------------------- | ------------------------------------------------------------------------------------------- |
69
+ | target | `ValidTargetOrSource` | The object receiving values. |
70
+ | source | `ValidTargetOrSource` | The object providing values. |
71
+ | \[exclude\] | `Array` | Keys to exclude from the addition or update. |
72
+ | \[addedKeys\] | `Array` | Precaulcated array of keys to add, if available. Otherwise, the keys will be calculated. |
73
+ | \[sameKeys\] | `Array` | Precaulcated array of keys to update, if available. Otherwise, the keys will be calculated. |
74
+
75
+ ### utils/assignReactiveObject~trimReactiveObject(target, source, \[exclude\], \[removedKeys\])
76
+
77
+ Removes keys from a target that are not present in a source.
78
+
79
+ **Kind**: inner method of [`utils/assignReactiveObject`]
80
+ **Returns**: `boolean` - True if any keys were removed, false otherwise.
81
+ **Throws**:
82
+
83
+ - `AssignReactiveObjectError` If either target or source are not ultimately objects or arrays.
84
+
85
+ | Param | Type | Description |
86
+ | --------------- | ------------------------------- | ------------------------------------------------------------------------------- |
87
+ | target | `ValidTargetOrSource` | The object receiving trimming. |
88
+ | source | `ValidTargetOrSource` \| `null` | The object that provides the allowed set of keys for calculating `removedKeys`. |
89
+ | \[exclude\] | `Array` | Keys to exclude from removal. |
90
+ | \[removedKeys\] | `Array` | An array to store removed keys. |
91
+
92
+ ### utils/assignReactiveObject~assignReactiveObject(target, source, \[exclude\])
93
+
94
+ Change a target to match a source, where keys missing from the source are removed from the target,
95
+ keys present in the source are added to the target, and keys present in both are updated in the target.
96
+
97
+ **Kind**: inner method of [`utils/assignReactiveObject`]
98
+ **Returns**: `boolean` - True if any keys were added, updated, or removed, false otherwise.
99
+ **Throws**:
100
+
101
+ - `AssignReactiveObjectError` If either target or source are not ultimately objects or arrays.
102
+
103
+ | Param | Type | Description |
104
+ | ----------- | --------------------- | ------------------------------------ |
105
+ | target | `ValidTargetOrSource` | The target object or array. |
106
+ | source | `ValidTargetOrSource` | The reactive object to assign. |
107
+ | \[exclude\] | `Array` | Keys to exclude from the assignment. |
108
+
109
+ ### utils/assignReactiveObject~assignReactiveObjectDeep(target, source, \[exclude\])
110
+
111
+ Recursively change a target to match a source, where keys missing from the source are removed from the target,
112
+ keys present in the source are added to the target, and keys present in both are updated in the target.
113
+
114
+ **Kind**: inner method of [`utils/assignReactiveObject`]
115
+ **Returns**: `boolean` - True if any keys were added, updated, or removed, false otherwise.
116
+ **Throws**:
117
+
118
+ - `AssignReactiveObjectError` If either target or source are not ultimately objects or arrays.
119
+
120
+ | Param | Type | Description |
121
+ | ----------- | --------------------- | ------------------------------------ |
122
+ | target | `ValidTargetOrSource` | The object receiving updates. |
123
+ | source | `ValidTargetOrSource` | The object providing updates. |
124
+ | \[exclude\] | `Array` | Keys to exclude from the assignment. |
125
+
126
+ ### utils/assignReactiveObject~addOrUpdateReactiveObjectDeep(target, source, \[exclude\])
127
+
128
+ Recursively change a target to match a source, where keys present in the source are added to the target, and
129
+ keys present in both are updated in the target. Missing keys are not removed.
130
+
131
+ **Kind**: inner method of [`utils/assignReactiveObject`]
132
+ **Returns**: `boolean` - True if any keys were added or updated, false otherwise.
133
+ **Throws**:
134
+
135
+ - `AssignReactiveObjectError` If either target or source are not ultimately objects or arrays.
136
+
137
+ | Param | Type | Description |
138
+ | ----------- | --------------------- | -------------------------------- |
139
+ | target | `ValidTargetOrSource` | The object receiving updates. |
140
+ | source | `ValidTargetOrSource` | The object providing updates. |
141
+ | \[exclude\] | `Array` | Keys to exclude from the update. |
142
+
143
+ ### utils/assignReactiveObject~ValidTargetOrSource
144
+
145
+ targets and sources must be refs, objects, or arrays
146
+ and refs must ultimately resolve to objects or arrays
147
+
148
+ **Kind**: inner typedef of [`utils/assignReactiveObject`]
149
+
150
+ ## utils/debugMessage
151
+
152
+ Configurable logging of debug messages at runtime.
153
+
154
+ - [utils/debugMessage]
155
+ - [~useDebugMessage(categories)]
156
+ - [~DebugMessageFunction]
157
+
158
+ ### utils/debugMessage~useDebugMessage(categories)
159
+
160
+ Returns a function that logs debug messages based on enabled categories.
161
+
162
+ **Kind**: inner method of [`utils/debugMessage`]
163
+ **Returns**: `DebugMessageFunction` - debug message function
164
+
165
+ | Param | Type | Description |
166
+ | ---------- | ---------------- | ------------------------------ |
167
+ | categories | `Array.<string>` | categories for the message log |
168
+
169
+ ### utils/debugMessage~DebugMessageFunction
170
+
171
+ Logs debug messages based on the specified categories and logging rules.
172
+
173
+ **Kind**: inner typedef of [`utils/debugMessage`]
174
+ **Properties**
175
+
176
+ | Name | Type | Description |
177
+ | -------- | ---------- | ------------- |
178
+ | messages | `function` | log a message |
179
+
180
+ ## utils/flattenPaths
181
+
182
+ Get all paths from an array or object.
183
+
184
+ ### utils/flattenPaths~flattenPaths(arrayOrObject, currentPath)
185
+
186
+ Turn an array or object into an array of path strings. Recurses for any found arrays or objects.
187
+
188
+ Array indexes are wrapped in square brackets and object keys are prefixed with a period.
189
+
190
+ **Kind**: inner method of [`utils/flattenPaths`]
191
+ **Returns**: `Array.<string>` - paths
192
+
193
+ | Param | Type | Description |
194
+ | ------------- | ------------------- | -------------------------------------------------- |
195
+ | arrayOrObject | `Array` \| `object` | array or object to flatten |
196
+ | currentPath | `string` | current path, for recursion or as a starting point |
197
+
198
+ ## utils/keyDiff
199
+
200
+ Calculate the difference between objects in terms of what keys
201
+ are the same, what keys are removed, and what keys are added.
202
+
203
+ - [utils/keyDiff]
204
+ - [~keyDiff(newKeys, oldKeys, \[options\])]
205
+ - [~keyDiffDeep(newObj, oldObj, \[options\])]
206
+ - [~KeyDiffOptions]
207
+ - [~KeyDiffResult]
208
+
209
+ ### utils/keyDiff~keyDiff(newKeys, oldKeys, \[options\])
210
+
211
+ Calculate the difference between two arrays of keys, in terms of what keys
212
+ are the same, what keys are removed, and what keys are added.
213
+
214
+ **Kind**: inner method of [`utils/keyDiff`]
215
+ **Returns**: `KeyDiffResult` - - the differences
216
+
217
+ | Param | Type | Description |
218
+ | ----------- | ---------------- | ------------------------------ |
219
+ | newKeys | `Array.<string>` | keys to consider as new |
220
+ | oldKeys | `Array.<string>` | keys to consider as old |
221
+ | \[options\] | `KeyDiffOptions` | which differences are returned |
222
+
223
+ ### utils/keyDiff~keyDiffDeep(newObj, oldObj, \[options\])
224
+
225
+ Calculate the difference between two objects, in terms of what keys are the same,
226
+ what keys are removed, and what keys are added. Keys are sourced deeply in the objects.
227
+
228
+ **Kind**: inner method of [`utils/keyDiff`]
229
+ **Returns**: `KeyDiffResult` - - the differences
230
+
231
+ | Param | Type | Description |
232
+ | ----------- | ---------------- | ------------------------------ |
233
+ | newObj | `object` | the new version of the object |
234
+ | oldObj | `object` | the old version of the object |
235
+ | \[options\] | `KeyDiffOptions` | which differences are returned |
236
+
237
+ ### utils/keyDiff~KeyDiffOptions
238
+
239
+ Options for keyDiff and keyDiffDeep
240
+
241
+ **Kind**: inner typedef of [`utils/keyDiff`]
242
+ **Properties**
243
+
244
+ | Name | Type | Default | Description |
245
+ | --------------- | --------- | ------- | -------------------------------------- |
246
+ | \[sameKeys\] | `boolean` | `true` | if true, return keys that are the same |
247
+ | \[removedKeys\] | `boolean` | `true` | if true, return keys that are removed |
248
+ | \[addedKeys\] | `boolean` | `true` | if true, return keys that are added |
249
+
250
+ ### utils/keyDiff~KeyDiffResult
251
+
252
+ Result object of keyDiff and keyDiffDeep
253
+
254
+ **Kind**: inner typedef of [`utils/keyDiff`]
255
+ **Properties**
256
+
257
+ | Name | Type | Description |
258
+ | --------------- | ---------------- | ----------------------------------------------------------- |
259
+ | \[sameKeys\] | `Array.<string>` | if sameKeys option is true, return keys that are the same |
260
+ | \[removedKeys\] | `Array.<string>` | if removedKeys option is true, return keys that are removed |
261
+ | \[addedKeys\] | `Array.<string>` | if addedKeys option is true, return keys that are added |
262
+
263
+ ## utils/lifecycleDebug
264
+
265
+ Debug lifecycle hooks
266
+
267
+ ### utils/lifecycleDebug~useLifecycleDebug(categories, \[includes\], \[excludes\])
268
+
269
+ Using useDebugMessage, log lifecycle events for the current component, with the specified categories.
270
+
271
+ **Kind**: inner method of [`utils/lifecycleDebug`]
272
+
273
+ | Param | Type | Description |
274
+ | ------------ | ---------------- | ---------------------------------------------- |
275
+ | categories | `Array.<string>` | the categories to give messages this generates |
276
+ | \[includes\] | `Array.<string>` | the lifecycle functions to include |
277
+ | \[excludes\] | `Array.<string>` | the lifecycle functions to exclude |
278
+
279
+ ## utils/transformWalk
280
+
281
+ Object walking utility.
282
+
283
+ ### utils/transformWalk~transformWalk(obj, transformFn, path)
284
+
285
+ Recursively walks through an object's values and applies a transformation function to each value.
286
+ The value recursed into is the transformed value, not the original value.
287
+
288
+ **Kind**: inner method of [`utils/transformWalk`]
289
+ **Returns**: `*` - The transformed initial value.
290
+
291
+ | Param | Type | Description |
292
+ | ----------- | ---------- | ------------------------------------- |
293
+ | obj | `*` | The object to start walking from. |
294
+ | transformFn | `function` | The function to transform each value. |
295
+ | path | `string` | The path to the current value. |
296
+
297
+ **Example**
298
+
299
+ ```js
300
+ const obj = {
301
+ a: 1,
302
+ b: {
303
+ c: 2,
304
+ d: [3, 4, { e: 5 }],
305
+ },
306
+ };
307
+
308
+ const transformed = transformWalk(obj, (key, value, path) => {
309
+ if (key === "e") {
310
+ return value * 2;
311
+ }
312
+ return value;
313
+ });
314
+ // transformed = {
315
+ // a: 1,
316
+ // b: {
317
+ // c: 2,
318
+ // d: [3, 4, { e: 10 }]
319
+ // }
320
+ // }
321
+ ```
322
+
323
+ <!-- LINKS -->
324
+
325
+ [utils/assignreactiveobject]: #utilsassignreactiveobject
326
+ [utils/debugmessage]: #utilsdebugmessage
327
+ [utils/flattenpaths]: #utilsflattenpaths
328
+ [utils/keydiff]: #utilskeydiff
329
+ [utils/lifecycledebug]: #utilslifecycledebug
330
+ [utils/transformwalk]: #utilstransformwalk
331
+ [~validtargetorsource]: #utilsassignreactiveobjectvalidtargetorsource
332
+ [`utils/assignreactiveobject`]: #utilsassignreactiveobject
333
+ [~debugmessagefunction]: #utilsdebugmessagedebugmessagefunction
334
+ [`utils/debugmessage`]: #utilsdebugmessage
335
+ [`utils/flattenpaths`]: #utilsflattenpaths
336
+ [~keydiffoptions]: #utilskeydiffkeydiffoptions
337
+ [~keydiffresult]: #utilskeydiffkeydiffresult
338
+ [`utils/keydiff`]: #utilskeydiff
339
+ [`utils/lifecycledebug`]: #utilslifecycledebug
340
+ [`utils/transformwalk`]: #utilstransformwalk
341
+ [~addreactiveobject(target, source, \[exclude\], \[addedkeys\])]: #utilsassignreactiveobjectaddreactiveobjecttarget-source-exclude-addedkeys
342
+ [~updatereactiveobject(target, source, \[exclude\], \[samekeys\])]: #utilsassignreactiveobjectupdatereactiveobjecttarget-source-exclude-samekeys
343
+ [~addorupdatereactiveobject(target, source, \[exclude\], \[addedkeys\], \[samekeys\])]: #utilsassignreactiveobjectaddorupdatereactiveobjecttarget-source-exclude-addedkeys-samekeys
344
+ [~trimreactiveobject(target, source, \[exclude\], \[removedkeys\])]: #utilsassignreactiveobjecttrimreactiveobjecttarget-source-exclude-removedkeys
345
+ [~assignreactiveobject(target, source, \[exclude\])]: #utilsassignreactiveobjectassignreactiveobjecttarget-source-exclude
346
+ [~assignreactiveobjectdeep(target, source, \[exclude\])]: #utilsassignreactiveobjectassignreactiveobjectdeeptarget-source-exclude
347
+ [~addorupdatereactiveobjectdeep(target, source, \[exclude\])]: #utilsassignreactiveobjectaddorupdatereactiveobjectdeeptarget-source-exclude
348
+ [~usedebugmessage(categories)]: #utilsdebugmessageusedebugmessagecategories
349
+ [~keydiff(newkeys, oldkeys, \[options\])]: #utilskeydiffkeydiffnewkeys-oldkeys-options
350
+ [~keydiffdeep(newobj, oldobj, \[options\])]: #utilskeydiffkeydiffdeepnewobj-oldobj-options
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+ set -e
3
+ npx --no-install jsdoc-to-markdown > ./docs.new.md
4
+ npx --no-install prettier --write docs.new.md > /dev/null
5
+ set +e
6
+ diff ./docs.new.md ./docs.md > /dev/null
7
+ diffCode=$?
8
+ # we want to return a non-zero exit code if the files are different, to stop the commit
9
+ if [ $diffCode != 0 ]; then
10
+ echo "docs.md is out of date, see git diff for details"
11
+ mv ./docs.new.md ./docs.md
12
+ exit $diffCode
13
+ fi
14
+ set -e
15
+ rm ./docs.new.md
@@ -0,0 +1,10 @@
1
+ export default {
2
+ "**/*.{js,cjs,mjs,ts,jsx,tsx}": [
3
+ "npx --no-install eslint --fix",
4
+ "npx --no-install prettier --write",
5
+ () => "npm run docs",
6
+ ],
7
+ "**/*.{markdown,md}": ["npx --no-install doctoc --github -u ."],
8
+ "**/*.{less,scss,css,vue,markdown,json,md,yml,yaml,html}": ["npx --no-install prettier --write"],
9
+ ".circleci/config.yml": ["circleci config validate"],
10
+ };
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@arrai-innovations/reactive-helpers",
3
- "version": "8.0.1",
3
+ "version": "8.0.4",
4
4
  "description": "VueJS 3 utility composition functions to help manipulate objects and lists.",
5
5
  "main": "index.js",
6
+ "type": "module",
6
7
  "directories": {
7
8
  "use": "use",
8
9
  "utils": "utils",
@@ -12,7 +13,8 @@
12
13
  "test": "jest",
13
14
  "coverage": "npm run coverage:clean; npm test -- --coverage=true",
14
15
  "coverage:clean": "rm -rf coverage",
15
- "prepare": "husky install"
16
+ "prepare": "husky install",
17
+ "docs": "./jsdoc-to-markdown.sh"
16
18
  },
17
19
  "repository": {
18
20
  "type": "git",
@@ -28,6 +30,7 @@
28
30
  "@arrai-innovations/commitlint-config": "^1.1.0",
29
31
  "@babel/preset-env": "^7.17.10",
30
32
  "@commitlint/cli": "^16.2.4",
33
+ "@godaddy/dmd": "^1.0.4",
31
34
  "@trivago/prettier-plugin-sort-imports": "^4.1.1",
32
35
  "@types/jest": "^27.5.0",
33
36
  "@vue/compiler-sfc": "^3.3.4",
@@ -39,9 +42,11 @@
39
42
  "doctoc": "^2.1.0",
40
43
  "eslint": "^7.32.0",
41
44
  "eslint-plugin-jest": "^26.1.5",
45
+ "eslint-plugin-jsdoc": "^46.2.6",
42
46
  "eslint-plugin-vue": "^8.7.1",
43
47
  "flush-promises": "^1.0.2",
44
- "lint-staged": "^11.1.2",
48
+ "jsdoc-to-markdown": "^8.0.0",
49
+ "lint-staged": "^13.2.2",
45
50
  "prettier": "2.6.2"
46
51
  },
47
52
  "dependencies": {
@@ -1,6 +1,7 @@
1
+ import { isEmpty } from "lodash-es";
1
2
  import identity from "lodash-es/identity";
2
3
  import isEqual from "lodash-es/isEqual";
3
- import { effectScope, nextTick, onScopeDispose, reactive, readonly, watch } from "vue";
4
+ import { computed, effectScope, nextTick, onScopeDispose, reactive, readonly, watch } from "vue";
4
5
  import { deepUnref } from "vue-deepunref";
5
6
 
6
7
  /*
@@ -8,7 +9,12 @@ import { deepUnref } from "vue-deepunref";
8
9
  * Watch arguments should be a reactive object.
9
10
  * If the promise is not resolved before the watch arguments change again, the previous promise is cancelled.
10
11
  */
11
- export function useCancellableIntent({ awaitableWithCancel, watchArguments = {}, clearActiveOnResolved = true }) {
12
+ export function useCancellableIntent({
13
+ awaitableWithCancel,
14
+ watchArguments = {},
15
+ guardArguments = {},
16
+ clearActiveOnResolved = true,
17
+ }) {
12
18
  if (!awaitableWithCancel) {
13
19
  throw new Error("awaitableWithCancel is required");
14
20
  }
@@ -16,7 +22,9 @@ export function useCancellableIntent({ awaitableWithCancel, watchArguments = {},
16
22
  throw new Error("awaitableWithCancel must be a function");
17
23
  }
18
24
  const state = reactive({
25
+ activeCount: undefined, // the active count doesn't mean much when not using clearActiveOnResolved
19
26
  active: undefined,
27
+ resolvingCount: undefined,
20
28
  resolving: undefined,
21
29
  errored: false,
22
30
  error: null,
@@ -34,8 +42,6 @@ export function useCancellableIntent({ awaitableWithCancel, watchArguments = {},
34
42
 
35
43
  async function cancel() {
36
44
  if (cancelFunction) {
37
- state.active = false;
38
- state.resolving = false;
39
45
  const cancelPromise = cancelFunction().catch(console.error);
40
46
  cancelFunction = null;
41
47
  return cancelPromise;
@@ -43,52 +49,95 @@ export function useCancellableIntent({ awaitableWithCancel, watchArguments = {},
43
49
  return false;
44
50
  }
45
51
 
46
- const watchFn = () => {
52
+ const doIntentWatch = async () => {
53
+ state.errored = false;
54
+ state.error = null;
55
+ if (state.activeCount === undefined) {
56
+ state.activeCount = 0;
57
+ }
58
+ state.activeCount += 1;
59
+ if (state.resolvingCount === undefined) {
60
+ state.resolvingCount = 0;
61
+ }
62
+ state.resolvingCount += 1;
63
+ let awaitablePromise = awaitableWithCancel();
64
+
65
+ if (awaitablePromise.cancel) {
66
+ cancelFunction = awaitablePromise.cancel;
67
+ }
68
+ // we don't want to await this, because we want to be able to cancel it
69
+ awaitablePromise
70
+ .catch(async (err) => {
71
+ await cancel();
72
+ console.error(err);
73
+ state.errored = true;
74
+ state.error = err;
75
+ throw err;
76
+ })
77
+ .finally(() => {
78
+ state.resolvingCount--;
79
+ if (state.clearActiveOnResolved) {
80
+ cancelFunction = null;
81
+ state.activeCount--;
82
+ }
83
+ });
84
+ };
85
+
86
+ let delayedWatch = null;
87
+
88
+ const intentWatch = async () => {
47
89
  let newWatchValues = deepUnref(Object.values(watchArguments));
48
90
  if (isEqual(newWatchValues, previousWatchValues)) {
49
91
  return;
50
92
  }
51
93
  previousWatchValues = newWatchValues;
52
- cancel().catch(console.error);
94
+ await cancel();
53
95
  if (Object.values(previousWatchValues).every(identity)) {
54
- state.errored = false;
55
- state.error = null;
56
- let awaitablePromise = awaitableWithCancel();
57
- state.active = true;
58
- state.resolving = true;
59
- if (awaitablePromise.cancel) {
60
- cancelFunction = async () => {
61
- state.active = false;
62
- state.resolving = false;
63
- cancelFunction = null;
64
- return awaitablePromise.cancel();
65
- };
96
+ // if any guards are true, delay the watch.
97
+ if (guardArguments && !isEmpty(guardArguments) && Object.values(guardArguments).some(identity)) {
98
+ delayedWatch = doIntentWatch;
99
+ return;
100
+ }
101
+ doIntentWatch();
102
+ }
103
+ };
104
+
105
+ const guardWatch = async () => {
106
+ if (delayedWatch) {
107
+ // if all guards are false, run the watch
108
+ if (Object.values(guardArguments).every((x) => !x)) {
109
+ const myDelayedWatch = delayedWatch;
110
+ delayedWatch = null;
111
+ await myDelayedWatch();
66
112
  }
67
- awaitablePromise
68
- .then(() => {
69
- state.resolving = false;
70
- if (state.clearActiveOnResolved) {
71
- cancelFunction = null;
72
- state.active = false;
73
- }
74
- })
75
- .catch(async (err) => {
76
- await cancel();
77
- console.error(err);
78
- state.errored = true;
79
- state.error = err;
80
- throw err;
81
- });
82
113
  }
83
114
  };
84
115
 
85
116
  es.run(() => {
86
- watch(() => Object.values(watchArguments), watchFn, {
117
+ state.active = computed(() => {
118
+ if (state.activeCount === undefined) {
119
+ return undefined;
120
+ }
121
+ return state.activeCount > 0;
122
+ });
123
+ state.resolving = computed(() => {
124
+ if (state.resolvingCount === undefined) {
125
+ return undefined;
126
+ }
127
+ return state.resolvingCount > 0;
128
+ });
129
+
130
+ watch(() => Object.values(watchArguments), intentWatch, {
87
131
  // this can't be immediate because subscribe wants to look at our state, which won't exist yet.
88
132
  deep: true,
89
133
  });
90
134
 
91
- nextTick().then(watchFn);
135
+ watch(() => Object.values(guardArguments), guardWatch, {
136
+ // we can't possibly have a delayed watch immediately
137
+ deep: true,
138
+ });
139
+
140
+ nextTick().then(intentWatch);
92
141
 
93
142
  onScopeDispose(cancel);
94
143
  });
@@ -114,6 +114,7 @@ export function useListInstance({ props, functions = {} }) {
114
114
  });
115
115
 
116
116
  const defaultPageCallback = (newObjects) => {
117
+ clearList();
117
118
  newObjects.forEach((newObject) => {
118
119
  if (newObject.id in state.objects) {
119
120
  updateListObject(newObject);
@@ -139,11 +140,10 @@ export function useListInstance({ props, functions = {} }) {
139
140
  listArgs: state.listArgs,
140
141
  pageCallback: returnedObject.pageCallback,
141
142
  });
143
+ let resolveState = false;
142
144
  if (listPromise.cancel) {
143
145
  returnPromise.cancel = async () => {
144
146
  let promise = listPromise.cancel();
145
- state.loading = false;
146
- returnPromiseResolve(false);
147
147
  if (promise) {
148
148
  await promise;
149
149
  }
@@ -152,14 +152,15 @@ export function useListInstance({ props, functions = {} }) {
152
152
  // the indirection of promises here is to allow us to do additional work on listPromise's cancel
153
153
  listPromise
154
154
  .then(() => {
155
- state.loading = false;
156
- returnPromiseResolve(true);
155
+ resolveState = true;
157
156
  })
158
157
  .catch((error) => {
159
- state.loading = false;
160
158
  state.errored = true;
161
159
  state.error = error;
162
- returnPromiseResolve(false);
160
+ })
161
+ .finally(() => {
162
+ state.loading = false;
163
+ returnPromiseResolve(resolveState);
163
164
  });
164
165
  return returnPromise;
165
166
  }
@@ -196,15 +196,17 @@ export function useListSubscription({ listInstance, props, functions }) {
196
196
  state.subscribed = toRef(subscribeIntent.state, "active");
197
197
 
198
198
  listIntent = useCancellableIntent({
199
- awaitableWithCancel: () => {
200
- listInstance.clearList();
201
- return listInstance.list();
202
- },
199
+ awaitableWithCancel: listInstance.list,
203
200
  watchArguments: reactive({
204
201
  intendToList: toRef(state, "intendToList"),
205
202
  listArgs: toRef(parentState, "listArgs"),
206
203
  retrieveArgs: toRef(parentState, "retrieveArgs"),
207
204
  }),
205
+ // delay triggering a list until the last list has finished/cancelled
206
+ // cancel can still be triggered
207
+ guardArguments: reactive({
208
+ loading: toRef(parentState, "loading"),
209
+ }),
208
210
  });
209
211
  });
210
212
 
@@ -7,14 +7,27 @@ export function usePagedListInstance({ keepOldPages = false, ...useListInstanceA
7
7
  listInstance.state.totalPages = 0;
8
8
  listInstance.state.perPage = 0;
9
9
 
10
+ const superClearList = listInstance.clearList;
11
+ listInstance.clearList = () => {
12
+ superClearList();
13
+ listInstance.state.totalRecords = 0;
14
+ listInstance.state.totalPages = 0;
15
+ listInstance.state.perPage = 0;
16
+ };
17
+
10
18
  listInstance.pageCallback = (newObjects, { totalRecords, totalPages, perPage }) => {
11
19
  // with keepOldPages, you are responsible for clearing the list as needed
12
20
  if (!keepOldPages) {
13
21
  // display one page at a time, clear the list
14
22
  listInstance.clearList();
15
23
  }
16
-
17
- listInstance.defaultPageCallback(newObjects);
24
+ newObjects.forEach((newObject) => {
25
+ if (newObject.id in listInstance.state.objects) {
26
+ listInstance.updateListObject(newObject);
27
+ } else {
28
+ listInstance.addListObject(newObject);
29
+ }
30
+ });
18
31
  if (totalRecords !== undefined) {
19
32
  listInstance.state.totalRecords = totalRecords;
20
33
  }
@@ -4,6 +4,11 @@ import isArray from "lodash-es/isArray";
4
4
  import isObject from "lodash-es/isObject";
5
5
  import { isReactive, isRef, toRef, unref } from "vue";
6
6
 
7
+ /**
8
+ * Reactive object assignment utilities
9
+ * @module utils/assignReactiveObject
10
+ */
11
+
7
12
  export class AssignReactiveObjectError extends Error {
8
13
  constructor(message) {
9
14
  super(message);
@@ -12,13 +17,18 @@ export class AssignReactiveObjectError extends Error {
12
17
  }
13
18
 
14
19
  /**
15
- * @typedef {Ref|object|array} ValidTargetOrSource targets and sources must be refs, objects, or arrays
20
+ * @typedef {*} Ref A Vue ref
21
+ * @private
22
+ */
23
+
24
+ /**
25
+ * @typedef {Ref|object|Array} ValidTargetOrSource targets and sources must be refs, objects, or arrays
16
26
  * and refs must ultimately resolve to objects or arrays
17
27
  */
18
28
 
19
29
  /**
20
30
  * Validates that a value is an array or an object, and throws an error if it is not.
21
- *
31
+ * @private
22
32
  * @param {string} key The key being validated.
23
33
  * @param {*} value The value being validated.
24
34
  * @throws {AssignReactiveObjectError} If the value is not an array or an object.
@@ -31,6 +41,7 @@ function isArrayOrObject(key, value) {
31
41
 
32
42
  /**
33
43
  * @typedef validateTargetAndSourceResult
44
+ * @private
34
45
  * @property {ValidTargetOrSource} target The validated target value.
35
46
  * @property {ValidTargetOrSource} source The validated source value.
36
47
  */
@@ -38,7 +49,7 @@ function isArrayOrObject(key, value) {
38
49
  /**
39
50
  * Validates that the target and source values are arrays or objects, and returns them.
40
51
  * If either value is a ref, it is dereferenced before validation.
41
- *
52
+ * @private
42
53
  * @param {ValidTargetOrSource} target The target value to validate.
43
54
  * @param {ValidTargetOrSource} source The source value to validate.
44
55
  * @returns {validateTargetAndSourceResult} An object containing the validated target and source values.
@@ -63,11 +74,11 @@ function validateTargetAndSource(target, source) {
63
74
  /**
64
75
  * Replaces keys in a target object or array with reactive refs to the corresponding keys in a
65
76
  * source object or array.
66
- *
77
+ * @private
67
78
  * @param {ValidTargetOrSource} target The object receiving values.
68
79
  * @param {ValidTargetOrSource} source The object providing values.
69
- * @param {array} keys The keys to replace.
70
- * @param {array} {exclude} Keys to exclude from replacement.
80
+ * @param {Array} keys The keys to replace.
81
+ * @param {Array} [exclude] Keys to exclude from replacement.
71
82
  * @returns {boolean} True if any keys were replaced, false otherwise.
72
83
  * @throws {AssignReactiveObjectError} If either target or source are not ultimately objects or arrays.
73
84
  */
@@ -91,11 +102,11 @@ function reactiveReplaceKeys(target, source, keys, exclude = []) {
91
102
 
92
103
  /**
93
104
  * Adds to a target the missing keys from a source. `addedKeys` can be precalculated to avoid recalculation.
94
- *
105
+ * @function addReactiveObject
95
106
  * @param {ValidTargetOrSource} target The object receiving values.
96
107
  * @param {ValidTargetOrSource} source The object providing values.
97
- * @param {array} {exclude} Keys to exclude from the addition.
98
- * @param {array} {addedKeys} Precaulcated array of keys to add, if available. Otherwise, the
108
+ * @param {Array} [exclude] Keys to exclude from the addition.
109
+ * @param {Array} [addedKeys] Precaulcated array of keys to add, if available. Otherwise, the
99
110
  * keys will be calculated.
100
111
  * @returns {boolean} True if any keys were added, false otherwise.
101
112
  * @throws {AssignReactiveObjectError} If either target or source are not ultimately objects or arrays.
@@ -113,11 +124,11 @@ export function addReactiveObject(target, source, exclude = [], addedKeys = null
113
124
 
114
125
  /**
115
126
  * Updates a target with mutually shared keys from a source. `sameKeys` can be precalculated to avoid recalculation.
116
- *
127
+ * @function updateReactiveObject
117
128
  * @param {ValidTargetOrSource} target The object receiving values.
118
129
  * @param {ValidTargetOrSource} source The object providing values.
119
- * @param {array} {exclude} Keys to exclude from the update.
120
- * @param {array} {sameKeys} Precaulcated array of keys to update, if available. Otherwise, the
130
+ * @param {Array} [exclude] Keys to exclude from the update.
131
+ * @param {Array} [sameKeys] Precaulcated array of keys to update, if available. Otherwise, the
121
132
  * keys will be calculated.
122
133
  * @returns {boolean} True if any keys were updated, false otherwise.
123
134
  * @throws {AssignReactiveObjectError} If either target or source are not ultimately objects or arrays.
@@ -135,19 +146,20 @@ export function updateReactiveObject(target, source, exclude = [], sameKeys = nu
135
146
 
136
147
  /**
137
148
  * Adds to a target the missing keys from a source, and updates a target with mutually shared keys from a source.
138
- *
149
+ * @function addOrUpdateReactiveObject
139
150
  * @param {ValidTargetOrSource} target The object receiving values.
140
151
  * @param {ValidTargetOrSource} source The object providing values.
141
- * @param {array} {exclude} Keys to exclude from the addition or update.
142
- * @param {array} {addedKeys} Precaulcated array of keys to add, if available. Otherwise, the
152
+ * @param {Array} [exclude] Keys to exclude from the addition or update.
153
+ * @param {Array} [addedKeys] Precaulcated array of keys to add, if available. Otherwise, the
143
154
  * keys will be calculated.
144
- * @param {array} {sameKeys} Precaulcated array of keys to update, if available. Otherwise, the
155
+ * @param {Array} [sameKeys] Precaulcated array of keys to update, if available. Otherwise, the
145
156
  * keys will be calculated.
157
+ * @returns {boolean} True if any keys were added or updated, false otherwise.
146
158
  */
147
159
  export function addOrUpdateReactiveObject(target, source, exclude = [], addedKeys = null, sameKeys = null) {
148
160
  if (!addedKeys && !sameKeys) {
149
161
  if (target === source) {
150
- return;
162
+ return false;
151
163
  }
152
164
  ({ target, source } = validateTargetAndSource(target, source));
153
165
  ({ addedKeys, sameKeys } = keyDiff(Object.keys(source) || [], Object.keys(target) || []));
@@ -160,11 +172,11 @@ export function addOrUpdateReactiveObject(target, source, exclude = [], addedKey
160
172
 
161
173
  /**
162
174
  * Removes keys from a target that are not present in a source.
163
- *
175
+ * @function trimReactiveObject
164
176
  * @param {ValidTargetOrSource} target The object receiving trimming.
165
177
  * @param {ValidTargetOrSource|null} source The object that provides the allowed set of keys for calculating `removedKeys`.
166
- * @param {array} {exclude} Keys to exclude from removal.
167
- * @param {array} {removedKeys} An array to store removed keys.
178
+ * @param {Array} [exclude] Keys to exclude from removal.
179
+ * @param {Array} [removedKeys] An array to store removed keys.
168
180
  * @returns {boolean} True if any keys were removed, false otherwise.
169
181
  * @throws {AssignReactiveObjectError} If either target or source are not ultimately objects or arrays.
170
182
  */
@@ -200,15 +212,16 @@ export function trimReactiveObject(target, source, exclude = [], removedKeys = n
200
212
  /**
201
213
  * Change a target to match a source, where keys missing from the source are removed from the target,
202
214
  * keys present in the source are added to the target, and keys present in both are updated in the target.
203
- *
215
+ * @function assignReactiveObject
204
216
  * @param {ValidTargetOrSource} target The target object or array.
205
217
  * @param {ValidTargetOrSource} source The reactive object to assign.
206
- * @param {array} {exclude} Keys to exclude from the assignment.
218
+ * @param {Array} [exclude] Keys to exclude from the assignment.
207
219
  * @throws {AssignReactiveObjectError} If either target or source are not ultimately objects or arrays.
220
+ * @returns {boolean} True if any keys were added, updated, or removed, false otherwise.
208
221
  */
209
222
  export function assignReactiveObject(target, source, exclude = []) {
210
223
  if (target === source) {
211
- return;
224
+ return false;
212
225
  }
213
226
  ({ target, source } = validateTargetAndSource(target, source));
214
227
  const { addedKeys, sameKeys, removedKeys } = keyDiff(Object.keys(source) || [], Object.keys(target) || []);
@@ -223,16 +236,17 @@ export function assignReactiveObject(target, source, exclude = []) {
223
236
  * keys present in the source are added to the target, and keys present in both are updated in the target.
224
237
  *
225
238
  * As an internal function, this function does not validate its arguments and has no optional arguments.
226
- *
239
+ * @private
227
240
  * @param {ValidTargetOrSource} target The object receiving updates.
228
241
  * @param {ValidTargetOrSource} source The object providing updates.
229
- * @param {array} exclude Keys to exclude from the update.
230
- * @param {array} addedKeys Precaulcated array of keys to add, if available. Otherwise, the
242
+ * @param {Array} exclude Keys to exclude from the update.
243
+ * @param {Array} addedKeys Precaulcated array of keys to add, if available. Otherwise, the
231
244
  * keys will be calculated.
232
- * @param {array} sameKeys Precaulcated array of keys to update, if available. Otherwise, the
245
+ * @param {Array} sameKeys Precaulcated array of keys to update, if available. Otherwise, the
233
246
  * keys will be calculated.
234
247
  * @param {string} path The current path, used to rescope exclude for the next level.
235
- * @param {function} fn The recursive function to call, likely the calling function itself.
248
+ * @param {Function} fn The recursive function to call, likely the calling function itself.
249
+ * @returns {boolean} True if any keys were added, updated, or removed, false otherwise.
236
250
  */
237
251
  function recursiveInner(target, source, exclude, addedKeys, sameKeys, path, fn) {
238
252
  let didAnything = false;
@@ -265,11 +279,11 @@ function recursiveInner(target, source, exclude, addedKeys, sameKeys, path, fn)
265
279
  * keys present in the source are added to the target, and keys present in both are updated in the target.
266
280
  *
267
281
  * An internal function to avoid validating arguments repeatedly.
268
- *
282
+ * @private
269
283
  * @param {ValidTargetOrSource} target The object receiving updates.
270
284
  * @param {ValidTargetOrSource} source The object providing updates.
271
- * @param {array} {exclude} Keys to exclude from the assignment.
272
- * @param {string} {path} The current path, used to rescope exclude for the next level.
285
+ * @param {Array} [exclude] Keys to exclude from the assignment.
286
+ * @param {string} [path] The current path, used to rescope exclude for the next level.
273
287
  * @returns {boolean} True if any keys were added, updated, or removed, false otherwise.
274
288
  * @throws {AssignReactiveObjectError} If either target or source are not ultimately objects or arrays.
275
289
  */
@@ -284,17 +298,17 @@ function assignReactiveObjectRecursive(target, source, exclude = [], path = "")
284
298
  /**
285
299
  * Recursively change a target to match a source, where keys missing from the source are removed from the target,
286
300
  * keys present in the source are added to the target, and keys present in both are updated in the target.
287
- *
301
+ * @function assignReactiveObjectDeep
288
302
  * @param {ValidTargetOrSource} target The object receiving updates.
289
303
  * @param {ValidTargetOrSource} source The object providing updates.
290
- * @param {array} {exclude} Keys to exclude from the assignment.
304
+ * @param {Array} [exclude] Keys to exclude from the assignment.
291
305
  * @returns {boolean} True if any keys were added, updated, or removed, false otherwise.
292
306
  * @throws {AssignReactiveObjectError} If either target or source are not ultimately objects or arrays.
293
307
  */
294
308
  export function assignReactiveObjectDeep(target, source, exclude = []) {
295
309
  // exclude keys will need to be lodash get strings
296
310
  if (target === source) {
297
- return;
311
+ return false;
298
312
  }
299
313
  ({ target, source } = validateTargetAndSource(target, source));
300
314
  return assignReactiveObjectRecursive(target, source, exclude);
@@ -305,11 +319,12 @@ export function assignReactiveObjectDeep(target, source, exclude = []) {
305
319
  * keys present in both are updated in the target. Missing keys are not removed.
306
320
  *
307
321
  * As an internal function, this function does not validate its argument.
308
- *
322
+ * @private
309
323
  * @param {ValidTargetOrSource} target The object receiving updates.
310
324
  * @param {ValidTargetOrSource} source The object providing updates.
311
- * @param {array} [exclude] Keys to exclude from the update.
325
+ * @param {Array} [exclude] Keys to exclude from the update.
312
326
  * @param {string} [path] The current path, used to rescope exclude for the next level.
327
+ * @returns {boolean} True if any keys were added or updated, false otherwise.
313
328
  */
314
329
  function addOrUpdateReactiveObjectRecursive(target, source, exclude = [], path = "") {
315
330
  let addedKeys,
@@ -320,18 +335,18 @@ function addOrUpdateReactiveObjectRecursive(target, source, exclude = [], path =
320
335
  /**
321
336
  * Recursively change a target to match a source, where keys present in the source are added to the target, and
322
337
  * keys present in both are updated in the target. Missing keys are not removed.
323
- *
338
+ * @function addOrUpdateReactiveObjectDeep
324
339
  * @param {ValidTargetOrSource} target The object receiving updates.
325
340
  * @param {ValidTargetOrSource} source The object providing updates.
326
- * @param {array} [exclude] Keys to exclude from the update.
341
+ * @param {Array} [exclude] Keys to exclude from the update.
327
342
  * @returns {boolean} True if any keys were added or updated, false otherwise.
328
343
  * @throws {AssignReactiveObjectError} If either target or source are not ultimately objects or arrays.
329
344
  */
330
345
  export function addOrUpdateReactiveObjectDeep(target, source, exclude = []) {
331
346
  // exclude keys will need to be lodash get strings
332
347
  if (target === source) {
333
- return;
348
+ return false;
334
349
  }
335
350
  ({ target, source } = validateTargetAndSource(target, source));
336
- addOrUpdateReactiveObjectRecursive(target, source, exclude);
351
+ return addOrUpdateReactiveObjectRecursive(target, source, exclude);
337
352
  }
@@ -4,10 +4,14 @@ import { isSet, partial, union } from "lodash-es";
4
4
  import debounce from "lodash-es/debounce";
5
5
  import { unref } from "vue";
6
6
 
7
+ /**
8
+ * Configurable logging of debug messages at runtime.
9
+ * @module utils/debugMessage
10
+ */
11
+
7
12
  /**
8
13
  * Whether debug messages are enabled or not. For deploying to production with debugging but not
9
14
  * spamming everyone with debug messages.
10
- *
11
15
  * @type {boolean}
12
16
  */
13
17
  window.RH_DEBUG = false;
@@ -20,7 +24,6 @@ window.RH_DEBUG = false;
20
24
  * The special category "*" will match all messages.
21
25
  * Strings passed as keys will be treated as a single category.
22
26
  * Sets can also be passed as keys, which is what the arrays get converted to.
23
- *
24
27
  * @type {Map<string[]|string|Set, boolean>}
25
28
  * @example
26
29
  * window.RH_DEBUG = true; // turn it on
@@ -34,7 +37,6 @@ window.RH_DEBUG_CATEGORIES = new Map();
34
37
  /**
35
38
  * Group identical messages together and show a count of how many times they were logged.
36
39
  * Messages are only shown on the trailing edge, so logging is delayed and somewhat out of order.
37
- *
38
40
  * @type {boolean}
39
41
  */
40
42
  window.RH_DEBOUNCE_DEBUG = false;
@@ -42,7 +44,6 @@ window.RH_DEBOUNCE_DEBUG = false;
42
44
  /**
43
45
  * Whether to process arguments to be more friendly for console.log, with regard to circular references
44
46
  * and not recursing into vue components.
45
- *
46
47
  * @type {boolean}
47
48
  */
48
49
  window.RH_TRANSFORM_MESSAGES = true;
@@ -53,9 +54,10 @@ const messageBounceFns = {};
53
54
  const counts = {};
54
55
 
55
56
  /**
57
+ * @private
56
58
  * @param {Set} categoriesSet categories for the message log
57
59
  * @param {string} categoriesKey key for debouncing
58
- * @param {*[]} messages
60
+ * @param {Array.<*>} messages messages to log
59
61
  */
60
62
  const doLog = (categoriesSet, categoriesKey, messages) => {
61
63
  if (messages.length > 0) {
@@ -74,7 +76,8 @@ const doLog = (categoriesSet, categoriesKey, messages) => {
74
76
  /**
75
77
  * Process a value for logging, dealing with circular references and
76
78
  * not recursing into vue components.
77
- *
79
+ * @private
80
+ * @function inspectWalkFn
78
81
  * @param {Map} seenObjects for circlular reference detection
79
82
  * @param {string} key keys is an unused argument from walk
80
83
  * @param {*} value value to process
@@ -98,8 +101,9 @@ export const inspectWalkFn = (seenObjects, key, value, path) => {
98
101
  };
99
102
 
100
103
  /**
101
- * @param {(string|function)[]} messages messages to resolve
102
- * @returns {*[]} resolved messages
104
+ * @private
105
+ * @param {Array.<string | Function>} messages messages to resolve
106
+ * @returns {Array.<*>} resolved messages
103
107
  */
104
108
  const resolveMessages = (messages) => {
105
109
  const resolvedMessages = [];
@@ -115,9 +119,11 @@ const resolveMessages = (messages) => {
115
119
  };
116
120
 
117
121
  /**
122
+ * @private
118
123
  * @param {Set} categoriesSet categories for the message log
119
124
  * @param {string} categoriesKey key for debouncing
120
- * @param {*[]} messages messages to log
125
+ * @param {Array.<*>} messages messages to log
126
+ * @returns {void}
121
127
  */
122
128
  const doDebouncedLog = (categoriesSet, categoriesKey, messages) => {
123
129
  if (!window.RH_DEBOUNCE_DEBUG) {
@@ -134,18 +140,22 @@ const doDebouncedLog = (categoriesSet, categoriesKey, messages) => {
134
140
  };
135
141
 
136
142
  /**
143
+ * @private
137
144
  * @param {string} categoriesKey categories for the message log
138
- * @param {(string|function)[]} messages messages to log
145
+ * @param {Array.<string | Function>} messages messages to log
139
146
  * @returns {string} key
140
- **/
147
+ */
141
148
  const getKey = (categoriesKey, messages) => `${categoriesKey}|${messages.join("-")}`;
142
149
 
143
150
  /**
144
- * @typedef {Object} DebugMessageFunction
145
- * @property {function(...((string|function)[]|string|function)): void} log log a message
151
+ * Logs debug messages based on the specified categories and logging rules.
152
+ * @typedef {object} DebugMessageFunction
153
+ * @property {function(...(Array.<string | Function> | string | Function)): void} messages log a message
146
154
  */
147
155
 
148
156
  /**
157
+ * Returns a function that logs debug messages based on enabled categories.
158
+ * @function useDebugMessage
149
159
  * @param {string[]} categories categories for the message log
150
160
  * @returns {DebugMessageFunction} debug message function
151
161
  */
@@ -1,12 +1,17 @@
1
1
  import isArray from "lodash-es/isArray";
2
2
  import isObject from "lodash-es/isObject";
3
3
 
4
+ /**
5
+ * Get all paths from an array or object.
6
+ * @module utils/flattenPaths
7
+ */
8
+
4
9
  /**
5
10
  * Turn an array or object into an array of path strings. Recurses for any found arrays or objects.
6
11
  *
7
12
  * Array indexes are wrapped in square brackets and object keys are prefixed with a period.
8
- *
9
- * @param {Array|Object} arrayOrObject array or object to flatten
13
+ * @function flattenPaths
14
+ * @param {Array | object} arrayOrObject array or object to flatten
10
15
  * @param {string} currentPath current path, for recursion or as a starting point
11
16
  * @returns {string[]} paths
12
17
  */
package/utils/keyDiff.js CHANGED
@@ -2,27 +2,35 @@ import { flattenPaths } from "./flattenPaths.js";
2
2
  import { difference, intersection } from "./set.js";
3
3
 
4
4
  /**
5
+ * Calculate the difference between objects in terms of what keys
6
+ * are the same, what keys are removed, and what keys are added.
7
+ * @module utils/keyDiff
8
+ */
9
+
10
+ /**
11
+ * Options for keyDiff and keyDiffDeep
5
12
  * @typedef {object} KeyDiffOptions
6
- * @property {boolean} [sameKeys=true]
7
- * @property {boolean} [removedKeys=true]
8
- * @property {boolean} [addedKeys=true]
13
+ * @property {boolean} [sameKeys=true] - if true, return keys that are the same
14
+ * @property {boolean} [removedKeys=true] - if true, return keys that are removed
15
+ * @property {boolean} [addedKeys=true] - if true, return keys that are added
9
16
  */
10
17
 
11
18
  /**
19
+ * Result object of keyDiff and keyDiffDeep
12
20
  * @typedef {object} KeyDiffResult
13
- * @property {string[]} [sameKeys]
14
- * @property {string[]} [removedKeys]
15
- * @property {string[]} [addedKeys]
21
+ * @property {string[]} [sameKeys] - if sameKeys option is true, return keys that are the same
22
+ * @property {string[]} [removedKeys] - if removedKeys option is true, return keys that are removed
23
+ * @property {string[]} [addedKeys] - if addedKeys option is true, return keys that are added
16
24
  */
17
25
 
18
26
  /**
19
27
  * Calculate the difference between two arrays of keys, in terms of what keys
20
- * are the same, what keys are removed, and what keys are added.
21
- *
22
- * @param {string[]} newKeys
23
- * @param {string[]} oldKeys
24
- * @param {KeyDiffOptions} [options]
25
- * @returns {KeyDiffResult}
28
+ * are the same, what keys are removed, and what keys are added.
29
+ * @function keyDiff
30
+ * @param {string[]} newKeys - keys to consider as new
31
+ * @param {string[]} oldKeys - keys to consider as old
32
+ * @param {KeyDiffOptions} [options] - which differences are returned
33
+ * @returns {KeyDiffResult} - the differences
26
34
  */
27
35
  export function keyDiff(newKeys, oldKeys, { sameKeys = true, removedKeys = true, addedKeys = true } = {}) {
28
36
  const newKeysSet = new Set(newKeys);
@@ -43,11 +51,11 @@ export function keyDiff(newKeys, oldKeys, { sameKeys = true, removedKeys = true,
43
51
  /**
44
52
  * Calculate the difference between two objects, in terms of what keys are the same,
45
53
  * what keys are removed, and what keys are added. Keys are sourced deeply in the objects.
46
- *
47
- * @param {object} newObj
48
- * @param {object} oldObj
49
- * @param {KeyDiffOptions} [options]
50
- * @returns {KeyDiffResult}
54
+ * @function keyDiffDeep
55
+ * @param {object} newObj - the new version of the object
56
+ * @param {object} oldObj - the old version of the object
57
+ * @param {KeyDiffOptions} [options] - which differences are returned
58
+ * @returns {KeyDiffResult} - the differences
51
59
  */
52
60
  export function keyDiffDeep(newObj, oldObj, options = {}) {
53
61
  const newPaths = flattenPaths(newObj);
@@ -18,6 +18,11 @@ import {
18
18
  unref,
19
19
  } from "vue";
20
20
 
21
+ /**
22
+ * Debug lifecycle hooks
23
+ * @module utils/lifecycleDebug
24
+ */
25
+
21
26
  window.RH_DEBUG_SKIP_EMPTY_CHANGE_EFFECTS = true;
22
27
 
23
28
  export const customHandlers = {
@@ -81,7 +86,11 @@ const defaultHandler = (debugMessage) => {
81
86
  };
82
87
 
83
88
  /**
84
- * @param {string[]} categories
89
+ * Using useDebugMessage, log lifecycle events for the current component, with the specified categories.
90
+ * @function useLifecycleDebug
91
+ * @param {string[]} categories - the categories to give messages this generates
92
+ * @param {string[]} [includes] - the lifecycle functions to include
93
+ * @param {string[]} [excludes] - the lifecycle functions to exclude
85
94
  */
86
95
  export function useLifecycleDebug(categories, includes = [], excludes = []) {
87
96
  const lifeCycleFns = {
@@ -1,9 +1,13 @@
1
1
  import { isSet } from "lodash-es";
2
2
 
3
+ /**
4
+ * Object walking utility.
5
+ * @module utils/transformWalk
6
+ */
7
+
3
8
  /**
4
9
  * Recursively walks through an object's values and applies a transformation function to each value.
5
10
  * The value recursed into is the transformed value, not the original value.
6
- *
7
11
  * @example
8
12
  *
9
13
  * const obj = {
@@ -27,9 +31,9 @@ import { isSet } from "lodash-es";
27
31
  * // d: [3, 4, { e: 10 }]
28
32
  * // }
29
33
  * // }
30
- *
34
+ * @function transformWalk
31
35
  * @param {*} obj The object to start walking from.
32
- * @param {function} transformFn The function to transform each value.
36
+ * @param {Function} transformFn The function to transform each value.
33
37
  * @param {string} path The path to the current value.
34
38
  * @returns {*} The transformed initial value.
35
39
  */
package/.lintstagedrc DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "**/*.{js,cjs,mjs,ts,jsx,tsx}": [
3
- "npx --no-install eslint --fix"
4
- ],
5
- "**/*.{markdown,md}": [
6
- "npx --no-install doctoc --github -u ."
7
- ],
8
- "**/*.{js,cjs,mjs,ts,jsx,tsx,less,scss,css,vue,markdown,json,md,yml,yaml,html}": [
9
- "npx --no-install prettier --write"
10
- ],
11
- ".circleci/config.yml": [
12
- "circleci config validate"
13
- ]
14
- }
File without changes
File without changes