react-native-onyx 3.0.132 → 3.0.134
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/dist/OnyxCache.js +2 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +34 -5
- package/package.json +4 -1
package/dist/OnyxCache.js
CHANGED
|
@@ -22,6 +22,8 @@ const FROZEN_EMPTY_COLLECTION = Object.freeze({});
|
|
|
22
22
|
const CACHE_MERGE_OPTIONS = {
|
|
23
23
|
shouldRemoveNestedNulls: true,
|
|
24
24
|
objectRemovalMode: 'replace',
|
|
25
|
+
// Keeps cached references of deep-equal arrays, so unchanged merges are no-ops.
|
|
26
|
+
shouldKeepEqualArrays: true,
|
|
25
27
|
};
|
|
26
28
|
// Task constants
|
|
27
29
|
const TASK = {
|
package/dist/utils.d.ts
CHANGED
|
@@ -18,6 +18,11 @@ type FastMergeOptions = {
|
|
|
18
18
|
* If set to "replace", we will completely replace the marked objects with the new value instead of merging them.
|
|
19
19
|
*/
|
|
20
20
|
objectRemovalMode?: 'mark' | 'replace' | 'none';
|
|
21
|
+
/**
|
|
22
|
+
* If true, a source array deep-equal to the target array keeps the target reference, so unchanged merges return the target.
|
|
23
|
+
* Arrays inside an object are only compared when nothing else in it changed. Costs a deep comparison per array.
|
|
24
|
+
*/
|
|
25
|
+
shouldKeepEqualArrays?: boolean;
|
|
21
26
|
};
|
|
22
27
|
type FastMergeMetadata = {
|
|
23
28
|
/** The list of tuples that will be used in SQLiteProvider to replace the nested objects using `JSON_REPLACE`. */
|
package/dist/utils.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const fast_equals_1 = require("fast-equals");
|
|
3
4
|
const ONYX_INTERNALS__REPLACE_OBJECT_MARK = 'ONYX_INTERNALS__REPLACE_OBJECT_MARK';
|
|
4
5
|
/**
|
|
5
6
|
* Merges two objects and removes null values if "shouldRemoveNestedNulls" is set to true
|
|
@@ -7,7 +8,7 @@ const ONYX_INTERNALS__REPLACE_OBJECT_MARK = 'ONYX_INTERNALS__REPLACE_OBJECT_MARK
|
|
|
7
8
|
* We generally want to remove null values from objects written to disk and cache, because it decreases the amount of data stored in memory and on disk.
|
|
8
9
|
*/
|
|
9
10
|
function fastMerge(target, source, options, metadata, basePath = []) {
|
|
10
|
-
var _a, _b;
|
|
11
|
+
var _a, _b, _c;
|
|
11
12
|
if (!metadata) {
|
|
12
13
|
// eslint-disable-next-line no-param-reassign
|
|
13
14
|
metadata = {
|
|
@@ -18,11 +19,14 @@ function fastMerge(target, source, options, metadata, basePath = []) {
|
|
|
18
19
|
// otherwise "mergeObject" will throw an error,
|
|
19
20
|
// because it expects an object as "source"
|
|
20
21
|
if (!isMergeableObject(source)) {
|
|
21
|
-
|
|
22
|
+
// Arrays are replaced, not merged, but a deep-equal source array keeps the target reference.
|
|
23
|
+
const result = (options === null || options === void 0 ? void 0 : options.shouldKeepEqualArrays) && areDeepEqualArrays(target, source) ? target : source;
|
|
24
|
+
return { result, replaceNullPatches: metadata.replaceNullPatches };
|
|
22
25
|
}
|
|
23
26
|
const optionsWithDefaults = {
|
|
24
27
|
shouldRemoveNestedNulls: (_a = options === null || options === void 0 ? void 0 : options.shouldRemoveNestedNulls) !== null && _a !== void 0 ? _a : false,
|
|
25
28
|
objectRemovalMode: (_b = options === null || options === void 0 ? void 0 : options.objectRemovalMode) !== null && _b !== void 0 ? _b : 'none',
|
|
29
|
+
shouldKeepEqualArrays: (_c = options === null || options === void 0 ? void 0 : options.shouldKeepEqualArrays) !== null && _c !== void 0 ? _c : false,
|
|
26
30
|
};
|
|
27
31
|
const mergedValue = mergeObject(target, source, optionsWithDefaults, metadata, basePath);
|
|
28
32
|
return { result: mergedValue, replaceNullPatches: metadata.replaceNullPatches };
|
|
@@ -42,6 +46,9 @@ function mergeObject(target, source, options, metadata, basePath) {
|
|
|
42
46
|
// Track whether the merge actually changed anything compared to target.
|
|
43
47
|
// If nothing changed, we return the original target reference for reference stability.
|
|
44
48
|
let hasChanged = !targetObject;
|
|
49
|
+
// Keys whose array was replaced. Compared at the end, and only if nothing else changed,
|
|
50
|
+
// since any other change gives the object a new reference anyway.
|
|
51
|
+
let replacedArrayKeys;
|
|
45
52
|
// First we want to copy over all keys from the target into the destination object,
|
|
46
53
|
// in case "target" is a mergable object.
|
|
47
54
|
// If "shouldRemoveNestedNulls" is true, we want to remove null values from the merged object
|
|
@@ -72,8 +79,15 @@ function mergeObject(target, source, options, metadata, basePath) {
|
|
|
72
79
|
}
|
|
73
80
|
// If the source value is not a mergable object, we need to set the key directly.
|
|
74
81
|
if (!isMergeableObject(sourceProperty)) {
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
const destinationProperty = destination[key];
|
|
83
|
+
if (destinationProperty !== sourceProperty) {
|
|
84
|
+
if (options.shouldKeepEqualArrays && !hasChanged && Array.isArray(destinationProperty) && Array.isArray(sourceProperty)) {
|
|
85
|
+
replacedArrayKeys !== null && replacedArrayKeys !== void 0 ? replacedArrayKeys : (replacedArrayKeys = []);
|
|
86
|
+
replacedArrayKeys.push(key);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
hasChanged = true;
|
|
90
|
+
}
|
|
77
91
|
}
|
|
78
92
|
destination[key] = sourceProperty;
|
|
79
93
|
continue;
|
|
@@ -105,7 +119,18 @@ function mergeObject(target, source, options, metadata, basePath) {
|
|
|
105
119
|
}
|
|
106
120
|
destination[key] = merged;
|
|
107
121
|
}
|
|
108
|
-
|
|
122
|
+
if (hasChanged) {
|
|
123
|
+
return destination;
|
|
124
|
+
}
|
|
125
|
+
// Only arrays were replaced. If they are all deep-equal, the merge is a no-op.
|
|
126
|
+
if (replacedArrayKeys) {
|
|
127
|
+
for (const key of replacedArrayKeys) {
|
|
128
|
+
if (!(0, fast_equals_1.deepEqual)(targetObject === null || targetObject === void 0 ? void 0 : targetObject[key], destination[key])) {
|
|
129
|
+
return destination;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return targetObject;
|
|
109
134
|
}
|
|
110
135
|
/** Checks whether the given object is an object and not null/undefined. */
|
|
111
136
|
function isEmptyObject(obj) {
|
|
@@ -129,6 +154,10 @@ function isMergeableObject(value) {
|
|
|
129
154
|
const isNonNullObject = value != null ? typeof value === 'object' : false;
|
|
130
155
|
return isNonNullObject && !(value instanceof RegExp) && !(value instanceof Date) && !Array.isArray(value);
|
|
131
156
|
}
|
|
157
|
+
/** Checks whether both values are arrays with deep-equal contents. */
|
|
158
|
+
function areDeepEqualArrays(a, b) {
|
|
159
|
+
return Array.isArray(a) && Array.isArray(b) && (0, fast_equals_1.deepEqual)(a, b);
|
|
160
|
+
}
|
|
132
161
|
/**
|
|
133
162
|
* Reports whether a value needs cleaning (nested null/undefined, or the replace-object mark) before it's
|
|
134
163
|
* safe to store by reference. Read-only, non-allocating.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-onyx",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.134",
|
|
4
4
|
"author": "Expensify, Inc.",
|
|
5
5
|
"homepage": "https://expensify.com",
|
|
6
6
|
"description": "State management for React Native",
|
|
@@ -126,6 +126,9 @@
|
|
|
126
126
|
"optional": true
|
|
127
127
|
}
|
|
128
128
|
},
|
|
129
|
+
"overrides": {
|
|
130
|
+
"simple-git": "^4.0.2"
|
|
131
|
+
},
|
|
129
132
|
"engines": {
|
|
130
133
|
"node": ">=20.19.5",
|
|
131
134
|
"npm": ">=10.8.2"
|