@oh-my-pi/hashline 15.8.0 → 15.8.3

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/apply.ts +7 -3
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/hashline",
4
- "version": "15.8.0",
4
+ "version": "15.8.3",
5
5
  "description": "Hashline: a compact, line-anchored patch language and applier. Pluggable FS/IO so it works over disk, in-memory, or any custom backend.",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
package/src/apply.ts CHANGED
@@ -257,9 +257,13 @@ function findReplacementGroup(edits: readonly AppliedEdit[], start: number): Rep
257
257
  /**
258
258
  * Largest `k` such that the payload's last `k` lines exactly equal the `k`
259
259
  * surviving file lines just below the range AND dropping them zeroes `delta`.
260
- * Single-line drops are limited to pure structural closers.
260
+ * Requires a non-zero `delta`: a zero-balance candidate can never account for
261
+ * the imbalance, so intentional duplicates of ordinary statements stay intact,
262
+ * while duplicated structural lines (closers like `});`, openers like `foo(`)
263
+ * are dropped when they exactly explain the imbalance.
261
264
  */
262
265
  function findDuplicateSuffix(group: ReplacementGroup, fileLines: readonly string[], delta: DelimiterBalance): number {
266
+ if (balanceIsZero(delta)) return 0;
263
267
  const { payload, endLine } = group;
264
268
  const maxK = Math.min(payload.length, fileLines.length - endLine);
265
269
  for (let k = maxK; k >= 1; k--) {
@@ -271,7 +275,6 @@ function findDuplicateSuffix(group: ReplacementGroup, fileLines: readonly string
271
275
  }
272
276
  }
273
277
  if (!matches) continue;
274
- if (k === 1 && !STRUCTURAL_CLOSER_RE.test(payload[payload.length - 1])) continue;
275
278
  if (balanceEqual(computeDelimiterBalance(payload.slice(payload.length - k)), delta)) return k;
276
279
  }
277
280
  return 0;
@@ -280,8 +283,10 @@ function findDuplicateSuffix(group: ReplacementGroup, fileLines: readonly string
280
283
  /**
281
284
  * Largest `j` such that the payload's first `j` lines exactly equal the `j`
282
285
  * surviving file lines just above the range AND dropping them zeroes `delta`.
286
+ * Requires a non-zero `delta`; see {@link findDuplicateSuffix}.
283
287
  */
284
288
  function findDuplicatePrefix(group: ReplacementGroup, fileLines: readonly string[], delta: DelimiterBalance): number {
289
+ if (balanceIsZero(delta)) return 0;
285
290
  const { payload, startLine } = group;
286
291
  const maxJ = Math.min(payload.length, startLine - 1);
287
292
  for (let j = maxJ; j >= 1; j--) {
@@ -293,7 +298,6 @@ function findDuplicatePrefix(group: ReplacementGroup, fileLines: readonly string
293
298
  }
294
299
  }
295
300
  if (!matches) continue;
296
- if (j === 1 && !STRUCTURAL_CLOSER_RE.test(payload[0])) continue;
297
301
  if (balanceEqual(computeDelimiterBalance(payload.slice(0, j)), delta)) return j;
298
302
  }
299
303
  return 0;