@arrai-innovations/reactive-helpers 11.4.2 → 13.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.
Files changed (115) hide show
  1. package/.husky/pre-commit +0 -1
  2. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  3. package/.prettierignore +1 -0
  4. package/README.md +11 -10
  5. package/config/listCrud.js +32 -1
  6. package/config/objectCrud.js +47 -1
  7. package/docs/README.md +43 -0
  8. package/docs/config/listCrud.md +97 -0
  9. package/docs/config/objectCrud.md +123 -0
  10. package/docs/use/cancellableIntent.md +163 -0
  11. package/docs/use/combineClasses.md +52 -0
  12. package/docs/use/list.md +285 -0
  13. package/docs/use/listCalculated.md +773 -0
  14. package/docs/use/listFilter.md +877 -0
  15. package/docs/use/listInstance.md +483 -0
  16. package/docs/use/listKeys.md +91 -0
  17. package/docs/use/listRelated.md +685 -0
  18. package/docs/use/listSearch.md +889 -0
  19. package/docs/use/listSort.md +1144 -0
  20. package/docs/use/listSubscription.md +379 -0
  21. package/docs/use/loadingError.md +21 -0
  22. package/docs/use/object.md +437 -0
  23. package/docs/use/objectCalculated.md +606 -0
  24. package/docs/use/objectInstance.md +486 -0
  25. package/docs/use/objectRelated.md +588 -0
  26. package/docs/use/objectSubscription.md +459 -0
  27. package/docs/use/paginatedListInstance.md +147 -0
  28. package/docs/use/search.md +311 -0
  29. package/docs/use/watchesRunning.md +80 -0
  30. package/docs/utils/assignReactiveObject.md +351 -0
  31. package/docs/utils/classes.md +100 -0
  32. package/docs/utils/compact.md +57 -0
  33. package/docs/utils/deleteKey.md +53 -0
  34. package/docs/utils/flattenPaths.md +45 -0
  35. package/docs/utils/getFakeId.md +34 -0
  36. package/docs/utils/keyDiff.md +101 -0
  37. package/docs/utils/loadingCombine.md +28 -0
  38. package/docs/utils/proxyRunning.md +33 -0
  39. package/docs/utils/relatedCalculatedHelpers.md +75 -0
  40. package/docs/utils/set.md +139 -0
  41. package/docs/utils/transformWalk.md +33 -0
  42. package/docs/utils/watches.md +441 -0
  43. package/eslint.config.js +125 -0
  44. package/index.js +34 -3
  45. package/lint-staged.config.js +5 -1
  46. package/makeTypeDoc.sh +25 -0
  47. package/package.json +27 -19
  48. package/tests/unit/config/listCrud.spec.js +5 -0
  49. package/tests/unit/config/objectCrud.spec.js +5 -0
  50. package/tests/unit/crudPromise.js +22 -3
  51. package/tests/unit/mockOnUnmounted.js +1 -1
  52. package/tests/unit/use/cancellableIntent.spec.js +2 -0
  53. package/tests/unit/use/listCalculated.spec.js +4 -3
  54. package/tests/unit/use/listFilter.spec.js +11 -7
  55. package/tests/unit/use/listInstance.spec.js +32 -14
  56. package/tests/unit/use/listRelated.spec.js +3 -2
  57. package/tests/unit/use/listSearch.spec.js +9 -7
  58. package/tests/unit/use/listSort.spec.js +29 -22
  59. package/tests/unit/use/listSubscription.spec.js +11 -5
  60. package/tests/unit/use/objectInstance.spec.js +15 -2
  61. package/tests/unit/use/objectSubscription.spec.js +31 -16
  62. package/tests/unit/use/search.spec.js +2 -2
  63. package/tests/unit/utils/assignReactiveObject.spec.js +21 -13
  64. package/tests/unit/utils/classes.spec.js +7 -6
  65. package/tests/unit/utils/watches.spec.js +4 -4
  66. package/tsconfig.json +19 -0
  67. package/typedoc-local-plugins/customize-output.js +13 -0
  68. package/typedoc.json +12 -0
  69. package/use/cancellableIntent.js +73 -2
  70. package/use/combineClasses.js +41 -31
  71. package/use/list.js +139 -5
  72. package/use/listCalculated.js +175 -10
  73. package/use/listFilter.js +175 -21
  74. package/use/listInstance.js +215 -94
  75. package/use/listRelated.js +260 -72
  76. package/use/listSearch.js +178 -57
  77. package/use/listSort.js +188 -21
  78. package/use/listSubscription.js +211 -63
  79. package/use/loadingError.js +43 -0
  80. package/use/object.js +187 -23
  81. package/use/objectCalculated.js +168 -16
  82. package/use/objectInstance.js +183 -102
  83. package/use/objectRelated.js +276 -84
  84. package/use/objectSubscription.js +169 -17
  85. package/use/paginatedListInstance.js +30 -1
  86. package/use/search.js +39 -23
  87. package/use/watchesRunning.js +41 -6
  88. package/utils/assignReactiveObject.js +139 -88
  89. package/utils/classes.js +57 -48
  90. package/utils/compact.js +28 -2
  91. package/utils/deleteKey.js +14 -1
  92. package/utils/flattenPaths.js +19 -9
  93. package/utils/getFakeId.js +11 -1
  94. package/utils/keyDiff.js +26 -35
  95. package/utils/loadingCombine.js +7 -4
  96. package/utils/proxyRunning.js +16 -8
  97. package/utils/relatedCalculatedHelpers.js +17 -0
  98. package/utils/set.js +66 -0
  99. package/utils/transformWalk.js +7 -6
  100. package/utils/watches.js +205 -71
  101. package/.eslintignore +0 -2
  102. package/.eslintrc.cjs +0 -25
  103. package/.jsdoc2md.json +0 -4
  104. package/config/index.js +0 -2
  105. package/docs.md +0 -1002
  106. package/jsdoc-to-markdown.sh +0 -16
  107. package/tests/unit/.eslintrc.cjs +0 -11
  108. package/tests/unit/config/index.spec.js +0 -18
  109. package/tests/unit/use/index.spec.js +0 -18
  110. package/tests/unit/utils/index.spec.js +0 -18
  111. package/use/index.js +0 -19
  112. package/utils/debugMessage.js +0 -209
  113. package/utils/debugWatch.js +0 -29
  114. package/utils/index.js +0 -16
  115. package/utils/lifecycleDebug.js +0 -126
