Files
codegraph/src/extraction/parse-budget.ts
T
Colby MchenryandClaude Opus 5.5 41cfc8356f fix(viewer): highlighting runs in a worker the server can stop (#2266)
The viewer's server classifies a code slice with the engine's tree-sitter
grammars on its one thread. The COBOL grammar's scanner loops forever on a
line like `    .`, which a cobolcraft Flow card's window ends with, so the
whole server froze — /api/stats included — and a parse inside WebAssembly
cannot be interrupted from JavaScript. Slices are now classified in a
worker that is terminated past a 2 s deadline; the slice is served plain
and the next one gets a fresh worker. Request-time parses also carry a
progress-callback budget.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:33:37 +00:00

24 lines
1.2 KiB
TypeScript

/**
* A parse that answers a request — the viewer's syntax highlighting, the
* branch guards a Steps or Flow card reads — runs on the server's one thread,
* so a parse that does not finish takes every other request down with it.
* Indexing parses in workers it can kill; these cannot be killed, so they are
* cancelled instead: tree-sitter asks its progress callback as it goes, and a
* `true` stops the parse. A free-format COBOL window handed to the
* fixed-format grammar kept cobolcraft's Flow strip — and the whole viewer
* after it — parsing for good.
*/
import type { Parser, Tree } from 'web-tree-sitter';
/** Longest a request-time parse may run before it is given up — far past any file that parses at all. */
export const REQUEST_PARSE_BUDGET_MS = 3000;
/** `parser.parse(source)`, or null when it runs past the budget. */
export function parseWithinBudget(parser: Parser, source: string, budgetMs = REQUEST_PARSE_BUDGET_MS): Tree | null {
const deadline = Date.now() + budgetMs;
// The runtime hands the callback's return value to the parser: `true` cancels.
const cancel = (() => Date.now() > deadline) as unknown as () => void;
return parser.parse(source, null, { progressCallback: cancel }) ?? null;
}