@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,335 @@
1
+ /**
2
+ * GitWand — Résolveur Markdown section-aware
3
+ *
4
+ * Résout les conflits dans les fichiers Markdown en identifiant
5
+ * la structure de sections (headings H1..H6) et en fusionnant
6
+ * section par section lorsque les modifications sont non-overlapping.
7
+ *
8
+ * Stratégie :
9
+ * 1. Détecter les headings dans les trois versions
10
+ * 2. Découper chaque version en sections (heading + contenu jusqu'au prochain heading de niveau ≤)
11
+ * 3. Pour chaque section :
12
+ * a. Si identique dans ours et theirs → garder
13
+ * b. Si modifiée d'un seul côté → accepter la modification
14
+ * c. Si section ajoutée d'un côté → ajouter
15
+ * d. Si modifiée des deux côtés différemment → conflit partiel (insert les deux versions)
16
+ * 4. Gestion du frontmatter YAML (entre --- au début du fichier) : traité séparément
17
+ *
18
+ * Limites :
19
+ * - Ne pas résoudre les conflits intra-section (renvoyés au moteur textuel)
20
+ * - Pas de merge sémantique du contenu riche (listes, tableaux, code)
21
+ */
22
+ // ─── Frontmatter ─────────────────────────────────────────
23
+ /**
24
+ * Détecte et extrait le frontmatter YAML si présent (--- au début).
25
+ * Retourne { frontmatter: string[], rest: string[] }.
26
+ */
27
+ export function extractFrontmatter(lines) {
28
+ if (lines.length === 0 || lines[0].trim() !== "---") {
29
+ return { frontmatter: [], rest: lines };
30
+ }
31
+ let end = -1;
32
+ for (let i = 1; i < lines.length; i++) {
33
+ if (lines[i].trim() === "---" || lines[i].trim() === "...") {
34
+ end = i;
35
+ break;
36
+ }
37
+ }
38
+ if (end === -1) {
39
+ // Pas de frontmatter fermant → traiter comme texte normal
40
+ return { frontmatter: [], rest: lines };
41
+ }
42
+ return {
43
+ frontmatter: lines.slice(0, end + 1),
44
+ rest: lines.slice(end + 1),
45
+ };
46
+ }
47
+ // ─── Section parsing ──────────────────────────────────────
48
+ /**
49
+ * Détecte le niveau d'un heading ATX (`# ... `).
50
+ * Retourne 0 si la ligne n'est pas un heading.
51
+ */
52
+ function headingLevel(line) {
53
+ const match = line.match(/^(#{1,6})\s/);
54
+ return match ? match[1].length : 0;
55
+ }
56
+ /**
57
+ * Découpe un tableau de lignes en sections Markdown.
58
+ * Chaque section commence par un heading ATX.
59
+ * Le contenu avant le premier heading forme une section "prologue" (level 0).
60
+ */
61
+ export function parseSections(lines) {
62
+ const sections = [];
63
+ let currentSection = {
64
+ heading: null,
65
+ level: 0,
66
+ lines: [],
67
+ startIdx: 0,
68
+ };
69
+ for (let i = 0; i < lines.length; i++) {
70
+ const level = headingLevel(lines[i]);
71
+ if (level > 0) {
72
+ // Nouveau heading → sauvegarder la section courante, en commencer une nouvelle
73
+ sections.push(currentSection);
74
+ currentSection = {
75
+ heading: lines[i],
76
+ level,
77
+ lines: [],
78
+ startIdx: i,
79
+ };
80
+ }
81
+ else {
82
+ currentSection.lines.push(lines[i]);
83
+ }
84
+ }
85
+ // Sauvegarder la dernière section
86
+ sections.push(currentSection);
87
+ return sections;
88
+ }
89
+ // ─── Section key ─────────────────────────────────────────
90
+ /**
91
+ * Retourne une clé unique pour identifier une section par son heading.
92
+ * Les sections sans heading utilisent "__prologue__".
93
+ */
94
+ function sectionKey(section) {
95
+ return section.heading ?? "__prologue__";
96
+ }
97
+ /**
98
+ * Compare deux sections (heading + contenu) pour égalité textuelle.
99
+ */
100
+ function sectionsEqual(a, b) {
101
+ if (a.heading !== b.heading)
102
+ return false;
103
+ if (a.lines.length !== b.lines.length)
104
+ return false;
105
+ return a.lines.every((line, i) => line === b.lines[i]);
106
+ }
107
+ /**
108
+ * Fusionne deux versions Markdown section par section avec une base commune.
109
+ *
110
+ * @param baseLines - Lignes de la version base
111
+ * @param oursLines - Lignes de la version ours
112
+ * @param theirsLines - Lignes de la version theirs
113
+ */
114
+ export function tryResolveMarkdownConflict(baseLines, oursLines, theirsLines) {
115
+ // Extraire frontmatter de chaque version
116
+ const baseFm = extractFrontmatter(baseLines);
117
+ const oursFm = extractFrontmatter(oursLines);
118
+ const theirsFm = extractFrontmatter(theirsLines);
119
+ // Résoudre le frontmatter séparément
120
+ const mergedFrontmatter = resolveFrontmatter(baseFm.frontmatter, oursFm.frontmatter, theirsFm.frontmatter);
121
+ if (mergedFrontmatter === null) {
122
+ return {
123
+ mergedLines: null,
124
+ conflictedSections: ["frontmatter"],
125
+ resolvedSections: 0,
126
+ reason: "Conflit dans le frontmatter YAML — fusion manuelle requise.",
127
+ };
128
+ }
129
+ // Découper en sections
130
+ const baseSections = parseSections(baseFm.rest);
131
+ const oursSections = parseSections(oursFm.rest);
132
+ const theirsSections = parseSections(theirsFm.rest);
133
+ // Indexer par clé
134
+ const baseMap = new Map(baseSections.map((s) => [sectionKey(s), s]));
135
+ const oursMap = new Map(oursSections.map((s) => [sectionKey(s), s]));
136
+ const theirsMap = new Map(theirsSections.map((s) => [sectionKey(s), s]));
137
+ // Ordre des sections : union de toutes les clés dans l'ordre d'apparition
138
+ const orderedKeys = buildSectionOrder(baseSections, oursSections, theirsSections);
139
+ const mergedLines = [...mergedFrontmatter];
140
+ const conflictedSections = [];
141
+ let resolvedSections = 0;
142
+ for (const key of orderedKeys) {
143
+ const baseSection = baseMap.get(key);
144
+ const oursSection = oursMap.get(key);
145
+ const theirsSection = theirsMap.get(key);
146
+ const resolution = resolveSectionConflict(baseSection, oursSection, theirsSection, key);
147
+ if (resolution.resolved) {
148
+ const lines = resolution.lines;
149
+ mergedLines.push(...lines);
150
+ resolvedSections++;
151
+ }
152
+ else {
153
+ // Conflit non résolvable → insérer les deux versions avec marqueurs de section
154
+ conflictedSections.push(key);
155
+ if (oursSection) {
156
+ if (oursSection.heading)
157
+ mergedLines.push(oursSection.heading);
158
+ mergedLines.push(...oursSection.lines);
159
+ }
160
+ if (theirsSection && !sectionsEqual(oursSection ?? emptySectionFor(key), theirsSection)) {
161
+ // Ajouter la version theirs avec un commentaire d'avertissement
162
+ mergedLines.push(`<!-- ⚠️ GitWand: section "${key}" modifiée des deux côtés -->`);
163
+ if (theirsSection.heading)
164
+ mergedLines.push(theirsSection.heading);
165
+ mergedLines.push(...theirsSection.lines);
166
+ }
167
+ }
168
+ }
169
+ // Si des conflits partiels → le contenu est produit mais marqué
170
+ if (conflictedSections.length > 0) {
171
+ return {
172
+ mergedLines: null, // Force resolution manuelle si des sections ont conflicté
173
+ conflictedSections,
174
+ resolvedSections,
175
+ reason: `Fusion Markdown partielle : ${resolvedSections} section(s) résolue(s), ${conflictedSections.length} en conflit (${conflictedSections.join(", ")}).`,
176
+ };
177
+ }
178
+ return {
179
+ mergedLines,
180
+ conflictedSections: [],
181
+ resolvedSections,
182
+ reason: `Fusion Markdown réussie : ${resolvedSections} section(s) fusionnée(s) automatiquement.`,
183
+ };
184
+ }
185
+ // ─── Helpers ──────────────────────────────────────────────
186
+ function emptySectionFor(key) {
187
+ return { heading: key === "__prologue__" ? null : key, level: 0, lines: [], startIdx: 0 };
188
+ }
189
+ /**
190
+ * Résout le frontmatter : simple comparaison textuelle.
191
+ * Si ours = base → prendre theirs. Si theirs = base → prendre ours.
192
+ * Si same → prendre ours. Sinon null (conflit).
193
+ */
194
+ function resolveFrontmatter(base, ours, theirs) {
195
+ if (base.length === 0 && ours.length === 0 && theirs.length === 0)
196
+ return [];
197
+ const arrEq = (a, b) => a.length === b.length && a.every((l, i) => l === b[i]);
198
+ if (arrEq(ours, theirs))
199
+ return ours;
200
+ if (arrEq(ours, base))
201
+ return theirs; // ours n'a pas changé → prendre theirs
202
+ if (arrEq(theirs, base))
203
+ return ours; // theirs n'a pas changé → prendre ours
204
+ return null; // conflit
205
+ }
206
+ /**
207
+ * Détermine l'ordre de fusion des sections en combinant les ordres de ours et theirs.
208
+ * Utilise une heuristique simple : préserver l'ordre de ours, insérer les nouvelles
209
+ * sections de theirs après leur section précédente dans theirs.
210
+ */
211
+ function buildSectionOrder(base, ours, theirs) {
212
+ const oursKeys = ours.map(sectionKey);
213
+ const theirsKeys = theirs.map(sectionKey);
214
+ const baseKeys = new Set(base.map(sectionKey));
215
+ // Sections présentes dans ours en premier
216
+ const result = [...oursKeys];
217
+ const resultSet = new Set(result);
218
+ // Ajouter les sections de theirs absentes de ours (sections ajoutées par theirs)
219
+ for (let i = 0; i < theirsKeys.length; i++) {
220
+ const key = theirsKeys[i];
221
+ if (!resultSet.has(key)) {
222
+ // Trouver la bonne position : après la section précédente dans theirs
223
+ const prevKey = i > 0 ? theirsKeys[i - 1] : null;
224
+ const insertIdx = prevKey ? result.indexOf(prevKey) + 1 : 0;
225
+ result.splice(insertIdx, 0, key);
226
+ resultSet.add(key);
227
+ }
228
+ }
229
+ // Retirer les sections supprimées des deux côtés
230
+ return result.filter((key) => {
231
+ const inOurs = oursKeys.includes(key);
232
+ const inTheirs = theirsKeys.includes(key);
233
+ const inBase = baseKeys.has(key);
234
+ // Garder si présent dans au moins une branche active
235
+ return inOurs || inTheirs || !inBase;
236
+ });
237
+ }
238
+ // ─── Bullet list merge (v1.4) ─────────────────────────────
239
+ const RE_BULLET = /^(\s*)[*-]\s/;
240
+ /**
241
+ * Vérifie si un ensemble de lignes est une liste à puces cohérente.
242
+ * Toutes les lignes non-vides doivent commencer par `- ` ou `* ` à l'indentation de base.
243
+ */
244
+ function isBulletList(lines) {
245
+ const contentLines = lines.filter((l) => l.trim() !== "");
246
+ if (contentLines.length === 0)
247
+ return false;
248
+ return contentLines.every((l) => RE_BULLET.test(l));
249
+ }
250
+ /**
251
+ * Fusionne deux listes à puces Markdown en union d'items (ours order preserved,
252
+ * items de theirs absents de ours ajoutés à la fin).
253
+ * Retourne null si les items sont en conflit irréductible (même item différent).
254
+ */
255
+ function mergeBulletLists(baseLines, oursLines, theirsLines) {
256
+ // Normaliser : retirer trailing whitespace des items
257
+ const normalize = (l) => l.trimEnd();
258
+ const oursNorm = oursLines.map(normalize);
259
+ const theirsNorm = theirsLines.map(normalize);
260
+ if (oursNorm.join("\n") === theirsNorm.join("\n"))
261
+ return oursNorm;
262
+ const baseNorm = baseLines.map(normalize);
263
+ if (oursNorm.join("\n") === baseNorm.join("\n"))
264
+ return theirsNorm;
265
+ if (theirsNorm.join("\n") === baseNorm.join("\n"))
266
+ return oursNorm;
267
+ // Union par valeur d'item (text after bullet marker)
268
+ const stripBullet = (l) => l.replace(/^\s*[*-]\s+/, "").trimEnd();
269
+ const oursSet = new Set(oursNorm.map(stripBullet));
270
+ const extra = theirsNorm.filter((l) => !oursSet.has(stripBullet(l)));
271
+ return [...oursNorm, ...extra];
272
+ }
273
+ /**
274
+ * Résout un conflit pour une section donnée.
275
+ */
276
+ function resolveSectionConflict(base, ours, theirs, key) {
277
+ const empty = emptySectionFor(key);
278
+ const b = base ?? empty;
279
+ const o = ours ?? empty;
280
+ const t = theirs ?? empty;
281
+ const toLines = (s) => {
282
+ const lines = [];
283
+ if (s.heading)
284
+ lines.push(s.heading);
285
+ lines.push(...s.lines);
286
+ return lines;
287
+ };
288
+ // Section absente de ours et de base, présente dans theirs → ajout theirs
289
+ if (!ours && !base && theirs) {
290
+ return { resolved: true, lines: toLines(t) };
291
+ }
292
+ // Section absente de theirs et de base, présente dans ours → ajout ours
293
+ if (!theirs && !base && ours) {
294
+ return { resolved: true, lines: toLines(o) };
295
+ }
296
+ // Section supprimée des deux côtés (présente dans base)
297
+ if (base && !ours && !theirs) {
298
+ return { resolved: true, lines: [] };
299
+ }
300
+ // Ours a supprimé, theirs n'a pas changé
301
+ if (base && !ours && theirs && sectionsEqual(b, t)) {
302
+ return { resolved: true, lines: [] };
303
+ }
304
+ // Theirs a supprimé, ours n'a pas changé
305
+ if (base && ours && !theirs && sectionsEqual(b, o)) {
306
+ return { resolved: true, lines: [] };
307
+ }
308
+ // Les deux ont fait la même modification
309
+ if (sectionsEqual(o, t)) {
310
+ return { resolved: true, lines: toLines(o) };
311
+ }
312
+ // Seul ours a changé (theirs = base ou theirs absent)
313
+ if (base && theirs && sectionsEqual(b, t)) {
314
+ return { resolved: true, lines: toLines(o) };
315
+ }
316
+ // Seul theirs a changé (ours = base ou ours absent)
317
+ if (base && ours && sectionsEqual(b, o)) {
318
+ return { resolved: true, lines: toLines(t) };
319
+ }
320
+ // Les deux ont changé différemment
321
+ // v1.4 — Tenter un merge bullet-list si les deux sections sont des listes à puces
322
+ if (isBulletList(o.lines) && isBulletList(t.lines)) {
323
+ const merged = mergeBulletLists(b.lines, o.lines, t.lines);
324
+ if (merged !== null) {
325
+ const resultLines = [];
326
+ if (o.heading)
327
+ resultLines.push(o.heading);
328
+ resultLines.push(...merged);
329
+ return { resolved: true, lines: resultLines };
330
+ }
331
+ }
332
+ // Conflit non résolvable
333
+ return { resolved: false, lines: [] };
334
+ }
335
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/resolvers/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * GitWand — Résolveur Vue SFC (Single File Component)
3
+ *
4
+ * Résout les conflits dans les fichiers `.vue` en reconnaissant la structure
5
+ * SFC et en traitant chaque bloc indépendamment.
6
+ *
7
+ * Structure d'un fichier Vue SFC :
8
+ * <template> - HTML du composant
9
+ * <script> - Logique (JS ou TS, avec possibles sous-blocs)
10
+ * <script setup> - Composition API
11
+ * <style> - CSS/SCSS/Less
12
+ * <style scoped> - CSS scopé
13
+ * <custom-block> - Blocs personnalisés (i18n, docs, etc.)
14
+ *
15
+ * Stratégie :
16
+ * 1. Découper chaque version en blocs SFC identifiés par leur balise ouvrante
17
+ * 2. Pour chaque bloc : appliquer la logique 3-way standard
18
+ * - Bloc non modifié → garder base
19
+ * - Seul un côté a changé → accepter le changement
20
+ * - Same change → accepter
21
+ * - Conflit réel → fallback textuel (null)
22
+ * 3. Reconstruire le fichier dans l'ordre des blocs de `ours`
23
+ * (en insérant les nouveaux blocs de `theirs` à la bonne position)
24
+ */
25
+ /**
26
+ * Un bloc SFC parsé.
27
+ */
28
+ export interface SfcBlock {
29
+ /** Tag d'ouverture complet (ex: `<template>`, `<script setup lang="ts">`) */
30
+ openTag: string;
31
+ /** Nom du bloc (ex: 'template', 'script', 'style') */
32
+ name: string;
33
+ /** Attributs bruts (ex: 'setup lang="ts"') */
34
+ attrs: string;
35
+ /** Lignes de contenu (sans le tag d'ouverture et de fermeture) */
36
+ lines: string[];
37
+ /** Tag de fermeture (ex: `</template>`) */
38
+ closeTag: string;
39
+ }
40
+ /**
41
+ * Découpe un fichier Vue SFC en blocs.
42
+ * Les lignes hors blocs reconnus (commentaires HTML, attributs en tête…)
43
+ * sont regroupées dans un bloc virtuel "preamble".
44
+ */
45
+ export declare function parseSfcBlocks(lines: string[]): SfcBlock[];
46
+ /** Résultat du merge Vue SFC */
47
+ export interface VueMergeResult {
48
+ /** Lignes fusionnées (null = conflit non résolvable) */
49
+ mergedLines: string[] | null;
50
+ /** Description de la fusion */
51
+ reason: string;
52
+ /** Blocs résolus automatiquement */
53
+ resolvedBlocks: number;
54
+ /** Blocs en conflit */
55
+ conflictedBlocks: string[];
56
+ }
57
+ /**
58
+ * Tente de résoudre un conflit Vue SFC en fusionnant bloc par bloc.
59
+ *
60
+ * @param baseLines - Lignes de la version base
61
+ * @param oursLines - Lignes de la version ours
62
+ * @param theirsLines - Lignes de la version theirs
63
+ */
64
+ export declare function tryResolveVueConflict(baseLines: string[], oursLines: string[], theirsLines: string[]): VueMergeResult;
65
+ //# sourceMappingURL=vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue.d.ts","sourceRoot":"","sources":["../../src/resolvers/vue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAUD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CA4E1D;AAID,gCAAgC;AAChC,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC7B,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB;IACvB,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AA6BD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,MAAM,EAAE,GACpB,cAAc,CA6HhB"}
@@ -0,0 +1,258 @@
1
+ /**
2
+ * GitWand — Résolveur Vue SFC (Single File Component)
3
+ *
4
+ * Résout les conflits dans les fichiers `.vue` en reconnaissant la structure
5
+ * SFC et en traitant chaque bloc indépendamment.
6
+ *
7
+ * Structure d'un fichier Vue SFC :
8
+ * <template> - HTML du composant
9
+ * <script> - Logique (JS ou TS, avec possibles sous-blocs)
10
+ * <script setup> - Composition API
11
+ * <style> - CSS/SCSS/Less
12
+ * <style scoped> - CSS scopé
13
+ * <custom-block> - Blocs personnalisés (i18n, docs, etc.)
14
+ *
15
+ * Stratégie :
16
+ * 1. Découper chaque version en blocs SFC identifiés par leur balise ouvrante
17
+ * 2. Pour chaque bloc : appliquer la logique 3-way standard
18
+ * - Bloc non modifié → garder base
19
+ * - Seul un côté a changé → accepter le changement
20
+ * - Same change → accepter
21
+ * - Conflit réel → fallback textuel (null)
22
+ * 3. Reconstruire le fichier dans l'ordre des blocs de `ours`
23
+ * (en insérant les nouveaux blocs de `theirs` à la bonne position)
24
+ */
25
+ // ─── Parser SFC ───────────────────────────────────────────
26
+ const RE_OPEN_TAG = /^<([\w-]+)((?:\s+[\w-]+(?:="[^"]*")?)*)\s*>$/;
27
+ const RE_CLOSE_TAG = /^<\/([\w-]+)>$/;
28
+ /** Tags racines reconnus comme blocs SFC (les autres sont ignorés comme texte) */
29
+ const SFC_ROOT_TAGS = new Set(["template", "script", "style"]);
30
+ /**
31
+ * Découpe un fichier Vue SFC en blocs.
32
+ * Les lignes hors blocs reconnus (commentaires HTML, attributs en tête…)
33
+ * sont regroupées dans un bloc virtuel "preamble".
34
+ */
35
+ export function parseSfcBlocks(lines) {
36
+ const blocks = [];
37
+ let i = 0;
38
+ // Lignes de préambule avant le premier bloc racine
39
+ const preamble = [];
40
+ while (i < lines.length) {
41
+ const line = lines[i];
42
+ const openMatch = line.trim().match(RE_OPEN_TAG);
43
+ if (openMatch) {
44
+ const name = openMatch[1].toLowerCase();
45
+ const attrs = openMatch[2].trim();
46
+ // Reconnaître les blocs racines SFC et les custom blocks
47
+ // On accepte tout tag au niveau racine (i18n, docs, etc.)
48
+ if (preamble.length > 0 && blocks.length === 0) {
49
+ // Sauvegarder le préambule comme bloc virtuel
50
+ blocks.push({
51
+ openTag: "",
52
+ name: "__preamble__",
53
+ attrs: "",
54
+ lines: [...preamble],
55
+ closeTag: "",
56
+ });
57
+ preamble.length = 0;
58
+ }
59
+ const closeTagStr = `</${name}>`;
60
+ const contentLines = [];
61
+ i++;
62
+ while (i < lines.length) {
63
+ const inner = lines[i];
64
+ const closeMatch = inner.trim().match(RE_CLOSE_TAG);
65
+ if (closeMatch && closeMatch[1].toLowerCase() === name) {
66
+ break;
67
+ }
68
+ contentLines.push(inner);
69
+ i++;
70
+ }
71
+ blocks.push({
72
+ openTag: line.trim(),
73
+ name,
74
+ attrs,
75
+ lines: contentLines,
76
+ closeTag: closeTagStr,
77
+ });
78
+ i++; // passer le closeTag
79
+ continue;
80
+ }
81
+ // Ligne hors bloc → préambule ou texte entre blocs
82
+ preamble.push(line);
83
+ i++;
84
+ }
85
+ // Préambule résiduel
86
+ if (preamble.length > 0) {
87
+ if (blocks.length === 0) {
88
+ blocks.push({
89
+ openTag: "",
90
+ name: "__preamble__",
91
+ attrs: "",
92
+ lines: [...preamble],
93
+ closeTag: "",
94
+ });
95
+ }
96
+ else {
97
+ // Ajouter au dernier bloc (espace avant EOF)
98
+ blocks[blocks.length - 1].lines.push(...preamble);
99
+ }
100
+ }
101
+ return blocks;
102
+ }
103
+ /**
104
+ * Clé d'identification d'un bloc : nom + attributs.
105
+ * Deux blocs avec la même clé représentent le même bloc SFC.
106
+ */
107
+ function blockKey(block) {
108
+ return `${block.name}:${block.attrs}`;
109
+ }
110
+ /**
111
+ * Compare le contenu de deux blocs pour égalité textuelle.
112
+ */
113
+ function blocksContentEqual(a, b) {
114
+ return (a.openTag === b.openTag &&
115
+ a.lines.length === b.lines.length &&
116
+ a.lines.every((l, i) => l === b.lines[i]));
117
+ }
118
+ /**
119
+ * Sérialise un bloc SFC en lignes.
120
+ */
121
+ function blockToLines(block) {
122
+ if (block.name === "__preamble__")
123
+ return [...block.lines];
124
+ return [block.openTag, ...block.lines, block.closeTag];
125
+ }
126
+ /**
127
+ * Tente de résoudre un conflit Vue SFC en fusionnant bloc par bloc.
128
+ *
129
+ * @param baseLines - Lignes de la version base
130
+ * @param oursLines - Lignes de la version ours
131
+ * @param theirsLines - Lignes de la version theirs
132
+ */
133
+ export function tryResolveVueConflict(baseLines, oursLines, theirsLines) {
134
+ const baseBlocks = parseSfcBlocks(baseLines);
135
+ const oursBlocks = parseSfcBlocks(oursLines);
136
+ const theirsBlocks = parseSfcBlocks(theirsLines);
137
+ // Indexer par clé
138
+ const baseMap = new Map(baseBlocks.map((b) => [blockKey(b), b]));
139
+ const oursMap = new Map(oursBlocks.map((b) => [blockKey(b), b]));
140
+ const theirsMap = new Map(theirsBlocks.map((b) => [blockKey(b), b]));
141
+ // Ordre : ours first, puis nouveaux blocs de theirs
142
+ const oursOrder = oursBlocks.map(blockKey);
143
+ const theirsOrder = theirsBlocks.map(blockKey);
144
+ const allKeys = [...oursOrder];
145
+ for (const k of theirsOrder) {
146
+ if (!allKeys.includes(k))
147
+ allKeys.push(k);
148
+ }
149
+ const resultLines = [];
150
+ let resolvedBlocks = 0;
151
+ const conflictedBlocks = [];
152
+ for (const key of allKeys) {
153
+ const base = baseMap.get(key);
154
+ const ours = oursMap.get(key);
155
+ const theirs = theirsMap.get(key);
156
+ // Bloc absent de base → ajout d'un côté ou des deux
157
+ if (!base) {
158
+ if (ours && theirs) {
159
+ if (blocksContentEqual(ours, theirs)) {
160
+ resultLines.push(...blockToLines(ours));
161
+ resolvedBlocks++;
162
+ }
163
+ else {
164
+ // Deux versions différentes d'un nouveau bloc → conflit
165
+ conflictedBlocks.push(key);
166
+ return {
167
+ mergedLines: null,
168
+ conflictedBlocks,
169
+ resolvedBlocks,
170
+ reason: `Conflit sur le bloc <${ours.name}> — ajouté différemment des deux côtés.`,
171
+ };
172
+ }
173
+ }
174
+ else if (ours) {
175
+ resultLines.push(...blockToLines(ours));
176
+ resolvedBlocks++;
177
+ }
178
+ else if (theirs) {
179
+ resultLines.push(...blockToLines(theirs));
180
+ resolvedBlocks++;
181
+ }
182
+ continue;
183
+ }
184
+ const oursChanged = ours ? !blocksContentEqual(base, ours) : true;
185
+ const theirsChanged = theirs ? !blocksContentEqual(base, theirs) : true;
186
+ // Suppression des deux côtés
187
+ if (!ours && !theirs) {
188
+ resolvedBlocks++;
189
+ continue;
190
+ }
191
+ // Ours supprimé
192
+ if (!ours) {
193
+ if (!theirsChanged) {
194
+ resolvedBlocks++; // theirs = base, ours supprimé → supprimer
195
+ }
196
+ else {
197
+ conflictedBlocks.push(key);
198
+ return {
199
+ mergedLines: null,
200
+ conflictedBlocks,
201
+ resolvedBlocks,
202
+ reason: `Conflit sur le bloc <${base.name}> — ours l'a supprimé, theirs l'a modifié.`,
203
+ };
204
+ }
205
+ continue;
206
+ }
207
+ // Theirs supprimé
208
+ if (!theirs) {
209
+ if (!oursChanged) {
210
+ resolvedBlocks++; // ours = base, theirs supprimé → supprimer
211
+ }
212
+ else {
213
+ conflictedBlocks.push(key);
214
+ return {
215
+ mergedLines: null,
216
+ conflictedBlocks,
217
+ resolvedBlocks,
218
+ reason: `Conflit sur le bloc <${base.name}> — theirs l'a supprimé, ours l'a modifié.`,
219
+ };
220
+ }
221
+ continue;
222
+ }
223
+ // Les deux présents
224
+ if (!oursChanged && !theirsChanged) {
225
+ resultLines.push(...blockToLines(base));
226
+ resolvedBlocks++;
227
+ }
228
+ else if (blocksContentEqual(ours, theirs)) {
229
+ resultLines.push(...blockToLines(ours));
230
+ resolvedBlocks++;
231
+ }
232
+ else if (!oursChanged) {
233
+ resultLines.push(...blockToLines(theirs));
234
+ resolvedBlocks++;
235
+ }
236
+ else if (!theirsChanged) {
237
+ resultLines.push(...blockToLines(ours));
238
+ resolvedBlocks++;
239
+ }
240
+ else {
241
+ // Les deux ont modifié le même bloc différemment → conflit
242
+ conflictedBlocks.push(key);
243
+ return {
244
+ mergedLines: null,
245
+ conflictedBlocks,
246
+ resolvedBlocks,
247
+ reason: `Conflit sur le bloc <${ours.name}> — modifié des deux côtés de façon incompatible.`,
248
+ };
249
+ }
250
+ }
251
+ return {
252
+ mergedLines: resultLines,
253
+ conflictedBlocks: [],
254
+ resolvedBlocks,
255
+ reason: `Fusion Vue SFC réussie : ${resolvedBlocks} bloc(s) fusionné(s).`,
256
+ };
257
+ }
258
+ //# sourceMappingURL=vue.js.map