@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.
- package/dist/ast/astChunker.d.ts +124 -0
- package/dist/ast/astChunker.d.ts.map +1 -0
- package/dist/ast/astChunker.js +559 -0
- package/dist/ast/astChunker.js.map +1 -0
- package/dist/ast/grammars.d.ts +170 -0
- package/dist/ast/grammars.d.ts.map +1 -0
- package/dist/ast/grammars.js +411 -0
- package/dist/ast/grammars.js.map +1 -0
- package/dist/codeScanner.d.ts +59 -0
- package/dist/codeScanner.d.ts.map +1 -1
- package/dist/codeScanner.js +259 -2
- package/dist/codeScanner.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/queries/bash.tags.scm +7 -0
- package/queries/groovy.tags.scm +15 -0
- package/queries/powershell.tags.scm +14 -0
- package/scripts/vendor-grammars.ts +317 -0
- package/src/ast/astChunker.ts +661 -0
- package/src/ast/grammars.ts +490 -0
- package/src/codeScanner.ts +273 -3
- package/src/index.ts +22 -0
- package/wasm/bash.tags.scm +7 -0
- package/wasm/bash.wasm +0 -0
- package/wasm/c-sharp.tags.scm +23 -0
- package/wasm/c-sharp.wasm +0 -0
- package/wasm/c.tags.scm +9 -0
- package/wasm/c.wasm +0 -0
- package/wasm/cpp.tags.scm +15 -0
- package/wasm/cpp.wasm +0 -0
- package/wasm/elixir.tags.scm +54 -0
- package/wasm/elixir.wasm +0 -0
- package/wasm/go.tags.scm +42 -0
- package/wasm/go.wasm +0 -0
- package/wasm/groovy.tags.scm +15 -0
- package/wasm/groovy.wasm +0 -0
- package/wasm/java.tags.scm +20 -0
- package/wasm/java.wasm +0 -0
- package/wasm/javascript.tags.scm +99 -0
- package/wasm/javascript.wasm +0 -0
- package/wasm/php.tags.scm +40 -0
- package/wasm/php.wasm +0 -0
- package/wasm/powershell.tags.scm +14 -0
- package/wasm/powershell.wasm +0 -0
- package/wasm/python.tags.scm +14 -0
- package/wasm/python.wasm +0 -0
- package/wasm/ruby.tags.scm +64 -0
- package/wasm/ruby.wasm +0 -0
- package/wasm/rust.tags.scm +60 -0
- package/wasm/rust.wasm +0 -0
- package/wasm/scala.tags.scm +66 -0
- package/wasm/scala.wasm +0 -0
- package/wasm/solidity.tags.scm +43 -0
- package/wasm/solidity.wasm +0 -0
- package/wasm/tsx.wasm +0 -0
- package/wasm/typescript.tags.scm +23 -0
- 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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"}
|