@gitwand/core 2.2.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/dist/__tests__/corpus.d.ts.map +1 -1
  2. package/dist/__tests__/corpus.js +115 -0
  3. package/dist/__tests__/corpus.js.map +1 -1
  4. package/dist/__tests__/patterns/complex.test.d.ts +9 -0
  5. package/dist/__tests__/patterns/complex.test.d.ts.map +1 -0
  6. package/dist/__tests__/patterns/complex.test.js +198 -0
  7. package/dist/__tests__/patterns/complex.test.js.map +1 -0
  8. package/dist/__tests__/patterns/delete-no-change.test.d.ts +11 -0
  9. package/dist/__tests__/patterns/delete-no-change.test.d.ts.map +1 -0
  10. package/dist/__tests__/patterns/delete-no-change.test.js +178 -0
  11. package/dist/__tests__/patterns/delete-no-change.test.js.map +1 -0
  12. package/dist/__tests__/patterns/non-overlapping.test.d.ts +11 -0
  13. package/dist/__tests__/patterns/non-overlapping.test.d.ts.map +1 -0
  14. package/dist/__tests__/patterns/non-overlapping.test.js +240 -0
  15. package/dist/__tests__/patterns/non-overlapping.test.js.map +1 -0
  16. package/dist/__tests__/patterns/one-side-change.test.d.ts +10 -0
  17. package/dist/__tests__/patterns/one-side-change.test.d.ts.map +1 -0
  18. package/dist/__tests__/patterns/one-side-change.test.js +191 -0
  19. package/dist/__tests__/patterns/one-side-change.test.js.map +1 -0
  20. package/dist/__tests__/patterns/same-change.test.d.ts +9 -0
  21. package/dist/__tests__/patterns/same-change.test.d.ts.map +1 -0
  22. package/dist/__tests__/patterns/same-change.test.js +173 -0
  23. package/dist/__tests__/patterns/same-change.test.js.map +1 -0
  24. package/dist/__tests__/patterns/value-only-change.test.d.ts +11 -0
  25. package/dist/__tests__/patterns/value-only-change.test.d.ts.map +1 -0
  26. package/dist/__tests__/patterns/value-only-change.test.js +159 -0
  27. package/dist/__tests__/patterns/value-only-change.test.js.map +1 -0
  28. package/dist/__tests__/patterns/whitespace-only.test.d.ts +10 -0
  29. package/dist/__tests__/patterns/whitespace-only.test.d.ts.map +1 -0
  30. package/dist/__tests__/patterns/whitespace-only.test.js +177 -0
  31. package/dist/__tests__/patterns/whitespace-only.test.js.map +1 -0
  32. package/dist/__tests__/resolvers/css.test.d.ts +12 -0
  33. package/dist/__tests__/resolvers/css.test.d.ts.map +1 -0
  34. package/dist/__tests__/resolvers/css.test.js +171 -0
  35. package/dist/__tests__/resolvers/css.test.js.map +1 -0
  36. package/dist/__tests__/resolvers/imports.test.d.ts +12 -0
  37. package/dist/__tests__/resolvers/imports.test.d.ts.map +1 -0
  38. package/dist/__tests__/resolvers/imports.test.js +135 -0
  39. package/dist/__tests__/resolvers/imports.test.js.map +1 -0
  40. package/dist/__tests__/resolvers/json.test.d.ts +12 -0
  41. package/dist/__tests__/resolvers/json.test.d.ts.map +1 -0
  42. package/dist/__tests__/resolvers/json.test.js +184 -0
  43. package/dist/__tests__/resolvers/json.test.js.map +1 -0
  44. package/dist/__tests__/resolvers/lockfile-npm.test.d.ts +12 -0
  45. package/dist/__tests__/resolvers/lockfile-npm.test.d.ts.map +1 -0
  46. package/dist/__tests__/resolvers/lockfile-npm.test.js +187 -0
  47. package/dist/__tests__/resolvers/lockfile-npm.test.js.map +1 -0
  48. package/dist/__tests__/resolvers/lockfile-pnpm.test.d.ts +12 -0
  49. package/dist/__tests__/resolvers/lockfile-pnpm.test.d.ts.map +1 -0
  50. package/dist/__tests__/resolvers/lockfile-pnpm.test.js +175 -0
  51. package/dist/__tests__/resolvers/lockfile-pnpm.test.js.map +1 -0
  52. package/dist/__tests__/resolvers/lockfile-yarn.test.d.ts +12 -0
  53. package/dist/__tests__/resolvers/lockfile-yarn.test.d.ts.map +1 -0
  54. package/dist/__tests__/resolvers/lockfile-yarn.test.js +165 -0
  55. package/dist/__tests__/resolvers/lockfile-yarn.test.js.map +1 -0
  56. package/dist/__tests__/resolvers/markdown.test.d.ts +12 -0
  57. package/dist/__tests__/resolvers/markdown.test.d.ts.map +1 -0
  58. package/dist/__tests__/resolvers/markdown.test.js +188 -0
  59. package/dist/__tests__/resolvers/markdown.test.js.map +1 -0
  60. package/dist/__tests__/resolvers/vue.test.d.ts +12 -0
  61. package/dist/__tests__/resolvers/vue.test.d.ts.map +1 -0
  62. package/dist/__tests__/resolvers/vue.test.js +225 -0
  63. package/dist/__tests__/resolvers/vue.test.js.map +1 -0
  64. package/dist/__tests__/resolvers/yaml.test.d.ts +12 -0
  65. package/dist/__tests__/resolvers/yaml.test.d.ts.map +1 -0
  66. package/dist/__tests__/resolvers/yaml.test.js +203 -0
  67. package/dist/__tests__/resolvers/yaml.test.js.map +1 -0
  68. package/dist/__tests__/structural/grandeur-nature.test.d.ts +31 -0
  69. package/dist/__tests__/structural/grandeur-nature.test.d.ts.map +1 -0
  70. package/dist/__tests__/structural/grandeur-nature.test.js +264 -0
  71. package/dist/__tests__/structural/grandeur-nature.test.js.map +1 -0
  72. package/dist/__tests__/structural/languages.test.d.ts +5 -0
  73. package/dist/__tests__/structural/languages.test.d.ts.map +1 -0
  74. package/dist/__tests__/structural/languages.test.js +74 -0
  75. package/dist/__tests__/structural/languages.test.js.map +1 -0
  76. package/dist/__tests__/structural/matching.test.d.ts +6 -0
  77. package/dist/__tests__/structural/matching.test.d.ts.map +1 -0
  78. package/dist/__tests__/structural/matching.test.js +113 -0
  79. package/dist/__tests__/structural/matching.test.js.map +1 -0
  80. package/dist/__tests__/structural/merge.test.d.ts +6 -0
  81. package/dist/__tests__/structural/merge.test.d.ts.map +1 -0
  82. package/dist/__tests__/structural/merge.test.js +117 -0
  83. package/dist/__tests__/structural/merge.test.js.map +1 -0
  84. package/dist/__tests__/structural/reconstruct.test.d.ts +6 -0
  85. package/dist/__tests__/structural/reconstruct.test.d.ts.map +1 -0
  86. package/dist/__tests__/structural/reconstruct.test.js +104 -0
  87. package/dist/__tests__/structural/reconstruct.test.js.map +1 -0
  88. package/dist/__tests__/structural/structural-index.test.d.ts +14 -0
  89. package/dist/__tests__/structural/structural-index.test.d.ts.map +1 -0
  90. package/dist/__tests__/structural/structural-index.test.js +108 -0
  91. package/dist/__tests__/structural/structural-index.test.js.map +1 -0
  92. package/dist/__tests__/v2-core-scenarios.test.d.ts +35 -0
  93. package/dist/__tests__/v2-core-scenarios.test.d.ts.map +1 -0
  94. package/dist/__tests__/v2-core-scenarios.test.js +692 -0
  95. package/dist/__tests__/v2-core-scenarios.test.js.map +1 -0
  96. package/dist/__tests__/validation-parse-tree.test.d.ts +15 -0
  97. package/dist/__tests__/validation-parse-tree.test.d.ts.map +1 -0
  98. package/dist/__tests__/validation-parse-tree.test.js +243 -0
  99. package/dist/__tests__/validation-parse-tree.test.js.map +1 -0
  100. package/dist/config.d.ts +25 -0
  101. package/dist/config.d.ts.map +1 -1
  102. package/dist/config.js +17 -0
  103. package/dist/config.js.map +1 -1
  104. package/dist/diff/index.d.ts.map +1 -1
  105. package/dist/diff/index.js +1 -3
  106. package/dist/diff/index.js.map +1 -1
  107. package/dist/index.d.ts +5 -1
  108. package/dist/index.d.ts.map +1 -1
  109. package/dist/index.js +5 -1
  110. package/dist/index.js.map +1 -1
  111. package/dist/patterns/utils.d.ts +8 -7
  112. package/dist/patterns/utils.d.ts.map +1 -1
  113. package/dist/patterns/utils.js +13 -12
  114. package/dist/patterns/utils.js.map +1 -1
  115. package/dist/resolver/adapters/strict-node.d.ts +32 -0
  116. package/dist/resolver/adapters/strict-node.d.ts.map +1 -0
  117. package/dist/resolver/adapters/strict-node.js +117 -0
  118. package/dist/resolver/adapters/strict-node.js.map +1 -0
  119. package/dist/resolver/index.d.ts +33 -0
  120. package/dist/resolver/index.d.ts.map +1 -1
  121. package/dist/resolver/index.js +113 -0
  122. package/dist/resolver/index.js.map +1 -1
  123. package/dist/resolver/policy.d.ts.map +1 -1
  124. package/dist/resolver/policy.js +3 -0
  125. package/dist/resolver/policy.js.map +1 -1
  126. package/dist/resolver/validate-parse-tree.d.ts +52 -0
  127. package/dist/resolver/validate-parse-tree.d.ts.map +1 -0
  128. package/dist/resolver/validate-parse-tree.js +87 -0
  129. package/dist/resolver/validate-parse-tree.js.map +1 -0
  130. package/dist/resolver/validate-strict.d.ts +27 -0
  131. package/dist/resolver/validate-strict.d.ts.map +1 -0
  132. package/dist/resolver/validate-strict.js +41 -0
  133. package/dist/resolver/validate-strict.js.map +1 -0
  134. package/dist/resolver/validation.d.ts.map +1 -1
  135. package/dist/resolver/validation.js +15 -1
  136. package/dist/resolver/validation.js.map +1 -1
  137. package/dist/resolvers/dispatcher.d.ts +17 -1
  138. package/dist/resolvers/dispatcher.d.ts.map +1 -1
  139. package/dist/resolvers/dispatcher.js.map +1 -1
  140. package/dist/structural/entities.d.ts +44 -0
  141. package/dist/structural/entities.d.ts.map +1 -0
  142. package/dist/structural/entities.js +315 -0
  143. package/dist/structural/entities.js.map +1 -0
  144. package/dist/structural/index.d.ts +48 -0
  145. package/dist/structural/index.d.ts.map +1 -0
  146. package/dist/structural/index.js +177 -0
  147. package/dist/structural/index.js.map +1 -0
  148. package/dist/structural/matching.d.ts +46 -0
  149. package/dist/structural/matching.d.ts.map +1 -0
  150. package/dist/structural/matching.js +83 -0
  151. package/dist/structural/matching.js.map +1 -0
  152. package/dist/structural/merge.d.ts +45 -0
  153. package/dist/structural/merge.d.ts.map +1 -0
  154. package/dist/structural/merge.js +127 -0
  155. package/dist/structural/merge.js.map +1 -0
  156. package/dist/structural/parsers/adapters/browser.d.ts +22 -0
  157. package/dist/structural/parsers/adapters/browser.d.ts.map +1 -0
  158. package/dist/structural/parsers/adapters/browser.js +27 -0
  159. package/dist/structural/parsers/adapters/browser.js.map +1 -0
  160. package/dist/structural/parsers/adapters/node.d.ts +18 -0
  161. package/dist/structural/parsers/adapters/node.d.ts.map +1 -0
  162. package/dist/structural/parsers/adapters/node.js +42 -0
  163. package/dist/structural/parsers/adapters/node.js.map +1 -0
  164. package/dist/structural/parsers/adapters/tauri.d.ts +26 -0
  165. package/dist/structural/parsers/adapters/tauri.d.ts.map +1 -0
  166. package/dist/structural/parsers/adapters/tauri.js +34 -0
  167. package/dist/structural/parsers/adapters/tauri.js.map +1 -0
  168. package/dist/structural/parsers/grammars/languages.d.ts +32 -0
  169. package/dist/structural/parsers/grammars/languages.d.ts.map +1 -0
  170. package/dist/structural/parsers/grammars/languages.js +73 -0
  171. package/dist/structural/parsers/grammars/languages.js.map +1 -0
  172. package/dist/structural/parsers/grammars/ts.d.ts +26 -0
  173. package/dist/structural/parsers/grammars/ts.d.ts.map +1 -0
  174. package/dist/structural/parsers/grammars/ts.js +46 -0
  175. package/dist/structural/parsers/grammars/ts.js.map +1 -0
  176. package/dist/structural/parsers/loader.d.ts +74 -0
  177. package/dist/structural/parsers/loader.d.ts.map +1 -0
  178. package/dist/structural/parsers/loader.js +181 -0
  179. package/dist/structural/parsers/loader.js.map +1 -0
  180. package/dist/structural/reconstruct.d.ts +28 -0
  181. package/dist/structural/reconstruct.d.ts.map +1 -0
  182. package/dist/structural/reconstruct.js +63 -0
  183. package/dist/structural/reconstruct.js.map +1 -0
  184. package/dist/types.d.ts +60 -3
  185. package/dist/types.d.ts.map +1 -1
  186. package/package.json +16 -2
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Integration tests — "grandeur nature"
3
+ *
4
+ * These tests use content derived from the `_tmp_split_scenario` sub-repo
5
+ * (a tiny calculator module with a linear commit history) to produce
6
+ * realistic 3-way merge conflicts and run the full `resolveAsync` pipeline
7
+ * including the structural merge engine (tree-sitter / WASM).
8
+ *
9
+ * Source versions used (from _tmp_split_scenario git history):
10
+ * - test-branch-from-ctx : add()
11
+ * - split-base : add() + subtract()
12
+ * - main : add/subtract/multiply/divide/modulo
13
+ *
14
+ * Four scenarios:
15
+ * S1 — two-branches-grow-independently : both sides add different functions
16
+ * → structural merge should resolve cleanly
17
+ * S2 — ours-only-change : ours modifies + adds, theirs unchanged
18
+ * → structural merge should resolve cleanly
19
+ * S3 — body-conflict : both sides change the same function body
20
+ * → structural merge returns null, hunk-based resolver takes over
21
+ * S4 — delete-vs-modify : ours deletes a function, theirs modifies it
22
+ * → structural merge returns null, hunk-based resolver cannot resolve either
23
+ *
24
+ * The tests are designed to be non-flaky:
25
+ * • If web-tree-sitter / tree-sitter-wasms are available (devDeps in this
26
+ * package), the structural path is exercised and assertions are strict.
27
+ * • If WASM loading fails (CI without optional deps), `resolveAsync` falls
28
+ * back transparently and the tests still verify the hunk-based fallback.
29
+ */
30
+ import { describe, it, expect, beforeAll } from "vitest";
31
+ import { resolveAsync } from "../../resolver/index.js";
32
+ import { tryStructuralMergeResolve } from "../../structural/index.js";
33
+ import { _resetCache } from "../../structural/parsers/loader.js";
34
+ // Reset WASM cache once before the suite so every run starts clean.
35
+ beforeAll(() => {
36
+ _resetCache();
37
+ });
38
+ // ─────────────────────────────────────────────────────────────────────────────
39
+ // Helpers
40
+ // ─────────────────────────────────────────────────────────────────────────────
41
+ /** Build a diff3-format conflict string from three source versions. */
42
+ function makeConflict(ours, base, theirs) {
43
+ const parts = [];
44
+ parts.push(`<<<<<<< ours\n${ours}`);
45
+ parts.push(`||||||| base\n${base}`);
46
+ parts.push(`=======\n${theirs}`);
47
+ parts.push(`>>>>>>> theirs`);
48
+ return parts.join("\n") + "\n";
49
+ }
50
+ // ─────────────────────────────────────────────────────────────────────────────
51
+ // Shared source fragments (extracted from _tmp_split_scenario git history)
52
+ // ─────────────────────────────────────────────────────────────────────────────
53
+ const HEADER = `// Tiny calculator module — educational demo\n`;
54
+ const FN_ADD = `export function add(a, b) {
55
+ return a + b;
56
+ }`;
57
+ const FN_ADD_WITH_LOG = `export function add(a, b) {
58
+ console.log(\`add(\${a}, \${b})\`);
59
+ return a + b;
60
+ }`;
61
+ const FN_ADD_WITH_VALIDATION = `export function add(a, b) {
62
+ if (!Number.isFinite(a) || !Number.isFinite(b)) {
63
+ throw new RangeError("add: arguments must be finite");
64
+ }
65
+ return a + b;
66
+ }`;
67
+ const FN_SUBTRACT = `export function subtract(a, b) {
68
+ return a - b;
69
+ }`;
70
+ const FN_SUBTRACT_GUARDED = `export function subtract(a, b) {
71
+ if (b === undefined) throw new TypeError("subtract requires two arguments");
72
+ return a - b;
73
+ }`;
74
+ const FN_MULTIPLY = `export function multiply(a, b) {
75
+ return a * b;
76
+ }`;
77
+ const FN_DIVIDE = `export function divide(a, b) {
78
+ if (b === 0) {
79
+ throw new Error("division by zero");
80
+ }
81
+ return a / b;
82
+ }`;
83
+ const FN_MODULO = `export function modulo(a, b) {
84
+ if (b === 0) {
85
+ throw new Error("modulo by zero");
86
+ }
87
+ return a % b;
88
+ }`;
89
+ // S3 variants — both sides REPLACE the same return line with different content.
90
+ // These are genuine line-level conflicts (not pure insertions) that neither
91
+ // structural nor hunk-based resolver can auto-merge.
92
+ const FN_ADD_RETURN_PARENS = `export function add(a, b) {
93
+ return (a + b);
94
+ }`;
95
+ const FN_ADD_RETURN_FALLBACK = `export function add(a, b) {
96
+ return a + b || 0;
97
+ }`;
98
+ // ─────────────────────────────────────────────────────────────────────────────
99
+ // S1 — Two branches grow independently
100
+ // Base: add()
101
+ // Ours: add() + subtract() + multiply()
102
+ // Theirs: add() + divide() + modulo()
103
+ // ─────────────────────────────────────────────────────────────────────────────
104
+ describe("S1 — two-branches-grow-independently (calculator.js)", () => {
105
+ // Both branches branched from the "add only" state and each added their own
106
+ // functions. Git produces one big conflict block after the shared `add`.
107
+ const BASE = FN_ADD;
108
+ const OURS = [FN_ADD, FN_SUBTRACT, FN_MULTIPLY].join("\n\n");
109
+ const THEIRS = [FN_ADD, FN_DIVIDE, FN_MODULO].join("\n\n");
110
+ // Conflict: the preamble (header + add) is identical; everything after is conflicted.
111
+ const CONFLICT = HEADER + FN_ADD + "\n\n" + makeConflict([FN_SUBTRACT, FN_MULTIPLY].join("\n\n") + "\n", "", [FN_DIVIDE, FN_MODULO].join("\n\n") + "\n");
112
+ it("resolveAsync resolves the file cleanly (requires WASM)", async () => {
113
+ // S1 has two independent insertion blocks at the same base boundary.
114
+ // The hunk-based resolver correctly flags this as ambiguous (it cannot
115
+ // decide the interleaving order without AST context). Structural merge
116
+ // resolves it correctly — but only when WASM is available.
117
+ // Gate: skip strict assertion when structural merge is not available.
118
+ const structuralAvailable = (await tryStructuralMergeResolve(CONFLICT, "calculator.js")) !== null;
119
+ if (!structuralAvailable)
120
+ return; // WASM not available in this environment
121
+ const result = await resolveAsync(CONFLICT, "calculator.js");
122
+ expect(result.stats.remaining).toBe(0);
123
+ expect(result.mergedContent).toBeTruthy();
124
+ });
125
+ it("merged content contains all five functions (when WASM available)", async () => {
126
+ const result = await resolveAsync(CONFLICT, "calculator.js");
127
+ if (!result.mergedContent)
128
+ return; // structural WASM unavailable, hunk-based left a conflict
129
+ expect(result.mergedContent).toContain("function add");
130
+ expect(result.mergedContent).toContain("function subtract");
131
+ expect(result.mergedContent).toContain("function multiply");
132
+ expect(result.mergedContent).toContain("function divide");
133
+ expect(result.mergedContent).toContain("function modulo");
134
+ });
135
+ it("structural merge specifically resolves it (when WASM available)", async () => {
136
+ const merged = await tryStructuralMergeResolve(CONFLICT, "calculator.js");
137
+ if (merged === null) {
138
+ // WASM not available in this environment — skip strict assertion
139
+ return;
140
+ }
141
+ expect(merged).toContain("function subtract");
142
+ expect(merged).toContain("function multiply");
143
+ expect(merged).toContain("function divide");
144
+ expect(merged).toContain("function modulo");
145
+ // No conflict markers left
146
+ expect(merged).not.toContain("<<<<<<<");
147
+ expect(merged).not.toContain("=======");
148
+ expect(merged).not.toContain(">>>>>>>");
149
+ });
150
+ it("tryStructuralMergeResolve never throws", async () => {
151
+ await expect(tryStructuralMergeResolve(CONFLICT, "calculator.js")).resolves.not.toThrow();
152
+ });
153
+ });
154
+ // ─────────────────────────────────────────────────────────────────────────────
155
+ // S2 — Ours modifies a function + adds another; theirs unchanged
156
+ // Base: add() + subtract()
157
+ // Ours: modified add (with comment) + subtract + new multiply
158
+ // Theirs: add() + subtract() (unchanged)
159
+ // ─────────────────────────────────────────────────────────────────────────────
160
+ describe("S2 — ours-only-change + ours-added (calculator.js)", () => {
161
+ const FN_ADD_COMMENTED = `// Adds two numbers and returns the result
162
+ ${FN_ADD}`;
163
+ const BASE_CONTENT = [FN_ADD, FN_SUBTRACT].join("\n\n");
164
+ const OURS_CONTENT = [FN_ADD_COMMENTED, FN_SUBTRACT, FN_MULTIPLY].join("\n\n");
165
+ const THEIRS_CONTENT = BASE_CONTENT;
166
+ const CONFLICT = HEADER + makeConflict(OURS_CONTENT + "\n", BASE_CONTENT + "\n", THEIRS_CONTENT + "\n");
167
+ it("resolveAsync resolves the file cleanly", async () => {
168
+ const result = await resolveAsync(CONFLICT, "calculator.js");
169
+ expect(result.stats.remaining).toBe(0);
170
+ expect(result.mergedContent).toBeTruthy();
171
+ });
172
+ it("merged content preserves the ours-only changes", async () => {
173
+ const result = await resolveAsync(CONFLICT, "calculator.js");
174
+ if (!result.mergedContent)
175
+ return;
176
+ // The ours comment and multiply should be present
177
+ expect(result.mergedContent).toContain("function multiply");
178
+ });
179
+ it("tryStructuralMergeResolve: merged output has multiply (when WASM available)", async () => {
180
+ const merged = await tryStructuralMergeResolve(CONFLICT, "calculator.js");
181
+ if (merged === null)
182
+ return; // WASM unavailable
183
+ expect(merged).toContain("function multiply");
184
+ expect(merged).toContain("function subtract");
185
+ expect(merged).not.toContain("<<<<<<<");
186
+ });
187
+ });
188
+ // ─────────────────────────────────────────────────────────────────────────────
189
+ // S3 — Both branches modify the same line of the function body → true conflict
190
+ // Base: add() returning `a + b`
191
+ // Ours: add() returning `(a + b)` — wraps in parens
192
+ // Theirs: add() returning `a + b || 0` — adds a fallback
193
+ //
194
+ // Both sides REPLACE the `return a + b;` line with a different version.
195
+ // There are no pure insertions — both have a removal+add on the same base line.
196
+ // Neither insertion_at_boundary nor non_overlapping can fire, so this remains
197
+ // an unresolvable conflict for the hunk-based resolver too.
198
+ // ─────────────────────────────────────────────────────────────────────────────
199
+ describe("S3 — body-conflict: both sides change the same function (calculator.js)", () => {
200
+ const CONFLICT = makeConflict(FN_ADD_RETURN_PARENS + "\n", FN_ADD + "\n", FN_ADD_RETURN_FALLBACK + "\n");
201
+ it("tryStructuralMergeResolve returns null — cannot auto-resolve", async () => {
202
+ const merged = await tryStructuralMergeResolve(CONFLICT, "calculator.js");
203
+ // Structural merge must not silently pick a side when both changed differently
204
+ expect(merged).toBeNull();
205
+ });
206
+ it("resolveAsync fallback result has remaining conflicts", async () => {
207
+ const result = await resolveAsync(CONFLICT, "calculator.js");
208
+ // Hunk-based resolver also cannot resolve this (both sides differ)
209
+ expect(result.stats.remaining).toBeGreaterThan(0);
210
+ expect(result.mergedContent).toBeNull();
211
+ });
212
+ it("resolveAsync never throws", async () => {
213
+ await expect(resolveAsync(CONFLICT, "calculator.js")).resolves.not.toThrow();
214
+ });
215
+ });
216
+ // ─────────────────────────────────────────────────────────────────────────────
217
+ // S4 — Ours deletes a function that theirs modifies → conflict
218
+ // Base: add() + subtract()
219
+ // Ours: add() only (subtract removed)
220
+ // Theirs: add() + subtract() with a guard
221
+ // ─────────────────────────────────────────────────────────────────────────────
222
+ describe("S4 — delete-vs-modify: ours deletes what theirs modifies (calculator.js)", () => {
223
+ const BASE_CONTENT = [FN_ADD, FN_SUBTRACT].join("\n\n");
224
+ const OURS_CONTENT = FN_ADD;
225
+ const THEIRS_CONTENT = [FN_ADD, FN_SUBTRACT_GUARDED].join("\n\n");
226
+ // Git produces a conflict covering the subtract block (ours deleted it, theirs changed it)
227
+ const CONFLICT = HEADER +
228
+ FN_ADD + "\n" +
229
+ makeConflict("\n", // ours: nothing after add
230
+ "\n" + FN_SUBTRACT + "\n", // base: subtract was here
231
+ "\n" + FN_SUBTRACT_GUARDED + "\n");
232
+ it("tryStructuralMergeResolve returns null — delete vs modify is a conflict", async () => {
233
+ const merged = await tryStructuralMergeResolve(CONFLICT, "calculator.js");
234
+ expect(merged).toBeNull();
235
+ });
236
+ it("resolveAsync fallback result has remaining conflicts", async () => {
237
+ const result = await resolveAsync(CONFLICT, "calculator.js");
238
+ // Neither resolver can auto-merge a delete vs a change
239
+ expect(result.stats.remaining).toBeGreaterThan(0);
240
+ expect(result.mergedContent).toBeNull();
241
+ });
242
+ it("resolveAsync never throws", async () => {
243
+ await expect(resolveAsync(CONFLICT, "calculator.js")).resolves.not.toThrow();
244
+ });
245
+ });
246
+ // ─────────────────────────────────────────────────────────────────────────────
247
+ // S5 — Unsupported language: same scenarios on a .css file
248
+ // Structural merge is disabled for .css — falls through to hunk-based resolver
249
+ // ─────────────────────────────────────────────────────────────────────────────
250
+ describe("S5 — unsupported language: structural merge skipped for .css files", () => {
251
+ const CSS_CONFLICT = makeConflict(".btn { color: red; }\n", ".btn { color: blue; }\n", ".btn { color: green; }\n");
252
+ it("tryStructuralMergeResolve returns null immediately for .css", async () => {
253
+ const merged = await tryStructuralMergeResolve(CSS_CONFLICT, "styles.css");
254
+ expect(merged).toBeNull();
255
+ });
256
+ it("resolveAsync falls back to hunk-based for .css", async () => {
257
+ const result = await resolveAsync(CSS_CONFLICT, "styles.css");
258
+ // Hunk-based: both sides changed differently → still a conflict
259
+ expect(result.stats.totalConflicts).toBe(1);
260
+ // structural merge is skipped for .css — resolution reason must not mention it
261
+ expect(result.resolutions[0]?.resolutionReason).not.toContain("structural");
262
+ });
263
+ });
264
+ //# sourceMappingURL=grandeur-nature.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grandeur-nature.test.js","sourceRoot":"","sources":["../../../src/__tests__/structural/grandeur-nature.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for structural/parsers/grammars/languages.ts
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=languages.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"languages.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/structural/languages.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Tests for structural/parsers/grammars/languages.ts
3
+ */
4
+ import { describe, it, expect } from "vitest";
5
+ import { languageForFile, isStructuralLanguage, grammarNameForFile, } from "../../structural/parsers/grammars/languages.js";
6
+ describe("languageForFile", () => {
7
+ it.each([
8
+ ["src/app.ts", "typescript"],
9
+ ["src/Component.tsx", "tsx"],
10
+ ["src/index.js", "javascript"],
11
+ ["src/utils.mjs", "javascript"],
12
+ ["lib/helper.cjs", "javascript"],
13
+ ["src/App.jsx", "jsx"],
14
+ ["src/main.py", "python"],
15
+ ["cmd/server.go", "go"],
16
+ ["src/lib.rs", "rust"],
17
+ ])("%s → %s", (path, lang) => {
18
+ expect(languageForFile(path)).toBe(lang);
19
+ });
20
+ it("returns null for unsupported extensions", () => {
21
+ expect(languageForFile("styles.css")).toBeNull();
22
+ expect(languageForFile("config.yaml")).toBeNull();
23
+ expect(languageForFile("README.md")).toBeNull();
24
+ });
25
+ });
26
+ describe("isStructuralLanguage", () => {
27
+ it("returns true for supported languages", () => {
28
+ expect(isStructuralLanguage("src/app.ts")).toBe(true);
29
+ expect(isStructuralLanguage("src/app.tsx")).toBe(true);
30
+ expect(isStructuralLanguage("src/app.js")).toBe(true);
31
+ expect(isStructuralLanguage("src/app.jsx")).toBe(true);
32
+ expect(isStructuralLanguage("src/app.py")).toBe(true);
33
+ expect(isStructuralLanguage("src/app.go")).toBe(true);
34
+ expect(isStructuralLanguage("src/app.rs")).toBe(true);
35
+ });
36
+ it("returns false for .d.ts (declaration files)", () => {
37
+ expect(isStructuralLanguage("src/types.d.ts")).toBe(false);
38
+ expect(isStructuralLanguage("dist/index.d.ts")).toBe(false);
39
+ });
40
+ it("returns false for unsupported extensions", () => {
41
+ expect(isStructuralLanguage("styles.css")).toBe(false);
42
+ expect(isStructuralLanguage("config.json")).toBe(false);
43
+ });
44
+ });
45
+ describe("grammarNameForFile", () => {
46
+ it("returns tree-sitter-typescript for .ts", () => {
47
+ expect(grammarNameForFile("src/app.ts")).toBe("tree-sitter-typescript");
48
+ });
49
+ it("returns tree-sitter-tsx for .tsx", () => {
50
+ expect(grammarNameForFile("src/app.tsx")).toBe("tree-sitter-tsx");
51
+ });
52
+ it("returns tree-sitter-javascript for .js and .jsx", () => {
53
+ expect(grammarNameForFile("src/app.js")).toBe("tree-sitter-javascript");
54
+ expect(grammarNameForFile("src/App.jsx")).toBe("tree-sitter-javascript");
55
+ });
56
+ it("returns tree-sitter-python for .py", () => {
57
+ expect(grammarNameForFile("main.py")).toBe("tree-sitter-python");
58
+ });
59
+ it("returns tree-sitter-go for .go", () => {
60
+ expect(grammarNameForFile("server.go")).toBe("tree-sitter-go");
61
+ });
62
+ it("returns tree-sitter-rust for .rs", () => {
63
+ expect(grammarNameForFile("lib.rs")).toBe("tree-sitter-rust");
64
+ });
65
+ it("returns null for unsupported extensions", () => {
66
+ expect(grammarNameForFile("style.css")).toBeNull();
67
+ expect(grammarNameForFile("config.yaml")).toBeNull();
68
+ });
69
+ it("still returns grammar name for .d.ts (exclusion is in isStructuralLanguage, not here)", () => {
70
+ // grammarNameForFile only maps extension → grammar; the .d.ts guard is in isStructuralLanguage
71
+ expect(grammarNameForFile("types.d.ts")).toBe("tree-sitter-typescript");
72
+ });
73
+ });
74
+ //# sourceMappingURL=languages.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"languages.test.js","sourceRoot":"","sources":["../../../src/__tests__/structural/languages.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests for structural/matching.ts — 3-way entity matching.
3
+ * Pure logic, no tree-sitter / WASM dependency.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=matching.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matching.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/structural/matching.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Tests for structural/matching.ts — 3-way entity matching.
3
+ * Pure logic, no tree-sitter / WASM dependency.
4
+ */
5
+ import { describe, it, expect } from "vitest";
6
+ import { matchEntities } from "../../structural/matching.js";
7
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
8
+ function entity(sig, text) {
9
+ return {
10
+ signature: sig,
11
+ kind: "function",
12
+ text,
13
+ startByte: 0,
14
+ endByte: text.length,
15
+ startLine: 0,
16
+ };
17
+ }
18
+ // ─── Tests ────────────────────────────────────────────────────────────────────
19
+ describe("matchEntities", () => {
20
+ it("marks entities identical in all three versions as unchanged", () => {
21
+ const e = entity("function:foo", "function foo() {}");
22
+ const matches = matchEntities([e], [e], [e]);
23
+ expect(matches).toHaveLength(1);
24
+ expect(matches[0].status).toBe("unchanged");
25
+ });
26
+ it("detects ours-only-change", () => {
27
+ const base = entity("function:foo", "function foo() {}");
28
+ const ours = entity("function:foo", "function foo() { return 1; }");
29
+ const theirs = entity("function:foo", "function foo() {}");
30
+ const [m] = matchEntities([base], [ours], [theirs]);
31
+ expect(m.status).toBe("ours-only-change");
32
+ expect(m.ours?.text).toBe(ours.text);
33
+ });
34
+ it("detects theirs-only-change", () => {
35
+ const base = entity("function:foo", "function foo() {}");
36
+ const ours = entity("function:foo", "function foo() {}");
37
+ const theirs = entity("function:foo", "function foo() { return 2; }");
38
+ const [m] = matchEntities([base], [ours], [theirs]);
39
+ expect(m.status).toBe("theirs-only-change");
40
+ });
41
+ it("detects both-changed-same when text is identical", () => {
42
+ const base = entity("function:foo", "function foo() {}");
43
+ const changed = entity("function:foo", "function foo() { /* same */ }");
44
+ const [m] = matchEntities([base], [changed], [changed]);
45
+ expect(m.status).toBe("both-changed-same");
46
+ });
47
+ it("detects both-changed-diff", () => {
48
+ const base = entity("function:foo", "function foo() {}");
49
+ const ours = entity("function:foo", "function foo() { return 1; }");
50
+ const theirs = entity("function:foo", "function foo() { return 2; }");
51
+ const [m] = matchEntities([base], [ours], [theirs]);
52
+ expect(m.status).toBe("both-changed-diff");
53
+ });
54
+ it("detects ours-added (entity not in base or theirs)", () => {
55
+ const e = entity("function:bar", "function bar() {}");
56
+ const matches = matchEntities([], [e], []);
57
+ expect(matches[0].status).toBe("ours-added");
58
+ });
59
+ it("detects theirs-added (entity not in base or ours)", () => {
60
+ const e = entity("function:bar", "function bar() {}");
61
+ const matches = matchEntities([], [], [e]);
62
+ expect(matches[0].status).toBe("theirs-added");
63
+ });
64
+ it("detects ours-deleted", () => {
65
+ const base = entity("function:foo", "function foo() {}");
66
+ const theirs = entity("function:foo", "function foo() {}");
67
+ const [m] = matchEntities([base], [], [theirs]);
68
+ expect(m.status).toBe("ours-deleted");
69
+ });
70
+ it("detects theirs-deleted", () => {
71
+ const base = entity("function:foo", "function foo() {}");
72
+ const ours = entity("function:foo", "function foo() {}");
73
+ const [m] = matchEntities([base], [ours], []);
74
+ expect(m.status).toBe("theirs-deleted");
75
+ });
76
+ it("handles multiple entities with different statuses", () => {
77
+ const unchanged = entity("function:unchanged", "function unchanged() {}");
78
+ const oursAdded = entity("function:oursAdded", "function oursAdded() {}");
79
+ const theirsAdded = entity("function:theirsAdded", "function theirsAdded() {}");
80
+ const base = entity("function:deleted", "function deleted() {}");
81
+ const matches = matchEntities([unchanged, base], [unchanged, oursAdded], [unchanged, theirsAdded]);
82
+ const byName = Object.fromEntries(matches.map((m) => [m.signature, m.status]));
83
+ expect(byName["function:unchanged"]).toBe("unchanged");
84
+ expect(byName["function:oursAdded"]).toBe("ours-added");
85
+ expect(byName["function:theirsAdded"]).toBe("theirs-added");
86
+ // "deleted" is in base but absent from both ours and theirs → both agreed to delete it
87
+ expect(byName["function:deleted"]).toBe("both-changed-same");
88
+ });
89
+ it("preserves base+ours order with new signatures appended", () => {
90
+ const a = entity("function:a", "function a() {}");
91
+ const b = entity("function:b", "function b() {}");
92
+ const c = entity("function:c", "function c() {}"); // only in theirs
93
+ const matches = matchEntities([a, b], [a, b], [a, b, c]);
94
+ expect(matches.map((m) => m.signature)).toEqual(["function:a", "function:b", "function:c"]);
95
+ });
96
+ it("both-deleted → both-changed-same", () => {
97
+ const base = entity("function:foo", "function foo() {}");
98
+ const [m] = matchEntities([base], [], []);
99
+ expect(m.status).toBe("both-changed-same");
100
+ });
101
+ it("both added with same text → both-changed-same", () => {
102
+ const e = entity("function:new", "function new() {}");
103
+ const [m] = matchEntities([], [e], [e]);
104
+ expect(m.status).toBe("both-changed-same");
105
+ });
106
+ it("both added with different text → both-changed-diff", () => {
107
+ const ours = entity("function:new", "function new() { return 1; }");
108
+ const theirs = entity("function:new", "function new() { return 2; }");
109
+ const [m] = matchEntities([], [ours], [theirs]);
110
+ expect(m.status).toBe("both-changed-diff");
111
+ });
112
+ });
113
+ //# sourceMappingURL=matching.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matching.test.js","sourceRoot":"","sources":["../../../src/__tests__/structural/matching.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests for structural/merge.ts — entity-level merge decisions.
3
+ * Pure logic, no tree-sitter / WASM dependency.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=merge.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/structural/merge.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}