Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374import type { FileDiffMetadata } from "@pierre/diffs";import { streamPatchInWorker } from "$lib/components/repo/diffRpc";
/** * A patch being parsed in the worker while it downloads. Starting one does not * wait for anything else on the page: the file list and the patch describe the * same commit, and fetching them one after the other costs the sum of both. */export interface PatchStream { /** parsed files, keyed by current name and by previous name for renames */ readonly byName: Map<string, FileDiffMetadata>; /** called with each batch as it lands, and unsubscribed on teardown */ subscribe: (listener: (files: FileDiffMetadata[]) => void) => () => void; /** false when the patch could not be read, so a caller can fall back */ readonly done: Promise<boolean>; stop: () => void;}
// Dedupes in-flight patch streams by URL.const live = new Map<string, PatchStream>();const KEEP = 2;
export const getPatchStream = (url: string): PatchStream => { const held = live.get(url); if (held) return held; const stream = startPatchStream(url); live.set(url, stream); // a navigation leaves its patch behind; keeping the last couple means going // back to a commit is instant, and anything older is dropped for (const [key, value] of live) { if (live.size <= KEEP) break; value.stop(); live.delete(key); } return stream;};
export const startPatchStream = (url: string): PatchStream => { const byName = new Map<string, FileDiffMetadata>(); const listeners = new Set<(files: FileDiffMetadata[]) => void>(); const controller = new AbortController(); let stopped = false;
const land = (files: FileDiffMetadata[]) => { if (stopped) return; for (const file of files) { byName.set(file.name, file); if (file.prevName) byName.set(file.prevName, file); } for (const listener of listeners) listener(files); };
const stream: PatchStream = { byName, subscribe: (listener) => { listeners.add(listener); return () => listeners.delete(listener); }, // resolved either way: a caller that never asks cannot leave a rejection // unhandled, and one that does gets an answer instead of an exception done: streamPatchInWorker(url, land, controller.signal).then( () => true, () => false ), stop: () => { stopped = true; listeners.clear(); controller.abort(); } };
return stream;};