MCPcopy Create free account
hub / github.com/backnotprop/plannotator / useValidatedCodePaths

Function useValidatedCodePaths

packages/ui/hooks/useValidatedCodePaths.ts:29–85  ·  view source on GitHub ↗
(
	markdown: string,
	baseDir?: string,
)

Source from the content-addressed store, hash-verified

27 * demoted to plain text.
28 */
29export function useValidatedCodePaths(
30 markdown: string,
31 baseDir?: string,
32): { validated: ValidatedMap; ready: boolean } {
33 const [validated, setValidated] = useState<ValidatedMap>(new Map());
34 const [ready, setReady] = useState<boolean>(false);
35
36 useEffect(() => {
37 setValidated(new Map());
38 setReady(false);
39
40 const candidates = extractCandidateCodePaths(markdown);
41 if (candidates.length === 0) {
42 setReady(true);
43 return;
44 }
45
46 let cancelled = false;
47 (async () => {
48 try {
49 const res = await fetch("/api/doc/exists", {
50 method: "POST",
51 headers: { "Content-Type": "application/json" },
52 body: JSON.stringify(
53 baseDir ? { paths: candidates, base: baseDir } : { paths: candidates },
54 ),
55 });
56 if (cancelled) return;
57 if (!res.ok) {
58 setReady(true);
59 return;
60 }
61 const data = (await res.json()) as {
62 results: Record<string, ValidationEntry>;
63 };
64 if (cancelled) return;
65 const next: ValidatedMap = new Map();
66 for (const [k, v] of Object.entries(data.results ?? {})) {
67 next.set(k, v);
68 }
69 setValidated(next);
70 setReady(true);
71 } catch {
72 if (!cancelled) setReady(true);
73 }
74 })();
75
76 return () => {
77 cancelled = true;
78 };
79 }, [markdown, baseDir]);
80
81 // Stable reference: only changes when validated/ready actually change.
82 // Without memoization, the parent provider's value is a fresh object every
83 // render, forcing all context consumers (every InlineMarkdown) to re-render.
84 return useMemo(() => ({ validated, ready }), [validated, ready]);
85}

Callers 1

Viewer.tsxFile · 0.90

Calls 4

entriesMethod · 0.80
fetchFunction · 0.50
setMethod · 0.45

Tested by

no test coverage detected