refactor: fix unicode regex discrepancy and standardize function naming (#1031)

Add missing \u1680 (Ogham space mark) to UNICODE_SPACES in path-utils.ts
and loader.ts. Make edit-diff.ts import the shared constant from
path-utils.ts instead of maintaining an inline copy.

Rename hashlineParseText to parseHashlineText to follow the parseX()
convention used across the codebase.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
TÂCHES 2026-03-17 18:29:44 -06:00 committed by GitHub
parent 3537f6b716
commit 5657f302a6
7 changed files with 18 additions and 18 deletions

View file

@ -105,7 +105,7 @@ function getAliases(): Record<string, string> {
return _aliases;
}
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
const UNICODE_SPACES = /[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g;
function normalizeUnicodeSpaces(str: string): string {
return str.replace(UNICODE_SPACES, " ");

View file

@ -9,7 +9,7 @@
import { constants } from "fs";
import { access, readFile } from "fs/promises";
import { resolveToCwd } from "./path-utils.js";
import { resolveToCwd, UNICODE_SPACES } from "./path-utils.js";
export function detectLineEnding(content: string): "\r\n" | "\n" {
const crlfIdx = content.indexOf("\r\n");
@ -41,7 +41,7 @@ export function normalizeForFuzzyMatch(text: string): string {
.replace(/[“”]/g, '"')
.replace(/[]/g, "'")
.replace(/[‐‑‒–—−]/g, "-")
.replace(/[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g, " ")
.replace(UNICODE_SPACES, " ")
.split("\n")
.map((line) => line.replace(/[ \t]+$/g, ""))
.join("\n");

View file

@ -20,7 +20,7 @@ import {
applyHashlineEdits,
computeLineHash,
type HashlineEdit,
hashlineParseText,
parseHashlineText,
parseTag,
} from "./hashline.js";
import { resolveToCwd } from "./path-utils.js";
@ -99,7 +99,7 @@ function tryParseTag(raw: string): Anchor | undefined {
function resolveEditAnchors(edits: HashlineEditItem[]): HashlineEdit[] {
const result: HashlineEdit[] = [];
for (const edit of edits) {
const lines = hashlineParseText(edit.lines);
const lines = parseHashlineText(edit.lines);
const tag = edit.pos ? tryParseTag(edit.pos) : undefined;
const end = edit.end ? tryParseTag(edit.end) : undefined;
@ -207,9 +207,9 @@ export function createHashlineEditTool(cwd: string, options?: HashlineEditToolOp
for (const edit of edits) {
if ((edit.op === "append" || edit.op === "prepend") && !edit.pos && !edit.end) {
if (edit.op === "prepend") {
lines.unshift(...hashlineParseText(edit.lines));
lines.unshift(...parseHashlineText(edit.lines));
} else {
lines.push(...hashlineParseText(edit.lines));
lines.push(...parseHashlineText(edit.lines));
}
} else {
throw new Error(`File not found: ${path}`);

View file

@ -8,7 +8,7 @@ import {
validateLineRef,
applyHashlineEdits,
HashlineMismatchError,
hashlineParseText,
parseHashlineText,
stripNewLinePrefixes,
type HashlineEdit,
type Anchor,
@ -395,31 +395,31 @@ describe("stripNewLinePrefixes", () => {
});
// ═══════════════════════════════════════════════════════════════════════════
// hashlineParseText
// parseHashlineText
// ═══════════════════════════════════════════════════════════════════════════
describe("hashlineParseText", () => {
describe("parseHashlineText", () => {
it("returns empty array for null", () => {
assert.deepEqual(hashlineParseText(null), []);
assert.deepEqual(parseHashlineText(null), []);
});
it("returns array input as-is when no strip heuristic applies", () => {
const input = ["- [x] done", "- [ ] todo"];
assert.equal(hashlineParseText(input), input);
assert.equal(parseHashlineText(input), input);
});
it("splits string on newline and preserves Markdown list '-' prefix", () => {
const result = hashlineParseText("- item one\n- item two\n- item three");
const result = parseHashlineText("- item one\n- item two\n- item three");
assert.deepEqual(result, ["- item one", "- item two", "- item three"]);
});
it("strips '+' diff markers from string input", () => {
const result = hashlineParseText("+line one\n+line two");
const result = parseHashlineText("+line one\n+line two");
assert.deepEqual(result, ["line one", "line two"]);
});
it("still strips trailing empty from string split", () => {
assert.deepEqual(hashlineParseText("foo\n"), ["foo"]);
assert.deepEqual(parseHashlineText("foo\n"), ["foo"]);
});
});

View file

@ -230,7 +230,7 @@ export function stripNewLinePrefixes(lines: string[]): string[] {
* Parse edit content handles string, array, or null input.
* Strips hashline prefixes and diff markers from model output.
*/
export function hashlineParseText(edit: string[] | string | null): string[] {
export function parseHashlineText(edit: string[] | string | null): string[] {
if (edit === null) return [];
if (typeof edit === "string") {
const normalizedEdit = edit.endsWith("\n") ? edit.slice(0, -1) : edit;

View file

@ -99,7 +99,7 @@ export {
formatLineTag,
type HashlineEdit,
HashlineMismatchError,
hashlineParseText,
parseHashlineText,
type HashMismatch,
parseTag,
stripNewLinePrefixes,

View file

@ -2,7 +2,7 @@ import { accessSync, constants } from "node:fs";
import * as os from "node:os";
import { isAbsolute, resolve as resolvePath } from "node:path";
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
export const UNICODE_SPACES = /[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g;
const NARROW_NO_BREAK_SPACE = "\u202F";
function normalizeUnicodeSpaces(str: string): string {
return str.replace(UNICODE_SPACES, " ");