gitnexus 1.6.6-rc.102 → 1.6.6-rc.104

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,7 +28,7 @@ import { generateId } from '../../lib/utils.js';
28
28
  import { getLanguageFromFilename, SupportedLanguages } from '../../_shared/index.js';
29
29
  import { isRegistryPrimary } from './registry-primary-flag.js';
30
30
  import { isVerboseIngestionEnabled } from './utils/verbose.js';
31
- import { deferredCallFileSlowMs, deferredCallLogEveryN, getDeferredProfileDroppedCount, isDeferredResolutionProfileEnabled, logDeferredProfile, profileElapsedMs, resetDeferredProfileDroppedCount, startTimer, } from './utils/deferred-resolution-profile.js';
31
+ import { ALWAYS_ON_SLOW_FILE_WARN_THROTTLE_MS, alwaysOnSlowFileWarnMs, deferredCallFileSlowMs, deferredCallLogEveryN, getDeferredProfileDroppedCount, isDeferredResolutionProfileEnabled, logDeferredProfile, profileElapsedMs, resetDeferredProfileDroppedCount, startTimer, } from './utils/deferred-resolution-profile.js';
32
32
  import { yieldToEventLoop } from './utils/event-loop.js';
33
33
  import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
34
34
  import { CLASS_CONTAINER_TYPES, FUNCTION_NODE_TYPES, findEnclosingClassInfo, genericFuncName, inferFunctionLabel, } from './utils/ast-helpers.js';
