sf-git-merge-driver 1.0.0-dev-3.13990972267-1 → 1.0.0-dev-3.14022905562-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/lib/constant/conflicConstant.d.ts +6 -0
- package/lib/constant/conflicConstant.js +7 -0
- package/lib/constant/conflicConstant.js.map +1 -0
- package/lib/constant/metadataConstant.d.ts +4 -53
- package/lib/constant/metadataConstant.js +4 -53
- package/lib/constant/metadataConstant.js.map +1 -1
- package/lib/merger/JsonMerger.d.ts +2 -36
- package/lib/merger/JsonMerger.js +151 -532
- package/lib/merger/JsonMerger.js.map +1 -1
- package/lib/merger/XmlMerger.js +1 -1
- package/lib/merger/XmlMerger.js.map +1 -1
- package/lib/merger/conflictMarker.d.ts +2 -0
- package/lib/merger/conflictMarker.js +12 -0
- package/lib/merger/conflictMarker.js.map +1 -0
- package/lib/merger/textAttribute.d.ts +2 -0
- package/lib/merger/textAttribute.js +55 -0
- package/lib/merger/textAttribute.js.map +1 -0
- package/lib/service/MetadataService.d.ts +4 -0
- package/lib/service/MetadataService.js +70 -0
- package/lib/service/MetadataService.js.map +1 -0
- package/lib/service/NamespaceHandler.d.ts +5 -0
- package/lib/service/NamespaceHandler.js +35 -0
- package/lib/service/NamespaceHandler.js.map +1 -0
- package/lib/types/jsonTypes.d.ts +6 -0
- package/lib/types/jsonTypes.js +2 -0
- package/lib/types/jsonTypes.js.map +1 -0
- package/lib/types/mergeScenario.d.ts +17 -0
- package/lib/types/mergeScenario.js +38 -0
- package/lib/types/mergeScenario.js.map +1 -0
- package/lib/utils/mergeUtils.d.ts +4 -0
- package/lib/utils/mergeUtils.js +5 -0
- package/lib/utils/mergeUtils.js.map +1 -0
- package/npm-shrinkwrap.json +237 -16
- package/oclif.manifest.json +1 -1
- package/package.json +4 -4
package/lib/merger/JsonMerger.js
CHANGED
|
@@ -1,560 +1,179 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { isEmpty, isEqual, keyBy, unionWith } from 'lodash-es';
|
|
2
|
+
import { MetadataService } from '../service/MetadataService.js';
|
|
3
|
+
import { NamespaceHandler } from '../service/NamespaceHandler.js';
|
|
4
|
+
import { MergeScenario, getScenario } from '../types/mergeScenario.js';
|
|
5
|
+
import { ensureArray, getUniqueSortedProps, isObject, } from '../utils/mergeUtils.js';
|
|
6
|
+
import { addConflictMarkers } from './conflictMarker.js';
|
|
7
|
+
import { mergeTextAttribute } from './textAttribute.js';
|
|
3
8
|
export class JsonMerger {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (ancestor && !isEqual(ancestor, {})) {
|
|
14
|
-
caseCode += 100;
|
|
15
|
-
arrProperties.push(...Object.keys(ancestor));
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
ancestor = {};
|
|
19
|
-
}
|
|
20
|
-
if (ours && !isEqual(ours, {})) {
|
|
21
|
-
caseCode += 10;
|
|
22
|
-
arrProperties.push(...Object.keys(ours));
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
ours = {};
|
|
26
|
-
}
|
|
27
|
-
if (theirs && !isEqual(theirs, {})) {
|
|
28
|
-
caseCode += 1;
|
|
29
|
-
arrProperties.push(...Object.keys(theirs));
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
theirs = {};
|
|
33
|
-
}
|
|
34
|
-
const allProperties = new Set(arrProperties.sort());
|
|
35
|
-
// TODO filter the namespace here and reapply it in the end of the loop if necessary
|
|
36
|
-
// Process each property
|
|
37
|
-
const mergedContent = [];
|
|
38
|
-
for (const property of allProperties) {
|
|
39
|
-
// console.info('property: '+property+'\ntypeof: '+this.getAttributePrimarytype(
|
|
40
|
-
// ancestor[property],
|
|
41
|
-
// ours[property],
|
|
42
|
-
// theirs[property]
|
|
43
|
-
// ))
|
|
44
|
-
switch (this.getAttributePrimarytype(ancestor[property], ours[property], theirs[property])) {
|
|
45
|
-
case 'object': {
|
|
46
|
-
if (parent) {
|
|
47
|
-
mergedContent.push(...this.mergeArrays(this.ensureArray(ancestor[property]), this.ensureArray(ours[property]), this.ensureArray(theirs[property]), this.ensureArray(parent), property, this.getKeyField(property)));
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
let propObject = {};
|
|
51
|
-
switch (caseCode) {
|
|
52
|
-
case 100:
|
|
53
|
-
return [];
|
|
54
|
-
case 11:
|
|
55
|
-
if (isEqual(ours, theirs)) {
|
|
56
|
-
propObject[property] = [];
|
|
57
|
-
propObject[property].push(...this.mergeObjects({}, ours[property], {}, propObject));
|
|
58
|
-
mergedContent.push(propObject);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
mergedContent.push({ '#text': '\n<<<<<<< LOCAL' });
|
|
62
|
-
propObject[property] = [];
|
|
63
|
-
propObject[property].push(...this.mergeObjects({}, ours[property], {}, propObject));
|
|
64
|
-
mergedContent.push(propObject);
|
|
65
|
-
mergedContent.push({ '#text': '||||||| BASE' });
|
|
66
|
-
mergedContent.push({ '#text': '\n' });
|
|
67
|
-
mergedContent.push({ '#text': '=======' });
|
|
68
|
-
propObject = {};
|
|
69
|
-
propObject[property] = [];
|
|
70
|
-
propObject[property].push(...this.mergeObjects({}, {}, theirs[property], propObject));
|
|
71
|
-
mergedContent.push(propObject);
|
|
72
|
-
mergedContent.push({ '#text': '>>>>>>> REMOTE' });
|
|
73
|
-
}
|
|
74
|
-
break;
|
|
75
|
-
case 101:
|
|
76
|
-
if (isEqual(ancestor, theirs)) {
|
|
77
|
-
return [];
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
mergedContent.push({ '#text': '\n<<<<<<< LOCAL' });
|
|
81
|
-
mergedContent.push({ '#text': '\n' });
|
|
82
|
-
mergedContent.push({ '#text': '||||||| BASE' });
|
|
83
|
-
propObject[property] = [];
|
|
84
|
-
propObject[property].push(...this.mergeObjects({}, ancestor[property], {}, propObject));
|
|
85
|
-
mergedContent.push(propObject);
|
|
86
|
-
mergedContent.push({ '#text': '=======' });
|
|
87
|
-
propObject = {};
|
|
88
|
-
propObject[property] = [];
|
|
89
|
-
propObject[property].push(...this.mergeObjects({}, {}, theirs[property], propObject));
|
|
90
|
-
mergedContent.push(propObject);
|
|
91
|
-
mergedContent.push({ '#text': '>>>>>>> REMOTE' });
|
|
92
|
-
}
|
|
93
|
-
break;
|
|
94
|
-
case 110:
|
|
95
|
-
if (isEqual(ancestor, ours)) {
|
|
96
|
-
return [];
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
mergedContent.push({ '#text': '\n<<<<<<< LOCAL' });
|
|
100
|
-
propObject[property] = [];
|
|
101
|
-
propObject[property].push(...this.mergeObjects({}, ours[property], {}, propObject));
|
|
102
|
-
mergedContent.push(propObject);
|
|
103
|
-
mergedContent.push({ '#text': '||||||| BASE' });
|
|
104
|
-
propObject = {};
|
|
105
|
-
propObject[property] = [];
|
|
106
|
-
propObject[property].push(...this.mergeObjects({}, {}, ancestor[property], propObject));
|
|
107
|
-
mergedContent.push(propObject);
|
|
108
|
-
mergedContent.push({ '#text': '=======' });
|
|
109
|
-
mergedContent.push({ '#text': '\n' });
|
|
110
|
-
mergedContent.push({ '#text': '>>>>>>> REMOTE' });
|
|
111
|
-
}
|
|
112
|
-
break;
|
|
113
|
-
default:
|
|
114
|
-
propObject[property] = [];
|
|
115
|
-
propObject[property].push(...this.mergeObjects(ancestor[property], ours[property], theirs[property], propObject));
|
|
116
|
-
mergedContent.push(propObject);
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
9
|
+
merge(ancestor, ours, theirs) {
|
|
10
|
+
const namespaceHandler = new NamespaceHandler();
|
|
11
|
+
const namespaces = namespaceHandler.processNamespaces(ancestor, ours, theirs);
|
|
12
|
+
const scenario = getScenario(ancestor, ours, theirs);
|
|
13
|
+
const acc = [];
|
|
14
|
+
const props = getUniqueSortedProps(ancestor, ours, theirs);
|
|
15
|
+
for (const key of props) {
|
|
16
|
+
switch (scenario) {
|
|
17
|
+
case MergeScenario.ANCESTOR_ONLY:
|
|
120
18
|
break;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
parent[':@'] = {};
|
|
129
|
-
parent[':@'][property] = ancestor[property];
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
mergedContent.push(...this.mergeTextAttribute(property, ancestor[property], ours[property], theirs[property]));
|
|
134
|
-
}
|
|
19
|
+
case MergeScenario.OURS_AND_THEIRS:
|
|
20
|
+
acc.push(handleOursAndTheirs(key, ours, theirs));
|
|
21
|
+
break;
|
|
22
|
+
case MergeScenario.ANCESTOR_AND_THEIRS:
|
|
23
|
+
acc.push(handleAncestorAndTheirs(key, ancestor, theirs));
|
|
135
24
|
break;
|
|
25
|
+
case MergeScenario.ANCESTOR_AND_OURS:
|
|
26
|
+
acc.push(handleAncestorAndOurs(key, ancestor, ours));
|
|
27
|
+
break;
|
|
28
|
+
default: {
|
|
29
|
+
const obj = {
|
|
30
|
+
[key]: mergeMetadata(ancestor[key], ours[key], theirs[key]),
|
|
31
|
+
};
|
|
32
|
+
acc.push([obj]);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
136
35
|
}
|
|
137
36
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// typeof ours === 'object' &&
|
|
142
|
-
// ours !== null &&
|
|
143
|
-
// !Array.isArray(ours) &&
|
|
144
|
-
// typeof theirs === 'object' &&
|
|
145
|
-
// theirs !== null &&
|
|
146
|
-
// !Array.isArray(theirs)
|
|
147
|
-
// ) {
|
|
148
|
-
// // Get the base attribute (e.g., Profile)
|
|
149
|
-
// const baseKey = Object.keys(ours)[0]
|
|
150
|
-
// if (baseKey && Object.keys(theirs)[0] === baseKey) {
|
|
151
|
-
// const result = { ...ours } as JsonObject
|
|
152
|
-
// // Get the content of the base attribute
|
|
153
|
-
// const ourContent = ours[baseKey] as JsonObject
|
|
154
|
-
// const theirContent = theirs[baseKey] as JsonObject
|
|
155
|
-
// const ancestorContent =
|
|
156
|
-
// ancestor &&
|
|
157
|
-
// typeof ancestor === 'object' &&
|
|
158
|
-
// !Array.isArray(ancestor) &&
|
|
159
|
-
// baseKey in ancestor
|
|
160
|
-
// ? ((ancestor as JsonObject)[baseKey] as JsonObject)
|
|
161
|
-
// : {}
|
|
162
|
-
// // Get all properties from both contents
|
|
163
|
-
// const allProperties = new Set([
|
|
164
|
-
// ...Object.keys(ourContent),
|
|
165
|
-
// ...Object.keys(theirContent),
|
|
166
|
-
// ])
|
|
167
|
-
// // Process each property
|
|
168
|
-
// const mergedContent = { ...ourContent } as JsonObject
|
|
169
|
-
// for (const property of allProperties) {
|
|
170
|
-
// // Skip if property doesn't exist in their content
|
|
171
|
-
// if (!(property in theirContent)) continue
|
|
172
|
-
// // Use their version if property doesn't exist in our content
|
|
173
|
-
// if (!(property in mergedContent)) {
|
|
174
|
-
// mergedContent[property] = this.ensureArray(theirContent[property])
|
|
175
|
-
// continue
|
|
176
|
-
// }
|
|
177
|
-
// // Ensure both values are arrays
|
|
178
|
-
// const ourArray = this.ensureArray(mergedContent[property])
|
|
179
|
-
// const theirArray = this.ensureArray(theirContent[property])
|
|
180
|
-
// const ancestorArray =
|
|
181
|
-
// property in ancestorContent
|
|
182
|
-
// ? this.ensureArray(ancestorContent[property])
|
|
183
|
-
// : []
|
|
184
|
-
// // Get the key field for this property if available
|
|
185
|
-
// const keyField = this.getKeyField(property)
|
|
186
|
-
// // Merge the arrays
|
|
187
|
-
// mergedContent[property] = this.mergeArrays(
|
|
188
|
-
// ancestorArray,
|
|
189
|
-
// ourArray,
|
|
190
|
-
// theirArray,
|
|
191
|
-
// keyField
|
|
192
|
-
// )
|
|
193
|
-
// }
|
|
194
|
-
// result[baseKey] = mergedContent
|
|
195
|
-
// return result
|
|
196
|
-
// }
|
|
197
|
-
// }
|
|
198
|
-
// // Default to our version for other cases
|
|
199
|
-
// return ours
|
|
37
|
+
const result = acc.flat();
|
|
38
|
+
namespaceHandler.addNamespacesToResult(result, namespaces);
|
|
39
|
+
return result;
|
|
200
40
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
41
|
+
}
|
|
42
|
+
const mergeMetadata = (ancestor, ours, theirs) => {
|
|
43
|
+
const acc = [];
|
|
44
|
+
const props = getUniqueSortedProps(ancestor, ours, theirs);
|
|
45
|
+
for (const key of props) {
|
|
46
|
+
let values = [];
|
|
47
|
+
if (isObject(ancestor[key], ours[key], theirs[key])) {
|
|
48
|
+
const [ancestorkey, ourkey, theirkey] = [
|
|
49
|
+
ancestor[key],
|
|
50
|
+
ours[key],
|
|
51
|
+
theirs[key],
|
|
52
|
+
].map(ensureArray);
|
|
53
|
+
values = mergeArrays(ancestorkey, ourkey, theirkey, key);
|
|
213
54
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
caseCode += 1;
|
|
55
|
+
else {
|
|
56
|
+
values = mergeTextAttribute(ancestor[key], ours[key], theirs[key], key);
|
|
217
57
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
58
|
+
acc.push(values);
|
|
59
|
+
}
|
|
60
|
+
return acc.flat();
|
|
61
|
+
};
|
|
62
|
+
const handleOursAndTheirs = (key, ours, theirs) => {
|
|
63
|
+
const obj = {};
|
|
64
|
+
obj[key] = mergeMetadata({}, ours[key], {});
|
|
65
|
+
const acc = [];
|
|
66
|
+
if (!isEqual(ours, theirs)) {
|
|
67
|
+
const theirsProp = {
|
|
68
|
+
[key]: mergeMetadata({}, {}, theirs[key]),
|
|
69
|
+
};
|
|
70
|
+
addConflictMarkers(acc, obj, {}, theirsProp);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
acc.push(obj);
|
|
74
|
+
}
|
|
75
|
+
return acc;
|
|
76
|
+
};
|
|
77
|
+
const handleAncestorAndTheirs = (key, ancestor, theirs) => {
|
|
78
|
+
const acc = [];
|
|
79
|
+
if (!isEqual(ancestor, theirs)) {
|
|
80
|
+
const ancestorProp = {
|
|
81
|
+
[key]: mergeMetadata({}, {}, ancestor[key]),
|
|
82
|
+
};
|
|
83
|
+
const theirsProp = {
|
|
84
|
+
[key]: mergeMetadata({}, {}, theirs[key]),
|
|
85
|
+
};
|
|
86
|
+
addConflictMarkers(acc, {}, ancestorProp, theirsProp);
|
|
87
|
+
}
|
|
88
|
+
return acc;
|
|
89
|
+
};
|
|
90
|
+
const handleAncestorAndOurs = (key, ancestor, ours) => {
|
|
91
|
+
const acc = [];
|
|
92
|
+
if (!isEqual(ancestor, ours)) {
|
|
93
|
+
const oursProp = {
|
|
94
|
+
[key]: mergeMetadata({}, {}, ours[key]),
|
|
95
|
+
};
|
|
96
|
+
const ancestorProp = {
|
|
97
|
+
[key]: mergeMetadata({}, {}, ancestor[key]),
|
|
98
|
+
};
|
|
99
|
+
addConflictMarkers(acc, oursProp, ancestorProp, {});
|
|
100
|
+
}
|
|
101
|
+
return acc;
|
|
102
|
+
};
|
|
103
|
+
const mergeArrays = (ancestor, ours, theirs, attribute) => {
|
|
104
|
+
const keyField = MetadataService.getKeyFieldExtractor(attribute);
|
|
105
|
+
if (!keyField) {
|
|
106
|
+
const obj = {};
|
|
107
|
+
obj[attribute] = unionWith(ours, theirs, isEqual);
|
|
108
|
+
return [obj];
|
|
109
|
+
}
|
|
110
|
+
const [keyedAnc, keyedOurs, keyedTheirs] = [ancestor, ours, theirs].map(arr => keyBy(arr, keyField));
|
|
111
|
+
return mergeByKeyField(keyedAnc, keyedOurs, keyedTheirs, attribute);
|
|
112
|
+
};
|
|
113
|
+
const mergeByKeyField = (ancestor, ours, theirs, attribute) => {
|
|
114
|
+
const acc = [];
|
|
115
|
+
const props = getUniqueSortedProps(ancestor, ours, theirs);
|
|
116
|
+
for (const key of props) {
|
|
117
|
+
const scenario = getScenario(ancestor[key], ours[key], theirs[key]);
|
|
118
|
+
const obj = {};
|
|
119
|
+
switch (scenario) {
|
|
120
|
+
case MergeScenario.THEIRS_ONLY:
|
|
121
|
+
obj[attribute] = mergeMetadata({}, {}, theirs[key]);
|
|
222
122
|
break;
|
|
223
|
-
case
|
|
224
|
-
|
|
123
|
+
case MergeScenario.OURS_ONLY:
|
|
124
|
+
obj[attribute] = mergeMetadata({}, ours[key], {});
|
|
225
125
|
break;
|
|
226
|
-
case
|
|
227
|
-
|
|
228
|
-
|
|
126
|
+
case MergeScenario.ANCESTOR_ONLY:
|
|
127
|
+
break;
|
|
128
|
+
case MergeScenario.OURS_AND_THEIRS:
|
|
129
|
+
if (isEqual(ours, theirs)) {
|
|
130
|
+
obj[attribute] = mergeMetadata({}, {}, theirs[key]);
|
|
229
131
|
}
|
|
230
132
|
else {
|
|
231
|
-
|
|
232
|
-
finalArray.push(objOurs);
|
|
233
|
-
finalArray.push({ '#text': '||||||| BASE' });
|
|
234
|
-
finalArray.push({ '#text': '\n' });
|
|
235
|
-
finalArray.push({ '#text': '=======' });
|
|
236
|
-
finalArray.push(objTheirs);
|
|
237
|
-
finalArray.push({ '#text': '>>>>>>> REMOTE' });
|
|
133
|
+
obj[attribute] = mergeMetadata({}, ours[key], theirs[key]);
|
|
238
134
|
}
|
|
239
135
|
break;
|
|
240
|
-
case
|
|
241
|
-
if (ancestor
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
136
|
+
case MergeScenario.ANCESTOR_AND_THEIRS:
|
|
137
|
+
if (!isEqual(ancestor, theirs)) {
|
|
138
|
+
const ancestorProp = {
|
|
139
|
+
[attribute]: mergeMetadata({}, ancestor[key], {}),
|
|
140
|
+
};
|
|
141
|
+
const theirsProp = {
|
|
142
|
+
[attribute]: mergeMetadata({}, {}, theirs[key]),
|
|
143
|
+
};
|
|
144
|
+
addConflictMarkers(acc, {}, ancestorProp, theirsProp);
|
|
249
145
|
}
|
|
250
146
|
break;
|
|
251
|
-
case
|
|
252
|
-
if (ancestor
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
147
|
+
case MergeScenario.ANCESTOR_AND_OURS:
|
|
148
|
+
if (!isEqual(ancestor, ours)) {
|
|
149
|
+
const oursProp = {
|
|
150
|
+
[attribute]: mergeMetadata({}, ours[key], {}),
|
|
151
|
+
};
|
|
152
|
+
const ancestorProp = {
|
|
153
|
+
[attribute]: mergeMetadata({}, ancestor[key], {}),
|
|
154
|
+
};
|
|
155
|
+
addConflictMarkers(acc, oursProp, ancestorProp, {});
|
|
260
156
|
}
|
|
261
157
|
break;
|
|
262
|
-
case
|
|
263
|
-
if (ours
|
|
264
|
-
|
|
158
|
+
case MergeScenario.ALL:
|
|
159
|
+
if (isEqual(ours, theirs)) {
|
|
160
|
+
obj[attribute] = mergeMetadata({}, {}, theirs[key]);
|
|
265
161
|
}
|
|
266
|
-
else if (ancestor
|
|
267
|
-
|
|
162
|
+
else if (isEqual(ancestor[key], ours[key])) {
|
|
163
|
+
obj[attribute] = mergeMetadata({}, {}, theirs[key]);
|
|
268
164
|
}
|
|
269
|
-
else if (ancestor
|
|
270
|
-
|
|
165
|
+
else if (isEqual(ancestor, theirs)) {
|
|
166
|
+
obj[attribute] = mergeMetadata({}, ours[key], {});
|
|
271
167
|
}
|
|
272
168
|
else {
|
|
273
|
-
|
|
274
|
-
finalArray.push(objOurs);
|
|
275
|
-
finalArray.push({ '#text': '||||||| BASE' });
|
|
276
|
-
finalArray.push(objAnc);
|
|
277
|
-
finalArray.push({ '#text': '=======' });
|
|
278
|
-
finalArray.push(objTheirs);
|
|
279
|
-
finalArray.push({ '#text': '>>>>>>> REMOTE' });
|
|
169
|
+
obj[attribute] = mergeMetadata(ancestor[key], ours[key], theirs[key]);
|
|
280
170
|
}
|
|
281
171
|
break;
|
|
282
|
-
default:
|
|
283
172
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Gets the typeof of the attribute
|
|
288
|
-
*/
|
|
289
|
-
getAttributePrimarytype(ancestor, ours, theirs) {
|
|
290
|
-
return typeof [ancestor, theirs, ours].find(ele => !isNil(ele));
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Ensures a value is an array
|
|
294
|
-
*/
|
|
295
|
-
ensureArray(value) {
|
|
296
|
-
return isNil(value) ? [] : castArray(value);
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Gets the key field for a property from KEY_FIELD_METADATA
|
|
300
|
-
*/
|
|
301
|
-
getKeyField(property) {
|
|
302
|
-
return property in KEY_FIELD_METADATA
|
|
303
|
-
? KEY_FIELD_METADATA[property]
|
|
304
|
-
: undefined;
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Merges arrays using the specified key field if available
|
|
308
|
-
*/
|
|
309
|
-
mergeArrays(ancestor, ours, theirs, parent, attribute, keyField) {
|
|
310
|
-
const propObject = {};
|
|
311
|
-
// If no key field, use unionWith to merge arrays without duplicates
|
|
312
|
-
if (!keyField) {
|
|
313
|
-
propObject[attribute] = unionWith([...ours], theirs, isEqual);
|
|
314
|
-
return [propObject];
|
|
315
|
-
}
|
|
316
|
-
// Special case for array position
|
|
317
|
-
if (keyField === '<array>') {
|
|
318
|
-
propObject[attribute] = this.mergeByPosition(ancestor, ours, theirs);
|
|
319
|
-
return [propObject];
|
|
320
|
-
}
|
|
321
|
-
// Merge using key field
|
|
322
|
-
return this.mergeByKeyField(ancestor, ours, theirs, keyField, attribute, parent);
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Merges arrays by position
|
|
326
|
-
*/
|
|
327
|
-
mergeByPosition(ancestor, ours, theirs) {
|
|
328
|
-
const result = [...ours];
|
|
329
|
-
// Merge items at the same positions
|
|
330
|
-
for (let i = 0; i < Math.min(ours.length, theirs.length); i++) {
|
|
331
|
-
const ancestorItem = i < ancestor.length ? ancestor[i] : undefined;
|
|
332
|
-
// If they changed it from ancestor but we didn't, use their version
|
|
333
|
-
if (!isEqual(theirs[i], ancestorItem) && isEqual(ours[i], ancestorItem)) {
|
|
334
|
-
result[i] = theirs[i];
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
// Add items that only exist in their version
|
|
338
|
-
if (theirs.length > ours.length) {
|
|
339
|
-
for (let i = ours.length; i < theirs.length; i++) {
|
|
340
|
-
result.push(theirs[i]);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return result;
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Merges arrays using a key field
|
|
347
|
-
*/
|
|
348
|
-
mergeByKeyField(ancestor, ours, theirs, keyField, attribute, parent) {
|
|
349
|
-
const finalArray = [];
|
|
350
|
-
let caseCode = 0;
|
|
351
|
-
if (ancestor.length !== 0) {
|
|
352
|
-
caseCode += 100;
|
|
353
|
-
}
|
|
354
|
-
if (ours.length !== 0) {
|
|
355
|
-
caseCode += 10;
|
|
356
|
-
}
|
|
357
|
-
if (theirs.length !== 0) {
|
|
358
|
-
caseCode += 1;
|
|
173
|
+
if (!isEmpty(obj)) {
|
|
174
|
+
acc.push(obj);
|
|
359
175
|
}
|
|
360
|
-
// console.info(
|
|
361
|
-
// 'attribute: ' +
|
|
362
|
-
// attribute +
|
|
363
|
-
// '\nkeyField: ' +
|
|
364
|
-
// keyField +
|
|
365
|
-
// '\ncaseCode: ' +
|
|
366
|
-
// caseCode
|
|
367
|
-
// )
|
|
368
|
-
// console.dir(ours, {depth: null})
|
|
369
|
-
const keyedAnc = keyBy(ancestor, keyField);
|
|
370
|
-
const keyedOurs = keyBy(ours, keyField);
|
|
371
|
-
const keyedTheirs = keyBy(theirs, keyField);
|
|
372
|
-
const allKeys = new Set([
|
|
373
|
-
...Object.keys(keyedAnc),
|
|
374
|
-
...Object.keys(keyedOurs),
|
|
375
|
-
...Object.keys(keyedTheirs),
|
|
376
|
-
].sort());
|
|
377
|
-
for (const key of allKeys) {
|
|
378
|
-
caseCode = 0;
|
|
379
|
-
if (keyedAnc[key]) {
|
|
380
|
-
caseCode += 100;
|
|
381
|
-
}
|
|
382
|
-
if (keyedOurs[key]) {
|
|
383
|
-
caseCode += 10;
|
|
384
|
-
}
|
|
385
|
-
if (keyedTheirs[key]) {
|
|
386
|
-
caseCode += 1;
|
|
387
|
-
}
|
|
388
|
-
// console.log('caseCode: ' + caseCode);
|
|
389
|
-
let propObject = {};
|
|
390
|
-
switch (caseCode) {
|
|
391
|
-
case 1:
|
|
392
|
-
propObject[attribute] = [
|
|
393
|
-
...this.mergeObjects({}, {}, keyedTheirs[key], parent),
|
|
394
|
-
];
|
|
395
|
-
finalArray.push(propObject);
|
|
396
|
-
break;
|
|
397
|
-
case 10:
|
|
398
|
-
propObject[attribute] = [
|
|
399
|
-
...this.mergeObjects({}, {}, keyedOurs[key], parent),
|
|
400
|
-
];
|
|
401
|
-
finalArray.push(propObject);
|
|
402
|
-
break;
|
|
403
|
-
case 100:
|
|
404
|
-
break;
|
|
405
|
-
case 11:
|
|
406
|
-
if (isEqual(ours, theirs)) {
|
|
407
|
-
propObject[attribute] = [
|
|
408
|
-
...this.mergeObjects({}, {}, keyedOurs[key], parent),
|
|
409
|
-
];
|
|
410
|
-
finalArray.push(propObject);
|
|
411
|
-
}
|
|
412
|
-
else {
|
|
413
|
-
// finalArray.push({ '#text': '<<<<<<< LOCAL' })
|
|
414
|
-
// propObject[attribute] = [
|
|
415
|
-
// ...this.mergeObjects({}, {}, keyedOurs[key], parent),
|
|
416
|
-
// ]
|
|
417
|
-
// finalArray.push(propObject)
|
|
418
|
-
// finalArray.push({ '#text': '||||||| BASE' })
|
|
419
|
-
// finalArray.push({ '#text': '\n' })
|
|
420
|
-
// finalArray.push({ '#text': '=======' })
|
|
421
|
-
// propObject[attribute] = [
|
|
422
|
-
// ...this.mergeObjects({}, {}, keyedTheirs[key], parent),
|
|
423
|
-
// ]
|
|
424
|
-
// finalArray.push(propObject)
|
|
425
|
-
// finalArray.push({ '#text': '>>>>>>> REMOTE' })
|
|
426
|
-
propObject[attribute] = [
|
|
427
|
-
...this.mergeObjects({}, keyedOurs[key], keyedTheirs[key], parent),
|
|
428
|
-
];
|
|
429
|
-
finalArray.push(propObject);
|
|
430
|
-
}
|
|
431
|
-
break;
|
|
432
|
-
case 101:
|
|
433
|
-
if (!isEqual(ancestor, theirs)) {
|
|
434
|
-
finalArray.push({ '#text': '\n<<<<<<< LOCAL' });
|
|
435
|
-
finalArray.push({ '#text': '\n' });
|
|
436
|
-
finalArray.push({ '#text': '||||||| BASE' });
|
|
437
|
-
propObject = {};
|
|
438
|
-
propObject[attribute] = [
|
|
439
|
-
...this.mergeObjects({}, {}, keyedAnc[key], parent),
|
|
440
|
-
];
|
|
441
|
-
finalArray.push(propObject);
|
|
442
|
-
finalArray.push({ '#text': '=======' });
|
|
443
|
-
propObject = {};
|
|
444
|
-
propObject[attribute] = [
|
|
445
|
-
...this.mergeObjects({}, {}, keyedTheirs[key], parent),
|
|
446
|
-
];
|
|
447
|
-
finalArray.push(propObject);
|
|
448
|
-
finalArray.push({ '#text': '>>>>>>> REMOTE' });
|
|
449
|
-
// propObject[attribute] = [
|
|
450
|
-
// ...this.mergeObjects(keyedAnc[key], {}, keyedTheirs[key], parent),
|
|
451
|
-
// ]
|
|
452
|
-
// finalArray.push(propObject)
|
|
453
|
-
}
|
|
454
|
-
break;
|
|
455
|
-
case 110:
|
|
456
|
-
if (!isEqual(ancestor, ours)) {
|
|
457
|
-
finalArray.push({ '#text': '\n<<<<<<< LOCAL' });
|
|
458
|
-
propObject = {};
|
|
459
|
-
propObject[attribute] = [
|
|
460
|
-
...this.mergeObjects({}, {}, keyedOurs[key], parent),
|
|
461
|
-
];
|
|
462
|
-
finalArray.push(propObject);
|
|
463
|
-
finalArray.push({ '#text': '||||||| BASE' });
|
|
464
|
-
propObject = {};
|
|
465
|
-
propObject[attribute] = [
|
|
466
|
-
...this.mergeObjects({}, {}, keyedAnc[key], parent),
|
|
467
|
-
];
|
|
468
|
-
finalArray.push(propObject);
|
|
469
|
-
finalArray.push({ '#text': '=======' });
|
|
470
|
-
finalArray.push({ '#text': '\n' });
|
|
471
|
-
finalArray.push({ '#text': '>>>>>>> REMOTE' });
|
|
472
|
-
// propObject[attribute] = [
|
|
473
|
-
// ...this.mergeObjects(keyedAnc[key], keyedOurs[key], {}, parent),
|
|
474
|
-
// ]
|
|
475
|
-
// finalArray.push(propObject)
|
|
476
|
-
}
|
|
477
|
-
break;
|
|
478
|
-
case 111:
|
|
479
|
-
if (isEqual(ours, theirs)) {
|
|
480
|
-
propObject[attribute] = [
|
|
481
|
-
...this.mergeObjects({}, {}, keyedOurs[key], parent),
|
|
482
|
-
];
|
|
483
|
-
}
|
|
484
|
-
else if (isEqual(ancestor, ours)) {
|
|
485
|
-
propObject[attribute] = [
|
|
486
|
-
...this.mergeObjects({}, {}, keyedTheirs[key], parent),
|
|
487
|
-
];
|
|
488
|
-
}
|
|
489
|
-
else if (isEqual(ancestor, theirs)) {
|
|
490
|
-
propObject[attribute] = [
|
|
491
|
-
...this.mergeObjects({}, {}, keyedOurs[key], parent),
|
|
492
|
-
];
|
|
493
|
-
}
|
|
494
|
-
else {
|
|
495
|
-
// finalArray.push({ '#text': '<<<<<<< LOCAL' })
|
|
496
|
-
// finalArray.push(...this.mergeObjects({}, {}, keyedOurs[key], parent))
|
|
497
|
-
// finalArray.push({ '#text': '||||||| BASE' })
|
|
498
|
-
// finalArray.push(...this.mergeObjects({}, {}, keyedAnc[key], parent))
|
|
499
|
-
// finalArray.push({ '#text': '=======' })
|
|
500
|
-
// finalArray.push(...this.mergeObjects({}, {}, keyedTheirs[key], parent))
|
|
501
|
-
// finalArray.push({ '#text': '>>>>>>> REMOTE' })
|
|
502
|
-
propObject[attribute] = [
|
|
503
|
-
...this.mergeObjects(keyedAnc[key], keyedOurs[key], keyedTheirs[key], parent),
|
|
504
|
-
];
|
|
505
|
-
}
|
|
506
|
-
finalArray.push(propObject);
|
|
507
|
-
break;
|
|
508
|
-
default:
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
return finalArray;
|
|
512
|
-
// original by scolladon
|
|
513
|
-
// const result = [...ours]
|
|
514
|
-
// const processed = new Set<string>()
|
|
515
|
-
// // Create maps for efficient lookups
|
|
516
|
-
// const ourMap = new Map<string, JsonValue>()
|
|
517
|
-
// const theirMap = new Map<string, JsonValue>()
|
|
518
|
-
// const ancestorMap = new Map<string, JsonValue>()
|
|
519
|
-
// // Populate maps
|
|
520
|
-
// for (const item of ours) {
|
|
521
|
-
// const key = this.getItemKey(item, keyField)
|
|
522
|
-
// if (key) ourMap.set(key, item)
|
|
523
|
-
// }
|
|
524
|
-
// for (const item of theirs) {
|
|
525
|
-
// const key = this.getItemKey(item, keyField)
|
|
526
|
-
// if (key) theirMap.set(key, item)
|
|
527
|
-
// }
|
|
528
|
-
// for (const item of ancestor) {
|
|
529
|
-
// const key = this.getItemKey(item, keyField)
|
|
530
|
-
// if (key) ancestorMap.set(key, item)
|
|
531
|
-
// }
|
|
532
|
-
// // Process items in our version
|
|
533
|
-
// for (let i = 0; i < result.length; i++) {
|
|
534
|
-
// const key = this.getItemKey(result[i], keyField)
|
|
535
|
-
// if (!key) continue
|
|
536
|
-
// processed.add(key)
|
|
537
|
-
// // If item exists in both versions
|
|
538
|
-
// if (theirMap.has(key)) {
|
|
539
|
-
// const theirItem = theirMap.get(key)!
|
|
540
|
-
// const ancestorItem = ancestorMap.get(key)
|
|
541
|
-
// // If they changed it from ancestor but we didn't, use their version
|
|
542
|
-
// if (
|
|
543
|
-
// !isEqual(theirItem, ancestorItem) &&
|
|
544
|
-
// isEqual(result[i], ancestorItem)
|
|
545
|
-
// ) {
|
|
546
|
-
// result[i] = theirItem
|
|
547
|
-
// }
|
|
548
|
-
// }
|
|
549
|
-
// }
|
|
550
|
-
// // Add items that only exist in their version
|
|
551
|
-
// const uniqueTheirItems = differenceWith(
|
|
552
|
-
// Array.from(theirMap.values()),
|
|
553
|
-
// result,
|
|
554
|
-
// (a, b) => this.getItemKey(a, keyField) === this.getItemKey(b, keyField)
|
|
555
|
-
// )
|
|
556
|
-
// result.push(...uniqueTheirItems)
|
|
557
|
-
// return result
|
|
558
176
|
}
|
|
559
|
-
|
|
177
|
+
return acc;
|
|
178
|
+
};
|
|
560
179
|
//# sourceMappingURL=JsonMerger.js.map
|