@arrai-innovations/reactive-helpers 10.0.0 → 10.0.1
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/docs.md +17 -10
- package/package.json +2 -2
- package/tests/unit/use/listSort.spec.js +1 -1
- package/tests/unit/utils/flattenPaths.spec.js +8 -0
- package/tests/unit/utils/keyDiff.spec.js +44 -1
- package/use/list.js +2 -2
- package/use/listRelated.js +36 -8
- package/use/listSort.js +38 -41
- package/use/listSubscription.js +1 -1
- package/utils/flattenPaths.js +11 -3
- package/utils/keyDiff.js +11 -4
package/docs.md
CHANGED
|
@@ -221,7 +221,7 @@ Logs debug messages based on the specified categories and logging rules.
|
|
|
221
221
|
|
|
222
222
|
Get all paths from an array or object.
|
|
223
223
|
|
|
224
|
-
### utils/flattenPaths~flattenPaths(arrayOrObject,
|
|
224
|
+
### utils/flattenPaths~flattenPaths(arrayOrObject, options)
|
|
225
225
|
|
|
226
226
|
Turn an array or object into an array of path strings. Recurses for any found arrays or objects.
|
|
227
227
|
|
|
@@ -230,10 +230,13 @@ Array indexes are wrapped in square brackets and object keys are prefixed with a
|
|
|
230
230
|
**Kind**: inner method of [`utils/flattenPaths`]
|
|
231
231
|
**Returns**: `Array.<string>` - paths
|
|
232
232
|
|
|
233
|
-
| Param
|
|
234
|
-
|
|
|
235
|
-
| arrayOrObject
|
|
236
|
-
|
|
|
233
|
+
| Param | Type | Description |
|
|
234
|
+
| ------------------- | ------------------- | -------------------------------------------------- |
|
|
235
|
+
| arrayOrObject | `Array` \| `object` | array or object to flatten |
|
|
236
|
+
| options | `object` | options |
|
|
237
|
+
| options.currentPath | `string` | current path, for recursion or as a starting point |
|
|
238
|
+
| options.depth | `number` | current depth, for recursion |
|
|
239
|
+
| options.limit | `number` | limit the depth of recursion |
|
|
237
240
|
|
|
238
241
|
## utils/keyDiff
|
|
239
242
|
|
|
@@ -268,11 +271,15 @@ what keys are removed, and what keys are added. Keys are sourced deeply in the o
|
|
|
268
271
|
**Kind**: inner method of [`utils/keyDiff`]
|
|
269
272
|
**Returns**: `KeyDiffResult` - - the differences
|
|
270
273
|
|
|
271
|
-
| Param
|
|
272
|
-
|
|
|
273
|
-
| newObj
|
|
274
|
-
| oldObj
|
|
275
|
-
| \[options\]
|
|
274
|
+
| Param | Type | Description |
|
|
275
|
+
| ----------------------- | ---------------- | -------------------------------------- |
|
|
276
|
+
| newObj | `object` | the new version of the object |
|
|
277
|
+
| oldObj | `object` | the old version of the object |
|
|
278
|
+
| \[options\] | `KeyDiffOptions` | which differences are returned |
|
|
279
|
+
| \[options.sameKeys\] | `boolean` | if true, return keys that are the same |
|
|
280
|
+
| \[options.removedKeys\] | `boolean` | if true, return keys that are removed |
|
|
281
|
+
| \[options.addedKeys\] | `boolean` | if true, return keys that are added |
|
|
282
|
+
| \[options.limit\] | `number` | limit the depth of recursion |
|
|
276
283
|
|
|
277
284
|
### utils/keyDiff~KeyDiffOptions
|
|
278
285
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arrai-innovations/reactive-helpers",
|
|
3
|
-
"version": "10.0.
|
|
3
|
+
"version": "10.0.1",
|
|
4
4
|
"description": "VueJS 3 utility composition functions to help manipulate objects and lists.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"jsdoc-to-markdown": "^8.0.0",
|
|
46
46
|
"lint-staged": "^13.2.2",
|
|
47
47
|
"prettier": "2.6.2",
|
|
48
|
-
"vitest": "^0.
|
|
48
|
+
"vitest": "^0.34.1"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"browser-util-inspect": "^0.2.0",
|
|
@@ -68,7 +68,7 @@ describe("use/useListSort", () => {
|
|
|
68
68
|
expect(listSort.state.order).toEqual([]);
|
|
69
69
|
expect(listSort.state.objectsInOrder).toEqual([]);
|
|
70
70
|
expect(listSort.state.sortCriteria).toEqual({});
|
|
71
|
-
expect(listSort.state.
|
|
71
|
+
expect(listSort.state.sortCriteriaEffectScopes).toEqual({});
|
|
72
72
|
expect(listSort.state.orderByDesc).toEqual([true, false]);
|
|
73
73
|
});
|
|
74
74
|
describe("addSortCriteria and removeSortCriteria", () => {
|
|
@@ -15,6 +15,10 @@ describe("utils/flattenPaths", () => {
|
|
|
15
15
|
it("with a single level and a nested object and array", () => {
|
|
16
16
|
expect(flattenPaths({ a: 1, b: { c: [2] } })).toEqual(["a", "b.c[0]"]);
|
|
17
17
|
});
|
|
18
|
+
it("should limit to a specific depth", () => {
|
|
19
|
+
expect(flattenPaths({ a: 1, b: { c: [2] } }, { limit: 1 })).toEqual(["a"]);
|
|
20
|
+
expect(flattenPaths({ a: 1, b: { c: 1, d: [2], e: { f: 3 } } }, { limit: 2 })).toEqual(["a", "b.c"]);
|
|
21
|
+
});
|
|
18
22
|
});
|
|
19
23
|
describe("should work on arrays as the base", () => {
|
|
20
24
|
it("with a single level", () => {
|
|
@@ -29,6 +33,10 @@ describe("utils/flattenPaths", () => {
|
|
|
29
33
|
it("with a single level and a nested object and array", () => {
|
|
30
34
|
expect(flattenPaths([1, { c: [2] }])).toEqual(["[0]", "[1].c[0]"]);
|
|
31
35
|
});
|
|
36
|
+
it("should limit to a specific depth", () => {
|
|
37
|
+
expect(flattenPaths([1, { c: [2] }], { limit: 1 })).toEqual(["[0]"]);
|
|
38
|
+
expect(flattenPaths([1, [1, [2, [3], 4], 5]], { limit: 2 })).toEqual(["[0]", "[1][0]", "[1][2]"]);
|
|
39
|
+
});
|
|
32
40
|
});
|
|
33
41
|
it("should work on a real world example", () => {
|
|
34
42
|
const toBeFlattened = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { keyDiff } from "../../../utils/keyDiff.js";
|
|
1
|
+
import { keyDiff, keyDiffDeep } from "../../../utils/keyDiff.js";
|
|
2
2
|
|
|
3
3
|
describe("keyDiff", function () {
|
|
4
4
|
describe("should return the difference between two arrays of object keys", function () {
|
|
@@ -64,4 +64,47 @@ describe("keyDiff", function () {
|
|
|
64
64
|
expect(removedKeys).toEqual(new Set(["c"]));
|
|
65
65
|
expect(sameKeys).toEqual(new Set(["a"]));
|
|
66
66
|
});
|
|
67
|
+
describe("keyDiffDeep", function () {
|
|
68
|
+
it("should return the difference between two objects", function () {
|
|
69
|
+
const newObj = {
|
|
70
|
+
a: 1,
|
|
71
|
+
b: {
|
|
72
|
+
c: 2,
|
|
73
|
+
},
|
|
74
|
+
c: 3,
|
|
75
|
+
};
|
|
76
|
+
const oldObj = {
|
|
77
|
+
a: 1,
|
|
78
|
+
b: 2,
|
|
79
|
+
c: 3,
|
|
80
|
+
};
|
|
81
|
+
// if using to patch, be sure to remove keys before adding them
|
|
82
|
+
expect(keyDiffDeep(newObj, oldObj)).toEqual({
|
|
83
|
+
addedKeys: new Set(["b.c"]),
|
|
84
|
+
removedKeys: new Set(["b"]),
|
|
85
|
+
sameKeys: new Set(["a", "c"]),
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
it("should be able to limit the depth", function () {
|
|
89
|
+
const newObj = {
|
|
90
|
+
a: 1,
|
|
91
|
+
b: {
|
|
92
|
+
c: { d: 1, e: 2, f: 3 },
|
|
93
|
+
},
|
|
94
|
+
g: 3,
|
|
95
|
+
};
|
|
96
|
+
const oldObj = {
|
|
97
|
+
a: 1,
|
|
98
|
+
b: {
|
|
99
|
+
c: {},
|
|
100
|
+
},
|
|
101
|
+
g: 3,
|
|
102
|
+
};
|
|
103
|
+
expect(keyDiffDeep(newObj, oldObj, { limit: 1 })).toEqual({
|
|
104
|
+
addedKeys: new Set(),
|
|
105
|
+
removedKeys: new Set(),
|
|
106
|
+
sameKeys: new Set(["a", "g"]),
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
67
110
|
});
|
package/use/list.js
CHANGED
|
@@ -16,7 +16,7 @@ export const useLists = (listArgs) => {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
// the big brother of useObject, managing a chain of useList* instances.
|
|
19
|
-
export const useList = ({ props, functions, paged = false, keepOldPages = false }) => {
|
|
19
|
+
export const useList = ({ props, functions = {}, paged = false, keepOldPages = false, useTextSearch = false }) => {
|
|
20
20
|
const managed = shallowReactive({
|
|
21
21
|
listInstance: null,
|
|
22
22
|
listSubscription: null,
|
|
@@ -58,7 +58,7 @@ export const useList = ({ props, functions, paged = false, keepOldPages = false
|
|
|
58
58
|
|
|
59
59
|
managed.listFilter = useListFilter({
|
|
60
60
|
parentState: managed.listCalculated.state,
|
|
61
|
-
useTextSearch
|
|
61
|
+
useTextSearch,
|
|
62
62
|
textSearchRules: toRef(props, "textSearchRules"),
|
|
63
63
|
textSearchValue: toRef(props, "textSearchValue"),
|
|
64
64
|
allowedValues: toRef(props, "allowedValues"),
|
package/use/listRelated.js
CHANGED
|
@@ -4,8 +4,10 @@ import { listInstanceStateKeys } from "./listInstance.js";
|
|
|
4
4
|
import { listSubscriptionStateKeys } from "./listSubscription.js";
|
|
5
5
|
import { useWatchesRunning } from "./watchesRunning.js";
|
|
6
6
|
import get from "lodash-es/get.js";
|
|
7
|
+
import identity from "lodash-es/identity.js";
|
|
7
8
|
import isArray from "lodash-es/isArray.js";
|
|
8
9
|
import isEmpty from "lodash-es/isEmpty.js";
|
|
10
|
+
import isEqual from "lodash-es/isEqual.js";
|
|
9
11
|
import isUndefined from "lodash-es/isUndefined.js";
|
|
10
12
|
import { computed, effectScope, onScopeDispose, reactive, toRef, unref, watch } from "vue";
|
|
11
13
|
|
|
@@ -55,7 +57,7 @@ export function useListRelated({ parentState, relatedObjectsRules }) {
|
|
|
55
57
|
const relatedObjectsRulesIsEmpty = !state.relatedObjectsRules || isEmpty(state.relatedObjectsRules);
|
|
56
58
|
for (const objectKey of Object.keys(state.relatedObjects)) {
|
|
57
59
|
const relatedObjectsObject = state.relatedObjects[objectKey];
|
|
58
|
-
const
|
|
60
|
+
const originalObjectRef = toRef(parentState.objects, objectKey);
|
|
59
61
|
let removedRuleKeys, addedRuleKeys;
|
|
60
62
|
if (!relatedObjectsRulesIsEmpty) {
|
|
61
63
|
({ removedKeys: removedRuleKeys, addedKeys: addedRuleKeys } = keyDiff(
|
|
@@ -77,22 +79,48 @@ export function useListRelated({ parentState, relatedObjectsRules }) {
|
|
|
77
79
|
}
|
|
78
80
|
relatedObjectsEffectScopes[objectKey].run(() => {
|
|
79
81
|
for (const addedRuleKey of addedRuleKeys) {
|
|
80
|
-
relatedObjectsObject[addedRuleKey] =
|
|
82
|
+
relatedObjectsObject[addedRuleKey] = undefined;
|
|
83
|
+
const relatedObjectsObjectWatchFn = () => {
|
|
81
84
|
// deal with computed objects being passed.
|
|
82
85
|
const ruleObjects = unref(state.relatedObjectsRules?.[addedRuleKey]?.objects);
|
|
83
86
|
const rulePkKey = state.relatedObjectsRules?.[addedRuleKey]?.pkKey || addedRuleKey;
|
|
87
|
+
const ruleOrder = unref(state.relatedObjectsRules?.[addedRuleKey]?.order);
|
|
84
88
|
if (!ruleObjects || !rulePkKey) {
|
|
85
|
-
|
|
89
|
+
relatedObjectsObject[addedRuleKey] = undefined;
|
|
90
|
+
return;
|
|
86
91
|
}
|
|
87
|
-
|
|
92
|
+
let value = get(unref(originalObjectRef), rulePkKey);
|
|
88
93
|
if (isUndefined(value)) {
|
|
89
|
-
|
|
94
|
+
relatedObjectsObject[addedRuleKey] = undefined;
|
|
95
|
+
return;
|
|
90
96
|
}
|
|
91
97
|
if (isArray(value)) {
|
|
92
|
-
|
|
98
|
+
// the related list could be sorted differently than the original list.
|
|
99
|
+
if (ruleOrder?.length) {
|
|
100
|
+
value = value.filter(identity);
|
|
101
|
+
const indexById = Object.fromEntries(ruleOrder.map((e, i) => [e, i]));
|
|
102
|
+
value.sort((a, b) => {
|
|
103
|
+
const aIndex = indexById[a];
|
|
104
|
+
const bIndex = indexById[b];
|
|
105
|
+
return aIndex - bIndex;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
value = value.map((e) => ruleObjects[e]).filter(identity);
|
|
109
|
+
} else {
|
|
110
|
+
value = ruleObjects[value];
|
|
93
111
|
}
|
|
94
|
-
|
|
95
|
-
|
|
112
|
+
if (!isEqual(value, relatedObjectsObject[addedRuleKey])) {
|
|
113
|
+
relatedObjectsObject[addedRuleKey] = value;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
watch(
|
|
117
|
+
[toRef(state.relatedObjectsRules, addedRuleKey), originalObjectRef],
|
|
118
|
+
relatedObjectsObjectWatchFn,
|
|
119
|
+
{
|
|
120
|
+
deep: true,
|
|
121
|
+
immediate: true,
|
|
122
|
+
}
|
|
123
|
+
);
|
|
96
124
|
}
|
|
97
125
|
});
|
|
98
126
|
}
|
package/use/listSort.js
CHANGED
|
@@ -10,17 +10,16 @@ import identity from "lodash-es/identity.js";
|
|
|
10
10
|
import isEmpty from "lodash-es/isEmpty.js";
|
|
11
11
|
import isNull from "lodash-es/isNull.js";
|
|
12
12
|
import isUndefined from "lodash-es/isUndefined.js";
|
|
13
|
-
import partial from "lodash-es/partial.js";
|
|
14
13
|
import throttle from "lodash-es/throttle.js";
|
|
15
14
|
import zip from "lodash-es/zip.js";
|
|
16
|
-
import { effectScope,
|
|
15
|
+
import { effectScope, reactive, toRef, unref, watch } from "vue";
|
|
17
16
|
|
|
18
17
|
export const listSortStateKeys = [
|
|
19
18
|
"orderByRules",
|
|
20
19
|
// "order",
|
|
21
20
|
// "objectsInOrder",
|
|
22
21
|
"sortCriteria",
|
|
23
|
-
"
|
|
22
|
+
"sortCriteriaEffectScopes",
|
|
24
23
|
"orderByDesc",
|
|
25
24
|
];
|
|
26
25
|
|
|
@@ -55,42 +54,43 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
55
54
|
order: [],
|
|
56
55
|
objectsInOrder: [],
|
|
57
56
|
sortCriteria: {},
|
|
58
|
-
|
|
57
|
+
sortCriteriaEffectScopes: {},
|
|
59
58
|
orderByDesc: [],
|
|
60
59
|
});
|
|
61
60
|
const es = effectScope();
|
|
62
61
|
|
|
63
62
|
function removeSortCriteria(removedKey) {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
stopWatch = stopWatches.pop();
|
|
63
|
+
const oldScope = state.sortCriteriaEffectScopes[removedKey];
|
|
64
|
+
if (oldScope) {
|
|
65
|
+
oldScope.stop();
|
|
66
|
+
delete state.sortCriteriaEffectScopes[removedKey];
|
|
69
67
|
}
|
|
70
|
-
delete state.sortCriteriaWatches[removedKey];
|
|
71
68
|
delete state.sortCriteria[removedKey];
|
|
72
69
|
}
|
|
73
70
|
|
|
74
71
|
function addSortCriteria(object, key) {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
stopWatch();
|
|
79
|
-
stopWatch = oldStopWatches.pop();
|
|
72
|
+
const oldScope = state.sortCriteriaEffectScopes[key];
|
|
73
|
+
if (oldScope) {
|
|
74
|
+
oldScope.stop();
|
|
80
75
|
}
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
state.sortCriteria[key]
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
const newScope = effectScope();
|
|
77
|
+
newScope.run(() => {
|
|
78
|
+
if (!state.sortCriteria[key]) {
|
|
79
|
+
state.sortCriteria[key] = [];
|
|
80
|
+
}
|
|
86
81
|
watch(
|
|
87
|
-
[object, state
|
|
82
|
+
[object, toRef(state, "orderByRules")],
|
|
88
83
|
() => {
|
|
84
|
+
const obj = unref(object);
|
|
89
85
|
const newSearchCriteria = [];
|
|
90
86
|
for (const orderByObj of state.orderByRules.filter(identity)) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
let newItem;
|
|
88
|
+
if (orderByObj.keyFn) {
|
|
89
|
+
newItem = orderByObj.keyFn(obj, state);
|
|
90
|
+
} else {
|
|
91
|
+
newItem = get(obj, orderByObj.key);
|
|
92
|
+
}
|
|
93
|
+
newSearchCriteria.push(newItem);
|
|
94
94
|
}
|
|
95
95
|
assignReactiveObject(state.sortCriteria[key], newSearchCriteria);
|
|
96
96
|
},
|
|
@@ -98,9 +98,9 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
98
98
|
deep: true,
|
|
99
99
|
immediate: true,
|
|
100
100
|
}
|
|
101
|
-
)
|
|
102
|
-
);
|
|
103
|
-
state.
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
state.sortCriteriaEffectScopes[key] = newScope;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
function sortCriteriaWatch() {
|
|
@@ -117,10 +117,12 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
117
117
|
removeSortCriteria(removedKey);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
es.run(() => {
|
|
121
|
+
for (const addedKey of addedKeys) {
|
|
122
|
+
const object = toRef(() => parentState.objects[addedKey]);
|
|
123
|
+
addSortCriteria(object, addedKey);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
124
126
|
assignReactiveObject(
|
|
125
127
|
state.orderByDesc,
|
|
126
128
|
state.orderByRules.filter(identity).map((e) => e.desc || false)
|
|
@@ -129,8 +131,9 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
129
131
|
|
|
130
132
|
function sortWatch() {
|
|
131
133
|
if (!state.orderByRules || !state.orderByRules.length) {
|
|
132
|
-
|
|
133
|
-
assignReactiveObject(state.
|
|
134
|
+
console.log("sortWatch no orderByRules");
|
|
135
|
+
assignReactiveObject(state.order, cloneDeep(parentState.order));
|
|
136
|
+
assignReactiveObject(state.objectsInOrder, cloneDeep(parentState.objectsInOrder));
|
|
134
137
|
return;
|
|
135
138
|
}
|
|
136
139
|
|
|
@@ -197,20 +200,14 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
197
200
|
}
|
|
198
201
|
// we do not need two immediate watches to the same function.
|
|
199
202
|
watch(() => Object.keys(parentState.objects), sortCriteriaWatch);
|
|
200
|
-
watch((
|
|
203
|
+
watch(toRef(state, "orderByRules"), sortCriteriaWatch, {
|
|
201
204
|
deep: true,
|
|
202
205
|
immediate: true,
|
|
203
206
|
});
|
|
204
207
|
|
|
205
|
-
|
|
206
|
-
watch([toRef(state, "orderByDesc"), () => state.sortCriteria], throttledSortWatch, {
|
|
208
|
+
watch([toRef(state, "orderByDesc"), toRef(state, "sortCriteria")], throttledSortWatch, {
|
|
207
209
|
deep: true,
|
|
208
210
|
});
|
|
209
|
-
onScopeDispose(() => {
|
|
210
|
-
Object.keys(state.sortCriteriaWatches).forEach((key) => {
|
|
211
|
-
removeSortCriteria(key);
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
211
|
});
|
|
215
212
|
|
|
216
213
|
return {
|
package/use/listSubscription.js
CHANGED
|
@@ -230,7 +230,7 @@ export function useListSubscription({ listInstance, props, functions, keepOldPag
|
|
|
230
230
|
state.subscriptionErrored = true;
|
|
231
231
|
state.subscriptionError = err;
|
|
232
232
|
});
|
|
233
|
-
catchPromise.cancel = subscribePromise.cancel;
|
|
233
|
+
catchPromise.cancel = subscribePromise.cancel.bind(subscribePromise);
|
|
234
234
|
return catchPromise;
|
|
235
235
|
},
|
|
236
236
|
watchArguments: reactive({
|
package/utils/flattenPaths.js
CHANGED
|
@@ -12,10 +12,13 @@ import isObject from "lodash-es/isObject.js";
|
|
|
12
12
|
* Array indexes are wrapped in square brackets and object keys are prefixed with a period.
|
|
13
13
|
* @function flattenPaths
|
|
14
14
|
* @param {Array | object} arrayOrObject array or object to flatten
|
|
15
|
-
* @param {
|
|
15
|
+
* @param {object} options options
|
|
16
|
+
* @param {string} options.currentPath current path, for recursion or as a starting point
|
|
17
|
+
* @param {number} options.depth current depth, for recursion
|
|
18
|
+
* @param {number} options.limit limit the depth of recursion
|
|
16
19
|
* @returns {string[]} paths
|
|
17
20
|
*/
|
|
18
|
-
export function flattenPaths(arrayOrObject, currentPath = "") {
|
|
21
|
+
export function flattenPaths(arrayOrObject, { currentPath = "", depth = 0, limit = 0 } = {}) {
|
|
19
22
|
// arrayOrObject keys or indexes values can be objects or arrays.
|
|
20
23
|
// find all paths you could use lodash to "get()" to.
|
|
21
24
|
// indexes use `[${index}]`, keys use `.${key}`
|
|
@@ -23,11 +26,16 @@ export function flattenPaths(arrayOrObject, currentPath = "") {
|
|
|
23
26
|
const paths = [];
|
|
24
27
|
const keysOrIndexes = isArray(arrayOrObject);
|
|
25
28
|
const dotOrNot = currentPath ? "." : "";
|
|
29
|
+
if (limit && depth >= limit) {
|
|
30
|
+
return paths;
|
|
31
|
+
}
|
|
26
32
|
if (isObject(arrayOrObject)) {
|
|
27
33
|
for (const [key, value] of Object.entries(arrayOrObject)) {
|
|
28
34
|
const keyPath = keysOrIndexes ? `[${key}]` : `${dotOrNot}${key}`;
|
|
29
35
|
if (isObject(value) || isArray(value)) {
|
|
30
|
-
paths.push(
|
|
36
|
+
paths.push(
|
|
37
|
+
...flattenPaths(value, { currentPath: `${currentPath}${keyPath}`, depth: depth + 1, limit })
|
|
38
|
+
);
|
|
31
39
|
} else {
|
|
32
40
|
paths.push(`${currentPath}${keyPath}`);
|
|
33
41
|
}
|
package/utils/keyDiff.js
CHANGED
|
@@ -55,11 +55,18 @@ export function keyDiff(newKeys, oldKeys, { sameKeys = true, removedKeys = true,
|
|
|
55
55
|
* @param {object} newObj - the new version of the object
|
|
56
56
|
* @param {object} oldObj - the old version of the object
|
|
57
57
|
* @param {KeyDiffOptions} [options] - which differences are returned
|
|
58
|
+
* @param {boolean} [options.sameKeys] - if true, return keys that are the same
|
|
59
|
+
* @param {boolean} [options.removedKeys] - if true, return keys that are removed
|
|
60
|
+
* @param {boolean} [options.addedKeys] - if true, return keys that are added
|
|
61
|
+
* @param {number} [options.limit] - limit the depth of recursion
|
|
58
62
|
* @returns {KeyDiffResult} - the differences
|
|
59
63
|
*/
|
|
60
64
|
export function keyDiffDeep(newObj, oldObj, options = {}) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
const additionalFlattenArgs = [];
|
|
66
|
+
if (options.limit) {
|
|
67
|
+
additionalFlattenArgs.push({ limit: options.limit });
|
|
68
|
+
}
|
|
69
|
+
const newPaths = flattenPaths(newObj, ...additionalFlattenArgs);
|
|
70
|
+
const oldPaths = flattenPaths(oldObj, ...additionalFlattenArgs);
|
|
71
|
+
return keyDiff(newPaths, oldPaths, options);
|
|
65
72
|
}
|