@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.
Files changed (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -0
  3. package/dist/__tests__/bench.bench.d.ts +14 -0
  4. package/dist/__tests__/bench.bench.d.ts.map +1 -0
  5. package/dist/__tests__/bench.bench.js +137 -0
  6. package/dist/__tests__/bench.bench.js.map +1 -0
  7. package/dist/__tests__/confidence-v14.test.d.ts +13 -0
  8. package/dist/__tests__/confidence-v14.test.d.ts.map +1 -0
  9. package/dist/__tests__/confidence-v14.test.js +284 -0
  10. package/dist/__tests__/confidence-v14.test.js.map +1 -0
  11. package/dist/__tests__/config.test.d.ts +2 -0
  12. package/dist/__tests__/config.test.d.ts.map +1 -0
  13. package/dist/__tests__/config.test.js +317 -0
  14. package/dist/__tests__/config.test.js.map +1 -0
  15. package/dist/__tests__/corpus.d.ts +36 -0
  16. package/dist/__tests__/corpus.d.ts.map +1 -0
  17. package/dist/__tests__/corpus.js +541 -0
  18. package/dist/__tests__/corpus.js.map +1 -0
  19. package/dist/__tests__/corpus.test.d.ts +17 -0
  20. package/dist/__tests__/corpus.test.d.ts.map +1 -0
  21. package/dist/__tests__/corpus.test.js +179 -0
  22. package/dist/__tests__/corpus.test.js.map +1 -0
  23. package/dist/__tests__/diff.test.d.ts +10 -0
  24. package/dist/__tests__/diff.test.d.ts.map +1 -0
  25. package/dist/__tests__/diff.test.js +178 -0
  26. package/dist/__tests__/diff.test.js.map +1 -0
  27. package/dist/__tests__/format-resolvers.test.d.ts +2 -0
  28. package/dist/__tests__/format-resolvers.test.d.ts.map +1 -0
  29. package/dist/__tests__/format-resolvers.test.js +577 -0
  30. package/dist/__tests__/format-resolvers.test.js.map +1 -0
  31. package/dist/__tests__/imports-extended.test.d.ts +2 -0
  32. package/dist/__tests__/imports-extended.test.d.ts.map +1 -0
  33. package/dist/__tests__/imports-extended.test.js +94 -0
  34. package/dist/__tests__/imports-extended.test.js.map +1 -0
  35. package/dist/__tests__/lockfile-resolvers.test.d.ts +2 -0
  36. package/dist/__tests__/lockfile-resolvers.test.d.ts.map +1 -0
  37. package/dist/__tests__/lockfile-resolvers.test.js +200 -0
  38. package/dist/__tests__/lockfile-resolvers.test.js.map +1 -0
  39. package/dist/__tests__/patterns/insertion-at-boundary.test.d.ts +10 -0
  40. package/dist/__tests__/patterns/insertion-at-boundary.test.d.ts.map +1 -0
  41. package/dist/__tests__/patterns/insertion-at-boundary.test.js +185 -0
  42. package/dist/__tests__/patterns/insertion-at-boundary.test.js.map +1 -0
  43. package/dist/__tests__/patterns/reorder-only.test.d.ts +10 -0
  44. package/dist/__tests__/patterns/reorder-only.test.d.ts.map +1 -0
  45. package/dist/__tests__/patterns/reorder-only.test.js +181 -0
  46. package/dist/__tests__/patterns/reorder-only.test.js.map +1 -0
  47. package/dist/__tests__/phase-7-2-3b.test.d.ts +6 -0
  48. package/dist/__tests__/phase-7-2-3b.test.d.ts.map +1 -0
  49. package/dist/__tests__/phase-7-2-3b.test.js +730 -0
  50. package/dist/__tests__/phase-7-2-3b.test.js.map +1 -0
  51. package/dist/__tests__/resolver.test.d.ts +2 -0
  52. package/dist/__tests__/resolver.test.d.ts.map +1 -0
  53. package/dist/__tests__/resolver.test.js +927 -0
  54. package/dist/__tests__/resolver.test.js.map +1 -0
  55. package/dist/__tests__/resolvers/cargo.test.d.ts +10 -0
  56. package/dist/__tests__/resolvers/cargo.test.d.ts.map +1 -0
  57. package/dist/__tests__/resolvers/cargo.test.js +158 -0
  58. package/dist/__tests__/resolvers/cargo.test.js.map +1 -0
  59. package/dist/__tests__/resolvers/dockerfile.test.d.ts +8 -0
  60. package/dist/__tests__/resolvers/dockerfile.test.d.ts.map +1 -0
  61. package/dist/__tests__/resolvers/dockerfile.test.js +120 -0
  62. package/dist/__tests__/resolvers/dockerfile.test.js.map +1 -0
  63. package/dist/__tests__/resolvers/dotenv.test.d.ts +9 -0
  64. package/dist/__tests__/resolvers/dotenv.test.d.ts.map +1 -0
  65. package/dist/__tests__/resolvers/dotenv.test.js +113 -0
  66. package/dist/__tests__/resolvers/dotenv.test.js.map +1 -0
  67. package/dist/__tests__/resolvers/improvements-v14.test.d.ts +8 -0
  68. package/dist/__tests__/resolvers/improvements-v14.test.d.ts.map +1 -0
  69. package/dist/__tests__/resolvers/improvements-v14.test.js +306 -0
  70. package/dist/__tests__/resolvers/improvements-v14.test.js.map +1 -0
  71. package/dist/__tests__/validation.test.d.ts +12 -0
  72. package/dist/__tests__/validation.test.d.ts.map +1 -0
  73. package/dist/__tests__/validation.test.js +136 -0
  74. package/dist/__tests__/validation.test.js.map +1 -0
  75. package/dist/classifier.d.ts +21 -0
  76. package/dist/classifier.d.ts.map +1 -0
  77. package/dist/classifier.js +127 -0
  78. package/dist/classifier.js.map +1 -0
  79. package/dist/config.d.ts +108 -0
  80. package/dist/config.d.ts.map +1 -0
  81. package/dist/config.js +200 -0
  82. package/dist/config.js.map +1 -0
  83. package/dist/diff.d.ts +69 -0
  84. package/dist/diff.d.ts.map +1 -0
  85. package/dist/diff.js +328 -0
  86. package/dist/diff.js.map +1 -0
  87. package/dist/index.d.ts +47 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +38 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/parser.d.ts +39 -0
  92. package/dist/parser.d.ts.map +1 -0
  93. package/dist/parser.js +164 -0
  94. package/dist/parser.js.map +1 -0
  95. package/dist/patterns/complex.d.ts +5 -0
  96. package/dist/patterns/complex.d.ts.map +1 -0
  97. package/dist/patterns/complex.js +27 -0
  98. package/dist/patterns/complex.js.map +1 -0
  99. package/dist/patterns/delete-no-change.d.ts +4 -0
  100. package/dist/patterns/delete-no-change.d.ts.map +1 -0
  101. package/dist/patterns/delete-no-change.js +75 -0
  102. package/dist/patterns/delete-no-change.js.map +1 -0
  103. package/dist/patterns/insertion-at-boundary.d.ts +22 -0
  104. package/dist/patterns/insertion-at-boundary.d.ts.map +1 -0
  105. package/dist/patterns/insertion-at-boundary.js +164 -0
  106. package/dist/patterns/insertion-at-boundary.js.map +1 -0
  107. package/dist/patterns/non-overlapping.d.ts +4 -0
  108. package/dist/patterns/non-overlapping.d.ts.map +1 -0
  109. package/dist/patterns/non-overlapping.js +28 -0
  110. package/dist/patterns/non-overlapping.js.map +1 -0
  111. package/dist/patterns/one-side-change.d.ts +4 -0
  112. package/dist/patterns/one-side-change.d.ts.map +1 -0
  113. package/dist/patterns/one-side-change.js +45 -0
  114. package/dist/patterns/one-side-change.js.map +1 -0
  115. package/dist/patterns/reorder-only.d.ts +14 -0
  116. package/dist/patterns/reorder-only.d.ts.map +1 -0
  117. package/dist/patterns/reorder-only.js +81 -0
  118. package/dist/patterns/reorder-only.js.map +1 -0
  119. package/dist/patterns/same-change.d.ts +4 -0
  120. package/dist/patterns/same-change.d.ts.map +1 -0
  121. package/dist/patterns/same-change.js +25 -0
  122. package/dist/patterns/same-change.js.map +1 -0
  123. package/dist/patterns/utils.d.ts +70 -0
  124. package/dist/patterns/utils.d.ts.map +1 -0
  125. package/dist/patterns/utils.js +206 -0
  126. package/dist/patterns/utils.js.map +1 -0
  127. package/dist/patterns/value-only-change.d.ts +4 -0
  128. package/dist/patterns/value-only-change.d.ts.map +1 -0
  129. package/dist/patterns/value-only-change.js +34 -0
  130. package/dist/patterns/value-only-change.js.map +1 -0
  131. package/dist/patterns/whitespace-only.d.ts +4 -0
  132. package/dist/patterns/whitespace-only.d.ts.map +1 -0
  133. package/dist/patterns/whitespace-only.js +32 -0
  134. package/dist/patterns/whitespace-only.js.map +1 -0
  135. package/dist/resolver/assemble.d.ts +25 -0
  136. package/dist/resolver/assemble.d.ts.map +1 -0
  137. package/dist/resolver/assemble.js +170 -0
  138. package/dist/resolver/assemble.js.map +1 -0
  139. package/dist/resolver/format-dispatch.d.ts +40 -0
  140. package/dist/resolver/format-dispatch.d.ts.map +1 -0
  141. package/dist/resolver/format-dispatch.js +51 -0
  142. package/dist/resolver/format-dispatch.js.map +1 -0
  143. package/dist/resolver/generated-detection.d.ts +48 -0
  144. package/dist/resolver/generated-detection.d.ts.map +1 -0
  145. package/dist/resolver/generated-detection.js +123 -0
  146. package/dist/resolver/generated-detection.js.map +1 -0
  147. package/dist/resolver/index.d.ts +26 -0
  148. package/dist/resolver/index.d.ts.map +1 -0
  149. package/dist/resolver/index.js +147 -0
  150. package/dist/resolver/index.js.map +1 -0
  151. package/dist/resolver/policy.d.ts +53 -0
  152. package/dist/resolver/policy.d.ts.map +1 -0
  153. package/dist/resolver/policy.js +99 -0
  154. package/dist/resolver/policy.js.map +1 -0
  155. package/dist/resolver/validation.d.ts +28 -0
  156. package/dist/resolver/validation.d.ts.map +1 -0
  157. package/dist/resolver/validation.js +96 -0
  158. package/dist/resolver/validation.js.map +1 -0
  159. package/dist/resolver.d.ts +18 -0
  160. package/dist/resolver.d.ts.map +1 -0
  161. package/dist/resolver.js +18 -0
  162. package/dist/resolver.js.map +1 -0
  163. package/dist/resolvers/cargo.d.ts +34 -0
  164. package/dist/resolvers/cargo.d.ts.map +1 -0
  165. package/dist/resolvers/cargo.js +262 -0
  166. package/dist/resolvers/cargo.js.map +1 -0
  167. package/dist/resolvers/css.d.ts +60 -0
  168. package/dist/resolvers/css.d.ts.map +1 -0
  169. package/dist/resolvers/css.js +531 -0
  170. package/dist/resolvers/css.js.map +1 -0
  171. package/dist/resolvers/dispatcher.d.ts +78 -0
  172. package/dist/resolvers/dispatcher.d.ts.map +1 -0
  173. package/dist/resolvers/dispatcher.js +290 -0
  174. package/dist/resolvers/dispatcher.js.map +1 -0
  175. package/dist/resolvers/dockerfile.d.ts +24 -0
  176. package/dist/resolvers/dockerfile.d.ts.map +1 -0
  177. package/dist/resolvers/dockerfile.js +221 -0
  178. package/dist/resolvers/dockerfile.js.map +1 -0
  179. package/dist/resolvers/dotenv.d.ts +27 -0
  180. package/dist/resolvers/dotenv.d.ts.map +1 -0
  181. package/dist/resolvers/dotenv.js +114 -0
  182. package/dist/resolvers/dotenv.js.map +1 -0
  183. package/dist/resolvers/imports.d.ts +63 -0
  184. package/dist/resolvers/imports.d.ts.map +1 -0
  185. package/dist/resolvers/imports.js +513 -0
  186. package/dist/resolvers/imports.js.map +1 -0
  187. package/dist/resolvers/json.d.ts +48 -0
  188. package/dist/resolvers/json.d.ts.map +1 -0
  189. package/dist/resolvers/json.js +363 -0
  190. package/dist/resolvers/json.js.map +1 -0
  191. package/dist/resolvers/lockfile-npm.d.ts +38 -0
  192. package/dist/resolvers/lockfile-npm.d.ts.map +1 -0
  193. package/dist/resolvers/lockfile-npm.js +267 -0
  194. package/dist/resolvers/lockfile-npm.js.map +1 -0
  195. package/dist/resolvers/lockfile-pnpm.d.ts +44 -0
  196. package/dist/resolvers/lockfile-pnpm.d.ts.map +1 -0
  197. package/dist/resolvers/lockfile-pnpm.js +277 -0
  198. package/dist/resolvers/lockfile-pnpm.js.map +1 -0
  199. package/dist/resolvers/lockfile-yarn.d.ts +40 -0
  200. package/dist/resolvers/lockfile-yarn.d.ts.map +1 -0
  201. package/dist/resolvers/lockfile-yarn.js +184 -0
  202. package/dist/resolvers/lockfile-yarn.js.map +1 -0
  203. package/dist/resolvers/markdown.d.ts +64 -0
  204. package/dist/resolvers/markdown.d.ts.map +1 -0
  205. package/dist/resolvers/markdown.js +335 -0
  206. package/dist/resolvers/markdown.js.map +1 -0
  207. package/dist/resolvers/vue.d.ts +65 -0
  208. package/dist/resolvers/vue.d.ts.map +1 -0
  209. package/dist/resolvers/vue.js +258 -0
  210. package/dist/resolvers/vue.js.map +1 -0
  211. package/dist/resolvers/yaml.d.ts +65 -0
  212. package/dist/resolvers/yaml.d.ts.map +1 -0
  213. package/dist/resolvers/yaml.js +405 -0
  214. package/dist/resolvers/yaml.js.map +1 -0
  215. package/dist/types.d.ts +256 -0
  216. package/dist/types.d.ts.map +1 -0
  217. package/dist/types.js +8 -0
  218. package/dist/types.js.map +1 -0
  219. 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