Merge pull request #2086 from code-yeongyu/refactor/hashline-legacy-cleanup

refactor(hashline-edit): clean up legacy code and dead exports
This commit is contained in:
YeonGyu-Kim
2026-02-24 15:44:32 +09:00
committed by GitHub
7 changed files with 7 additions and 123 deletions

View File

@@ -7,5 +7,4 @@ export const HASHLINE_DICT = Array.from({ length: 256 }, (_, i) => {
})
export const HASHLINE_REF_PATTERN = /^([0-9]+)#([ZPMQVRWSNKTXJBYH]{2})$/
export const HASHLINE_OUTPUT_PATTERN = /^([0-9]+)#([ZPMQVRWSNKTXJBYH]{2}):(.*)$/
export const HASHLINE_LEGACY_REF_PATTERN = /^([0-9]+):([0-9a-fA-F]{2,})$/
export const HASHLINE_OUTPUT_PATTERN = /^([0-9]+)#([ZPMQVRWSNKTXJBYH]{2})\|(.*)$/

View File

@@ -80,7 +80,7 @@ export function applyInsertAfter(
const result = [...lines]
const newLines = stripInsertAnchorEcho(lines[line - 1], toNewLines(text))
if (newLines.length === 0) {
throw new Error(`insert_after requires non-empty text for ${anchor}`)
throw new Error(`append (anchored) requires non-empty text for ${anchor}`)
}
result.splice(line, 0, ...newLines)
return result
@@ -97,38 +97,12 @@ export function applyInsertBefore(
const result = [...lines]
const newLines = stripInsertBeforeEcho(lines[line - 1], toNewLines(text))
if (newLines.length === 0) {
throw new Error(`insert_before requires non-empty text for ${anchor}`)
throw new Error(`prepend (anchored) requires non-empty text for ${anchor}`)
}
result.splice(line - 1, 0, ...newLines)
return result
}
export function applyInsertBetween(
lines: string[],
afterAnchor: string,
beforeAnchor: string,
text: string | string[],
options?: EditApplyOptions
): string[] {
if (shouldValidate(options)) {
validateLineRef(lines, afterAnchor)
validateLineRef(lines, beforeAnchor)
}
const { line: afterLine } = parseLineRef(afterAnchor)
const { line: beforeLine } = parseLineRef(beforeAnchor)
if (beforeLine <= afterLine) {
throw new Error(`insert_between requires after_line (${afterLine}) < before_line (${beforeLine})`)
}
const result = [...lines]
const newLines = stripInsertBoundaryEcho(lines[afterLine - 1], lines[beforeLine - 1], toNewLines(text))
if (newLines.length === 0) {
throw new Error(`insert_between requires non-empty text for ${afterAnchor}..${beforeAnchor}`)
}
result.splice(beforeLine - 1, 0, ...newLines)
return result
}
export function applyAppend(lines: string[], text: string | string[]): string[] {
const normalized = toNewLines(text)
if (normalized.length === 0) {

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from "bun:test"
import { applyHashlineEdits, applyInsertAfter, applyReplaceLines, applySetLine } from "./edit-operations"
import { applyAppend, applyInsertBetween, applyPrepend } from "./edit-operation-primitives"
import { applyHashlineEdits } from "./edit-operations"
import { applyAppend, applyInsertAfter, applyPrepend, applyReplaceLines, applySetLine } from "./edit-operation-primitives"
import { computeLineHash } from "./hash-computation"
import type { HashlineEdit } from "./types"
@@ -56,16 +56,6 @@ describe("hashline edit operations", () => {
expect(result).toEqual("line 1\nbefore 2\nline 2\nline 3")
})
it("applies insert_between with dual anchors", () => {
//#given
const lines = ["line 1", "line 2", "line 3"]
//#when
const result = applyInsertBetween(lines, anchorFor(lines, 1), anchorFor(lines, 2), ["between"]).join("\n")
//#then
expect(result).toEqual("line 1\nbetween\nline 2\nline 3")
})
it("throws when insert_after receives empty text array", () => {
//#given
@@ -85,13 +75,6 @@ describe("hashline edit operations", () => {
).toThrow(/non-empty/i)
})
it("throws when insert_between receives empty text array", () => {
//#given
const lines = ["line 1", "line 2"]
//#when / #then
expect(() => applyInsertBetween(lines, anchorFor(lines, 1), anchorFor(lines, 2), [])).toThrow(/non-empty/i)
})
it("applies mixed edits in one pass", () => {
//#given
@@ -215,15 +198,6 @@ describe("hashline edit operations", () => {
expect(result).toEqual(["before", "new 1", "new 2", "after"])
})
it("throws when insert_between payload contains only boundary echoes", () => {
//#given
const lines = ["line 1", "line 2", "line 3"]
//#when / #then
expect(() => applyInsertBetween(lines, anchorFor(lines, 1), anchorFor(lines, 2), ["line 1", "line 2"])).toThrow(
/non-empty/i
)
})
it("restores indentation for first replace_lines entry", () => {
//#given

View File

@@ -88,9 +88,3 @@ export function applyHashlineEdits(content: string, edits: HashlineEdit[]): stri
return applyHashlineEditsWithReport(content, edits).content
}
export {
applySetLine,
applyReplaceLines,
applyInsertAfter,
applyInsertBefore,
} from "./edit-operation-primitives"

View File

@@ -16,9 +16,5 @@ export type {
export { NIBBLE_STR, HASHLINE_DICT, HASHLINE_REF_PATTERN, HASHLINE_OUTPUT_PATTERN } from "./constants"
export {
applyHashlineEdits,
applyInsertAfter,
applyInsertBefore,
applyReplaceLines,
applySetLine,
} from "./edit-operations"
export { createHashlineEditTool } from "./tools"

View File

@@ -61,46 +61,3 @@ describe("validateLineRef", () => {
.toThrow(/>>>\s+2#[ZPMQVRWSNKTXJBYH]{2}\|two/)
})
})
describe("legacy LINE:HEX backward compatibility", () => {
it("parses legacy LINE:HEX ref", () => {
//#given
const ref = "42:ab"
//#when
const result = parseLineRef(ref)
//#then
expect(result).toEqual({ line: 42, hash: "ab" })
})
it("parses legacy LINE:HEX ref with uppercase hex", () => {
//#given
const ref = "10:FF"
//#when
const result = parseLineRef(ref)
//#then
expect(result).toEqual({ line: 10, hash: "FF" })
})
it("legacy ref fails validation with hash mismatch, not parse error", () => {
//#given
const lines = ["function hello() {"]
//#when / #then
expect(() => validateLineRef(lines, "1:ab")).toThrow(/>>>\s+1#[ZPMQVRWSNKTXJBYH]{2}\|/)
})
it("extracts legacy ref from content with markers", () => {
//#given
const ref = ">>> 42:ab|const x = 1"
//#when
const result = parseLineRef(ref)
//#then
expect(result).toEqual({ line: 42, hash: "ab" })
})
})

View File

@@ -1,5 +1,5 @@
import { computeLineHash } from "./hash-computation"
import { HASHLINE_REF_PATTERN, HASHLINE_LEGACY_REF_PATTERN } from "./constants"
import { HASHLINE_REF_PATTERN } from "./constants"
export interface LineRef {
line: number
@@ -13,16 +13,13 @@ interface HashMismatch {
const MISMATCH_CONTEXT = 2
const LINE_REF_EXTRACT_PATTERN = /([0-9]+#[ZPMQVRWSNKTXJBYH]{2}|[0-9]+:[0-9a-fA-F]{2,})/
const LINE_REF_EXTRACT_PATTERN = /([0-9]+#[ZPMQVRWSNKTXJBYH]{2})/
function normalizeLineRef(ref: string): string {
const trimmed = ref.trim()
if (HASHLINE_REF_PATTERN.test(trimmed)) {
return trimmed
}
if (HASHLINE_LEGACY_REF_PATTERN.test(trimmed)) {
return trimmed
}
const extracted = trimmed.match(LINE_REF_EXTRACT_PATTERN)
if (extracted) {
@@ -41,13 +38,6 @@ export function parseLineRef(ref: string): LineRef {
hash: match[2],
}
}
const legacyMatch = normalized.match(HASHLINE_LEGACY_REF_PATTERN)
if (legacyMatch) {
return {
line: Number.parseInt(legacyMatch[1], 10),
hash: legacyMatch[2],
}
}
throw new Error(
`Invalid line reference format: "${ref}". Expected format: "LINE#ID" (e.g., "42#VK")`
)