Unify internal hashline edit handling around replace/append/prepend to remove legacy operation shapes. This keeps normalization, ordering, deduplication, execution, and tests aligned with the new op/pos/end/lines contract.
96 lines
2.6 KiB
TypeScript
96 lines
2.6 KiB
TypeScript
import type { AppendEdit, HashlineEdit, PrependEdit, ReplaceEdit } from "./types"
|
|
|
|
type HashlineToolOp = "replace" | "append" | "prepend"
|
|
|
|
export interface RawHashlineEdit {
|
|
op?: HashlineToolOp
|
|
pos?: string
|
|
end?: string
|
|
lines?: string | string[] | null
|
|
}
|
|
|
|
function normalizeAnchor(value: string | undefined): string | undefined {
|
|
if (typeof value !== "string") return undefined
|
|
const trimmed = value.trim()
|
|
return trimmed === "" ? undefined : trimmed
|
|
}
|
|
|
|
function requireLines(edit: RawHashlineEdit, index: number): string | string[] {
|
|
if (edit.lines === undefined) {
|
|
throw new Error(`Edit ${index}: lines is required for ${edit.op ?? "unknown"}`)
|
|
}
|
|
if (edit.lines === null) {
|
|
return []
|
|
}
|
|
return edit.lines
|
|
}
|
|
|
|
function requireLine(anchor: string | undefined, index: number, op: HashlineToolOp): string {
|
|
if (!anchor) {
|
|
throw new Error(`Edit ${index}: ${op} requires at least one anchor line reference (pos or end)`)
|
|
}
|
|
return anchor
|
|
}
|
|
|
|
function normalizeReplaceEdit(edit: RawHashlineEdit, index: number): HashlineEdit {
|
|
const pos = normalizeAnchor(edit.pos)
|
|
const end = normalizeAnchor(edit.end)
|
|
const anchor = requireLine(pos ?? end, index, "replace")
|
|
const lines = requireLines(edit, index)
|
|
|
|
const normalized: ReplaceEdit = {
|
|
op: "replace",
|
|
pos: anchor,
|
|
lines,
|
|
}
|
|
if (end) normalized.end = end
|
|
return normalized
|
|
}
|
|
|
|
function normalizeAppendEdit(edit: RawHashlineEdit, index: number): HashlineEdit {
|
|
const pos = normalizeAnchor(edit.pos)
|
|
const end = normalizeAnchor(edit.end)
|
|
const anchor = pos ?? end
|
|
const lines = requireLines(edit, index)
|
|
|
|
const normalized: AppendEdit = {
|
|
op: "append",
|
|
lines,
|
|
}
|
|
if (anchor) normalized.pos = anchor
|
|
return normalized
|
|
}
|
|
|
|
function normalizePrependEdit(edit: RawHashlineEdit, index: number): HashlineEdit {
|
|
const pos = normalizeAnchor(edit.pos)
|
|
const end = normalizeAnchor(edit.end)
|
|
const anchor = pos ?? end
|
|
const lines = requireLines(edit, index)
|
|
|
|
const normalized: PrependEdit = {
|
|
op: "prepend",
|
|
lines,
|
|
}
|
|
if (anchor) normalized.pos = anchor
|
|
return normalized
|
|
}
|
|
|
|
export function normalizeHashlineEdits(rawEdits: RawHashlineEdit[]): HashlineEdit[] {
|
|
return rawEdits.map((rawEdit, index) => {
|
|
const edit = rawEdit ?? {}
|
|
|
|
switch (edit.op) {
|
|
case "replace":
|
|
return normalizeReplaceEdit(edit, index)
|
|
case "append":
|
|
return normalizeAppendEdit(edit, index)
|
|
case "prepend":
|
|
return normalizePrependEdit(edit, index)
|
|
default:
|
|
throw new Error(
|
|
`Edit ${index}: unsupported op "${String(edit.op)}". Legacy format was removed; use op/pos/end/lines.`
|
|
)
|
|
}
|
|
})
|
|
}
|