package/utils/watches.js CHANGED
@@ -1,18 +1,44 @@
1
1
  import { watch, toRef } from "vue";
2
2
 
3
- // If you want an immediate watch, but you can't use immediate because you want to stop the watch in the function.
3
+ /**
4
+ * @module utils/watches.js
5
+ * @description
6
+ *
7
+ * A collection of utility classes and functions for managing Vue.js watchers.
8
+ *
9
+ */
10
+
11
+ /**
12
+ * Provides a mechanism for immediately starting and potentially stopping a Vue.js watcher
13
+ * during its first invocation. This is useful when the need arises to terminate the watch
14
+ * based on conditions encountered during the initial execution of the watch function.
15
+ */
4
16
  export class ImmediateStopWatch {
5
17
  constructor() {}
6
18
 
7
- // watchFuncArgs are for immediate call only.
19
+ /**
20
+ * Starts the watch.
21
+ *
22
+ * @param {import("vue").WatchSource | import("vue").WatchSource[]} watchSources - The source(s) to watch.
23
+ * @param {import("vue").WatchCallback} watchFunc - The callback to execute when the source changes.
24
+ * @param {any[]} [watchFuncArgs=[]] - Optional arguments to pass to the watch function.
25
+ * @param {import("vue").WatchOptions} [watchOptions={}] - Optional watch options.
26
+ * @returns {void}
27
+ */
8
28
  start(watchSources, watchFunc, watchFuncArgs = [], watchOptions = {}) {
9
29
  if (watchOptions.immediate) {
10
30
  throw new Error("ImmediateStopWatch is always immediate.");
11
31
  }
12
32
  this.stopWatch = watch(watchSources, watchFunc, watchOptions);
33
+ // @ts-ignore - an array is fine to be spread here
13
34
  watchFunc(...watchFuncArgs);
14
35
  }
15
36
 
37
+ /**
38
+ * Stops the watch.
39
+ *
40
+ * @returns {void}
41
+ */
16
42
  stop() {
17
43
  if (this.stopWatch) {
18
44
  this.stopWatch();
@@ -21,6 +47,11 @@ export class ImmediateStopWatch {
21
47
  }
22
48
  }
23
49
 
50
+ /**
51
+ * The error thrown when an AwaitTimeout operation times out.
52
+ *
53
+ * @property {string} code - The error code.
54
+ */
24
55
  export class AwaitTimeoutError extends Error {
25
56
  constructor(message, code) {
26
57
  super(message);
@@ -29,6 +60,12 @@ export class AwaitTimeoutError extends Error {
29
60
  }
30
61
  }
31
62
 
63
+ /**
64
+ * The error thrown when an AwaitNot operation times out.
65
+ *
66
+ * @property {string} code - The error code.
67
+ * @property {string} name - The error name.
68
+ */
32
69
  export class AwaitNotError extends Error {
33
70
  constructor(message, code) {
34
71
  super(message);
@@ -37,7 +74,31 @@ export class AwaitNotError extends Error {
37
74
  }
38
75
  }
39
76
 
77
+ /**
78
+ * @private
79
+ * @param {AwaitTimeout} awaitTimeout - The AwaitTimeout instance.
80
+ */
81
+ const doTimeout = (awaitTimeout) => {
82
+ delete awaitTimeout.timeoutId;
83
+ if (awaitTimeout.resolve) {
84
+ awaitTimeout.resolve();
85
+ delete awaitTimeout.resolve;
86
+ }
87
+ awaitTimeout.stop();
88
+ };
89
+
90
+ /**
91
+ * A utility class for managing a promise that resolves or rejects based on a set timeout or an explicit stop action.
92
+ * This class is useful for implementing timeouts in asynchronous operations, where you might need to reject a promise
93
+ * if an operation takes too long or cancel the timeout based on certain conditions.
94
+ */
40
95
  export class AwaitTimeout {
96
+ /**
97
+ * Creates an instance of AwaitTimeout with a specified timeout duration.
98
+ *
99
+ * @param {object} options - The options for the AwaitTimeout.
100
+ * @param {number} [options.timeout=1000] - The timeout in milliseconds.
101
+ */
41
102
  constructor({ timeout = 1000 }) {
42
103
  this.promise = new Promise((resolve, reject) => {
43
104
  this.resolve = resolve;
@@ -49,23 +110,24 @@ export class AwaitTimeout {
49
110
  this.cancelledError = new AwaitTimeoutError("Cancelled", "timeout_cancelled");
50
111
  }
51
112
 
113
+ /**
114
+ * Starts the timeout process. If the timeout duration is reached without being stopped, the promise resolves.
115
+ *
116
+ * @returns {void}
117
+ */
52
118
  start() {
53
119
  if (this.timeout) {
54
- this.timeoutId = setTimeout(this.doTimeout.bind(this), this.timeout);
120
+ this.timeoutId = setTimeout(doTimeout.bind(null, this), this.timeout);
55
121
  } else {
56
- this.doTimeout();
57
- }
58
- }
59
-
60
- doTimeout() {
61
- delete this.timeoutId;
62
- if (this.resolve) {
63
- this.resolve();
64
- delete this.resolve;
122
+ doTimeout(this);
65
123
  }
66
- this.stop();
67
124
  }
68
125
 
126
+ /**
127
+ * Stops the timeout if it is active, rejecting the promise with a "Cancelled" error. Clears all pending actions.
128
+ *
129
+ * @returns {void}
130
+ */
69
131
  stop() {
70
132
  if (this.timeoutId) {
71
133
  clearTimeout(this.timeoutId);
@@ -81,13 +143,115 @@ export class AwaitTimeout {
81
143
  }
82
144
  }
83
145
 
146
+ /**
147
+ * Helper function to get the resulting promise from an AwaitTimeout instance.
148
+ *
149
+ * @param {number} timeout - The timeout in milliseconds.
150
+ * @returns {Promise} A promise that resolves after the specified timeout.
151
+ */
84
152
  export function doAwaitTimeout(timeout) {
85
153
  const newAwaitTimeout = new AwaitTimeout({ timeout });
86
154
  newAwaitTimeout.start();
87
155
  return newAwaitTimeout.promise;
88
156
  }
89
157
 
158
+ /**
159
+ * Helper function to get the resulting promise from an AwaitTimeout instance.
160
+ *
161
+ * @private
162
+ * @param {AwaitNot} awaitNot - The AwaitNot instance.
163
+ */
164
+ const waitForTrue = (awaitNot) => {
165
+ awaitNot.trueISW.start(
166
+ awaitNot.ref,
167
+ (newValue) => {
168
+ if (newValue === true) {
169
+ stopTrue(awaitNot);
170
+ waitForFalse(awaitNot);
171
+ }
172
+ },
173
+ [awaitNot.ref.value]
174
+ );
175
+ };
176
+
177
+ /**
178
+ * Helper function to get the resulting promise from an AwaitTimeout instance.
179
+ *
180
+ * @private
181
+ * @param {AwaitNot} awaitNot - The AwaitNot instance.
182
+ */
183
+ const stopTrue = (awaitNot) => {
184
+ if (awaitNot.trueISW) {
185
+ awaitNot.trueISW.stop();
186
+ delete awaitNot.trueISW;
187
+ }
188
+ };
189
+
190
+ /**
191
+ * Helper function to get the resulting promise from an AwaitTimeout instance.
192
+ *
193
+ * @private
194
+ * @param {AwaitNot} awaitNot - The AwaitNot instance.
195
+ */
196
+ const waitForFalse = (awaitNot) => {
197
+ awaitNot.falseISW.start(
198
+ awaitNot.ref,
199
+ (newValue) => {
200
+ if (newValue === false) {
201
+ awaitNot.stop();
202
+ if (awaitNot.resolve) {
203
+ awaitNot.resolve();
204
+ }
205
+ cleanPromise(awaitNot);
206
+ }
207
+ },
208
+ [awaitNot.ref.value]
209
+ );
210
+ };
211
+
212
+ /**
213
+ * Helper function to get the resulting promise from an AwaitTimeout instance.
214
+ *
215
+ * @private
216
+ * @param {AwaitNot} awaitNot - The AwaitNot instance.
217
+ */
218
+ const stopFalse = (awaitNot) => {
219
+ if (awaitNot.falseISW) {
220
+ awaitNot.falseISW.stop();
221
+ delete awaitNot.falseISW;
222
+ }
223
+ };
224
+
225
+ /**
226
+ * Helper function to get the resulting promise from an AwaitTimeout instance.
227
+ *
228
+ * @private
229
+ * @param {AwaitNot} awaitNot - The AwaitNot instance.
230
+ */
231
+ const cleanPromise = (awaitNot) => {
232
+ if (awaitNot.resolve) {
233
+ delete awaitNot.resolve;
234
+ }
235
+ if (awaitNot.reject) {
236
+ delete awaitNot.reject;
237
+ }
238
+ };
239
+
240
+ /**
241
+ * Manages an asynchronous watch on a property, waiting for it to toggle between true and false states.
242
+ * This class uses immediate watchers to react to changes and supports a timeout to limit waiting duration.
243
+ */
90
244
  export class AwaitNot {
245
+ /**
246
+ * Initializes the AwaitNot with specified options for reactive property watching and timeout settings.
247
+ *
248
+ * @param {object} options - Configuration options for AwaitNot.
249
+ * @param {object} [options.obj] - The object containing the property to watch.
250
+ * @param {string} [options.prop] - The property name to watch within the object.
251
+ * @param {import("vue").Ref} [options.ref] - A Vue ref to directly watch if provided.
252
+ * @param {boolean} [options.couldAlreadyBeFalse=false] - Indicates if the property could already be in the false state at initialization.
253
+ * @param {number} [options.timeout=1000] - The timeout in milliseconds before the promise is rejected.
254
+ */
91
255
  constructor({ obj, prop, ref, couldAlreadyBeFalse = false, timeout = 1000 }) {
92
256
  if (timeout > 0) {
93
257
  this.timeout = new AwaitTimeout({ timeout });
@@ -110,6 +274,12 @@ export class AwaitNot {
110
274
  }
111
275
  }
112
276
 
277
+ /**
278
+ * Starts the process of watching the property for changes between true and false.
279
+ * It sets up the necessary watchers and a timeout if specified.
280
+ *
281
+ * @returns {void}
282
+ */
113
283
  start() {
114
284
  if (this.timeout) {
115
285
  this.timeout.promise
@@ -118,87 +288,51 @@ export class AwaitNot {
118
288
  this.reject(this.timeoutError);
119
289
  }
120
290
  this.stop();
121
- this.cleanPromise();
291
+ cleanPromise(this);
122
292
  })
123
293
  .catch((err) => {
124
294
  if (!(err instanceof AwaitTimeoutError)) {
125
295
  if (this.reject) {
126
296
  this.reject(err);
127
297
  }
128
- this.cleanPromise();
298
+ cleanPromise(this);
129
299
  }
130
300
  this.stop();
131
301
  });
132
302
  this.timeout.start();
133
303
  }
134
304
  if (this.ref.value === false && this.couldAlreadyBeFalse) {
135
- this.waitForTrue();
305
+ waitForTrue(this);
136
306
  } else {
137
- this.waitForFalse();
138
- }
139
- }
140
-
141
- waitForTrue() {
142
- this.trueISW.start(
143
- this.ref,
144
- (newValue) => {
145
- if (newValue === true) {
146
- this.stopTrue();
147
- this.waitForFalse();
148
- }
149
- },
150
- [this.ref.value]
151
- );
152
- }
153
-
154
- stopTrue() {
155
- if (this.trueISW) {
156
- this.trueISW.stop();
157
- delete this.trueISW;
158
- }
159
- }
160
-
161
- waitForFalse() {
162
- this.falseISW.start(
163
- this.ref,
164
- (newValue) => {
165
- if (newValue === false) {
166
- this.stop();
167
- if (this.resolve) {
168
- this.resolve();
169
- }
170
- this.cleanPromise();
171
- }
172
- },
173
- [this.ref.value]
174
- );
175
- }
176
-
177
- stopFalse() {
178
- if (this.falseISW) {
179
- this.falseISW.stop();
180
- delete this.falseISW;
307
+ waitForFalse(this);
181
308
  }
182
309
  }
183
310
 
311
+ /**
312
+ * Stops all watchers and the timeout, cleaning up resources.
313
+ *
314
+ * @returns {void}
315
+ */
184
316
  stop() {
185
317
  if (this.timeout) {
186
318
  this.timeout.stop();
187
319
  }
188
- this.stopTrue();
189
- this.stopFalse();
190
- }
191
-
192
- cleanPromise() {
193
- if (this.resolve) {
194
- delete this.resolve;
195
- }
196
- if (this.reject) {
197
- delete this.reject;
198
- }
320
+ stopTrue(this);
321
+ stopFalse(this);
199
322
  }
200
323
  }
201
324
 
325
+ /**
326
+ * Helper function to get the resulting promise from an AwaitNot instance.
327
+ *
328
+ * @param {object} options - Configuration options for AwaitNot.
329
+ * @param {object} options.obj - The object containing the property to watch.
330
+ * @param {string} options.prop - The property name to watch within the object.
331
+ * @param {import("vue").Ref} [options.ref] - A Vue ref to directly watch if provided.
332
+ * @param {boolean} [options.couldAlreadyBeFalse=false] - Indicates if the property could already be in the false state at initialization.
333
+ * @param {number} [options.timeout=1000] - The timeout in milliseconds before the promise is rejected.
334
+ * @returns {Promise} A promise that resolves when the property toggles from true to false.
335
+ */
202
336
  export function doAwaitNot({ obj, prop, ref, couldAlreadyBeFalse = true, timeout = 1000 }) {
203
337
  const awaitNot = new AwaitNot({ obj, prop, ref, couldAlreadyBeFalse, timeout });
204
338
  awaitNot.start();
package/.eslintignore DELETED
@@ -1,2 +0,0 @@
1
- **/.eslintrc.js
2
- .prettierrc.js
package/.eslintrc.cjs DELETED
@@ -1,25 +0,0 @@
1
- module.exports = {
2
- root: true,
3
-
4
- env: {
5
- node: true,
6
- },
7
- plugins: ["jsdoc"],
8
- extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier", "plugin:jsdoc/recommended"],
9
-
10
- rules: {
11
- "no-console": "off", // console.error is useful.
12
- "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
13
- "space-before-function-paren": [
14
- "error",
15
- {
16
- anonymous: "always",
17
- named: "never",
18
- asyncArrow: "always",
19
- },
20
- ],
21
- "jsdoc/require-jsdoc": "off", // let's ease into this
22
- "jsdoc/check-types": "off", // this rule is overly broad and gives advice that doesn't work with jsdoc2md.
23
- "jsdoc/no-undefined-types": "off", // jsdoc2md considers all types to be global and doesn't understand imports.
24
- },
25
- };
package/.jsdoc2md.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "files": ["use/**/*.js", "utils/**/*.js"],
3
- "plugin": "@godaddy/dmd"
4
- }
package/config/index.js DELETED
@@ -1,2 +0,0 @@
1
- export * from "./listCrud.js";
2
- export * from "./objectCrud.js";