@mnemonik/shared 6.50.0 → 6.51.0

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.
Files changed (60) hide show
  1. package/dist/ast/astChunker.d.ts +124 -0
  2. package/dist/ast/astChunker.d.ts.map +1 -0
  3. package/dist/ast/astChunker.js +559 -0
  4. package/dist/ast/astChunker.js.map +1 -0
  5. package/dist/ast/grammars.d.ts +170 -0
  6. package/dist/ast/grammars.d.ts.map +1 -0
  7. package/dist/ast/grammars.js +411 -0
  8. package/dist/ast/grammars.js.map +1 -0
  9. package/dist/codeScanner.d.ts +59 -0
  10. package/dist/codeScanner.d.ts.map +1 -1
  11. package/dist/codeScanner.js +259 -2
  12. package/dist/codeScanner.js.map +1 -1
  13. package/dist/index.d.ts +3 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +3 -1
  16. package/dist/index.js.map +1 -1
  17. package/package.json +3 -2
  18. package/queries/bash.tags.scm +7 -0
  19. package/queries/groovy.tags.scm +15 -0
  20. package/queries/powershell.tags.scm +14 -0
  21. package/scripts/vendor-grammars.ts +317 -0
  22. package/src/ast/astChunker.ts +661 -0
  23. package/src/ast/grammars.ts +490 -0
  24. package/src/codeScanner.ts +273 -3
  25. package/src/index.ts +22 -0
  26. package/wasm/bash.tags.scm +7 -0
  27. package/wasm/bash.wasm +0 -0
  28. package/wasm/c-sharp.tags.scm +23 -0
  29. package/wasm/c-sharp.wasm +0 -0
  30. package/wasm/c.tags.scm +9 -0
  31. package/wasm/c.wasm +0 -0
  32. package/wasm/cpp.tags.scm +15 -0
  33. package/wasm/cpp.wasm +0 -0
  34. package/wasm/elixir.tags.scm +54 -0
  35. package/wasm/elixir.wasm +0 -0
  36. package/wasm/go.tags.scm +42 -0
  37. package/wasm/go.wasm +0 -0
  38. package/wasm/groovy.tags.scm +15 -0
  39. package/wasm/groovy.wasm +0 -0
  40. package/wasm/java.tags.scm +20 -0
  41. package/wasm/java.wasm +0 -0
  42. package/wasm/javascript.tags.scm +99 -0
  43. package/wasm/javascript.wasm +0 -0
  44. package/wasm/php.tags.scm +40 -0
  45. package/wasm/php.wasm +0 -0
  46. package/wasm/powershell.tags.scm +14 -0
  47. package/wasm/powershell.wasm +0 -0
  48. package/wasm/python.tags.scm +14 -0
  49. package/wasm/python.wasm +0 -0
  50. package/wasm/ruby.tags.scm +64 -0
  51. package/wasm/ruby.wasm +0 -0
  52. package/wasm/rust.tags.scm +60 -0
  53. package/wasm/rust.wasm +0 -0
  54. package/wasm/scala.tags.scm +66 -0
  55. package/wasm/scala.wasm +0 -0
  56. package/wasm/solidity.tags.scm +43 -0
  57. package/wasm/solidity.wasm +0 -0
  58. package/wasm/tsx.wasm +0 -0
  59. package/wasm/typescript.tags.scm +23 -0
  60. package/wasm/typescript.wasm +0 -0
