@mrclrchtr/supi-code-intelligence 4.0.0 → 4.2.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 (68) hide show
  1. package/README.md +8 -3
  2. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  3. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  4. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  5. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  6. package/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
  7. package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  8. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  9. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  10. package/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  11. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -5
  12. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  13. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  14. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  15. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
  16. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  17. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  18. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  19. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  20. package/node_modules/@mrclrchtr/supi-lsp/package.json +3 -3
  21. package/node_modules/@mrclrchtr/supi-lsp/src/utils.ts +2 -2
  22. package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +5 -5
  23. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -5
  24. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  25. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  26. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  27. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
  28. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  29. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  30. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  31. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  32. package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +3 -3
  33. package/node_modules/@mrclrchtr/supi-tree-sitter/src/language.ts +2 -1
  34. package/node_modules/@mrclrchtr/supi-tree-sitter/src/operation-support.ts +19 -0
  35. package/node_modules/@mrclrchtr/supi-tree-sitter/src/syntax-node.ts +1 -0
  36. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-c-family.ts +230 -0
  37. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-html-sql.ts +186 -0
  38. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-jvm.ts +311 -0
  39. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-polyglot.ts +218 -0
  40. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-scripting.ts +307 -0
  41. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline.ts +9 -5
  42. package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +6 -2
  43. package/package.json +6 -5
  44. package/src/analysis/search/pattern.ts +2 -2
  45. package/src/analysis/target/symbol.ts +5 -2
  46. package/src/app/app.ts +4 -1
  47. package/src/extension.ts +6 -84
  48. package/src/headless.ts +41 -0
  49. package/src/session/orientation/collect.ts +134 -180
  50. package/src/session/orientation/context-sections.ts +14 -48
  51. package/src/session/orientation-types.ts +14 -4
  52. package/src/session/orientation-workflow.ts +20 -48
  53. package/src/substrate/lsp/lifecycle.ts +25 -39
  54. package/src/substrate/lsp/state.ts +3 -0
  55. package/src/substrate/workspace-provider-host.ts +129 -0
  56. package/src/tool/graph/execute.ts +1 -1
  57. package/src/tool/graph/markdown.ts +222 -0
  58. package/src/tool/orientation/markdown.ts +66 -11
  59. package/src/tool/register.ts +10 -0
  60. package/src/ui/markdown/overview-data.ts +3 -15
  61. package/src/ui/markdown/overview.ts +4 -10
  62. package/src/ui/markdown/types.ts +0 -1
  63. package/src/substrate/tree-sitter/lifecycle.ts +0 -52
  64. package/src/tool/graph/calls-md.ts +0 -41
  65. package/src/tool/graph/implementations-md.ts +0 -57
  66. package/src/tool/graph/markdown-base.ts +0 -88
  67. package/src/tool/graph/provider-location-md.ts +0 -9
  68. package/src/tool/graph/references-md.ts +0 -41
