@arrai-innovations/reactive-helpers 14.0.1 → 14.1.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/package.json
CHANGED
|
@@ -2,6 +2,8 @@ import {
|
|
|
2
2
|
addOrUpdateReactiveObject,
|
|
3
3
|
assignReactiveObject,
|
|
4
4
|
AssignReactiveObjectError,
|
|
5
|
+
assignReactiveObjectDeep,
|
|
6
|
+
assignReactiveArray,
|
|
5
7
|
} from "../../../utils/assignReactiveObject.js";
|
|
6
8
|
import { computed, EffectScope, effectScope, reactive, toRef, unref } from "vue";
|
|
7
9
|
import { deepUnref } from "vue-deepunref";
|
|
@@ -164,6 +166,280 @@ describe("utils/assignReactiveObject", function () {
|
|
|
164
166
|
);
|
|
165
167
|
});
|
|
166
168
|
});
|
|
169
|
+
it("should update nested Sets within reactive objects", async () => {
|
|
170
|
+
const target = reactive({
|
|
171
|
+
setA: new Set([1, 2, 3]),
|
|
172
|
+
value: 10,
|
|
173
|
+
});
|
|
174
|
+
const source = reactive({
|
|
175
|
+
setA: new Set([3, 4, 5]),
|
|
176
|
+
value: 20,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const es = effectScope();
|
|
180
|
+
let computedSum;
|
|
181
|
+
es.run(() => {
|
|
182
|
+
computedSum = computed(() => {
|
|
183
|
+
let sum = 0;
|
|
184
|
+
for (const num of target.setA) {
|
|
185
|
+
sum += num;
|
|
186
|
+
}
|
|
187
|
+
return sum + target.value;
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
193
|
+
expect(computedSum.value).toBe(16);
|
|
194
|
+
|
|
195
|
+
assignReactiveObject(target, source);
|
|
196
|
+
|
|
197
|
+
expect(Array.from(target.setA)).toEqual([3, 4, 5]);
|
|
198
|
+
expect(target.value).toBe(20);
|
|
199
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
200
|
+
expect(computedSum.value).toBe(32);
|
|
201
|
+
|
|
202
|
+
source.setA.add(6);
|
|
203
|
+
expect(target.setA.has(6)).toBe(true);
|
|
204
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
205
|
+
expect(computedSum.value).toBe(38);
|
|
206
|
+
|
|
207
|
+
source.value = 25;
|
|
208
|
+
expect(target.value).toBe(25);
|
|
209
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
210
|
+
expect(computedSum.value).toBe(43);
|
|
211
|
+
} finally {
|
|
212
|
+
es.stop();
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
it("should update nested Maps within reactive objects", () => {
|
|
216
|
+
const target = reactive({
|
|
217
|
+
mapA: new Map([
|
|
218
|
+
["x", 1],
|
|
219
|
+
["y", 2],
|
|
220
|
+
]),
|
|
221
|
+
value: 5,
|
|
222
|
+
});
|
|
223
|
+
const source = reactive({
|
|
224
|
+
mapA: new Map([
|
|
225
|
+
["y", 3],
|
|
226
|
+
["z", 4],
|
|
227
|
+
]),
|
|
228
|
+
value: 15,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const es = effectScope();
|
|
232
|
+
let computedSum;
|
|
233
|
+
es.run(() => {
|
|
234
|
+
computedSum = computed(() => {
|
|
235
|
+
let sum = 0;
|
|
236
|
+
for (const val of target.mapA.values()) {
|
|
237
|
+
sum += val;
|
|
238
|
+
}
|
|
239
|
+
return sum + target.value;
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
245
|
+
expect(computedSum.value).toBe(8);
|
|
246
|
+
|
|
247
|
+
assignReactiveObject(target, source);
|
|
248
|
+
|
|
249
|
+
expect(Array.from(target.mapA.entries())).toEqual([
|
|
250
|
+
["y", 3],
|
|
251
|
+
["z", 4],
|
|
252
|
+
]);
|
|
253
|
+
expect(target.value).toBe(15);
|
|
254
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
255
|
+
expect(computedSum.value).toBe(22);
|
|
256
|
+
|
|
257
|
+
source.mapA.set("w", 5);
|
|
258
|
+
expect(target.mapA.has("w")).toBe(true);
|
|
259
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
260
|
+
expect(computedSum.value).toBe(27);
|
|
261
|
+
|
|
262
|
+
source.value = 20;
|
|
263
|
+
expect(target.value).toBe(20);
|
|
264
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
265
|
+
expect(computedSum.value).toBe(32);
|
|
266
|
+
} finally {
|
|
267
|
+
es.stop();
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
it("should update Sets within arrays", () => {
|
|
271
|
+
const target = reactive([new Set([1, 2]), new Set([3, 4])]);
|
|
272
|
+
const source = reactive([new Set([2, 3]), new Set([4, 5])]);
|
|
273
|
+
|
|
274
|
+
const es = effectScope();
|
|
275
|
+
let computedSum;
|
|
276
|
+
es.run(() => {
|
|
277
|
+
computedSum = computed(() => {
|
|
278
|
+
return target.reduce((sum, set) => {
|
|
279
|
+
for (const num of set) {
|
|
280
|
+
sum += num;
|
|
281
|
+
}
|
|
282
|
+
return sum;
|
|
283
|
+
}, 0);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
289
|
+
expect(computedSum.value).toBe(10);
|
|
290
|
+
|
|
291
|
+
assignReactiveObject(target, source);
|
|
292
|
+
|
|
293
|
+
expect(target.length).toBe(2);
|
|
294
|
+
expect(Array.from(target[0])).toEqual([2, 3]);
|
|
295
|
+
expect(Array.from(target[1])).toEqual([4, 5]);
|
|
296
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
297
|
+
expect(computedSum.value).toBe(14);
|
|
298
|
+
|
|
299
|
+
source[0].add(6);
|
|
300
|
+
expect(target[0].has(6)).toBe(true);
|
|
301
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
302
|
+
expect(computedSum.value).toBe(20);
|
|
303
|
+
|
|
304
|
+
source[1].delete(4);
|
|
305
|
+
expect(target[1].has(4)).toBe(false);
|
|
306
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
307
|
+
expect(computedSum.value).toBe(16);
|
|
308
|
+
} finally {
|
|
309
|
+
es.stop();
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
it("should update Maps within arrays", () => {
|
|
313
|
+
const target = reactive([
|
|
314
|
+
new Map([
|
|
315
|
+
["a", 1],
|
|
316
|
+
["b", 2],
|
|
317
|
+
]),
|
|
318
|
+
new Map([["c", 3]]),
|
|
319
|
+
]);
|
|
320
|
+
const source = reactive([
|
|
321
|
+
new Map([
|
|
322
|
+
["a", 2],
|
|
323
|
+
["d", 4],
|
|
324
|
+
]),
|
|
325
|
+
new Map([
|
|
326
|
+
["c", 3],
|
|
327
|
+
["e", 5],
|
|
328
|
+
]),
|
|
329
|
+
]);
|
|
330
|
+
|
|
331
|
+
const es = effectScope();
|
|
332
|
+
let computedSum;
|
|
333
|
+
es.run(() => {
|
|
334
|
+
computedSum = computed(() => {
|
|
335
|
+
return target.reduce((sum, map) => {
|
|
336
|
+
for (const val of map.values()) {
|
|
337
|
+
sum += val;
|
|
338
|
+
}
|
|
339
|
+
return sum;
|
|
340
|
+
}, 0);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
346
|
+
expect(computedSum.value).toBe(6);
|
|
347
|
+
|
|
348
|
+
assignReactiveObject(target, source);
|
|
349
|
+
|
|
350
|
+
expect(target.length).toBe(2);
|
|
351
|
+
expect(Array.from(target[0].entries())).toEqual([
|
|
352
|
+
["a", 2],
|
|
353
|
+
["d", 4],
|
|
354
|
+
]);
|
|
355
|
+
expect(Array.from(target[1].entries())).toEqual([
|
|
356
|
+
["c", 3],
|
|
357
|
+
["e", 5],
|
|
358
|
+
]);
|
|
359
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
360
|
+
expect(computedSum.value).toBe(14);
|
|
361
|
+
|
|
362
|
+
source[0].set("f", 6);
|
|
363
|
+
expect(target[0].has("f")).toBe(true);
|
|
364
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
365
|
+
expect(computedSum.value).toBe(20);
|
|
366
|
+
|
|
367
|
+
source[1].delete("c");
|
|
368
|
+
expect(target[1].has("c")).toBe(false);
|
|
369
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
370
|
+
expect(computedSum.value).toBe(17);
|
|
371
|
+
} finally {
|
|
372
|
+
es.stop();
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
describe("assignReactiveObjectDeep", () => {
|
|
377
|
+
it("should recursively assign nested Sets and Maps", () => {
|
|
378
|
+
const target = reactive({
|
|
379
|
+
level1: {
|
|
380
|
+
set: new Set([1]),
|
|
381
|
+
map: new Map([["a", 1]]),
|
|
382
|
+
level2: {
|
|
383
|
+
array: [new Set([2])],
|
|
384
|
+
object: {
|
|
385
|
+
map: new Map([["b", 2]]),
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
const source = reactive({
|
|
392
|
+
level1: {
|
|
393
|
+
set: new Set([3]),
|
|
394
|
+
map: new Map([["a", 3]]),
|
|
395
|
+
level2: {
|
|
396
|
+
array: [new Set([4])],
|
|
397
|
+
object: {
|
|
398
|
+
map: new Map([["b", 4]]),
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const es = effectScope();
|
|
405
|
+
let computedSum;
|
|
406
|
+
es.run(() => {
|
|
407
|
+
computedSum = computed(() => {
|
|
408
|
+
let sum = 0;
|
|
409
|
+
for (const num of target.level1.set) sum += num;
|
|
410
|
+
for (const val of target.level1.map.values()) sum += val;
|
|
411
|
+
for (const num of target.level1.level2.array[0]) sum += num;
|
|
412
|
+
for (const val of target.level1.level2.object.map.values()) sum += val;
|
|
413
|
+
return sum;
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
try {
|
|
418
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
419
|
+
expect(computedSum.value).toBe(6);
|
|
420
|
+
|
|
421
|
+
assignReactiveObjectDeep(target, source);
|
|
422
|
+
|
|
423
|
+
expect(Array.from(target.level1.set)).toEqual([3]);
|
|
424
|
+
expect(Array.from(target.level1.map.entries())).toEqual([["a", 3]]);
|
|
425
|
+
expect(Array.from(target.level1.level2.array[0])).toEqual([4]);
|
|
426
|
+
expect(Array.from(target.level1.level2.object.map.entries())).toEqual([["b", 4]]);
|
|
427
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
428
|
+
expect(computedSum.value).toBe(14);
|
|
429
|
+
|
|
430
|
+
source.level1.set.add(5);
|
|
431
|
+
expect(target.level1.set.has(5)).toBe(true);
|
|
432
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
433
|
+
expect(computedSum.value).toBe(19);
|
|
434
|
+
|
|
435
|
+
source.level1.level2.object.map.set("c", 6);
|
|
436
|
+
expect(target.level1.level2.object.map.has("c")).toBe(true);
|
|
437
|
+
// @ts-ignore - computedSum.value won't be undefined, it is calculated immediately as required
|
|
438
|
+
expect(computedSum.value).toBe(25);
|
|
439
|
+
} finally {
|
|
440
|
+
es.stop();
|
|
441
|
+
}
|
|
442
|
+
});
|
|
167
443
|
});
|
|
168
444
|
it("should work as in the example for the readme", function () {
|
|
169
445
|
const es = new EffectScope();
|
|
@@ -234,4 +510,84 @@ describe("utils/assignReactiveObject", function () {
|
|
|
234
510
|
expect(target.a).toEqual({ b: 7, c: 8, d: 9 });
|
|
235
511
|
});
|
|
236
512
|
});
|
|
513
|
+
describe("assignReactiveArray", () => {
|
|
514
|
+
it("should assign values from source to target array", () => {
|
|
515
|
+
const target = reactive([1, 2, 3]);
|
|
516
|
+
const source = reactive([4, 5, 6]);
|
|
517
|
+
|
|
518
|
+
const didAnything = assignReactiveArray(target, source);
|
|
519
|
+
expect(didAnything).toBe(true);
|
|
520
|
+
|
|
521
|
+
// Unref the elements for comparison
|
|
522
|
+
const unrefTarget = target.map(unref);
|
|
523
|
+
expect(unrefTarget).toEqual([4, 5, 6]);
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it("should handle source array longer than target", () => {
|
|
527
|
+
const target = reactive([1, 2]);
|
|
528
|
+
const source = reactive([3, 4, 5]);
|
|
529
|
+
|
|
530
|
+
assignReactiveArray(target, source);
|
|
531
|
+
|
|
532
|
+
const unrefTarget = target.map(unref);
|
|
533
|
+
expect(unrefTarget).toEqual([3, 4, 5]);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
it("should handle source array shorter than target", () => {
|
|
537
|
+
const target = reactive([1, 2, 3]);
|
|
538
|
+
const source = reactive([4]);
|
|
539
|
+
|
|
540
|
+
assignReactiveArray(target, source);
|
|
541
|
+
|
|
542
|
+
const unrefTarget = target.map(unref);
|
|
543
|
+
expect(unrefTarget).toEqual([4]);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
it("should not create reactive links between array elements", () => {
|
|
547
|
+
const target = reactive([{ val: 1 }, { val: 2 }]);
|
|
548
|
+
const source = reactive([{ val: 3 }, { val: 4 }]);
|
|
549
|
+
|
|
550
|
+
assignReactiveArray(target, source);
|
|
551
|
+
|
|
552
|
+
const unrefTarget = target.map(unref);
|
|
553
|
+
expect(unrefTarget).toEqual([{ val: 3 }, { val: 4 }]);
|
|
554
|
+
|
|
555
|
+
// Modify source
|
|
556
|
+
source[0].val = 5;
|
|
557
|
+
|
|
558
|
+
// Since the elements are refs to source, target should reflect changes
|
|
559
|
+
expect(unref(target[0]).val).toBe(5);
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
it("should reverse the target array if it matches the reversed source", () => {
|
|
563
|
+
const target = reactive([1, 2, 3]);
|
|
564
|
+
const source = reactive([3, 2, 1]);
|
|
565
|
+
|
|
566
|
+
const didAnything = assignReactiveArray(target, source);
|
|
567
|
+
expect(didAnything).toBe(true);
|
|
568
|
+
|
|
569
|
+
const unrefTarget = target.map(unref);
|
|
570
|
+
expect(unrefTarget).toEqual([3, 2, 1]);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
it("should handle nested arrays and objects", () => {
|
|
574
|
+
const target = reactive([[1], [2], [3]]);
|
|
575
|
+
const source = reactive([[4], [5], [6]]);
|
|
576
|
+
|
|
577
|
+
assignReactiveArray(target, source);
|
|
578
|
+
|
|
579
|
+
const unrefTarget = target.map(unref).map((item) => (Array.isArray(item) ? item.map(unref) : item));
|
|
580
|
+
expect(unrefTarget).toEqual([[4], [5], [6]]);
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
it("should handle nested arrays and objects with different lengths", () => {
|
|
584
|
+
const target = reactive([[1], [2], [3]]);
|
|
585
|
+
const source = reactive([[4], [5]]);
|
|
586
|
+
|
|
587
|
+
assignReactiveArray(target, source);
|
|
588
|
+
|
|
589
|
+
const unrefTarget = target.map(unref).map((item) => (Array.isArray(item) ? item.map(unref) : item));
|
|
590
|
+
expect(unrefTarget).toEqual([[4], [5]]);
|
|
591
|
+
});
|
|
592
|
+
});
|
|
237
593
|
});
|
|
@@ -2,9 +2,10 @@ import { keyDiff } from "./keyDiff.js";
|
|
|
2
2
|
import inspect from "browser-util-inspect";
|
|
3
3
|
import isArray from "lodash-es/isArray.js";
|
|
4
4
|
import isObject from "lodash-es/isObject.js";
|
|
5
|
-
import isObjectLike from "lodash-es/isObjectLike.js";
|
|
6
5
|
import { isReactive, isRef, toRef, unref } from "vue";
|
|
7
6
|
import isSet from "lodash-es/isSet.js";
|
|
7
|
+
import isMap from "lodash-es/isMap.js";
|
|
8
|
+
import isPlainObject from "lodash-es/isPlainObject.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Reactive object assignment utilities.
|
|
@@ -100,16 +101,20 @@ function reactiveReplaceKeys(target, source, keys, exclude) {
|
|
|
100
101
|
let didAnything = false;
|
|
101
102
|
for (const key of keys) {
|
|
102
103
|
if (!exclude?.includes(key)) {
|
|
104
|
+
const sourceValue = source[key];
|
|
105
|
+
const targetValue = target[key];
|
|
106
|
+
if (isSet(sourceValue) || isMap(sourceValue)) {
|
|
107
|
+
if (targetValue === sourceValue) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
target[key] = sourceValue;
|
|
111
|
+
didAnything = true;
|
|
112
|
+
}
|
|
103
113
|
if (targetIsReactive && sourceIsReactive) {
|
|
104
114
|
const targetPropRaw = unref(toRef(target, key));
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
if (isObjectLike(sourcePropRaw)) {
|
|
109
|
-
if (targetPropRaw === sourcePropRaw) {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
115
|
+
const sourcePropRaw = unref(toRef(source, key));
|
|
116
|
+
if (targetPropRaw === sourcePropRaw) {
|
|
117
|
+
continue;
|
|
113
118
|
}
|
|
114
119
|
target[key] = toRef(source, key);
|
|
115
120
|
didAnything = true;
|
|
@@ -348,28 +353,37 @@ export function assignReactiveObject(target, source, exclude) {
|
|
|
348
353
|
* @returns {boolean} True if any keys were added, updated, or removed, false otherwise.
|
|
349
354
|
*/
|
|
350
355
|
function recursiveInner(target, source, exclude, addedKeys, sameKeys, path, fn) {
|
|
356
|
+
let didAnything = false;
|
|
351
357
|
const wasAdded = addReactiveObject(target, source, exclude, addedKeys);
|
|
352
|
-
|
|
353
|
-
const keysForReplace = [];
|
|
358
|
+
didAnything = didAnything || wasAdded;
|
|
354
359
|
for (const key of sameKeys) {
|
|
355
360
|
if (!exclude?.includes(key)) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
361
|
+
const sourceValue = source[key];
|
|
362
|
+
const targetValue = target[key];
|
|
363
|
+
|
|
364
|
+
if (isSet(sourceValue) || isMap(sourceValue)) {
|
|
365
|
+
if (targetValue !== sourceValue) {
|
|
366
|
+
target[key] = sourceValue;
|
|
367
|
+
didAnything = true;
|
|
368
|
+
}
|
|
369
|
+
} else if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
|
|
370
|
+
const nextLevelExclude = exclude
|
|
371
|
+
?.filter((excludeKey) => !excludeKey.startsWith(path))
|
|
372
|
+
.map((excludeKey) => excludeKey.replace(path, ""));
|
|
373
|
+
const nextPath = `${path}.${key}`;
|
|
374
|
+
const didRecurse = fn(targetValue, sourceValue, nextLevelExclude, nextPath);
|
|
375
|
+
didAnything = didAnything || didRecurse;
|
|
376
|
+
} else if (isArray(sourceValue) && isArray(targetValue)) {
|
|
377
|
+
const didAssignArray = assignReactiveArray(targetValue, sourceValue);
|
|
378
|
+
didAnything = didAnything || didAssignArray;
|
|
379
|
+
} else if (targetValue !== sourceValue) {
|
|
380
|
+
// Assign other types directly
|
|
381
|
+
target[key] = sourceValue;
|
|
382
|
+
didAnything = true;
|
|
360
383
|
}
|
|
361
384
|
}
|
|
362
385
|
}
|
|
363
|
-
|
|
364
|
-
for (const key of keysForRecurse) {
|
|
365
|
-
// scope exclude for this next level, remove keys that don't start with the current path, trim keys that do to remove the current path
|
|
366
|
-
const nextLevelExclude = exclude
|
|
367
|
-
?.filter((excludeKey) => !excludeKey.startsWith(path))
|
|
368
|
-
.map((excludeKey) => excludeKey.replace(path, ""));
|
|
369
|
-
const nextPath = isArray(source[key]) ? `${path}[${key}]` : `${path}.${key}`;
|
|
370
|
-
fn(target[key], source[key], nextLevelExclude, nextPath);
|
|
371
|
-
}
|
|
372
|
-
return wasAdded || wasReplaced;
|
|
386
|
+
return didAnything;
|
|
373
387
|
}
|
|
374
388
|
|
|
375
389
|
/**
|