@gitwand/core 1.6.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/LICENSE +21 -0
- package/README.md +52 -0
- package/dist/__tests__/bench.bench.d.ts +14 -0
- package/dist/__tests__/bench.bench.d.ts.map +1 -0
- package/dist/__tests__/bench.bench.js +137 -0
- package/dist/__tests__/bench.bench.js.map +1 -0
- package/dist/__tests__/confidence-v14.test.d.ts +13 -0
- package/dist/__tests__/confidence-v14.test.d.ts.map +1 -0
- package/dist/__tests__/confidence-v14.test.js +284 -0
- package/dist/__tests__/confidence-v14.test.js.map +1 -0
- package/dist/__tests__/config.test.d.ts +2 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +317 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/corpus.d.ts +36 -0
- package/dist/__tests__/corpus.d.ts.map +1 -0
- package/dist/__tests__/corpus.js +541 -0
- package/dist/__tests__/corpus.js.map +1 -0
- package/dist/__tests__/corpus.test.d.ts +17 -0
- package/dist/__tests__/corpus.test.d.ts.map +1 -0
- package/dist/__tests__/corpus.test.js +179 -0
- package/dist/__tests__/corpus.test.js.map +1 -0
- package/dist/__tests__/diff.test.d.ts +10 -0
- package/dist/__tests__/diff.test.d.ts.map +1 -0
- package/dist/__tests__/diff.test.js +178 -0
- package/dist/__tests__/diff.test.js.map +1 -0
- package/dist/__tests__/format-resolvers.test.d.ts +2 -0
- package/dist/__tests__/format-resolvers.test.d.ts.map +1 -0
- package/dist/__tests__/format-resolvers.test.js +577 -0
- package/dist/__tests__/format-resolvers.test.js.map +1 -0
- package/dist/__tests__/imports-extended.test.d.ts +2 -0
- package/dist/__tests__/imports-extended.test.d.ts.map +1 -0
- package/dist/__tests__/imports-extended.test.js +94 -0
- package/dist/__tests__/imports-extended.test.js.map +1 -0
- package/dist/__tests__/lockfile-resolvers.test.d.ts +2 -0
- package/dist/__tests__/lockfile-resolvers.test.d.ts.map +1 -0
- package/dist/__tests__/lockfile-resolvers.test.js +200 -0
- package/dist/__tests__/lockfile-resolvers.test.js.map +1 -0
- package/dist/__tests__/patterns/insertion-at-boundary.test.d.ts +10 -0
- package/dist/__tests__/patterns/insertion-at-boundary.test.d.ts.map +1 -0
- package/dist/__tests__/patterns/insertion-at-boundary.test.js +185 -0
- package/dist/__tests__/patterns/insertion-at-boundary.test.js.map +1 -0
- package/dist/__tests__/patterns/reorder-only.test.d.ts +10 -0
- package/dist/__tests__/patterns/reorder-only.test.d.ts.map +1 -0
- package/dist/__tests__/patterns/reorder-only.test.js +181 -0
- package/dist/__tests__/patterns/reorder-only.test.js.map +1 -0
- package/dist/__tests__/phase-7-2-3b.test.d.ts +6 -0
- package/dist/__tests__/phase-7-2-3b.test.d.ts.map +1 -0
- package/dist/__tests__/phase-7-2-3b.test.js +730 -0
- package/dist/__tests__/phase-7-2-3b.test.js.map +1 -0
- package/dist/__tests__/resolver.test.d.ts +2 -0
- package/dist/__tests__/resolver.test.d.ts.map +1 -0
- package/dist/__tests__/resolver.test.js +927 -0
- package/dist/__tests__/resolver.test.js.map +1 -0
- package/dist/__tests__/resolvers/cargo.test.d.ts +10 -0
- package/dist/__tests__/resolvers/cargo.test.d.ts.map +1 -0
- package/dist/__tests__/resolvers/cargo.test.js +158 -0
- package/dist/__tests__/resolvers/cargo.test.js.map +1 -0
- package/dist/__tests__/resolvers/dockerfile.test.d.ts +8 -0
- package/dist/__tests__/resolvers/dockerfile.test.d.ts.map +1 -0
- package/dist/__tests__/resolvers/dockerfile.test.js +120 -0
- package/dist/__tests__/resolvers/dockerfile.test.js.map +1 -0
- package/dist/__tests__/resolvers/dotenv.test.d.ts +9 -0
- package/dist/__tests__/resolvers/dotenv.test.d.ts.map +1 -0
- package/dist/__tests__/resolvers/dotenv.test.js +113 -0
- package/dist/__tests__/resolvers/dotenv.test.js.map +1 -0
- package/dist/__tests__/resolvers/improvements-v14.test.d.ts +8 -0
- package/dist/__tests__/resolvers/improvements-v14.test.d.ts.map +1 -0
- package/dist/__tests__/resolvers/improvements-v14.test.js +306 -0
- package/dist/__tests__/resolvers/improvements-v14.test.js.map +1 -0
- package/dist/__tests__/validation.test.d.ts +12 -0
- package/dist/__tests__/validation.test.d.ts.map +1 -0
- package/dist/__tests__/validation.test.js +136 -0
- package/dist/__tests__/validation.test.js.map +1 -0
- package/dist/classifier.d.ts +21 -0
- package/dist/classifier.d.ts.map +1 -0
- package/dist/classifier.js +127 -0
- package/dist/classifier.js.map +1 -0
- package/dist/config.d.ts +108 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +200 -0
- package/dist/config.js.map +1 -0
- package/dist/diff.d.ts +69 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +328 -0
- package/dist/diff.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +39 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +164 -0
- package/dist/parser.js.map +1 -0
- package/dist/patterns/complex.d.ts +5 -0
- package/dist/patterns/complex.d.ts.map +1 -0
- package/dist/patterns/complex.js +27 -0
- package/dist/patterns/complex.js.map +1 -0
- package/dist/patterns/delete-no-change.d.ts +4 -0
- package/dist/patterns/delete-no-change.d.ts.map +1 -0
- package/dist/patterns/delete-no-change.js +75 -0
- package/dist/patterns/delete-no-change.js.map +1 -0
- package/dist/patterns/insertion-at-boundary.d.ts +22 -0
- package/dist/patterns/insertion-at-boundary.d.ts.map +1 -0
- package/dist/patterns/insertion-at-boundary.js +164 -0
- package/dist/patterns/insertion-at-boundary.js.map +1 -0
- package/dist/patterns/non-overlapping.d.ts +4 -0
- package/dist/patterns/non-overlapping.d.ts.map +1 -0
- package/dist/patterns/non-overlapping.js +28 -0
- package/dist/patterns/non-overlapping.js.map +1 -0
- package/dist/patterns/one-side-change.d.ts +4 -0
- package/dist/patterns/one-side-change.d.ts.map +1 -0
- package/dist/patterns/one-side-change.js +45 -0
- package/dist/patterns/one-side-change.js.map +1 -0
- package/dist/patterns/reorder-only.d.ts +14 -0
- package/dist/patterns/reorder-only.d.ts.map +1 -0
- package/dist/patterns/reorder-only.js +81 -0
- package/dist/patterns/reorder-only.js.map +1 -0
- package/dist/patterns/same-change.d.ts +4 -0
- package/dist/patterns/same-change.d.ts.map +1 -0
- package/dist/patterns/same-change.js +25 -0
- package/dist/patterns/same-change.js.map +1 -0
- package/dist/patterns/utils.d.ts +70 -0
- package/dist/patterns/utils.d.ts.map +1 -0
- package/dist/patterns/utils.js +206 -0
- package/dist/patterns/utils.js.map +1 -0
- package/dist/patterns/value-only-change.d.ts +4 -0
- package/dist/patterns/value-only-change.d.ts.map +1 -0
- package/dist/patterns/value-only-change.js +34 -0
- package/dist/patterns/value-only-change.js.map +1 -0
- package/dist/patterns/whitespace-only.d.ts +4 -0
- package/dist/patterns/whitespace-only.d.ts.map +1 -0
- package/dist/patterns/whitespace-only.js +32 -0
- package/dist/patterns/whitespace-only.js.map +1 -0
- package/dist/resolver/assemble.d.ts +25 -0
- package/dist/resolver/assemble.d.ts.map +1 -0
- package/dist/resolver/assemble.js +170 -0
- package/dist/resolver/assemble.js.map +1 -0
- package/dist/resolver/format-dispatch.d.ts +40 -0
- package/dist/resolver/format-dispatch.d.ts.map +1 -0
- package/dist/resolver/format-dispatch.js +51 -0
- package/dist/resolver/format-dispatch.js.map +1 -0
- package/dist/resolver/generated-detection.d.ts +48 -0
- package/dist/resolver/generated-detection.d.ts.map +1 -0
- package/dist/resolver/generated-detection.js +123 -0
- package/dist/resolver/generated-detection.js.map +1 -0
- package/dist/resolver/index.d.ts +26 -0
- package/dist/resolver/index.d.ts.map +1 -0
- package/dist/resolver/index.js +147 -0
- package/dist/resolver/index.js.map +1 -0
- package/dist/resolver/policy.d.ts +53 -0
- package/dist/resolver/policy.d.ts.map +1 -0
- package/dist/resolver/policy.js +99 -0
- package/dist/resolver/policy.js.map +1 -0
- package/dist/resolver/validation.d.ts +28 -0
- package/dist/resolver/validation.d.ts.map +1 -0
- package/dist/resolver/validation.js +96 -0
- package/dist/resolver/validation.js.map +1 -0
- package/dist/resolver.d.ts +18 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +18 -0
- package/dist/resolver.js.map +1 -0
- package/dist/resolvers/cargo.d.ts +34 -0
- package/dist/resolvers/cargo.d.ts.map +1 -0
- package/dist/resolvers/cargo.js +262 -0
- package/dist/resolvers/cargo.js.map +1 -0
- package/dist/resolvers/css.d.ts +60 -0
- package/dist/resolvers/css.d.ts.map +1 -0
- package/dist/resolvers/css.js +531 -0
- package/dist/resolvers/css.js.map +1 -0
- package/dist/resolvers/dispatcher.d.ts +78 -0
- package/dist/resolvers/dispatcher.d.ts.map +1 -0
- package/dist/resolvers/dispatcher.js +290 -0
- package/dist/resolvers/dispatcher.js.map +1 -0
- package/dist/resolvers/dockerfile.d.ts +24 -0
- package/dist/resolvers/dockerfile.d.ts.map +1 -0
- package/dist/resolvers/dockerfile.js +221 -0
- package/dist/resolvers/dockerfile.js.map +1 -0
- package/dist/resolvers/dotenv.d.ts +27 -0
- package/dist/resolvers/dotenv.d.ts.map +1 -0
- package/dist/resolvers/dotenv.js +114 -0
- package/dist/resolvers/dotenv.js.map +1 -0
- package/dist/resolvers/imports.d.ts +63 -0
- package/dist/resolvers/imports.d.ts.map +1 -0
- package/dist/resolvers/imports.js +513 -0
- package/dist/resolvers/imports.js.map +1 -0
- package/dist/resolvers/json.d.ts +48 -0
- package/dist/resolvers/json.d.ts.map +1 -0
- package/dist/resolvers/json.js +363 -0
- package/dist/resolvers/json.js.map +1 -0
- package/dist/resolvers/lockfile-npm.d.ts +38 -0
- package/dist/resolvers/lockfile-npm.d.ts.map +1 -0
- package/dist/resolvers/lockfile-npm.js +267 -0
- package/dist/resolvers/lockfile-npm.js.map +1 -0
- package/dist/resolvers/lockfile-pnpm.d.ts +44 -0
- package/dist/resolvers/lockfile-pnpm.d.ts.map +1 -0
- package/dist/resolvers/lockfile-pnpm.js +277 -0
- package/dist/resolvers/lockfile-pnpm.js.map +1 -0
- package/dist/resolvers/lockfile-yarn.d.ts +40 -0
- package/dist/resolvers/lockfile-yarn.d.ts.map +1 -0
- package/dist/resolvers/lockfile-yarn.js +184 -0
- package/dist/resolvers/lockfile-yarn.js.map +1 -0
- package/dist/resolvers/markdown.d.ts +64 -0
- package/dist/resolvers/markdown.d.ts.map +1 -0
- package/dist/resolvers/markdown.js +335 -0
- package/dist/resolvers/markdown.js.map +1 -0
- package/dist/resolvers/vue.d.ts +65 -0
- package/dist/resolvers/vue.d.ts.map +1 -0
- package/dist/resolvers/vue.js +258 -0
- package/dist/resolvers/vue.js.map +1 -0
- package/dist/resolvers/yaml.d.ts +65 -0
- package/dist/resolvers/yaml.d.ts.map +1 -0
- package/dist/resolvers/yaml.js +405 -0
- package/dist/resolvers/yaml.js.map +1 -0
- package/dist/types.d.ts +256 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand — Résolveur JSON/JSONC sémantique
|
|
3
|
+
*
|
|
4
|
+
* Résout les conflits dans les fichiers JSON et JSONC en parsant
|
|
5
|
+
* les trois versions (base, ours, theirs) et en effectuant une
|
|
6
|
+
* fusion au niveau des clés plutôt que des lignes.
|
|
7
|
+
*
|
|
8
|
+
* Stratégie :
|
|
9
|
+
* 1. Tenter de parser les trois versions comme JSON (strip de commentaires JSONC)
|
|
10
|
+
* 2. Calculer les deltas clé-par-clé (récursif sur les objets)
|
|
11
|
+
* 3. Si tous les conflits de clés sont trivialement résolvables → merge
|
|
12
|
+
* 4. Sinon → retourner null (fallback textuel dans resolver.ts)
|
|
13
|
+
*
|
|
14
|
+
* Cas gérés :
|
|
15
|
+
* - Clé ajoutée des deux côtés avec valeurs différentes → conflit non résolvable
|
|
16
|
+
* - Clé ajoutée d'un seul côté → accepter l'ajout
|
|
17
|
+
* - Clé supprimée d'un seul côté, pas modifiée de l'autre → supprimer
|
|
18
|
+
* - Clé modifiée des deux côtés de la même façon → prendre la valeur
|
|
19
|
+
* - Clé modifiée des deux côtés différemment → conflit non résolvable
|
|
20
|
+
* - Merge récursif pour les objets imbriqués
|
|
21
|
+
*/
|
|
22
|
+
// ─── Strip JSONC comments ─────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Supprime les commentaires // et /* *\/ d'un fichier JSONC.
|
|
25
|
+
* Assez robuste pour les cas courants (config files).
|
|
26
|
+
*/
|
|
27
|
+
export function stripJsoncComments(text) {
|
|
28
|
+
let result = "";
|
|
29
|
+
let i = 0;
|
|
30
|
+
let inString = false;
|
|
31
|
+
let stringChar = "";
|
|
32
|
+
while (i < text.length) {
|
|
33
|
+
const ch = text[i];
|
|
34
|
+
const next = text[i + 1];
|
|
35
|
+
// Gestion des chaînes de caractères
|
|
36
|
+
if (inString) {
|
|
37
|
+
if (ch === "\\" && i + 1 < text.length) {
|
|
38
|
+
result += ch + next;
|
|
39
|
+
i += 2;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (ch === stringChar) {
|
|
43
|
+
inString = false;
|
|
44
|
+
}
|
|
45
|
+
result += ch;
|
|
46
|
+
i++;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (ch === '"' || ch === "'") {
|
|
50
|
+
inString = true;
|
|
51
|
+
stringChar = ch;
|
|
52
|
+
result += ch;
|
|
53
|
+
i++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Commentaire ligne // ...
|
|
57
|
+
if (ch === "/" && next === "/") {
|
|
58
|
+
while (i < text.length && text[i] !== "\n")
|
|
59
|
+
i++;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
// Commentaire bloc /* ... */
|
|
63
|
+
if (ch === "/" && next === "*") {
|
|
64
|
+
i += 2;
|
|
65
|
+
while (i < text.length - 1 && !(text[i] === "*" && text[i + 1] === "/")) {
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
i += 2; // sauter */
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
result += ch;
|
|
72
|
+
i++;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Vérifie si une valeur est un objet JSON (et pas null, ni tableau).
|
|
78
|
+
*/
|
|
79
|
+
function isObject(v) {
|
|
80
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Vérifie si deux valeurs JSON sont profondément égales.
|
|
84
|
+
*/
|
|
85
|
+
function jsonEqual(a, b) {
|
|
86
|
+
if (a === b)
|
|
87
|
+
return true;
|
|
88
|
+
if (typeof a !== typeof b)
|
|
89
|
+
return false;
|
|
90
|
+
if (a === null || b === null)
|
|
91
|
+
return false;
|
|
92
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
93
|
+
if (a.length !== b.length)
|
|
94
|
+
return false;
|
|
95
|
+
return a.every((v, i) => jsonEqual(v, b[i]));
|
|
96
|
+
}
|
|
97
|
+
if (isObject(a) && isObject(b)) {
|
|
98
|
+
const aKeys = Object.keys(a);
|
|
99
|
+
const bKeys = Object.keys(b);
|
|
100
|
+
if (aKeys.length !== bKeys.length)
|
|
101
|
+
return false;
|
|
102
|
+
return aKeys.every((k) => k in b && jsonEqual(a[k], b[k]));
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Fusionne récursivement deux objets JSON avec une base commune.
|
|
108
|
+
*
|
|
109
|
+
* Retourne `{ merged, resolvedKeys, unresolvedKeys }`.
|
|
110
|
+
* Si `merged === null`, au moins un conflit est non résolvable.
|
|
111
|
+
*/
|
|
112
|
+
function mergeObjects(base, ours, theirs) {
|
|
113
|
+
const result = {};
|
|
114
|
+
let resolvedKeys = 0;
|
|
115
|
+
let unresolvedKeys = 0;
|
|
116
|
+
// Ensemble de toutes les clés présentes dans au moins une version
|
|
117
|
+
const allKeys = new Set([
|
|
118
|
+
...Object.keys(base),
|
|
119
|
+
...Object.keys(ours),
|
|
120
|
+
...Object.keys(theirs),
|
|
121
|
+
]);
|
|
122
|
+
for (const key of allKeys) {
|
|
123
|
+
const inBase = key in base;
|
|
124
|
+
const inOurs = key in ours;
|
|
125
|
+
const inTheirs = key in theirs;
|
|
126
|
+
const baseVal = base[key];
|
|
127
|
+
const oursVal = ours[key];
|
|
128
|
+
const theirsVal = theirs[key];
|
|
129
|
+
// Clé présente dans les deux branches, absente de la base → ajout des deux côtés
|
|
130
|
+
if (!inBase && inOurs && inTheirs) {
|
|
131
|
+
if (jsonEqual(oursVal, theirsVal)) {
|
|
132
|
+
// Même valeur ajoutée des deux côtés → same_change
|
|
133
|
+
result[key] = oursVal;
|
|
134
|
+
resolvedKeys++;
|
|
135
|
+
}
|
|
136
|
+
else if (isObject(oursVal) && isObject(theirsVal)) {
|
|
137
|
+
// Objets ajoutés différemment → fusion récursive depuis base vide
|
|
138
|
+
const sub = mergeObjects({}, oursVal, theirsVal);
|
|
139
|
+
if (sub.merged !== null) {
|
|
140
|
+
result[key] = sub.merged;
|
|
141
|
+
resolvedKeys += sub.resolvedKeys + 1;
|
|
142
|
+
unresolvedKeys += sub.unresolvedKeys;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
unresolvedKeys++;
|
|
146
|
+
return { merged: null, resolvedKeys, unresolvedKeys };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// Valeurs scalaires différentes → conflit non résolvable
|
|
151
|
+
unresolvedKeys++;
|
|
152
|
+
return { merged: null, resolvedKeys, unresolvedKeys };
|
|
153
|
+
}
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
// Clé dans base + ours, absent de theirs → theirs a supprimé
|
|
157
|
+
if (inBase && inOurs && !inTheirs) {
|
|
158
|
+
if (jsonEqual(baseVal, oursVal)) {
|
|
159
|
+
// Ours n'a pas changé, theirs a supprimé → supprimer
|
|
160
|
+
resolvedKeys++;
|
|
161
|
+
// Ne pas ajouter à result (suppression)
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// Ours a modifié, theirs a supprimé → conflit
|
|
165
|
+
unresolvedKeys++;
|
|
166
|
+
return { merged: null, resolvedKeys, unresolvedKeys };
|
|
167
|
+
}
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
// Clé dans base + theirs, absent de ours → ours a supprimé
|
|
171
|
+
if (inBase && !inOurs && inTheirs) {
|
|
172
|
+
if (jsonEqual(baseVal, theirsVal)) {
|
|
173
|
+
// Theirs n'a pas changé, ours a supprimé → supprimer
|
|
174
|
+
resolvedKeys++;
|
|
175
|
+
// Ne pas ajouter à result
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
// Theirs a modifié, ours a supprimé → conflit
|
|
179
|
+
unresolvedKeys++;
|
|
180
|
+
return { merged: null, resolvedKeys, unresolvedKeys };
|
|
181
|
+
}
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
// Clé dans base seulement → supprimée des deux côtés
|
|
185
|
+
if (inBase && !inOurs && !inTheirs) {
|
|
186
|
+
resolvedKeys++;
|
|
187
|
+
// Ne pas ajouter à result
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
// Clé dans ours seulement (ajout ours)
|
|
191
|
+
if (!inBase && inOurs && !inTheirs) {
|
|
192
|
+
result[key] = oursVal;
|
|
193
|
+
resolvedKeys++;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
// Clé dans theirs seulement (ajout theirs)
|
|
197
|
+
if (!inBase && !inOurs && inTheirs) {
|
|
198
|
+
result[key] = theirsVal;
|
|
199
|
+
resolvedKeys++;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
// Clé présente partout → modifier éventuelle
|
|
203
|
+
if (inBase && inOurs && inTheirs) {
|
|
204
|
+
const oursChanged = !jsonEqual(baseVal, oursVal);
|
|
205
|
+
const theirsChanged = !jsonEqual(baseVal, theirsVal);
|
|
206
|
+
if (!oursChanged && !theirsChanged) {
|
|
207
|
+
// Aucun côté n'a changé → garder base
|
|
208
|
+
result[key] = baseVal;
|
|
209
|
+
resolvedKeys++;
|
|
210
|
+
}
|
|
211
|
+
else if (oursChanged && !theirsChanged) {
|
|
212
|
+
// Seul ours a changé → accepter ours
|
|
213
|
+
result[key] = oursVal;
|
|
214
|
+
resolvedKeys++;
|
|
215
|
+
}
|
|
216
|
+
else if (!oursChanged && theirsChanged) {
|
|
217
|
+
// Seul theirs a changé → accepter theirs
|
|
218
|
+
result[key] = theirsVal;
|
|
219
|
+
resolvedKeys++;
|
|
220
|
+
}
|
|
221
|
+
else if (jsonEqual(oursVal, theirsVal)) {
|
|
222
|
+
// Les deux ont fait la même modif → same_change
|
|
223
|
+
result[key] = oursVal;
|
|
224
|
+
resolvedKeys++;
|
|
225
|
+
}
|
|
226
|
+
else if (isObject(oursVal) && isObject(theirsVal) && isObject(baseVal)) {
|
|
227
|
+
// Les deux ont modifié des objets → fusion récursive
|
|
228
|
+
const sub = mergeObjects(baseVal, oursVal, theirsVal);
|
|
229
|
+
if (sub.merged !== null) {
|
|
230
|
+
result[key] = sub.merged;
|
|
231
|
+
resolvedKeys += sub.resolvedKeys + 1;
|
|
232
|
+
unresolvedKeys += sub.unresolvedKeys;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
unresolvedKeys++;
|
|
236
|
+
return { merged: null, resolvedKeys, unresolvedKeys };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
// Scalaires modifiés différemment → conflit non résolvable
|
|
241
|
+
unresolvedKeys++;
|
|
242
|
+
return { merged: null, resolvedKeys, unresolvedKeys };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return { merged: result, resolvedKeys, unresolvedKeys };
|
|
247
|
+
}
|
|
248
|
+
// ─── Indentation detection ────────────────────────────────
|
|
249
|
+
/**
|
|
250
|
+
* Détecte le style d'indentation d'un fichier JSON (espaces ou tab).
|
|
251
|
+
* Retourne le string d'indentation utilisé (ex: " ", " ", "\t").
|
|
252
|
+
*/
|
|
253
|
+
function detectIndentation(jsonText) {
|
|
254
|
+
const lines = jsonText.split("\n");
|
|
255
|
+
for (const line of lines) {
|
|
256
|
+
const match = line.match(/^(\t+|\s+)/);
|
|
257
|
+
if (match) {
|
|
258
|
+
const indent = match[1];
|
|
259
|
+
if (indent.includes("\t"))
|
|
260
|
+
return "\t";
|
|
261
|
+
return indent.length;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return 2; // défaut
|
|
265
|
+
}
|
|
266
|
+
// ─── Public API ───────────────────────────────────────────
|
|
267
|
+
/**
|
|
268
|
+
* Tente de résoudre un conflit JSON en fusionnant sémantiquement
|
|
269
|
+
* les trois versions.
|
|
270
|
+
*
|
|
271
|
+
* @param baseLines - Lignes de la version base
|
|
272
|
+
* @param oursLines - Lignes de la version ours
|
|
273
|
+
* @param theirsLines - Lignes de la version theirs
|
|
274
|
+
* @returns `JsonMergeResult` avec `merged !== null` si résolu, `null` sinon
|
|
275
|
+
*/
|
|
276
|
+
export function tryResolveJsonConflict(baseLines, oursLines, theirsLines) {
|
|
277
|
+
const baseText = baseLines.join("\n");
|
|
278
|
+
const oursText = oursLines.join("\n");
|
|
279
|
+
const theirsText = theirsLines.join("\n");
|
|
280
|
+
// Tenter de parser les trois versions
|
|
281
|
+
let baseJson;
|
|
282
|
+
let oursJson;
|
|
283
|
+
let theirsJson;
|
|
284
|
+
try {
|
|
285
|
+
baseJson = JSON.parse(stripJsoncComments(baseText) || "{}");
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
// Base peut être vide (conflict sans diff3)
|
|
289
|
+
baseJson = {};
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
oursJson = JSON.parse(stripJsoncComments(oursText));
|
|
293
|
+
}
|
|
294
|
+
catch (e) {
|
|
295
|
+
return {
|
|
296
|
+
merged: null,
|
|
297
|
+
reason: `Impossible de parser ours comme JSON : ${e instanceof Error ? e.message : String(e)}`,
|
|
298
|
+
resolvedKeys: 0,
|
|
299
|
+
unresolvedKeys: 1,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
theirsJson = JSON.parse(stripJsoncComments(theirsText));
|
|
304
|
+
}
|
|
305
|
+
catch (e) {
|
|
306
|
+
return {
|
|
307
|
+
merged: null,
|
|
308
|
+
reason: `Impossible de parser theirs comme JSON : ${e instanceof Error ? e.message : String(e)}`,
|
|
309
|
+
resolvedKeys: 0,
|
|
310
|
+
unresolvedKeys: 1,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
// Cas : les deux versions ne sont pas des objets (tableau, scalaire…)
|
|
314
|
+
if (!isObject(oursJson) || !isObject(theirsJson)) {
|
|
315
|
+
// Pour les tableaux ou scalaires, on peut tenter un merge basique
|
|
316
|
+
if (Array.isArray(oursJson) && Array.isArray(theirsJson)) {
|
|
317
|
+
// Pour l'instant, pas de merge sémantique des tableaux — fallback textuel
|
|
318
|
+
return {
|
|
319
|
+
merged: null,
|
|
320
|
+
reason: "Fusion sémantique de tableaux JSON non supportée (fallback textuel).",
|
|
321
|
+
resolvedKeys: 0,
|
|
322
|
+
unresolvedKeys: 1,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (jsonEqual(oursJson, theirsJson)) {
|
|
326
|
+
// Même valeur scalaire des deux côtés
|
|
327
|
+
const indent = detectIndentation(oursText);
|
|
328
|
+
return {
|
|
329
|
+
merged: JSON.stringify(oursJson, null, indent),
|
|
330
|
+
reason: "Même valeur JSON des deux côtés — résolution triviale.",
|
|
331
|
+
resolvedKeys: 1,
|
|
332
|
+
unresolvedKeys: 0,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
merged: null,
|
|
337
|
+
reason: "Valeurs JSON scalaires différentes — fallback textuel.",
|
|
338
|
+
resolvedKeys: 0,
|
|
339
|
+
unresolvedKeys: 1,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
const baseObj = isObject(baseJson) ? baseJson : {};
|
|
343
|
+
// Fusion sémantique
|
|
344
|
+
const { merged, resolvedKeys, unresolvedKeys } = mergeObjects(baseObj, oursJson, theirsJson);
|
|
345
|
+
if (merged === null) {
|
|
346
|
+
return {
|
|
347
|
+
merged: null,
|
|
348
|
+
reason: `Fusion JSON impossible : ${unresolvedKeys} clé(s) en conflit non résolvable.`,
|
|
349
|
+
resolvedKeys,
|
|
350
|
+
unresolvedKeys,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
// Reformater le JSON en préservant le style d'indentation de ours
|
|
354
|
+
const indent = detectIndentation(oursText);
|
|
355
|
+
const mergedText = JSON.stringify(merged, null, indent);
|
|
356
|
+
return {
|
|
357
|
+
merged: mergedText,
|
|
358
|
+
reason: `Fusion JSON sémantique réussie : ${resolvedKeys} clé(s) fusionnée(s), ${unresolvedKeys} conflit(s).`,
|
|
359
|
+
resolvedKeys,
|
|
360
|
+
unresolvedKeys,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/resolvers/json.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand — Résolveur sémantique pour package-lock.json (npm)
|
|
3
|
+
*
|
|
4
|
+
* Au lieu de traiter package-lock.json comme un fichier opaque (→ theirs),
|
|
5
|
+
* ce résolveur comprend la structure : chaque entrée dans "packages" ou
|
|
6
|
+
* "dependencies" est un nœud indépendant.
|
|
7
|
+
*
|
|
8
|
+
* Stratégie :
|
|
9
|
+
* 1. Parser les trois versions (base, ours, theirs) en maps de dépendances
|
|
10
|
+
* 2. Merge 3-way par clé (path de package) :
|
|
11
|
+
* - Ajouté d'un seul côté → prendre l'ajout
|
|
12
|
+
* - Supprimé d'un seul côté (pas modifié de l'autre) → supprimer
|
|
13
|
+
* - Modifié d'un seul côté → prendre la modification
|
|
14
|
+
* - Modifié des deux côtés avec même résultat → ok
|
|
15
|
+
* - Modifié des deux côtés avec résultat différent → conflit (prefer-theirs par défaut)
|
|
16
|
+
* 3. Reconstruire le JSON avec l'indentation d'origine
|
|
17
|
+
*
|
|
18
|
+
* Limitations :
|
|
19
|
+
* - Ne valide pas la cohérence sémantique (ranges vs resolved)
|
|
20
|
+
* - Après merge, un `npm install` reste recommandé
|
|
21
|
+
*/
|
|
22
|
+
export interface LockfileMergeResult {
|
|
23
|
+
/** Contenu JSON fusionné ou null si échec */
|
|
24
|
+
merged: string | null;
|
|
25
|
+
/** Raison de la résolution */
|
|
26
|
+
reason: string;
|
|
27
|
+
/** Nombre de paquets fusionnés */
|
|
28
|
+
resolvedPackages: number;
|
|
29
|
+
/** Nombre de conflits de versions */
|
|
30
|
+
versionConflicts: number;
|
|
31
|
+
/** Paquets en conflit (versions incompatibles) */
|
|
32
|
+
conflictedPackages: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Fusionne trois versions d'un package-lock.json par entrée de paquet.
|
|
36
|
+
*/
|
|
37
|
+
export declare function tryResolveLockfileNpmConflict(baseLines: string[], oursLines: string[], theirsLines: string[]): LockfileMergeResult;
|
|
38
|
+
//# sourceMappingURL=lockfile-npm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfile-npm.d.ts","sourceRoot":"","sources":["../../src/resolvers/lockfile-npm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,MAAM,WAAW,mBAAmB;IAClC,6CAA6C;IAC7C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,qCAAqC;IACrC,gBAAgB,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAoDD;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,MAAM,EAAE,GACpB,mBAAmB,CAsJrB"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand — Résolveur sémantique pour package-lock.json (npm)
|
|
3
|
+
*
|
|
4
|
+
* Au lieu de traiter package-lock.json comme un fichier opaque (→ theirs),
|
|
5
|
+
* ce résolveur comprend la structure : chaque entrée dans "packages" ou
|
|
6
|
+
* "dependencies" est un nœud indépendant.
|
|
7
|
+
*
|
|
8
|
+
* Stratégie :
|
|
9
|
+
* 1. Parser les trois versions (base, ours, theirs) en maps de dépendances
|
|
10
|
+
* 2. Merge 3-way par clé (path de package) :
|
|
11
|
+
* - Ajouté d'un seul côté → prendre l'ajout
|
|
12
|
+
* - Supprimé d'un seul côté (pas modifié de l'autre) → supprimer
|
|
13
|
+
* - Modifié d'un seul côté → prendre la modification
|
|
14
|
+
* - Modifié des deux côtés avec même résultat → ok
|
|
15
|
+
* - Modifié des deux côtés avec résultat différent → conflit (prefer-theirs par défaut)
|
|
16
|
+
* 3. Reconstruire le JSON avec l'indentation d'origine
|
|
17
|
+
*
|
|
18
|
+
* Limitations :
|
|
19
|
+
* - Ne valide pas la cohérence sémantique (ranges vs resolved)
|
|
20
|
+
* - Après merge, un `npm install` reste recommandé
|
|
21
|
+
*/
|
|
22
|
+
// ─── Parser simplifié ────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Extrait les entrées du lockfile v2/v3 (clé "packages") ou v1 ("dependencies").
|
|
25
|
+
* Retourne une Map<path, jsonStr> pour chaque entrée.
|
|
26
|
+
*/
|
|
27
|
+
function parseLockfileEntries(json) {
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = JSON.parse(json);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
// Détecter l'indentation
|
|
36
|
+
const indentMatch = json.match(/\n(\s+)"/);
|
|
37
|
+
const indent = indentMatch ? indentMatch[1] : " ";
|
|
38
|
+
const packages = new Map();
|
|
39
|
+
let format = "v1";
|
|
40
|
+
if (parsed.packages && typeof parsed.packages === "object") {
|
|
41
|
+
format = parsed.lockfileVersion === 3 ? "v3" : "v2";
|
|
42
|
+
for (const [key, value] of Object.entries(parsed.packages)) {
|
|
43
|
+
packages.set(key, JSON.stringify(value));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else if (parsed.dependencies && typeof parsed.dependencies === "object") {
|
|
47
|
+
for (const [key, value] of Object.entries(parsed.dependencies)) {
|
|
48
|
+
packages.set(key, JSON.stringify(value));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Header = tout sauf packages/dependencies
|
|
52
|
+
const header = {};
|
|
53
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
54
|
+
if (key !== "packages" && key !== "dependencies") {
|
|
55
|
+
header[key] = value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { header, packages, format, indent };
|
|
59
|
+
}
|
|
60
|
+
// ─── 3-way merge ─────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* Fusionne trois versions d'un package-lock.json par entrée de paquet.
|
|
63
|
+
*/
|
|
64
|
+
export function tryResolveLockfileNpmConflict(baseLines, oursLines, theirsLines) {
|
|
65
|
+
const baseText = baseLines.join("\n");
|
|
66
|
+
const oursText = oursLines.join("\n");
|
|
67
|
+
const theirsText = theirsLines.join("\n");
|
|
68
|
+
const baseParsed = parseLockfileEntries(baseText);
|
|
69
|
+
const oursParsed = parseLockfileEntries(oursText);
|
|
70
|
+
const theirsParsed = parseLockfileEntries(theirsText);
|
|
71
|
+
if (!baseParsed || !oursParsed || !theirsParsed) {
|
|
72
|
+
return {
|
|
73
|
+
merged: null,
|
|
74
|
+
reason: "Impossible de parser une des versions du package-lock.json.",
|
|
75
|
+
resolvedPackages: 0,
|
|
76
|
+
versionConflicts: 0,
|
|
77
|
+
conflictedPackages: [],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const basePkgs = baseParsed.packages;
|
|
81
|
+
const oursPkgs = oursParsed.packages;
|
|
82
|
+
const theirsPkgs = theirsParsed.packages;
|
|
83
|
+
// Toutes les clés
|
|
84
|
+
const allKeys = new Set([...basePkgs.keys(), ...oursPkgs.keys(), ...theirsPkgs.keys()]);
|
|
85
|
+
const mergedPkgs = new Map();
|
|
86
|
+
let resolvedPackages = 0;
|
|
87
|
+
let versionConflicts = 0;
|
|
88
|
+
const conflictedPackages = [];
|
|
89
|
+
for (const key of allKeys) {
|
|
90
|
+
const base = basePkgs.get(key);
|
|
91
|
+
const ours = oursPkgs.get(key);
|
|
92
|
+
const theirs = theirsPkgs.get(key);
|
|
93
|
+
// Pas dans base → ajout(s)
|
|
94
|
+
if (base === undefined) {
|
|
95
|
+
if (ours !== undefined && theirs !== undefined) {
|
|
96
|
+
if (ours === theirs) {
|
|
97
|
+
// Même ajout
|
|
98
|
+
mergedPkgs.set(key, ours);
|
|
99
|
+
resolvedPackages++;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// Ajout différent des deux côtés → merge de version (prefer theirs)
|
|
103
|
+
mergedPkgs.set(key, theirs);
|
|
104
|
+
resolvedPackages++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (ours !== undefined) {
|
|
108
|
+
mergedPkgs.set(key, ours);
|
|
109
|
+
resolvedPackages++;
|
|
110
|
+
}
|
|
111
|
+
else if (theirs !== undefined) {
|
|
112
|
+
mergedPkgs.set(key, theirs);
|
|
113
|
+
resolvedPackages++;
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Dans base mais supprimé d'un côté
|
|
118
|
+
if (ours === undefined && theirs === undefined) {
|
|
119
|
+
// Supprimé des deux côtés → supprimer
|
|
120
|
+
resolvedPackages++;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (ours === undefined) {
|
|
124
|
+
// Ours supprimé
|
|
125
|
+
if (theirs === base) {
|
|
126
|
+
// Theirs pas modifié → supprimer (ours gagne)
|
|
127
|
+
resolvedPackages++;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// Theirs modifié, ours supprimé → garder theirs (il a été mis à jour)
|
|
131
|
+
mergedPkgs.set(key, theirs);
|
|
132
|
+
resolvedPackages++;
|
|
133
|
+
}
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (theirs === undefined) {
|
|
137
|
+
// Theirs supprimé
|
|
138
|
+
if (ours === base) {
|
|
139
|
+
// Ours pas modifié → supprimer (theirs gagne)
|
|
140
|
+
resolvedPackages++;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// Ours modifié, theirs supprimé → garder ours
|
|
144
|
+
mergedPkgs.set(key, ours);
|
|
145
|
+
resolvedPackages++;
|
|
146
|
+
}
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
// Présent partout — comparer
|
|
150
|
+
const oursChanged = ours !== base;
|
|
151
|
+
const theirsChanged = theirs !== base;
|
|
152
|
+
if (!oursChanged && !theirsChanged) {
|
|
153
|
+
mergedPkgs.set(key, base);
|
|
154
|
+
resolvedPackages++;
|
|
155
|
+
}
|
|
156
|
+
else if (!oursChanged) {
|
|
157
|
+
mergedPkgs.set(key, theirs);
|
|
158
|
+
resolvedPackages++;
|
|
159
|
+
}
|
|
160
|
+
else if (!theirsChanged) {
|
|
161
|
+
mergedPkgs.set(key, ours);
|
|
162
|
+
resolvedPackages++;
|
|
163
|
+
}
|
|
164
|
+
else if (ours === theirs) {
|
|
165
|
+
mergedPkgs.set(key, ours);
|
|
166
|
+
resolvedPackages++;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// Vrai conflit de version → merge au niveau des propriétés
|
|
170
|
+
const merged = mergePackageEntry(base, ours, theirs);
|
|
171
|
+
if (merged !== null) {
|
|
172
|
+
mergedPkgs.set(key, merged);
|
|
173
|
+
resolvedPackages++;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// Fallback : prefer theirs
|
|
177
|
+
mergedPkgs.set(key, theirs);
|
|
178
|
+
versionConflicts++;
|
|
179
|
+
conflictedPackages.push(key);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Reconstruire le JSON
|
|
184
|
+
const indent = oursParsed.indent;
|
|
185
|
+
const header = { ...oursParsed.header };
|
|
186
|
+
const pkgKey = oursParsed.format === "v1" ? "dependencies" : "packages";
|
|
187
|
+
// Trier les clés comme npm le fait (alphabétique)
|
|
188
|
+
const sortedEntries = {};
|
|
189
|
+
const sortedKeys = [...mergedPkgs.keys()].sort();
|
|
190
|
+
for (const key of sortedKeys) {
|
|
191
|
+
try {
|
|
192
|
+
sortedEntries[key] = JSON.parse(mergedPkgs.get(key));
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
sortedEntries[key] = mergedPkgs.get(key);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const result = { ...header, [pkgKey]: sortedEntries };
|
|
199
|
+
const merged = JSON.stringify(result, null, indent.length) + "\n";
|
|
200
|
+
const reason = versionConflicts > 0
|
|
201
|
+
? `Fusion sémantique lockfile : ${resolvedPackages} paquet(s) fusionné(s), ${versionConflicts} conflit(s) de version résolu(s) (prefer-theirs).`
|
|
202
|
+
: `Fusion sémantique lockfile réussie : ${resolvedPackages} paquet(s) fusionné(s) sans conflit.`;
|
|
203
|
+
return {
|
|
204
|
+
merged,
|
|
205
|
+
reason,
|
|
206
|
+
resolvedPackages,
|
|
207
|
+
versionConflicts,
|
|
208
|
+
conflictedPackages,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
// ─── Merge de propriétés d'un paquet ─────────────────────
|
|
212
|
+
/**
|
|
213
|
+
* Fusionne deux versions différentes d'une entrée de paquet au niveau propriété.
|
|
214
|
+
* Permet de résoudre les cas où ours met à jour `version` et theirs met à jour `integrity`.
|
|
215
|
+
*/
|
|
216
|
+
function mergePackageEntry(baseJson, oursJson, theirsJson) {
|
|
217
|
+
let base;
|
|
218
|
+
let ours;
|
|
219
|
+
let theirs;
|
|
220
|
+
try {
|
|
221
|
+
base = JSON.parse(baseJson);
|
|
222
|
+
ours = JSON.parse(oursJson);
|
|
223
|
+
theirs = JSON.parse(theirsJson);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
if (typeof base !== "object" || typeof ours !== "object" || typeof theirs !== "object") {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
const allProps = new Set([
|
|
232
|
+
...Object.keys(base),
|
|
233
|
+
...Object.keys(ours),
|
|
234
|
+
...Object.keys(theirs),
|
|
235
|
+
]);
|
|
236
|
+
const merged = {};
|
|
237
|
+
for (const prop of allProps) {
|
|
238
|
+
const baseVal = JSON.stringify(base[prop]);
|
|
239
|
+
const oursVal = JSON.stringify(ours[prop]);
|
|
240
|
+
const theirsVal = JSON.stringify(theirs[prop]);
|
|
241
|
+
const oursChanged = oursVal !== baseVal;
|
|
242
|
+
const theirsChanged = theirsVal !== baseVal;
|
|
243
|
+
if (!oursChanged && !theirsChanged) {
|
|
244
|
+
if (base[prop] !== undefined)
|
|
245
|
+
merged[prop] = base[prop];
|
|
246
|
+
}
|
|
247
|
+
else if (!oursChanged) {
|
|
248
|
+
if (theirs[prop] !== undefined)
|
|
249
|
+
merged[prop] = theirs[prop];
|
|
250
|
+
}
|
|
251
|
+
else if (!theirsChanged) {
|
|
252
|
+
if (ours[prop] !== undefined)
|
|
253
|
+
merged[prop] = ours[prop];
|
|
254
|
+
}
|
|
255
|
+
else if (oursVal === theirsVal) {
|
|
256
|
+
if (ours[prop] !== undefined)
|
|
257
|
+
merged[prop] = ours[prop];
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
// Vrai conflit sur cette propriété → prefer theirs
|
|
261
|
+
if (theirs[prop] !== undefined)
|
|
262
|
+
merged[prop] = theirs[prop];
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return JSON.stringify(merged);
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=lockfile-npm.js.map
|