@@ -0,0 +1,311 @@
1
+ import { nodeToRange } from "../coordinates.ts";
2
+ import type { SyntaxNodeLike } from "../syntax-node.ts";
3
+ import type { OutlineItem } from "../types.ts";
4
+
5
+ /** Extract Java and Kotlin declarations from their grammar-specific node shapes. */
6
+ export function extractJvmOutlineItems(
7
+ node: SyntaxNodeLike,
8
+ source: string,
9
+ ): OutlineItem[] | undefined {
10
+ switch (node.type) {
11
+ case "class_declaration":
12
+ return classDeclaration(node, source);
13
+ case "interface_declaration":
14
+ return javaContainer(node, "interface", source);
15
+ case "enum_declaration":
16
+ return javaContainer(node, "enum", source);
17
+ case "record_declaration":
18
+ return one(javaRecord(node, source));
19
+ case "annotation_type_declaration":
20
+ return one(javaContainerItem(node, "interface", source));
21
+ case "module_declaration":
22
+ return one(javaNamed(node, "module", source));
23
+ case "object_declaration":
24
+ return one(kotlinObject(node, source));
25
+ case "function_declaration":
26
+ return kotlinFunction(node, "function", source);
27
+ case "property_declaration":
28
+ return kotlinProperties(node, undefined, source);
29
+ default:
30
+ return undefined;
31
+ }
32
+ }
33
+
34
+ function one(item: OutlineItem | null): OutlineItem[] {
35
+ return item ? [item] : [];
36
+ }
37
+
38
+ function classDeclaration(node: SyntaxNodeLike, source: string): OutlineItem[] | undefined {
39
+ if (!node.childForFieldName("name") && directChild(node, "type_identifier")) {
40
+ return one(kotlinClass(node, source));
41
+ }
42
+ const body = node.childForFieldName("body");
43
+ if (!body?.children.some((child) => JAVA_CLASS_MEMBER_TYPES.has(child.type))) {
44
+ return undefined;
45
+ }
46
+ return one(javaContainerItem(node, "class", source));
47
+ }
48
+
49
+ function javaContainer(
50
+ node: SyntaxNodeLike,
51
+ kind: "interface" | "enum",
52
+ source: string,
53
+ ): OutlineItem[] | undefined {
54
+ const body = node.childForFieldName("body");
55
+ if (!body?.children.some((child) => JAVA_CONTAINER_MEMBER_TYPES.has(child.type))) {
56
+ return undefined;
57
+ }
58
+ return one(javaContainerItem(node, kind, source));
59
+ }
60
+
61
+ function javaContainerItem(
62
+ node: SyntaxNodeLike,
63
+ kind: "class" | "interface" | "enum",
64
+ source: string,
65
+ ): OutlineItem | null {
66
+ const name = node.childForFieldName("name");
67
+ if (!name) return null;
68
+ return {
69
+ name: name.text,
70
+ kind,
71
+ range: nodeToRange(node, source),
72
+ children: javaMembers(node.childForFieldName("body"), name.text, source),
73
+ };
74
+ }
75
+
76
+ function javaRecord(node: SyntaxNodeLike, source: string): OutlineItem | null {
77
+ const name = node.childForFieldName("name");
78
+ if (!name) return null;
79
+ return {
80
+ name: name.text,
81
+ kind: "record",
82
+ range: nodeToRange(node, source),
83
+ children: [
84
+ ...javaRecordFields(node.childForFieldName("parameters"), source),
85
+ ...javaMembers(node.childForFieldName("body"), name.text, source),
86
+ ],
87
+ };
88
+ }
89
+
90
+ function javaRecordFields(
91
+ parameters: SyntaxNodeLike | null | undefined,
92
+ source: string,
93
+ ): OutlineItem[] {
94
+ if (!parameters) return [];
95
+ return parameters.children.flatMap((child) => {
96
+ if (child.type !== "formal_parameter" && child.type !== "spread_parameter") return [];
97
+ return one(javaNamed(child, "field", source));
98
+ });
99
+ }
100
+
101
+ function javaMembers(
102
+ parent: SyntaxNodeLike | null | undefined,
103
+ ownerName: string,
104
+ source: string,
105
+ ): OutlineItem[] {
106
+ if (!parent) return [];
107
+ return parent.children.flatMap((child) => javaMemberItems(child, ownerName, source));
108
+ }
109
+
110
+ function javaMemberItems(node: SyntaxNodeLike, ownerName: string, source: string): OutlineItem[] {
111
+ switch (node.type) {
112
+ case "field_declaration":
113
+ case "constant_declaration":
114
+ return javaVariables(node, "field", source);
115
+ case "constructor_declaration":
116
+ return one(javaNamed(node, "method", source));
117
+ case "compact_constructor_declaration":
118
+ return [{ name: ownerName, kind: "method", range: nodeToRange(node, source) }];
119
+ case "method_declaration":
120
+ case "annotation_type_element_declaration":
121
+ return one(javaNamed(node, "method", source));
122
+ case "enum_constant":
123
+ return one(javaNamed(node, "enum-member", source));
124
+ case "enum_body_declarations":
125
+ return javaMembers(node, ownerName, source);
126
+ case "class_declaration":
127
+ return one(javaContainerItem(node, "class", source) ?? javaNamed(node, "class", source));
128
+ case "interface_declaration":
129
+ return one(
130
+ javaContainerItem(node, "interface", source) ?? javaNamed(node, "interface", source),
131
+ );
132
+ case "enum_declaration":
133
+ return one(javaContainerItem(node, "enum", source) ?? javaNamed(node, "enum", source));
134
+ case "record_declaration":
135
+ return one(javaRecord(node, source));
136
+ case "annotation_type_declaration":
137
+ return one(
138
+ javaContainerItem(node, "interface", source) ?? javaNamed(node, "interface", source),
139
+ );
140
+ default:
141
+ return [];
142
+ }
143
+ }
144
+
145
+ function javaVariables(node: SyntaxNodeLike, kind: string, source: string): OutlineItem[] {
146
+ const range = nodeToRange(node, source);
147
+ return node.childrenForFieldName("declarator").flatMap((declarator) => {
148
+ const name = declarator.childForFieldName("name");
149
+ return name ? [{ name: name.text, kind, range }] : [];
150
+ });
151
+ }
152
+
153
+ function javaNamed(node: SyntaxNodeLike, kind: string, source: string): OutlineItem | null {
154
+ const name = node.childForFieldName("name");
155
+ return name ? { name: name.text, kind, range: nodeToRange(node, source) } : null;
156
+ }
157
+
158
+ function kotlinClass(node: SyntaxNodeLike, source: string): OutlineItem | null {
159
+ const name = directChild(node, "type_identifier");
160
+ if (!name) return null;
161
+ const kind = hasDirectToken(node, "interface")
162
+ ? "interface"
163
+ : hasDirectToken(node, "enum")
164
+ ? "enum"
165
+ : "class";
166
+ const body = node.children.find(
167
+ (child) => child.type === "class_body" || child.type === "enum_class_body",
168
+ );
169
+ return {
170
+ name: name.text,
171
+ kind,
172
+ range: nodeToRange(node, source),
173
+ children: [...kotlinConstructorFields(node, source), ...kotlinMembers(body, name.text, source)],
174
+ };
175
+ }
176
+
177
+ function kotlinObject(node: SyntaxNodeLike, source: string): OutlineItem | null {
178
+ const name = directChild(node, "type_identifier");
179
+ if (!name) return null;
180
+ const body = directChild(node, "class_body");
181
+ return {
182
+ name: name.text,
183
+ kind: "object",
184
+ range: nodeToRange(node, source),
185
+ children: kotlinMembers(body, name.text, source),
186
+ };
187
+ }
188
+
189
+ function kotlinCompanion(node: SyntaxNodeLike, source: string): OutlineItem {
190
+ const name = directChild(node, "type_identifier")?.text ?? "Companion";
191
+ return {
192
+ name,
193
+ kind: "object",
194
+ range: nodeToRange(node, source),
195
+ children: kotlinMembers(directChild(node, "class_body"), name, source),
196
+ };
197
+ }
198
+
199
+ function kotlinMembers(
200
+ parent: SyntaxNodeLike | null | undefined,
201
+ ownerName: string,
202
+ source: string,
203
+ ): OutlineItem[] {
204
+ if (!parent) return [];
205
+ return parent.children.flatMap((child) => {
206
+ switch (child.type) {
207
+ case "property_declaration":
208
+ return kotlinProperties(child, "field", source);
209
+ case "function_declaration":
210
+ return kotlinFunction(child, "method", source) ?? [];
211
+ case "secondary_constructor":
212
+ return [{ name: ownerName, kind: "method", range: nodeToRange(child, source) }];
213
+ case "class_declaration":
214
+ return one(kotlinClass(child, source));
215
+ case "object_declaration":
216
+ return one(kotlinObject(child, source));
217
+ case "companion_object":
218
+ return [kotlinCompanion(child, source)];
219
+ case "type_alias":
220
+ return one(kotlinTypeAlias(child, source));
221
+ case "enum_entry":
222
+ return one(kotlinSimpleNamed(child, "enum-member", source));
223
+ default:
224
+ return [];
225
+ }
226
+ });
227
+ }
228
+
229
+ function kotlinConstructorFields(node: SyntaxNodeLike, source: string): OutlineItem[] {
230
+ const primaryConstructor = directChild(node, "primary_constructor");
231
+ if (!primaryConstructor) return [];
232
+ return primaryConstructor.children.flatMap((child) => {
233
+ if (child.type !== "class_parameter" || !directChild(child, "binding_pattern_kind")) return [];
234
+ return one(kotlinSimpleNamed(child, "field", source));
235
+ });
236
+ }
237
+
238
+ function kotlinFunction(
239
+ node: SyntaxNodeLike,
240
+ kind: "function" | "method",
241
+ source: string,
242
+ ): OutlineItem[] | undefined {
243
+ if (node.childForFieldName("name")) return undefined;
244
+ return one(kotlinSimpleNamed(node, kind, source));
245
+ }
246
+
247
+ function kotlinProperties(
248
+ node: SyntaxNodeLike,
249
+ memberKind: "field" | undefined,
250
+ source: string,
251
+ ): OutlineItem[] {
252
+ const kind = memberKind ?? (containsToken(node, "const") ? "constant" : "variable");
253
+ const declarations = node.children.filter(
254
+ (child) => child.type === "variable_declaration" || child.type === "multi_variable_declaration",
255
+ );
256
+ const range = nodeToRange(node, source);
257
+ return declarations.flatMap((declaration) =>
258
+ simpleIdentifiers(declaration).map((name) => ({ name, kind, range })),
259
+ );
260
+ }
261
+
262
+ function kotlinTypeAlias(node: SyntaxNodeLike, source: string): OutlineItem | null {
263
+ const name = directChild(node, "type_identifier");
264
+ return name ? { name: name.text, kind: "type", range: nodeToRange(node, source) } : null;
265
+ }
266
+
267
+ function kotlinSimpleNamed(node: SyntaxNodeLike, kind: string, source: string): OutlineItem | null {
268
+ const name = directChild(node, "simple_identifier");
269
+ return name ? { name: name.text, kind, range: nodeToRange(node, source) } : null;
270
+ }
271
+
272
+ function simpleIdentifiers(node: SyntaxNodeLike): string[] {
273
+ if (node.type === "simple_identifier") return [node.text];
274
+ return node.children.flatMap(simpleIdentifiers);
275
+ }
276
+
277
+ function directChild(node: SyntaxNodeLike, type: string): SyntaxNodeLike | null {
278
+ return node.children.find((child) => child.type === type) ?? null;
279
+ }
280
+
281
+ function hasDirectToken(node: SyntaxNodeLike, type: string): boolean {
282
+ return node.children.some((child) => child.type === type);
283
+ }
284
+
285
+ function containsToken(node: SyntaxNodeLike, type: string): boolean {
286
+ return (
287
+ node.type === type ||
288
+ (node.children.length === 0 && node.text === type) ||
289
+ node.children.some((child) => containsToken(child, type))
290
+ );
291
+ }
292
+
293
+ const JAVA_CLASS_MEMBER_TYPES = new Set([
294
+ "annotation_type_declaration",
295
+ "class_declaration",
296
+ "compact_constructor_declaration",
297
+ "constructor_declaration",
298
+ "enum_declaration",
299
+ "field_declaration",
300
+ "interface_declaration",
301
+ "method_declaration",
302
+ "record_declaration",
303
+ ]);
304
+
305
+ const JAVA_CONTAINER_MEMBER_TYPES = new Set([
306
+ ...JAVA_CLASS_MEMBER_TYPES,
307
+ "constant_declaration",
308
+ "enum_body_declarations",
309
+ "enum_constant",
310
+ "annotation_type_element_declaration",
311
+ ]);
@@ -0,0 +1,218 @@
1
+ import { nodeToRange } from "../coordinates.ts";
2
+ import type { SyntaxNodeLike } from "../syntax-node.ts";
3
+ import type { OutlineItem } from "../types.ts";
4
+ import { extractCFamilyOutlineItems } from "./outline-c-family.ts";
5
+ import { extractHtmlSqlOutlineItems } from "./outline-html-sql.ts";
6
+ import { extractJvmOutlineItems } from "./outline-jvm.ts";
7
+ import { extractScriptingOutlineItems } from "./outline-scripting.ts";
8
+
9
+ /** Extract declarations whose Tree-sitter node shapes are specific to non-JS/TS grammars. */
10
+ export function extractPolyglotOutlineItems(
11
+ node: SyntaxNodeLike,
12
+ source: string,
13
+ ): OutlineItem[] | undefined {
14
+ const scriptingItems = extractScriptingOutlineItems(node, source);
15
+ if (scriptingItems) return scriptingItems;
16
+
17
+ const htmlSqlItems = extractHtmlSqlOutlineItems(node, source);
18
+ if (htmlSqlItems) return htmlSqlItems;
19
+
20
+ switch (node.type) {
21
+ case "function_definition": {
22
+ const name = node.childForFieldName("name");
23
+ return name
24
+ ? [{ name: name.text, kind: "function", range: nodeToRange(node, source) }]
25
+ : extractCFamilyOutlineItems(node, source);
26
+ }
27
+ case "class_definition":
28
+ return one(container(node, "class", source, pythonMethods));
29
+ case "expression_statement":
30
+ return pythonAssignments(node, source);
31
+ case "function_item":
32
+ return one(named(node, "function", source));
33
+ case "struct_item":
34
+ return one(container(node, "struct", source, rustFields));
35
+ case "union_item":
36
+ return one(container(node, "union", source, rustFields));
37
+ case "enum_item":
38
+ return one(container(node, "enum", source, rustEnumVariants));
39
+ case "trait_item":
40
+ return one(container(node, "interface", source, rustMethods));
41
+ case "impl_item":
42
+ return one(rustImplementation(node, source));
43
+ case "const_item":
44
+ return one(named(node, "constant", source));
45
+ case "static_item":
46
+ return one(named(node, "variable", source));
47
+ case "type_item":
48
+ return one(named(node, "type", source));
49
+ case "mod_item":
50
+ return one(named(node, "module", source));
51
+ case "method_declaration":
52
+ return one(named(node, "method", source));
53
+ case "type_spec":
54
+ return one(goType(node, source));
55
+ case "type_alias":
56
+ return one(named(node, "type", source));
57
+ case "const_spec":
58
+ return namedItems(node, "constant", source);
59
+ case "var_spec":
60
+ return namedItems(node, "variable", source);
61
+ default:
62
+ return extractCFamilyOutlineItems(node, source) ?? extractJvmOutlineItems(node, source);
63
+ }
64
+ }
65
+
66
+ function one(item: OutlineItem | null): OutlineItem[] {
67
+ return item ? [item] : [];
68
+ }
69
+
70
+ function named(node: SyntaxNodeLike, kind: string, source: string): OutlineItem | null {
71
+ const name = findName(node);
72
+ return name ? { name: name.text, kind, range: nodeToRange(node, source) } : null;
73
+ }
74
+
75
+ function container(
76
+ node: SyntaxNodeLike,
77
+ kind: string,
78
+ source: string,
79
+ collectChildren: (node: SyntaxNodeLike, source: string) => OutlineItem[],
80
+ ): OutlineItem | null {
81
+ const name = findName(node);
82
+ if (!name) return null;
83
+ return {
84
+ name: name.text,
85
+ kind,
86
+ range: nodeToRange(node, source),
87
+ children: collectChildren(node, source),
88
+ };
89
+ }
90
+
91
+ function pythonAssignments(node: SyntaxNodeLike, source: string): OutlineItem[] | undefined {
92
+ const assignment = node.children.find((child) => child.type === "assignment");
93
+ return assignment ? collectPythonAssignment(assignment, source) : undefined;
94
+ }
95
+
96
+ function collectPythonAssignment(node: SyntaxNodeLike, source: string): OutlineItem[] {
97
+ const items = pythonBindingItems(node.childForFieldName("left"), node, source);
98
+ const right = node.childForFieldName("right");
99
+ if (right?.type === "assignment") items.push(...collectPythonAssignment(right, source));
100
+ return items;
101
+ }
102
+
103
+ function pythonBindingItems(
104
+ target: SyntaxNodeLike | null,
105
+ declaration: SyntaxNodeLike,
106
+ source: string,
107
+ ): OutlineItem[] {
108
+ if (!target) return [];
109
+ if (target.type === "identifier") {
110
+ return [{ name: target.text, kind: "variable", range: nodeToRange(declaration, source) }];
111
+ }
112
+ if (!PYTHON_BINDING_PATTERNS.has(target.type)) return [];
113
+ return target.children.flatMap((child) => pythonBindingItems(child, declaration, source));
114
+ }
115
+
116
+ const PYTHON_BINDING_PATTERNS = new Set(["pattern_list", "list_pattern", "tuple_pattern"]);
117
+
118
+ function pythonMethods(node: SyntaxNodeLike, source: string): OutlineItem[] {
119
+ const body = node.childForFieldName("body");
120
+ if (!body) return [];
121
+ return body.children.flatMap((child) => {
122
+ const declaration =
123
+ child.type === "decorated_definition"
124
+ ? child.children.find((nested) => nested.type === "function_definition")
125
+ : child;
126
+ if (declaration?.type !== "function_definition") return [];
127
+ const item = named(declaration, "method", source);
128
+ return item ? [item] : [];
129
+ });
130
+ }
131
+
132
+ function rustFields(node: SyntaxNodeLike, source: string): OutlineItem[] {
133
+ const body = node.childForFieldName("body");
134
+ return collectNamedChildren(body, new Set(["field_declaration"]), "field", source);
135
+ }
136
+
137
+ function rustEnumVariants(node: SyntaxNodeLike, source: string): OutlineItem[] {
138
+ const body = node.childForFieldName("body");
139
+ return collectNamedChildren(body, new Set(["enum_variant"]), "enum-member", source);
140
+ }
141
+
142
+ function rustMethods(node: SyntaxNodeLike, source: string): OutlineItem[] {
143
+ const body = node.childForFieldName("body");
144
+ return collectNamedChildren(
145
+ body,
146
+ new Set(["function_item", "function_signature_item"]),
147
+ "method",
148
+ source,
149
+ );
150
+ }
151
+
152
+ function rustImplementation(node: SyntaxNodeLike, source: string): OutlineItem | null {
153
+ const type = node.childForFieldName("type");
154
+ if (!type) return null;
155
+ const trait = node.childForFieldName("trait");
156
+ return {
157
+ name: trait ? `${trait.text} for ${type.text}` : type.text,
158
+ kind: "implementation",
159
+ range: nodeToRange(node, source),
160
+ children: rustMethods(node, source),
161
+ };
162
+ }
163
+
164
+ function goType(node: SyntaxNodeLike, source: string): OutlineItem | null {
165
+ const type = node.childForFieldName("type");
166
+ if (!type) return named(node, "type", source);
167
+ if (type.type === "struct_type") return container(node, "struct", source, goStructFields);
168
+ if (type.type === "interface_type") return container(node, "interface", source, goMethods);
169
+ return named(node, "type", source);
170
+ }
171
+
172
+ function goStructFields(node: SyntaxNodeLike, source: string): OutlineItem[] {
173
+ const body = node
174
+ .childForFieldName("type")
175
+ ?.children.find((child) => child.type.endsWith("list"));
176
+ if (!body) return [];
177
+ return body.children.flatMap((child) =>
178
+ child.type === "field_declaration" ? namedItems(child, "field", source) : [],
179
+ );
180
+ }
181
+
182
+ function goMethods(node: SyntaxNodeLike, source: string): OutlineItem[] {
183
+ const body = node.childForFieldName("type");
184
+ return collectNamedChildren(body, new Set(["method_elem"]), "method", source);
185
+ }
186
+
187
+ function collectNamedChildren(
188
+ parent: SyntaxNodeLike | null | undefined,
189
+ accepted: ReadonlySet<string>,
190
+ kind: string,
191
+ source: string,
192
+ ): OutlineItem[] {
193
+ if (!parent) return [];
194
+ return parent.children.flatMap((child) => {
195
+ if (!accepted.has(child.type)) return [];
196
+ const item = named(child, kind, source);
197
+ return item ? [item] : [];
198
+ });
199
+ }
200
+
201
+ function namedItems(node: SyntaxNodeLike, kind: string, source: string): OutlineItem[] {
202
+ const names = node
203
+ .childrenForFieldName("name")
204
+ .filter((child) => NAME_NODE_TYPES.has(child.type));
205
+ if (names.length === 0) return one(named(node, kind, source));
206
+ const range = nodeToRange(node, source);
207
+ return names.map((name) => ({ name: name.text, kind, range }));
208
+ }
209
+
210
+ const NAME_NODE_TYPES = new Set(["identifier", "type_identifier", "field_identifier"]);
211
+
212
+ function findName(node: SyntaxNodeLike): SyntaxNodeLike | null {
213
+ return (
214
+ node.childForFieldName("name") ??
215
+ node.children.find((child) => NAME_NODE_TYPES.has(child.type)) ??
216
+ null
217
+ );
218
+ }