@shapeshift-labs/frontier-engine 0.0.1 → 0.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/dist/engine.js ADDED
@@ -0,0 +1,3843 @@
1
+ import { OP_SET, OP_REMOVE, OP_TRUNCATE, OP_APPEND, OP_ASSIGN, OP_STRING_SPLICE, OP_ARRAY_SPLICE, OP_ARRAY_MOVE, OP_STRING_COPY, OP_ARRAY_ASSIGN, OP_ARRAY_OBJECT_ASSIGN, OP_ARRAY_TUPLE_ASSIGN, OP_ARRAY_OBJECT_FIELD_ASSIGN, OP_SCALAR_ARRAY_REPLACE, OP_ARRAY_TWO_FIELD_INSERT } from '@shapeshift-labs/frontier/constants';
2
+ import { diffInto as computeDiffInto } from '@shapeshift-labs/frontier/diff';
3
+ import { cloneJson } from '@shapeshift-labs/frontier/clone';
4
+ import { equalsJsonFast } from '@shapeshift-labs/frontier/equal';
5
+ import { applyEncodedPatchHistory, applyPatchHistory, createPatchHistoryBuilder, decodePatchHistory, encodePatchHistory } from '@shapeshift-labs/frontier-codec/history';
6
+ import { createEngineProfilePlansSnapshot, readProfilePlans } from './profile.js';
7
+ const DEFAULT_MAX_ENTRIES = 256;
8
+ const MAX_PAIR_SIGNATURES = 8;
9
+ const DEFAULT_ADAPTIVE_THRESHOLD = 1;
10
+ const ADAPTIVE_SAMPLE_LIMIT = 16;
11
+ const ADAPTIVE_RECORD_FIELD_MIN = 2;
12
+ const ADAPTIVE_RECORD_CELL_MIN = 96;
13
+ const ADAPTIVE_OBJECT_FIELD_MIN = 32;
14
+ const ADAPTIVE_PATH_OBJECT_FIELD_MIN = 8;
15
+ const ADAPTIVE_DEFER_OBJECT_FIELD_MIN = 128;
16
+ const BITMASK_RECORD_FIELD_MAX = 24;
17
+ const ADAPTIVE_NESTED_FIELD_DEPTH = 2;
18
+ const TRAINING_MAX_DEPTH = 4;
19
+ const TRAINING_MAX_SCHEMAS = 16;
20
+ const COMPILED_PLAN_CACHE_LIMIT = 128;
21
+ const ADAPTIVE_FAILED_PLAN_SIGNATURE_LIMIT = 32;
22
+ const HISTORY_OBJECT_ASSIGN_FIELD_MIN = 8;
23
+ const HISTORY_OBJECT_ASSIGN_GROUP_MAX = 16;
24
+ const HISTORY_OBJECT_ASSIGN_TOTAL_KEY_MAX = 512;
25
+ const PROFILE_VERSION = 1;
26
+ const DEFERRED_WIDE_ROOT_OBJECT_SIGNATURE = '\u0003wide-root-object';
27
+ const hasOwn = Object.prototype.hasOwnProperty;
28
+ const flatRecordArrayDiffCache = new Map();
29
+ const flatRecordArrayBitmaskDiffCache = new Map();
30
+ const nestedRecordArrayDiffCache = new Map();
31
+ const flatObjectDiffCache = new Map();
32
+ const nestedObjectDiffCache = new Map();
33
+ const flatRecordArrayEqualsCache = new Map();
34
+ const flatObjectEqualsCache = new Map();
35
+ const nestedRecordArrayEqualsCache = new Map();
36
+ const nestedObjectEqualsCache = new Map();
37
+ export function createDiffEngine(defaultOptions) {
38
+ const rawBaseOptions = readOptions(defaultOptions, 'default options');
39
+ const initialProfile = readProfile(rawBaseOptions && rawBaseOptions.profile);
40
+ const baseOptions = omitProfileOption(rawBaseOptions);
41
+ let profileOptions = initialProfile === null ? undefined : initialProfile.settings;
42
+ let effectiveOptions = mergeOptions(profileOptions, baseOptions);
43
+ let maxEntries = readMaxEntries(effectiveOptions);
44
+ validateAdaptiveOption(effectiveOptions);
45
+ const baseSchemaPlan = baseOptions && baseOptions.schema !== undefined && baseOptions.schema !== null
46
+ ? compileSchemaPlan(baseOptions.schema)
47
+ : null;
48
+ let profilePlan = initialProfile === null ? null : initialProfile.plan;
49
+ let profilePlans = initialProfile === null ? undefined : initialProfile.plans;
50
+ let learnedHistoryStrategy = readHistoryPlanStrategy(profilePlans);
51
+ let adaptive = createAdaptiveState(effectiveOptions);
52
+ let pairCache = new WeakMap();
53
+ const tokenEntries = [];
54
+ const plannedHistoryStrategyOut = { value: null };
55
+ function diff(source, target, options) {
56
+ return diffInto(source, target, [], options);
57
+ }
58
+ function diffHistory(initial, states, options) {
59
+ if (!Array.isArray(states)) {
60
+ throw new TypeError('diffHistory(initial, states) requires states to be an array');
61
+ }
62
+ if (options === undefined || options === null) {
63
+ plannedHistoryStrategyOut.value = null;
64
+ const plannedHistory = tryPlannedDiffHistory(initial, states, learnedHistoryStrategy, plannedHistoryStrategyOut);
65
+ if (plannedHistory !== null) {
66
+ if (plannedHistoryStrategyOut.value !== null)
67
+ learnedHistoryStrategy = plannedHistoryStrategyOut.value;
68
+ return plannedHistory;
69
+ }
70
+ }
71
+ const patches = new Array(states.length);
72
+ let source = initial;
73
+ for (let i = 0, length = states.length; i < length; i++) {
74
+ const target = states[i];
75
+ patches[i] = diff(source, target, options);
76
+ source = target;
77
+ }
78
+ return patches;
79
+ }
80
+ function encodeHistory(patches, options) {
81
+ return encodePatchHistory(patches, options);
82
+ }
83
+ function decodeHistory(bytes, options) {
84
+ return decodePatchHistory(bytes, options);
85
+ }
86
+ function applyHistory(source, patches, options) {
87
+ return applyPatchHistory(source, patches, options);
88
+ }
89
+ function applyEncodedHistory(source, bytes, options) {
90
+ return applyEncodedPatchHistory(source, bytes, options);
91
+ }
92
+ function createHistoryBuilder() {
93
+ return createPatchHistoryBuilder();
94
+ }
95
+ function diffInto(source, target, patch, options) {
96
+ if (!Array.isArray(patch)) {
97
+ throw new TypeError('patch output must be an array');
98
+ }
99
+ const mergedOptions = mergeOptions(effectiveOptions, options);
100
+ validateAdaptiveOption(mergedOptions);
101
+ const cacheState = readCacheState(source, target, mergedOptions);
102
+ const canLearnAdaptive = !hasAvailableSchemaPlan(mergedOptions, baseSchemaPlan, profilePlan) && shouldUseEnginePlan(mergedOptions);
103
+ if (canLearnAdaptive && readAdaptivePlan(adaptive) === null && observeAdaptiveShape(adaptive, source, target)) {
104
+ pairCache = new WeakMap();
105
+ tokenEntries.length = 0;
106
+ }
107
+ if (cacheState !== null && maxEntries !== 0) {
108
+ const pairEntry = lookupPairEntry(pairCache, source, target, cacheState);
109
+ if (pairEntry !== null) {
110
+ return clonePatchInto(pairEntry.patch, patch);
111
+ }
112
+ const tokenEntry = lookupTokenEntry(tokenEntries, cacheState);
113
+ if (tokenEntry !== null) {
114
+ storePairEntry(pairCache, source, target, tokenEntry);
115
+ return clonePatchInto(tokenEntry.patch, patch);
116
+ }
117
+ }
118
+ patch.length = 0;
119
+ let configuredPlan = null;
120
+ let adaptivePlan = null;
121
+ if (shouldUseEnginePlan(mergedOptions)) {
122
+ configuredPlan = baseSchemaPlan || readSchemaPlan(mergedOptions) || profilePlan;
123
+ if (configuredPlan === null) {
124
+ adaptivePlan = readAdaptivePlan(adaptive);
125
+ }
126
+ }
127
+ const plan = configuredPlan || adaptivePlan;
128
+ const skipAdaptivePlan = adaptivePlan !== null && hasAdaptiveFailedPlan(adaptive, adaptivePlan, source, target);
129
+ let planned = false;
130
+ if (plan !== null && !skipAdaptivePlan) {
131
+ planned = tryPlannedDiff(plan, source, target, patch, mergedOptions);
132
+ if (!planned && adaptivePlan !== null) {
133
+ rememberAdaptiveFailedPlan(adaptive, adaptivePlan, source, target);
134
+ }
135
+ }
136
+ if (!planned && !skipAdaptivePlan && canLearnAdaptive && plan !== null && observeAdaptiveShape(adaptive, source, target)) {
137
+ pairCache = new WeakMap();
138
+ tokenEntries.length = 0;
139
+ patch.length = 0;
140
+ const retryPlan = readAdaptivePlan(adaptive);
141
+ if (retryPlan !== null && !hasAdaptiveFailedPlan(adaptive, retryPlan, source, target)) {
142
+ planned = tryPlannedDiff(retryPlan, source, target, patch, mergedOptions);
143
+ if (!planned) {
144
+ rememberAdaptiveFailedPlan(adaptive, retryPlan, source, target);
145
+ }
146
+ }
147
+ }
148
+ if (!planned) {
149
+ computeDiffInto(source, target, patch, mergedOptions);
150
+ }
151
+ else {
152
+ if (canLearnAdaptive &&
153
+ adaptivePlan !== null &&
154
+ !planCoversRoot(adaptivePlan) &&
155
+ observeAdaptiveShape(adaptive, source, target)) {
156
+ pairCache = new WeakMap();
157
+ tokenEntries.length = 0;
158
+ }
159
+ compactPlannedArrayObjectSetRuns(patch);
160
+ }
161
+ if (cacheState !== null && maxEntries !== 0) {
162
+ const entry = {
163
+ sourceToken: cacheState.sourceToken,
164
+ targetToken: cacheState.targetToken,
165
+ signature: cacheState.signature,
166
+ patch: clonePatch(patch)
167
+ };
168
+ storePairEntry(pairCache, source, target, entry);
169
+ storeTokenEntry(tokenEntries, entry, maxEntries);
170
+ }
171
+ return patch;
172
+ }
173
+ function equals(source, target, options) {
174
+ const mergedOptions = mergeOptions(effectiveOptions, options);
175
+ validateAdaptiveOption(mergedOptions);
176
+ const cacheState = readCacheState(source, target, mergedOptions);
177
+ if (cacheState !== null && cacheState.sourceToken === cacheState.targetToken)
178
+ return true;
179
+ const canLearnAdaptive = !hasAvailableSchemaPlan(mergedOptions, baseSchemaPlan, profilePlan) && shouldUseEnginePlan(mergedOptions);
180
+ if (canLearnAdaptive && readAdaptivePlan(adaptive) === null) {
181
+ observeAdaptiveShape(adaptive, source, target);
182
+ }
183
+ if (shouldUseEnginePlan(mergedOptions)) {
184
+ const configuredPlan = baseSchemaPlan || readSchemaPlan(mergedOptions) || profilePlan;
185
+ const adaptivePlan = configuredPlan === null ? readAdaptivePlan(adaptive) : null;
186
+ const plan = configuredPlan || adaptivePlan;
187
+ if (plan !== null && !(adaptivePlan !== null && hasAdaptiveFailedPlan(adaptive, adaptivePlan, source, target))) {
188
+ const planned = tryPlannedEquals(plan, source, target, mergedOptions);
189
+ if (planned === true)
190
+ return true;
191
+ }
192
+ }
193
+ return equalsJsonFast(source, target, mergedOptions);
194
+ }
195
+ function clear() {
196
+ pairCache = new WeakMap();
197
+ tokenEntries.length = 0;
198
+ clearAdaptiveState(adaptive);
199
+ }
200
+ function train(samples) {
201
+ if (adaptive === null || !adaptive.enabled) {
202
+ throw new TypeError('train(samples) requires createDiffEngine({ adaptive: true })');
203
+ }
204
+ const plan = trainProfilePlan(samples, adaptive.recordKeyCandidates);
205
+ if (plan !== null) {
206
+ adaptive.plan = plan;
207
+ adaptive.candidates.clear();
208
+ adaptive.learnedKeys.clear();
209
+ adaptive.rejectedKeys.clear();
210
+ adaptive.deferredObjectSignatures.clear();
211
+ clearAdaptiveFailedPlanPairs(adaptive);
212
+ }
213
+ pairCache = new WeakMap();
214
+ tokenEntries.length = 0;
215
+ return getProfile();
216
+ }
217
+ function getProfile() {
218
+ return createProfileSnapshot(effectiveOptions, maxEntries, baseSchemaPlan, profilePlan, profilePlans, adaptive, learnedHistoryStrategy);
219
+ }
220
+ function loadProfile(profile) {
221
+ const state = readProfile(profile);
222
+ profilePlan = state === null ? null : state.plan;
223
+ profilePlans = state === null ? undefined : state.plans;
224
+ learnedHistoryStrategy = readHistoryPlanStrategy(profilePlans);
225
+ profileOptions = state === null ? undefined : state.settings;
226
+ effectiveOptions = mergeOptions(profileOptions, baseOptions);
227
+ maxEntries = readMaxEntries(effectiveOptions);
228
+ validateAdaptiveOption(effectiveOptions);
229
+ adaptive = createAdaptiveState(effectiveOptions);
230
+ pairCache = new WeakMap();
231
+ tokenEntries.length = 0;
232
+ }
233
+ return {
234
+ diff,
235
+ diffInto,
236
+ equals,
237
+ diffHistory,
238
+ encodeHistory,
239
+ decodeHistory,
240
+ applyHistory,
241
+ applyEncodedHistory,
242
+ createHistoryBuilder,
243
+ clear,
244
+ train,
245
+ getProfile,
246
+ loadProfile
247
+ };
248
+ }
249
+ function tryPlannedDiffHistory(initial, states, preferred, strategyOut) {
250
+ if (states.length === 0)
251
+ return [];
252
+ if (preferred !== undefined && preferred !== null && preferred !== 'auto') {
253
+ const preferredPatches = tryDiffHistoryStrategy(preferred, initial, states);
254
+ if (preferredPatches !== null)
255
+ return preferredPatches;
256
+ }
257
+ const stringAppend = tryStringAppendDiffHistory(initial, states);
258
+ if (stringAppend !== null) {
259
+ strategyOut.value = 'string-append';
260
+ return stringAppend;
261
+ }
262
+ const rowObjectAssign = tryRowObjectAssignDiffHistory(initial, states);
263
+ if (rowObjectAssign !== null) {
264
+ strategyOut.value = 'row-object-assign';
265
+ return rowObjectAssign;
266
+ }
267
+ const objectAssign = tryObjectAssignDiffHistory(initial, states);
268
+ if (objectAssign !== null) {
269
+ strategyOut.value = 'object-assign';
270
+ return objectAssign;
271
+ }
272
+ const scalarObject = tryScalarObjectDiffHistory(initial, states);
273
+ if (scalarObject !== null) {
274
+ strategyOut.value = 'scalar-object';
275
+ return scalarObject;
276
+ }
277
+ return null;
278
+ }
279
+ function tryDiffHistoryStrategy(strategy, initial, states) {
280
+ if (strategy === 'string-append')
281
+ return tryStringAppendDiffHistory(initial, states);
282
+ if (strategy === 'row-object-assign')
283
+ return tryRowObjectAssignDiffHistory(initial, states);
284
+ if (strategy === 'object-assign')
285
+ return tryObjectAssignDiffHistory(initial, states);
286
+ if (strategy === 'scalar-object')
287
+ return tryScalarObjectDiffHistory(initial, states);
288
+ return null;
289
+ }
290
+ function tryStringAppendDiffHistory(initial, states) {
291
+ const firstPath = findOnlyStringAppendPath(initial, states[0]);
292
+ if (firstPath === null)
293
+ return null;
294
+ const patches = new Array(states.length);
295
+ let previous = initial;
296
+ for (let i = 0, length = states.length; i < length; i++) {
297
+ const target = states[i];
298
+ if (!isOnlyStringAppendAtPath(previous, target, firstPath))
299
+ return null;
300
+ const sourceText = readHistoryPath(previous, firstPath);
301
+ const targetText = readHistoryPath(target, firstPath);
302
+ if (typeof sourceText !== 'string' || typeof targetText !== 'string')
303
+ return null;
304
+ patches[i] = [[OP_STRING_SPLICE, firstPath.slice(), sourceText.length, 0, targetText.slice(sourceText.length)]];
305
+ previous = target;
306
+ }
307
+ return patches;
308
+ }
309
+ function isOnlyStringAppendAtPath(source, target, path) {
310
+ return isOnlyStringAppendAtPathInto(source, target, path, 0);
311
+ }
312
+ function isOnlyStringAppendAtPathInto(source, target, path, depth) {
313
+ if (depth === path.length) {
314
+ return typeof source === 'string' &&
315
+ typeof target === 'string' &&
316
+ isStringAppend(source, target);
317
+ }
318
+ if (!isHistoryPlainObject(source) || !isHistoryPlainObject(target))
319
+ return false;
320
+ const sourceKeys = Object.keys(source);
321
+ const targetKeys = Object.keys(target);
322
+ if (sourceKeys.length !== targetKeys.length)
323
+ return false;
324
+ const segment = path[depth];
325
+ let found = false;
326
+ for (let i = 0, length = sourceKeys.length; i < length; i++) {
327
+ const key = sourceKeys[i];
328
+ if (targetKeys[i] !== key || !hasOwn.call(target, key))
329
+ return false;
330
+ if (key === segment) {
331
+ if (!isOnlyStringAppendAtPathInto(source[key], target[key], path, depth + 1))
332
+ return false;
333
+ found = true;
334
+ }
335
+ else if (!sameHistoryScalarOrRef(source[key], target[key])) {
336
+ return false;
337
+ }
338
+ }
339
+ return found;
340
+ }
341
+ function findOnlyStringAppendPath(source, target) {
342
+ const out = [];
343
+ return findOnlyStringAppendPathInto(source, target, out) ? out : null;
344
+ }
345
+ function findOnlyStringAppendPathInto(source, target, out) {
346
+ if (source === target) {
347
+ if (source !== 0 || 1 / source === 1 / target)
348
+ return false;
349
+ }
350
+ if (typeof source === 'string' && typeof target === 'string') {
351
+ return isStringAppend(source, target);
352
+ }
353
+ if (!isHistoryPlainObject(source) || !isHistoryPlainObject(target))
354
+ return false;
355
+ const sourceKeys = Object.keys(source);
356
+ const targetKeys = Object.keys(target);
357
+ if (sourceKeys.length !== targetKeys.length)
358
+ return false;
359
+ let found = false;
360
+ for (let i = 0, length = sourceKeys.length; i < length; i++) {
361
+ const key = sourceKeys[i];
362
+ if (targetKeys[i] !== key || !hasOwn.call(target, key))
363
+ return false;
364
+ const sourceValue = source[key];
365
+ const targetValue = target[key];
366
+ if (sameHistoryScalarOrRef(sourceValue, targetValue))
367
+ continue;
368
+ const depth = out.length;
369
+ out[depth] = key;
370
+ if (!findOnlyStringAppendPathInto(sourceValue, targetValue, out) || found)
371
+ return false;
372
+ out.length = depth + 1;
373
+ found = true;
374
+ }
375
+ return found;
376
+ }
377
+ function isStringAppend(source, target) {
378
+ return target.length > source.length && target.slice(0, source.length) === source;
379
+ }
380
+ function tryRowObjectAssignDiffHistory(initial, states) {
381
+ if (states.length < 8)
382
+ return null;
383
+ const changes = new Array(states.length);
384
+ const firstChange = collectRowObjectHistoryChange(initial, states[0]);
385
+ if (firstChange === null || firstChange.indexes.length === 0 || firstChange.fields.length === 0)
386
+ return null;
387
+ const arrayPath = firstChange.arrayPath;
388
+ const setPaths = firstChange.setOps.map((op) => op[0]);
389
+ const fields = firstChange.fields.slice();
390
+ changes[0] = firstChange;
391
+ let previous = initial;
392
+ for (let i = 1, length = states.length; i < length; i++) {
393
+ previous = states[i - 1];
394
+ const target = states[i];
395
+ const change = collectRowObjectHistoryChange(previous, target);
396
+ if (change === null || change.indexes.length === 0)
397
+ return null;
398
+ if (!sameHistoryPath(arrayPath, change.arrayPath) || !sameHistoryPathList(setPaths, change.setOps.map((op) => op[0]))) {
399
+ return null;
400
+ }
401
+ for (let fieldIndex = 0, fieldCount = change.fields.length; fieldIndex < fieldCount; fieldIndex++) {
402
+ addUniqueHistoryField(fields, change.fields[fieldIndex]);
403
+ }
404
+ changes[i] = change;
405
+ }
406
+ if (fields.length > BITMASK_RECORD_FIELD_MAX)
407
+ return null;
408
+ const patches = new Array(states.length);
409
+ for (let i = 0, length = changes.length; i < length; i++) {
410
+ const change = changes[i];
411
+ const rows = readHistoryPath(change.target, arrayPath);
412
+ if (!Array.isArray(rows))
413
+ return null;
414
+ let firstOp;
415
+ if (fields.length === 1) {
416
+ const field = fields[0];
417
+ const values = new Array(change.indexes.length);
418
+ for (let rowOffset = 0, rowCount = change.indexes.length; rowOffset < rowCount; rowOffset++) {
419
+ const row = rows[change.indexes[rowOffset]];
420
+ if (!isHistoryPlainObject(row) || !hasOwn.call(row, field))
421
+ return null;
422
+ values[rowOffset] = row[field];
423
+ }
424
+ firstOp = [OP_ARRAY_OBJECT_FIELD_ASSIGN, arrayPath.slice(), change.indexes.slice(), [[field]], values];
425
+ }
426
+ else {
427
+ const assigns = new Array(change.indexes.length);
428
+ for (let rowOffset = 0, rowCount = change.indexes.length; rowOffset < rowCount; rowOffset++) {
429
+ const row = rows[change.indexes[rowOffset]];
430
+ if (!isHistoryPlainObject(row))
431
+ return null;
432
+ const assign = {};
433
+ for (let fieldIndex = 0, fieldCount = fields.length; fieldIndex < fieldCount; fieldIndex++) {
434
+ const field = fields[fieldIndex];
435
+ if (!hasOwn.call(row, field))
436
+ return null;
437
+ assign[field] = row[field];
438
+ }
439
+ assigns[rowOffset] = assign;
440
+ }
441
+ firstOp = [OP_ARRAY_OBJECT_ASSIGN, arrayPath.slice(), change.indexes.slice(), assigns];
442
+ }
443
+ const patch = new Array(1 + change.setOps.length);
444
+ patch[0] = firstOp;
445
+ for (let setIndex = 0, setCount = change.setOps.length; setIndex < setCount; setIndex++) {
446
+ const setOp = change.setOps[setIndex];
447
+ patch[setIndex + 1] = [OP_SET, setOp[0].slice(), setOp[1]];
448
+ }
449
+ patches[i] = patch;
450
+ }
451
+ return patches;
452
+ }
453
+ function collectRowObjectHistoryChange(source, target) {
454
+ const collector = {
455
+ arrayPath: null,
456
+ indexes: [],
457
+ fields: [],
458
+ setOps: []
459
+ };
460
+ const path = [];
461
+ if (!collectRowObjectHistoryChangeInto(source, target, path, collector, 0) || collector.arrayPath === null)
462
+ return null;
463
+ return {
464
+ arrayPath: collector.arrayPath,
465
+ indexes: collector.indexes,
466
+ fields: collector.fields,
467
+ setOps: collector.setOps,
468
+ target
469
+ };
470
+ }
471
+ function collectRowObjectHistoryChangeInto(source, target, path, collector, depth) {
472
+ if (sameHistoryScalarOrRef(source, target))
473
+ return true;
474
+ if (Array.isArray(source) || Array.isArray(target)) {
475
+ return collectRowObjectArrayHistoryChange(source, target, path, collector);
476
+ }
477
+ if (!isHistoryPlainObject(source) || !isHistoryPlainObject(target)) {
478
+ collector.setOps[collector.setOps.length] = [path.slice(), target];
479
+ return true;
480
+ }
481
+ const sourceKeys = Object.keys(source);
482
+ const targetKeys = Object.keys(target);
483
+ if (sourceKeys.length !== targetKeys.length || depth > TRAINING_MAX_DEPTH)
484
+ return false;
485
+ for (let i = 0, length = sourceKeys.length; i < length; i++) {
486
+ const key = sourceKeys[i];
487
+ if (targetKeys[i] !== key || !hasOwn.call(target, key))
488
+ return false;
489
+ path[depth] = key;
490
+ if (!collectRowObjectHistoryChangeInto(source[key], target[key], path, collector, depth + 1))
491
+ return false;
492
+ path.length = depth;
493
+ }
494
+ return true;
495
+ }
496
+ function collectRowObjectArrayHistoryChange(source, target, path, collector) {
497
+ if (!Array.isArray(source) || !Array.isArray(target) || source.length !== target.length || collector.arrayPath !== null)
498
+ return false;
499
+ const indexes = [];
500
+ const fields = [];
501
+ const rowCount = source.length;
502
+ let startRow = 0;
503
+ while (startRow < rowCount && sameHistoryScalarOrRef(source[startRow], target[startRow]))
504
+ startRow++;
505
+ if (startRow === rowCount)
506
+ return true;
507
+ let endRow = rowCount - 1;
508
+ while (endRow > startRow && sameHistoryScalarOrRef(source[endRow], target[endRow]))
509
+ endRow--;
510
+ for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) {
511
+ const sourceRow = source[rowIndex];
512
+ const targetRow = target[rowIndex];
513
+ if (sameHistoryScalarOrRef(sourceRow, targetRow))
514
+ continue;
515
+ if (!isHistoryPlainObject(sourceRow) || !isHistoryPlainObject(targetRow))
516
+ return false;
517
+ const sourceKeys = Object.keys(sourceRow);
518
+ const targetKeys = Object.keys(targetRow);
519
+ if (sourceKeys.length !== targetKeys.length)
520
+ return false;
521
+ let changed = false;
522
+ for (let keyIndex = 0, keyCount = sourceKeys.length; keyIndex < keyCount; keyIndex++) {
523
+ const key = sourceKeys[keyIndex];
524
+ if (targetKeys[keyIndex] !== key || !hasOwn.call(targetRow, key))
525
+ return false;
526
+ if (!sameHistoryScalarOrRef(sourceRow[key], targetRow[key])) {
527
+ changed = true;
528
+ addUniqueHistoryField(fields, key);
529
+ }
530
+ }
531
+ if (changed)
532
+ indexes[indexes.length] = rowIndex;
533
+ }
534
+ if (indexes.length === 0)
535
+ return true;
536
+ collector.arrayPath = path.slice();
537
+ collector.indexes = indexes;
538
+ for (let i = 0, length = fields.length; i < length; i++)
539
+ addUniqueHistoryField(collector.fields, fields[i]);
540
+ return true;
541
+ }
542
+ function addUniqueHistoryField(fields, field) {
543
+ for (let i = 0, length = fields.length; i < length; i++) {
544
+ if (fields[i] === field)
545
+ return;
546
+ }
547
+ fields[fields.length] = field;
548
+ }
549
+ function tryObjectAssignDiffHistory(initial, states) {
550
+ if (states.length < 8)
551
+ return null;
552
+ const groups = collectHistoryAssignGroups(initial, states[0]);
553
+ if (groups === null || groups.length === 0 || groups.length > HISTORY_OBJECT_ASSIGN_GROUP_MAX)
554
+ return null;
555
+ let hasLargeGroup = false;
556
+ let totalKeys = 0;
557
+ for (let i = 0, groupCount = groups.length; i < groupCount; i++) {
558
+ const keyCount = groups[i].keys.length;
559
+ totalKeys += keyCount;
560
+ if (keyCount >= HISTORY_OBJECT_ASSIGN_FIELD_MIN)
561
+ hasLargeGroup = true;
562
+ }
563
+ if (!hasLargeGroup || totalKeys > HISTORY_OBJECT_ASSIGN_TOTAL_KEY_MAX)
564
+ return null;
565
+ const patches = new Array(states.length);
566
+ let previous = initial;
567
+ for (let i = 0, length = states.length; i < length; i++) {
568
+ const target = states[i];
569
+ const nextGroups = collectHistoryAssignGroups(previous, target);
570
+ if (nextGroups === null || !sameHistoryAssignGroups(groups, nextGroups))
571
+ return null;
572
+ const patch = new Array(groups.length);
573
+ for (let groupIndex = 0, groupCount = groups.length; groupIndex < groupCount; groupIndex++) {
574
+ const group = groups[groupIndex];
575
+ const object = readHistoryPath(target, group.path);
576
+ if (!isHistoryPlainObject(object))
577
+ return null;
578
+ patch[groupIndex] = [
579
+ OP_ASSIGN,
580
+ group.path.slice(),
581
+ historyAssignGroupCoversObject(group.keys, object) ? object : makeHistoryAssignPayload(group.keys, object)
582
+ ];
583
+ }
584
+ patches[i] = patch;
585
+ previous = target;
586
+ }
587
+ return patches;
588
+ }
589
+ function historyAssignGroupCoversObject(keys, object) {
590
+ const objectKeys = Object.keys(object);
591
+ if (objectKeys.length !== keys.length)
592
+ return false;
593
+ for (let i = 0, length = keys.length; i < length; i++) {
594
+ if (objectKeys[i] !== keys[i])
595
+ return false;
596
+ }
597
+ return true;
598
+ }
599
+ function makeHistoryAssignPayload(keys, object) {
600
+ const assign = {};
601
+ for (let keyIndex = 0, keyCount = keys.length; keyIndex < keyCount; keyIndex++) {
602
+ const key = keys[keyIndex];
603
+ assign[key] = object[key];
604
+ }
605
+ return assign;
606
+ }
607
+ function collectHistoryAssignGroups(source, target) {
608
+ const groups = [];
609
+ const path = [];
610
+ return collectHistoryAssignGroupsInto(source, target, path, groups, 0) ? groups : null;
611
+ }
612
+ function collectHistoryAssignGroupsInto(source, target, path, groups, depth) {
613
+ if (groups.length > HISTORY_OBJECT_ASSIGN_GROUP_MAX || depth > TRAINING_MAX_DEPTH)
614
+ return false;
615
+ if (sameHistoryScalarOrRef(source, target))
616
+ return true;
617
+ if (!isHistoryPlainObject(source) || !isHistoryPlainObject(target))
618
+ return false;
619
+ const sourceKeys = Object.keys(source);
620
+ const targetKeys = Object.keys(target);
621
+ if (sourceKeys.length !== targetKeys.length)
622
+ return false;
623
+ const changedKeys = [];
624
+ for (let i = 0, length = sourceKeys.length; i < length; i++) {
625
+ const key = sourceKeys[i];
626
+ if (targetKeys[i] !== key || !hasOwn.call(target, key))
627
+ return false;
628
+ const sourceValue = source[key];
629
+ const targetValue = target[key];
630
+ if (sameHistoryScalarOrRef(sourceValue, targetValue))
631
+ continue;
632
+ if (isHistoryPlainObject(sourceValue) && isHistoryPlainObject(targetValue)) {
633
+ path[depth] = key;
634
+ if (!collectHistoryAssignGroupsInto(sourceValue, targetValue, path, groups, depth + 1))
635
+ return false;
636
+ path.length = depth;
637
+ }
638
+ else {
639
+ changedKeys[changedKeys.length] = key;
640
+ }
641
+ }
642
+ if (changedKeys.length !== 0) {
643
+ groups[groups.length] = { path: path.slice(), keys: changedKeys };
644
+ }
645
+ return true;
646
+ }
647
+ function sameHistoryAssignGroups(left, right) {
648
+ if (left.length !== right.length)
649
+ return false;
650
+ for (let i = 0, length = left.length; i < length; i++) {
651
+ const leftGroup = left[i];
652
+ const rightGroup = right[i];
653
+ if (!sameHistoryPath(leftGroup.path, rightGroup.path))
654
+ return false;
655
+ const leftKeys = leftGroup.keys;
656
+ const rightKeys = rightGroup.keys;
657
+ if (leftKeys.length !== rightKeys.length)
658
+ return false;
659
+ for (let j = 0, keyCount = leftKeys.length; j < keyCount; j++) {
660
+ if (leftKeys[j] !== rightKeys[j])
661
+ return false;
662
+ }
663
+ }
664
+ return true;
665
+ }
666
+ function tryScalarObjectDiffHistory(initial, states) {
667
+ const paths = collectScalarHistoryPaths(initial);
668
+ if (paths === null || paths.length === 0 || paths.length > 64)
669
+ return null;
670
+ for (let i = 0, length = states.length; i < length; i++) {
671
+ if (!hasSameScalarHistoryShapeAsTemplate(states[i], initial))
672
+ return null;
673
+ }
674
+ const patches = new Array(states.length);
675
+ let previous = initial;
676
+ for (let i = 0, length = states.length; i < length; i++) {
677
+ const target = states[i];
678
+ const patch = [];
679
+ for (let j = 0, pathCount = paths.length; j < pathCount; j++) {
680
+ const path = paths[j];
681
+ const sourceValue = readHistoryPath(previous, path);
682
+ const targetValue = readHistoryPath(target, path);
683
+ if (sameHistoryScalarOrRef(sourceValue, targetValue))
684
+ continue;
685
+ if (typeof sourceValue === 'string' &&
686
+ typeof targetValue === 'string' &&
687
+ (sourceValue.length >= 32 || targetValue.length >= 32)) {
688
+ return null;
689
+ }
690
+ patch[patch.length] = [OP_SET, path.slice(), targetValue];
691
+ }
692
+ patches[i] = patch;
693
+ previous = target;
694
+ }
695
+ return patches;
696
+ }
697
+ function collectScalarHistoryPaths(value) {
698
+ if (!isHistoryPlainObject(value))
699
+ return null;
700
+ const paths = [];
701
+ return collectScalarHistoryPathsInto(value, [], paths, 0) ? paths : null;
702
+ }
703
+ function collectScalarHistoryPathsInto(value, path, paths, depth) {
704
+ if (paths.length > 64 || depth > 4)
705
+ return false;
706
+ if (value === null || typeof value !== 'object') {
707
+ paths[paths.length] = path.slice();
708
+ return true;
709
+ }
710
+ if (!isHistoryPlainObject(value))
711
+ return false;
712
+ const keys = Object.keys(value);
713
+ for (let i = 0, length = keys.length; i < length; i++) {
714
+ const key = keys[i];
715
+ path[depth] = key;
716
+ if (!collectScalarHistoryPathsInto(value[key], path, paths, depth + 1))
717
+ return false;
718
+ path.length = depth;
719
+ }
720
+ return true;
721
+ }
722
+ function readHistoryPath(value, path) {
723
+ let cursor = value;
724
+ for (let i = 0, length = path.length; i < length; i++) {
725
+ if (cursor === null || typeof cursor !== 'object')
726
+ return undefined;
727
+ cursor = cursor[path[i]];
728
+ }
729
+ return cursor;
730
+ }
731
+ function hasSameScalarHistoryShapeAsTemplate(value, template) {
732
+ if (template === null || typeof template !== 'object') {
733
+ return value === null || typeof value !== 'object';
734
+ }
735
+ if (!isHistoryPlainObject(value) || !isHistoryPlainObject(template))
736
+ return false;
737
+ const templateKeys = Object.keys(template);
738
+ const valueKeys = Object.keys(value);
739
+ if (valueKeys.length !== templateKeys.length)
740
+ return false;
741
+ for (let i = 0, length = templateKeys.length; i < length; i++) {
742
+ const key = templateKeys[i];
743
+ if (valueKeys[i] !== key || !hasOwn.call(value, key))
744
+ return false;
745
+ if (!hasSameScalarHistoryShapeAsTemplate(value[key], template[key]))
746
+ return false;
747
+ }
748
+ return true;
749
+ }
750
+ function isHistoryPlainObject(value) {
751
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
752
+ return false;
753
+ const proto = Object.getPrototypeOf(value);
754
+ return proto === Object.prototype || proto === null;
755
+ }
756
+ function sameHistoryPath(left, right) {
757
+ if (left.length !== right.length)
758
+ return false;
759
+ for (let i = 0, length = left.length; i < length; i++) {
760
+ if (left[i] !== right[i])
761
+ return false;
762
+ }
763
+ return true;
764
+ }
765
+ function sameHistoryPathList(left, right) {
766
+ if (left.length !== right.length)
767
+ return false;
768
+ for (let i = 0, length = left.length; i < length; i++) {
769
+ if (!sameHistoryPath(left[i], right[i]))
770
+ return false;
771
+ }
772
+ return true;
773
+ }
774
+ function sameHistoryScalarOrRef(source, target) {
775
+ return source === target && (source !== 0 || 1 / source === 1 / target);
776
+ }
777
+ function readOptions(options, label) {
778
+ if (options === undefined || options === null)
779
+ return undefined;
780
+ if (typeof options !== 'object') {
781
+ throw new TypeError(label + ' must be an object');
782
+ }
783
+ return options;
784
+ }
785
+ function mergeOptions(baseOptions, options) {
786
+ const callOptions = readOptions(options, 'options');
787
+ if (baseOptions === undefined)
788
+ return callOptions;
789
+ if (callOptions === undefined)
790
+ return baseOptions;
791
+ return { ...baseOptions, ...callOptions };
792
+ }
793
+ function omitProfileOption(options) {
794
+ if (options === undefined || options === null || options.profile === undefined)
795
+ return options;
796
+ const out = { ...options };
797
+ delete out.profile;
798
+ return out;
799
+ }
800
+ function readMaxEntries(options) {
801
+ if (!options)
802
+ return DEFAULT_MAX_ENTRIES;
803
+ const value = options.cacheSize === undefined ? options.maxEntries : options.cacheSize;
804
+ if (value === undefined)
805
+ return DEFAULT_MAX_ENTRIES;
806
+ if (!Number.isSafeInteger(value) || value < 0) {
807
+ throw new TypeError('cacheSize option must be a non-negative safe integer');
808
+ }
809
+ return value;
810
+ }
811
+ function validateAdaptiveOption(options) {
812
+ if (!options || options.adaptive === undefined)
813
+ return;
814
+ if (typeof options.adaptive !== 'boolean') {
815
+ throw new TypeError('adaptive option must be a boolean');
816
+ }
817
+ }
818
+ function shouldUseEnginePlan(options) {
819
+ return !options ||
820
+ ((options.dirtyPaths === undefined || options.dirtyPaths === null) &&
821
+ (options.dirtyRows === undefined || options.dirtyRows === null));
822
+ }
823
+ function hasAvailableSchemaPlan(options, baseSchemaPlan, profilePlan) {
824
+ if (!shouldUseEnginePlan(options))
825
+ return false;
826
+ if (baseSchemaPlan !== null || profilePlan !== null)
827
+ return true;
828
+ return options && options.schema !== undefined && options.schema !== null;
829
+ }
830
+ function readCacheState(source, target, options) {
831
+ if (options &&
832
+ ((options.dirtyPaths !== undefined && options.dirtyPaths !== null) ||
833
+ (options.dirtyRows !== undefined && options.dirtyRows !== null))) {
834
+ return null;
835
+ }
836
+ const tokenState = readTokenState(options);
837
+ if (tokenState === null)
838
+ return null;
839
+ const sourceToken = tokenState.read(source);
840
+ const targetToken = tokenState.read(target);
841
+ if (sourceToken === undefined ||
842
+ sourceToken === null ||
843
+ targetToken === undefined ||
844
+ targetToken === null) {
845
+ return null;
846
+ }
847
+ return {
848
+ sourceToken,
849
+ targetToken,
850
+ signature: makeOutputSignature(options, tokenState)
851
+ };
852
+ }
853
+ function readTokenState(options) {
854
+ if (!options)
855
+ return null;
856
+ if (options.getVersion !== undefined) {
857
+ if (typeof options.getVersion !== 'function') {
858
+ throw new TypeError('getVersion option must be a function');
859
+ }
860
+ return {
861
+ mode: 'getVersion',
862
+ value: options.getVersion,
863
+ read: options.getVersion
864
+ };
865
+ }
866
+ if (options.getFingerprint !== undefined) {
867
+ if (typeof options.getFingerprint !== 'function') {
868
+ throw new TypeError('getFingerprint option must be a function');
869
+ }
870
+ return {
871
+ mode: 'getFingerprint',
872
+ value: options.getFingerprint,
873
+ read: options.getFingerprint
874
+ };
875
+ }
876
+ if (options.versionKey !== undefined) {
877
+ const key = options.versionKey;
878
+ return {
879
+ mode: 'versionKey',
880
+ value: key,
881
+ read: (value) => value !== null && typeof value === 'object'
882
+ ? value[key]
883
+ : undefined
884
+ };
885
+ }
886
+ if (options.fingerprintKey !== undefined) {
887
+ const key = options.fingerprintKey;
888
+ return {
889
+ mode: 'fingerprintKey',
890
+ value: key,
891
+ read: (value) => value !== null && typeof value === 'object'
892
+ ? value[key]
893
+ : undefined
894
+ };
895
+ }
896
+ return null;
897
+ }
898
+ function makeOutputSignature(options, tokenState) {
899
+ const keyState = readKeyState(options);
900
+ const arrayState = readArrayState(options);
901
+ const planState = readPlanState(options);
902
+ const patchState = readPatchState(options);
903
+ return [
904
+ tokenState.mode,
905
+ tokenState.value,
906
+ keyState.mode,
907
+ keyState.value,
908
+ arrayState.mode,
909
+ arrayState.value,
910
+ planState.mode,
911
+ planState.value,
912
+ patchState.mode,
913
+ patchState.value
914
+ ];
915
+ }
916
+ function readKeyState(options) {
917
+ if (!options)
918
+ return { mode: 'none', value: undefined };
919
+ if (typeof options.keyCompare === 'function') {
920
+ return { mode: 'keyCompare', value: options.keyCompare };
921
+ }
922
+ if (typeof options.stable === 'function') {
923
+ return { mode: 'stableCompare', value: options.stable };
924
+ }
925
+ if (options.stable || options.sortKeys) {
926
+ return { mode: 'lexical', value: undefined };
927
+ }
928
+ return { mode: 'none', value: undefined };
929
+ }
930
+ function readArrayState(options) {
931
+ if (!options)
932
+ return { mode: 'auto', value: undefined };
933
+ if (options.arrayKey === false || options.autoArrayKey === false) {
934
+ return { mode: 'disabled', value: undefined };
935
+ }
936
+ if (options.getArrayKey !== undefined) {
937
+ if (typeof options.getArrayKey !== 'function') {
938
+ throw new TypeError('getArrayKey option must be a function');
939
+ }
940
+ return { mode: 'getArrayKey', value: options.getArrayKey };
941
+ }
942
+ if (options.arrayKey !== undefined && options.arrayKey !== null && options.arrayKey !== true) {
943
+ if (typeof options.arrayKey === 'function') {
944
+ return { mode: 'arrayKeyFn', value: options.arrayKey };
945
+ }
946
+ if (typeof options.arrayKey === 'string' || typeof options.arrayKey === 'number') {
947
+ return { mode: 'arrayKey', value: options.arrayKey };
948
+ }
949
+ throw new TypeError('arrayKey option must be a string, number, function, true, false, or null');
950
+ }
951
+ if (options.recordKeyCandidates !== undefined) {
952
+ return { mode: 'recordKeyCandidates', value: options.recordKeyCandidates };
953
+ }
954
+ return { mode: 'auto', value: undefined };
955
+ }
956
+ function readPlanState(options) {
957
+ if (!options)
958
+ return { mode: 'none', value: undefined };
959
+ if (options.schema !== undefined)
960
+ return { mode: 'schema', value: options.schema };
961
+ if (options.profile !== undefined)
962
+ return { mode: 'profile', value: options.profile };
963
+ if (options.adaptive)
964
+ return { mode: 'adaptive', value: true };
965
+ return { mode: 'none', value: undefined };
966
+ }
967
+ function readPatchState(options) {
968
+ if (!options || options.maxPatchOperations === undefined || options.maxPatchOperations === null) {
969
+ return { mode: 'none', value: undefined };
970
+ }
971
+ return { mode: 'maxPatchOperations', value: options.maxPatchOperations };
972
+ }
973
+ function readSchemaPlan(options) {
974
+ if (!options || options.schema === undefined || options.schema === null)
975
+ return null;
976
+ return compileSchemaPlan(options.schema);
977
+ }
978
+ function readProfile(profile) {
979
+ if (profile === undefined || profile === null)
980
+ return null;
981
+ if (typeof profile !== 'object' || Array.isArray(profile)) {
982
+ throw new TypeError('profile option must be an object');
983
+ }
984
+ if (profile.version !== undefined &&
985
+ profile.version !== PROFILE_VERSION) {
986
+ throw new TypeError('unsupported profile version: ' + profile.version);
987
+ }
988
+ const settings = profile.settings === undefined
989
+ ? null
990
+ : readOptions(profile.settings, 'profile settings');
991
+ const schemas = readProfileSchemas(profile);
992
+ const plans = readProfilePlans(profile);
993
+ const profileSchemas = schemas === null
994
+ ? null
995
+ : shouldReadProfileSchemasAsExact(plans)
996
+ ? schemas.map(markProfileSchemaExact)
997
+ : schemas;
998
+ return {
999
+ settings,
1000
+ plans,
1001
+ plan: profileSchemas === null ? null : compileSchemaPlan({ schemas: profileSchemas })
1002
+ };
1003
+ }
1004
+ function readHistoryPlanStrategy(plans) {
1005
+ if (plans === undefined || plans.history === undefined || plans.history.strategy === undefined)
1006
+ return null;
1007
+ return plans.history.strategy;
1008
+ }
1009
+ function shouldReadProfileSchemasAsExact(plans) {
1010
+ return plans !== undefined && plans.diff !== undefined && plans.diff.strategy === 'adaptive-schema';
1011
+ }
1012
+ function markProfileSchemaExact(schema) {
1013
+ if (schema === null || typeof schema !== 'object' || Array.isArray(schema))
1014
+ return schema;
1015
+ return { ...schema, exact: true };
1016
+ }
1017
+ function readProfileSchemas(profile) {
1018
+ if (profile.schemas !== undefined) {
1019
+ if (!Array.isArray(profile.schemas)) {
1020
+ throw new TypeError('profile schemas must be an array');
1021
+ }
1022
+ return profile.schemas;
1023
+ }
1024
+ if (profile.schema !== undefined && profile.schema !== null) {
1025
+ return [profile.schema];
1026
+ }
1027
+ return null;
1028
+ }
1029
+ function compileSchemaPlan(schema) {
1030
+ if (schema === null || typeof schema !== 'object' || Array.isArray(schema)) {
1031
+ throw new TypeError('schema option must be an object');
1032
+ }
1033
+ if (Array.isArray(schema.schemas)) {
1034
+ if (schema.schemas.length === 0) {
1035
+ throw new TypeError('schema list must not be empty');
1036
+ }
1037
+ const plans = new Array(schema.schemas.length);
1038
+ for (let i = 0; i < schema.schemas.length; i++) {
1039
+ plans[i] = compileSingleSchemaPlan(schema.schemas[i]);
1040
+ }
1041
+ return plans.length === 1
1042
+ ? plans[0]
1043
+ : {
1044
+ type: 'multi',
1045
+ plans,
1046
+ trie: buildPlanPathTrie(plans),
1047
+ schema: { schemas: plans.map((plan) => plan.schema) }
1048
+ };
1049
+ }
1050
+ return compileSingleSchemaPlan(schema);
1051
+ }
1052
+ function compileSingleSchemaPlan(schema) {
1053
+ if (schema === null || typeof schema !== 'object' || Array.isArray(schema)) {
1054
+ throw new TypeError('schema option must be an object');
1055
+ }
1056
+ if (schema.type === 'array' &&
1057
+ schema.item !== null &&
1058
+ typeof schema.item === 'object' &&
1059
+ schema.item.type === 'object' &&
1060
+ Array.isArray(schema.item.fields)) {
1061
+ return createRecordArrayPlan(schema);
1062
+ }
1063
+ if (schema.type === 'object' &&
1064
+ Array.isArray(schema.fields)) {
1065
+ return createObjectPlan(schema);
1066
+ }
1067
+ throw new TypeError('schema option currently supports record arrays or { type: "object", fields: [...] }');
1068
+ }
1069
+ function createObjectPlan(schema) {
1070
+ const fields = schema.fields;
1071
+ if (fields.length === 0) {
1072
+ throw new TypeError('schema fields must not be empty');
1073
+ }
1074
+ const fieldSet = Object.create(null);
1075
+ const fieldList = [];
1076
+ for (let i = 0; i < fields.length; i++) {
1077
+ addFieldPlan(fieldList, fieldSet, fields[i], []);
1078
+ }
1079
+ const path = readSchemaPath(schema.path);
1080
+ const flatKeys = readFlatKeys(fieldList);
1081
+ const normalized = {
1082
+ type: 'object',
1083
+ fields: normalizeFieldSchemas(fields)
1084
+ };
1085
+ if (path.length !== 0)
1086
+ normalized.path = path.slice();
1087
+ if (schema.exact === true)
1088
+ normalized.exact = true;
1089
+ return {
1090
+ type: 'object',
1091
+ path,
1092
+ fields: fieldList,
1093
+ flatKeys,
1094
+ fieldCount: fieldList.length,
1095
+ exact: schema.exact === true,
1096
+ compiled: flatKeys === null
1097
+ ? compileNestedObjectDiff(path, fieldList)
1098
+ : compileFlatObjectDiff(path, flatKeys),
1099
+ equals: flatKeys === null ? compileNestedObjectEquals(fieldList) : compileFlatObjectEquals(flatKeys),
1100
+ schema: normalized
1101
+ };
1102
+ }
1103
+ function createRecordArrayPlan(schema) {
1104
+ const fields = schema.item.fields;
1105
+ const fieldCount = fields.length;
1106
+ if (fieldCount === 0) {
1107
+ throw new TypeError('schema item fields must not be empty');
1108
+ }
1109
+ const fieldSet = Object.create(null);
1110
+ const fieldList = [];
1111
+ for (let i = 0; i < fieldCount; i++) {
1112
+ addFieldPlan(fieldList, fieldSet, fields[i], []);
1113
+ }
1114
+ const path = readSchemaPath(schema.path);
1115
+ const key = readSchemaKey(schema);
1116
+ const flatKeys = readFlatKeys(fieldList);
1117
+ const normalized = {
1118
+ type: 'array',
1119
+ item: {
1120
+ type: 'object',
1121
+ fields: normalizeFieldSchemas(fields)
1122
+ }
1123
+ };
1124
+ if (path.length !== 0)
1125
+ normalized.path = path.slice();
1126
+ if (key !== undefined)
1127
+ normalized.key = key;
1128
+ if (schema.exact === true)
1129
+ normalized.exact = true;
1130
+ return {
1131
+ type: 'recordArray',
1132
+ path,
1133
+ fields: fieldList,
1134
+ flatKeys,
1135
+ fieldCount: fieldList.length,
1136
+ key,
1137
+ exact: schema.exact === true,
1138
+ compiled: flatKeys === null
1139
+ ? compileNestedRecordArrayDiff(path, fieldList, key)
1140
+ : compileFlatRecordArrayDiff(path, flatKeys, key),
1141
+ equals: flatKeys === null ? compileNestedRecordArrayEquals(fieldList, key) : compileFlatRecordArrayEquals(flatKeys, key),
1142
+ schema: normalized
1143
+ };
1144
+ }
1145
+ function readFlatKeys(fields) {
1146
+ const keys = new Array(fields.length);
1147
+ for (let i = 0; i < fields.length; i++) {
1148
+ if (fields[i].path.length !== 1)
1149
+ return null;
1150
+ keys[i] = fields[i].path[0];
1151
+ }
1152
+ return keys;
1153
+ }
1154
+ function addFieldPlan(fieldList, fieldSet, field, prefix) {
1155
+ if (typeof field === 'string' || typeof field === 'number') {
1156
+ const path = prefix.concat(field);
1157
+ const id = path.join('\0');
1158
+ if (fieldSet[id] === true) {
1159
+ throw new TypeError('schema item fields must be unique');
1160
+ }
1161
+ fieldSet[id] = true;
1162
+ fieldList[fieldList.length] = { path };
1163
+ return;
1164
+ }
1165
+ if (field !== null &&
1166
+ typeof field === 'object' &&
1167
+ !Array.isArray(field) &&
1168
+ (typeof field.key === 'string' || typeof field.key === 'number') &&
1169
+ field.type === 'object' &&
1170
+ Array.isArray(field.fields)) {
1171
+ const nextPrefix = prefix.concat(field.key);
1172
+ if (field.fields.length === 0) {
1173
+ throw new TypeError('schema nested object fields must not be empty');
1174
+ }
1175
+ for (let i = 0; i < field.fields.length; i++) {
1176
+ addFieldPlan(fieldList, fieldSet, field.fields[i], nextPrefix);
1177
+ }
1178
+ return;
1179
+ }
1180
+ throw new TypeError('schema item fields must be strings, numbers, or nested object field descriptors');
1181
+ }
1182
+ function normalizeFieldSchemas(fields) {
1183
+ const out = new Array(fields.length);
1184
+ for (let i = 0; i < fields.length; i++) {
1185
+ const field = fields[i];
1186
+ if (typeof field === 'string' || typeof field === 'number') {
1187
+ out[i] = field;
1188
+ }
1189
+ else {
1190
+ out[i] = {
1191
+ key: field.key,
1192
+ type: 'object',
1193
+ fields: normalizeFieldSchemas(field.fields)
1194
+ };
1195
+ }
1196
+ }
1197
+ return out;
1198
+ }
1199
+ function readSchemaPath(path) {
1200
+ if (path === undefined || path === null)
1201
+ return [];
1202
+ if (!Array.isArray(path)) {
1203
+ throw new TypeError('schema path must be an array');
1204
+ }
1205
+ for (let i = 0; i < path.length; i++) {
1206
+ const segment = path[i];
1207
+ if (typeof segment !== 'string' && typeof segment !== 'number') {
1208
+ throw new TypeError('schema path segments must be strings or numbers');
1209
+ }
1210
+ }
1211
+ return path.slice();
1212
+ }
1213
+ function readSchemaKey(schema) {
1214
+ const key = schema.key !== undefined ? schema.key : schema.item.key;
1215
+ if (key === undefined || key === null)
1216
+ return undefined;
1217
+ if (typeof key !== 'string' && typeof key !== 'number') {
1218
+ throw new TypeError('schema key must be a string or number');
1219
+ }
1220
+ return key;
1221
+ }
1222
+ function tryPlannedDiff(plan, source, target, patch, options) {
1223
+ if (plan.type === 'multi') {
1224
+ const startLength = patch.length;
1225
+ for (let i = 0, length = plan.plans.length; i < length; i++) {
1226
+ if (!tryPlannedDiffOnly(plan.plans[i], source, target, patch)) {
1227
+ patch.length = startLength;
1228
+ return false;
1229
+ }
1230
+ }
1231
+ if (!appendOutsidePlanPathsDiff(source, target, plan.trie, [], patch, options)) {
1232
+ patch.length = startLength;
1233
+ return false;
1234
+ }
1235
+ return true;
1236
+ }
1237
+ if (plan.type === 'recordArray') {
1238
+ const startLength = patch.length;
1239
+ const sourceValue = readPlanPathValue(source, plan.path);
1240
+ const targetValue = readPlanPathValue(target, plan.path);
1241
+ if (sourceValue === MISSING_PLAN_VALUE || targetValue === MISSING_PLAN_VALUE)
1242
+ return false;
1243
+ if (!exactPlanRegionMatches(plan, sourceValue, targetValue))
1244
+ return false;
1245
+ if (!tryRecordArrayDiff(plan, sourceValue, targetValue, patch))
1246
+ return false;
1247
+ if (plan.path.length !== 0 &&
1248
+ !appendOutsidePlanPathDiff(source, target, plan.path, 0, [], patch, options)) {
1249
+ patch.length = startLength;
1250
+ return false;
1251
+ }
1252
+ return true;
1253
+ }
1254
+ if (plan.type === 'object') {
1255
+ const startLength = patch.length;
1256
+ const sourceValue = readPlanPathValue(source, plan.path);
1257
+ const targetValue = readPlanPathValue(target, plan.path);
1258
+ if (sourceValue === MISSING_PLAN_VALUE || targetValue === MISSING_PLAN_VALUE)
1259
+ return false;
1260
+ if (!exactPlanRegionMatches(plan, sourceValue, targetValue))
1261
+ return false;
1262
+ if (!tryObjectDiff(plan, sourceValue, targetValue, patch))
1263
+ return false;
1264
+ if (plan.path.length !== 0 &&
1265
+ !appendOutsidePlanPathDiff(source, target, plan.path, 0, [], patch, options)) {
1266
+ patch.length = startLength;
1267
+ return false;
1268
+ }
1269
+ return true;
1270
+ }
1271
+ return false;
1272
+ }
1273
+ function tryPlannedDiffOnly(plan, source, target, patch) {
1274
+ if (plan.type === 'recordArray') {
1275
+ const sourceValue = readPlanPathValue(source, plan.path);
1276
+ const targetValue = readPlanPathValue(target, plan.path);
1277
+ return (sourceValue !== MISSING_PLAN_VALUE &&
1278
+ targetValue !== MISSING_PLAN_VALUE &&
1279
+ exactPlanRegionMatches(plan, sourceValue, targetValue) &&
1280
+ tryRecordArrayDiff(plan, sourceValue, targetValue, patch));
1281
+ }
1282
+ if (plan.type === 'object') {
1283
+ const sourceValue = readPlanPathValue(source, plan.path);
1284
+ const targetValue = readPlanPathValue(target, plan.path);
1285
+ return (sourceValue !== MISSING_PLAN_VALUE &&
1286
+ targetValue !== MISSING_PLAN_VALUE &&
1287
+ exactPlanRegionMatches(plan, sourceValue, targetValue) &&
1288
+ tryObjectDiff(plan, sourceValue, targetValue, patch));
1289
+ }
1290
+ if (plan.type === 'multi') {
1291
+ return tryPlannedDiff(plan, source, target, patch, undefined);
1292
+ }
1293
+ return false;
1294
+ }
1295
+ function tryPlannedEquals(plan, source, target, options) {
1296
+ const exact = tryPlannedEqualsNoPatch(plan, source, target);
1297
+ if (exact === true)
1298
+ return true;
1299
+ const patch = [];
1300
+ return tryPlannedDiff(plan, source, target, patch, options) && patch.length === 0 ? true : null;
1301
+ }
1302
+ function tryPlannedEqualsNoPatch(plan, source, target) {
1303
+ if (plan.type === 'multi') {
1304
+ for (let i = 0, length = plan.plans.length; i < length; i++) {
1305
+ if (tryPlannedRegionEquals(plan.plans[i], source, target) !== true)
1306
+ return null;
1307
+ }
1308
+ return equalsOutsidePlanPaths(source, target, plan.trie) ? true : null;
1309
+ }
1310
+ if (tryPlannedRegionEquals(plan, source, target) !== true)
1311
+ return null;
1312
+ return plan.path.length === 0 || equalsOutsidePlanPath(source, target, plan.path, 0) ? true : null;
1313
+ }
1314
+ function tryPlannedRegionEquals(plan, source, target) {
1315
+ if (plan.type !== 'recordArray' && plan.type !== 'object')
1316
+ return null;
1317
+ const compiledEquals = plan.equals;
1318
+ if (compiledEquals === null)
1319
+ return null;
1320
+ const sourceValue = readPlanPathValue(source, plan.path);
1321
+ const targetValue = readPlanPathValue(target, plan.path);
1322
+ if (sourceValue === MISSING_PLAN_VALUE || targetValue === MISSING_PLAN_VALUE)
1323
+ return null;
1324
+ if (!exactPlanRegionMatches(plan, sourceValue, targetValue))
1325
+ return null;
1326
+ return compiledEquals(sourceValue, targetValue) ? true : null;
1327
+ }
1328
+ function exactPlanRegionMatches(plan, sourceValue, targetValue) {
1329
+ if (plan.exact !== true)
1330
+ return true;
1331
+ if (plan.type === 'object') {
1332
+ const fields = plan.schema && plan.schema.fields;
1333
+ return exactObjectMatchesSchema(sourceValue, fields) && exactObjectMatchesSchema(targetValue, fields);
1334
+ }
1335
+ if (plan.type === 'recordArray') {
1336
+ const fields = plan.schema && plan.schema.item && plan.schema.item.fields;
1337
+ return exactRecordArrayMatchesSchema(sourceValue, fields) && exactRecordArrayMatchesSchema(targetValue, fields);
1338
+ }
1339
+ return true;
1340
+ }
1341
+ function exactRecordArrayMatchesSchema(value, fields) {
1342
+ if (!Array.isArray(value) || !Array.isArray(fields))
1343
+ return false;
1344
+ for (let i = 0, length = value.length; i < length; i++) {
1345
+ if (!exactObjectMatchesSchema(value[i], fields))
1346
+ return false;
1347
+ }
1348
+ return true;
1349
+ }
1350
+ function exactObjectMatchesSchema(value, fields) {
1351
+ if (!isPlanRecordRow(value) || !Array.isArray(fields))
1352
+ return false;
1353
+ const keys = Object.keys(value);
1354
+ if (keys.length !== fields.length)
1355
+ return false;
1356
+ for (let i = 0, length = fields.length; i < length; i++) {
1357
+ const field = fields[i];
1358
+ if (typeof field === 'string' || typeof field === 'number') {
1359
+ if (!hasOwn.call(value, field))
1360
+ return false;
1361
+ }
1362
+ else {
1363
+ if (!hasOwn.call(value, field.key) || !exactObjectMatchesSchema(value[field.key], field.fields))
1364
+ return false;
1365
+ }
1366
+ }
1367
+ return true;
1368
+ }
1369
+ function equalsOutsidePlanPath(source, target, planPath, depth) {
1370
+ if (depth >= planPath.length)
1371
+ return true;
1372
+ if (!isDiffableContainer(source) || !isDiffableContainer(target))
1373
+ return false;
1374
+ if (Array.isArray(source) || Array.isArray(target)) {
1375
+ if (!Array.isArray(source) || !Array.isArray(target) || source.length !== target.length)
1376
+ return false;
1377
+ }
1378
+ const skip = planPath[depth];
1379
+ const skipKey = String(skip);
1380
+ const sourceKeys = Object.keys(source);
1381
+ for (let i = 0, length = sourceKeys.length; i < length; i++) {
1382
+ const key = sourceKeys[i];
1383
+ if (key === skipKey)
1384
+ continue;
1385
+ if (!hasOwn.call(target, key) || !equalsJsonFast(source[key], target[key]))
1386
+ return false;
1387
+ }
1388
+ const targetKeys = Object.keys(target);
1389
+ for (let i = 0, length = targetKeys.length; i < length; i++) {
1390
+ const key = targetKeys[i];
1391
+ if (key !== skipKey && !hasOwn.call(source, key))
1392
+ return false;
1393
+ }
1394
+ if (!hasOwn.call(source, skip) || !hasOwn.call(target, skip))
1395
+ return false;
1396
+ return equalsOutsidePlanPath(source[skip], target[skip], planPath, depth + 1);
1397
+ }
1398
+ function equalsOutsidePlanPaths(source, target, trie) {
1399
+ if (trie.terminal)
1400
+ return true;
1401
+ if (!isDiffableContainer(source) || !isDiffableContainer(target))
1402
+ return false;
1403
+ if (Array.isArray(source) || Array.isArray(target)) {
1404
+ if (!Array.isArray(source) || !Array.isArray(target) || source.length !== target.length)
1405
+ return false;
1406
+ }
1407
+ const children = trie.children;
1408
+ const sourceKeys = Object.keys(source);
1409
+ for (let i = 0, length = sourceKeys.length; i < length; i++) {
1410
+ const key = sourceKeys[i];
1411
+ const child = children[key];
1412
+ if (child !== undefined) {
1413
+ if (!hasOwn.call(target, key) || !equalsOutsidePlanPaths(source[key], target[key], child))
1414
+ return false;
1415
+ }
1416
+ else if (!hasOwn.call(target, key) || !equalsJsonFast(source[key], target[key])) {
1417
+ return false;
1418
+ }
1419
+ }
1420
+ const targetKeys = Object.keys(target);
1421
+ for (let i = 0, length = targetKeys.length; i < length; i++) {
1422
+ const key = targetKeys[i];
1423
+ if (!hasOwn.call(source, key))
1424
+ return false;
1425
+ }
1426
+ return true;
1427
+ }
1428
+ function buildPlanPathTrie(plans) {
1429
+ const root = createPlanPathTrieNode();
1430
+ for (let i = 0, length = plans.length; i < length; i++) {
1431
+ let node = root;
1432
+ const path = plans[i].path;
1433
+ for (let j = 0, pathLength = path.length; j < pathLength; j++) {
1434
+ const key = String(path[j]);
1435
+ let child = node.children[key];
1436
+ if (child === undefined) {
1437
+ child = createPlanPathTrieNode();
1438
+ node.children[key] = child;
1439
+ }
1440
+ node = child;
1441
+ }
1442
+ node.terminal = true;
1443
+ }
1444
+ return root;
1445
+ }
1446
+ function createPlanPathTrieNode() {
1447
+ return {
1448
+ terminal: false,
1449
+ children: Object.create(null)
1450
+ };
1451
+ }
1452
+ const MISSING_PLAN_VALUE = Symbol('missingPlanValue');
1453
+ function readPlanPathValue(root, path) {
1454
+ let value = root;
1455
+ for (let i = 0, length = path.length; i < length; i++) {
1456
+ if (value === null || typeof value !== 'object')
1457
+ return MISSING_PLAN_VALUE;
1458
+ const key = path[i];
1459
+ if (!hasOwn.call(value, key))
1460
+ return MISSING_PLAN_VALUE;
1461
+ value = value[key];
1462
+ }
1463
+ return value;
1464
+ }
1465
+ function appendOutsidePlanPathDiff(source, target, planPath, depth, prefix, patch, options) {
1466
+ if (depth >= planPath.length)
1467
+ return true;
1468
+ if (!isDiffableContainer(source) || !isDiffableContainer(target))
1469
+ return false;
1470
+ const skip = planPath[depth];
1471
+ const skipKey = String(skip);
1472
+ const sourceKeys = Object.keys(source);
1473
+ for (let i = 0, length = sourceKeys.length; i < length; i++) {
1474
+ const key = sourceKeys[i];
1475
+ if (key === skipKey)
1476
+ continue;
1477
+ if (hasOwn.call(target, key)) {
1478
+ const sourceChild = source[key];
1479
+ const targetChild = target[key];
1480
+ if (sameJsonValue(sourceChild, targetChild))
1481
+ continue;
1482
+ appendGenericDiffAtPath(sourceChild, targetChild, appendPathSegment(prefix, key), patch, options);
1483
+ }
1484
+ else {
1485
+ patch[patch.length] = [OP_REMOVE, appendPathSegment(prefix, key)];
1486
+ }
1487
+ }
1488
+ const targetKeys = Object.keys(target);
1489
+ for (let i = 0, length = targetKeys.length; i < length; i++) {
1490
+ const key = targetKeys[i];
1491
+ if (key === skipKey || hasOwn.call(source, key))
1492
+ continue;
1493
+ patch[patch.length] = [OP_SET, appendPathSegment(prefix, key), clonePayload(target[key])];
1494
+ }
1495
+ if (!hasOwn.call(source, skip) || !hasOwn.call(target, skip))
1496
+ return false;
1497
+ prefix[prefix.length] = skip;
1498
+ const ok = appendOutsidePlanPathDiff(source[skip], target[skip], planPath, depth + 1, prefix, patch, options);
1499
+ prefix.length--;
1500
+ return ok;
1501
+ }
1502
+ function appendOutsidePlanPathsDiff(source, target, trie, prefix, patch, options) {
1503
+ if (trie.terminal)
1504
+ return true;
1505
+ if (!isDiffableContainer(source) || !isDiffableContainer(target))
1506
+ return false;
1507
+ const children = trie.children;
1508
+ const sourceKeys = Object.keys(source);
1509
+ for (let i = 0, length = sourceKeys.length; i < length; i++) {
1510
+ const key = sourceKeys[i];
1511
+ const child = children[key];
1512
+ if (child !== undefined) {
1513
+ if (!hasOwn.call(target, key))
1514
+ return false;
1515
+ prefix[prefix.length] = readOutputPathSegment(source, key);
1516
+ const ok = appendOutsidePlanPathsDiff(source[key], target[key], child, prefix, patch, options);
1517
+ prefix.length--;
1518
+ if (!ok)
1519
+ return false;
1520
+ continue;
1521
+ }
1522
+ if (hasOwn.call(target, key)) {
1523
+ const sourceChild = source[key];
1524
+ const targetChild = target[key];
1525
+ if (sameJsonValue(sourceChild, targetChild))
1526
+ continue;
1527
+ appendGenericDiffAtPath(sourceChild, targetChild, appendPathSegment(prefix, readOutputPathSegment(source, key)), patch, options);
1528
+ }
1529
+ else {
1530
+ patch[patch.length] = [OP_REMOVE, appendPathSegment(prefix, readOutputPathSegment(source, key))];
1531
+ }
1532
+ }
1533
+ const targetKeys = Object.keys(target);
1534
+ for (let i = 0, length = targetKeys.length; i < length; i++) {
1535
+ const key = targetKeys[i];
1536
+ if (hasOwn.call(source, key))
1537
+ continue;
1538
+ if (children[key] !== undefined)
1539
+ return false;
1540
+ patch[patch.length] = [OP_SET, appendPathSegment(prefix, readOutputPathSegment(target, key)), clonePayload(target[key])];
1541
+ }
1542
+ return true;
1543
+ }
1544
+ function readOutputPathSegment(container, key) {
1545
+ return Array.isArray(container) && isArrayIndexKey(key) ? Number(key) : key;
1546
+ }
1547
+ function isArrayIndexKey(key) {
1548
+ return key !== '' && String(Number(key)) === key && Number.isSafeInteger(Number(key)) && Number(key) >= 0;
1549
+ }
1550
+ function isDiffableContainer(value) {
1551
+ return value !== null && typeof value === 'object';
1552
+ }
1553
+ function appendPathSegment(prefix, key) {
1554
+ const out = prefix.slice();
1555
+ out[out.length] = key;
1556
+ return out;
1557
+ }
1558
+ function appendGenericDiffAtPath(source, target, prefix, patch, options) {
1559
+ const local = computeDiffInto(source, target, [], options);
1560
+ for (let i = 0, length = local.length; i < length; i++) {
1561
+ const op = cloneOperation(local[i]);
1562
+ op[1] = prefix.concat(op[1]);
1563
+ patch[patch.length] = op;
1564
+ }
1565
+ }
1566
+ function tryRecordArrayDiff(plan, source, target, patch) {
1567
+ if (plan.compiled !== null) {
1568
+ const startLength = patch.length;
1569
+ if (plan.compiled(source, target, patch))
1570
+ return true;
1571
+ patch.length = startLength;
1572
+ return plan.key !== undefined && tryKeyedRecordArrayPlanDiff(plan, source, target, patch);
1573
+ }
1574
+ if (plan.flatKeys !== null) {
1575
+ const startLength = patch.length;
1576
+ if (tryFlatRecordArrayDiff(plan, source, target, patch))
1577
+ return true;
1578
+ patch.length = startLength;
1579
+ return plan.key !== undefined && tryKeyedRecordArrayPlanDiff(plan, source, target, patch);
1580
+ }
1581
+ if (!Array.isArray(source) || !Array.isArray(target))
1582
+ return false;
1583
+ const length = source.length;
1584
+ if (length !== target.length)
1585
+ return false;
1586
+ const startLength = patch.length;
1587
+ const fields = plan.fields;
1588
+ const fieldCount = plan.fieldCount;
1589
+ for (let i = 0; i < length; i++) {
1590
+ const sourceRow = source[i];
1591
+ const targetRow = target[i];
1592
+ if (sourceRow === null ||
1593
+ targetRow === null ||
1594
+ typeof sourceRow !== 'object' ||
1595
+ typeof targetRow !== 'object' ||
1596
+ Array.isArray(sourceRow) ||
1597
+ Array.isArray(targetRow)) {
1598
+ patch.length = startLength;
1599
+ return false;
1600
+ }
1601
+ if (plan.key !== undefined) {
1602
+ if (!hasOwn.call(sourceRow, plan.key) ||
1603
+ !hasOwn.call(targetRow, plan.key) ||
1604
+ !sameJsonValue(sourceRow[plan.key], targetRow[plan.key])) {
1605
+ patch.length = startLength;
1606
+ return false;
1607
+ }
1608
+ }
1609
+ let assign = null;
1610
+ let changeCount = 0;
1611
+ let changeKey;
1612
+ let changeValue;
1613
+ for (let j = 0; j < fieldCount; j++) {
1614
+ const field = fields[j];
1615
+ if (plan.key !== undefined && field.path.length === 1 && field.path[0] === plan.key)
1616
+ continue;
1617
+ const sourceValue = field.path.length === 1
1618
+ ? readOwnValue(sourceRow, field.path[0])
1619
+ : readPlanPathValue(sourceRow, field.path);
1620
+ const targetValue = field.path.length === 1
1621
+ ? readOwnValue(targetRow, field.path[0])
1622
+ : readPlanPathValue(targetRow, field.path);
1623
+ if (sourceValue === MISSING_PLAN_VALUE || targetValue === MISSING_PLAN_VALUE) {
1624
+ patch.length = startLength;
1625
+ return false;
1626
+ }
1627
+ if (sameJsonValue(sourceValue, targetValue))
1628
+ continue;
1629
+ if (field.path.length === 1) {
1630
+ const key = field.path[0];
1631
+ changeCount++;
1632
+ if (changeCount === 1) {
1633
+ changeKey = key;
1634
+ changeValue = targetValue;
1635
+ }
1636
+ else {
1637
+ if (assign === null) {
1638
+ assign = {};
1639
+ assign[changeKey] = clonePayload(changeValue);
1640
+ }
1641
+ assign[key] = clonePayload(targetValue);
1642
+ }
1643
+ }
1644
+ else {
1645
+ patch[patch.length] = [OP_SET, makeRecordPath(plan.path, i, field.path), clonePayload(targetValue)];
1646
+ }
1647
+ }
1648
+ if (changeCount === 1) {
1649
+ patch[patch.length] = [OP_SET, makeRecordPath(plan.path, i, changeKey), clonePayload(changeValue)];
1650
+ }
1651
+ else if (changeCount > 1) {
1652
+ patch[patch.length] = [OP_ASSIGN, makeRecordPath(plan.path, i), assign];
1653
+ }
1654
+ }
1655
+ return true;
1656
+ }
1657
+ function tryKeyedRecordArrayPlanDiff(plan, source, target, patch) {
1658
+ if (plan.key === undefined || !Array.isArray(source) || !Array.isArray(target))
1659
+ return false;
1660
+ const startLength = patch.length;
1661
+ const sourceLength = source.length;
1662
+ const targetLength = target.length;
1663
+ const arrayPath = plan.path.slice();
1664
+ if (sourceLength === 0) {
1665
+ if (targetLength !== 0) {
1666
+ patch[patch.length] = [OP_APPEND, arrayPath, clonePayload(target)];
1667
+ }
1668
+ return true;
1669
+ }
1670
+ if (targetLength === 0) {
1671
+ patch[patch.length] = [OP_TRUNCATE, arrayPath, 0];
1672
+ return true;
1673
+ }
1674
+ const sourceKeys = new Array(sourceLength);
1675
+ const sourceKeyToIndex = new Map();
1676
+ for (let i = 0; i < sourceLength; i++) {
1677
+ const row = source[i];
1678
+ if (!isPlanRecordRow(row) || !hasOwn.call(row, plan.key))
1679
+ return false;
1680
+ const key = row[plan.key];
1681
+ if (!isPlannedRecordKeyValue(key) || sourceKeyToIndex.has(key))
1682
+ return false;
1683
+ sourceKeys[i] = key;
1684
+ sourceKeyToIndex.set(key, i);
1685
+ }
1686
+ const targetKeys = new Array(targetLength);
1687
+ const targetSeen = new Set();
1688
+ for (let i = 0; i < targetLength; i++) {
1689
+ const row = target[i];
1690
+ if (!isPlanRecordRow(row) || !hasOwn.call(row, plan.key))
1691
+ return false;
1692
+ const key = row[plan.key];
1693
+ if (!isPlannedRecordKeyValue(key) || targetSeen.has(key))
1694
+ return false;
1695
+ targetKeys[i] = key;
1696
+ targetSeen.add(key);
1697
+ }
1698
+ const workKeys = sourceKeys.slice();
1699
+ for (let sourceIndex = sourceLength - 1; sourceIndex >= 0;) {
1700
+ if (targetSeen.has(workKeys[sourceIndex])) {
1701
+ sourceIndex--;
1702
+ continue;
1703
+ }
1704
+ const deleteEnd = sourceIndex + 1;
1705
+ do {
1706
+ sourceIndex--;
1707
+ } while (sourceIndex >= 0 && !targetSeen.has(workKeys[sourceIndex]));
1708
+ const deleteStart = sourceIndex + 1;
1709
+ const deleteCount = deleteEnd - deleteStart;
1710
+ patch[patch.length] = [OP_ARRAY_SPLICE, arrayPath, deleteStart, deleteCount, []];
1711
+ workKeys.splice(deleteStart, deleteCount);
1712
+ }
1713
+ for (let targetIndex = 0; targetIndex < targetLength; targetIndex++) {
1714
+ const targetKey = targetKeys[targetIndex];
1715
+ if (workKeys[targetIndex] === targetKey)
1716
+ continue;
1717
+ if (!sourceKeyToIndex.has(targetKey)) {
1718
+ let insertEnd = targetIndex + 1;
1719
+ while (insertEnd < targetLength && !sourceKeyToIndex.has(targetKeys[insertEnd]))
1720
+ insertEnd++;
1721
+ const insertCount = insertEnd - targetIndex;
1722
+ const values = new Array(insertCount);
1723
+ const keys = new Array(insertCount);
1724
+ for (let i = 0; i < insertCount; i++) {
1725
+ values[i] = clonePayload(target[targetIndex + i]);
1726
+ keys[i] = targetKeys[targetIndex + i];
1727
+ }
1728
+ patch[patch.length] = [OP_ARRAY_SPLICE, arrayPath, targetIndex, 0, values];
1729
+ insertPlannedKeys(workKeys, targetIndex, keys);
1730
+ targetIndex = insertEnd - 1;
1731
+ continue;
1732
+ }
1733
+ const sourceIndex = indexOfPlannedKey(workKeys, targetKey, targetIndex + 1);
1734
+ if (sourceIndex < 0) {
1735
+ patch.length = startLength;
1736
+ return false;
1737
+ }
1738
+ patch[patch.length] = [OP_ARRAY_MOVE, arrayPath, sourceIndex, targetIndex];
1739
+ movePlannedKey(workKeys, sourceIndex, targetIndex);
1740
+ }
1741
+ const batch = { indexes: null, values: null };
1742
+ for (let targetIndex = 0; targetIndex < targetLength; targetIndex++) {
1743
+ const sourceIndex = sourceKeyToIndex.get(targetKeys[targetIndex]);
1744
+ if (sourceIndex === undefined)
1745
+ continue;
1746
+ if (!appendKeyedRecordArrayPlanRowDiff(plan, source[sourceIndex], target[targetIndex], targetIndex, patch, batch)) {
1747
+ patch.length = startLength;
1748
+ return false;
1749
+ }
1750
+ }
1751
+ flushKeyedRecordArrayPlanBatch(plan, patch, batch);
1752
+ return true;
1753
+ }
1754
+ function appendKeyedRecordArrayPlanRowDiff(plan, sourceRow, targetRow, targetIndex, patch, batch) {
1755
+ if (!isPlanRecordRow(sourceRow) || !isPlanRecordRow(targetRow))
1756
+ return false;
1757
+ const fields = plan.fields;
1758
+ const fieldCount = plan.fieldCount;
1759
+ let assign = null;
1760
+ let changeCount = 0;
1761
+ let changeKey;
1762
+ let changeValue;
1763
+ for (let i = 0; i < fieldCount; i++) {
1764
+ const field = fields[i];
1765
+ if (field.path.length === 1 && field.path[0] === plan.key)
1766
+ continue;
1767
+ const sourceValue = field.path.length === 1
1768
+ ? readOwnValue(sourceRow, field.path[0])
1769
+ : readPlanPathValue(sourceRow, field.path);
1770
+ const targetValue = field.path.length === 1
1771
+ ? readOwnValue(targetRow, field.path[0])
1772
+ : readPlanPathValue(targetRow, field.path);
1773
+ if (sourceValue === MISSING_PLAN_VALUE || targetValue === MISSING_PLAN_VALUE)
1774
+ return false;
1775
+ if (sameJsonValue(sourceValue, targetValue))
1776
+ continue;
1777
+ if (field.path.length === 1) {
1778
+ const key = field.path[0];
1779
+ changeCount++;
1780
+ if (changeCount === 1) {
1781
+ changeKey = key;
1782
+ changeValue = targetValue;
1783
+ }
1784
+ else {
1785
+ if (assign === null) {
1786
+ assign = {};
1787
+ assign[changeKey] = clonePayload(changeValue);
1788
+ }
1789
+ assign[key] = clonePayload(targetValue);
1790
+ }
1791
+ }
1792
+ else {
1793
+ flushKeyedRecordArrayPlanBatch(plan, patch, batch);
1794
+ patch[patch.length] = [OP_SET, makeRecordPath(plan.path, targetIndex, field.path), clonePayload(targetValue)];
1795
+ }
1796
+ }
1797
+ if (changeCount === 1) {
1798
+ appendKeyedRecordArrayPlanBatchValue(batch, targetIndex, { [changeKey]: clonePayload(changeValue) });
1799
+ }
1800
+ else if (changeCount > 1) {
1801
+ appendKeyedRecordArrayPlanBatchValue(batch, targetIndex, assign);
1802
+ }
1803
+ return true;
1804
+ }
1805
+ function appendKeyedRecordArrayPlanBatchValue(batch, index, assign) {
1806
+ if (batch.indexes === null) {
1807
+ batch.indexes = [];
1808
+ batch.values = [];
1809
+ }
1810
+ batch.indexes[batch.indexes.length] = index;
1811
+ batch.values[batch.values.length] = assign;
1812
+ }
1813
+ function flushKeyedRecordArrayPlanBatch(plan, patch, batch) {
1814
+ if (batch.indexes === null)
1815
+ return;
1816
+ const indexes = batch.indexes;
1817
+ const values = batch.values;
1818
+ if (indexes.length === 1) {
1819
+ const assign = values[0];
1820
+ const keys = Object.keys(assign);
1821
+ if (keys.length === 1) {
1822
+ const key = keys[0];
1823
+ patch[patch.length] = [OP_SET, makeRecordPath(plan.path, indexes[0], key), assign[key]];
1824
+ }
1825
+ else {
1826
+ patch[patch.length] = [OP_ASSIGN, makeRecordPath(plan.path, indexes[0]), assign];
1827
+ }
1828
+ }
1829
+ else if (!tryEmitObjectAssignAsFieldAssign(patch, plan.path.slice(), indexes, values)) {
1830
+ patch[patch.length] = [OP_ARRAY_OBJECT_ASSIGN, plan.path.slice(), indexes, values];
1831
+ }
1832
+ batch.indexes = null;
1833
+ batch.values = null;
1834
+ }
1835
+ function isPlanRecordRow(value) {
1836
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
1837
+ }
1838
+ function isPlannedRecordKeyValue(value) {
1839
+ if (typeof value === 'string')
1840
+ return value.length > 0;
1841
+ if (typeof value === 'number')
1842
+ return Number.isSafeInteger(value) && !Object.is(value, -0);
1843
+ return typeof value === 'boolean';
1844
+ }
1845
+ function indexOfPlannedKey(keys, key, start) {
1846
+ for (let i = start, length = keys.length; i < length; i++) {
1847
+ if (keys[i] === key)
1848
+ return i;
1849
+ }
1850
+ return -1;
1851
+ }
1852
+ function insertPlannedKeys(keys, index, values) {
1853
+ for (let i = keys.length - 1; i >= index; i--)
1854
+ keys[i + values.length] = keys[i];
1855
+ for (let i = 0, length = values.length; i < length; i++)
1856
+ keys[index + i] = values[i];
1857
+ }
1858
+ function movePlannedKey(keys, from, to) {
1859
+ const value = keys[from];
1860
+ if (from < to) {
1861
+ for (let i = from; i < to; i++)
1862
+ keys[i] = keys[i + 1];
1863
+ }
1864
+ else {
1865
+ for (let i = from; i > to; i--)
1866
+ keys[i] = keys[i - 1];
1867
+ }
1868
+ keys[to] = value;
1869
+ }
1870
+ function tryObjectDiff(plan, source, target, patch) {
1871
+ if (plan.compiled !== null) {
1872
+ return plan.compiled(source, target, patch);
1873
+ }
1874
+ if (source === null ||
1875
+ target === null ||
1876
+ typeof source !== 'object' ||
1877
+ typeof target !== 'object' ||
1878
+ Array.isArray(source) ||
1879
+ Array.isArray(target)) {
1880
+ return false;
1881
+ }
1882
+ const startLength = patch.length;
1883
+ const fields = plan.fields;
1884
+ const fieldCount = plan.fieldCount;
1885
+ let assign = null;
1886
+ let changeCount = 0;
1887
+ let changeKey;
1888
+ let changeValue;
1889
+ for (let i = 0; i < fieldCount; i++) {
1890
+ const field = fields[i];
1891
+ const sourceValue = field.path.length === 1
1892
+ ? readOwnValue(source, field.path[0])
1893
+ : readPlanPathValue(source, field.path);
1894
+ const targetValue = field.path.length === 1
1895
+ ? readOwnValue(target, field.path[0])
1896
+ : readPlanPathValue(target, field.path);
1897
+ if (sourceValue === MISSING_PLAN_VALUE || targetValue === MISSING_PLAN_VALUE) {
1898
+ patch.length = startLength;
1899
+ return false;
1900
+ }
1901
+ if (sameJsonValue(sourceValue, targetValue))
1902
+ continue;
1903
+ if (field.path.length === 1) {
1904
+ if (!canAssignPlannedValue(sourceValue, targetValue)) {
1905
+ patch.length = startLength;
1906
+ return false;
1907
+ }
1908
+ const key = field.path[0];
1909
+ changeCount++;
1910
+ if (changeCount === 1) {
1911
+ changeKey = key;
1912
+ changeValue = targetValue;
1913
+ }
1914
+ else {
1915
+ if (assign === null) {
1916
+ assign = {};
1917
+ assign[changeKey] = clonePayload(changeValue);
1918
+ }
1919
+ assign[key] = clonePayload(targetValue);
1920
+ }
1921
+ }
1922
+ else {
1923
+ patch[patch.length] = [OP_SET, makeObjectPath(plan.path, field.path), clonePayload(targetValue)];
1924
+ }
1925
+ }
1926
+ if (changeCount === 1) {
1927
+ patch[patch.length] = [OP_SET, makeObjectPath(plan.path, changeKey), clonePayload(changeValue)];
1928
+ }
1929
+ else if (changeCount > 1) {
1930
+ patch[patch.length] = [OP_ASSIGN, plan.path.slice(), assign];
1931
+ }
1932
+ return true;
1933
+ }
1934
+ function tryFlatRecordArrayDiff(plan, source, target, patch) {
1935
+ if (plan.compiled !== null) {
1936
+ return plan.compiled(source, target, patch);
1937
+ }
1938
+ if (!Array.isArray(source) || !Array.isArray(target))
1939
+ return false;
1940
+ const length = source.length;
1941
+ if (length !== target.length)
1942
+ return false;
1943
+ const startLength = patch.length;
1944
+ const fields = plan.flatKeys;
1945
+ const fieldCount = plan.fieldCount;
1946
+ for (let i = 0; i < length; i++) {
1947
+ const sourceRow = source[i];
1948
+ const targetRow = target[i];
1949
+ if (sourceRow === null ||
1950
+ targetRow === null ||
1951
+ typeof sourceRow !== 'object' ||
1952
+ typeof targetRow !== 'object' ||
1953
+ Array.isArray(sourceRow) ||
1954
+ Array.isArray(targetRow)) {
1955
+ patch.length = startLength;
1956
+ return false;
1957
+ }
1958
+ if (plan.key !== undefined) {
1959
+ if (!hasOwn.call(sourceRow, plan.key) ||
1960
+ !hasOwn.call(targetRow, plan.key) ||
1961
+ !sameJsonValue(sourceRow[plan.key], targetRow[plan.key])) {
1962
+ patch.length = startLength;
1963
+ return false;
1964
+ }
1965
+ }
1966
+ let assign = null;
1967
+ let changeCount = 0;
1968
+ let changeKey;
1969
+ let changeValue;
1970
+ for (let j = 0; j < fieldCount; j++) {
1971
+ const key = fields[j];
1972
+ if (plan.key !== undefined && key === plan.key)
1973
+ continue;
1974
+ const sourceValue = sourceRow[key];
1975
+ const targetValue = targetRow[key];
1976
+ if ((sourceValue === undefined && !hasOwn.call(sourceRow, key)) ||
1977
+ (targetValue === undefined && !hasOwn.call(targetRow, key))) {
1978
+ patch.length = startLength;
1979
+ return false;
1980
+ }
1981
+ if (sameJsonValue(sourceValue, targetValue))
1982
+ continue;
1983
+ changeCount++;
1984
+ if (changeCount === 1) {
1985
+ changeKey = key;
1986
+ changeValue = targetValue;
1987
+ }
1988
+ else {
1989
+ if (assign === null) {
1990
+ assign = {};
1991
+ assign[changeKey] = clonePayload(changeValue);
1992
+ }
1993
+ assign[key] = clonePayload(targetValue);
1994
+ }
1995
+ }
1996
+ if (changeCount === 1) {
1997
+ patch[patch.length] = [OP_SET, makeRecordPath(plan.path, i, changeKey), clonePayload(changeValue)];
1998
+ }
1999
+ else if (changeCount > 1) {
2000
+ patch[patch.length] = [OP_ASSIGN, makeRecordPath(plan.path, i), assign];
2001
+ }
2002
+ }
2003
+ return true;
2004
+ }
2005
+ function compileFlatRecordArrayDiff(path, fields, key) {
2006
+ const bitmaskCompiled = compileFlatRecordArrayBitmaskDiff(path, fields, key);
2007
+ if (bitmaskCompiled !== null)
2008
+ return bitmaskCompiled;
2009
+ const cacheKey = makeCompiledPlanCacheKey('recordArray', path, fields, key);
2010
+ const cached = flatRecordArrayDiffCache.get(cacheKey);
2011
+ if (cached !== undefined)
2012
+ return cached;
2013
+ const pathPrefix = path.map((segment) => JSON.stringify(segment)).join(',');
2014
+ const prefix = pathPrefix === '' ? '' : pathPrefix + ',';
2015
+ const rowPath = '[' + prefix + 'i]';
2016
+ const startPath = pathPrefix === '' ? '[]' : '[' + pathPrefix + ']';
2017
+ const singleRowPath = '[' + prefix + 'batchIndexes[0]]';
2018
+ const singleKeyPath = '[' + prefix + 'batchIndexes[0],singleKey]';
2019
+ const lines = [
2020
+ 'return function compiledFlatRecordArrayDiff(source,target,patch){',
2021
+ 'if(!Array.isArray(source)||!Array.isArray(target))return false;',
2022
+ 'const length=source.length;',
2023
+ 'if(length!==target.length)return false;',
2024
+ 'const startLength=patch.length;',
2025
+ 'let batchIndexes=null;',
2026
+ 'let batchValues=null;',
2027
+ 'for(let i=0;i<length;i++){',
2028
+ 'const sr=source[i];',
2029
+ 'const tr=target[i];',
2030
+ 'if(i<16&&(sr===null||tr===null||typeof sr!=="object"||typeof tr!=="object"||Array.isArray(sr)||Array.isArray(tr))){patch.length=startLength;return false;}'
2031
+ ];
2032
+ if (key !== undefined) {
2033
+ const keyLiteral = JSON.stringify(key);
2034
+ lines.push('const sk=sr[' + keyLiteral + '];', 'const tk=tr[' + keyLiteral + '];', 'if((sk!==tk)||(sk===0&&1/sk!==1/tk)){patch.length=startLength;return false;}');
2035
+ }
2036
+ lines.push('let assign=null;', 'let changeCount=0;', 'let changeKey;', 'let changeValue;');
2037
+ for (let i = 0; i < fields.length; i++) {
2038
+ if (key !== undefined && fields[i] === key)
2039
+ continue;
2040
+ const literal = JSON.stringify(fields[i]);
2041
+ const sourceName = 's' + i;
2042
+ const targetName = 't' + i;
2043
+ lines.push('const ' + sourceName + '=sr[' + literal + '];', 'const ' + targetName + '=tr[' + literal + '];');
2044
+ lines.push('if((' + sourceName + '!==' + targetName + ')||(' + sourceName + '===0&&1/' + sourceName + '!==1/' + targetName + ')){', 'changeCount++;', 'if(changeCount===1){changeKey=' + literal + ';changeValue=' + targetName + ';}else{', 'if(assign===null){assign={};assign[changeKey]=clonePayload(changeValue);}', 'assign[' + literal + ']=clonePayload(' + targetName + ');', '}', '}');
2045
+ }
2046
+ lines.push('if(changeCount===1){if(batchIndexes===null){batchIndexes=[];batchValues=[];}const singleAssign={};singleAssign[changeKey]=clonePayload(changeValue);batchIndexes[batchIndexes.length]=i;batchValues[batchValues.length]=singleAssign;}', 'else if(changeCount>1){if(batchIndexes===null){batchIndexes=[];batchValues=[];}batchIndexes[batchIndexes.length]=i;batchValues[batchValues.length]=assign;}', '}', 'if(batchIndexes!==null){if(batchIndexes.length===1){const singleAssign=batchValues[0];const singleKeys=Object.keys(singleAssign);if(singleKeys.length===1){const singleKey=singleKeys[0];patch[patch.length]=[OP_SET,' + singleKeyPath + ',singleAssign[singleKey]];}else{patch[patch.length]=[OP_ASSIGN,' + singleRowPath + ',singleAssign];}}else if(!tryEmitObjectAssignAsFieldAssign(patch,' + startPath + ',batchIndexes,batchValues)){patch[patch.length]=[OP_ARRAY_OBJECT_ASSIGN,' + startPath + ',batchIndexes,batchValues];}}', 'return true;', '}');
2047
+ try {
2048
+ const compiled = Function('OP_SET', 'OP_ASSIGN', 'OP_ARRAY_OBJECT_ASSIGN', 'clonePayload', 'tryEmitObjectAssignAsFieldAssign', lines.join('\n'))(OP_SET, OP_ASSIGN, OP_ARRAY_OBJECT_ASSIGN, clonePayload, tryEmitObjectAssignAsFieldAssign);
2049
+ rememberCompiledPlan(flatRecordArrayDiffCache, cacheKey, compiled);
2050
+ return compiled;
2051
+ }
2052
+ catch {
2053
+ return null;
2054
+ }
2055
+ }
2056
+ function compileFlatRecordArrayEquals(fields, key) {
2057
+ const cacheKey = makeCompiledPlanCacheKey('recordArrayEquals', [], fields, key);
2058
+ const cached = flatRecordArrayEqualsCache.get(cacheKey);
2059
+ if (cached !== undefined)
2060
+ return cached;
2061
+ const lines = [
2062
+ 'return function compiledFlatRecordArrayEquals(source,target){',
2063
+ 'if(!Array.isArray(source)||!Array.isArray(target))return false;',
2064
+ 'const length=source.length;',
2065
+ 'if(length!==target.length)return false;',
2066
+ 'for(let i=0;i<length;i++){',
2067
+ 'const sr=source[i];',
2068
+ 'const tr=target[i];',
2069
+ 'if(i<16&&(sr===null||tr===null||typeof sr!=="object"||typeof tr!=="object"||Array.isArray(sr)||Array.isArray(tr)))return false;'
2070
+ ];
2071
+ if (key !== undefined) {
2072
+ const keyLiteral = JSON.stringify(key);
2073
+ lines.push('const sk=sr[' + keyLiteral + '];', 'const tk=tr[' + keyLiteral + '];', 'if((sk!==tk)||(sk===0&&1/sk!==1/tk))return false;');
2074
+ }
2075
+ for (let i = 0; i < fields.length; i++) {
2076
+ if (key !== undefined && fields[i] === key)
2077
+ continue;
2078
+ const literal = JSON.stringify(fields[i]);
2079
+ const sourceName = 's' + i;
2080
+ const targetName = 't' + i;
2081
+ lines.push('const ' + sourceName + '=sr[' + literal + '];', 'const ' + targetName + '=tr[' + literal + '];', 'if((' + sourceName + '!==' + targetName + ')||(' + sourceName + '===0&&1/' + sourceName + '!==1/' + targetName + '))return false;');
2082
+ }
2083
+ lines.push('}', 'return true;', '}');
2084
+ try {
2085
+ const compiled = Function(lines.join('\n'))();
2086
+ rememberCompiledPlan(flatRecordArrayEqualsCache, cacheKey, compiled);
2087
+ return compiled;
2088
+ }
2089
+ catch {
2090
+ return null;
2091
+ }
2092
+ }
2093
+ function compileNestedRecordArrayEquals(fields, key) {
2094
+ const cacheKey = makeCompiledPlanCacheKey('recordArrayNestedEquals', [], fields.map((field) => field.path), key);
2095
+ const cached = nestedRecordArrayEqualsCache.get(cacheKey);
2096
+ if (cached !== undefined)
2097
+ return cached;
2098
+ const lines = [
2099
+ 'return function compiledNestedRecordArrayEquals(source,target){',
2100
+ 'if(!Array.isArray(source)||!Array.isArray(target))return false;',
2101
+ 'const length=source.length;',
2102
+ 'if(length!==target.length)return false;',
2103
+ 'for(let i=0;i<length;i++){',
2104
+ 'const sr=source[i];',
2105
+ 'const tr=target[i];',
2106
+ 'if(sr===null||tr===null||typeof sr!=="object"||typeof tr!=="object"||Array.isArray(sr)||Array.isArray(tr))return false;'
2107
+ ];
2108
+ if (key !== undefined) {
2109
+ const keyLiteral = JSON.stringify(key);
2110
+ lines.push('const sk=sr[' + keyLiteral + '];', 'const tk=tr[' + keyLiteral + '];', 'if((sk!==tk)||(sk===0&&1/sk!==1/tk))return false;');
2111
+ }
2112
+ const parentPrefixes = readNestedParentPrefixes(fields);
2113
+ const sourceParents = new Map();
2114
+ const targetParents = new Map();
2115
+ for (let i = 0; i < parentPrefixes.length; i++) {
2116
+ const parentPath = parentPrefixes[i];
2117
+ const sourceParent = 'sp' + i;
2118
+ const targetParent = 'tp' + i;
2119
+ sourceParents.set(pathKey(parentPath), sourceParent);
2120
+ targetParents.set(pathKey(parentPath), targetParent);
2121
+ appendNestedParentEqualsRead(lines, 'sr', parentPath, sourceParent);
2122
+ appendNestedParentEqualsRead(lines, 'tr', parentPath, targetParent);
2123
+ }
2124
+ for (let i = 0; i < fields.length; i++) {
2125
+ const field = fields[i];
2126
+ if (key !== undefined && field.path.length === 1 && field.path[0] === key)
2127
+ continue;
2128
+ const sourceName = 's' + i;
2129
+ const targetName = 't' + i;
2130
+ appendPlannedValueRead(lines, 'sr', field.path, sourceName, sourceParents);
2131
+ appendPlannedValueRead(lines, 'tr', field.path, targetName, targetParents);
2132
+ appendPlannedEqualsCompare(lines, sourceName, targetName);
2133
+ }
2134
+ lines.push('}', 'return true;', '}');
2135
+ try {
2136
+ const compiled = Function('equalsJsonFast', lines.join('\n'))(equalsJsonFast);
2137
+ rememberCompiledPlan(nestedRecordArrayEqualsCache, cacheKey, compiled);
2138
+ return compiled;
2139
+ }
2140
+ catch {
2141
+ return null;
2142
+ }
2143
+ }
2144
+ function compileFlatRecordArrayBitmaskDiff(path, fields, key) {
2145
+ const activeFields = [];
2146
+ for (let i = 0; i < fields.length; i++) {
2147
+ if (key !== undefined && fields[i] === key)
2148
+ continue;
2149
+ activeFields[activeFields.length] = fields[i];
2150
+ }
2151
+ if (activeFields.length < 2 || activeFields.length > BITMASK_RECORD_FIELD_MAX) {
2152
+ return null;
2153
+ }
2154
+ const cacheKey = makeCompiledPlanCacheKey('recordArrayBitmask', path, fields, key);
2155
+ const cached = flatRecordArrayBitmaskDiffCache.get(cacheKey);
2156
+ if (cached !== undefined)
2157
+ return cached;
2158
+ const pathPrefix = path.map((segment) => JSON.stringify(segment)).join(',');
2159
+ const prefix = pathPrefix === '' ? '' : pathPrefix + ',';
2160
+ const startPath = pathPrefix === '' ? '[]' : '[' + pathPrefix + ']';
2161
+ const singleRowPath = '[' + prefix + 'batchIndexes[0]]';
2162
+ const singleKeyPath = '[' + prefix + 'batchIndexes[0],singleKey]';
2163
+ const lines = [
2164
+ 'return function compiledFlatRecordArrayBitmaskDiff(source,target,patch){',
2165
+ 'if(!Array.isArray(source)||!Array.isArray(target))return false;',
2166
+ 'const length=source.length;',
2167
+ 'if(length!==target.length)return false;',
2168
+ 'const startLength=patch.length;',
2169
+ 'let batchIndexes=null;',
2170
+ 'let batchMasks=null;',
2171
+ 'let commonMask=0;',
2172
+ 'let sameMask=true;',
2173
+ 'for(let i=0;i<length;i++){',
2174
+ 'const sr=source[i];',
2175
+ 'const tr=target[i];',
2176
+ 'if(i<16&&(sr===null||tr===null||typeof sr!=="object"||typeof tr!=="object"||Array.isArray(sr)||Array.isArray(tr))){patch.length=startLength;return false;}'
2177
+ ];
2178
+ if (key !== undefined) {
2179
+ const keyLiteral = JSON.stringify(key);
2180
+ lines.push('const sk=sr[' + keyLiteral + '];', 'const tk=tr[' + keyLiteral + '];', 'if((sk!==tk)||(sk===0&&1/sk!==1/tk)){patch.length=startLength;return false;}');
2181
+ }
2182
+ lines.push('let mask=0;');
2183
+ for (let i = 0; i < activeFields.length; i++) {
2184
+ const literal = JSON.stringify(activeFields[i]);
2185
+ const sourceName = 's' + i;
2186
+ const targetName = 't' + i;
2187
+ lines.push('const ' + sourceName + '=sr[' + literal + '];', 'const ' + targetName + '=tr[' + literal + '];', 'if((' + sourceName + '!==' + targetName + ')||(' + sourceName + '===0&&1/' + sourceName + '!==1/' + targetName + '))mask|=' + (1 << i) + ';');
2188
+ }
2189
+ lines.push('if(mask!==0){', 'if(batchIndexes===null){batchIndexes=[];batchMasks=[];commonMask=mask;}else if(mask!==commonMask){sameMask=false;}', 'batchIndexes[batchIndexes.length]=i;', 'batchMasks[batchMasks.length]=mask;', '}', '}', 'if(batchIndexes!==null){', 'if(batchIndexes.length===1){const singleAssign=makeBitmaskAssign(target[batchIndexes[0]],activeFields,batchMasks[0]);const singleKeys=Object.keys(singleAssign);if(singleKeys.length===1){const singleKey=singleKeys[0];patch[patch.length]=[OP_SET,' + singleKeyPath + ',singleAssign[singleKey]];}else{patch[patch.length]=[OP_ASSIGN,' + singleRowPath + ',singleAssign];}}', 'else if(sameMask){const fieldPaths=makeBitmaskFieldPaths(activeFields,commonMask);const fieldValues=[];appendBitmaskFieldValues(target,batchIndexes,activeFields,commonMask,fieldValues);patch[patch.length]=[OP_ARRAY_OBJECT_FIELD_ASSIGN,' + startPath + ',batchIndexes,fieldPaths,fieldValues];}', 'else{const batchValues=[];for(let bi=0;bi<batchIndexes.length;bi++){batchValues[bi]=makeBitmaskAssign(target[batchIndexes[bi]],activeFields,batchMasks[bi]);}patch[patch.length]=[OP_ARRAY_OBJECT_ASSIGN,' + startPath + ',batchIndexes,batchValues];}', '}', 'return true;', '}');
2190
+ try {
2191
+ const compiled = Function('OP_SET', 'OP_ASSIGN', 'OP_ARRAY_OBJECT_ASSIGN', 'OP_ARRAY_OBJECT_FIELD_ASSIGN', 'clonePayload', 'activeFields', 'makeBitmaskAssign', 'makeBitmaskFieldPaths', 'appendBitmaskFieldValues', lines.join('\n'))(OP_SET, OP_ASSIGN, OP_ARRAY_OBJECT_ASSIGN, OP_ARRAY_OBJECT_FIELD_ASSIGN, clonePayload, activeFields, makeBitmaskAssign, makeBitmaskFieldPaths, appendBitmaskFieldValues);
2192
+ rememberCompiledPlan(flatRecordArrayBitmaskDiffCache, cacheKey, compiled);
2193
+ return compiled;
2194
+ }
2195
+ catch {
2196
+ return null;
2197
+ }
2198
+ }
2199
+ function makeBitmaskAssign(row, fields, mask) {
2200
+ const assign = {};
2201
+ for (let i = 0, length = fields.length; i < length; i++) {
2202
+ if ((mask & (1 << i)) !== 0)
2203
+ assign[fields[i]] = clonePayload(row[fields[i]]);
2204
+ }
2205
+ return assign;
2206
+ }
2207
+ function makeBitmaskFieldPaths(fields, mask) {
2208
+ const fieldPaths = [];
2209
+ for (let i = 0, length = fields.length; i < length; i++) {
2210
+ if ((mask & (1 << i)) !== 0)
2211
+ fieldPaths[fieldPaths.length] = [fields[i]];
2212
+ }
2213
+ return fieldPaths;
2214
+ }
2215
+ function appendBitmaskFieldValues(rows, indexes, fields, mask, values) {
2216
+ for (let rowOffset = 0, rowCount = indexes.length; rowOffset < rowCount; rowOffset++) {
2217
+ const row = rows[indexes[rowOffset]];
2218
+ for (let i = 0, fieldCount = fields.length; i < fieldCount; i++) {
2219
+ if ((mask & (1 << i)) !== 0)
2220
+ values[values.length] = clonePayload(row[fields[i]]);
2221
+ }
2222
+ }
2223
+ }
2224
+ function tryEmitObjectAssignAsFieldAssign(patch, path, indexes, assigns) {
2225
+ if (indexes.length < 4 || assigns.length !== indexes.length)
2226
+ return false;
2227
+ const keys = Object.keys(assigns[0]);
2228
+ const fieldCount = keys.length;
2229
+ if (fieldCount === 0 || fieldCount > 16)
2230
+ return false;
2231
+ const values = [];
2232
+ for (let rowOffset = 0, rowCount = assigns.length; rowOffset < rowCount; rowOffset++) {
2233
+ const assign = assigns[rowOffset];
2234
+ if (assign === null || typeof assign !== 'object' || Array.isArray(assign))
2235
+ return false;
2236
+ for (let fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
2237
+ const key = keys[fieldIndex];
2238
+ if (!hasOwn.call(assign, key))
2239
+ return false;
2240
+ values[values.length] = clonePayload(assign[key]);
2241
+ }
2242
+ for (const key in assign) {
2243
+ if (!hasOwn.call(assign, key))
2244
+ continue;
2245
+ let matched = false;
2246
+ for (let fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
2247
+ if (keys[fieldIndex] === key) {
2248
+ matched = true;
2249
+ break;
2250
+ }
2251
+ }
2252
+ if (!matched)
2253
+ return false;
2254
+ }
2255
+ }
2256
+ const fields = new Array(fieldCount);
2257
+ for (let fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
2258
+ fields[fieldIndex] = [keys[fieldIndex]];
2259
+ }
2260
+ patch[patch.length] = [OP_ARRAY_OBJECT_FIELD_ASSIGN, path, indexes, fields, values];
2261
+ return true;
2262
+ }
2263
+ function compileNestedRecordArrayDiff(path, fields, key) {
2264
+ const cacheKey = makeCompiledPlanCacheKey('recordArrayNested', path, fields.map((field) => field.path), key);
2265
+ const cached = nestedRecordArrayDiffCache.get(cacheKey);
2266
+ if (cached !== undefined)
2267
+ return cached;
2268
+ const pathPrefix = path.map((segment) => JSON.stringify(segment)).join(',');
2269
+ const prefix = pathPrefix === '' ? '' : pathPrefix + ',';
2270
+ const startPath = pathPrefix === '' ? '[]' : '[' + pathPrefix + ']';
2271
+ const singleRowPath = '[' + prefix + 'batchIndexes[0]]';
2272
+ const singleKeyPath = '[' + prefix + 'batchIndexes[0],singleKey]';
2273
+ const lines = [
2274
+ 'return function compiledNestedRecordArrayDiff(source,target,patch){',
2275
+ 'if(!Array.isArray(source)||!Array.isArray(target))return false;',
2276
+ 'const length=source.length;',
2277
+ 'if(length!==target.length)return false;',
2278
+ 'const startLength=patch.length;',
2279
+ 'let batchIndexes=null;',
2280
+ 'let batchValues=null;',
2281
+ 'function flushBatch(){if(batchIndexes!==null){if(batchIndexes.length===1){const singleAssign=batchValues[0];const singleKeys=Object.keys(singleAssign);if(singleKeys.length===1){const singleKey=singleKeys[0];patch[patch.length]=[OP_SET,' + singleKeyPath + ',singleAssign[singleKey]];}else{patch[patch.length]=[OP_ASSIGN,' + singleRowPath + ',singleAssign];}}else if(!tryEmitObjectAssignAsFieldAssign(patch,' + startPath + ',batchIndexes,batchValues)){patch[patch.length]=[OP_ARRAY_OBJECT_ASSIGN,' + startPath + ',batchIndexes,batchValues];}batchIndexes=null;batchValues=null;}}',
2282
+ 'for(let i=0;i<length;i++){',
2283
+ 'const sr=source[i];',
2284
+ 'const tr=target[i];',
2285
+ 'if(sr===null||tr===null||typeof sr!=="object"||typeof tr!=="object"||Array.isArray(sr)||Array.isArray(tr)){patch.length=startLength;return false;}'
2286
+ ];
2287
+ if (key !== undefined) {
2288
+ const keyLiteral = JSON.stringify(key);
2289
+ lines.push('const sk=sr[' + keyLiteral + '];', 'const tk=tr[' + keyLiteral + '];', 'if((sk!==tk)||(sk===0&&1/sk!==1/tk)){patch.length=startLength;return false;}');
2290
+ }
2291
+ const parentPrefixes = readNestedParentPrefixes(fields);
2292
+ const sourceParents = new Map();
2293
+ const targetParents = new Map();
2294
+ const nestedTopKeyStates = new Map();
2295
+ for (let i = 0; i < parentPrefixes.length; i++) {
2296
+ const parentPath = parentPrefixes[i];
2297
+ const sourceParent = 'sp' + i;
2298
+ const targetParent = 'tp' + i;
2299
+ sourceParents.set(pathKey(parentPath), sourceParent);
2300
+ targetParents.set(pathKey(parentPath), targetParent);
2301
+ appendNestedParentRead(lines, 'sr', parentPath, sourceParent);
2302
+ appendNestedParentRead(lines, 'tr', parentPath, targetParent);
2303
+ }
2304
+ for (let i = 0; i < fields.length; i++) {
2305
+ const field = fields[i];
2306
+ if (field.path.length <= 1)
2307
+ continue;
2308
+ const topKey = field.path[0];
2309
+ const topKeyStateKey = String(topKey);
2310
+ if (!nestedTopKeyStates.has(topKeyStateKey)) {
2311
+ const index = nestedTopKeyStates.size;
2312
+ nestedTopKeyStates.set(topKeyStateKey, {
2313
+ count: 'nestedCount' + index,
2314
+ value: 'nestedValue' + index,
2315
+ path: 'nestedPath' + index,
2316
+ key: topKey
2317
+ });
2318
+ }
2319
+ }
2320
+ lines.push('let assign=null;');
2321
+ nestedTopKeyStates.forEach((entry) => {
2322
+ lines.push('let ' + entry.count + '=0;', 'let ' + entry.value + ';', 'let ' + entry.path + ';');
2323
+ });
2324
+ for (let i = 0; i < fields.length; i++) {
2325
+ const field = fields[i];
2326
+ if (key !== undefined && field.path.length === 1 && field.path[0] === key)
2327
+ continue;
2328
+ const sourceName = 's' + i;
2329
+ const targetName = 't' + i;
2330
+ appendPlannedValueRead(lines, 'sr', field.path, sourceName, sourceParents);
2331
+ appendPlannedValueRead(lines, 'tr', field.path, targetName, targetParents);
2332
+ lines.push('if((' + sourceName + '!==' + targetName + ')||(' + sourceName + '===0&&1/' + sourceName + '!==1/' + targetName + ')){');
2333
+ if (field.path.length === 1) {
2334
+ const literal = JSON.stringify(field.path[0]);
2335
+ const nestedEntry = nestedTopKeyStates.get(String(field.path[0]));
2336
+ lines.push('if(assign===null)assign={};', 'assign[' + literal + ']=clonePayload(' + targetName + ');');
2337
+ if (nestedEntry !== undefined) {
2338
+ lines.push(nestedEntry.count + '=2;');
2339
+ }
2340
+ }
2341
+ else {
2342
+ const entry = nestedTopKeyStates.get(String(field.path[0]));
2343
+ const topLiteral = JSON.stringify(field.path[0]);
2344
+ lines.push('if(' + entry.count + '===0){' + entry.value + '=' + targetName + ';' + entry.path + '=' + makeGeneratedRecordPath(path, 'i', field.path) + ';}', entry.count + '++;', 'if(' + entry.count + '===2){', 'if(assign===null)assign={};', 'assign[' + topLiteral + ']=clonePayload(tr[' + topLiteral + ']);', '}');
2345
+ }
2346
+ lines.push('}');
2347
+ }
2348
+ lines.push('if(assign!==null){if(batchIndexes===null){batchIndexes=[];batchValues=[];}batchIndexes[batchIndexes.length]=i;batchValues[batchValues.length]=assign;}');
2349
+ nestedTopKeyStates.forEach((entry) => {
2350
+ lines.push('if(' + entry.count + '===1){flushBatch();patch[patch.length]=[OP_SET,' + entry.path + ',clonePayload(' + entry.value + ')];}');
2351
+ });
2352
+ lines.push('}', 'flushBatch();', 'return true;', '}');
2353
+ try {
2354
+ const compiled = Function('OP_SET', 'OP_ASSIGN', 'OP_ARRAY_OBJECT_ASSIGN', 'clonePayload', 'hasOwn', 'tryEmitObjectAssignAsFieldAssign', lines.join('\n'))(OP_SET, OP_ASSIGN, OP_ARRAY_OBJECT_ASSIGN, clonePayload, hasOwn, tryEmitObjectAssignAsFieldAssign);
2355
+ rememberCompiledPlan(nestedRecordArrayDiffCache, cacheKey, compiled);
2356
+ return compiled;
2357
+ }
2358
+ catch {
2359
+ return null;
2360
+ }
2361
+ }
2362
+ function compileFlatObjectDiff(path, fields) {
2363
+ const cacheKey = makeCompiledPlanCacheKey('object', path, fields, undefined);
2364
+ const cached = flatObjectDiffCache.get(cacheKey);
2365
+ if (cached !== undefined)
2366
+ return cached;
2367
+ const pathPrefix = path.map((segment) => JSON.stringify(segment)).join(',');
2368
+ const rootPath = pathPrefix === '' ? '[]' : '[' + pathPrefix + ']';
2369
+ const singleKeyPath = pathPrefix === '' ? '[singleKey]' : '[' + pathPrefix + ',singleKey]';
2370
+ const lines = [
2371
+ 'return function compiledFlatObjectDiff(source,target,patch){',
2372
+ 'if(source===null||target===null||typeof source!=="object"||typeof target!=="object"||Array.isArray(source)||Array.isArray(target))return false;',
2373
+ 'const startLength=patch.length;',
2374
+ 'let assign=null;',
2375
+ 'let changeCount=0;',
2376
+ 'let changeKey;',
2377
+ 'let changeValue;'
2378
+ ];
2379
+ for (let i = 0; i < fields.length; i++) {
2380
+ const literal = JSON.stringify(fields[i]);
2381
+ const sourceName = 's' + i;
2382
+ const targetName = 't' + i;
2383
+ lines.push('const ' + sourceName + '=source[' + literal + '];', 'const ' + targetName + '=target[' + literal + '];', 'if((' + sourceName + '!==' + targetName + ')||(' + sourceName + '===0&&1/' + sourceName + '!==1/' + targetName + ')){', 'if(!canAssignPlannedValue(' + sourceName + ',' + targetName + ')){patch.length=startLength;return false;}', 'changeCount++;', 'if(changeCount===1){changeKey=' + literal + ';changeValue=' + targetName + ';}else{', 'if(assign===null){assign={};assign[changeKey]=clonePayload(changeValue);}', 'assign[' + literal + ']=clonePayload(' + targetName + ');', '}', '}');
2384
+ }
2385
+ lines.push('if(changeCount===1){const singleKey=changeKey;patch[patch.length]=[OP_SET,' + singleKeyPath + ',clonePayload(changeValue)];}', 'else if(changeCount>1){patch[patch.length]=[OP_ASSIGN,' + rootPath + ',assign];}', 'return true;', '}');
2386
+ try {
2387
+ const compiled = Function('OP_SET', 'OP_ASSIGN', 'clonePayload', 'canAssignPlannedValue', lines.join('\n'))(OP_SET, OP_ASSIGN, clonePayload, canAssignPlannedValue);
2388
+ rememberCompiledPlan(flatObjectDiffCache, cacheKey, compiled);
2389
+ return compiled;
2390
+ }
2391
+ catch {
2392
+ return null;
2393
+ }
2394
+ }
2395
+ function compileFlatObjectEquals(fields) {
2396
+ const cacheKey = makeCompiledPlanCacheKey('objectEquals', [], fields, undefined);
2397
+ const cached = flatObjectEqualsCache.get(cacheKey);
2398
+ if (cached !== undefined)
2399
+ return cached;
2400
+ const lines = [
2401
+ 'return function compiledFlatObjectEquals(source,target){',
2402
+ 'if(source===null||target===null||typeof source!=="object"||typeof target!=="object"||Array.isArray(source)||Array.isArray(target))return false;'
2403
+ ];
2404
+ for (let i = 0; i < fields.length; i++) {
2405
+ const literal = JSON.stringify(fields[i]);
2406
+ const sourceName = 's' + i;
2407
+ const targetName = 't' + i;
2408
+ lines.push('const ' + sourceName + '=source[' + literal + '];', 'const ' + targetName + '=target[' + literal + '];', 'if((' + sourceName + '!==' + targetName + ')||(' + sourceName + '===0&&1/' + sourceName + '!==1/' + targetName + '))return false;');
2409
+ }
2410
+ lines.push('return true;', '}');
2411
+ try {
2412
+ const compiled = Function(lines.join('\n'))();
2413
+ rememberCompiledPlan(flatObjectEqualsCache, cacheKey, compiled);
2414
+ return compiled;
2415
+ }
2416
+ catch {
2417
+ return null;
2418
+ }
2419
+ }
2420
+ function compileNestedObjectEquals(fields) {
2421
+ const cacheKey = makeCompiledPlanCacheKey('objectNestedEquals', [], fields.map((field) => field.path), undefined);
2422
+ const cached = nestedObjectEqualsCache.get(cacheKey);
2423
+ if (cached !== undefined)
2424
+ return cached;
2425
+ const lines = [
2426
+ 'return function compiledNestedObjectEquals(source,target){',
2427
+ 'if(source===null||target===null||typeof source!=="object"||typeof target!=="object"||Array.isArray(source)||Array.isArray(target))return false;'
2428
+ ];
2429
+ const parentPrefixes = readNestedParentPrefixes(fields);
2430
+ const sourceParents = new Map();
2431
+ const targetParents = new Map();
2432
+ for (let i = 0; i < parentPrefixes.length; i++) {
2433
+ const parentPath = parentPrefixes[i];
2434
+ const sourceParent = 'sp' + i;
2435
+ const targetParent = 'tp' + i;
2436
+ sourceParents.set(pathKey(parentPath), sourceParent);
2437
+ targetParents.set(pathKey(parentPath), targetParent);
2438
+ appendNestedParentEqualsRead(lines, 'source', parentPath, sourceParent);
2439
+ appendNestedParentEqualsRead(lines, 'target', parentPath, targetParent);
2440
+ }
2441
+ for (let i = 0; i < fields.length; i++) {
2442
+ const field = fields[i];
2443
+ const sourceName = 's' + i;
2444
+ const targetName = 't' + i;
2445
+ appendPlannedValueRead(lines, 'source', field.path, sourceName, sourceParents);
2446
+ appendPlannedValueRead(lines, 'target', field.path, targetName, targetParents);
2447
+ appendPlannedEqualsCompare(lines, sourceName, targetName);
2448
+ }
2449
+ lines.push('return true;', '}');
2450
+ try {
2451
+ const compiled = Function('equalsJsonFast', lines.join('\n'))(equalsJsonFast);
2452
+ rememberCompiledPlan(nestedObjectEqualsCache, cacheKey, compiled);
2453
+ return compiled;
2454
+ }
2455
+ catch {
2456
+ return null;
2457
+ }
2458
+ }
2459
+ function compileNestedObjectDiff(path, fields) {
2460
+ const cacheKey = makeCompiledPlanCacheKey('objectNested', path, fields.map((field) => field.path), undefined);
2461
+ const cached = nestedObjectDiffCache.get(cacheKey);
2462
+ if (cached !== undefined)
2463
+ return cached;
2464
+ const pathPrefix = path.map((segment) => JSON.stringify(segment)).join(',');
2465
+ const rootPath = pathPrefix === '' ? '[]' : '[' + pathPrefix + ']';
2466
+ const singleKeyPath = pathPrefix === '' ? '[singleKey]' : '[' + pathPrefix + ',singleKey]';
2467
+ const lines = [
2468
+ 'return function compiledNestedObjectDiff(source,target,patch){',
2469
+ 'if(source===null||target===null||typeof source!=="object"||typeof target!=="object"||Array.isArray(source)||Array.isArray(target))return false;',
2470
+ 'const startLength=patch.length;',
2471
+ 'let assign=null;',
2472
+ 'let changeCount=0;',
2473
+ 'let changeKey;',
2474
+ 'let changeValue;'
2475
+ ];
2476
+ const parentPrefixes = readNestedParentPrefixes(fields);
2477
+ const sourceParents = new Map();
2478
+ const targetParents = new Map();
2479
+ for (let i = 0; i < parentPrefixes.length; i++) {
2480
+ const parentPath = parentPrefixes[i];
2481
+ const sourceParent = 'sp' + i;
2482
+ const targetParent = 'tp' + i;
2483
+ sourceParents.set(pathKey(parentPath), sourceParent);
2484
+ targetParents.set(pathKey(parentPath), targetParent);
2485
+ appendNestedParentRead(lines, 'source', parentPath, sourceParent);
2486
+ appendNestedParentRead(lines, 'target', parentPath, targetParent);
2487
+ }
2488
+ for (let i = 0; i < fields.length; i++) {
2489
+ const field = fields[i];
2490
+ const sourceName = 's' + i;
2491
+ const targetName = 't' + i;
2492
+ appendPlannedValueRead(lines, 'source', field.path, sourceName, sourceParents);
2493
+ appendPlannedValueRead(lines, 'target', field.path, targetName, targetParents);
2494
+ lines.push('if((' + sourceName + '!==' + targetName + ')||(' + sourceName + '===0&&1/' + sourceName + '!==1/' + targetName + ')){');
2495
+ if (field.path.length === 1) {
2496
+ const literal = JSON.stringify(field.path[0]);
2497
+ lines.push('if(!canAssignPlannedValue(' + sourceName + ',' + targetName + ')){patch.length=startLength;return false;}', 'changeCount++;', 'if(changeCount===1){changeKey=' + literal + ';changeValue=' + targetName + ';}else{', 'if(assign===null){assign={};assign[changeKey]=clonePayload(changeValue);}', 'assign[' + literal + ']=clonePayload(' + targetName + ');', '}');
2498
+ }
2499
+ else {
2500
+ lines.push('patch[patch.length]=[OP_SET,' + makeGeneratedObjectPath(path, field.path) + ',clonePayload(' + targetName + ')];');
2501
+ }
2502
+ lines.push('}');
2503
+ }
2504
+ lines.push('if(changeCount===1){const singleKey=changeKey;patch[patch.length]=[OP_SET,' + singleKeyPath + ',clonePayload(changeValue)];}', 'else if(changeCount>1){patch[patch.length]=[OP_ASSIGN,' + rootPath + ',assign];}', 'return true;', '}');
2505
+ try {
2506
+ const compiled = Function('OP_SET', 'OP_ASSIGN', 'clonePayload', 'canAssignPlannedValue', 'hasOwn', lines.join('\n'))(OP_SET, OP_ASSIGN, clonePayload, canAssignPlannedValue, hasOwn);
2507
+ rememberCompiledPlan(nestedObjectDiffCache, cacheKey, compiled);
2508
+ return compiled;
2509
+ }
2510
+ catch {
2511
+ return null;
2512
+ }
2513
+ }
2514
+ function readNestedParentPrefixes(fields) {
2515
+ const seen = new Set();
2516
+ const out = [];
2517
+ for (let i = 0; i < fields.length; i++) {
2518
+ const path = fields[i].path;
2519
+ for (let length = 1; length < path.length; length++) {
2520
+ const prefix = path.slice(0, length);
2521
+ const key = pathKey(prefix);
2522
+ if (!seen.has(key)) {
2523
+ seen.add(key);
2524
+ out[out.length] = prefix;
2525
+ }
2526
+ }
2527
+ }
2528
+ out.sort(comparePath);
2529
+ return out;
2530
+ }
2531
+ function appendNestedParentRead(lines, root, path, name) {
2532
+ let base = root;
2533
+ for (let i = 0; i < path.length; i++) {
2534
+ const next = i === path.length - 1 ? name : name + 'p' + i;
2535
+ const literal = JSON.stringify(path[i]);
2536
+ lines.push('const ' + next + '=' + base + '[' + literal + '];', 'if(' + next + '===null||typeof ' + next + '!=="object"||Array.isArray(' + next + ')){patch.length=startLength;return false;}');
2537
+ base = next;
2538
+ }
2539
+ }
2540
+ function appendNestedParentEqualsRead(lines, root, path, name) {
2541
+ let base = root;
2542
+ for (let i = 0; i < path.length; i++) {
2543
+ const next = i === path.length - 1 ? name : name + 'p' + i;
2544
+ const literal = JSON.stringify(path[i]);
2545
+ lines.push('const ' + next + '=' + base + '[' + literal + '];', 'if(' + next + '===null||typeof ' + next + '!=="object"||Array.isArray(' + next + '))return false;');
2546
+ base = next;
2547
+ }
2548
+ }
2549
+ function appendPlannedValueRead(lines, root, path, name, parents) {
2550
+ const parentPath = path.length > 1 ? path.slice(0, path.length - 1) : null;
2551
+ const base = parentPath === null ? root : parents.get(pathKey(parentPath));
2552
+ const literal = JSON.stringify(path[path.length - 1]);
2553
+ lines.push('const ' + name + '=' + base + '[' + literal + '];');
2554
+ }
2555
+ function appendPlannedEqualsCompare(lines, sourceName, targetName) {
2556
+ lines.push('if((' + sourceName + '!==' + targetName + ')||(' + sourceName + '===0&&1/' + sourceName + '!==1/' + targetName + ')){', 'if(' + sourceName + '===null||' + targetName + '===null||typeof ' + sourceName + '!=="object"||typeof ' + targetName + '!=="object"||!equalsJsonFast(' + sourceName + ',' + targetName + '))return false;', '}');
2557
+ }
2558
+ function pathKey(path) {
2559
+ return path.join('\0');
2560
+ }
2561
+ function makeGeneratedRecordPath(prefix, indexExpression, suffix) {
2562
+ const parts = [];
2563
+ for (let i = 0; i < prefix.length; i++)
2564
+ parts[parts.length] = JSON.stringify(prefix[i]);
2565
+ parts[parts.length] = indexExpression;
2566
+ for (let i = 0; i < suffix.length; i++)
2567
+ parts[parts.length] = JSON.stringify(suffix[i]);
2568
+ return '[' + parts.join(',') + ']';
2569
+ }
2570
+ function makeGeneratedObjectPath(prefix, suffix) {
2571
+ const parts = [];
2572
+ for (let i = 0; i < prefix.length; i++)
2573
+ parts[parts.length] = JSON.stringify(prefix[i]);
2574
+ for (let i = 0; i < suffix.length; i++)
2575
+ parts[parts.length] = JSON.stringify(suffix[i]);
2576
+ return '[' + parts.join(',') + ']';
2577
+ }
2578
+ function makeCompiledPlanCacheKey(kind, path, fields, key) {
2579
+ return kind + '\u0001' + JSON.stringify(path) + '\u0001' + JSON.stringify(fields) + '\u0001' + JSON.stringify(key);
2580
+ }
2581
+ function rememberCompiledPlan(cache, key, compiled) {
2582
+ if (cache.size >= COMPILED_PLAN_CACHE_LIMIT && !cache.has(key)) {
2583
+ const first = cache.keys().next();
2584
+ if (!first.done)
2585
+ cache.delete(first.value);
2586
+ }
2587
+ cache.set(key, compiled);
2588
+ }
2589
+ function readOwnValue(value, key) {
2590
+ return hasOwn.call(value, key) ? value[key] : MISSING_PLAN_VALUE;
2591
+ }
2592
+ function canAssignPlannedValue(source, target) {
2593
+ if (source !== null && target !== null && typeof source === 'object' && typeof target === 'object') {
2594
+ return false;
2595
+ }
2596
+ return !(typeof source === 'string' && typeof target === 'string' && (source.length >= 32 || target.length >= 32));
2597
+ }
2598
+ function makeObjectPath(prefix, suffix) {
2599
+ if (!Array.isArray(suffix)) {
2600
+ if (prefix.length === 0)
2601
+ return [suffix];
2602
+ const out = prefix.slice();
2603
+ out[out.length] = suffix;
2604
+ return out;
2605
+ }
2606
+ if (prefix.length === 0)
2607
+ return suffix.slice();
2608
+ const out = prefix.slice();
2609
+ for (let i = 0; i < suffix.length; i++)
2610
+ out[out.length] = suffix[i];
2611
+ return out;
2612
+ }
2613
+ function makeRecordPath(prefix, index, suffix) {
2614
+ const prefixLength = prefix.length;
2615
+ if (suffix === undefined) {
2616
+ if (prefixLength === 0)
2617
+ return [index];
2618
+ const out = prefix.slice();
2619
+ out[out.length] = index;
2620
+ return out;
2621
+ }
2622
+ if (!Array.isArray(suffix)) {
2623
+ if (prefixLength === 0)
2624
+ return [index, suffix];
2625
+ const out = prefix.slice();
2626
+ out[out.length] = index;
2627
+ out[out.length] = suffix;
2628
+ return out;
2629
+ }
2630
+ if (prefixLength === 0) {
2631
+ const out = new Array(suffix.length + 1);
2632
+ out[0] = index;
2633
+ for (let i = 0; i < suffix.length; i++)
2634
+ out[i + 1] = suffix[i];
2635
+ return out;
2636
+ }
2637
+ const out = prefix.slice();
2638
+ out[out.length] = index;
2639
+ for (let i = 0; i < suffix.length; i++)
2640
+ out[out.length] = suffix[i];
2641
+ return out;
2642
+ }
2643
+ function sameJsonValue(left, right) {
2644
+ return left === right && (left !== 0 || 1 / left === 1 / right);
2645
+ }
2646
+ function createProfileSnapshot(options, maxEntries, baseSchemaPlan, profilePlan, profilePlans, adaptive, historyStrategy) {
2647
+ const schemas = [];
2648
+ appendPlanSchemas(baseSchemaPlan, schemas);
2649
+ appendPlanSchemas(profilePlan, schemas);
2650
+ const adaptivePlan = readAdaptivePlan(adaptive);
2651
+ appendPlanSchemas(adaptivePlan, schemas);
2652
+ const settings = createProfileSettings(options, maxEntries, adaptive);
2653
+ const profile = { version: PROFILE_VERSION };
2654
+ if (Object.keys(settings).length !== 0)
2655
+ profile.settings = settings;
2656
+ const plans = createEngineProfilePlansSnapshot(profilePlans, {
2657
+ settings,
2658
+ schemaCount: schemas.length,
2659
+ schemaPaths: readProfileSchemaPaths(schemas),
2660
+ adaptivePlan: adaptivePlan !== null,
2661
+ historyStrategy
2662
+ });
2663
+ if (plans !== undefined)
2664
+ profile.plans = plans;
2665
+ if (schemas.length === 1) {
2666
+ profile.schema = schemas[0];
2667
+ }
2668
+ else if (schemas.length > 1) {
2669
+ profile.schemas = schemas;
2670
+ }
2671
+ return profile;
2672
+ }
2673
+ function readProfileSchemaPaths(schemas) {
2674
+ if (schemas.length === 0)
2675
+ return undefined;
2676
+ const paths = [];
2677
+ for (let i = 0, length = schemas.length; i < length; i++) {
2678
+ const path = schemas[i].path;
2679
+ if (Array.isArray(path))
2680
+ paths[paths.length] = path.slice();
2681
+ else
2682
+ paths[paths.length] = [];
2683
+ }
2684
+ return paths;
2685
+ }
2686
+ function createProfileSettings(options, maxEntries, adaptive) {
2687
+ const settings = {};
2688
+ if (maxEntries !== DEFAULT_MAX_ENTRIES)
2689
+ settings.cacheSize = maxEntries;
2690
+ if (adaptive !== null && adaptive.enabled) {
2691
+ settings.adaptive = true;
2692
+ if (adaptive.thresholdExplicit || adaptive.threshold !== DEFAULT_ADAPTIVE_THRESHOLD) {
2693
+ settings.adaptiveThreshold = adaptive.threshold;
2694
+ }
2695
+ }
2696
+ else if (options && options.adaptive === false) {
2697
+ settings.adaptive = false;
2698
+ }
2699
+ if (options) {
2700
+ copyProfileSetting(settings, options, 'arrayKey', isJsonProfileScalarOrFalse);
2701
+ copyProfileSetting(settings, options, 'autoArrayKey', isBoolean);
2702
+ copyProfileSetting(settings, options, 'recordKeyCandidates', isPortablePolicyKeys);
2703
+ copyProfileSetting(settings, options, 'containerKeys', isPortablePolicyKeys);
2704
+ copyProfileSetting(settings, options, 'stable', isBoolean);
2705
+ copyProfileSetting(settings, options, 'sortKeys', isBoolean);
2706
+ copyProfileSetting(settings, options, 'maxPatchOperations', isNonNegativeSafeIntegerOrNull);
2707
+ copyProfileSetting(settings, options, 'versionKey', isJsonProfileScalar);
2708
+ copyProfileSetting(settings, options, 'fingerprintKey', isJsonProfileScalar);
2709
+ }
2710
+ return settings;
2711
+ }
2712
+ function copyProfileSetting(settings, options, key, predicate) {
2713
+ if (options[key] !== undefined && predicate(options[key])) {
2714
+ settings[key] = options[key];
2715
+ }
2716
+ }
2717
+ function isBoolean(value) {
2718
+ return typeof value === 'boolean';
2719
+ }
2720
+ function isNonNegativeSafeIntegerOrNull(value) {
2721
+ return value === null || (Number.isSafeInteger(value) && value >= 0);
2722
+ }
2723
+ function isJsonProfileScalarOrFalse(value) {
2724
+ return value === false || isJsonProfileScalar(value);
2725
+ }
2726
+ function isJsonProfileScalar(value) {
2727
+ return typeof value === 'string' || typeof value === 'number';
2728
+ }
2729
+ function isPortablePolicyKeys(value) {
2730
+ if (value === false || value === null)
2731
+ return true;
2732
+ if (!Array.isArray(value))
2733
+ return false;
2734
+ for (let i = 0, length = value.length; i < length; i++) {
2735
+ if (!isJsonProfileScalar(value[i]))
2736
+ return false;
2737
+ }
2738
+ return true;
2739
+ }
2740
+ function appendPlanSchemas(plan, schemas) {
2741
+ if (plan === null || plan === undefined)
2742
+ return;
2743
+ if (plan.type === 'multi') {
2744
+ for (let i = 0, length = plan.plans.length; i < length; i++) {
2745
+ appendPlanSchemas(plan.plans[i], schemas);
2746
+ }
2747
+ return;
2748
+ }
2749
+ if (plan.schema !== undefined)
2750
+ schemas[schemas.length] = clonePayload(plan.schema);
2751
+ }
2752
+ function createAdaptiveState(options) {
2753
+ if (!options || !options.adaptive)
2754
+ return null;
2755
+ const thresholdExplicit = options.adaptiveThreshold !== undefined;
2756
+ const threshold = options.adaptiveThreshold === undefined
2757
+ ? DEFAULT_ADAPTIVE_THRESHOLD
2758
+ : options.adaptiveThreshold;
2759
+ if (!Number.isSafeInteger(threshold) || threshold < 1) {
2760
+ throw new TypeError('adaptiveThreshold option must be a positive safe integer');
2761
+ }
2762
+ return {
2763
+ enabled: true,
2764
+ threshold,
2765
+ thresholdExplicit,
2766
+ recordKeyCandidates: readPolicyKeys(options.recordKeyCandidates, 'recordKeyCandidates'),
2767
+ containerKeys: readPolicyKeys(options.containerKeys, 'containerKeys'),
2768
+ plan: null,
2769
+ candidates: new Map(),
2770
+ learnedKeys: new Set(),
2771
+ rejectedKeys: new Set(),
2772
+ deferredObjectSignatures: new Set(),
2773
+ failedPlanPairs: new WeakMap(),
2774
+ failedPlanPairsActive: false,
2775
+ failedPlanSignatures: new Set(),
2776
+ failedPlanSignatureOrder: []
2777
+ };
2778
+ }
2779
+ function readPolicyKeys(value, name) {
2780
+ if (value === undefined)
2781
+ return undefined;
2782
+ if (value === false || value === null)
2783
+ return null;
2784
+ if (!Array.isArray(value)) {
2785
+ throw new TypeError(name + ' option must be an array of strings/numbers or false');
2786
+ }
2787
+ const out = new Array(value.length);
2788
+ for (let i = 0, length = value.length; i < length; i++) {
2789
+ const key = value[i];
2790
+ if (typeof key !== 'string' && typeof key !== 'number') {
2791
+ throw new TypeError(name + ' entries must be strings or numbers');
2792
+ }
2793
+ out[i] = key;
2794
+ }
2795
+ return out;
2796
+ }
2797
+ function readAdaptivePlan(state) {
2798
+ return state !== null && state.enabled ? state.plan : null;
2799
+ }
2800
+ function planCoversRoot(plan) {
2801
+ if (plan.type === 'multi') {
2802
+ for (let i = 0, length = plan.plans.length; i < length; i++) {
2803
+ if (planCoversRoot(plan.plans[i]))
2804
+ return true;
2805
+ }
2806
+ return false;
2807
+ }
2808
+ return plan.path.length === 0;
2809
+ }
2810
+ function hasAdaptiveFailedPlan(state, plan, source, target) {
2811
+ if (state === null || !state.failedPlanPairsActive)
2812
+ return false;
2813
+ if (hasAdaptiveFailedPlanPair(state, source, target))
2814
+ return true;
2815
+ const signature = readAdaptiveFailedPlanSignature(plan, source, target);
2816
+ return signature !== null && state.failedPlanSignatures.has(signature);
2817
+ }
2818
+ function hasAdaptiveFailedPlanPair(state, source, target) {
2819
+ if (state === null || !state.failedPlanPairsActive)
2820
+ return false;
2821
+ if (!canUseWeakMapKey(source) || !canUseWeakMapKey(target))
2822
+ return false;
2823
+ const targets = state.failedPlanPairs.get(source);
2824
+ return targets !== undefined && targets.has(target);
2825
+ }
2826
+ function rememberAdaptiveFailedPlan(state, plan, source, target) {
2827
+ if (state === null)
2828
+ return;
2829
+ rememberAdaptiveFailedPlanPair(state, source, target);
2830
+ const signature = readAdaptiveFailedPlanSignature(plan, source, target);
2831
+ if (signature !== null) {
2832
+ rememberAdaptiveFailedPlanSignature(state, signature);
2833
+ state.failedPlanPairsActive = true;
2834
+ }
2835
+ }
2836
+ function rememberAdaptiveFailedPlanPair(state, source, target) {
2837
+ if (!canUseWeakMapKey(source) || !canUseWeakMapKey(target))
2838
+ return;
2839
+ let targets = state.failedPlanPairs.get(source);
2840
+ if (targets === undefined) {
2841
+ targets = new WeakSet();
2842
+ state.failedPlanPairs.set(source, targets);
2843
+ }
2844
+ targets.add(target);
2845
+ state.failedPlanPairsActive = true;
2846
+ }
2847
+ function rememberAdaptiveFailedPlanSignature(state, signature) {
2848
+ if (state.failedPlanSignatures.has(signature))
2849
+ return;
2850
+ state.failedPlanSignatures.add(signature);
2851
+ state.failedPlanSignatureOrder[state.failedPlanSignatureOrder.length] = signature;
2852
+ if (state.failedPlanSignatureOrder.length > ADAPTIVE_FAILED_PLAN_SIGNATURE_LIMIT) {
2853
+ const dropped = state.failedPlanSignatureOrder.shift();
2854
+ if (dropped !== undefined)
2855
+ state.failedPlanSignatures.delete(dropped);
2856
+ }
2857
+ }
2858
+ function clearAdaptiveFailedPlanPairs(state) {
2859
+ if (state === null || !state.failedPlanPairsActive)
2860
+ return;
2861
+ state.failedPlanPairs = new WeakMap();
2862
+ state.failedPlanSignatures.clear();
2863
+ state.failedPlanSignatureOrder.length = 0;
2864
+ state.failedPlanPairsActive = false;
2865
+ }
2866
+ function canUseWeakMapKey(value) {
2867
+ return value !== null && (typeof value === 'object' || typeof value === 'function');
2868
+ }
2869
+ function readAdaptiveFailedPlanSignature(plan, source, target) {
2870
+ const parts = [];
2871
+ return appendAdaptiveFailedPlanSignature(plan, source, target, parts)
2872
+ ? parts.join('\u0001')
2873
+ : null;
2874
+ }
2875
+ function appendAdaptiveFailedPlanSignature(plan, source, target, parts) {
2876
+ if (plan.type === 'multi') {
2877
+ let invalid = false;
2878
+ parts[parts.length] = 'm';
2879
+ parts[parts.length] = plan.plans.length;
2880
+ for (let i = 0, length = plan.plans.length; i < length; i++) {
2881
+ if (appendAdaptiveFailedPlanSignature(plan.plans[i], source, target, parts))
2882
+ invalid = true;
2883
+ }
2884
+ return invalid;
2885
+ }
2886
+ const sourceValue = readPlanPathValue(source, plan.path);
2887
+ const targetValue = readPlanPathValue(target, plan.path);
2888
+ parts[parts.length] = plan.type;
2889
+ parts[parts.length] = pathKey(plan.path);
2890
+ if (plan.type === 'recordArray') {
2891
+ return appendRecordArrayFailedPlanSignature(plan, sourceValue, targetValue, parts);
2892
+ }
2893
+ return appendObjectFailedPlanSignature(plan, sourceValue, targetValue, parts);
2894
+ }
2895
+ function appendRecordArrayFailedPlanSignature(plan, source, target, parts) {
2896
+ if (!Array.isArray(source) || !Array.isArray(target)) {
2897
+ parts[parts.length] = readPlanValueKind(source);
2898
+ parts[parts.length] = readPlanValueKind(target);
2899
+ return true;
2900
+ }
2901
+ const sourceLength = source.length;
2902
+ const targetLength = target.length;
2903
+ let invalid = plan.key === undefined && sourceLength !== targetLength;
2904
+ parts[parts.length] = sourceLength;
2905
+ parts[parts.length] = targetLength;
2906
+ parts[parts.length] = plan.key === undefined ? '' : String(plan.key);
2907
+ const sampleIndexes = readAdaptiveArraySampleIndexes(sourceLength, targetLength);
2908
+ for (let i = 0, length = sampleIndexes.length; i < length; i++) {
2909
+ const index = sampleIndexes[i];
2910
+ parts[parts.length] = index;
2911
+ if (index >= 0 && index < sourceLength) {
2912
+ if (appendRecordRowGuardSignature(plan, source[index], parts))
2913
+ invalid = true;
2914
+ }
2915
+ else {
2916
+ parts[parts.length] = 'source-out';
2917
+ }
2918
+ if (index >= 0 && index < targetLength) {
2919
+ if (appendRecordRowGuardSignature(plan, target[index], parts))
2920
+ invalid = true;
2921
+ }
2922
+ else {
2923
+ parts[parts.length] = 'target-out';
2924
+ }
2925
+ }
2926
+ return invalid;
2927
+ }
2928
+ function appendObjectFailedPlanSignature(plan, source, target, parts) {
2929
+ let invalid = false;
2930
+ if (appendObjectGuardSignature(plan, source, parts))
2931
+ invalid = true;
2932
+ if (appendObjectGuardSignature(plan, target, parts))
2933
+ invalid = true;
2934
+ return invalid;
2935
+ }
2936
+ function readAdaptiveArraySampleIndexes(sourceLength, targetLength) {
2937
+ const maxLength = sourceLength > targetLength ? sourceLength : targetLength;
2938
+ if (maxLength <= 0)
2939
+ return [];
2940
+ if (maxLength === 1)
2941
+ return [0];
2942
+ const mid = maxLength >> 1;
2943
+ return mid === 0 || mid === maxLength - 1 ? [0, maxLength - 1] : [0, mid, maxLength - 1];
2944
+ }
2945
+ function appendRecordRowGuardSignature(plan, row, parts) {
2946
+ if (!isPlanRecordRow(row)) {
2947
+ parts[parts.length] = readPlanValueKind(row);
2948
+ return true;
2949
+ }
2950
+ let invalid = false;
2951
+ if (plan.exact === true && !exactObjectMatchesSchema(row, plan.schema && plan.schema.item && plan.schema.item.fields)) {
2952
+ invalid = true;
2953
+ }
2954
+ if (plan.key !== undefined) {
2955
+ const keyValue = readOwnValue(row, plan.key);
2956
+ if (keyValue === MISSING_PLAN_VALUE || !isPlannedRecordKeyValue(keyValue))
2957
+ invalid = true;
2958
+ parts[parts.length] = keyValue === MISSING_PLAN_VALUE ? 'km' : typeof keyValue;
2959
+ }
2960
+ if (appendFieldsGuardSignature(row, plan.fields, parts))
2961
+ invalid = true;
2962
+ return invalid;
2963
+ }
2964
+ function appendObjectGuardSignature(plan, value, parts) {
2965
+ if (!isPlanRecordRow(value)) {
2966
+ parts[parts.length] = readPlanValueKind(value);
2967
+ return true;
2968
+ }
2969
+ let invalid = false;
2970
+ if (plan.exact === true && !exactObjectMatchesSchema(value, plan.schema && plan.schema.fields)) {
2971
+ invalid = true;
2972
+ }
2973
+ return appendFieldsGuardSignature(value, plan.fields, parts) || invalid;
2974
+ }
2975
+ function appendFieldsGuardSignature(value, fields, parts) {
2976
+ let invalid = false;
2977
+ let mask = 0;
2978
+ const limit = fields.length < 30 ? fields.length : 30;
2979
+ for (let i = 0; i < limit; i++) {
2980
+ const field = fields[i];
2981
+ const fieldValue = field.path.length === 1
2982
+ ? readOwnValue(value, field.path[0])
2983
+ : readPlanPathValue(value, field.path);
2984
+ if (fieldValue !== MISSING_PLAN_VALUE) {
2985
+ mask |= 1 << i;
2986
+ }
2987
+ else {
2988
+ invalid = true;
2989
+ }
2990
+ }
2991
+ parts[parts.length] = fields.length;
2992
+ parts[parts.length] = mask;
2993
+ return invalid;
2994
+ }
2995
+ function readPlanValueKind(value) {
2996
+ if (value === MISSING_PLAN_VALUE)
2997
+ return 'missing';
2998
+ if (value === null)
2999
+ return 'null';
3000
+ if (Array.isArray(value))
3001
+ return 'array';
3002
+ return typeof value;
3003
+ }
3004
+ function observeAdaptiveShape(state, source, target) {
3005
+ if (state === null || !state.enabled)
3006
+ return false;
3007
+ if (shouldDeferWideRootObjectObservation(state, source, target)) {
3008
+ return false;
3009
+ }
3010
+ const shapes = readAdaptiveShapes(source, target);
3011
+ if (shapes.length === 0) {
3012
+ return false;
3013
+ }
3014
+ let changed = false;
3015
+ for (let i = 0, length = shapes.length; i < length; i++) {
3016
+ const shape = shapes[i];
3017
+ if (!isAdaptiveShapeSupported(shape))
3018
+ continue;
3019
+ const key = makeAdaptiveShapeKey(shape);
3020
+ if (state.learnedKeys.has(key) || state.rejectedKeys.has(key))
3021
+ continue;
3022
+ if (hasAdaptivePlanPathConflict(state.plan, shape.path)) {
3023
+ state.rejectedKeys.add(key);
3024
+ continue;
3025
+ }
3026
+ let entry = state.candidates.get(key);
3027
+ const score = scoreAdaptiveShape(shape);
3028
+ const initialHits = readInitialAdaptiveShapeHits(state, shape);
3029
+ if (entry === undefined) {
3030
+ entry = { shape, hits: initialHits, score };
3031
+ state.candidates.set(key, entry);
3032
+ }
3033
+ else {
3034
+ entry.hits += initialHits;
3035
+ if (score > entry.score) {
3036
+ entry.shape = shape;
3037
+ entry.score = score;
3038
+ }
3039
+ }
3040
+ if (entry.hits >= readAdaptiveShapeThreshold(state, shape)) {
3041
+ const plan = createPlanFromAdaptiveShape(entry.shape, state.recordKeyCandidates);
3042
+ const merged = plan === null ? null : appendAdaptivePlan(state.plan, plan);
3043
+ state.candidates.delete(key);
3044
+ if (merged === null) {
3045
+ state.rejectedKeys.add(key);
3046
+ }
3047
+ else {
3048
+ state.plan = merged;
3049
+ state.learnedKeys.add(key);
3050
+ clearAdaptiveFailedPlanPairs(state);
3051
+ changed = true;
3052
+ }
3053
+ }
3054
+ }
3055
+ return changed;
3056
+ }
3057
+ function readAdaptiveShapeThreshold(state, shape) {
3058
+ if (shape.kind === 'object' &&
3059
+ shape.path.length === 0 &&
3060
+ !state.thresholdExplicit &&
3061
+ state.threshold < 2) {
3062
+ return 2;
3063
+ }
3064
+ return state.threshold;
3065
+ }
3066
+ function shouldDeferWideRootObjectObservation(state, source, target) {
3067
+ if (state.thresholdExplicit || state.threshold >= 2)
3068
+ return false;
3069
+ if (!isPlainObjectPair(source, target))
3070
+ return false;
3071
+ if (hasAdaptiveContainerCandidate(source, target, state) || hasAnyAdaptiveContainerCandidate(source, target))
3072
+ return false;
3073
+ if (state.deferredObjectSignatures.has(DEFERRED_WIDE_ROOT_OBJECT_SIGNATURE))
3074
+ return false;
3075
+ state.deferredObjectSignatures.add(DEFERRED_WIDE_ROOT_OBJECT_SIGNATURE);
3076
+ return true;
3077
+ }
3078
+ function readInitialAdaptiveShapeHits(state, shape) {
3079
+ if (shape.kind !== 'object')
3080
+ return 1;
3081
+ if (shape.path.length !== 0 ||
3082
+ !state.deferredObjectSignatures.has(DEFERRED_WIDE_ROOT_OBJECT_SIGNATURE)) {
3083
+ return 1;
3084
+ }
3085
+ state.deferredObjectSignatures.delete(DEFERRED_WIDE_ROOT_OBJECT_SIGNATURE);
3086
+ return 2;
3087
+ }
3088
+ function hasAdaptiveContainerCandidate(source, target, state) {
3089
+ const keys = state === null || state.containerKeys === undefined ? null : state.containerKeys;
3090
+ if (keys === null)
3091
+ return false;
3092
+ for (let i = 0; i < keys.length; i++) {
3093
+ const key = keys[i];
3094
+ const sourceValue = source[key];
3095
+ const targetValue = target[key];
3096
+ if (sourceValue !== null &&
3097
+ targetValue !== null &&
3098
+ typeof sourceValue === 'object' &&
3099
+ typeof targetValue === 'object' &&
3100
+ hasOwn.call(source, key) &&
3101
+ hasOwn.call(target, key)) {
3102
+ return true;
3103
+ }
3104
+ }
3105
+ return false;
3106
+ }
3107
+ function hasAnyAdaptiveContainerCandidate(source, target) {
3108
+ const keys = Object.keys(source);
3109
+ for (let i = 0, length = keys.length; i < length; i++) {
3110
+ const key = keys[i];
3111
+ if (!hasOwn.call(target, key))
3112
+ continue;
3113
+ const sourceValue = source[key];
3114
+ const targetValue = target[key];
3115
+ if (sourceValue !== null &&
3116
+ targetValue !== null &&
3117
+ typeof sourceValue === 'object' &&
3118
+ typeof targetValue === 'object') {
3119
+ return true;
3120
+ }
3121
+ }
3122
+ return false;
3123
+ }
3124
+ function trainProfilePlan(samples, recordKeyCandidates) {
3125
+ if (!Array.isArray(samples) || samples.length === 0) {
3126
+ throw new TypeError('training samples must be a non-empty array');
3127
+ }
3128
+ const candidates = new Map();
3129
+ for (let i = 0, length = samples.length; i < length; i++) {
3130
+ const pair = readTrainingPair(samples[i], i);
3131
+ const rootShapes = readRootAdaptiveShapes(pair.source, pair.target);
3132
+ if (rootShapes !== null) {
3133
+ for (let j = 0; j < rootShapes.length; j++) {
3134
+ addTrainingShape(candidates, rootShapes[j]);
3135
+ }
3136
+ }
3137
+ else {
3138
+ collectTrainingShapes(pair.source, pair.target, [], 0, candidates);
3139
+ }
3140
+ }
3141
+ const shapes = selectTrainingShapes(candidates);
3142
+ if (shapes.length === 0)
3143
+ return null;
3144
+ return createPlanFromAdaptiveShapes(shapes, recordKeyCandidates);
3145
+ }
3146
+ function createPlanFromAdaptiveShapes(shapes, recordKeyCandidates) {
3147
+ const plans = [];
3148
+ for (let i = 0, length = shapes.length; i < length; i++) {
3149
+ const plan = createPlanFromAdaptiveShape(shapes[i], recordKeyCandidates);
3150
+ if (plan !== null)
3151
+ plans[plans.length] = plan;
3152
+ }
3153
+ if (plans.length === 0)
3154
+ return null;
3155
+ return plans.length === 1
3156
+ ? plans[0]
3157
+ : {
3158
+ type: 'multi',
3159
+ plans,
3160
+ trie: buildPlanPathTrie(plans),
3161
+ schema: { schemas: plans.map((plan) => plan.schema) }
3162
+ };
3163
+ }
3164
+ function appendAdaptivePlan(existing, next) {
3165
+ if (existing === null || existing === undefined)
3166
+ return next;
3167
+ const plans = existing.type === 'multi' ? existing.plans.slice() : [existing];
3168
+ for (let i = 0, length = plans.length; i < length; i++) {
3169
+ if (pathsOverlap(plans[i].path, next.path))
3170
+ return null;
3171
+ }
3172
+ plans[plans.length] = next;
3173
+ plans.sort(comparePlanPath);
3174
+ return {
3175
+ type: 'multi',
3176
+ plans,
3177
+ trie: buildPlanPathTrie(plans),
3178
+ schema: { schemas: plans.map((plan) => plan.schema) }
3179
+ };
3180
+ }
3181
+ function comparePlanPath(left, right) {
3182
+ return comparePath(left.path, right.path);
3183
+ }
3184
+ function hasAdaptivePlanPathConflict(plan, path) {
3185
+ if (plan === null || plan === undefined)
3186
+ return false;
3187
+ if (plan.type === 'multi') {
3188
+ for (let i = 0, length = plan.plans.length; i < length; i++) {
3189
+ if (pathsOverlap(plan.plans[i].path, path))
3190
+ return true;
3191
+ }
3192
+ return false;
3193
+ }
3194
+ return pathsOverlap(plan.path, path);
3195
+ }
3196
+ function readTrainingPair(sample, index) {
3197
+ if (Array.isArray(sample) && sample.length >= 2) {
3198
+ return { source: sample[0], target: sample[1] };
3199
+ }
3200
+ if (sample !== null && typeof sample === 'object' && !Array.isArray(sample)) {
3201
+ if (hasOwn.call(sample, 'source') && hasOwn.call(sample, 'target')) {
3202
+ return { source: sample.source, target: sample.target };
3203
+ }
3204
+ if (hasOwn.call(sample, 'before') && hasOwn.call(sample, 'after')) {
3205
+ return { source: sample.before, target: sample.after };
3206
+ }
3207
+ }
3208
+ throw new TypeError('training sample at index ' + index + ' must be [source, target], { source, target }, or { before, after }');
3209
+ }
3210
+ function collectTrainingShapes(source, target, path, depth, candidates) {
3211
+ const recordArray = readRecordArrayShape(source, target);
3212
+ if (recordArray !== null) {
3213
+ recordArray.path = path.slice();
3214
+ addTrainingShape(candidates, recordArray);
3215
+ if (isAdaptiveShapeSupported(recordArray))
3216
+ return;
3217
+ }
3218
+ if (Array.isArray(source) || Array.isArray(target)) {
3219
+ if (!Array.isArray(source) || !Array.isArray(target) || depth >= TRAINING_MAX_DEPTH)
3220
+ return;
3221
+ const length = source.length < target.length ? source.length : target.length;
3222
+ const limit = length < ADAPTIVE_SAMPLE_LIMIT ? length : ADAPTIVE_SAMPLE_LIMIT;
3223
+ for (let i = 0; i < limit; i++) {
3224
+ const sourceValue = source[i];
3225
+ const targetValue = target[i];
3226
+ if (sourceValue === null || targetValue === null)
3227
+ continue;
3228
+ if (typeof sourceValue !== 'object' || typeof targetValue !== 'object')
3229
+ continue;
3230
+ const childPath = path.slice();
3231
+ childPath[childPath.length] = i;
3232
+ collectTrainingShapes(sourceValue, targetValue, childPath, depth + 1, candidates);
3233
+ }
3234
+ return;
3235
+ }
3236
+ if (path.length !== 0 ||
3237
+ !hasAnyAdaptiveContainerCandidate(source, target)) {
3238
+ const objectShape = readTrainableObjectShape(source, target, path);
3239
+ if (objectShape !== null)
3240
+ addTrainingShape(candidates, objectShape);
3241
+ }
3242
+ if (depth >= TRAINING_MAX_DEPTH || !isPlainObjectPair(source, target))
3243
+ return;
3244
+ const keys = Object.keys(source);
3245
+ for (let i = 0, length = keys.length; i < length; i++) {
3246
+ const key = keys[i];
3247
+ if (!hasOwn.call(target, key))
3248
+ continue;
3249
+ const sourceValue = source[key];
3250
+ const targetValue = target[key];
3251
+ if (sourceValue === null || targetValue === null)
3252
+ continue;
3253
+ if (typeof sourceValue !== 'object' || typeof targetValue !== 'object')
3254
+ continue;
3255
+ const childPath = path.slice();
3256
+ childPath[childPath.length] = key;
3257
+ collectTrainingShapes(sourceValue, targetValue, childPath, depth + 1, candidates);
3258
+ }
3259
+ }
3260
+ function addTrainingShape(candidates, shape) {
3261
+ if (!isAdaptiveShapeSupported(shape))
3262
+ return;
3263
+ const key = makeAdaptiveShapeKey(shape);
3264
+ let entry = candidates.get(key);
3265
+ const score = scoreAdaptiveShape(shape);
3266
+ if (entry === undefined) {
3267
+ candidates.set(key, { shape, hits: 1, score });
3268
+ }
3269
+ else {
3270
+ entry.hits++;
3271
+ if (score > entry.score) {
3272
+ entry.shape = shape;
3273
+ entry.score = score;
3274
+ }
3275
+ }
3276
+ }
3277
+ function selectTrainingShapes(candidates) {
3278
+ const entries = Array.from(candidates.values());
3279
+ entries.sort(compareTrainingEntries);
3280
+ const selected = [];
3281
+ for (let i = 0, length = entries.length; i < length && selected.length < TRAINING_MAX_SCHEMAS; i++) {
3282
+ const shape = entries[i].shape;
3283
+ if (hasSelectedPathConflict(selected, shape.path))
3284
+ continue;
3285
+ selected[selected.length] = shape;
3286
+ }
3287
+ selected.sort(compareShapePath);
3288
+ return selected;
3289
+ }
3290
+ function compareTrainingEntries(left, right) {
3291
+ const leftScore = left.hits * left.score;
3292
+ const rightScore = right.hits * right.score;
3293
+ if (leftScore !== rightScore)
3294
+ return rightScore - leftScore;
3295
+ if (left.score !== right.score)
3296
+ return right.score - left.score;
3297
+ return comparePath(left.shape.path, right.shape.path);
3298
+ }
3299
+ function hasSelectedPathConflict(selected, path) {
3300
+ for (let i = 0, length = selected.length; i < length; i++) {
3301
+ if (pathsOverlap(selected[i].path, path))
3302
+ return true;
3303
+ }
3304
+ return false;
3305
+ }
3306
+ function pathsOverlap(left, right) {
3307
+ const length = left.length < right.length ? left.length : right.length;
3308
+ for (let i = 0; i < length; i++) {
3309
+ if (left[i] !== right[i])
3310
+ return false;
3311
+ }
3312
+ return true;
3313
+ }
3314
+ function compareShapePath(left, right) {
3315
+ return comparePath(left.path, right.path);
3316
+ }
3317
+ function comparePath(left, right) {
3318
+ const length = left.length < right.length ? left.length : right.length;
3319
+ for (let i = 0; i < length; i++) {
3320
+ const a = String(left[i]);
3321
+ const b = String(right[i]);
3322
+ if (a < b)
3323
+ return -1;
3324
+ if (a > b)
3325
+ return 1;
3326
+ }
3327
+ return left.length - right.length;
3328
+ }
3329
+ function readTrainableObjectShape(source, target, path) {
3330
+ const fields = readAdaptiveFieldSchemas(source, target, 0);
3331
+ if (fields === null)
3332
+ return null;
3333
+ return {
3334
+ kind: 'object',
3335
+ fields,
3336
+ path: path.slice()
3337
+ };
3338
+ }
3339
+ function isPlainObjectPair(source, target) {
3340
+ return (source !== null &&
3341
+ target !== null &&
3342
+ typeof source === 'object' &&
3343
+ typeof target === 'object' &&
3344
+ !Array.isArray(source) &&
3345
+ !Array.isArray(target));
3346
+ }
3347
+ function createPlanFromAdaptiveShape(shape, recordKeyCandidates) {
3348
+ const fields = shape.fields;
3349
+ const fieldCount = countSchemaFields(fields);
3350
+ if (shape.kind === 'recordArray' &&
3351
+ fieldCount >= ADAPTIVE_RECORD_FIELD_MIN &&
3352
+ shape.rowCount * fieldCount >= ADAPTIVE_RECORD_CELL_MIN) {
3353
+ return createRecordArrayPlan({
3354
+ type: 'array',
3355
+ path: shape.path,
3356
+ key: inferRecordArrayKey(fields, shape.source, shape.target, recordKeyCandidates),
3357
+ item: {
3358
+ type: 'object',
3359
+ fields
3360
+ },
3361
+ exact: true
3362
+ });
3363
+ }
3364
+ if (shape.kind === 'object' &&
3365
+ fieldCount >= readAdaptiveObjectFieldMin(shape)) {
3366
+ return createObjectPlan({
3367
+ type: 'object',
3368
+ path: shape.path,
3369
+ fields,
3370
+ exact: true
3371
+ });
3372
+ }
3373
+ return null;
3374
+ }
3375
+ function isAdaptiveShapeSupported(shape) {
3376
+ const fieldCount = countSchemaFields(shape.fields);
3377
+ if (shape.kind === 'recordArray') {
3378
+ return (fieldCount >= ADAPTIVE_RECORD_FIELD_MIN &&
3379
+ shape.rowCount * fieldCount >= ADAPTIVE_RECORD_CELL_MIN);
3380
+ }
3381
+ return shape.kind === 'object' && fieldCount >= readAdaptiveObjectFieldMin(shape);
3382
+ }
3383
+ function readAdaptiveObjectFieldMin(shape) {
3384
+ return shape.path.length === 0 ? ADAPTIVE_OBJECT_FIELD_MIN : ADAPTIVE_PATH_OBJECT_FIELD_MIN;
3385
+ }
3386
+ function scoreAdaptiveShape(shape) {
3387
+ return shape.kind === 'recordArray'
3388
+ ? shape.rowCount * countSchemaFields(shape.fields)
3389
+ : countSchemaFields(shape.fields);
3390
+ }
3391
+ function makeAdaptiveShapeKey(shape) {
3392
+ return shape.kind + '\u0001' + shape.path.join('\0') + '\u0001' + JSON.stringify(shape.fields);
3393
+ }
3394
+ function clearAdaptiveState(state) {
3395
+ if (state === null)
3396
+ return;
3397
+ state.plan = null;
3398
+ state.candidates.clear();
3399
+ state.learnedKeys.clear();
3400
+ state.rejectedKeys.clear();
3401
+ state.deferredObjectSignatures.clear();
3402
+ clearAdaptiveFailedPlanPairs(state);
3403
+ }
3404
+ function readAdaptiveShapes(source, target) {
3405
+ const rootShapes = readRootAdaptiveShapes(source, target);
3406
+ if (rootShapes !== null)
3407
+ return rootShapes;
3408
+ const candidates = new Map();
3409
+ collectTrainingShapes(source, target, [], 0, candidates);
3410
+ return selectTrainingShapes(candidates);
3411
+ }
3412
+ function readRootAdaptiveShapes(source, target) {
3413
+ const recordArray = readRecordArrayShape(source, target);
3414
+ if (recordArray !== null) {
3415
+ return isAdaptiveShapeSupported(recordArray) ? [recordArray] : [];
3416
+ }
3417
+ if (isPlainObjectPair(source, target)) {
3418
+ if (hasAnyAdaptiveContainerCandidate(source, target))
3419
+ return null;
3420
+ }
3421
+ const objectShape = readTrainableObjectShape(source, target, []);
3422
+ if (objectShape !== null) {
3423
+ return isAdaptiveShapeSupported(objectShape) ? [objectShape] : null;
3424
+ }
3425
+ return null;
3426
+ }
3427
+ function readRecordArrayShape(source, target) {
3428
+ if (!Array.isArray(source) || !Array.isArray(target))
3429
+ return null;
3430
+ const length = source.length < target.length ? source.length : target.length;
3431
+ if (length === 0 || source.length !== target.length)
3432
+ return null;
3433
+ let fields = null;
3434
+ const sampleLength = length < ADAPTIVE_SAMPLE_LIMIT ? length : ADAPTIVE_SAMPLE_LIMIT;
3435
+ for (let i = 0; i < sampleLength; i++) {
3436
+ const sourceFields = readAdaptiveFieldSchemas(source[i], target[i], 0);
3437
+ if (sourceFields === null)
3438
+ return null;
3439
+ if (fields === null) {
3440
+ fields = sourceFields;
3441
+ }
3442
+ else if (!sameSchemaFieldList(fields, sourceFields)) {
3443
+ return null;
3444
+ }
3445
+ }
3446
+ return { kind: 'recordArray', fields, rowCount: length, source, target, path: [] };
3447
+ }
3448
+ function readAdaptiveFieldSchemas(source, target, depth) {
3449
+ if (source === null ||
3450
+ target === null ||
3451
+ typeof source !== 'object' ||
3452
+ typeof target !== 'object' ||
3453
+ Array.isArray(source) ||
3454
+ Array.isArray(target)) {
3455
+ return null;
3456
+ }
3457
+ const sourceFields = Object.keys(source);
3458
+ const targetFields = Object.keys(target);
3459
+ if (!sameFieldList(sourceFields, targetFields))
3460
+ return null;
3461
+ const fields = new Array(sourceFields.length);
3462
+ for (let i = 0, length = sourceFields.length; i < length; i++) {
3463
+ const key = sourceFields[i];
3464
+ const sourceValue = source[key];
3465
+ const targetValue = target[key];
3466
+ if (depth < ADAPTIVE_NESTED_FIELD_DEPTH &&
3467
+ isPlainObjectValue(sourceValue) &&
3468
+ isPlainObjectValue(targetValue)) {
3469
+ const nested = readAdaptiveFieldSchemas(sourceValue, targetValue, depth + 1);
3470
+ fields[i] = nested === null
3471
+ ? key
3472
+ : { key, type: 'object', fields: nested };
3473
+ }
3474
+ else {
3475
+ fields[i] = key;
3476
+ }
3477
+ }
3478
+ return fields.length === 0 ? null : fields;
3479
+ }
3480
+ function inferRecordArrayKey(fields, source, target, recordKeyCandidates) {
3481
+ const key = pickRecordArrayKey(fields, source, target, recordKeyCandidates);
3482
+ if (key === undefined)
3483
+ return undefined;
3484
+ return key;
3485
+ }
3486
+ function pickRecordArrayKey(fields, source, target, recordKeyCandidates) {
3487
+ const policyKey = pickPolicyRecordArrayKey(fields, source, target, recordKeyCandidates);
3488
+ if (policyKey !== undefined)
3489
+ return policyKey;
3490
+ for (let i = 0; i < fields.length; i++) {
3491
+ const field = fields[i];
3492
+ if ((typeof field === 'string' || typeof field === 'number') && isStableUniqueRecordKey(field, source, target)) {
3493
+ return field;
3494
+ }
3495
+ }
3496
+ return undefined;
3497
+ }
3498
+ function pickPolicyRecordArrayKey(fields, source, target, recordKeyCandidates) {
3499
+ if (recordKeyCandidates === undefined || recordKeyCandidates === null)
3500
+ return undefined;
3501
+ for (let i = 0, length = recordKeyCandidates.length; i < length; i++) {
3502
+ const key = recordKeyCandidates[i];
3503
+ if (hasSchemaField(fields, key) && isStableUniqueRecordKey(key, source, target))
3504
+ return key;
3505
+ }
3506
+ return undefined;
3507
+ }
3508
+ function hasSchemaField(fields, key) {
3509
+ for (let i = 0, length = fields.length; i < length; i++) {
3510
+ const field = fields[i];
3511
+ if ((typeof field === 'string' || typeof field === 'number') && field === key)
3512
+ return true;
3513
+ }
3514
+ return false;
3515
+ }
3516
+ function isStableUniqueRecordKey(key, source, target) {
3517
+ const sampleLength = source.length < ADAPTIVE_SAMPLE_LIMIT ? source.length : ADAPTIVE_SAMPLE_LIMIT;
3518
+ const sourceSeen = new Set();
3519
+ const targetSeen = new Set();
3520
+ for (let i = 0; i < sampleLength; i++) {
3521
+ const sourceRow = source[i];
3522
+ const targetRow = target[i];
3523
+ if (sourceRow === null ||
3524
+ targetRow === null ||
3525
+ typeof sourceRow !== 'object' ||
3526
+ typeof targetRow !== 'object' ||
3527
+ Array.isArray(sourceRow) ||
3528
+ Array.isArray(targetRow) ||
3529
+ !hasOwn.call(sourceRow, key) ||
3530
+ !hasOwn.call(targetRow, key)) {
3531
+ return false;
3532
+ }
3533
+ const sourceKey = sourceRow[key];
3534
+ const targetKey = targetRow[key];
3535
+ if (!isAdaptiveRecordKeyValue(sourceKey) ||
3536
+ !isAdaptiveRecordKeyValue(targetKey) ||
3537
+ !sameJsonValue(sourceKey, targetKey) ||
3538
+ sourceSeen.has(sourceKey) ||
3539
+ targetSeen.has(targetKey)) {
3540
+ return false;
3541
+ }
3542
+ sourceSeen.add(sourceKey);
3543
+ targetSeen.add(targetKey);
3544
+ }
3545
+ return true;
3546
+ }
3547
+ function isAdaptiveRecordKeyValue(value) {
3548
+ if (typeof value === 'string')
3549
+ return value.length > 0 && value.length <= 256;
3550
+ return typeof value === 'number' && Number.isSafeInteger(value) && !Object.is(value, -0);
3551
+ }
3552
+ function countSchemaFields(fields) {
3553
+ let count = 0;
3554
+ for (let i = 0, length = fields.length; i < length; i++) {
3555
+ const field = fields[i];
3556
+ count += typeof field === 'string' || typeof field === 'number'
3557
+ ? 1
3558
+ : countSchemaFields(field.fields);
3559
+ }
3560
+ return count;
3561
+ }
3562
+ function isPlainObjectValue(value) {
3563
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
3564
+ }
3565
+ function sameFieldList(left, right) {
3566
+ if (left.length !== right.length)
3567
+ return false;
3568
+ for (let i = 0, length = left.length; i < length; i++) {
3569
+ if (left[i] !== right[i])
3570
+ return false;
3571
+ }
3572
+ return true;
3573
+ }
3574
+ function sameSchemaFieldList(left, right) {
3575
+ if (left.length !== right.length)
3576
+ return false;
3577
+ for (let i = 0, length = left.length; i < length; i++) {
3578
+ if (!sameSchemaField(left[i], right[i]))
3579
+ return false;
3580
+ }
3581
+ return true;
3582
+ }
3583
+ function sameSchemaField(left, right) {
3584
+ const leftScalar = typeof left === 'string' || typeof left === 'number';
3585
+ const rightScalar = typeof right === 'string' || typeof right === 'number';
3586
+ if (leftScalar || rightScalar)
3587
+ return leftScalar && rightScalar && left === right;
3588
+ return left.key === right.key &&
3589
+ left.type === right.type &&
3590
+ sameSchemaFieldList(left.fields, right.fields);
3591
+ }
3592
+ function lookupPairEntry(cache, source, target, state) {
3593
+ if (!isObject(source) || !isObject(target))
3594
+ return null;
3595
+ const byTarget = cache.get(source);
3596
+ if (byTarget === undefined)
3597
+ return null;
3598
+ const entries = byTarget.get(target);
3599
+ if (entries === undefined)
3600
+ return null;
3601
+ return lookupEntry(entries, state);
3602
+ }
3603
+ function storePairEntry(cache, source, target, entry) {
3604
+ if (!isObject(source) || !isObject(target))
3605
+ return;
3606
+ let byTarget = cache.get(source);
3607
+ if (byTarget === undefined) {
3608
+ byTarget = new WeakMap();
3609
+ cache.set(source, byTarget);
3610
+ }
3611
+ let entries = byTarget.get(target);
3612
+ if (entries === undefined) {
3613
+ entries = [];
3614
+ byTarget.set(target, entries);
3615
+ }
3616
+ replaceOrAppendEntry(entries, entry);
3617
+ if (entries.length > MAX_PAIR_SIGNATURES)
3618
+ entries.shift();
3619
+ }
3620
+ function lookupTokenEntry(entries, state) {
3621
+ const entry = lookupEntry(entries, state);
3622
+ if (entry !== null) {
3623
+ const index = entries.indexOf(entry);
3624
+ if (index > 0) {
3625
+ entries.splice(index, 1);
3626
+ entries[entries.length] = entry;
3627
+ }
3628
+ }
3629
+ return entry;
3630
+ }
3631
+ function storeTokenEntry(entries, entry, maxEntries) {
3632
+ replaceOrAppendEntry(entries, entry);
3633
+ while (entries.length > maxEntries)
3634
+ entries.shift();
3635
+ }
3636
+ function replaceOrAppendEntry(entries, entry) {
3637
+ for (let i = 0, length = entries.length; i < length; i++) {
3638
+ if (sameEntryIdentity(entries[i], entry)) {
3639
+ entries[i] = entry;
3640
+ return;
3641
+ }
3642
+ }
3643
+ entries[entries.length] = entry;
3644
+ }
3645
+ function lookupEntry(entries, state) {
3646
+ for (let i = entries.length - 1; i >= 0; i--) {
3647
+ const entry = entries[i];
3648
+ if (Object.is(entry.sourceToken, state.sourceToken) &&
3649
+ Object.is(entry.targetToken, state.targetToken) &&
3650
+ sameSignature(entry.signature, state.signature)) {
3651
+ return entry;
3652
+ }
3653
+ }
3654
+ return null;
3655
+ }
3656
+ function sameEntryIdentity(left, right) {
3657
+ return Object.is(left.sourceToken, right.sourceToken) &&
3658
+ Object.is(left.targetToken, right.targetToken) &&
3659
+ sameSignature(left.signature, right.signature);
3660
+ }
3661
+ function sameSignature(left, right) {
3662
+ if (left.length !== right.length)
3663
+ return false;
3664
+ for (let i = 0, length = left.length; i < length; i++) {
3665
+ if (!Object.is(left[i], right[i]))
3666
+ return false;
3667
+ }
3668
+ return true;
3669
+ }
3670
+ function clonePatch(patch) {
3671
+ const out = new Array(patch.length);
3672
+ for (let i = 0, length = patch.length; i < length; i++) {
3673
+ out[i] = cloneOperation(patch[i]);
3674
+ }
3675
+ return out;
3676
+ }
3677
+ function clonePatchInto(source, target) {
3678
+ target.length = source.length;
3679
+ for (let i = 0, length = source.length; i < length; i++) {
3680
+ target[i] = cloneOperation(source[i]);
3681
+ }
3682
+ return target;
3683
+ }
3684
+ function cloneOperation(op) {
3685
+ const code = op[0];
3686
+ if (code === OP_SET) {
3687
+ return [OP_SET, op[1].slice(), clonePayload(op[2])];
3688
+ }
3689
+ if (code === OP_REMOVE) {
3690
+ return [OP_REMOVE, op[1].slice()];
3691
+ }
3692
+ if (code === OP_TRUNCATE) {
3693
+ return [OP_TRUNCATE, op[1].slice(), op[2]];
3694
+ }
3695
+ if (code === OP_APPEND) {
3696
+ return [OP_APPEND, op[1].slice(), clonePayload(op[2])];
3697
+ }
3698
+ if (code === OP_SCALAR_ARRAY_REPLACE) {
3699
+ return [OP_SCALAR_ARRAY_REPLACE, op[1].slice(), op[2].slice()];
3700
+ }
3701
+ if (code === OP_ASSIGN) {
3702
+ return [OP_ASSIGN, op[1].slice(), clonePayload(op[2])];
3703
+ }
3704
+ if (code === OP_STRING_SPLICE) {
3705
+ return [OP_STRING_SPLICE, op[1].slice(), op[2], op[3], op[4]];
3706
+ }
3707
+ if (code === OP_ARRAY_SPLICE) {
3708
+ return [OP_ARRAY_SPLICE, op[1].slice(), op[2], op[3], clonePayload(op[4])];
3709
+ }
3710
+ if (code === OP_ARRAY_TWO_FIELD_INSERT) {
3711
+ return [OP_ARRAY_TWO_FIELD_INSERT, op[1].slice(), op[2], op[3], op[4], op[5].slice(), op[6].slice()];
3712
+ }
3713
+ if (code === OP_ARRAY_MOVE) {
3714
+ return [OP_ARRAY_MOVE, op[1].slice(), op[2], op[3]];
3715
+ }
3716
+ if (code === OP_STRING_COPY) {
3717
+ return [OP_STRING_COPY, op[1].slice(), op[2], op[3], op[4]];
3718
+ }
3719
+ if (code === OP_ARRAY_ASSIGN) {
3720
+ return [OP_ARRAY_ASSIGN, op[1].slice(), op[2].slice(), clonePayload(op[3])];
3721
+ }
3722
+ if (code === OP_ARRAY_OBJECT_ASSIGN) {
3723
+ return [OP_ARRAY_OBJECT_ASSIGN, op[1].slice(), op[2].slice(), clonePayload(op[3])];
3724
+ }
3725
+ if (code === OP_ARRAY_TUPLE_ASSIGN) {
3726
+ return [OP_ARRAY_TUPLE_ASSIGN, op[1].slice(), op[2].slice(), op[3].slice(), clonePayload(op[4])];
3727
+ }
3728
+ if (code === OP_ARRAY_OBJECT_FIELD_ASSIGN) {
3729
+ return [OP_ARRAY_OBJECT_FIELD_ASSIGN, op[1].slice(), op[2].slice(), copyFieldPaths(op[3]), clonePayload(op[4])];
3730
+ }
3731
+ return op.slice();
3732
+ }
3733
+ function compactPlannedArrayObjectSetRuns(patch) {
3734
+ const length = patch.length;
3735
+ if (length < 4)
3736
+ return;
3737
+ let out = null;
3738
+ let write = 0;
3739
+ let index = 0;
3740
+ while (index < length) {
3741
+ const first = readArrayObjectSetCandidate(patch[index]);
3742
+ if (first === null) {
3743
+ if (out !== null)
3744
+ out[write] = patch[index];
3745
+ write++;
3746
+ index++;
3747
+ continue;
3748
+ }
3749
+ let end = index + 1;
3750
+ let previousRow = first.row;
3751
+ while (end < length) {
3752
+ const next = readMatchingArrayObjectSetCandidate(patch[end], first);
3753
+ if (next === null ||
3754
+ next.row <= previousRow) {
3755
+ break;
3756
+ }
3757
+ previousRow = next.row;
3758
+ end++;
3759
+ }
3760
+ const count = end - index;
3761
+ if (count >= 4) {
3762
+ if (out === null)
3763
+ out = patch.slice(0, write);
3764
+ const rowIndexes = new Array(count);
3765
+ const values = new Array(count);
3766
+ for (let i = 0; i < count; i++) {
3767
+ const op = patch[index + i];
3768
+ rowIndexes[i] = op[1][first.rowOffset];
3769
+ values[i] = op[2];
3770
+ }
3771
+ out[write++] = [OP_ARRAY_OBJECT_FIELD_ASSIGN, first.base, rowIndexes, [first.field], values];
3772
+ }
3773
+ else {
3774
+ if (out !== null) {
3775
+ for (let i = index; i < end; i++)
3776
+ out[write++] = patch[i];
3777
+ }
3778
+ else {
3779
+ write += count;
3780
+ }
3781
+ }
3782
+ index = end;
3783
+ }
3784
+ if (out !== null) {
3785
+ patch.length = write;
3786
+ for (let i = 0; i < write; i++)
3787
+ patch[i] = out[i];
3788
+ }
3789
+ }
3790
+ function readMatchingArrayObjectSetCandidate(op, first) {
3791
+ if (op[0] !== OP_SET)
3792
+ return null;
3793
+ const path = op[1];
3794
+ const base = first.base;
3795
+ const field = first.field;
3796
+ const rowOffset = first.rowOffset;
3797
+ if (path.length !== base.length + field.length + 1)
3798
+ return null;
3799
+ for (let i = 0; i < rowOffset; i++) {
3800
+ if (path[i] !== base[i])
3801
+ return null;
3802
+ }
3803
+ for (let i = 0, length = field.length; i < length; i++) {
3804
+ if (path[rowOffset + 1 + i] !== field[i])
3805
+ return null;
3806
+ }
3807
+ const row = path[rowOffset];
3808
+ return Number.isSafeInteger(row) && row >= 0 && !Object.is(row, -0)
3809
+ ? { row }
3810
+ : null;
3811
+ }
3812
+ function readArrayObjectSetCandidate(op) {
3813
+ if (op[0] !== OP_SET)
3814
+ return null;
3815
+ const path = op[1];
3816
+ if (path.length < 3)
3817
+ return null;
3818
+ for (let i = path.length - 2; i >= 1; i--) {
3819
+ const row = path[i];
3820
+ if (Number.isSafeInteger(row) && row >= 0 && !Object.is(row, -0)) {
3821
+ return {
3822
+ base: path.slice(0, i),
3823
+ row,
3824
+ rowOffset: i,
3825
+ field: path.slice(i + 1)
3826
+ };
3827
+ }
3828
+ }
3829
+ return null;
3830
+ }
3831
+ function copyFieldPaths(fields) {
3832
+ const out = new Array(fields.length);
3833
+ for (let i = 0, length = fields.length; i < length; i++)
3834
+ out[i] = fields[i].slice();
3835
+ return out;
3836
+ }
3837
+ function clonePayload(value) {
3838
+ return value !== null && typeof value === 'object' ? cloneJson(value) : value;
3839
+ }
3840
+ function isObject(value) {
3841
+ return value !== null && typeof value === 'object';
3842
+ }
3843
+ //# sourceMappingURL=engine.js.map