@@ -0,0 +1,559 @@
1
+ /**
2
+ * The AST chunker: source text in, named line-ranges out. No filesystem, no
3
+ * logging of file contents, one pure entry point (`chunkWithAst`).
4
+ *
5
+ * WHY THIS EXISTS. The heuristic chunker matches a regex whose name pattern
6
+ * requires a leading `function`/`class`/`const` keyword — a keyword a method's
7
+ * first line never has. So it produces method-shaped chunks with no
8
+ * `symbolName`: 1,512 methods in this repo, unnameable and therefore unusable
9
+ * as citation anchors. Measured over the same 1,037 TypeScript files, the
10
+ * heuristic named 16.9% of its 16,604 chunks; the tag queries name 100% of
11
+ * 6,471 definitions.
12
+ *
13
+ * THE NESTING RULE. Emitting both a whole class and each of its methods would
14
+ * duplicate every method body and double the embedding bill, so:
15
+ *
16
+ * - a STRUCTURAL definition — one whose body is a container of other definitions
17
+ * (class, interface, enum, struct, trait, object, module, namespace) — emits a
18
+ * HEADER chunk from its own first line to the line before its first nested
19
+ * definition: the declaration plus the fields that precede the first method.
20
+ * Real contiguous source, never an elision;
21
+ * - every other definition is a LEAF and becomes one chunk over its FULL line
22
+ * range, whatever it happens to contain. A local arrow function is part of
23
+ * what the enclosing function IS, not a sibling of it, so definitions nested
24
+ * inside a leaf are not emitted separately — the leaf's chunk already carries
25
+ * their source verbatim. See `STRUCTURAL_KINDS` for why that distinction is
26
+ * load-bearing rather than cosmetic;
27
+ * - every remaining uncovered line span becomes a `raw` chunk.
28
+ *
29
+ * Coverage is therefore total: every non-blank line of a file belongs to some
30
+ * chunk, replacing the ~50% coverage of the old heuristic and giving citation
31
+ * anchoring a line -> chunk map with no holes.
32
+ *
33
+ * A NEWLINE IS A TERMINATOR, NOT A LINE. `'...}\n'.split('\n')` yields a phantom
34
+ * trailing `''` that is not a line of the file. It is dropped before any length
35
+ * arithmetic, because `memory_file_index.end_line` feeds citation anchoring and
36
+ * the golden eval's containment scoring, and a one-line drift misaligns both
37
+ * silently.
38
+ *
39
+ * CHUNKS ARE LINE-GRANULAR, NOT BYTE-GRANULAR. A chunk's content is always
40
+ * `lines.slice(startLine - 1, endLine).join('\n')`. That is deliberate: the tag
41
+ * queries capture `class_declaration`, which starts at `class` and excludes the
42
+ * `export ` in front of it, and a citation anchor that omitted `export` would
43
+ * not match what a reader sees. Line granularity also keeps content verbatim
44
+ * and contiguous by construction.
45
+ *
46
+ * SYMBOL NAMES ARE BARE. `verifyForFile`, not `CitationManager.verifyForFile`.
47
+ * `memory_file_index.symbol_name` is one column with a partial index on
48
+ * `(project_id, symbol_name)` and citations reference bare names; storing
49
+ * qualified names would break lookup. Qualified names are a deliberate
50
+ * deferral — see the plan's Task 11 gate.
51
+ *
52
+ * WASM MEMORY IS NOT GC'd BY THE JS HEAP. Every `Tree` and `TreeCursor` created
53
+ * here is explicitly deleted in a `finally`. Skipping that leaks across a
54
+ * whole-repo walk in a long-lived daemon (the scanner is one).
55
+ */
56
+ import { Parser } from 'web-tree-sitter';
57
+ import { loadGrammar } from './grammars.js';
58
+ /**
59
+ * Parse ceiling, derived from Task 4's measurement rather than guessed: the
60
+ * largest source file in this repo is 415 KB (`src/agent/ContextAgent.ts`) and
61
+ * the slowest per-file parse across 1,061 files was 108.6 ms. 2 MiB is ~5x that
62
+ * largest real file, which bounds the worst case near half a second — while
63
+ * still refusing the multi-megabyte generated blobs that `MAX_SCANNED_FILE_BYTES`
64
+ * (10 MB) otherwise lets through. Above the ceiling the caller degrades to the
65
+ * heuristic chunker, which is line-bounded and cheap.
66
+ */
67
+ export const MAX_AST_PARSE_BYTES = 2 * 1024 * 1024;
68
+ /**
69
+ * Line budget for a single `raw` span chunk, mirroring `ScanOptions.maxChunkSize`
70
+ * (8000 chars, ~2000 tokens) so AST raw spans and heuristic raw chunks land in
71
+ * the same size class.
72
+ */
73
+ const MAX_RAW_SPAN_CHARS = 8000;
74
+ const MAX_SIGNATURE_CHARS = 500;
75
+ /**
76
+ * `definition.<kind>` -> the wire enum. `chunkType` is constrained to
77
+ * `function|class|module|raw` by `CodeChunk` and by `scanChunkSchema`;
78
+ * `symbolKind` is not, and keeps the capture name verbatim.
79
+ *
80
+ * Kinds absent here (`constant`, `field`, `property`, `variable`) fall to
81
+ * `'raw'`: the enum has no value-shaped member, and claiming a constant is a
82
+ * `class` or a `module` would be false where `'raw'` only says "no coarse class
83
+ * for this" — the identity is still carried by `symbolName` + `symbolKind`.
84
+ */
85
+ const CHUNK_TYPE_BY_KIND = {
86
+ function: 'function',
87
+ method: 'function',
88
+ macro: 'function',
89
+ class: 'class',
90
+ interface: 'class',
91
+ enum: 'class',
92
+ object: 'class',
93
+ struct: 'class',
94
+ trait: 'class',
95
+ type: 'class',
96
+ module: 'module',
97
+ namespace: 'module',
98
+ };
99
+ /**
100
+ * Kinds whose BODY IS A CONTAINER of other definitions. Only these split into a
101
+ * header chunk; every other kind is a LEAF and gets its full line range.
102
+ *
103
+ * The distinction is load-bearing, not cosmetic. When every `definition.*`
104
+ * capture counted as a nested child, a function declaring one local arrow
105
+ * function collapsed to its first two lines: `ContextAgent.registerDocsTools`
106
+ * spans 513 lines and was recorded as 2. A wrong extent is worse than no extent —
107
+ * it anchors citations confidently at the wrong place instead of failing to
108
+ * anchor them.
109
+ *
110
+ * A closure, a variable, a constant, a field and a property are VALUE-SHAPED:
111
+ * they are part of what the enclosing definition IS. So is a nested helper
112
+ * function. Definitions inside a leaf are therefore not emitted at all; the
113
+ * leaf's own chunk carries their source verbatim, and emitting both would
114
+ * duplicate it and double the embedding bill.
115
+ *
116
+ * `type` stays out deliberately. C's `(type_definition declarator:
117
+ * (type_identifier) @name) @definition.type` matches `typedef struct {...} Foo;`,
118
+ * whose nested `struct_specifier` opens on the typedef's own first line — as a
119
+ * container it would split to an empty header and be dropped entirely, so the
120
+ * typedef is the leaf and keeps the whole range.
121
+ */
122
+ const STRUCTURAL_KINDS = new Set([
123
+ 'class',
124
+ 'interface',
125
+ 'enum',
126
+ 'struct',
127
+ 'trait',
128
+ 'object',
129
+ 'module',
130
+ 'namespace',
131
+ ]);
132
+ /**
133
+ * One `Parser` per language for the life of the process. Constructing a parser
134
+ * per file allocates and frees a wasm parser object 30,000 times on a repo walk
135
+ * for no benefit; the parse itself is synchronous and stateless once the
136
+ * language is set.
137
+ */
138
+ const parsers = new Map();
139
+ function parserFor(binding) {
140
+ const cached = parsers.get(binding.id);
141
+ if (cached)
142
+ return cached;
143
+ // `Parser.init()` has already run: `loadGrammar` awaits it before
144
+ // `Language.load`, and we only get a binding after that succeeded.
145
+ const parser = new Parser();
146
+ parser.setLanguage(binding.language);
147
+ parsers.set(binding.id, parser);
148
+ return parser;
149
+ }
150
+ /**
151
+ * Chunk `content` by syntax for a language with a vendored grammar.
152
+ *
153
+ * Async only because `loadGrammar` is; the grammar is cached per process, so
154
+ * after the first file of a given language there is no per-file async cost.
155
+ * Never throws — every failure is a named `unsupported` reason with a detail the
156
+ * caller can log before degrading.
157
+ */
158
+ export async function chunkWithAst(content, languageId, opts) {
159
+ // Size first: refusing a 6 MB generated file must not first instantiate a
160
+ // 5 MB grammar we then throw away.
161
+ const ceiling = opts?.maxParseBytes ?? MAX_AST_PARSE_BYTES;
162
+ const bytes = Buffer.byteLength(content, 'utf8');
163
+ if (bytes > ceiling) {
164
+ return {
165
+ unsupported: 'file_too_large',
166
+ detail: `${bytes} bytes exceeds the AST parse ceiling of ${ceiling} bytes`,
167
+ };
168
+ }
169
+ const loaded = await loadGrammar(languageId);
170
+ if ('unavailable' in loaded) {
171
+ return {
172
+ unsupported: 'grammar_unavailable',
173
+ detail: `${String(languageId)}: ${loaded.unavailable}: ${loaded.detail}`,
174
+ };
175
+ }
176
+ const startedAt = performance.now();
177
+ let tree;
178
+ try {
179
+ tree = parserFor(loaded.ok).parse(content);
180
+ }
181
+ catch (err) {
182
+ return {
183
+ unsupported: 'parse_failed',
184
+ detail: `${languageId}: web-tree-sitter threw while parsing ${bytes} bytes: ${describe(err)}`,
185
+ };
186
+ }
187
+ if (!tree) {
188
+ // Documented return value of `Parser.parse`, not a theoretical branch: it
189
+ // is null when the parse is cancelled or the language is unset.
190
+ return {
191
+ unsupported: 'parse_failed',
192
+ detail: `${languageId}: web-tree-sitter returned no tree for ${bytes} bytes`,
193
+ };
194
+ }
195
+ const parseMs = performance.now() - startedAt;
196
+ try {
197
+ const lines = content.split('\n');
198
+ // A trailing newline TERMINATES the last line, it does not open a new one,
199
+ // but `split` yields a phantom '' for it. Dropping it here — before
200
+ // `lines.length` is read by the coverage array, `uncoveredSpans` or
201
+ // `sliceLines` — is what keeps `endLine` equal to the file's last line
202
+ // number. Left in, the final raw chunk of every newline-terminated file (109
203
+ // of this repo's 268 `src/` TypeScript files) ran one line past the end, and
204
+ // `memory_file_index.end_line` feeds citation anchoring and the golden eval's
205
+ // containment scoring.
206
+ if (content.endsWith('\n'))
207
+ lines.pop();
208
+ const collected = collectDefinitions(loaded.ok.query, tree.rootNode);
209
+ const built = buildChunks(collected.definitions, lines);
210
+ return {
211
+ chunks: built.chunks,
212
+ errorNodes: countErrorNodes(tree),
213
+ parseMs,
214
+ // A definition can be lost at either stage — collapsed onto another
215
+ // definition's byte range here, or reaching no chunk in `buildChunks` — and
216
+ // the caller logs one number, so both have to be in it.
217
+ droppedDefinitions: built.droppedDefinitions + collected.collapsedDefinitions,
218
+ };
219
+ }
220
+ finally {
221
+ tree.delete();
222
+ }
223
+ }
224
+ /**
225
+ * Every `definition.*` capture with its paired `@name`, outermost first.
226
+ *
227
+ * `matches()` rather than `captures()`: a match is one pattern's captures, so
228
+ * the `@name` belonging to a definition is unambiguous. `captures()` returns a
229
+ * flat stream in which pairing is guesswork — and the composed QUERY_CHAIN
230
+ * concatenates several files' patterns, so guessing would mispair across
231
+ * grammars.
232
+ */
233
+ function collectDefinitions(query, root) {
234
+ // Keyed by byte range: the composed chain can match one node from two
235
+ // patterns (javascript's `class` and `class_declaration` alternates, for
236
+ // instance), and two chunks over one range would collide on
237
+ // `filePath:startLine-endLine`, the key ProjectManager uses for staleness.
238
+ const byRange = new Map();
239
+ let collapsedDefinitions = 0;
240
+ for (const match of query.matches(root)) {
241
+ let definition;
242
+ let kind = '';
243
+ let name;
244
+ for (const capture of match.captures) {
245
+ if (!definition && capture.name.startsWith('definition.')) {
246
+ definition = capture.node;
247
+ kind = capture.name.slice('definition.'.length);
248
+ }
249
+ else if (!name && capture.name === 'name') {
250
+ name = capture.node;
251
+ }
252
+ }
253
+ if (!definition)
254
+ continue;
255
+ const extent = widenToDefinition(definition);
256
+ const key = `${extent.startIndex}:${extent.endIndex}`;
257
+ // A `@name` from outside the definition's extent would be a query bug;
258
+ // dropping it costs a name, keeping it would attach a wrong one.
259
+ const named = name && name.startIndex >= extent.startIndex && name.endIndex <= extent.endIndex
260
+ ? name.text
261
+ : undefined;
262
+ const existing = byRange.get(key);
263
+ if (existing) {
264
+ // Two names over one range means a real symbol is gone from
265
+ // `memory_file_index`, and a citation to it will resolve as
266
+ // `unresolved_symbol`; the same name twice means the same symbol twice.
267
+ if (named !== undefined && existing.name !== undefined && existing.name !== named) {
268
+ collapsedDefinitions++;
269
+ }
270
+ continue;
271
+ }
272
+ byRange.set(key, {
273
+ startIndex: extent.startIndex,
274
+ endIndex: extent.endIndex,
275
+ startRow: extent.startPosition.row,
276
+ endRow: extent.endPosition.row,
277
+ kind,
278
+ ...(named ? { name: named } : {}),
279
+ });
280
+ }
281
+ // Start ascending, end descending: a parent therefore always precedes the
282
+ // children it contains, which is what makes the single-pass stack below
283
+ // correct.
284
+ const definitions = [...byRange.values()].sort((a, b) => a.startIndex === b.startIndex ? b.endIndex - a.endIndex : a.startIndex - b.startIndex);
285
+ return { definitions, collapsedDefinitions };
286
+ }
287
+ /**
288
+ * Ascend from a `@definition.*` capture to the node that actually SPANS the
289
+ * definition.
290
+ *
291
+ * Some tag queries bind the capture to a node that names the definition without
292
+ * containing its body. `c.tags.scm` and `cpp.tags.scm` are the loud case:
293
+ *
294
+ * (function_declarator declarator: (identifier) @name) @definition.function
295
+ *
296
+ * `function_declarator` ends at the closing paren of the parameter list, so
297
+ * naming it alone reproduces — for two whole languages — the exact defect this
298
+ * module exists to fix: a named signature line plus an anonymous raw chunk
299
+ * holding the body.
300
+ *
301
+ * The rule is general rather than a C special case, and it takes TWO forms
302
+ * because C and C++ nest declarators inside other declarators:
303
+ *
304
+ * 1. THE `declarator` FIELD. Ascend while the node is bound to its parent's
305
+ * `declarator` field. That field is the grammar's own statement of "this node
306
+ * is the declarator OF something larger", so the ascent lands on the node that
307
+ * owns the body (`function_definition`, `declaration`, `field_declaration`,
308
+ * through any `pointer_declarator` or `array_declarator` in between).
309
+ * 2. A DECLARATOR WRAPPER. `int &f()` parses as
310
+ * `(function_definition declarator: (reference_declarator (function_declarator …)))`
311
+ * and `int (*f(void))[4]` as `… (parenthesized_declarator (pointer_declarator …))`.
312
+ * Neither `reference_declarator` nor `parenthesized_declarator` NAMES the
313
+ * declarator it wraps — the child sits in an unnamed field — so rule 1 alone
314
+ * stopped dead at `function_declarator` and reproduced the very defect above
315
+ * for `T &operator[]`, `std::string &name()`, and every other
316
+ * reference-returning accessor in real C++. So also ascend when the parent is
317
+ * itself a declarator that holds this declarator in an UNNAMED field.
318
+ *
319
+ * Both forms keep the property that made rule 1 safe: neither can reach an
320
+ * unrelated ancestor. Rule 1 follows a field the grammar defines only within a
321
+ * declaration; rule 2 requires BOTH ends to be declarator nodes, and a
322
+ * `field_declaration_list` is not one — a method inside a class body therefore
323
+ * still stops at its own `function_definition` and a class is never swallowed.
324
+ * Grammars that already bind the whole definition (every JS/TS, Python, Go, Rust,
325
+ * Ruby pattern) fail both conditions on the first iteration, which makes this a
326
+ * no-op for them: TypeScript's `variable_declarator` sits unnamed in a
327
+ * `lexical_declaration`, which is not a declarator, so rule 2 does not fire and
328
+ * `const a = 1; const b = () => 2;` stays two statements.
329
+ */
330
+ function widenToDefinition(node) {
331
+ let current = node;
332
+ for (;;) {
333
+ const parent = current.parent;
334
+ if (!parent)
335
+ return current;
336
+ // `childrenForFieldName`, not `childForFieldName`: `int a, f(int x);` binds
337
+ // two declarators to one declaration, and the singular accessor answers only
338
+ // the first — which would refuse to widen every declarator but one.
339
+ const boundToDeclaratorField = parent
340
+ .childrenForFieldName('declarator')
341
+ .some((child) => child.id === current.id);
342
+ if (!boundToDeclaratorField && !wrapsDeclarator(parent, current))
343
+ return current;
344
+ current = parent;
345
+ }
346
+ }
347
+ /** A declarator node type, by the grammars' own naming convention. */
348
+ function isDeclarator(node) {
349
+ return node.type.endsWith('_declarator');
350
+ }
351
+ /**
352
+ * True when `parent` is a declarator that wraps `child` without naming the field
353
+ * — `reference_declarator` (`&` / `&&`) and `parenthesized_declarator` (`( … )`),
354
+ * whose grammar rules are a bare token sequence around the inner declarator.
355
+ *
356
+ * Both ends must be declarators, and the field must be UNNAMED: a declarator's
357
+ * named fields hold things that are NOT the wrapped declarator (`parameters`,
358
+ * `size`, `value`), and ascending out of one of those would leave the
359
+ * declaration the capture belongs to.
360
+ */
361
+ function wrapsDeclarator(parent, child) {
362
+ if (!isDeclarator(parent) || !isDeclarator(child))
363
+ return false;
364
+ return fieldNameForChild(parent, child) === null;
365
+ }
366
+ /**
367
+ * The field name binding `child` to `parent`, or null when the child sits in an
368
+ * unnamed field. `Node` exposes no direct accessor, so the index has to be found
369
+ * first; declarator nodes have a handful of children, so the scan is trivial.
370
+ */
371
+ function fieldNameForChild(parent, child) {
372
+ for (let i = 0; i < parent.childCount; i++) {
373
+ if (parent.child(i)?.id === child.id)
374
+ return parent.fieldNameForChild(i);
375
+ }
376
+ return null;
377
+ }
378
+ function buildChunks(definitions, lines) {
379
+ // `headerEndRow[i]` is the 0-based row of definition `i`'s first nested
380
+ // definition — set only for STRUCTURAL definitions, since only they split.
381
+ // `suppressed[i]` marks a definition that lies inside a leaf and is therefore
382
+ // already carried, verbatim, by that leaf's own chunk.
383
+ const headerEndRow = new Map();
384
+ const suppressed = new Uint8Array(definitions.length);
385
+ const open = [];
386
+ for (let i = 0; i < definitions.length; i++) {
387
+ const current = definitions[i];
388
+ if (!current)
389
+ continue;
390
+ while (open.length > 0) {
391
+ const top = definitions[open[open.length - 1] ?? -1];
392
+ if (top && top.endIndex > current.startIndex)
393
+ break;
394
+ open.pop();
395
+ }
396
+ const parentIndex = open[open.length - 1];
397
+ const parent = parentIndex === undefined ? undefined : definitions[parentIndex];
398
+ if (parentIndex !== undefined && parent) {
399
+ if (suppressed[parentIndex] === 1 || !STRUCTURAL_KINDS.has(parent.kind)) {
400
+ // Inside a leaf (or inside something already inside one). Suppression
401
+ // propagates: a class declared inside a function belongs to that
402
+ // function's chunk, and so do the class's own methods.
403
+ suppressed[i] = 1;
404
+ }
405
+ else if (!headerEndRow.has(parentIndex)) {
406
+ headerEndRow.set(parentIndex, current.startRow);
407
+ }
408
+ }
409
+ open.push(i);
410
+ }
411
+ const chunks = [];
412
+ const emittedRanges = new Set();
413
+ const covered = new Uint8Array(lines.length + 2);
414
+ let droppedDefinitions = 0;
415
+ /** True when the chunk was emitted; false when its range cannot carry one. */
416
+ const emit = (chunk) => {
417
+ if (chunk.endLine < chunk.startLine)
418
+ return false;
419
+ const key = `${chunk.startLine}:${chunk.endLine}`;
420
+ if (emittedRanges.has(key))
421
+ return false;
422
+ if (chunk.content.trim() === '')
423
+ return false;
424
+ emittedRanges.add(key);
425
+ chunks.push(chunk);
426
+ for (let line = chunk.startLine; line <= chunk.endLine; line++)
427
+ covered[line] = 1;
428
+ return true;
429
+ };
430
+ for (let i = 0; i < definitions.length; i++) {
431
+ const definition = definitions[i];
432
+ if (!definition || suppressed[i] === 1)
433
+ continue;
434
+ // THE ONE 0-based -> 1-based conversion. `Point.row` is 0-based; startLine
435
+ // and endLine are 1-based inclusive. A structural definition's first child
436
+ // starts on `headerEnd + 1`, so its header ends on the line before that:
437
+ // `headerEnd`. When the child opens on the container's own first line
438
+ // (`class A { m() {} }`) that range is empty, `emit` refuses it and the
439
+ // refusal is counted — emitting the line anyway would duplicate the child's
440
+ // source. Clamped to the last real line so a definition whose node runs to
441
+ // end-of-file cannot name a line that does not exist.
442
+ const headerEnd = headerEndRow.get(i);
443
+ const startLine = definition.startRow + 1;
444
+ const endLine = Math.min(headerEnd ?? definition.endRow + 1, lines.length);
445
+ const content = sliceLines(lines, startLine, endLine);
446
+ const signature = (content.split('\n')[0] ?? '').trim().slice(0, MAX_SIGNATURE_CHARS);
447
+ const emitted = emit({
448
+ content,
449
+ startLine,
450
+ endLine,
451
+ chunkType: CHUNK_TYPE_BY_KIND[definition.kind] ?? 'raw',
452
+ ...(definition.name ? { symbolName: definition.name } : {}),
453
+ symbolKind: definition.kind,
454
+ ...(signature ? { signature } : {}),
455
+ });
456
+ // A definition that reaches no chunk reaches no index either, and a citation
457
+ // to it resolves as `unresolved_symbol`. It cannot be emitted without
458
+ // colliding on the staleness key, so it is counted and reported instead of
459
+ // vanishing — a silent no-op is the defect class, not the collision.
460
+ if (!emitted)
461
+ droppedDefinitions++;
462
+ }
463
+ for (const span of uncoveredSpans(covered, lines.length)) {
464
+ for (const [startLine, endLine] of splitSpan(lines, span)) {
465
+ // Uncovered spans are not counted when refused: a whitespace-only span is
466
+ // owed no chunk, which is the documented contract of `splitSpan`.
467
+ emit({
468
+ content: sliceLines(lines, startLine, endLine),
469
+ startLine,
470
+ endLine,
471
+ chunkType: 'raw',
472
+ });
473
+ }
474
+ }
475
+ return {
476
+ chunks: chunks.sort((a, b) => a.startLine - b.startLine || a.endLine - b.endLine),
477
+ droppedDefinitions,
478
+ };
479
+ }
480
+ const sliceLines = (lines, startLine, endLine) => lines.slice(startLine - 1, endLine).join('\n');
481
+ /** Maximal runs of lines no definition chunk claimed, as 1-based inclusive pairs. */
482
+ function uncoveredSpans(covered, lineCount) {
483
+ const spans = [];
484
+ let start = null;
485
+ for (let line = 1; line <= lineCount; line++) {
486
+ if (covered[line] === 1) {
487
+ if (start !== null)
488
+ spans.push([start, line - 1]);
489
+ start = null;
490
+ }
491
+ else if (start === null) {
492
+ start = line;
493
+ }
494
+ }
495
+ if (start !== null)
496
+ spans.push([start, lineCount]);
497
+ return spans;
498
+ }
499
+ /**
500
+ * Break an uncovered span on line boundaries so no chunk exceeds
501
+ * `MAX_RAW_SPAN_CHARS`. No overlap — overlap would re-embed the same lines — and
502
+ * no mid-line splitting: two chunks over one line range would collide on the
503
+ * `filePath:startLine-endLine` staleness key, so an over-long single line is
504
+ * left whole and the embedding layer truncates it with a warning
505
+ * (`EmbeddingService` caps each input at the 8191-token per-input limit).
506
+ *
507
+ * Whitespace-only spans yield nothing — `emit` drops them, and the blank lines
508
+ * between definitions are the one thing total coverage does not owe a chunk.
509
+ */
510
+ function splitSpan(lines, [spanStart, spanEnd]) {
511
+ const pieces = [];
512
+ let start = spanStart;
513
+ let length = 0;
514
+ for (let line = spanStart; line <= spanEnd; line++) {
515
+ const lineLength = (lines[line - 1] ?? '').length + 1;
516
+ if (line > start && length + lineLength > MAX_RAW_SPAN_CHARS) {
517
+ pieces.push([start, line - 1]);
518
+ start = line;
519
+ length = 0;
520
+ }
521
+ length += lineLength;
522
+ }
523
+ pieces.push([start, spanEnd]);
524
+ return pieces;
525
+ }
526
+ /**
527
+ * ERROR and MISSING nodes, so a caller can see that a file parsed badly instead
528
+ * of inferring it from thin chunks.
529
+ *
530
+ * Short-circuits on a clean tree, and descends only into subtrees whose own
531
+ * `hasError` is true — 97.6% of this repo's TypeScript files have no error at
532
+ * all, and they must not pay for a full tree walk.
533
+ */
534
+ function countErrorNodes(tree) {
535
+ if (!tree.rootNode.hasError)
536
+ return 0;
537
+ const cursor = tree.walk();
538
+ let count = 0;
539
+ try {
540
+ for (;;) {
541
+ const node = cursor.currentNode;
542
+ if (node.isError || node.isMissing)
543
+ count++;
544
+ if (node.hasError && cursor.gotoFirstChild())
545
+ continue;
546
+ for (;;) {
547
+ if (cursor.gotoNextSibling())
548
+ break;
549
+ if (!cursor.gotoParent())
550
+ return count;
551
+ }
552
+ }
553
+ }
554
+ finally {
555
+ cursor.delete();
556
+ }
557
+ }
558
+ const describe = (err) => err instanceof Error ? err.message.slice(0, 200) || err.constructor.name : String(err);
559
+ //# sourceMappingURL=astChunker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"astChunker.js","sourceRoot":"","sources":["../../src/ast/astChunker.ts"],"names":[],"mappings":"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"}