mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-11-15 05:59:11 +08:00
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>
24 lines
1.2 KiB
TypeScript
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;
|
|
}
|