feat(pi-natives-chunk): enabled row chunk support in pi-natives-chunk

- Added markdown `Row` chunk support by introducing `ChunkKind::Row`, mapping it to tag `"row"`, and emitting row chunks for table rows.
- Updated Go chunk parsing to support method signatures (`func (recv) Name`), prefer method parsing in signatures, and adjust root rules to classify package/import chunks correctly.
- Changed chunk-edit behavior to add read-only `read:true`, replace `write:null` deletes with explicit `delete`, and require one explicit action per entry.
- Added safer chunk-edit execution with region matching, replacement reindentation, table-row append handling, and stricter warnings/errors for boundary and invalid operations.
This commit is contained in:
can1357
2026-04-24 21:23:16 +02:00
parent 1dacb9a5b3
commit 99a21b95ba
16 changed files with 1113 additions and 168 deletions
@@ -194,6 +194,67 @@ describe("computeChunkDiff", () => {
expect("error" in result).toBe(true);
});
test("returns an empty preview for read-only chunk reads", async () => {
const file = path.join(tmpDir, "read.ts");
await fs.writeFile(file, "export const x = 1;\n");
const result = await computeChunkDiff(
{
path: "read.ts",
edits: [{ path: "read.ts:?", read: true }],
},
tmpDir,
);
expect(result).toEqual({ diff: "", firstChangedLine: undefined });
});
test("rejects write:null instead of previewing a delete", async () => {
const file = path.join(tmpDir, "null-delete.ts");
await fs.writeFile(file, "export const x = 1;\n");
const result = await computeChunkDiff(
{
path: "null-delete.ts",
edits: [{ path: "null-delete.ts", write: null }],
},
tmpDir,
);
expect("error" in result).toBe(true);
if ("error" in result) {
expect(result.error).toContain("write:null no longer deletes chunks");
}
});
test("rejects bare chunk edit entries instead of treating them as deletes", async () => {
const file = path.join(tmpDir, "bare.ts");
await fs.writeFile(file, "export const x = 1;\n");
const result = await computeChunkDiff(
{
path: "bare.ts",
edits: [{ path: "bare.ts" }],
},
tmpDir,
);
expect("error" in result).toBe(true);
if ("error" in result) {
expect(result.error).toContain("no operation specified");
}
});
test("rejects write empty string instead of previewing a destructive empty replacement", async () => {
const file = path.join(tmpDir, "empty-write.ts");
await fs.writeFile(file, "export const x = 1;\n");
const result = await computeChunkDiff(
{
path: "empty-write.ts",
edits: [{ path: "empty-write.ts", write: "" }],
},
tmpDir,
);
expect("error" in result).toBe(true);
if ("error" in result) {
expect(result.error).toContain('write:"" is a destructive empty replacement');
}
});
test("aborts when signal fires before compute completes", async () => {
const controller = new AbortController();
controller.abort();