pi-hashline-edit-pro 0.16.7 → 0.16.8
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.
- package/package.json +1 -1
- package/src/config.ts +9 -2
- package/src/hash-store.ts +5 -1
- package/src/hashline/apply.ts +0 -3
- package/src/replace-normalize.ts +0 -2
- package/src/utils.ts +1 -14
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "fs";
|
|
2
2
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
3
3
|
import { configDir, configPath } from "./paths";
|
|
4
|
+
import { errCode } from "./validation";
|
|
4
5
|
|
|
5
6
|
export type ReplaceMode = "bulk" | "flat";
|
|
6
7
|
|
|
@@ -22,7 +23,10 @@ export async function readConfig(): Promise<Config> {
|
|
|
22
23
|
replaceMode: parsed.replaceMode === "flat" ? "flat" : "bulk",
|
|
23
24
|
autoRead: parsed.autoRead === true,
|
|
24
25
|
};
|
|
25
|
-
} catch {
|
|
26
|
+
} catch (error: unknown) {
|
|
27
|
+
if (errCode(error) !== "ENOENT") {
|
|
28
|
+
console.error("Config file corrupted, using defaults:", error);
|
|
29
|
+
}
|
|
26
30
|
return { ...DEFAULT_CONFIG };
|
|
27
31
|
}
|
|
28
32
|
}
|
|
@@ -35,7 +39,10 @@ export function readConfigSync(): Config {
|
|
|
35
39
|
replaceMode: parsed.replaceMode === "flat" ? "flat" : "bulk",
|
|
36
40
|
autoRead: parsed.autoRead === true,
|
|
37
41
|
};
|
|
38
|
-
} catch {
|
|
42
|
+
} catch (error: unknown) {
|
|
43
|
+
if (errCode(error) !== "ENOENT") {
|
|
44
|
+
console.error("Config file corrupted, using defaults:", error);
|
|
45
|
+
}
|
|
39
46
|
return { ...DEFAULT_CONFIG };
|
|
40
47
|
}
|
|
41
48
|
}
|
package/src/hash-store.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
2
2
|
import { stat } from "fs/promises";
|
|
3
3
|
import { hashStorePath, hashStoreDir } from "./paths";
|
|
4
|
+
import { errCode } from "./validation";
|
|
4
5
|
|
|
5
6
|
export interface FileSnapshot {
|
|
6
7
|
content: string;
|
|
@@ -20,7 +21,10 @@ export async function loadHashStore(): Promise<HashStore> {
|
|
|
20
21
|
version: 1,
|
|
21
22
|
snapshots: parsed.snapshots ?? {},
|
|
22
23
|
};
|
|
23
|
-
} catch {
|
|
24
|
+
} catch (error: unknown) {
|
|
25
|
+
if (errCode(error) !== "ENOENT") {
|
|
26
|
+
console.error("Hash store corrupted, creating fresh store:", error);
|
|
27
|
+
}
|
|
24
28
|
await mkdir(hashStoreDir(), { recursive: true });
|
|
25
29
|
const defaultStore: HashStore = {
|
|
26
30
|
version: 1,
|
package/src/hashline/apply.ts
CHANGED
|
@@ -294,12 +294,10 @@ export function applyEdits(
|
|
|
294
294
|
assertNoBarePrefix(edits, lineIndex.fileLines, fileHashes);
|
|
295
295
|
warnUnicodeEsc(edits, warnings);
|
|
296
296
|
|
|
297
|
-
// Auto-fix boundary duplications: strip the offending line from content_lines
|
|
298
297
|
let resolved = initialResolved;
|
|
299
298
|
let autoFixes: AutoFix[] | undefined;
|
|
300
299
|
if (boundaryWarnings.length > 0) {
|
|
301
300
|
autoFixes = [];
|
|
302
|
-
// Deep-copy edits so we don't mutate the originals
|
|
303
301
|
const correctedEdits: import("./resolve").HEdit[] = edits.map(e => ({
|
|
304
302
|
...e,
|
|
305
303
|
content_lines: [...e.content_lines],
|
|
@@ -319,7 +317,6 @@ export function applyEdits(
|
|
|
319
317
|
}
|
|
320
318
|
}
|
|
321
319
|
}
|
|
322
|
-
// Re-validate with corrected edits
|
|
323
320
|
const correctedResult = valEdits(
|
|
324
321
|
correctedEdits,
|
|
325
322
|
lineIndex.fileLines,
|
package/src/replace-normalize.ts
CHANGED
|
@@ -43,7 +43,6 @@ export function normReq(input: unknown): unknown {
|
|
|
43
43
|
|
|
44
44
|
normalizeFilePath(record);
|
|
45
45
|
|
|
46
|
-
// Early validation: reject string-typed content_lines at the top level
|
|
47
46
|
if (has(record, "content_lines") && typeof record.content_lines === "string") {
|
|
48
47
|
assertContentLinesNotString(record.content_lines, "Top-level");
|
|
49
48
|
}
|
|
@@ -51,7 +50,6 @@ export function normReq(input: unknown): unknown {
|
|
|
51
50
|
normalizeField(record, "changes", "changes");
|
|
52
51
|
normalizeField(record, "edits", "changes");
|
|
53
52
|
|
|
54
|
-
// Validate items in the changes array before wrapping flat format
|
|
55
53
|
if (Array.isArray(record.changes)) {
|
|
56
54
|
for (let i = 0; i < record.changes.length; i++) {
|
|
57
55
|
const item = record.changes[i];
|
package/src/utils.ts
CHANGED
|
@@ -6,25 +6,12 @@ export function has(record: Record<string, unknown>, key: string): boolean {
|
|
|
6
6
|
return Object.hasOwn(record, key);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
* Splits text into visible lines, stripping the trailing empty element
|
|
11
|
-
* that `split("\n")` produces when the text ends with "\n".
|
|
12
|
-
*
|
|
13
|
-
* This is the canonical way to get user-visible lines from text.
|
|
14
|
-
* For internal hashing that needs the trailing empty string (e.g.
|
|
15
|
-
* `_lineHashesPure`, `mapStableHashes`, `buildIdx`), use
|
|
16
|
-
* `text.split("\n")` directly with a comment explaining why.
|
|
17
|
-
*/
|
|
18
|
-
export function splitLines(text: string): string[] {
|
|
9
|
+
export function visLines(text: string): string[] {
|
|
19
10
|
if (text.length === 0) return [];
|
|
20
11
|
const lines = text.split("\n");
|
|
21
12
|
return text.endsWith("\n") ? lines.slice(0, -1) : lines;
|
|
22
13
|
}
|
|
23
14
|
|
|
24
|
-
export function visLines(text: string): string[] {
|
|
25
|
-
return splitLines(text);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
15
|
export function cntLines(text: string): number {
|
|
29
16
|
return visLines(text).length;
|
|
30
17
|
}
|