react-jitter 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/package.json +1 -1
- package/runtime/dist/index.d.mts +3 -0
- package/runtime/dist/index.d.ts +3 -0
- package/runtime/dist/index.js +448 -13
- package/runtime/dist/index.mjs +448 -13
package/README.md
CHANGED
|
@@ -128,6 +128,44 @@ window.reactJitter.onRender = (render) => {
|
|
|
128
128
|
|
|
129
129
|
Modern bundlers will tree-shake the `import` and the function call from your production build, so it will have zero performance impact.
|
|
130
130
|
|
|
131
|
+
### Advanced: Custom Comparator Selection
|
|
132
|
+
|
|
133
|
+
By default, React Jitter uses the `deepEqual` comparator to detect changes in hook values. However, you can customize which comparator is used on a per-hook basis using the `selectComparator` function. This is useful when dealing with circular data structures or when you need different comparison strategies for different hooks.
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
// Set a custom comparator selector
|
|
137
|
+
window.reactJitter.selectComparator = (hookAddress) => {
|
|
138
|
+
// Use circularDeepEqual for hooks that might return circular structures
|
|
139
|
+
if (hookAddress.hook === 'useSelector' || hookAddress.hook === 'useReduxState') {
|
|
140
|
+
return 'circularDeepEqual';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Use deepEqual for everything else (default)
|
|
144
|
+
return 'deepEqual';
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The `hookAddress` parameter contains information about the hook:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
{
|
|
152
|
+
hook: string; // Hook name, e.g., "useState", "useContext"
|
|
153
|
+
file: string; // File path where the hook is called
|
|
154
|
+
line: number; // Line number
|
|
155
|
+
offset: number; // Column offset
|
|
156
|
+
arguments?: string[]; // Hook arguments (if includeArguments is enabled)
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Available Comparators:**
|
|
161
|
+
|
|
162
|
+
- `deepEqual` (default): Fast deep equality check that handles most cases. Will throw an error if it encounters deeply nested or circular structures.
|
|
163
|
+
- `circularDeepEqual`: Slower but handles circular references safely. Use this when your hooks return data with circular dependencies or extremely deep nesting.
|
|
164
|
+
|
|
165
|
+
**When to Use `circularDeepEqual`:**
|
|
166
|
+
|
|
167
|
+
If you see an error like "Maximum call stack size exceeded. Please use the 'circularDeepEqual' comparator", you should configure `selectComparator` to return `'circularDeepEqual'` for the specific hook mentioned in the error message.
|
|
168
|
+
|
|
131
169
|
## API and Configuration
|
|
132
170
|
|
|
133
171
|
The `reactJitter` function accepts a configuration object with two callbacks: `onHookChange` and `onRender`.
|
package/package.json
CHANGED
package/runtime/dist/index.d.mts
CHANGED
|
@@ -41,6 +41,7 @@ type HookEndEvent = {
|
|
|
41
41
|
offset: number;
|
|
42
42
|
arguments?: string[];
|
|
43
43
|
};
|
|
44
|
+
type HookAddress = Pick<HookEndEvent, 'hook' | 'file' | 'line' | 'offset' | 'arguments'>;
|
|
44
45
|
type ReactJitterOptions = {
|
|
45
46
|
enabled?: boolean;
|
|
46
47
|
onHookChange?: (change: HookChange) => void;
|
|
@@ -51,6 +52,7 @@ type ReactJitterOptions = {
|
|
|
51
52
|
}) => void;
|
|
52
53
|
};
|
|
53
54
|
type Scope = z.infer<typeof ScopeSchema>;
|
|
55
|
+
type Comparator = 'deepEqual' | 'circularDeepEqual';
|
|
54
56
|
|
|
55
57
|
type HookCall = HookChange & HookEndEvent & {
|
|
56
58
|
scope: Scope;
|
|
@@ -62,6 +64,7 @@ declare global {
|
|
|
62
64
|
reactJitter?: {
|
|
63
65
|
enabled?: boolean;
|
|
64
66
|
onHookChange?: (change: HookCall) => void;
|
|
67
|
+
selectComparator?: (hookAddress: HookAddress) => Comparator;
|
|
65
68
|
onRender?: (scope: Scope & {
|
|
66
69
|
hookResults: Record<string, unknown>;
|
|
67
70
|
renderCount: number;
|
package/runtime/dist/index.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ type HookEndEvent = {
|
|
|
41
41
|
offset: number;
|
|
42
42
|
arguments?: string[];
|
|
43
43
|
};
|
|
44
|
+
type HookAddress = Pick<HookEndEvent, 'hook' | 'file' | 'line' | 'offset' | 'arguments'>;
|
|
44
45
|
type ReactJitterOptions = {
|
|
45
46
|
enabled?: boolean;
|
|
46
47
|
onHookChange?: (change: HookChange) => void;
|
|
@@ -51,6 +52,7 @@ type ReactJitterOptions = {
|
|
|
51
52
|
}) => void;
|
|
52
53
|
};
|
|
53
54
|
type Scope = z.infer<typeof ScopeSchema>;
|
|
55
|
+
type Comparator = 'deepEqual' | 'circularDeepEqual';
|
|
54
56
|
|
|
55
57
|
type HookCall = HookChange & HookEndEvent & {
|
|
56
58
|
scope: Scope;
|
|
@@ -62,6 +64,7 @@ declare global {
|
|
|
62
64
|
reactJitter?: {
|
|
63
65
|
enabled?: boolean;
|
|
64
66
|
onHookChange?: (change: HookCall) => void;
|
|
67
|
+
selectComparator?: (hookAddress: HookAddress) => Comparator;
|
|
65
68
|
onRender?: (scope: Scope & {
|
|
66
69
|
hookResults: Record<string, unknown>;
|
|
67
70
|
renderCount: number;
|
package/runtime/dist/index.js
CHANGED
|
@@ -36,9 +36,419 @@ __export(index_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
var import_react = __toESM(require("react"));
|
|
38
38
|
|
|
39
|
+
// ../node_modules/fast-equals/dist/esm/index.mjs
|
|
40
|
+
var getOwnPropertyNames = Object.getOwnPropertyNames;
|
|
41
|
+
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
|
|
42
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
43
|
+
function combineComparators(comparatorA, comparatorB) {
|
|
44
|
+
return function isEqual(a, b, state) {
|
|
45
|
+
return comparatorA(a, b, state) && comparatorB(a, b, state);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function createIsCircular(areItemsEqual) {
|
|
49
|
+
return function isCircular(a, b, state) {
|
|
50
|
+
if (!a || !b || typeof a !== "object" || typeof b !== "object") {
|
|
51
|
+
return areItemsEqual(a, b, state);
|
|
52
|
+
}
|
|
53
|
+
var cache = state.cache;
|
|
54
|
+
var cachedA = cache.get(a);
|
|
55
|
+
var cachedB = cache.get(b);
|
|
56
|
+
if (cachedA && cachedB) {
|
|
57
|
+
return cachedA === b && cachedB === a;
|
|
58
|
+
}
|
|
59
|
+
cache.set(a, b);
|
|
60
|
+
cache.set(b, a);
|
|
61
|
+
var result = areItemsEqual(a, b, state);
|
|
62
|
+
cache.delete(a);
|
|
63
|
+
cache.delete(b);
|
|
64
|
+
return result;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function getStrictProperties(object) {
|
|
68
|
+
return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
|
|
69
|
+
}
|
|
70
|
+
var hasOwn = Object.hasOwn || function(object, property) {
|
|
71
|
+
return hasOwnProperty.call(object, property);
|
|
72
|
+
};
|
|
73
|
+
function sameValueZeroEqual(a, b) {
|
|
74
|
+
return a === b || !a && !b && a !== a && b !== b;
|
|
75
|
+
}
|
|
76
|
+
var PREACT_VNODE = "__v";
|
|
77
|
+
var PREACT_OWNER = "__o";
|
|
78
|
+
var REACT_OWNER = "_owner";
|
|
79
|
+
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
80
|
+
var keys = Object.keys;
|
|
81
|
+
function areArraysEqual(a, b, state) {
|
|
82
|
+
var index = a.length;
|
|
83
|
+
if (b.length !== index) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
while (index-- > 0) {
|
|
87
|
+
if (!state.equals(a[index], b[index], index, index, a, b, state)) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
function areDatesEqual(a, b) {
|
|
94
|
+
return sameValueZeroEqual(a.getTime(), b.getTime());
|
|
95
|
+
}
|
|
96
|
+
function areErrorsEqual(a, b) {
|
|
97
|
+
return a.name === b.name && a.message === b.message && a.cause === b.cause && a.stack === b.stack;
|
|
98
|
+
}
|
|
99
|
+
function areFunctionsEqual(a, b) {
|
|
100
|
+
return a === b;
|
|
101
|
+
}
|
|
102
|
+
function areMapsEqual(a, b, state) {
|
|
103
|
+
var size = a.size;
|
|
104
|
+
if (size !== b.size) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
if (!size) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
var matchedIndices = new Array(size);
|
|
111
|
+
var aIterable = a.entries();
|
|
112
|
+
var aResult;
|
|
113
|
+
var bResult;
|
|
114
|
+
var index = 0;
|
|
115
|
+
while (aResult = aIterable.next()) {
|
|
116
|
+
if (aResult.done) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
var bIterable = b.entries();
|
|
120
|
+
var hasMatch = false;
|
|
121
|
+
var matchIndex = 0;
|
|
122
|
+
while (bResult = bIterable.next()) {
|
|
123
|
+
if (bResult.done) {
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
if (matchedIndices[matchIndex]) {
|
|
127
|
+
matchIndex++;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
var aEntry = aResult.value;
|
|
131
|
+
var bEntry = bResult.value;
|
|
132
|
+
if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a, b, state) && state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a, b, state)) {
|
|
133
|
+
hasMatch = matchedIndices[matchIndex] = true;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
matchIndex++;
|
|
137
|
+
}
|
|
138
|
+
if (!hasMatch) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
index++;
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
var areNumbersEqual = sameValueZeroEqual;
|
|
146
|
+
function areObjectsEqual(a, b, state) {
|
|
147
|
+
var properties = keys(a);
|
|
148
|
+
var index = properties.length;
|
|
149
|
+
if (keys(b).length !== index) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
while (index-- > 0) {
|
|
153
|
+
if (!isPropertyEqual(a, b, state, properties[index])) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
function areObjectsEqualStrict(a, b, state) {
|
|
160
|
+
var properties = getStrictProperties(a);
|
|
161
|
+
var index = properties.length;
|
|
162
|
+
if (getStrictProperties(b).length !== index) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
var property;
|
|
166
|
+
var descriptorA;
|
|
167
|
+
var descriptorB;
|
|
168
|
+
while (index-- > 0) {
|
|
169
|
+
property = properties[index];
|
|
170
|
+
if (!isPropertyEqual(a, b, state, property)) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
descriptorA = getOwnPropertyDescriptor(a, property);
|
|
174
|
+
descriptorB = getOwnPropertyDescriptor(b, property);
|
|
175
|
+
if ((descriptorA || descriptorB) && (!descriptorA || !descriptorB || descriptorA.configurable !== descriptorB.configurable || descriptorA.enumerable !== descriptorB.enumerable || descriptorA.writable !== descriptorB.writable)) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
function arePrimitiveWrappersEqual(a, b) {
|
|
182
|
+
return sameValueZeroEqual(a.valueOf(), b.valueOf());
|
|
183
|
+
}
|
|
184
|
+
function areRegExpsEqual(a, b) {
|
|
185
|
+
return a.source === b.source && a.flags === b.flags;
|
|
186
|
+
}
|
|
187
|
+
function areSetsEqual(a, b, state) {
|
|
188
|
+
var size = a.size;
|
|
189
|
+
if (size !== b.size) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
if (!size) {
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
var matchedIndices = new Array(size);
|
|
196
|
+
var aIterable = a.values();
|
|
197
|
+
var aResult;
|
|
198
|
+
var bResult;
|
|
199
|
+
while (aResult = aIterable.next()) {
|
|
200
|
+
if (aResult.done) {
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
var bIterable = b.values();
|
|
204
|
+
var hasMatch = false;
|
|
205
|
+
var matchIndex = 0;
|
|
206
|
+
while (bResult = bIterable.next()) {
|
|
207
|
+
if (bResult.done) {
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
if (!matchedIndices[matchIndex] && state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state)) {
|
|
211
|
+
hasMatch = matchedIndices[matchIndex] = true;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
matchIndex++;
|
|
215
|
+
}
|
|
216
|
+
if (!hasMatch) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
function areTypedArraysEqual(a, b) {
|
|
223
|
+
var index = a.length;
|
|
224
|
+
if (b.length !== index) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
while (index-- > 0) {
|
|
228
|
+
if (a[index] !== b[index]) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
function areUrlsEqual(a, b) {
|
|
235
|
+
return a.hostname === b.hostname && a.pathname === b.pathname && a.protocol === b.protocol && a.port === b.port && a.hash === b.hash && a.username === b.username && a.password === b.password;
|
|
236
|
+
}
|
|
237
|
+
function isPropertyEqual(a, b, state, property) {
|
|
238
|
+
if ((property === REACT_OWNER || property === PREACT_OWNER || property === PREACT_VNODE) && (a.$$typeof || b.$$typeof)) {
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
return hasOwn(b, property) && state.equals(a[property], b[property], property, property, a, b, state);
|
|
242
|
+
}
|
|
243
|
+
var ARGUMENTS_TAG = "[object Arguments]";
|
|
244
|
+
var BOOLEAN_TAG = "[object Boolean]";
|
|
245
|
+
var DATE_TAG = "[object Date]";
|
|
246
|
+
var ERROR_TAG = "[object Error]";
|
|
247
|
+
var MAP_TAG = "[object Map]";
|
|
248
|
+
var NUMBER_TAG = "[object Number]";
|
|
249
|
+
var OBJECT_TAG = "[object Object]";
|
|
250
|
+
var REG_EXP_TAG = "[object RegExp]";
|
|
251
|
+
var SET_TAG = "[object Set]";
|
|
252
|
+
var STRING_TAG = "[object String]";
|
|
253
|
+
var URL_TAG = "[object URL]";
|
|
254
|
+
var isArray = Array.isArray;
|
|
255
|
+
var isTypedArray = typeof ArrayBuffer === "function" && ArrayBuffer.isView ? ArrayBuffer.isView : null;
|
|
256
|
+
var assign = Object.assign;
|
|
257
|
+
var getTag = Object.prototype.toString.call.bind(Object.prototype.toString);
|
|
258
|
+
function createEqualityComparator(_a) {
|
|
259
|
+
var areArraysEqual2 = _a.areArraysEqual, areDatesEqual2 = _a.areDatesEqual, areErrorsEqual2 = _a.areErrorsEqual, areFunctionsEqual2 = _a.areFunctionsEqual, areMapsEqual2 = _a.areMapsEqual, areNumbersEqual2 = _a.areNumbersEqual, areObjectsEqual2 = _a.areObjectsEqual, arePrimitiveWrappersEqual2 = _a.arePrimitiveWrappersEqual, areRegExpsEqual2 = _a.areRegExpsEqual, areSetsEqual2 = _a.areSetsEqual, areTypedArraysEqual2 = _a.areTypedArraysEqual, areUrlsEqual2 = _a.areUrlsEqual;
|
|
260
|
+
return function comparator(a, b, state) {
|
|
261
|
+
if (a === b) {
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
if (a == null || b == null) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
var type = typeof a;
|
|
268
|
+
if (type !== typeof b) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
if (type !== "object") {
|
|
272
|
+
if (type === "number") {
|
|
273
|
+
return areNumbersEqual2(a, b, state);
|
|
274
|
+
}
|
|
275
|
+
if (type === "function") {
|
|
276
|
+
return areFunctionsEqual2(a, b, state);
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
var constructor = a.constructor;
|
|
281
|
+
if (constructor !== b.constructor) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
if (constructor === Object) {
|
|
285
|
+
return areObjectsEqual2(a, b, state);
|
|
286
|
+
}
|
|
287
|
+
if (isArray(a)) {
|
|
288
|
+
return areArraysEqual2(a, b, state);
|
|
289
|
+
}
|
|
290
|
+
if (isTypedArray != null && isTypedArray(a)) {
|
|
291
|
+
return areTypedArraysEqual2(a, b, state);
|
|
292
|
+
}
|
|
293
|
+
if (constructor === Date) {
|
|
294
|
+
return areDatesEqual2(a, b, state);
|
|
295
|
+
}
|
|
296
|
+
if (constructor === RegExp) {
|
|
297
|
+
return areRegExpsEqual2(a, b, state);
|
|
298
|
+
}
|
|
299
|
+
if (constructor === Map) {
|
|
300
|
+
return areMapsEqual2(a, b, state);
|
|
301
|
+
}
|
|
302
|
+
if (constructor === Set) {
|
|
303
|
+
return areSetsEqual2(a, b, state);
|
|
304
|
+
}
|
|
305
|
+
var tag = getTag(a);
|
|
306
|
+
if (tag === DATE_TAG) {
|
|
307
|
+
return areDatesEqual2(a, b, state);
|
|
308
|
+
}
|
|
309
|
+
if (tag === REG_EXP_TAG) {
|
|
310
|
+
return areRegExpsEqual2(a, b, state);
|
|
311
|
+
}
|
|
312
|
+
if (tag === MAP_TAG) {
|
|
313
|
+
return areMapsEqual2(a, b, state);
|
|
314
|
+
}
|
|
315
|
+
if (tag === SET_TAG) {
|
|
316
|
+
return areSetsEqual2(a, b, state);
|
|
317
|
+
}
|
|
318
|
+
if (tag === OBJECT_TAG) {
|
|
319
|
+
return typeof a.then !== "function" && typeof b.then !== "function" && areObjectsEqual2(a, b, state);
|
|
320
|
+
}
|
|
321
|
+
if (tag === URL_TAG) {
|
|
322
|
+
return areUrlsEqual2(a, b, state);
|
|
323
|
+
}
|
|
324
|
+
if (tag === ERROR_TAG) {
|
|
325
|
+
return areErrorsEqual2(a, b, state);
|
|
326
|
+
}
|
|
327
|
+
if (tag === ARGUMENTS_TAG) {
|
|
328
|
+
return areObjectsEqual2(a, b, state);
|
|
329
|
+
}
|
|
330
|
+
if (tag === BOOLEAN_TAG || tag === NUMBER_TAG || tag === STRING_TAG) {
|
|
331
|
+
return arePrimitiveWrappersEqual2(a, b, state);
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function createEqualityComparatorConfig(_a) {
|
|
337
|
+
var circular = _a.circular, createCustomConfig = _a.createCustomConfig, strict = _a.strict;
|
|
338
|
+
var config = {
|
|
339
|
+
areArraysEqual: strict ? areObjectsEqualStrict : areArraysEqual,
|
|
340
|
+
areDatesEqual,
|
|
341
|
+
areErrorsEqual,
|
|
342
|
+
areFunctionsEqual,
|
|
343
|
+
areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
|
|
344
|
+
areNumbersEqual,
|
|
345
|
+
areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
|
|
346
|
+
arePrimitiveWrappersEqual,
|
|
347
|
+
areRegExpsEqual,
|
|
348
|
+
areSetsEqual: strict ? combineComparators(areSetsEqual, areObjectsEqualStrict) : areSetsEqual,
|
|
349
|
+
areTypedArraysEqual: strict ? areObjectsEqualStrict : areTypedArraysEqual,
|
|
350
|
+
areUrlsEqual
|
|
351
|
+
};
|
|
352
|
+
if (createCustomConfig) {
|
|
353
|
+
config = assign({}, config, createCustomConfig(config));
|
|
354
|
+
}
|
|
355
|
+
if (circular) {
|
|
356
|
+
var areArraysEqual$1 = createIsCircular(config.areArraysEqual);
|
|
357
|
+
var areMapsEqual$1 = createIsCircular(config.areMapsEqual);
|
|
358
|
+
var areObjectsEqual$1 = createIsCircular(config.areObjectsEqual);
|
|
359
|
+
var areSetsEqual$1 = createIsCircular(config.areSetsEqual);
|
|
360
|
+
config = assign({}, config, {
|
|
361
|
+
areArraysEqual: areArraysEqual$1,
|
|
362
|
+
areMapsEqual: areMapsEqual$1,
|
|
363
|
+
areObjectsEqual: areObjectsEqual$1,
|
|
364
|
+
areSetsEqual: areSetsEqual$1
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return config;
|
|
368
|
+
}
|
|
369
|
+
function createInternalEqualityComparator(compare) {
|
|
370
|
+
return function(a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, state) {
|
|
371
|
+
return compare(a, b, state);
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function createIsEqual(_a) {
|
|
375
|
+
var circular = _a.circular, comparator = _a.comparator, createState = _a.createState, equals = _a.equals, strict = _a.strict;
|
|
376
|
+
if (createState) {
|
|
377
|
+
return function isEqual(a, b) {
|
|
378
|
+
var _a2 = createState(), _b = _a2.cache, cache = _b === void 0 ? circular ? /* @__PURE__ */ new WeakMap() : void 0 : _b, meta = _a2.meta;
|
|
379
|
+
return comparator(a, b, {
|
|
380
|
+
cache,
|
|
381
|
+
equals,
|
|
382
|
+
meta,
|
|
383
|
+
strict
|
|
384
|
+
});
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
if (circular) {
|
|
388
|
+
return function isEqual(a, b) {
|
|
389
|
+
return comparator(a, b, {
|
|
390
|
+
cache: /* @__PURE__ */ new WeakMap(),
|
|
391
|
+
equals,
|
|
392
|
+
meta: void 0,
|
|
393
|
+
strict
|
|
394
|
+
});
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
var state = {
|
|
398
|
+
cache: void 0,
|
|
399
|
+
equals,
|
|
400
|
+
meta: void 0,
|
|
401
|
+
strict
|
|
402
|
+
};
|
|
403
|
+
return function isEqual(a, b) {
|
|
404
|
+
return comparator(a, b, state);
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
var deepEqual = createCustomEqual();
|
|
408
|
+
var strictDeepEqual = createCustomEqual({ strict: true });
|
|
409
|
+
var circularDeepEqual = createCustomEqual({ circular: true });
|
|
410
|
+
var strictCircularDeepEqual = createCustomEqual({
|
|
411
|
+
circular: true,
|
|
412
|
+
strict: true
|
|
413
|
+
});
|
|
414
|
+
var shallowEqual = createCustomEqual({
|
|
415
|
+
createInternalComparator: function() {
|
|
416
|
+
return sameValueZeroEqual;
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
var strictShallowEqual = createCustomEqual({
|
|
420
|
+
strict: true,
|
|
421
|
+
createInternalComparator: function() {
|
|
422
|
+
return sameValueZeroEqual;
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
var circularShallowEqual = createCustomEqual({
|
|
426
|
+
circular: true,
|
|
427
|
+
createInternalComparator: function() {
|
|
428
|
+
return sameValueZeroEqual;
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
var strictCircularShallowEqual = createCustomEqual({
|
|
432
|
+
circular: true,
|
|
433
|
+
createInternalComparator: function() {
|
|
434
|
+
return sameValueZeroEqual;
|
|
435
|
+
},
|
|
436
|
+
strict: true
|
|
437
|
+
});
|
|
438
|
+
function createCustomEqual(options) {
|
|
439
|
+
if (options === void 0) {
|
|
440
|
+
options = {};
|
|
441
|
+
}
|
|
442
|
+
var _a = options.circular, circular = _a === void 0 ? false : _a, createCustomInternalComparator = options.createInternalComparator, createState = options.createState, _b = options.strict, strict = _b === void 0 ? false : _b;
|
|
443
|
+
var config = createEqualityComparatorConfig(options);
|
|
444
|
+
var comparator = createEqualityComparator(config);
|
|
445
|
+
var equals = createCustomInternalComparator ? createCustomInternalComparator(comparator) : createInternalEqualityComparator(comparator);
|
|
446
|
+
return createIsEqual({ circular, comparator, createState, equals, strict });
|
|
447
|
+
}
|
|
448
|
+
|
|
39
449
|
// src/utils/getChanges.ts
|
|
40
|
-
|
|
41
|
-
|
|
450
|
+
function getChanges(prev, next, comparator = "deepEqual") {
|
|
451
|
+
const equals = comparator === "circularDeepEqual" ? circularDeepEqual : deepEqual;
|
|
42
452
|
const changedKeys = [];
|
|
43
453
|
const unstableKeys = [];
|
|
44
454
|
const isObject = (v) => v !== null && typeof v === "object";
|
|
@@ -57,7 +467,7 @@ function getChanges(prev, next) {
|
|
|
57
467
|
}
|
|
58
468
|
const max = Math.max(prev.length, next.length);
|
|
59
469
|
for (let i = 0; i < max; i++) {
|
|
60
|
-
const deepEqItem = (
|
|
470
|
+
const deepEqItem = equals(prev[i], next[i]);
|
|
61
471
|
const refDiffItem = isObject(prev[i]) && isObject(next[i]) && prev[i] !== next[i];
|
|
62
472
|
if (!deepEqItem || refDiffItem) {
|
|
63
473
|
const key = String(i);
|
|
@@ -70,7 +480,7 @@ function getChanges(prev, next) {
|
|
|
70
480
|
} else if (isObject(prev) && isObject(next)) {
|
|
71
481
|
const allKeys = /* @__PURE__ */ new Set([...Object.keys(prev), ...Object.keys(next)]);
|
|
72
482
|
for (const key of allKeys) {
|
|
73
|
-
const deepEqProp = (
|
|
483
|
+
const deepEqProp = equals(prev[key], next[key]);
|
|
74
484
|
const refDiffProp = isObject(prev[key]) && isObject(next[key]) && prev[key] !== next[key];
|
|
75
485
|
if (!deepEqProp || refDiffProp) {
|
|
76
486
|
changedKeys.push(key);
|
|
@@ -80,7 +490,7 @@ function getChanges(prev, next) {
|
|
|
80
490
|
}
|
|
81
491
|
}
|
|
82
492
|
} else {
|
|
83
|
-
const deepEqRoot = (
|
|
493
|
+
const deepEqRoot = equals(prev, next);
|
|
84
494
|
const refDiffRoot = isObject(prev) && isObject(next) && prev !== next;
|
|
85
495
|
const unstable = refDiffRoot && deepEqRoot;
|
|
86
496
|
const changed = !deepEqRoot || refDiffRoot;
|
|
@@ -91,7 +501,7 @@ function getChanges(prev, next) {
|
|
|
91
501
|
};
|
|
92
502
|
}
|
|
93
503
|
const isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
94
|
-
const unstableRoot = isPlainObject(prev) && isPlainObject(next) && prev !== next && (
|
|
504
|
+
const unstableRoot = isPlainObject(prev) && isPlainObject(next) && prev !== next && equals(prev, next);
|
|
95
505
|
if (unstableRoot && changedKeys.length === 0) {
|
|
96
506
|
changedKeys.push("");
|
|
97
507
|
unstableKeys.push("");
|
|
@@ -103,6 +513,31 @@ function getChanges(prev, next) {
|
|
|
103
513
|
};
|
|
104
514
|
}
|
|
105
515
|
|
|
516
|
+
// src/utils/compareChanges.ts
|
|
517
|
+
function compareChanges(hookAddress, prev, current) {
|
|
518
|
+
var _a, _b, _c;
|
|
519
|
+
if (prev !== "undefined" && prev !== current) {
|
|
520
|
+
const comparator = (_c = (_b = (_a = window == null ? void 0 : window.reactJitter) == null ? void 0 : _a.selectComparator) == null ? void 0 : _b.call(_a, hookAddress)) != null ? _c : "deepEqual";
|
|
521
|
+
try {
|
|
522
|
+
return getChanges(prev, current, comparator);
|
|
523
|
+
} catch (error) {
|
|
524
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
525
|
+
const isRecursionError = /(?:maximum call stack(?: size)? exceeded|too much recursion|stack overflow)/i.test(
|
|
526
|
+
errorMessage
|
|
527
|
+
);
|
|
528
|
+
if (isRecursionError && comparator !== "circularDeepEqual") {
|
|
529
|
+
throw new Error(
|
|
530
|
+
`Maximum call stack size exceeded. Please use the "circularDeepEqual" comparator with selectComparator option.
|
|
531
|
+
Hook address: ${JSON.stringify(hookAddress, null, 2)}.`,
|
|
532
|
+
{ cause: error }
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
throw error;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
|
|
106
541
|
// src/index.ts
|
|
107
542
|
var scopes = {};
|
|
108
543
|
var hookStack = /* @__PURE__ */ new Map();
|
|
@@ -135,7 +570,13 @@ function useJitterScope(scope) {
|
|
|
135
570
|
const hookId = `${scopeId}-${hookEndEvent.id}`;
|
|
136
571
|
if (shouldReportChanges()) {
|
|
137
572
|
const prevResult = currentScope.hookResults[hookId];
|
|
138
|
-
const
|
|
573
|
+
const hookAddress = {
|
|
574
|
+
hook: hookEndEvent.hook,
|
|
575
|
+
file: hookEndEvent.file,
|
|
576
|
+
line: hookEndEvent.line,
|
|
577
|
+
offset: hookEndEvent.offset
|
|
578
|
+
};
|
|
579
|
+
const changes = compareChanges(hookAddress, prevResult, hookResult);
|
|
139
580
|
if (changes) {
|
|
140
581
|
const hookCall = {
|
|
141
582
|
hook: hookEndEvent.hook,
|
|
@@ -212,12 +653,6 @@ function getScopeCount(scope) {
|
|
|
212
653
|
}
|
|
213
654
|
return scopeCounter[scope.id]++;
|
|
214
655
|
}
|
|
215
|
-
function compareChanges(prev, current) {
|
|
216
|
-
if (prev !== "undefined" && prev !== current) {
|
|
217
|
-
return getChanges(prev, current);
|
|
218
|
-
}
|
|
219
|
-
return null;
|
|
220
|
-
}
|
|
221
656
|
// Annotate the CommonJS export names for ESM import in node:
|
|
222
657
|
0 && (module.exports = {
|
|
223
658
|
reactJitter,
|
package/runtime/dist/index.mjs
CHANGED
|
@@ -1,9 +1,419 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import React from "react";
|
|
3
3
|
|
|
4
|
+
// ../node_modules/fast-equals/dist/esm/index.mjs
|
|
5
|
+
var getOwnPropertyNames = Object.getOwnPropertyNames;
|
|
6
|
+
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
|
|
7
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
8
|
+
function combineComparators(comparatorA, comparatorB) {
|
|
9
|
+
return function isEqual(a, b, state) {
|
|
10
|
+
return comparatorA(a, b, state) && comparatorB(a, b, state);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function createIsCircular(areItemsEqual) {
|
|
14
|
+
return function isCircular(a, b, state) {
|
|
15
|
+
if (!a || !b || typeof a !== "object" || typeof b !== "object") {
|
|
16
|
+
return areItemsEqual(a, b, state);
|
|
17
|
+
}
|
|
18
|
+
var cache = state.cache;
|
|
19
|
+
var cachedA = cache.get(a);
|
|
20
|
+
var cachedB = cache.get(b);
|
|
21
|
+
if (cachedA && cachedB) {
|
|
22
|
+
return cachedA === b && cachedB === a;
|
|
23
|
+
}
|
|
24
|
+
cache.set(a, b);
|
|
25
|
+
cache.set(b, a);
|
|
26
|
+
var result = areItemsEqual(a, b, state);
|
|
27
|
+
cache.delete(a);
|
|
28
|
+
cache.delete(b);
|
|
29
|
+
return result;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function getStrictProperties(object) {
|
|
33
|
+
return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
|
|
34
|
+
}
|
|
35
|
+
var hasOwn = Object.hasOwn || function(object, property) {
|
|
36
|
+
return hasOwnProperty.call(object, property);
|
|
37
|
+
};
|
|
38
|
+
function sameValueZeroEqual(a, b) {
|
|
39
|
+
return a === b || !a && !b && a !== a && b !== b;
|
|
40
|
+
}
|
|
41
|
+
var PREACT_VNODE = "__v";
|
|
42
|
+
var PREACT_OWNER = "__o";
|
|
43
|
+
var REACT_OWNER = "_owner";
|
|
44
|
+
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
45
|
+
var keys = Object.keys;
|
|
46
|
+
function areArraysEqual(a, b, state) {
|
|
47
|
+
var index = a.length;
|
|
48
|
+
if (b.length !== index) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
while (index-- > 0) {
|
|
52
|
+
if (!state.equals(a[index], b[index], index, index, a, b, state)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
function areDatesEqual(a, b) {
|
|
59
|
+
return sameValueZeroEqual(a.getTime(), b.getTime());
|
|
60
|
+
}
|
|
61
|
+
function areErrorsEqual(a, b) {
|
|
62
|
+
return a.name === b.name && a.message === b.message && a.cause === b.cause && a.stack === b.stack;
|
|
63
|
+
}
|
|
64
|
+
function areFunctionsEqual(a, b) {
|
|
65
|
+
return a === b;
|
|
66
|
+
}
|
|
67
|
+
function areMapsEqual(a, b, state) {
|
|
68
|
+
var size = a.size;
|
|
69
|
+
if (size !== b.size) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
if (!size) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
var matchedIndices = new Array(size);
|
|
76
|
+
var aIterable = a.entries();
|
|
77
|
+
var aResult;
|
|
78
|
+
var bResult;
|
|
79
|
+
var index = 0;
|
|
80
|
+
while (aResult = aIterable.next()) {
|
|
81
|
+
if (aResult.done) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
var bIterable = b.entries();
|
|
85
|
+
var hasMatch = false;
|
|
86
|
+
var matchIndex = 0;
|
|
87
|
+
while (bResult = bIterable.next()) {
|
|
88
|
+
if (bResult.done) {
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
if (matchedIndices[matchIndex]) {
|
|
92
|
+
matchIndex++;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
var aEntry = aResult.value;
|
|
96
|
+
var bEntry = bResult.value;
|
|
97
|
+
if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a, b, state) && state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a, b, state)) {
|
|
98
|
+
hasMatch = matchedIndices[matchIndex] = true;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
matchIndex++;
|
|
102
|
+
}
|
|
103
|
+
if (!hasMatch) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
index++;
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
var areNumbersEqual = sameValueZeroEqual;
|
|
111
|
+
function areObjectsEqual(a, b, state) {
|
|
112
|
+
var properties = keys(a);
|
|
113
|
+
var index = properties.length;
|
|
114
|
+
if (keys(b).length !== index) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
while (index-- > 0) {
|
|
118
|
+
if (!isPropertyEqual(a, b, state, properties[index])) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
function areObjectsEqualStrict(a, b, state) {
|
|
125
|
+
var properties = getStrictProperties(a);
|
|
126
|
+
var index = properties.length;
|
|
127
|
+
if (getStrictProperties(b).length !== index) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
var property;
|
|
131
|
+
var descriptorA;
|
|
132
|
+
var descriptorB;
|
|
133
|
+
while (index-- > 0) {
|
|
134
|
+
property = properties[index];
|
|
135
|
+
if (!isPropertyEqual(a, b, state, property)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
descriptorA = getOwnPropertyDescriptor(a, property);
|
|
139
|
+
descriptorB = getOwnPropertyDescriptor(b, property);
|
|
140
|
+
if ((descriptorA || descriptorB) && (!descriptorA || !descriptorB || descriptorA.configurable !== descriptorB.configurable || descriptorA.enumerable !== descriptorB.enumerable || descriptorA.writable !== descriptorB.writable)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
function arePrimitiveWrappersEqual(a, b) {
|
|
147
|
+
return sameValueZeroEqual(a.valueOf(), b.valueOf());
|
|
148
|
+
}
|
|
149
|
+
function areRegExpsEqual(a, b) {
|
|
150
|
+
return a.source === b.source && a.flags === b.flags;
|
|
151
|
+
}
|
|
152
|
+
function areSetsEqual(a, b, state) {
|
|
153
|
+
var size = a.size;
|
|
154
|
+
if (size !== b.size) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
if (!size) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
var matchedIndices = new Array(size);
|
|
161
|
+
var aIterable = a.values();
|
|
162
|
+
var aResult;
|
|
163
|
+
var bResult;
|
|
164
|
+
while (aResult = aIterable.next()) {
|
|
165
|
+
if (aResult.done) {
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
var bIterable = b.values();
|
|
169
|
+
var hasMatch = false;
|
|
170
|
+
var matchIndex = 0;
|
|
171
|
+
while (bResult = bIterable.next()) {
|
|
172
|
+
if (bResult.done) {
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
if (!matchedIndices[matchIndex] && state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state)) {
|
|
176
|
+
hasMatch = matchedIndices[matchIndex] = true;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
matchIndex++;
|
|
180
|
+
}
|
|
181
|
+
if (!hasMatch) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
function areTypedArraysEqual(a, b) {
|
|
188
|
+
var index = a.length;
|
|
189
|
+
if (b.length !== index) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
while (index-- > 0) {
|
|
193
|
+
if (a[index] !== b[index]) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
function areUrlsEqual(a, b) {
|
|
200
|
+
return a.hostname === b.hostname && a.pathname === b.pathname && a.protocol === b.protocol && a.port === b.port && a.hash === b.hash && a.username === b.username && a.password === b.password;
|
|
201
|
+
}
|
|
202
|
+
function isPropertyEqual(a, b, state, property) {
|
|
203
|
+
if ((property === REACT_OWNER || property === PREACT_OWNER || property === PREACT_VNODE) && (a.$$typeof || b.$$typeof)) {
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
return hasOwn(b, property) && state.equals(a[property], b[property], property, property, a, b, state);
|
|
207
|
+
}
|
|
208
|
+
var ARGUMENTS_TAG = "[object Arguments]";
|
|
209
|
+
var BOOLEAN_TAG = "[object Boolean]";
|
|
210
|
+
var DATE_TAG = "[object Date]";
|
|
211
|
+
var ERROR_TAG = "[object Error]";
|
|
212
|
+
var MAP_TAG = "[object Map]";
|
|
213
|
+
var NUMBER_TAG = "[object Number]";
|
|
214
|
+
var OBJECT_TAG = "[object Object]";
|
|
215
|
+
var REG_EXP_TAG = "[object RegExp]";
|
|
216
|
+
var SET_TAG = "[object Set]";
|
|
217
|
+
var STRING_TAG = "[object String]";
|
|
218
|
+
var URL_TAG = "[object URL]";
|
|
219
|
+
var isArray = Array.isArray;
|
|
220
|
+
var isTypedArray = typeof ArrayBuffer === "function" && ArrayBuffer.isView ? ArrayBuffer.isView : null;
|
|
221
|
+
var assign = Object.assign;
|
|
222
|
+
var getTag = Object.prototype.toString.call.bind(Object.prototype.toString);
|
|
223
|
+
function createEqualityComparator(_a) {
|
|
224
|
+
var areArraysEqual2 = _a.areArraysEqual, areDatesEqual2 = _a.areDatesEqual, areErrorsEqual2 = _a.areErrorsEqual, areFunctionsEqual2 = _a.areFunctionsEqual, areMapsEqual2 = _a.areMapsEqual, areNumbersEqual2 = _a.areNumbersEqual, areObjectsEqual2 = _a.areObjectsEqual, arePrimitiveWrappersEqual2 = _a.arePrimitiveWrappersEqual, areRegExpsEqual2 = _a.areRegExpsEqual, areSetsEqual2 = _a.areSetsEqual, areTypedArraysEqual2 = _a.areTypedArraysEqual, areUrlsEqual2 = _a.areUrlsEqual;
|
|
225
|
+
return function comparator(a, b, state) {
|
|
226
|
+
if (a === b) {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
if (a == null || b == null) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
var type = typeof a;
|
|
233
|
+
if (type !== typeof b) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
if (type !== "object") {
|
|
237
|
+
if (type === "number") {
|
|
238
|
+
return areNumbersEqual2(a, b, state);
|
|
239
|
+
}
|
|
240
|
+
if (type === "function") {
|
|
241
|
+
return areFunctionsEqual2(a, b, state);
|
|
242
|
+
}
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
var constructor = a.constructor;
|
|
246
|
+
if (constructor !== b.constructor) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
if (constructor === Object) {
|
|
250
|
+
return areObjectsEqual2(a, b, state);
|
|
251
|
+
}
|
|
252
|
+
if (isArray(a)) {
|
|
253
|
+
return areArraysEqual2(a, b, state);
|
|
254
|
+
}
|
|
255
|
+
if (isTypedArray != null && isTypedArray(a)) {
|
|
256
|
+
return areTypedArraysEqual2(a, b, state);
|
|
257
|
+
}
|
|
258
|
+
if (constructor === Date) {
|
|
259
|
+
return areDatesEqual2(a, b, state);
|
|
260
|
+
}
|
|
261
|
+
if (constructor === RegExp) {
|
|
262
|
+
return areRegExpsEqual2(a, b, state);
|
|
263
|
+
}
|
|
264
|
+
if (constructor === Map) {
|
|
265
|
+
return areMapsEqual2(a, b, state);
|
|
266
|
+
}
|
|
267
|
+
if (constructor === Set) {
|
|
268
|
+
return areSetsEqual2(a, b, state);
|
|
269
|
+
}
|
|
270
|
+
var tag = getTag(a);
|
|
271
|
+
if (tag === DATE_TAG) {
|
|
272
|
+
return areDatesEqual2(a, b, state);
|
|
273
|
+
}
|
|
274
|
+
if (tag === REG_EXP_TAG) {
|
|
275
|
+
return areRegExpsEqual2(a, b, state);
|
|
276
|
+
}
|
|
277
|
+
if (tag === MAP_TAG) {
|
|
278
|
+
return areMapsEqual2(a, b, state);
|
|
279
|
+
}
|
|
280
|
+
if (tag === SET_TAG) {
|
|
281
|
+
return areSetsEqual2(a, b, state);
|
|
282
|
+
}
|
|
283
|
+
if (tag === OBJECT_TAG) {
|
|
284
|
+
return typeof a.then !== "function" && typeof b.then !== "function" && areObjectsEqual2(a, b, state);
|
|
285
|
+
}
|
|
286
|
+
if (tag === URL_TAG) {
|
|
287
|
+
return areUrlsEqual2(a, b, state);
|
|
288
|
+
}
|
|
289
|
+
if (tag === ERROR_TAG) {
|
|
290
|
+
return areErrorsEqual2(a, b, state);
|
|
291
|
+
}
|
|
292
|
+
if (tag === ARGUMENTS_TAG) {
|
|
293
|
+
return areObjectsEqual2(a, b, state);
|
|
294
|
+
}
|
|
295
|
+
if (tag === BOOLEAN_TAG || tag === NUMBER_TAG || tag === STRING_TAG) {
|
|
296
|
+
return arePrimitiveWrappersEqual2(a, b, state);
|
|
297
|
+
}
|
|
298
|
+
return false;
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function createEqualityComparatorConfig(_a) {
|
|
302
|
+
var circular = _a.circular, createCustomConfig = _a.createCustomConfig, strict = _a.strict;
|
|
303
|
+
var config = {
|
|
304
|
+
areArraysEqual: strict ? areObjectsEqualStrict : areArraysEqual,
|
|
305
|
+
areDatesEqual,
|
|
306
|
+
areErrorsEqual,
|
|
307
|
+
areFunctionsEqual,
|
|
308
|
+
areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
|
|
309
|
+
areNumbersEqual,
|
|
310
|
+
areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
|
|
311
|
+
arePrimitiveWrappersEqual,
|
|
312
|
+
areRegExpsEqual,
|
|
313
|
+
areSetsEqual: strict ? combineComparators(areSetsEqual, areObjectsEqualStrict) : areSetsEqual,
|
|
314
|
+
areTypedArraysEqual: strict ? areObjectsEqualStrict : areTypedArraysEqual,
|
|
315
|
+
areUrlsEqual
|
|
316
|
+
};
|
|
317
|
+
if (createCustomConfig) {
|
|
318
|
+
config = assign({}, config, createCustomConfig(config));
|
|
319
|
+
}
|
|
320
|
+
if (circular) {
|
|
321
|
+
var areArraysEqual$1 = createIsCircular(config.areArraysEqual);
|
|
322
|
+
var areMapsEqual$1 = createIsCircular(config.areMapsEqual);
|
|
323
|
+
var areObjectsEqual$1 = createIsCircular(config.areObjectsEqual);
|
|
324
|
+
var areSetsEqual$1 = createIsCircular(config.areSetsEqual);
|
|
325
|
+
config = assign({}, config, {
|
|
326
|
+
areArraysEqual: areArraysEqual$1,
|
|
327
|
+
areMapsEqual: areMapsEqual$1,
|
|
328
|
+
areObjectsEqual: areObjectsEqual$1,
|
|
329
|
+
areSetsEqual: areSetsEqual$1
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
return config;
|
|
333
|
+
}
|
|
334
|
+
function createInternalEqualityComparator(compare) {
|
|
335
|
+
return function(a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, state) {
|
|
336
|
+
return compare(a, b, state);
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function createIsEqual(_a) {
|
|
340
|
+
var circular = _a.circular, comparator = _a.comparator, createState = _a.createState, equals = _a.equals, strict = _a.strict;
|
|
341
|
+
if (createState) {
|
|
342
|
+
return function isEqual(a, b) {
|
|
343
|
+
var _a2 = createState(), _b = _a2.cache, cache = _b === void 0 ? circular ? /* @__PURE__ */ new WeakMap() : void 0 : _b, meta = _a2.meta;
|
|
344
|
+
return comparator(a, b, {
|
|
345
|
+
cache,
|
|
346
|
+
equals,
|
|
347
|
+
meta,
|
|
348
|
+
strict
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
if (circular) {
|
|
353
|
+
return function isEqual(a, b) {
|
|
354
|
+
return comparator(a, b, {
|
|
355
|
+
cache: /* @__PURE__ */ new WeakMap(),
|
|
356
|
+
equals,
|
|
357
|
+
meta: void 0,
|
|
358
|
+
strict
|
|
359
|
+
});
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
var state = {
|
|
363
|
+
cache: void 0,
|
|
364
|
+
equals,
|
|
365
|
+
meta: void 0,
|
|
366
|
+
strict
|
|
367
|
+
};
|
|
368
|
+
return function isEqual(a, b) {
|
|
369
|
+
return comparator(a, b, state);
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
var deepEqual = createCustomEqual();
|
|
373
|
+
var strictDeepEqual = createCustomEqual({ strict: true });
|
|
374
|
+
var circularDeepEqual = createCustomEqual({ circular: true });
|
|
375
|
+
var strictCircularDeepEqual = createCustomEqual({
|
|
376
|
+
circular: true,
|
|
377
|
+
strict: true
|
|
378
|
+
});
|
|
379
|
+
var shallowEqual = createCustomEqual({
|
|
380
|
+
createInternalComparator: function() {
|
|
381
|
+
return sameValueZeroEqual;
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
var strictShallowEqual = createCustomEqual({
|
|
385
|
+
strict: true,
|
|
386
|
+
createInternalComparator: function() {
|
|
387
|
+
return sameValueZeroEqual;
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
var circularShallowEqual = createCustomEqual({
|
|
391
|
+
circular: true,
|
|
392
|
+
createInternalComparator: function() {
|
|
393
|
+
return sameValueZeroEqual;
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
var strictCircularShallowEqual = createCustomEqual({
|
|
397
|
+
circular: true,
|
|
398
|
+
createInternalComparator: function() {
|
|
399
|
+
return sameValueZeroEqual;
|
|
400
|
+
},
|
|
401
|
+
strict: true
|
|
402
|
+
});
|
|
403
|
+
function createCustomEqual(options) {
|
|
404
|
+
if (options === void 0) {
|
|
405
|
+
options = {};
|
|
406
|
+
}
|
|
407
|
+
var _a = options.circular, circular = _a === void 0 ? false : _a, createCustomInternalComparator = options.createInternalComparator, createState = options.createState, _b = options.strict, strict = _b === void 0 ? false : _b;
|
|
408
|
+
var config = createEqualityComparatorConfig(options);
|
|
409
|
+
var comparator = createEqualityComparator(config);
|
|
410
|
+
var equals = createCustomInternalComparator ? createCustomInternalComparator(comparator) : createInternalEqualityComparator(comparator);
|
|
411
|
+
return createIsEqual({ circular, comparator, createState, equals, strict });
|
|
412
|
+
}
|
|
413
|
+
|
|
4
414
|
// src/utils/getChanges.ts
|
|
5
|
-
|
|
6
|
-
|
|
415
|
+
function getChanges(prev, next, comparator = "deepEqual") {
|
|
416
|
+
const equals = comparator === "circularDeepEqual" ? circularDeepEqual : deepEqual;
|
|
7
417
|
const changedKeys = [];
|
|
8
418
|
const unstableKeys = [];
|
|
9
419
|
const isObject = (v) => v !== null && typeof v === "object";
|
|
@@ -22,7 +432,7 @@ function getChanges(prev, next) {
|
|
|
22
432
|
}
|
|
23
433
|
const max = Math.max(prev.length, next.length);
|
|
24
434
|
for (let i = 0; i < max; i++) {
|
|
25
|
-
const deepEqItem =
|
|
435
|
+
const deepEqItem = equals(prev[i], next[i]);
|
|
26
436
|
const refDiffItem = isObject(prev[i]) && isObject(next[i]) && prev[i] !== next[i];
|
|
27
437
|
if (!deepEqItem || refDiffItem) {
|
|
28
438
|
const key = String(i);
|
|
@@ -35,7 +445,7 @@ function getChanges(prev, next) {
|
|
|
35
445
|
} else if (isObject(prev) && isObject(next)) {
|
|
36
446
|
const allKeys = /* @__PURE__ */ new Set([...Object.keys(prev), ...Object.keys(next)]);
|
|
37
447
|
for (const key of allKeys) {
|
|
38
|
-
const deepEqProp =
|
|
448
|
+
const deepEqProp = equals(prev[key], next[key]);
|
|
39
449
|
const refDiffProp = isObject(prev[key]) && isObject(next[key]) && prev[key] !== next[key];
|
|
40
450
|
if (!deepEqProp || refDiffProp) {
|
|
41
451
|
changedKeys.push(key);
|
|
@@ -45,7 +455,7 @@ function getChanges(prev, next) {
|
|
|
45
455
|
}
|
|
46
456
|
}
|
|
47
457
|
} else {
|
|
48
|
-
const deepEqRoot =
|
|
458
|
+
const deepEqRoot = equals(prev, next);
|
|
49
459
|
const refDiffRoot = isObject(prev) && isObject(next) && prev !== next;
|
|
50
460
|
const unstable = refDiffRoot && deepEqRoot;
|
|
51
461
|
const changed = !deepEqRoot || refDiffRoot;
|
|
@@ -56,7 +466,7 @@ function getChanges(prev, next) {
|
|
|
56
466
|
};
|
|
57
467
|
}
|
|
58
468
|
const isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
59
|
-
const unstableRoot = isPlainObject(prev) && isPlainObject(next) && prev !== next &&
|
|
469
|
+
const unstableRoot = isPlainObject(prev) && isPlainObject(next) && prev !== next && equals(prev, next);
|
|
60
470
|
if (unstableRoot && changedKeys.length === 0) {
|
|
61
471
|
changedKeys.push("");
|
|
62
472
|
unstableKeys.push("");
|
|
@@ -68,6 +478,31 @@ function getChanges(prev, next) {
|
|
|
68
478
|
};
|
|
69
479
|
}
|
|
70
480
|
|
|
481
|
+
// src/utils/compareChanges.ts
|
|
482
|
+
function compareChanges(hookAddress, prev, current) {
|
|
483
|
+
var _a, _b, _c;
|
|
484
|
+
if (prev !== "undefined" && prev !== current) {
|
|
485
|
+
const comparator = (_c = (_b = (_a = window == null ? void 0 : window.reactJitter) == null ? void 0 : _a.selectComparator) == null ? void 0 : _b.call(_a, hookAddress)) != null ? _c : "deepEqual";
|
|
486
|
+
try {
|
|
487
|
+
return getChanges(prev, current, comparator);
|
|
488
|
+
} catch (error) {
|
|
489
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
490
|
+
const isRecursionError = /(?:maximum call stack(?: size)? exceeded|too much recursion|stack overflow)/i.test(
|
|
491
|
+
errorMessage
|
|
492
|
+
);
|
|
493
|
+
if (isRecursionError && comparator !== "circularDeepEqual") {
|
|
494
|
+
throw new Error(
|
|
495
|
+
`Maximum call stack size exceeded. Please use the "circularDeepEqual" comparator with selectComparator option.
|
|
496
|
+
Hook address: ${JSON.stringify(hookAddress, null, 2)}.`,
|
|
497
|
+
{ cause: error }
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
throw error;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
|
|
71
506
|
// src/index.ts
|
|
72
507
|
var scopes = {};
|
|
73
508
|
var hookStack = /* @__PURE__ */ new Map();
|
|
@@ -100,7 +535,13 @@ function useJitterScope(scope) {
|
|
|
100
535
|
const hookId = `${scopeId}-${hookEndEvent.id}`;
|
|
101
536
|
if (shouldReportChanges()) {
|
|
102
537
|
const prevResult = currentScope.hookResults[hookId];
|
|
103
|
-
const
|
|
538
|
+
const hookAddress = {
|
|
539
|
+
hook: hookEndEvent.hook,
|
|
540
|
+
file: hookEndEvent.file,
|
|
541
|
+
line: hookEndEvent.line,
|
|
542
|
+
offset: hookEndEvent.offset
|
|
543
|
+
};
|
|
544
|
+
const changes = compareChanges(hookAddress, prevResult, hookResult);
|
|
104
545
|
if (changes) {
|
|
105
546
|
const hookCall = {
|
|
106
547
|
hook: hookEndEvent.hook,
|
|
@@ -177,12 +618,6 @@ function getScopeCount(scope) {
|
|
|
177
618
|
}
|
|
178
619
|
return scopeCounter[scope.id]++;
|
|
179
620
|
}
|
|
180
|
-
function compareChanges(prev, current) {
|
|
181
|
-
if (prev !== "undefined" && prev !== current) {
|
|
182
|
-
return getChanges(prev, current);
|
|
183
|
-
}
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
621
|
export {
|
|
187
622
|
reactJitter,
|
|
188
623
|
useJitterScope
|