@@ -2303,6 +2303,14 @@ export const processCallsFromExtracted = async (graph, extractedCalls, ctx, onPr
2303
2303
  const slowFileMs = profileCalls ? deferredCallFileSlowMs() : 0;
2304
2304
  const logEveryN = profileCalls ? deferredCallLogEveryN() : 0;
2305
2305
  let skippedRegistryPrimaryFiles = 0;
2306
+ // Always-on slow-file watchdog (#1741). Independent of the verbose/profile
2307
+ // gate above: even a plain `analyze` run surfaces ONE actionable warning
2308
+ // when a single file's call resolution is pathologically slow — turning the
2309
+ // silent "stuck at Resolving calls (N/M)" symptom into a named culprit.
2310
+ // Throttled so a genuinely slow repo can't produce a warn storm.
2311
+ const alwaysSlowFileMs = alwaysOnSlowFileWarnMs();
2312
+ let lastSlowFileWarnAt = 0;
2313
+ let suppressedSlowFileWarnings = 0;
2306
2314
  // Fresh dropped-log counter per analyze run — the module-private counter
2307
2315
  // in deferred-resolution-profile.ts is process-lived, so without a reset
2308
2316
  // here it would accumulate across consecutive analyze invocations in the
@@ -2314,12 +2322,16 @@ export const processCallsFromExtracted = async (graph, extractedCalls, ctx, onPr
2314
2322
  // denominator stays stable as the loop iterates. Otherwise `${totalFiles -
2315
2323
  // skippedRegistryPrimaryFiles}` drifts upward — files iterated before later
2316
2324
  // registry-primary skips have been seen carry an inflated denominator, and
2317
- // the ratio only self-corrects after every file has been classified. Pre-
2318
- // count runs only on the enabled path so the disabled path stays free of
2319
- // the extra Map iteration. Defaults to 0 on the disabled path; the live log
2320
- // gate is also disabled there, so the value is never read.
2325
+ // the ratio only self-corrects after every file has been classified.
2326
+ //
2327
+ // Runs whenever its result will actually be read: on the profile path (the
2328
+ // live deferred-profile log) OR when the always-on slow-file watchdog is
2329
+ // active (#1741) — the watchdog's warning prints `${resolvedFiles}/${resolvedTotal}`
2330
+ // unconditionally, so leaving resolvedTotal at 0 on a plain run produced a
2331
+ // bogus "Resolved N/0 files" denominator on exactly the unprofiled runs the
2332
+ // watchdog exists for. When both gates are off, skip the extra Map pass.
2321
2333
  let resolvedTotal = 0;
2322
- if (profileCalls) {
2334
+ if (profileCalls || alwaysSlowFileMs > 0) {
2323
2335
  for (const filePath of byFile.keys()) {
2324
2336
  const lang = getLanguageFromFilename(filePath);
2325
2337
  if (!lang || !isRegistryPrimary(lang))
@@ -2341,6 +2353,9 @@ export const processCallsFromExtracted = async (graph, extractedCalls, ctx, onPr
2341
2353
  }
2342
2354
  resolvedFiles++;
2343
2355
  const tFile = startTimer(profileCalls);
2356
+ // Always-on timer (cheap: one hrtime read) feeding the slow-file watchdog
2357
+ // below. Distinct from `tFile`, which is null unless profiling is on.
2358
+ const tFileAlways = alwaysSlowFileMs > 0 ? process.hrtime.bigint() : null;
2344
2359
  if (profileCalls && (resolvedFiles === 1 || resolvedFiles % logEveryN === 0)) {
2345
2360
  logDeferredProfile(`calls ${resolvedFiles}/${resolvedTotal} file=${filePath} sites=${calls.length}`);
2346
2361
  }
@@ -2455,6 +2470,27 @@ export const processCallsFromExtracted = async (graph, extractedCalls, ctx, onPr
2455
2470
  logDeferredProfile(`slow file ${elapsed.toFixed(0)}ms path=${filePath} calls=${calls.length} lang=${fileLanguage ?? 'unknown'}`);
2456
2471
  }
2457
2472
  }
2473
+ // Always-on slow-file watchdog (#1741) — fires regardless of verbose.
2474
+ if (tFileAlways !== null) {
2475
+ const elapsedAlways = profileElapsedMs(tFileAlways);
2476
+ if (elapsedAlways >= alwaysSlowFileMs) {
2477
+ const now = Date.now();
2478
+ if (now - lastSlowFileWarnAt >= ALWAYS_ON_SLOW_FILE_WARN_THROTTLE_MS) {
2479
+ lastSlowFileWarnAt = now;
2480
+ const suppressedNote = suppressedSlowFileWarnings > 0
2481
+ ? ` (+${suppressedSlowFileWarnings} more slow files since the last warning)`
2482
+ : '';
2483
+ logger.warn(`⏳ Call resolution for ${filePath} took ${(elapsedAlways / 1000).toFixed(1)}s ` +
2484
+ `(${calls.length} call sites, ${fileLanguage ?? 'unknown'}). The run is not frozen — ` +
2485
+ `this file is unusually expensive to resolve. Resolved ${resolvedFiles}/${resolvedTotal} ` +
2486
+ `files so far.${suppressedNote} Pass -v for per-file deferred-resolution timing.`);
2487
+ suppressedSlowFileWarnings = 0;
2488
+ }
2489
+ else {
2490
+ suppressedSlowFileWarnings++;
2491
+ }
2492
+ }
2493
+ }
2458
2494
  }
2459
2495
  if (profileCalls) {
2460
2496
  logDeferredProfile(`processCallsFromExtracted done: ${totalFiles} files, ${extractedCalls.length} call sites, skipped registry-primary files=${skippedRegistryPrimaryFiles}`);
@@ -14,9 +14,9 @@ export function emitCScopeCaptures(sourceText, filePath, cachedTree) {
14
14
  }
15
15
  const rawMatches = getCScopeQuery().matches(tree.rootNode);
16
16
  const out = [];
17
- // Track ranges where typedef-struct/union was captured as @declaration.struct/union
18
- // so we can suppress the duplicate @declaration.typedef match at the same range.
19
- const structTypedefRanges = new Set();
17
+ // Track ranges where typedef-struct/union/enum was captured as its concrete
18
+ // type so we can suppress the duplicate @declaration.typedef match.
19
+ const concreteTypedefRanges = new Set();
20
20
  for (const m of rawMatches) {
21
21
  const grouped = {};
22
22
  for (const c of m.captures) {
@@ -39,18 +39,20 @@ export function emitCScopeCaptures(sourceText, filePath, cachedTree) {
39
39
  }
40
40
  }
41
41
  }
42
- // Track typedef-struct ranges to suppress duplicate typedef declarations
43
- const structAnchor = grouped['@declaration.struct'] ?? grouped['@declaration.union'];
44
- if (structAnchor !== undefined) {
45
- const r = structAnchor.range;
46
- structTypedefRanges.add(`${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`);
42
+ // Track typedef struct/union/enum ranges to suppress duplicate typedef declarations
43
+ const concreteTypeAnchor = grouped['@declaration.struct'] ??
44
+ grouped['@declaration.union'] ??
45
+ grouped['@declaration.enum'];
46
+ if (concreteTypeAnchor !== undefined) {
47
+ const r = concreteTypeAnchor.range;
48
+ concreteTypedefRanges.add(`${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`);
47
49
  }
48
- // Suppress @declaration.typedef if the same range was already captured as struct/union
50
+ // Suppress @declaration.typedef if the same range was already captured as a concrete type.
49
51
  const typedefAnchor = grouped['@declaration.typedef'];
50
52
  if (typedefAnchor !== undefined) {
51
53
  const r = typedefAnchor.range;
52
54
  const key = `${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`;
53
- if (structTypedefRanges.has(key))
55
+ if (concreteTypedefRanges.has(key))
54
56
  continue;
55
57
  }
56
58
  // Enrich function declarations with arity metadata and detect static linkage
@@ -40,6 +40,12 @@ const C_SCOPE_QUERY = `
40
40
  (enum_specifier
41
41
  name: (type_identifier) @declaration.name) @declaration.enum
42
42
 
43
+ ;; Declarations — enum (typedef enum { ... } Name)
44
+ (type_definition
45
+ type: (enum_specifier
46
+ body: (enumerator_list))
47
+ declarator: (type_identifier) @declaration.name) @declaration.enum
48
+
43
49
  ;; Declarations — function definition
44
50
  (function_definition
45
51
  declarator: (function_declarator
@@ -18,9 +18,9 @@ export function emitCppScopeCaptures(sourceText, filePath, cachedTree) {
18
18
  }
19
19
  const rawMatches = getCppScopeQuery().matches(tree.rootNode);
20
20
  const out = [];
21
- // Track ranges where typedef-struct was captured as @declaration.struct
21
+ // Track ranges where typedef-struct/enum was captured as its concrete type
22
22
  // so we can suppress the duplicate @declaration.typedef match.
23
- const structTypedefRanges = new Set();
23
+ const concreteTypedefRanges = new Set();
24
24
  for (const m of rawMatches) {
25
25
  const grouped = {};
26
26
  for (const c of m.captures) {
@@ -55,18 +55,20 @@ export function emitCppScopeCaptures(sourceText, filePath, cachedTree) {
55
55
  }
56
56
  }
57
57
  }
58
- // ── Track typedef-struct ranges ─────────────────────────────────
59
- const structAnchor = grouped['@declaration.struct'] ?? grouped['@declaration.class'];
60
- if (structAnchor !== undefined) {
61
- const r = structAnchor.range;
62
- structTypedefRanges.add(`${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`);
58
+ // ── Track concrete typedef ranges ───────────────────────────────
59
+ const concreteTypeAnchor = grouped['@declaration.struct'] ??
60
+ grouped['@declaration.class'] ??
61
+ grouped['@declaration.enum'];
62
+ if (concreteTypeAnchor !== undefined) {
63
+ const r = concreteTypeAnchor.range;
64
+ concreteTypedefRanges.add(`${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`);
63
65
  }
64
66
  // Suppress @declaration.typedef if the same range was already captured
65
67
  const typedefAnchor = grouped['@declaration.typedef'];
66
68
  if (typedefAnchor !== undefined) {
67
69
  const r = typedefAnchor.range;
68
70
  const key = `${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`;
69
- if (structTypedefRanges.has(key))
71
+ if (concreteTypedefRanges.has(key))
70
72
  continue;
71
73
  }
72
74
  // ── Enrich function/method declarations with arity metadata ─────
@@ -47,6 +47,12 @@ const CPP_SCOPE_QUERY = `
47
47
  (template_argument_list) @declaration.template-arguments)
48
48
  body: (field_declaration_list)) @declaration.struct
49
49
 
50
+ ;; Declarations — struct (typedef struct { ... } Name)
51
+ (type_definition
52
+ type: (struct_specifier
53
+ body: (field_declaration_list))
54
+ declarator: (type_identifier) @declaration.name) @declaration.struct
55
+
50
56
  ;; ─── Declarations — class / struct inside template_declaration ───────
51
57
  (template_declaration
52
58
  (class_specifier
@@ -76,6 +82,12 @@ const CPP_SCOPE_QUERY = `
76
82
  (enum_specifier
77
83
  name: (type_identifier) @declaration.name) @declaration.enum
78
84
 
85
+ ;; ─── Declarations — enum (typedef enum { ... } Name) ─────────────────
86
+ (type_definition
87
+ type: (enum_specifier
88
+ body: (enumerator_list))
89
+ declarator: (type_identifier) @declaration.name) @declaration.enum
90
+
79
91
  ;; ─── Declarations — enum constants ───────────────────────────────────
80
92
  (enumerator
81
93
  name: (identifier) @declaration.name) @declaration.const
@@ -7,7 +7,7 @@ import { extractVueScript, isVueSetupTopLevel } from './vue-sfc-extractor.js';
7
7
  import { yieldToEventLoop } from './utils/event-loop.js';
8
8
  import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
9
9
  import { isVerboseIngestionEnabled } from './utils/verbose.js';
10
- import { getDefinitionNodeFromCaptures, findEnclosingClassInfo, findObjectLiteralBindingInfo, getLabelFromCaptures, CLASS_CONTAINER_TYPES, } from './utils/ast-helpers.js';
10
+ import { buildConcreteTypedefDefinitionRanges, getDefinitionNodeFromCaptures, findEnclosingClassInfo, findObjectLiteralBindingInfo, getLabelFromCaptures, isSuppressedConcreteTypedefDuplicate, CLASS_CONTAINER_TYPES, } from './utils/ast-helpers.js';
11
11
  import { detectFrameworkFromAST } from './framework-detection.js';
12
12
  import { buildTypeEnv } from './type-env.js';
13
13
  import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, parameterShapeIdTag, } from './utils/method-props.js';
@@ -356,6 +356,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
356
356
  logger.warn({ queryError }, `Query error for ${file.path}:`);
357
357
  continue;
358
358
  }
359
+ const concreteTypedefRanges = buildConcreteTypedefDefinitionRanges(matches);
359
360
  // Build per-file type environment for FieldExtractor context (lightweight — skipped if no fieldExtractor).
360
361
  //
361
362
  // Note: this TypeEnv is intentionally NOT flushed into the BindingAccumulator.
@@ -375,6 +376,8 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
375
376
  match.captures.forEach((c) => {
376
377
  captureMap[c.name] = c.node;
377
378
  });
379
+ if (isSuppressedConcreteTypedefDuplicate(captureMap, concreteTypedefRanges))
380
+ return;
378
381
  const definitionNodeForRange = getDefinitionNodeFromCaptures(captureMap);
379
382
  const definitionNode = getDefinitionNodeFromCaptures(captureMap);
380
383
  const defaultNodeLabel = getLabelFromCaptures(captureMap, provider);
@@ -24,6 +24,29 @@ type ScannedFile = {
24
24
  size: number;
25
25
  };
26
26
  type ProgressFn = (progress: PipelineProgress) => void;
27
+ /**
28
+ * Handle a worker-pool startup failure by FAILING FAST with the captured cause
29
+ * (#1741). The pool self-heals *transient* worker crashes on its own — a
30
+ * bounded, jittered startup restart loop (see worker-pool.ts) — so this is
31
+ * reached only when that self-heal is EXHAUSTED, or a deterministic crash-loop
32
+ * was detected, or the pool could not even be constructed. In every such case
33
+ * the workers genuinely cannot start.
34
+ *
35
+ * Rather than silently degrade to the ~10× slower sequential parser — which
36
+ * masked a worker-startup regression as a 2-hour "stuck" run in #1741 (rc99:
37
+ * the failure was a dropped `logger.warn` and an unbounded sequential grind) —
38
+ * GitNexus surfaces the real crash and aborts. An operator who genuinely wants
39
+ * sequential parsing asks for it explicitly with `--workers 0`.
40
+ *
41
+ * The decision is automatic: NO `--allow-sequential-fallback` or pool-sizing
42
+ * flag participates. The pool's own crash classification (`crashClass` on
43
+ * WorkerPoolInitializationError) only sharpens the message.
44
+ *
45
+ * @throws always — an actionable Error carrying the captured worker crash.
46
+ * @internal Exported for unit tests; production callers are the parse loop's
47
+ * two worker-startup catch sites below.
48
+ */
49
+ export declare function handleWorkerStartupFailure(err: Error): never;
27
50
  /**
28
51
  * Chunked parse + resolve loop.
29
52
  *
@@ -25,7 +25,7 @@ import { getLanguageFromFilename } from '../../../_shared/index.js';
25
25
  import { isRegistryPrimary } from '../registry-primary-flag.js';
26
26
  import { readFileContents } from '../filesystem-walker.js';
27
27
  import { isLanguageAvailable } from '../../tree-sitter/parser-loader.js';
28
- import { createWorkerPool, WorkerPoolInitializationError } from '../workers/worker-pool.js';
28
+ import { createWorkerPool, workerPoolDisabledByEnv, WorkerPoolInitializationError, } from '../workers/worker-pool.js';
29
29
  import { extractFetchCallsFromFiles } from '../call-processor.js';
30
30
  import fs from 'node:fs';
31
31
  import path from 'node:path';
@@ -66,6 +66,64 @@ function resolveChunkByteBudget(options) {
66
66
  return env;
67
67
  return DEFAULT_CHUNK_BYTE_BUDGET;
68
68
  }
69
+ /**
70
+ * Handle a worker-pool startup failure by FAILING FAST with the captured cause
71
+ * (#1741). The pool self-heals *transient* worker crashes on its own — a
72
+ * bounded, jittered startup restart loop (see worker-pool.ts) — so this is
73
+ * reached only when that self-heal is EXHAUSTED, or a deterministic crash-loop
74
+ * was detected, or the pool could not even be constructed. In every such case
75
+ * the workers genuinely cannot start.
76
+ *
77
+ * Rather than silently degrade to the ~10× slower sequential parser — which
78
+ * masked a worker-startup regression as a 2-hour "stuck" run in #1741 (rc99:
79
+ * the failure was a dropped `logger.warn` and an unbounded sequential grind) —
80
+ * GitNexus surfaces the real crash and aborts. An operator who genuinely wants
81
+ * sequential parsing asks for it explicitly with `--workers 0`.
82
+ *
83
+ * The decision is automatic: NO `--allow-sequential-fallback` or pool-sizing
84
+ * flag participates. The pool's own crash classification (`crashClass` on
85
+ * WorkerPoolInitializationError) only sharpens the message.
86
+ *
87
+ * @throws always — an actionable Error carrying the captured worker crash.
88
+ * @internal Exported for unit tests; production callers are the parse loop's
89
+ * two worker-startup catch sites below.
90
+ */
91
+ export function handleWorkerStartupFailure(err) {
92
+ const isInit = err instanceof WorkerPoolInitializationError;
93
+ const readinessFailures = isInit ? err.readinessFailures : [];
94
+ const crashClass = isInit ? err.crashClass : undefined;
95
+ // Surface the real cause verbatim: readiness failures for an init crash, or
96
+ // the construction error message (e.g. "Worker script not found: …") when the
97
+ // pool never got to spawn workers.
98
+ const failureDetail = readinessFailures.length > 0
99
+ ? ` Underlying worker failure(s): ${readinessFailures.join(' | ')}`
100
+ : isInit
101
+ ? ''
102
+ : ` Underlying error: ${err.message}`;
103
+ // Always surface the real crash — never let a startup failure pass silently.
104
+ logger.error({ err: err.message, readinessFailures, crashClass }, 'Worker pool failed to start — workers could not start (bounded self-heal exhausted).');
105
+ const cause = crashClass === 'deterministic-startup'
106
+ ? `every worker crashed identically during startup (a deterministic ` +
107
+ `crash-loop — retrying cannot help), so the pool has no usable workers.`
108
+ : isInit
109
+ ? `workers exhausted the bounded startup retry budget without reporting ` +
110
+ `ready, so the pool has no usable workers.`
111
+ : `the worker pool could not be constructed.`;
112
+ // Class-aware fix hint: a missing/broken native binding is the likely cause
113
+ // when workers crashed during init, but it is the WRONG guess for a pool that
114
+ // never constructed (commonly a missing build / unresolvable worker path).
115
+ const fixHint = isInit
116
+ ? `Fix the worker startup failure shown above (often a missing/broken native ` +
117
+ `binding or a top-of-script import error in parse-worker).`
118
+ : `Fix the worker pool construction error shown above (commonly a missing ` +
119
+ `build, so dist/ has no parse-worker, or an unresolvable worker path).`;
120
+ throw new Error(`Worker pool failed to start: ${cause}${failureDetail}\n\n` +
121
+ `GitNexus will NOT silently fall back to the (much slower) sequential ` +
122
+ `parser and hide this crash — that masked a worker-startup regression as ` +
123
+ `a 2-hour "stuck" run in #1741. Options:\n` +
124
+ ` • ${fixHint}\n` +
125
+ ` • Re-run with --workers 0 to parse sequentially without the worker pool.`);
126
+ }
69
127
  /**
70
128
  * Chunked parse + resolve loop.
71
129
  *
@@ -168,13 +226,26 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
168
226
  // intentionally NOT created before parse-cache lookup: a warm-cache
169
227
  // all-hit run should replay cached worker output without loading
170
228
  // parse-worker.js or any tree-sitter/N-API native bindings.
229
+ // `--workers 0` (workerPoolSize === 0) and `GITNEXUS_WORKER_POOL_SIZE=0` both
230
+ // mean "no pool, parse sequentially". The env channel is consulted ONLY when
231
+ // no explicit `--workers <N>` was given, so an explicit positive size always
232
+ // wins over an ambient env=0 (#1741). Without this, env=0 built a size-0 pool
233
+ // that failed fast with a fabricated "retry budget exhausted" crash.
234
+ const envDisablesWorkers = options?.workerPoolSize === undefined && workerPoolDisabledByEnv();
235
+ const meetsWorkerThreshold = totalParseable >= MIN_FILES_FOR_WORKERS || totalBytes >= MIN_BYTES_FOR_WORKERS;
236
+ // Log only when env=0 actually skips a pool we'd otherwise have used, so the
237
+ // undocumented (possibly accidental) env=0 case is observable instead of a
238
+ // silent degrade — small repos go sequential anyway and need no notice.
239
+ if (envDisablesWorkers && meetsWorkerThreshold) {
240
+ logger.warn('GITNEXUS_WORKER_POOL_SIZE=0 → parsing sequentially; unset it or pass --workers <N> to use the worker pool.');
241
+ }
171
242
  const shouldUseWorkers = !options?.skipWorkers &&
172
243
  options?.workerPoolSize !== 0 &&
173
- (totalParseable >= MIN_FILES_FOR_WORKERS || totalBytes >= MIN_BYTES_FOR_WORKERS);
244
+ !envDisablesWorkers &&
245
+ meetsWorkerThreshold;
174
246
  let workerPool;
175
- let workerPoolDisabled = false;
176
247
  const getOrCreateWorkerPool = () => {
177
- if (!shouldUseWorkers || workerPoolDisabled)
248
+ if (!shouldUseWorkers)
178
249
  return undefined;
179
250
  if (workerPool)
180
251
  return workerPool;
@@ -199,9 +270,11 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
199
270
  return workerPool;
200
271
  }
201
272
  catch (err) {
202
- workerPoolDisabled = true;
203
- logger.warn({ err: err.message }, 'Worker pool creation failed, using sequential fallback:');
204
- return undefined;
273
+ // Pool *construction* failed (e.g. the worker script is missing — a
274
+ // broken install). Fail fast with the cause rather than silently
275
+ // degrading to the slow sequential parser (#1741); `--workers 0` is the
276
+ // explicit opt-out for anyone who genuinely wants sequential parsing.
277
+ handleWorkerStartupFailure(err);
205
278
  }
206
279
  };
207
280
  let filesParsedSoFar = 0;
@@ -400,16 +473,15 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
400
473
  catch (err) {
401
474
  if (!(err instanceof WorkerPoolInitializationError))
402
475
  throw err;
403
- logger.warn({
404
- err: err.message,
405
- readinessFailures: err.readinessFailures,
406
- }, 'Worker pool initialization failed, using sequential fallback:');
476
+ // Every worker crashed during startup and the pool's bounded
477
+ // self-heal (jittered restart, deterministic crash-loop detection —
478
+ // see worker-pool.ts) was exhausted. Fail fast with the captured
479
+ // cause rather than silently degrading to the ~10× slower sequential
480
+ // parser, which masked this exact regression as a 2-hour "stuck" run
481
+ // in #1741. The failed (zero-worker) pool is torn down by the outer
482
+ // finally. `--workers 0` is the explicit opt-in to sequential.
407
483
  rawResults.length = 0;
408
- workerPoolDisabled = true;
409
- const failedPool = workerPool;
410
- workerPool = undefined;
411
- await failedPool?.terminate().catch(() => undefined);
412
- chunkWorkerData = await processParsing(graph, chunkFiles, symbolTable, astCache, scopeTreeCache, progressForChunk, undefined, undefined);
484
+ handleWorkerStartupFailure(err); // always throws
413
485
  }
414
486
  // Persist the raw results for this chunk hash. Sequential path
415
487
  // doesn't populate rawResults (it writes directly to graph), so
@@ -2,9 +2,9 @@ export declare const TYPESCRIPT_QUERIES = "\n(class_declaration\n name: (type_i
2
2
  export declare const JAVASCRIPT_QUERIES = "\n(class_declaration\n name: (identifier) @name) @definition.class\n\n(function_declaration\n name: (identifier) @name) @definition.function\n\n(method_definition\n name: (property_identifier) @name) @definition.method\n\n; ES2022 #private methods\n(method_definition\n name: (private_property_identifier) @name) @definition.method\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function))) @definition.function\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (arrow_function)))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (function_expression)))) @definition.function\n\n; Object-property arrows / function expressions: `{ addItem: () => ... }`.\n; See TYPESCRIPT_QUERIES for rationale (issue #1166).\n(pair\n key: (property_identifier) @name\n value: (arrow_function)) @definition.function\n\n(pair\n key: (property_identifier) @name\n value: (function_expression)) @definition.function\n\n(pair\n key: (string (string_fragment) @name)\n value: (arrow_function)) @definition.function\n\n(pair\n key: (string (string_fragment) @name)\n value: (function_expression)) @definition.function\n\n; HOC-wrapped variable declarations: `const X = HOC((args) => { ... })`.\n; See TYPESCRIPT_QUERIES section above for the full rationale (issue #1166\n; follow-up \u2014 covers forwardRef / memo / useCallback / useMemo / observer\n; / debounce / user-defined HOC factories). Both `const` and `var` forms\n; are mirrored so JS code that uses `var` (or transpiler output) gets the\n; same attribution as the registry-primary path.\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (call_expression\n arguments: (arguments\n (arrow_function))))) @definition.function\n\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (call_expression\n arguments: (arguments\n (function_expression))))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (call_expression\n arguments: (arguments\n (arrow_function)))))) @definition.function\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (call_expression\n arguments: (arguments\n (function_expression)))))) @definition.function\n\n; `var X = HOC(...)` parity with registry-primary.\n(variable_declaration\n (variable_declarator\n name: (identifier) @name\n value: (call_expression\n arguments: (arguments\n (arrow_function))))) @definition.function\n\n(variable_declaration\n (variable_declarator\n name: (identifier) @name\n value: (call_expression\n arguments: (arguments\n (function_expression))))) @definition.function\n\n; Variable/constant declarations (non-function values).\n; Overlap with @definition.function patterns is handled by parse-worker dedup.\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name)) @definition.const\n\n(export_statement\n declaration: (lexical_declaration\n (variable_declarator\n name: (identifier) @name))) @definition.const\n\n; var declarations (mutable, function-scoped)\n(variable_declaration\n (variable_declarator\n name: (identifier) @name)) @definition.variable\n\n(import_statement\n source: (string) @import.source) @import\n\n; Re-export statements: export { X } from './y'\n(export_statement\n source: (string) @import.source) @import\n\n(call_expression\n function: (identifier) @call.name) @call\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @call.name)) @call\n\n; Constructor calls: new Foo()\n(new_expression\n constructor: (identifier) @call.name) @call\n\n; Class fields \u2014 field_definition captures JS class fields (class User { address = ... })\n(field_definition\n property: (property_identifier) @name) @definition.property\n\n; Heritage queries - class extends (JavaScript uses different AST than TypeScript)\n; In tree-sitter-javascript, class_heritage directly contains the parent identifier\n(class_declaration\n name: (identifier) @heritage.class\n (class_heritage\n (identifier) @heritage.extends)) @heritage\n\n; Write access: obj.field = value\n(assignment_expression\n left: (member_expression\n object: (_) @assignment.receiver\n property: (property_identifier) @assignment.property)\n right: (_)) @assignment\n\n; Write access: obj.field += value (compound assignment)\n(augmented_assignment_expression\n left: (member_expression\n object: (_) @assignment.receiver\n property: (property_identifier) @assignment.property)\n right: (_)) @assignment\n\n; HTTP consumers: fetch('/path'), axios.get('/path'), $.get('/path'), etc.\n(call_expression\n function: (identifier) @_fetch_fn (#eq? @_fetch_fn \"fetch\")\n arguments: (arguments\n [(string (string_fragment) @route.url)\n (template_string) @route.template_url])) @route.fetch\n\n; Custom fetch wrappers: apiFetch('/path'), fetchJSON('/api/data'), httpGet('/users'), etc.\n(call_expression\n function: (identifier) @_wrapper_fn (#match? @_wrapper_fn \"^(api(Fetch|Get|Post|Put|Delete|Patch|Request)|fetch(API|JSON|Data|Endpoint|Resource|Url)|http(Fetch|Get|Post|Put|Delete|Patch|Request))$\")\n arguments: (arguments\n (string (string_fragment) @route.url))) @route.fetch\n\n; axios.get/post, $.get/post/ajax\n(call_expression\n function: (member_expression\n property: (property_identifier) @http_client.method)\n arguments: (arguments\n (string (string_fragment) @http_client.url))) @http_client\n\n; Express/Hono route registration\n(call_expression\n function: (member_expression\n property: (property_identifier) @express_route.method)\n arguments: (arguments\n (string (string_fragment) @express_route.path))) @express_route\n";
3
3
  export declare const PYTHON_QUERIES = "\n(class_definition\n name: (identifier) @name) @definition.class\n\n(function_definition\n name: (identifier) @name) @definition.function\n\n(import_statement\n name: (dotted_name) @import.source) @import\n\n; import numpy as np \u2192 aliased_import captures the module name so the\n; import path is resolved and named-binding extraction stores \"np\" \u2192 \"numpy\".\n(import_statement\n name: (aliased_import\n name: (dotted_name) @import.source)) @import\n\n(import_from_statement\n module_name: (dotted_name) @import.source) @import\n\n(import_from_statement\n module_name: (relative_import) @import.source) @import\n\n(call\n function: (identifier) @call.name) @call\n\n(call\n function: (attribute\n attribute: (identifier) @call.name)) @call\n\n; Class attribute type annotations \u2014 PEP 526: address: Address or address: Address = Address()\n; Both bare annotations (address: Address) and annotated assignments (name: str = \"test\")\n; are parsed as (assignment left: ... type: ...) in tree-sitter-python.\n(expression_statement\n (assignment\n left: (identifier) @name\n type: (type)) @definition.property)\n\n; Plain variable assignments without type annotation: x = 5, MAX_SIZE = 100\n; Overlap with @definition.property (typed) is handled by parse-worker dedup.\n(expression_statement\n (assignment\n left: (identifier) @name)) @definition.variable\n\n; Heritage queries - Python class inheritance\n(class_definition\n name: (identifier) @heritage.class\n superclasses: (argument_list\n (identifier) @heritage.extends)) @heritage\n\n; Write access: obj.field = value\n(assignment\n left: (attribute\n object: (_) @assignment.receiver\n attribute: (identifier) @assignment.property)\n right: (_)) @assignment\n\n; Write access: obj.field += value (compound assignment)\n(augmented_assignment\n left: (attribute\n object: (_) @assignment.receiver\n attribute: (identifier) @assignment.property)\n right: (_)) @assignment\n\n; Python HTTP clients: requests.get('/path'), httpx.post('/path'), session.get('/path')\n(call\n function: (attribute\n attribute: (identifier) @http_client.method)\n arguments: (argument_list\n (string (string_content) @http_client.url))) @http_client\n\n; Python decorators: @app.route, @router.get, etc.\n(decorator\n (call\n function: (attribute\n object: (identifier) @decorator.receiver\n attribute: (identifier) @decorator.name)\n arguments: (argument_list\n (string (string_content) @decorator.arg)?))) @decorator\n";
4
4
  export declare const JAVA_QUERIES = "\n; Classes, Interfaces, Enums, Annotations\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(enum_declaration name: (identifier) @name) @definition.enum\n(annotation_type_declaration name: (identifier) @name) @definition.annotation\n\n; Methods & Constructors\n(method_declaration name: (identifier) @name) @definition.method\n(constructor_declaration name: (identifier) @name) @definition.constructor\n\n; Fields \u2014 typed field declarations inside class bodies\n(field_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.property\n\n; Imports - capture any import declaration child as source\n(import_declaration (_) @import.source) @import\n\n; Calls\n(method_invocation name: (identifier) @call.name) @call\n(method_invocation object: (_) name: (identifier) @call.name) @call\n(method_reference) @call\n\n; Constructor calls: new Foo()\n(object_creation_expression type: (type_identifier) @call.name) @call\n\n; Local variable declarations inside method bodies\n(local_variable_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.variable\n\n; Heritage - extends class\n(class_declaration name: (identifier) @heritage.class\n (superclass (type_identifier) @heritage.extends)) @heritage\n\n; Heritage - implements interfaces\n(class_declaration name: (identifier) @heritage.class\n (super_interfaces (type_list (type_identifier) @heritage.implements))) @heritage.impl\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_access\n object: (_) @assignment.receiver\n field: (identifier) @assignment.property)\n right: (_)) @assignment\n";
5
- export declare const C_QUERIES = "\n; Functions (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n\n; Functions returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n\n; Functions returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n\n; Structs, Unions, Enums, Typedefs\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(union_specifier name: (type_identifier) @name) @definition.union\n(enum_specifier name: (type_identifier) @name) @definition.enum\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n\n; Variable declarations: int x = 5; or int x;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n";
5
+ export declare const C_QUERIES = "\n; Functions (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n\n; Functions returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n\n; Functions returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n\n; Structs, Unions, Enums, Typedefs\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(type_definition\n type: (struct_specifier\n body: (field_declaration_list))\n declarator: (type_identifier) @name) @definition.struct\n(union_specifier name: (type_identifier) @name) @definition.union\n(enum_specifier name: (type_identifier) @name) @definition.enum\n(type_definition\n type: (enum_specifier\n body: (enumerator_list))\n declarator: (type_identifier) @name) @definition.enum\n(enumerator name: (identifier) @name) @definition.const\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n\n; Variable declarations: int x = 5; or int x;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n";
6
6
  export declare const GO_QUERIES = "\n; Functions & Methods\n(function_declaration name: (identifier) @name) @definition.function\n(method_declaration name: (field_identifier) @name) @definition.method\n\n; Types\n(type_declaration (type_spec name: (type_identifier) @name type: (struct_type))) @definition.struct\n(type_declaration (type_spec name: (type_identifier) @name type: (interface_type))) @definition.interface\n\n; Imports\n(import_declaration (import_spec path: (interpreted_string_literal) @import.source)) @import\n(import_declaration (import_spec_list (import_spec path: (interpreted_string_literal) @import.source))) @import\n\n; Struct fields \u2014 named field declarations inside struct types\n(field_declaration_list\n (field_declaration\n name: (field_identifier) @name) @definition.property)\n\n; Struct embedding (anonymous fields = inheritance)\n(type_declaration\n (type_spec\n name: (type_identifier) @heritage.class\n type: (struct_type\n (field_declaration_list\n (field_declaration\n type: (type_identifier) @heritage.extends))))) @definition.struct\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (selector_expression field: (field_identifier) @call.name)) @call\n\n; Const/var declarations\n(const_declaration (const_spec name: (identifier) @name)) @definition.const\n(var_declaration (var_spec name: (identifier) @name)) @definition.variable\n\n; Short variable declaration: x := 5\n(short_var_declaration left: (expression_list (identifier) @name)) @definition.variable\n\n; Struct literal construction: User{Name: \"Alice\"}\n(composite_literal type: (type_identifier) @call.name) @call\n\n; Write access: obj.field = value\n(assignment_statement\n left: (expression_list\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property))\n right: (_)) @assignment\n\n; Write access: obj.field++ / obj.field--\n(inc_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n(dec_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n";
7
- export declare const CPP_QUERIES = "\n; Classes, Structs, Namespaces\n(class_specifier name: (type_identifier) @name) @definition.class\n(class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.class\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(struct_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.struct\n(namespace_definition name: (namespace_identifier) @name) @definition.namespace\n(enum_specifier name: (type_identifier) @name) @definition.enum\n\n; Typedefs and unions (common in C-style headers and mixed C/C++ code)\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n(union_specifier name: (type_identifier) @name) @definition.union\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Functions & Methods (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))) @definition.method\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (operator_name) @name))) @definition.method\n\n; Functions/methods returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n\n; Functions/methods returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))))) @definition.method\n\n; Functions/methods returning references (reference_declarator wraps function_declarator)\n(function_definition declarator: (reference_declarator (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (operator_name) @name)))) @definition.method\n\n; Destructors (destructor_name is distinct from identifier in tree-sitter-cpp)\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (destructor_name) @name))) @definition.method\n\n; Function declarations / prototypes (common in headers)\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n\n; Class/struct data member fields (Address address; int count;)\n; Uses field_identifier to exclude method declarations (which use function_declarator)\n(field_declaration\n declarator: (field_identifier) @name) @definition.property\n\n; Pointer member fields (Address* address;)\n(field_declaration\n declarator: (pointer_declarator\n declarator: (field_identifier) @name)) @definition.property\n\n; Reference member fields (Address& address;)\n(field_declaration\n declarator: (reference_declarator\n (field_identifier) @name)) @definition.property\n\n; Inline class method declarations (inside class body, no body: void save();)\n; tree-sitter-cpp uses field_identifier (not identifier) for names inside class bodies\n(field_declaration declarator: (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name)) @definition.method\n\n; Inline class method declarations returning a pointer (User* lookup();)\n(field_declaration declarator: (pointer_declarator declarator: (function_declarator declarator: [(field_identifier) (identifier)] @name))) @definition.method\n\n; Inline class method declarations returning a reference (User& lookup();)\n(field_declaration declarator: (reference_declarator (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method\n\n; Inline class method definitions (inside class body, with body: void Foo() { ... })\n(field_declaration_list\n (function_definition\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name) (destructor_name)] @name)) @definition.method)\n\n; Inline class methods returning a pointer type (User* lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (pointer_declarator\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Inline class methods returning a reference type (User& lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (reference_declarator\n (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Templates\n(template_declaration (class_specifier name: (type_identifier) @name)) @definition.template\n(template_declaration\n (class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments))) @definition.template\n(template_declaration (function_definition declarator: (function_declarator declarator: (identifier) @name))) @definition.template\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (qualified_identifier name: (identifier) @call.name)) @call\n(call_expression function: (template_function name: (identifier) @call.name)) @call\n(binary_expression operator: \"+\" @call.name) @call\n(binary_expression operator: \"<<\" @call.name) @call\n\n; Constructor calls: new User()\n(new_expression type: (type_identifier) @call.name) @call\n\n; Variable declarations: int x = 5; or auto x = 5;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n\n; Heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (type_identifier) @heritage.extends)) @heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (access_specifier) (type_identifier) @heritage.extends)) @heritage\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_expression\n argument: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n\n";
7
+ export declare const CPP_QUERIES = "\n; Classes, Structs, Namespaces\n(class_specifier name: (type_identifier) @name) @definition.class\n(class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.class\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(struct_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.struct\n(namespace_definition name: (namespace_identifier) @name) @definition.namespace\n(enum_specifier name: (type_identifier) @name) @definition.enum\n\n; Typedefs and unions (common in C-style headers and mixed C/C++ code)\n(type_definition\n type: (struct_specifier\n body: (field_declaration_list))\n declarator: (type_identifier) @name) @definition.struct\n(type_definition\n type: (enum_specifier\n body: (enumerator_list))\n declarator: (type_identifier) @name) @definition.enum\n(enumerator name: (identifier) @name) @definition.const\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n(union_specifier name: (type_identifier) @name) @definition.union\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Functions & Methods (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))) @definition.method\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (operator_name) @name))) @definition.method\n\n; Functions/methods returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n\n; Functions/methods returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))))) @definition.method\n\n; Functions/methods returning references (reference_declarator wraps function_declarator)\n(function_definition declarator: (reference_declarator (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (operator_name) @name)))) @definition.method\n\n; Destructors (destructor_name is distinct from identifier in tree-sitter-cpp)\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (destructor_name) @name))) @definition.method\n\n; Function declarations / prototypes (common in headers)\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n\n; Class/struct data member fields (Address address; int count;)\n; Uses field_identifier to exclude method declarations (which use function_declarator)\n(field_declaration\n declarator: (field_identifier) @name) @definition.property\n\n; Pointer member fields (Address* address;)\n(field_declaration\n declarator: (pointer_declarator\n declarator: (field_identifier) @name)) @definition.property\n\n; Reference member fields (Address& address;)\n(field_declaration\n declarator: (reference_declarator\n (field_identifier) @name)) @definition.property\n\n; Inline class method declarations (inside class body, no body: void save();)\n; tree-sitter-cpp uses field_identifier (not identifier) for names inside class bodies\n(field_declaration declarator: (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name)) @definition.method\n\n; Inline class method declarations returning a pointer (User* lookup();)\n(field_declaration declarator: (pointer_declarator declarator: (function_declarator declarator: [(field_identifier) (identifier)] @name))) @definition.method\n\n; Inline class method declarations returning a reference (User& lookup();)\n(field_declaration declarator: (reference_declarator (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method\n\n; Inline class method definitions (inside class body, with body: void Foo() { ... })\n(field_declaration_list\n (function_definition\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name) (destructor_name)] @name)) @definition.method)\n\n; Inline class methods returning a pointer type (User* lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (pointer_declarator\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Inline class methods returning a reference type (User& lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (reference_declarator\n (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Templates\n(template_declaration (class_specifier name: (type_identifier) @name)) @definition.template\n(template_declaration\n (class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments))) @definition.template\n(template_declaration (function_definition declarator: (function_declarator declarator: (identifier) @name))) @definition.template\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (qualified_identifier name: (identifier) @call.name)) @call\n(call_expression function: (template_function name: (identifier) @call.name)) @call\n(binary_expression operator: \"+\" @call.name) @call\n(binary_expression operator: \"<<\" @call.name) @call\n\n; Constructor calls: new User()\n(new_expression type: (type_identifier) @call.name) @call\n\n; Variable declarations: int x = 5; or auto x = 5;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n\n; Heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (type_identifier) @heritage.extends)) @heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (access_specifier) (type_identifier) @heritage.extends)) @heritage\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_expression\n argument: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n\n";
8
8
  export declare const CSHARP_QUERIES = "\n; Types\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(struct_declaration name: (identifier) @name) @definition.struct\n(enum_declaration name: (identifier) @name) @definition.enum\n(record_declaration name: (identifier) @name) @definition.record\n(delegate_declaration name: (identifier) @name) @definition.delegate\n\n; Namespaces (block form and C# 10+ file-scoped form)\n(namespace_declaration name: (identifier) @name) @definition.namespace\n(namespace_declaration name: (qualified_name) @name) @definition.namespace\n(file_scoped_namespace_declaration name: (identifier) @name) @definition.namespace\n(file_scoped_namespace_declaration name: (qualified_name) @name) @definition.namespace\n\n; Methods & Properties\n(method_declaration name: (identifier) @name) @definition.method\n(local_function_statement name: (identifier) @name) @definition.function\n(constructor_declaration name: (identifier) @name) @definition.constructor\n(property_declaration name: (identifier) @name) @definition.property\n\n; Primary constructors (C# 12): class User(string name, int age) { }\n(class_declaration name: (identifier) @name (parameter_list) @definition.constructor)\n(record_declaration name: (identifier) @name (parameter_list) @definition.constructor)\n\n; Using\n(using_directive (qualified_name) @import.source) @import\n(using_directive (identifier) @import.source) @import\n\n; Calls\n(invocation_expression function: (identifier) @call.name) @call\n(invocation_expression function: (member_access_expression name: (identifier) @call.name)) @call\n\n; Null-conditional method calls: user?.Save()\n; Parses as: invocation_expression \u2192 conditional_access_expression \u2192 member_binding_expression \u2192 identifier\n(invocation_expression\n function: (conditional_access_expression\n (member_binding_expression\n (identifier) @call.name))) @call\n\n; Constructor calls: new Foo() and new Foo { Props }\n(object_creation_expression type: (identifier) @call.name) @call\n\n; Target-typed new (C# 9): User u = new(\"x\", 5)\n(variable_declaration type: (identifier) @call.name (variable_declarator (implicit_object_creation_expression) @call))\n\n; Local variable declarations\n(local_declaration_statement\n (variable_declaration\n (variable_declarator\n (identifier) @name))) @definition.variable\n\n; Heritage\n(class_declaration name: (identifier) @heritage.class\n (base_list (identifier) @heritage.extends)) @heritage\n(class_declaration name: (identifier) @heritage.class\n (base_list (generic_name (identifier) @heritage.extends))) @heritage\n\n; Interface inheritance: interface IFoo : IBar / interface IFoo : IBar, IBaz\n; Without these patterns, interface-to-interface relationships are never\n; captured, so transitive \"class X implements IBar\" chains are broken.\n(interface_declaration name: (identifier) @heritage.class\n (base_list (identifier) @heritage.extends)) @heritage\n(interface_declaration name: (identifier) @heritage.class\n (base_list (generic_name (identifier) @heritage.extends))) @heritage\n\n; Write access: obj.field = value\n(assignment_expression\n left: (member_access_expression\n expression: (_) @assignment.receiver\n name: (identifier) @assignment.property)\n right: (_)) @assignment\n";
9
9
  export declare const RUST_QUERIES = "\n; Functions & Items\n(function_item name: (identifier) @name) @definition.function\n(function_signature_item name: (identifier) @name) @definition.function\n(struct_item name: (type_identifier) @name) @definition.struct\n(enum_item name: (type_identifier) @name) @definition.enum\n(trait_item name: (type_identifier) @name) @definition.trait\n(impl_item type: (type_identifier) @name !trait) @definition.impl\n(impl_item type: (generic_type type: (type_identifier) @name) !trait) @definition.impl\n(mod_item name: (identifier) @name) @definition.module\n\n; Type aliases, const, static, macros\n(type_item name: (type_identifier) @name) @definition.type\n(const_item name: (identifier) @name) @definition.const\n(static_item name: (identifier) @name) @definition.static\n(macro_definition name: (identifier) @name) @definition.macro\n\n; Use statements\n(use_declaration argument: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (scoped_identifier name: (identifier) @call.name)) @call\n(call_expression function: (generic_function function: (identifier) @call.name)) @call\n\n; Struct literal construction: User { name: value }\n(struct_expression name: (type_identifier) @call.name) @call\n\n; Struct fields \u2014 named field declarations inside struct bodies\n(field_declaration_list\n (field_declaration\n name: (field_identifier) @name) @definition.property)\n\n; Heritage (trait implementation) \u2014 all combinations of concrete/generic trait \u00D7 concrete/generic type\n(impl_item trait: (type_identifier) @heritage.trait type: (type_identifier) @heritage.class) @heritage\n(impl_item trait: (generic_type type: (type_identifier) @heritage.trait) type: (type_identifier) @heritage.class) @heritage\n(impl_item trait: (type_identifier) @heritage.trait type: (generic_type type: (type_identifier) @heritage.class)) @heritage\n(impl_item trait: (generic_type type: (type_identifier) @heritage.trait) type: (generic_type type: (type_identifier) @heritage.class)) @heritage\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_expression\n value: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n\n; Write access: obj.field += value (compound assignment)\n(compound_assignment_expr\n left: (field_expression\n value: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n";
10
10
  export declare const PHP_QUERIES = "\n; \u2500\u2500 Namespace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(namespace_definition\n name: (namespace_name) @name) @definition.namespace\n\n; \u2500\u2500 Classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @name) @definition.class\n\n; \u2500\u2500 Interfaces \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(interface_declaration\n name: (name) @name) @definition.interface\n\n; \u2500\u2500 Traits \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(trait_declaration\n name: (name) @name) @definition.trait\n\n; \u2500\u2500 Enums (PHP 8.1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(enum_declaration\n name: (name) @name) @definition.enum\n\n; \u2500\u2500 Top-level functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(function_definition\n name: (name) @name) @definition.function\n\n; \u2500\u2500 Methods (including constructors) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(method_declaration\n name: (name) @name) @definition.method\n\n; \u2500\u2500 Class properties (including Eloquent $fillable, $casts, etc.) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(property_declaration\n (property_element\n (variable_name\n (name) @name))) @definition.property\n\n; Constructor property promotion (PHP 8.0+: public Address $address in __construct)\n(method_declaration\n parameters: (formal_parameters\n (property_promotion_parameter\n name: (variable_name\n (name) @name)))) @definition.property\n\n; \u2500\u2500 Imports: use statements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; Simple: use App\\Models\\User;\n(namespace_use_declaration\n (namespace_use_clause\n (qualified_name) @import.source)) @import\n\n; \u2500\u2500 Function/method calls \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; Regular function call: foo()\n(function_call_expression\n function: (name) @call.name) @call\n\n; Method call: $obj->method()\n(member_call_expression\n name: (name) @call.name) @call\n\n; Nullsafe method call: $obj?->method()\n(nullsafe_member_call_expression\n name: (name) @call.name) @call\n\n; Static call: Foo::bar() (php_only uses scoped_call_expression)\n(scoped_call_expression\n name: (name) @call.name) @call\n\n; Constructor call: new User()\n(object_creation_expression (name) @call.name) @call\n\n; Const declarations at class scope\n(const_declaration\n (const_element\n (name) @name)) @definition.const\n\n; \u2500\u2500 Heritage: extends \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @heritage.class\n (base_clause\n [(name) (qualified_name)] @heritage.extends)) @heritage\n\n; \u2500\u2500 Heritage: implements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @heritage.class\n (class_interface_clause\n [(name) (qualified_name)] @heritage.implements)) @heritage.impl\n\n; \u2500\u2500 Heritage: use trait (must capture enclosing class name) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @heritage.class\n body: (declaration_list\n (use_declaration\n [(name) (qualified_name)] @heritage.trait))) @heritage\n\n; \u2500\u2500 Heritage: trait uses another trait (transitive trait composition) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; PHP allows a trait body to contain \"use OtherTrait;\". The trait-uses-trait\n; IMPLEMENTS edge is required by buildPhpMro to compute the full transitive\n; trait closure (depth 3+ chains).\n(trait_declaration\n name: (name) @heritage.class\n body: (declaration_list\n (use_declaration\n [(name) (qualified_name)] @heritage.trait))) @heritage\n\n; PHP HTTP consumers: file_get_contents('/path'), curl_init('/path')\n(function_call_expression\n function: (name) @_php_http (#match? @_php_http \"^(file_get_contents|curl_init)$\")\n arguments: (arguments\n (argument (string (string_content) @http_client.url)))) @http_client\n\n; Write access: $obj->field = value\n(assignment_expression\n left: (member_access_expression\n object: (_) @assignment.receiver\n name: (name) @assignment.property)\n right: (_)) @assignment\n\n; Write access: ClassName::$field = value (static property)\n(assignment_expression\n left: (scoped_property_access_expression\n scope: (_) @assignment.receiver\n name: (variable_name (name) @assignment.property))\n right: (_)) @assignment\n";
@@ -601,8 +601,17 @@ export const C_QUERIES = `
601
601
 
602
602
  ; Structs, Unions, Enums, Typedefs
603
603
  (struct_specifier name: (type_identifier) @name) @definition.struct
604
+ (type_definition
605
+ type: (struct_specifier
606
+ body: (field_declaration_list))
607
+ declarator: (type_identifier) @name) @definition.struct
604
608
  (union_specifier name: (type_identifier) @name) @definition.union
605
609
  (enum_specifier name: (type_identifier) @name) @definition.enum
610
+ (type_definition
611
+ type: (enum_specifier
612
+ body: (enumerator_list))
613
+ declarator: (type_identifier) @name) @definition.enum
614
+ (enumerator name: (identifier) @name) @definition.const
606
615
  (type_definition declarator: (type_identifier) @name) @definition.typedef
607
616
 
608
617
  ; Macros
@@ -698,6 +707,15 @@ export const CPP_QUERIES = `
698
707
  (enum_specifier name: (type_identifier) @name) @definition.enum
699
708
 
700
709
  ; Typedefs and unions (common in C-style headers and mixed C/C++ code)
710
+ (type_definition
711
+ type: (struct_specifier
712
+ body: (field_declaration_list))
713
+ declarator: (type_identifier) @name) @definition.struct
714
+ (type_definition
715
+ type: (enum_specifier
716
+ body: (enumerator_list))
717
+ declarator: (type_identifier) @name) @definition.enum
718
+ (enumerator name: (identifier) @name) @definition.const
701
719
  (type_definition declarator: (type_identifier) @name) @definition.typedef
702
720
  (union_specifier name: (type_identifier) @name) @definition.union
703
721
 
@@ -10,6 +10,14 @@ export type SyntaxNode = Parser.SyntaxNode;
10
10
  export declare const DEFINITION_CAPTURE_KEYS: readonly ["definition.function", "definition.class", "definition.interface", "definition.method", "definition.struct", "definition.enum", "definition.namespace", "definition.module", "definition.trait", "definition.impl", "definition.type", "definition.const", "definition.static", "definition.variable", "definition.typedef", "definition.macro", "definition.union", "definition.property", "definition.record", "definition.delegate", "definition.annotation", "definition.constructor", "definition.template"];
11
11
  /** Extract the definition node from a tree-sitter query capture map. */
12
12
  export declare const getDefinitionNodeFromCaptures: (captureMap: Record<string, SyntaxNode>) => SyntaxNode | null;
13
+ type QueryMatchLike = {
14
+ captures: Array<{
15
+ name: string;
16
+ node: SyntaxNode;
17
+ }>;
18
+ };
19
+ export declare const buildConcreteTypedefDefinitionRanges: (matches: readonly QueryMatchLike[]) => Set<string>;
20
+ export declare const isSuppressedConcreteTypedefDuplicate: (captureMap: Record<string, SyntaxNode>, concreteTypedefRanges: ReadonlySet<string>) => boolean;
13
21
  /**
14
22
  * Node types that represent function/method definitions across languages.
15
23
  * Used by parent-walk in call-processor, parse-worker, and type-env to detect
@@ -144,3 +152,4 @@ export declare function findNodeAtRange(root: SyntaxNode, range: Range, expected
144
152
  * Used by every language's scope-capture path (go/python/ruby/php/rust/csharp).
145
153
  */
146
154
  export declare function nodeIfType<T extends SyntaxNode>(node: T | undefined, ...types: readonly string[]): T | null;
155
+ export {};
@@ -37,6 +37,32 @@ export const getDefinitionNodeFromCaptures = (captureMap) => {
37
37
  }
38
38
  return null;
39
39
  };
40
+ const nodeRangeKey = (node) => `${node.startPosition.row}:${node.startPosition.column}:${node.endPosition.row}:${node.endPosition.column}`;
41
+ const isConcreteTypedefCapture = (captureMap) => {
42
+ const definitionNode = getDefinitionNodeFromCaptures(captureMap);
43
+ return (definitionNode?.type === 'type_definition' &&
44
+ (captureMap['definition.struct'] !== undefined || captureMap['definition.enum'] !== undefined));
45
+ };
46
+ export const buildConcreteTypedefDefinitionRanges = (matches) => {
47
+ const ranges = new Set();
48
+ for (const match of matches) {
49
+ const captureMap = {};
50
+ for (const capture of match.captures) {
51
+ captureMap[capture.name] = capture.node;
52
+ }
53
+ const definitionNode = getDefinitionNodeFromCaptures(captureMap);
54
+ if (definitionNode && isConcreteTypedefCapture(captureMap)) {
55
+ ranges.add(nodeRangeKey(definitionNode));
56
+ }
57
+ }
58
+ return ranges;
59
+ };
60
+ export const isSuppressedConcreteTypedefDuplicate = (captureMap, concreteTypedefRanges) => {
61
+ const definitionNode = getDefinitionNodeFromCaptures(captureMap);
62
+ return (definitionNode?.type === 'type_definition' &&
63
+ captureMap['definition.typedef'] !== undefined &&
64
+ concreteTypedefRanges.has(nodeRangeKey(definitionNode)));
65
+ };
40
66
  /**
41
67
  * Node types that represent function/method definitions across languages.
42
68
  * Used by parent-walk in call-processor, parse-worker, and type-env to detect