@wuyanbin/ai-code-review-cli-remote 1.0.35 → 1.1.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 (42) hide show
  1. package/dist/core/context.d.ts +14 -3
  2. package/dist/core/context.d.ts.map +1 -1
  3. package/dist/core/context.js +47 -83
  4. package/dist/core/context.js.map +1 -1
  5. package/dist/core/diff.d.ts +12 -1
  6. package/dist/core/diff.d.ts.map +1 -1
  7. package/dist/core/diff.js +54 -17
  8. package/dist/core/diff.js.map +1 -1
  9. package/dist/core/import-resolve.d.ts +51 -0
  10. package/dist/core/import-resolve.d.ts.map +1 -0
  11. package/dist/core/import-resolve.js +389 -0
  12. package/dist/core/import-resolve.js.map +1 -0
  13. package/dist/core/prompt.d.ts.map +1 -1
  14. package/dist/core/prompt.js +3 -1
  15. package/dist/core/prompt.js.map +1 -1
  16. package/dist/core/reviewer.d.ts.map +1 -1
  17. package/dist/core/reviewer.js +54 -3
  18. package/dist/core/reviewer.js.map +1 -1
  19. package/dist/core/symbol-context.d.ts +56 -0
  20. package/dist/core/symbol-context.d.ts.map +1 -0
  21. package/dist/core/symbol-context.js +451 -0
  22. package/dist/core/symbol-context.js.map +1 -0
  23. package/dist/core/symbols.d.ts +65 -0
  24. package/dist/core/symbols.d.ts.map +1 -0
  25. package/dist/core/symbols.js +627 -0
  26. package/dist/core/symbols.js.map +1 -0
  27. package/dist/core/text-budget.d.ts +3 -0
  28. package/dist/core/text-budget.d.ts.map +1 -0
  29. package/dist/core/text-budget.js +14 -0
  30. package/dist/core/text-budget.js.map +1 -0
  31. package/dist/core/tree-sitter.d.ts +38 -0
  32. package/dist/core/tree-sitter.d.ts.map +1 -0
  33. package/dist/core/tree-sitter.js +151 -0
  34. package/dist/core/tree-sitter.js.map +1 -0
  35. package/dist/tree-sitter/tree-sitter-go.wasm +0 -0
  36. package/dist/tree-sitter/tree-sitter-java.wasm +0 -0
  37. package/dist/tree-sitter/tree-sitter-javascript.wasm +0 -0
  38. package/dist/tree-sitter/tree-sitter-tsx.wasm +0 -0
  39. package/dist/tree-sitter/tree-sitter-typescript.wasm +0 -0
  40. package/dist/tree-sitter/tree-sitter.js +4075 -0
  41. package/dist/tree-sitter/tree-sitter.wasm +0 -0
  42. package/package.json +4 -3
