@vorplex/core 0.0.33 → 0.0.34
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ArrayChange = Record<`$${number}` | `$${number}
|
|
1
|
+
export type ArrayChange = Record<`$${number}` | `$${number}+` | `${'$'}{${string | number}}`, any | typeof $Changes.deleted>;
|
|
2
2
|
export interface ChangeCompareResult {
|
|
3
3
|
differences: any;
|
|
4
4
|
similarities: any;
|
|
@@ -29,15 +29,12 @@ export interface ChangeRebase<T = any> {
|
|
|
29
29
|
* The `.source` with local conflicting changes applied
|
|
30
30
|
*/
|
|
31
31
|
local: T;
|
|
32
|
-
/**
|
|
33
|
-
* The remote with local non-conflicting changes applied
|
|
34
|
-
*/
|
|
35
|
-
result: T;
|
|
36
32
|
};
|
|
37
33
|
};
|
|
38
34
|
}
|
|
39
35
|
export declare class $Changes {
|
|
40
36
|
static readonly deleted: "[deleted]";
|
|
37
|
+
private static valueHasId;
|
|
41
38
|
/**
|
|
42
39
|
* Compute a minimal change object between `a` (base) and `b` (target).
|
|
43
40
|
* Returns `undefined` when there is no difference.
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { $Value } from '../value/value.util';
|
|
2
2
|
export class $Changes {
|
|
3
3
|
static deleted = '[deleted]';
|
|
4
|
+
static valueHasId(value) {
|
|
5
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value) && 'id' in value;
|
|
6
|
+
}
|
|
4
7
|
/**
|
|
5
8
|
* Compute a minimal change object between `a` (base) and `b` (target).
|
|
6
9
|
* Returns `undefined` when there is no difference.
|
|
@@ -25,6 +28,30 @@ export class $Changes {
|
|
|
25
28
|
return Object.keys(changes).length ? changes : undefined;
|
|
26
29
|
}
|
|
27
30
|
function getArrayChanges(base, target) {
|
|
31
|
+
const idKey = (id) => '$' + '{' + id + '}';
|
|
32
|
+
function getIdBasedArrayChanges(base, target) {
|
|
33
|
+
const changes = {};
|
|
34
|
+
const targetById = new Map(target.filter($Changes.valueHasId).map((item) => [item.id, item]));
|
|
35
|
+
const baseIds = new Set(base.filter($Changes.valueHasId).map((item) => item.id));
|
|
36
|
+
for (const item of base) {
|
|
37
|
+
if (!$Changes.valueHasId(item))
|
|
38
|
+
continue;
|
|
39
|
+
const targetItem = targetById.get(item.id);
|
|
40
|
+
if (targetItem === undefined) {
|
|
41
|
+
changes[idKey(item.id)] = $Changes.deleted;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const diff = $Changes.get(item, targetItem);
|
|
45
|
+
if (diff !== undefined)
|
|
46
|
+
changes[idKey(item.id)] = diff;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (let i = 0; i < target.length; i++) {
|
|
50
|
+
if ($Changes.valueHasId(target[i]) && !baseIds.has(target[i].id))
|
|
51
|
+
changes[`$${i}+`] = target[i];
|
|
52
|
+
}
|
|
53
|
+
return Object.keys(changes).length ? changes : undefined;
|
|
54
|
+
}
|
|
28
55
|
function getArrayOperations(base, target) {
|
|
29
56
|
function getLcsMatrix(a, b) {
|
|
30
57
|
const matrix = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
|
|
@@ -60,12 +87,14 @@ export class $Changes {
|
|
|
60
87
|
}
|
|
61
88
|
if (!target.length)
|
|
62
89
|
return [];
|
|
90
|
+
if (base.every($Changes.valueHasId) && target.every($Changes.valueHasId))
|
|
91
|
+
return getIdBasedArrayChanges(base, target);
|
|
63
92
|
const operations = getArrayOperations(base, target);
|
|
64
93
|
const paired = [];
|
|
65
94
|
for (let i = 0; i < operations.length; i++) {
|
|
66
95
|
const current = operations[i];
|
|
67
96
|
const next = operations[i + 1];
|
|
68
|
-
if (current.type === 'delete' && next?.type === 'insert') {
|
|
97
|
+
if (current.type === 'delete' && next?.type === 'insert' && $Value.isPrimitive(base[current.sourceIndex])) {
|
|
69
98
|
paired.push({ type: 'update', sourceIndex: current.sourceIndex, targetIndex: next.targetIndex, value: next.value });
|
|
70
99
|
i++;
|
|
71
100
|
}
|
|
@@ -176,9 +205,19 @@ export class $Changes {
|
|
|
176
205
|
const updates = new Map();
|
|
177
206
|
const inserts = new Map();
|
|
178
207
|
for (const [key, value] of Object.entries(changes)) {
|
|
208
|
+
const idMatch = key.match(/^\$\{(?<id>.+)\}$/);
|
|
179
209
|
const insertMatch = key.match(/^\$(?<index>\d+)\+$/);
|
|
180
210
|
const updateMatch = key.match(/^\$(?<index>\d+)$/);
|
|
181
|
-
if (
|
|
211
|
+
if (idMatch) {
|
|
212
|
+
const index = base.findIndex((item) => $Changes.valueHasId(item) && String(item.id) === idMatch.groups.id);
|
|
213
|
+
if (index !== -1) {
|
|
214
|
+
if (value === $Changes.deleted)
|
|
215
|
+
deletes.push(index);
|
|
216
|
+
else
|
|
217
|
+
updates.set(index, value);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if (insertMatch) {
|
|
182
221
|
inserts.set(Number.parseInt(insertMatch.groups.index, 10), value);
|
|
183
222
|
}
|
|
184
223
|
else if (updateMatch) {
|
|
@@ -213,11 +252,13 @@ export class $Changes {
|
|
|
213
252
|
return false;
|
|
214
253
|
if (!Object.keys(change).length)
|
|
215
254
|
return false;
|
|
216
|
-
for (const
|
|
217
|
-
if (!
|
|
255
|
+
for (const key of Object.keys(change)) {
|
|
256
|
+
if (!key.startsWith('$'))
|
|
218
257
|
return false;
|
|
219
|
-
|
|
220
|
-
|
|
258
|
+
if (/^\$\{.+\}$/.test(key))
|
|
259
|
+
continue;
|
|
260
|
+
const index = key.endsWith('+') ? key.slice(1, -1) : key.slice(1);
|
|
261
|
+
if (Number.isNaN(Number.parseInt(index, 10)))
|
|
221
262
|
return false;
|
|
222
263
|
}
|
|
223
264
|
return true;
|
|
@@ -279,17 +320,15 @@ export class $Changes {
|
|
|
279
320
|
return { result };
|
|
280
321
|
}
|
|
281
322
|
const sourceWithDifferences = $Changes.apply(source, remoteCompare.differences, localCompare.differences, remoteCompare.similarities, localCompare.similarities);
|
|
282
|
-
const mergedWithLocalDifferences = $Changes.apply(remote, localCompare.differences);
|
|
283
323
|
return {
|
|
284
|
-
result: $Changes.apply(
|
|
324
|
+
result: $Changes.apply(remote, local),
|
|
285
325
|
conflict: {
|
|
286
326
|
local: localCompare,
|
|
287
327
|
remote: remoteCompare,
|
|
288
328
|
merge: {
|
|
289
329
|
source: sourceWithDifferences,
|
|
290
330
|
remote: $Changes.apply(sourceWithDifferences, remoteCompare.conflicts),
|
|
291
|
-
local: $Changes.apply(sourceWithDifferences, localCompare.conflicts)
|
|
292
|
-
result: mergedWithLocalDifferences,
|
|
331
|
+
local: $Changes.apply(sourceWithDifferences, localCompare.conflicts)
|
|
293
332
|
},
|
|
294
333
|
},
|
|
295
334
|
};
|