feat(f6): diff-view toggle on any file — global storage, untitled in-memory (#19)
F6 no longer requires a workspace file. It gets its own diffable predicate (any file: or untitled:) decoupled from F2 isTracked, keys baselines by a sha256 of the document URI, and stores them in VS Code GLOBAL storage (context.globalStorageUri) — always present, never the repo (INV-19). Untitled buffers have no durable identity → in-memory baseline only (lost on reload). DiffViewController is now constructed before the workspace-root check and its commands are always live (never stubbed) — the machine-landing advance wiring stays in the with-root branch since the seam only fires on workspace files. BaselineStore generalized to key-by-hash (Baseline.docPath → uri). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+25
-17
@@ -13,41 +13,49 @@ afterEach(() => {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
function sample(docPath = "notes/chapter-1.md"): Baseline {
|
||||
return { docPath, text: "hello\nworld\n", capturedAt: "2026-06-11T00:00:00.000Z", reason: "opened" };
|
||||
const KEY = "a1b2c3"; // a stand-in for the controller's sha256(uri) key
|
||||
|
||||
function sample(uri = "file:///ws/notes/chapter-1.md"): Baseline {
|
||||
return { uri, text: "hello\nworld\n", capturedAt: "2026-06-11T00:00:00.000Z", reason: "opened" };
|
||||
}
|
||||
|
||||
describe("BaselineStore", () => {
|
||||
it("returns null for a document with no baseline", () => {
|
||||
expect(new BaselineStore(dir).load("notes/chapter-1.md")).toBeNull();
|
||||
it("returns null for a key with no baseline", () => {
|
||||
expect(new BaselineStore(dir).load(KEY)).toBeNull();
|
||||
});
|
||||
|
||||
it("computes the baseline path as baselines/<docPath>.json", () => {
|
||||
it("computes the baseline path as baselines/<key>.json", () => {
|
||||
const store = new BaselineStore(dir);
|
||||
expect(store.baselinePath("notes/chapter-1.md")).toBe(
|
||||
path.join(dir, "baselines", "notes", "chapter-1.md.json"),
|
||||
);
|
||||
expect(store.baselinePath(KEY)).toBe(path.join(dir, "baselines", "a1b2c3.json"));
|
||||
});
|
||||
|
||||
it("save then load round-trips the baseline (including nested docPaths)", () => {
|
||||
it("save then load round-trips the baseline (including the uri identity)", () => {
|
||||
const store = new BaselineStore(dir);
|
||||
const b = sample();
|
||||
store.save(b.docPath, b);
|
||||
expect(store.load(b.docPath)).toEqual(b);
|
||||
store.save(KEY, b);
|
||||
expect(store.load(KEY)).toEqual(b);
|
||||
});
|
||||
|
||||
it("overwrites in place: the newest epoch wins, no history kept", () => {
|
||||
const store = new BaselineStore(dir);
|
||||
store.save("d.md", { docPath: "d.md", text: "v1", capturedAt: "2026-06-11T00:00:00.000Z", reason: "opened" });
|
||||
store.save("d.md", { docPath: "d.md", text: "v2", capturedAt: "2026-06-11T00:01:00.000Z", reason: "pinned" });
|
||||
expect(store.load("d.md")).toEqual({ docPath: "d.md", text: "v2", capturedAt: "2026-06-11T00:01:00.000Z", reason: "pinned" });
|
||||
store.save(KEY, { uri: "untitled:Untitled-1", text: "v1", capturedAt: "2026-06-11T00:00:00.000Z", reason: "opened" });
|
||||
store.save(KEY, { uri: "untitled:Untitled-1", text: "v2", capturedAt: "2026-06-11T00:01:00.000Z", reason: "pinned" });
|
||||
expect(store.load(KEY)).toEqual({ uri: "untitled:Untitled-1", text: "v2", capturedAt: "2026-06-11T00:01:00.000Z", reason: "pinned" });
|
||||
});
|
||||
|
||||
it("writes pretty JSON with a trailing newline", () => {
|
||||
const store = new BaselineStore(dir);
|
||||
const b = sample("d.md");
|
||||
store.save("d.md", b);
|
||||
const raw = fs.readFileSync(store.baselinePath("d.md"), "utf8");
|
||||
const b = sample();
|
||||
store.save(KEY, b);
|
||||
const raw = fs.readFileSync(store.baselinePath(KEY), "utf8");
|
||||
expect(raw).toBe(JSON.stringify(b, null, 2) + "\n");
|
||||
});
|
||||
|
||||
it("distinct keys are independent files (no collision)", () => {
|
||||
const store = new BaselineStore(dir);
|
||||
store.save("k1", sample("file:///a.md"));
|
||||
store.save("k2", sample("file:///b.md"));
|
||||
expect(store.load("k1")!.uri).toBe("file:///a.md");
|
||||
expect(store.load("k2")!.uri).toBe("file:///b.md");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user