@@ -0,0 +1,627 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_TYPE_LINES = void 0;
4
+ exports.classifyNode = classifyNode;
5
+ exports.enclosingDeclaration = enclosingDeclaration;
6
+ exports.goPackageNameCandidates = goPackageNameCandidates;
7
+ exports.collectImports = collectImports;
8
+ exports.packageName = packageName;
9
+ exports.collectReferences = collectReferences;
10
+ exports.findDeclaration = findDeclaration;
11
+ exports.renderRanges = renderRanges;
12
+ exports.findDeclarationByRegex = findDeclarationByRegex;
13
+ const tree_sitter_1 = require("./tree-sitter");
14
+ /** 类型 / 值 / 类成员清单的渲染行数上限 */
15
+ exports.MAX_TYPE_LINES = 40;
16
+ function field(node, name) {
17
+ try {
18
+ return node.childForFieldName(name);
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
24
+ function firstChild(node, ...types) {
25
+ return (0, tree_sitter_1.namedChildren)(node).find((c) => types.includes(c.type)) ?? null;
26
+ }
27
+ function hasAnonymousChild(node, type) {
28
+ return node.children.some((c) => c !== null && c.type === type);
29
+ }
30
+ function stripQuotes(text) {
31
+ return text.trim().replace(/^['"`]/, "").replace(/['"`]$/, "");
32
+ }
33
+ function samePosition(a, b) {
34
+ return (a.startPosition.row === b.startPosition.row &&
35
+ a.startPosition.column === b.startPosition.column &&
36
+ a.endPosition.row === b.endPosition.row &&
37
+ a.endPosition.column === b.endPosition.column);
38
+ }
39
+ function makeDeclaration(stmt, kind, name, body) {
40
+ const start = (0, tree_sitter_1.startLine)(stmt);
41
+ const header = body ? Math.max(start, (0, tree_sitter_1.startLine)(body)) : start;
42
+ return {
43
+ name,
44
+ kind,
45
+ startLine: start,
46
+ endLine: (0, tree_sitter_1.endLine)(stmt),
47
+ headerEndLine: Math.min(header, (0, tree_sitter_1.endLine)(stmt)),
48
+ node: stmt,
49
+ };
50
+ }
51
+ /** `export function f` / `export const x`:把范围放大到 export 语句本身 */
52
+ function liftExport(stmt) {
53
+ return stmt.parent?.type === "export_statement" ? stmt.parent : stmt;
54
+ }
55
+ const TS_FUNCTION_STATEMENTS = new Set([
56
+ "function_declaration",
57
+ "generator_function_declaration",
58
+ "method_definition",
59
+ ]);
60
+ const TS_FUNCTION_EXPRESSIONS = new Set([
61
+ "arrow_function",
62
+ "function_expression",
63
+ "generator_function",
64
+ "function",
65
+ ]);
66
+ const TS_CLASS_LIKE = new Set(["class_declaration", "abstract_class_declaration"]);
67
+ /** 形状类声明:整体呈现(封顶 MAX_TYPE_LINES),不按成员拆分 */
68
+ const TS_TYPE_LIKE = new Set([
69
+ "interface_declaration",
70
+ "enum_declaration",
71
+ "internal_module",
72
+ "type_alias_declaration",
73
+ ]);
74
+ const GO_FUNCTION = new Set(["function_declaration", "method_declaration"]);
75
+ const GO_VALUE = new Set(["const_declaration", "var_declaration"]);
76
+ const JAVA_FUNCTION = new Set([
77
+ "method_declaration",
78
+ "constructor_declaration",
79
+ ]);
80
+ const JAVA_CLASS_LIKE = new Set(["class_declaration", "record_declaration"]);
81
+ const JAVA_TYPE_LIKE = new Set([
82
+ "interface_declaration",
83
+ "enum_declaration",
84
+ "annotation_type_declaration",
85
+ ]);
86
+ /** 顶层按名字查找时,class 与 type 两类都算「类型声明」 */
87
+ const JAVA_TOP_LEVEL_TYPES = new Set([...JAVA_CLASS_LIKE, ...JAVA_TYPE_LIKE]);
88
+ function isTsLike(language) {
89
+ return (language === "typescript" || language === "tsx" || language === "javascript");
90
+ }
91
+ /**
92
+ * 判断节点本身是否是一个声明;回调形式的函数表达式返回 null,让调用方继续向上找
93
+ * 真正的外层函数。
94
+ */
95
+ function classifyNode(node, language) {
96
+ if (isTsLike(language)) {
97
+ if (TS_FUNCTION_STATEMENTS.has(node.type)) {
98
+ return makeDeclaration(liftExport(node), "function", field(node, "name")?.text ?? null, field(node, "body"));
99
+ }
100
+ if (TS_FUNCTION_EXPRESSIONS.has(node.type) || node.type === "class") {
101
+ const parent = node.parent;
102
+ if (!parent)
103
+ return null;
104
+ const kind = node.type === "class" ? "class" : "function";
105
+ const body = field(node, "body");
106
+ if (parent.type === "variable_declarator") {
107
+ const stmt = parent.parent ?? parent;
108
+ return makeDeclaration(liftExport(stmt), kind, field(parent, "name")?.text ?? null, body);
109
+ }
110
+ if (parent.type === "pair") {
111
+ return makeDeclaration(parent, kind, field(parent, "key")?.text ?? null, body);
112
+ }
113
+ if (parent.type === "assignment_expression") {
114
+ const stmt = parent.parent?.type === "expression_statement" ? parent.parent : parent;
115
+ return makeDeclaration(stmt, kind, field(parent, "left")?.text ?? null, body);
116
+ }
117
+ if (parent.type === "public_field_definition") {
118
+ return makeDeclaration(parent, kind, field(parent, "name")?.text ?? null, body);
119
+ }
120
+ return null;
121
+ }
122
+ if (TS_CLASS_LIKE.has(node.type)) {
123
+ return makeDeclaration(liftExport(node), "class", field(node, "name")?.text ?? null, field(node, "body"));
124
+ }
125
+ if (TS_TYPE_LIKE.has(node.type)) {
126
+ return makeDeclaration(liftExport(node), "type", field(node, "name")?.text ?? null, null);
127
+ }
128
+ return null;
129
+ }
130
+ if (language === "go") {
131
+ if (GO_FUNCTION.has(node.type)) {
132
+ return makeDeclaration(node, "function", field(node, "name")?.text ?? null, field(node, "body"));
133
+ }
134
+ if (node.type === "type_declaration") {
135
+ const spec = firstChild(node, "type_spec", "type_alias");
136
+ return makeDeclaration(node, "type", spec ? field(spec, "name")?.text ?? null : null, null);
137
+ }
138
+ if (GO_VALUE.has(node.type) && node.parent?.type === "source_file") {
139
+ const spec = firstChild(node, "const_spec", "var_spec");
140
+ return makeDeclaration(node, "value", spec ? field(spec, "name")?.text ?? null : null, null);
141
+ }
142
+ return null;
143
+ }
144
+ // java
145
+ if (JAVA_FUNCTION.has(node.type)) {
146
+ return makeDeclaration(node, "function", field(node, "name")?.text ?? null, field(node, "body"));
147
+ }
148
+ if (JAVA_CLASS_LIKE.has(node.type)) {
149
+ return makeDeclaration(node, "class", field(node, "name")?.text ?? null, field(node, "body"));
150
+ }
151
+ if (JAVA_TYPE_LIKE.has(node.type)) {
152
+ return makeDeclaration(node, "type", field(node, "name")?.text ?? null, null);
153
+ }
154
+ return null;
155
+ }
156
+ /** 找包含指定行(1-based)的最内层声明;顶层语句、import 等返回 null */
157
+ function enclosingDeclaration(root, language, line, lineLength = 0) {
158
+ const row = line - 1;
159
+ if (row < 0 || row > root.endPosition.row)
160
+ return null;
161
+ let node = null;
162
+ try {
163
+ node =
164
+ root.descendantForPosition({ row, column: 0 }, { row, column: Math.max(0, lineLength) }) ?? root.descendantForPosition({ row, column: 0 });
165
+ }
166
+ catch {
167
+ return null;
168
+ }
169
+ for (let current = node; current; current = current.parent) {
170
+ const decl = classifyNode(current, language);
171
+ if (decl)
172
+ return decl;
173
+ }
174
+ return null;
175
+ }
176
+ /** Go 包名缺省取路径末段;`/v2` 版本段跳过;带连字符的目录再给两个常见变体 */
177
+ function goPackageNameCandidates(importPath) {
178
+ const segments = importPath.split("/").filter(Boolean);
179
+ let last = segments.pop() ?? importPath;
180
+ if (/^v\d+$/.test(last) && segments.length > 0)
181
+ last = segments.pop() ?? last;
182
+ const variants = new Set([
183
+ last,
184
+ last.replace(/^go-/, ""),
185
+ last.replace(/-go$/, ""),
186
+ last.replace(/-/g, ""),
187
+ last.replace(/[-.]/g, "_"),
188
+ ]);
189
+ return [...variants].filter(Boolean);
190
+ }
191
+ function collectImports(root, language) {
192
+ const bindings = [];
193
+ if (isTsLike(language)) {
194
+ for (const stmt of (0, tree_sitter_1.namedChildren)(root)) {
195
+ if (stmt.type === "import_statement") {
196
+ const sourceNode = field(stmt, "source");
197
+ if (!sourceNode)
198
+ continue;
199
+ const source = stripQuotes(sourceNode.text);
200
+ const clause = firstChild(stmt, "import_clause");
201
+ if (!clause)
202
+ continue;
203
+ for (const part of (0, tree_sitter_1.namedChildren)(clause)) {
204
+ if (part.type === "identifier") {
205
+ bindings.push({ local: part.text, imported: "default", source, kind: "default" });
206
+ }
207
+ else if (part.type === "namespace_import") {
208
+ const id = firstChild(part, "identifier");
209
+ if (id)
210
+ bindings.push({ local: id.text, imported: null, source, kind: "namespace" });
211
+ }
212
+ else if (part.type === "named_imports") {
213
+ for (const spec of (0, tree_sitter_1.namedChildren)(part)) {
214
+ if (spec.type !== "import_specifier")
215
+ continue;
216
+ const name = field(spec, "name")?.text;
217
+ if (!name)
218
+ continue;
219
+ const alias = field(spec, "alias")?.text;
220
+ bindings.push({ local: alias ?? name, imported: name, source, kind: "named" });
221
+ }
222
+ }
223
+ }
224
+ continue;
225
+ }
226
+ if (stmt.type === "lexical_declaration" || stmt.type === "variable_declaration") {
227
+ for (const declarator of (0, tree_sitter_1.namedChildren)(stmt)) {
228
+ if (declarator.type !== "variable_declarator")
229
+ continue;
230
+ const value = field(declarator, "value");
231
+ if (!value || value.type !== "call_expression")
232
+ continue;
233
+ if (field(value, "function")?.text !== "require")
234
+ continue;
235
+ const args = field(value, "arguments");
236
+ const str = args ? (0, tree_sitter_1.namedChildren)(args)[0] : null;
237
+ if (!str || str.type !== "string")
238
+ continue;
239
+ const source = stripQuotes(str.text);
240
+ const nameNode = field(declarator, "name");
241
+ if (!nameNode)
242
+ continue;
243
+ if (nameNode.type === "identifier") {
244
+ bindings.push({ local: nameNode.text, imported: null, source, kind: "namespace" });
245
+ }
246
+ else if (nameNode.type === "object_pattern") {
247
+ for (const prop of (0, tree_sitter_1.namedChildren)(nameNode)) {
248
+ if (prop.type === "shorthand_property_identifier_pattern") {
249
+ bindings.push({ local: prop.text, imported: prop.text, source, kind: "named" });
250
+ }
251
+ else if (prop.type === "pair_pattern") {
252
+ const key = field(prop, "key")?.text;
253
+ const local = field(prop, "value")?.text;
254
+ if (key && local)
255
+ bindings.push({ local, imported: key, source, kind: "named" });
256
+ }
257
+ }
258
+ }
259
+ }
260
+ }
261
+ }
262
+ return bindings;
263
+ }
264
+ if (language === "go") {
265
+ const specs = [];
266
+ for (const decl of (0, tree_sitter_1.namedChildren)(root)) {
267
+ if (decl.type !== "import_declaration")
268
+ continue;
269
+ for (const child of (0, tree_sitter_1.namedChildren)(decl)) {
270
+ if (child.type === "import_spec")
271
+ specs.push(child);
272
+ else if (child.type === "import_spec_list") {
273
+ specs.push(...(0, tree_sitter_1.namedChildren)(child).filter((c) => c.type === "import_spec"));
274
+ }
275
+ }
276
+ }
277
+ for (const spec of specs) {
278
+ const pathNode = field(spec, "path");
279
+ if (!pathNode)
280
+ continue;
281
+ const source = stripQuotes(pathNode.text);
282
+ const alias = field(spec, "name")?.text;
283
+ if (alias === "_" || alias === ".")
284
+ continue;
285
+ const locals = alias ? [alias] : goPackageNameCandidates(source);
286
+ for (const local of locals) {
287
+ bindings.push({ local, imported: null, source, kind: "package" });
288
+ }
289
+ }
290
+ return bindings;
291
+ }
292
+ for (const decl of (0, tree_sitter_1.namedChildren)(root)) {
293
+ if (decl.type !== "import_declaration")
294
+ continue;
295
+ if (hasAnonymousChild(decl, "static"))
296
+ continue;
297
+ const scoped = firstChild(decl, "scoped_identifier", "identifier");
298
+ if (!scoped)
299
+ continue;
300
+ const source = scoped.text;
301
+ if (hasAnonymousChild(decl, "asterisk")) {
302
+ bindings.push({ local: "*", imported: null, source, kind: "wildcard" });
303
+ }
304
+ else {
305
+ const last = source.split(".").pop() ?? source;
306
+ bindings.push({ local: last, imported: last, source, kind: "class" });
307
+ }
308
+ }
309
+ return bindings;
310
+ }
311
+ /** Go 的 package 名 / Java 的 package 路径;TS 无此概念返回 null */
312
+ function packageName(root, language) {
313
+ if (language === "go") {
314
+ const clause = firstChild(root, "package_clause");
315
+ return clause ? firstChild(clause, "package_identifier")?.text ?? null : null;
316
+ }
317
+ if (language === "java") {
318
+ const decl = firstChild(root, "package_declaration");
319
+ return decl ? firstChild(decl, "scoped_identifier", "identifier")?.text ?? null : null;
320
+ }
321
+ return null;
322
+ }
323
+ const IDENTIFIER_TYPES = {
324
+ typescript: new Set(["identifier", "type_identifier", "property_identifier", "shorthand_property_identifier"]),
325
+ tsx: new Set(["identifier", "type_identifier", "property_identifier", "shorthand_property_identifier"]),
326
+ javascript: new Set(["identifier", "property_identifier", "shorthand_property_identifier"]),
327
+ go: new Set(["identifier", "type_identifier", "field_identifier", "package_identifier"]),
328
+ java: new Set(["identifier", "type_identifier"]),
329
+ };
330
+ /** 限定引用的父节点:[对象侧字段名, 成员侧字段名];字段名为 null 时按首/末子节点 */
331
+ const QUALIFIED_PARENTS = {
332
+ member_expression: ["object", "property"],
333
+ nested_type_identifier: ["module", "name"],
334
+ nested_identifier: [null, null],
335
+ selector_expression: ["operand", "field"],
336
+ qualified_type: ["package", "name"],
337
+ field_access: ["object", "field"],
338
+ method_invocation: ["object", "name"],
339
+ scoped_type_identifier: [null, null],
340
+ scoped_identifier: [null, null],
341
+ };
342
+ /** 收集落在给定行(1-based)上的标识符引用;只下探与目标行相交的子树 */
343
+ function collectReferences(root, language, lines) {
344
+ if (lines.size === 0)
345
+ return [];
346
+ const rows = [...lines].map((l) => l - 1);
347
+ const minRow = Math.min(...rows);
348
+ const maxRow = Math.max(...rows);
349
+ const identifierTypes = IDENTIFIER_TYPES[language];
350
+ const seen = new Set();
351
+ const refs = [];
352
+ const push = (name, qualifier) => {
353
+ if (!name)
354
+ return;
355
+ const key = `${qualifier ?? ""}.${name}`;
356
+ if (seen.has(key))
357
+ return;
358
+ seen.add(key);
359
+ refs.push({ name, qualifier });
360
+ };
361
+ // 显式栈而不是递归:5000 层括号嵌套这种病态输入会撑爆调用栈,而异常一旦
362
+ // 逸出就会中断整次评审;先序、从左到右的顺序与递归版一致
363
+ const stack = [root];
364
+ while (stack.length > 0) {
365
+ const node = stack.pop();
366
+ if (node.endPosition.row < minRow || node.startPosition.row > maxRow)
367
+ continue;
368
+ const children = (0, tree_sitter_1.namedChildren)(node);
369
+ if (children.length > 0) {
370
+ for (let i = children.length - 1; i >= 0; i--)
371
+ stack.push(children[i]);
372
+ continue;
373
+ }
374
+ if (!identifierTypes.has(node.type) || !lines.has(node.startPosition.row + 1))
375
+ continue;
376
+ const parent = node.parent;
377
+ const spec = parent ? QUALIFIED_PARENTS[parent.type] : undefined;
378
+ if (parent && spec) {
379
+ const siblings = (0, tree_sitter_1.namedChildren)(parent);
380
+ const object = spec[0] ? field(parent, spec[0]) : siblings[0] ?? null;
381
+ const member = spec[1] ? field(parent, spec[1]) : siblings[siblings.length - 1] ?? null;
382
+ if (member && samePosition(member, node) && object && identifierTypes.has(object.type)) {
383
+ push(node.text, object.text);
384
+ continue;
385
+ }
386
+ // 对象侧(`Foo.BAZ` 里的 Foo)由成员侧那条限定引用覆盖,不再单独产出
387
+ if (object && samePosition(object, node) && member && identifierTypes.has(member.type)) {
388
+ continue;
389
+ }
390
+ }
391
+ push(node.text, null);
392
+ }
393
+ return refs;
394
+ }
395
+ function declaratorNames(node) {
396
+ return (0, tree_sitter_1.namedChildren)(node)
397
+ .filter((c) => c.type === "identifier" || c.type === "type_identifier")
398
+ .map((c) => c.text);
399
+ }
400
+ /** TS 顶层语句里按名字找声明(含 export 包装、const 箭头函数、default 导出) */
401
+ function findTsTopLevel(root, language, name) {
402
+ for (const stmt of (0, tree_sitter_1.namedChildren)(root)) {
403
+ const isExport = stmt.type === "export_statement";
404
+ const target = isExport ? field(stmt, "declaration") ?? field(stmt, "value") : stmt;
405
+ if (!target)
406
+ continue;
407
+ if (name === "default") {
408
+ if (!isExport || !hasAnonymousChild(stmt, "default"))
409
+ continue;
410
+ if (target.type === "identifier")
411
+ return findTsTopLevel(root, language, target.text);
412
+ const decl = classifyNode(target, language);
413
+ return decl ?? makeDeclaration(stmt, "value", "default", null);
414
+ }
415
+ if (target.type === "lexical_declaration" || target.type === "variable_declaration") {
416
+ for (const declarator of (0, tree_sitter_1.namedChildren)(target)) {
417
+ if (declarator.type !== "variable_declarator")
418
+ continue;
419
+ if (field(declarator, "name")?.text !== name)
420
+ continue;
421
+ const value = field(declarator, "value");
422
+ if (value && (TS_FUNCTION_EXPRESSIONS.has(value.type) || value.type === "class")) {
423
+ return classifyNode(value, language) ?? makeDeclaration(liftExport(target), "value", name, null);
424
+ }
425
+ return makeDeclaration(liftExport(target), "value", name, null);
426
+ }
427
+ continue;
428
+ }
429
+ if (field(target, "name")?.text === name) {
430
+ const decl = classifyNode(target, language);
431
+ if (decl)
432
+ return decl;
433
+ }
434
+ }
435
+ return null;
436
+ }
437
+ function findGoTopLevel(root, name) {
438
+ for (const stmt of (0, tree_sitter_1.namedChildren)(root)) {
439
+ if (stmt.type === "function_declaration" && field(stmt, "name")?.text === name) {
440
+ return classifyNode(stmt, "go");
441
+ }
442
+ if (stmt.type === "type_declaration") {
443
+ for (const spec of (0, tree_sitter_1.namedChildren)(stmt)) {
444
+ if ((spec.type === "type_spec" || spec.type === "type_alias") && field(spec, "name")?.text === name) {
445
+ const node = (0, tree_sitter_1.namedChildren)(stmt).length > 1 ? spec : stmt;
446
+ return makeDeclaration(node, "type", name, null);
447
+ }
448
+ }
449
+ continue;
450
+ }
451
+ if (GO_VALUE.has(stmt.type)) {
452
+ for (const spec of (0, tree_sitter_1.namedChildren)(stmt)) {
453
+ if (spec.type !== "const_spec" && spec.type !== "var_spec")
454
+ continue;
455
+ if (declaratorNames(spec).includes(name)) {
456
+ return makeDeclaration(spec, "value", name, null);
457
+ }
458
+ }
459
+ }
460
+ }
461
+ return null;
462
+ }
463
+ function javaMemberName(member) {
464
+ if (member.type === "field_declaration") {
465
+ return (0, tree_sitter_1.namedChildren)(member)
466
+ .filter((c) => c.type === "variable_declarator")
467
+ .map((c) => field(c, "name")?.text ?? "")
468
+ .filter(Boolean);
469
+ }
470
+ if (member.type === "enum_constant") {
471
+ return [field(member, "name")?.text ?? (0, tree_sitter_1.namedChildren)(member)[0]?.text ?? ""].filter(Boolean);
472
+ }
473
+ const name = field(member, "name")?.text;
474
+ return name ? [name] : [];
475
+ }
476
+ function javaBodyMembers(body) {
477
+ const members = [];
478
+ for (const child of (0, tree_sitter_1.namedChildren)(body)) {
479
+ if (child.type === "enum_body_declarations")
480
+ members.push(...(0, tree_sitter_1.namedChildren)(child));
481
+ else
482
+ members.push(child);
483
+ }
484
+ return members;
485
+ }
486
+ function findJavaTopLevel(root, name) {
487
+ for (const stmt of (0, tree_sitter_1.namedChildren)(root)) {
488
+ if (JAVA_TOP_LEVEL_TYPES.has(stmt.type) && field(stmt, "name")?.text === name) {
489
+ return classifyNode(stmt, "java");
490
+ }
491
+ }
492
+ return null;
493
+ }
494
+ function memberOf(decl, language, member) {
495
+ const body = field(decl.node, "body") ?? (decl.node.type === "export_statement" ? null : null);
496
+ const classNode = decl.node.type === "export_statement" ? field(decl.node, "declaration") ?? decl.node : decl.node;
497
+ const classBody = body ?? field(classNode, "body");
498
+ if (!classBody)
499
+ return null;
500
+ const members = language === "java" ? javaBodyMembers(classBody) : (0, tree_sitter_1.namedChildren)(classBody);
501
+ for (const m of members) {
502
+ if (m.type === "comment" || m.type === "line_comment" || m.type === "block_comment")
503
+ continue;
504
+ const names = language === "java" ? javaMemberName(m) : [field(m, "name")?.text ?? ""];
505
+ if (!names.includes(member))
506
+ continue;
507
+ const classified = classifyNode(m, language);
508
+ if (classified)
509
+ return classified;
510
+ return makeDeclaration(m, "value", member, null);
511
+ }
512
+ return null;
513
+ }
514
+ /** 在目标文件的语法树里按名字找顶层声明;member 用于 `Foo.BAR` 这类类成员引用 */
515
+ function findDeclaration(root, language, name, member) {
516
+ let decl = null;
517
+ if (isTsLike(language))
518
+ decl = findTsTopLevel(root, language, name);
519
+ else if (language === "go")
520
+ decl = findGoTopLevel(root, name);
521
+ else
522
+ decl = findJavaTopLevel(root, name);
523
+ if (!decl)
524
+ return null;
525
+ const memberDecl = member && decl.kind === "class" ? memberOf(decl, language, member) : null;
526
+ return { decl, member: memberDecl };
527
+ }
528
+ function isPublicMember(member, language) {
529
+ if (language === "java") {
530
+ if (member.type === "enum_constant")
531
+ return true;
532
+ const modifiers = firstChild(member, "modifiers")?.text ?? "";
533
+ if (/\bprivate\b|\bprotected\b/.test(modifiers))
534
+ return false;
535
+ return /\bpublic\b/.test(modifiers) || modifiers === "";
536
+ }
537
+ const accessibility = member.children.find((c) => c !== null && c.type === "accessibility_modifier");
538
+ if (accessibility && /private|protected/.test(accessibility.text))
539
+ return false;
540
+ const name = field(member, "name")?.text ?? "";
541
+ return !name.startsWith("#");
542
+ }
543
+ /**
544
+ * 决定渲染哪些行(1-based 闭区间,已排序不重叠):
545
+ * 函数 → 签名;类型/值 → 整体但封顶 MAX_TYPE_LINES;
546
+ * 类 → 类头 + 被引用成员的签名(无具体成员时列公开成员签名),封顶 MAX_TYPE_LINES。
547
+ */
548
+ function renderRanges(found, language) {
549
+ const { decl, member } = found;
550
+ if (decl.kind === "function")
551
+ return [[decl.startLine, decl.headerEndLine]];
552
+ if (decl.kind !== "class") {
553
+ return [[decl.startLine, Math.min(decl.endLine, decl.startLine + exports.MAX_TYPE_LINES - 1)]];
554
+ }
555
+ const ranges = [[decl.startLine, decl.headerEndLine]];
556
+ let used = decl.headerEndLine - decl.startLine + 1;
557
+ const pushRange = (start, end) => {
558
+ const last = ranges[ranges.length - 1];
559
+ if (start <= last[1])
560
+ return; // 已在类头范围内
561
+ const capped = Math.min(end, start + Math.max(0, exports.MAX_TYPE_LINES - used) - 1);
562
+ if (capped < start)
563
+ return;
564
+ ranges.push([start, capped]);
565
+ used += capped - start + 1;
566
+ };
567
+ if (member) {
568
+ pushRange(member.startLine, member.headerEndLine);
569
+ return ranges;
570
+ }
571
+ const classNode = decl.node.type === "export_statement" ? field(decl.node, "declaration") ?? decl.node : decl.node;
572
+ const body = field(classNode, "body");
573
+ if (!body)
574
+ return ranges;
575
+ const members = language === "java" ? javaBodyMembers(body) : (0, tree_sitter_1.namedChildren)(body);
576
+ for (const m of members) {
577
+ if (used >= exports.MAX_TYPE_LINES)
578
+ break;
579
+ if (m.type === "comment" || m.type === "line_comment" || m.type === "block_comment")
580
+ continue;
581
+ if (!isPublicMember(m, language))
582
+ continue;
583
+ const classified = classifyNode(m, language);
584
+ const end = classified ? classified.headerEndLine : Math.min((0, tree_sitter_1.endLine)(m), (0, tree_sitter_1.startLine)(m));
585
+ pushRange((0, tree_sitter_1.startLine)(m), end);
586
+ }
587
+ return ranges;
588
+ }
589
+ /**
590
+ * 语法树不可用(超大文件解析超时、运行时缺失)时的兜底:按行正则找声明头。
591
+ * 只认「行首就是声明」的常见形态,找不到就返回空。
592
+ */
593
+ function findDeclarationByRegex(lines, language, name) {
594
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
595
+ const patterns = isTsLike(language)
596
+ ? [
597
+ new RegExp(`^\\s*(export\\s+)?(default\\s+)?(declare\\s+)?(abstract\\s+)?(async\\s+)?(function\\*?\\s+${escaped}\\b|class\\s+${escaped}\\b|interface\\s+${escaped}\\b|type\\s+${escaped}\\b|enum\\s+${escaped}\\b|(const|let|var)\\s+${escaped}\\b)`),
598
+ ]
599
+ : language === "go"
600
+ ? [
601
+ new RegExp(`^\\s*func\\s+(\\([^)]*\\)\\s*)?${escaped}\\s*[\\[(]`),
602
+ new RegExp(`^\\s*type\\s+${escaped}\\b`),
603
+ new RegExp(`^\\s*(const|var)\\s+${escaped}\\b`),
604
+ new RegExp(`^\\s*${escaped}\\b[^=]*=`),
605
+ ]
606
+ : [
607
+ new RegExp(`^\\s*((public|private|protected|static|final|abstract|sealed|non-sealed)\\s+)*(class|interface|enum|record|@interface)\\s+${escaped}\\b`),
608
+ ];
609
+ for (let i = 0; i < lines.length; i++) {
610
+ const line = lines[i];
611
+ if (!line.includes(name))
612
+ continue;
613
+ if (!patterns.some((p) => p.test(line)))
614
+ continue;
615
+ let end = i;
616
+ if (!/[{;=]/.test(line)) {
617
+ for (let j = i + 1; j < Math.min(lines.length, i + 5); j++) {
618
+ end = j;
619
+ if (/[{;]/.test(lines[j]))
620
+ break;
621
+ }
622
+ }
623
+ return [[i + 1, end + 1]];
624
+ }
625
+ return [];
626
+ }
627
+ //# sourceMappingURL=symbols.js.map