codegraphcontext-rust 0.5.5__cp311-cp311-win_amd64.whl
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.
- codegraphcontext/__init__.py +2 -0
- codegraphcontext/__main__.py +5 -0
- codegraphcontext/_cgc_rust.cp311-win_amd64.pyd +0 -0
- codegraphcontext/cli/__init__.py +1 -0
- codegraphcontext/cli/cli_helpers.py +774 -0
- codegraphcontext/cli/config_manager.py +1051 -0
- codegraphcontext/cli/main.py +2386 -0
- codegraphcontext/cli/registry_commands.py +404 -0
- codegraphcontext/cli/setup_macos.py +93 -0
- codegraphcontext/cli/setup_wizard.py +991 -0
- codegraphcontext/cli/visualizer.py +50 -0
- codegraphcontext/core/__init__.py +165 -0
- codegraphcontext/core/bundle_registry.py +181 -0
- codegraphcontext/core/cgc_bundle.py +858 -0
- codegraphcontext/core/cgcignore.py +118 -0
- codegraphcontext/core/database.py +273 -0
- codegraphcontext/core/database_falkordb.py +480 -0
- codegraphcontext/core/database_falkordb_remote.py +199 -0
- codegraphcontext/core/database_kuzu.py +636 -0
- codegraphcontext/core/falkor_worker.py +132 -0
- codegraphcontext/core/jobs.py +132 -0
- codegraphcontext/core/watcher.py +260 -0
- codegraphcontext/prompts.py +125 -0
- codegraphcontext/server.py +471 -0
- codegraphcontext/tool_definitions.py +220 -0
- codegraphcontext/tools/__init__.py +0 -0
- codegraphcontext/tools/advanced_language_query_tool.py +103 -0
- codegraphcontext/tools/code_finder.py +1160 -0
- codegraphcontext/tools/graph_builder.py +337 -0
- codegraphcontext/tools/handlers/analysis_handlers.py +114 -0
- codegraphcontext/tools/handlers/indexing_handlers.py +116 -0
- codegraphcontext/tools/handlers/management_handlers.py +339 -0
- codegraphcontext/tools/handlers/query_handlers.py +83 -0
- codegraphcontext/tools/handlers/watcher_handlers.py +83 -0
- codegraphcontext/tools/indexing/__init__.py +1 -0
- codegraphcontext/tools/indexing/constants.py +25 -0
- codegraphcontext/tools/indexing/discovery.py +64 -0
- codegraphcontext/tools/indexing/engine.py +109 -0
- codegraphcontext/tools/indexing/persistence/__init__.py +3 -0
- codegraphcontext/tools/indexing/persistence/parquet_loader.py +643 -0
- codegraphcontext/tools/indexing/persistence/writer.py +1114 -0
- codegraphcontext/tools/indexing/pipeline.py +171 -0
- codegraphcontext/tools/indexing/pre_scan.py +105 -0
- codegraphcontext/tools/indexing/resolution/__init__.py +8 -0
- codegraphcontext/tools/indexing/resolution/calls.py +253 -0
- codegraphcontext/tools/indexing/resolution/inheritance.py +91 -0
- codegraphcontext/tools/indexing/sanitize.py +41 -0
- codegraphcontext/tools/indexing/schema.py +79 -0
- codegraphcontext/tools/indexing/schema_contract.py +44 -0
- codegraphcontext/tools/indexing/scip_pipeline.py +140 -0
- codegraphcontext/tools/languages/c.py +563 -0
- codegraphcontext/tools/languages/cpp.py +616 -0
- codegraphcontext/tools/languages/csharp.py +551 -0
- codegraphcontext/tools/languages/dart.py +378 -0
- codegraphcontext/tools/languages/elixir.py +460 -0
- codegraphcontext/tools/languages/go.py +499 -0
- codegraphcontext/tools/languages/haskell.py +426 -0
- codegraphcontext/tools/languages/java.py +500 -0
- codegraphcontext/tools/languages/javascript.py +589 -0
- codegraphcontext/tools/languages/kotlin.py +640 -0
- codegraphcontext/tools/languages/perl.py +260 -0
- codegraphcontext/tools/languages/php.py +519 -0
- codegraphcontext/tools/languages/python.py +576 -0
- codegraphcontext/tools/languages/ruby.py +537 -0
- codegraphcontext/tools/languages/rust.py +295 -0
- codegraphcontext/tools/languages/scala.py +519 -0
- codegraphcontext/tools/languages/swift.py +491 -0
- codegraphcontext/tools/languages/typescript.py +575 -0
- codegraphcontext/tools/languages/typescriptjsx.py +151 -0
- codegraphcontext/tools/package_resolver.py +472 -0
- codegraphcontext/tools/query_tool_languages/c_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +87 -0
- codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/dart_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/go_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/java_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/perl_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/python_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/rust_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/scala_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/swift_toolkit.py +5 -0
- codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +5 -0
- codegraphcontext/tools/scip_indexer.py +467 -0
- codegraphcontext/tools/scip_pb2.py +2455 -0
- codegraphcontext/tools/system.py +133 -0
- codegraphcontext/tools/tree_sitter_parser.py +103 -0
- codegraphcontext/utils/debug_log.py +90 -0
- codegraphcontext/utils/path_ignore.py +55 -0
- codegraphcontext/utils/repo_path.py +27 -0
- codegraphcontext/utils/tree_sitter_manager.py +285 -0
- codegraphcontext/utils/visualize_graph.py +0 -0
- codegraphcontext/viz/server.py +282 -0
- codegraphcontext_rust-0.5.5.dist-info/METADATA +537 -0
- codegraphcontext_rust-0.5.5.dist-info/RECORD +101 -0
- codegraphcontext_rust-0.5.5.dist-info/WHEEL +4 -0
- codegraphcontext_rust-0.5.5.dist-info/entry_points.txt +3 -0
- codegraphcontext_rust-0.5.5.dist-info/licenses/LICENSE +21 -0
- codegraphcontext_rust-0.5.5.dist-info/sboms/cgc-python.cyclonedx.json +2333 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
"""Haskell tree-sitter parser (tree-sitter-haskell grammar)."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from codegraphcontext.utils.debug_log import error_logger, warning_logger
|
|
8
|
+
from codegraphcontext.utils.tree_sitter_manager import execute_query
|
|
9
|
+
|
|
10
|
+
# Node names follow https://github.com/tree-sitter/tree-sitter-haskell
|
|
11
|
+
# Top-level: function, class (typeclass), data_type, newtype, type_synomym, import.
|
|
12
|
+
# Application uses node type `apply` (function application).
|
|
13
|
+
HASKELL_QUERIES = {
|
|
14
|
+
"functions": """
|
|
15
|
+
(function) @function_node
|
|
16
|
+
(bind
|
|
17
|
+
name: (variable) @bind_name) @bind_node
|
|
18
|
+
""",
|
|
19
|
+
"classes": """
|
|
20
|
+
(class) @class_node
|
|
21
|
+
(data_type) @data_type_node
|
|
22
|
+
(newtype) @newtype_node
|
|
23
|
+
(type_synomym) @type_synonym_node
|
|
24
|
+
""",
|
|
25
|
+
"imports": """
|
|
26
|
+
(import) @import
|
|
27
|
+
""",
|
|
28
|
+
"calls": """
|
|
29
|
+
(apply
|
|
30
|
+
function: (variable) @callee) @apply_node
|
|
31
|
+
""",
|
|
32
|
+
# Polymorphic parameters use `variable` under type `function`, not a separate `type_variable` kind
|
|
33
|
+
# in tree-sitter-haskell; keep variables to top-level/type signatures only.
|
|
34
|
+
"variables": """
|
|
35
|
+
(signature
|
|
36
|
+
name: (variable) @name) @signature_node
|
|
37
|
+
""",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class HaskellTreeSitterParser:
|
|
42
|
+
"""Parse Haskell sources using tree-sitter-haskell."""
|
|
43
|
+
|
|
44
|
+
def __init__(self, generic_parser_wrapper: Any):
|
|
45
|
+
self.generic_parser_wrapper = generic_parser_wrapper
|
|
46
|
+
self.language_name = "haskell"
|
|
47
|
+
self.language = generic_parser_wrapper.language
|
|
48
|
+
self.parser = generic_parser_wrapper.parser
|
|
49
|
+
self.index_source = False
|
|
50
|
+
|
|
51
|
+
def _get_node_text(self, node: Any) -> str:
|
|
52
|
+
if not node:
|
|
53
|
+
return ""
|
|
54
|
+
return node.text.decode("utf-8")
|
|
55
|
+
|
|
56
|
+
def _get_parent_context(
|
|
57
|
+
self,
|
|
58
|
+
node: Any,
|
|
59
|
+
types: Tuple[str, ...] = ("function", "bind", "class", "data_type", "newtype", "instance"),
|
|
60
|
+
) -> Tuple[Optional[str], Optional[str], Optional[int]]:
|
|
61
|
+
curr = node.parent
|
|
62
|
+
while curr:
|
|
63
|
+
if curr.type in types:
|
|
64
|
+
name_node = curr.child_by_field_name("name")
|
|
65
|
+
if name_node:
|
|
66
|
+
return (
|
|
67
|
+
self._get_node_text(name_node),
|
|
68
|
+
curr.type,
|
|
69
|
+
curr.start_point[0] + 1,
|
|
70
|
+
)
|
|
71
|
+
if curr.type == "function":
|
|
72
|
+
fn_name = curr.child_by_field_name("name")
|
|
73
|
+
if fn_name:
|
|
74
|
+
return (
|
|
75
|
+
self._get_node_text(fn_name),
|
|
76
|
+
curr.type,
|
|
77
|
+
curr.start_point[0] + 1,
|
|
78
|
+
)
|
|
79
|
+
if curr.type == "bind":
|
|
80
|
+
bn = curr.child_by_field_name("name")
|
|
81
|
+
if bn and bn.type == "variable":
|
|
82
|
+
return (
|
|
83
|
+
self._get_node_text(bn),
|
|
84
|
+
curr.type,
|
|
85
|
+
curr.start_point[0] + 1,
|
|
86
|
+
)
|
|
87
|
+
curr = curr.parent
|
|
88
|
+
return None, None, None
|
|
89
|
+
|
|
90
|
+
def _pattern_arg_names(self, patterns_node: Any) -> List[str]:
|
|
91
|
+
if not patterns_node:
|
|
92
|
+
return []
|
|
93
|
+
names: List[str] = []
|
|
94
|
+
|
|
95
|
+
def walk(n: Any) -> None:
|
|
96
|
+
if n.type == "variable":
|
|
97
|
+
names.append(self._get_node_text(n))
|
|
98
|
+
return
|
|
99
|
+
for c in n.children:
|
|
100
|
+
walk(c)
|
|
101
|
+
|
|
102
|
+
walk(patterns_node)
|
|
103
|
+
return names
|
|
104
|
+
|
|
105
|
+
def parse(self, path: Path, is_dependency: bool = False, index_source: bool = False) -> Dict[str, Any]:
|
|
106
|
+
self.index_source = index_source
|
|
107
|
+
try:
|
|
108
|
+
with open(path, "r", encoding="utf-8", errors="ignore") as f:
|
|
109
|
+
source_code = f.read()
|
|
110
|
+
if not source_code.strip():
|
|
111
|
+
warning_logger(f"Empty or whitespace-only file: {path}")
|
|
112
|
+
return self._empty_result(path, is_dependency)
|
|
113
|
+
|
|
114
|
+
tree = self.parser.parse(bytes(source_code, "utf8"))
|
|
115
|
+
root = tree.root_node
|
|
116
|
+
|
|
117
|
+
parsed_variables: List[Dict[str, Any]] = []
|
|
118
|
+
if "variables" in HASKELL_QUERIES:
|
|
119
|
+
var_caps = execute_query(self.language, HASKELL_QUERIES["variables"], root)
|
|
120
|
+
parsed_variables = self._parse_variables(var_caps, source_code, path)
|
|
121
|
+
|
|
122
|
+
parsed_functions: List[Dict[str, Any]] = []
|
|
123
|
+
parsed_classes: List[Dict[str, Any]] = []
|
|
124
|
+
parsed_imports: List[Dict[str, Any]] = []
|
|
125
|
+
parsed_calls: List[Dict[str, Any]] = []
|
|
126
|
+
|
|
127
|
+
for capture_name, query in HASKELL_QUERIES.items():
|
|
128
|
+
if capture_name == "variables":
|
|
129
|
+
continue
|
|
130
|
+
results = execute_query(self.language, query, root)
|
|
131
|
+
if capture_name == "functions":
|
|
132
|
+
parsed_functions.extend(self._parse_functions(results, source_code, path))
|
|
133
|
+
elif capture_name == "classes":
|
|
134
|
+
parsed_classes.extend(self._parse_classes(results, source_code, path))
|
|
135
|
+
elif capture_name == "imports":
|
|
136
|
+
parsed_imports.extend(self._parse_imports(results, source_code))
|
|
137
|
+
elif capture_name == "calls":
|
|
138
|
+
parsed_calls.extend(self._parse_calls(results, source_code, path))
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
"path": str(path),
|
|
142
|
+
"functions": parsed_functions,
|
|
143
|
+
"classes": parsed_classes,
|
|
144
|
+
"variables": parsed_variables,
|
|
145
|
+
"imports": parsed_imports,
|
|
146
|
+
"function_calls": parsed_calls,
|
|
147
|
+
"is_dependency": is_dependency,
|
|
148
|
+
"lang": self.language_name,
|
|
149
|
+
}
|
|
150
|
+
except Exception as e:
|
|
151
|
+
error_logger(f"Error parsing Haskell file {path}: {e}")
|
|
152
|
+
return self._empty_result(path, is_dependency)
|
|
153
|
+
|
|
154
|
+
def _empty_result(self, path: Path, is_dependency: bool) -> Dict[str, Any]:
|
|
155
|
+
return {
|
|
156
|
+
"path": str(path),
|
|
157
|
+
"functions": [],
|
|
158
|
+
"classes": [],
|
|
159
|
+
"variables": [],
|
|
160
|
+
"imports": [],
|
|
161
|
+
"function_calls": [],
|
|
162
|
+
"is_dependency": is_dependency,
|
|
163
|
+
"lang": self.language_name,
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
def _parse_functions(
|
|
167
|
+
self, captures: List[Tuple[Any, str]], source_code: str, path: Path
|
|
168
|
+
) -> List[Dict[str, Any]]:
|
|
169
|
+
functions: List[Dict[str, Any]] = []
|
|
170
|
+
seen: set = set()
|
|
171
|
+
|
|
172
|
+
for node, cap in captures:
|
|
173
|
+
if cap == "function_node" and node.type == "function":
|
|
174
|
+
name_node = node.child_by_field_name("name")
|
|
175
|
+
if not name_node:
|
|
176
|
+
continue
|
|
177
|
+
func_name = self._get_node_text(name_node)
|
|
178
|
+
key = ("fn", node.start_byte, node.end_byte)
|
|
179
|
+
if key in seen:
|
|
180
|
+
continue
|
|
181
|
+
seen.add(key)
|
|
182
|
+
patterns = node.child_by_field_name("patterns")
|
|
183
|
+
parameters = self._pattern_arg_names(patterns)
|
|
184
|
+
start_line = node.start_point[0] + 1
|
|
185
|
+
end_line = node.end_point[0] + 1
|
|
186
|
+
ctx_name, ctx_type, ctx_line = self._get_parent_context(node)
|
|
187
|
+
func_data: Dict[str, Any] = {
|
|
188
|
+
"name": func_name,
|
|
189
|
+
"args": parameters,
|
|
190
|
+
"line_number": start_line,
|
|
191
|
+
"end_line": end_line,
|
|
192
|
+
"path": str(path),
|
|
193
|
+
"lang": self.language_name,
|
|
194
|
+
"context": ctx_name,
|
|
195
|
+
"class_context": ctx_name
|
|
196
|
+
if ctx_type and ctx_type in ("class", "instance")
|
|
197
|
+
else None,
|
|
198
|
+
}
|
|
199
|
+
if self.index_source:
|
|
200
|
+
func_data["source"] = self._get_node_text(node)
|
|
201
|
+
functions.append(func_data)
|
|
202
|
+
|
|
203
|
+
elif cap == "bind_node" and node.type == "bind":
|
|
204
|
+
name_node = node.child_by_field_name("name")
|
|
205
|
+
if not name_node or name_node.type != "variable":
|
|
206
|
+
continue
|
|
207
|
+
func_name = self._get_node_text(name_node)
|
|
208
|
+
key = ("bind", node.start_byte, node.end_byte)
|
|
209
|
+
if key in seen:
|
|
210
|
+
continue
|
|
211
|
+
seen.add(key)
|
|
212
|
+
start_line = node.start_point[0] + 1
|
|
213
|
+
end_line = node.end_point[0] + 1
|
|
214
|
+
ctx_name, ctx_type, ctx_line = self._get_parent_context(node)
|
|
215
|
+
func_data = {
|
|
216
|
+
"name": func_name,
|
|
217
|
+
"args": [],
|
|
218
|
+
"line_number": start_line,
|
|
219
|
+
"end_line": end_line,
|
|
220
|
+
"path": str(path),
|
|
221
|
+
"lang": self.language_name,
|
|
222
|
+
"context": ctx_name,
|
|
223
|
+
"class_context": ctx_name
|
|
224
|
+
if ctx_type and ctx_type in ("class", "instance")
|
|
225
|
+
else None,
|
|
226
|
+
}
|
|
227
|
+
if self.index_source:
|
|
228
|
+
func_data["source"] = self._get_node_text(node)
|
|
229
|
+
functions.append(func_data)
|
|
230
|
+
|
|
231
|
+
return functions
|
|
232
|
+
|
|
233
|
+
def _parse_classes(
|
|
234
|
+
self, captures: List[Tuple[Any, str]], source_code: str, path: Path
|
|
235
|
+
) -> List[Dict[str, Any]]:
|
|
236
|
+
classes: List[Dict[str, Any]] = []
|
|
237
|
+
seen: set = set()
|
|
238
|
+
|
|
239
|
+
for node, cap in captures:
|
|
240
|
+
node_id = (node.start_byte, node.end_byte, node.type)
|
|
241
|
+
if node_id in seen:
|
|
242
|
+
continue
|
|
243
|
+
seen.add(node_id)
|
|
244
|
+
|
|
245
|
+
name_node = node.child_by_field_name("name")
|
|
246
|
+
if not name_node:
|
|
247
|
+
continue
|
|
248
|
+
class_name = self._get_node_text(name_node)
|
|
249
|
+
start_line = node.start_point[0] + 1
|
|
250
|
+
end_line = node.end_point[0] + 1
|
|
251
|
+
|
|
252
|
+
kind = node.type
|
|
253
|
+
if cap == "class_node":
|
|
254
|
+
kind = "typeclass"
|
|
255
|
+
|
|
256
|
+
class_data: Dict[str, Any] = {
|
|
257
|
+
"name": class_name,
|
|
258
|
+
"line_number": start_line,
|
|
259
|
+
"end_line": end_line,
|
|
260
|
+
"bases": [],
|
|
261
|
+
"path": str(path),
|
|
262
|
+
"lang": self.language_name,
|
|
263
|
+
"kind": kind,
|
|
264
|
+
}
|
|
265
|
+
if self.index_source:
|
|
266
|
+
class_data["source"] = self._get_node_text(node)
|
|
267
|
+
classes.append(class_data)
|
|
268
|
+
|
|
269
|
+
return classes
|
|
270
|
+
|
|
271
|
+
def _parse_variables(
|
|
272
|
+
self, captures: List[Tuple[Any, str]], source_code: str, path: Path
|
|
273
|
+
) -> List[Dict[str, Any]]:
|
|
274
|
+
variables: List[Dict[str, Any]] = []
|
|
275
|
+
seen: set = set()
|
|
276
|
+
|
|
277
|
+
for node, cap in captures:
|
|
278
|
+
if cap == "signature_node":
|
|
279
|
+
name_node = node.child_by_field_name("name")
|
|
280
|
+
if not name_node:
|
|
281
|
+
continue
|
|
282
|
+
var_name = self._get_node_text(name_node)
|
|
283
|
+
key = ("sig", node.start_byte, node.end_byte)
|
|
284
|
+
if key in seen:
|
|
285
|
+
continue
|
|
286
|
+
seen.add(key)
|
|
287
|
+
type_node = node.child_by_field_name("type")
|
|
288
|
+
var_type = self._get_node_text(type_node) if type_node else "Unknown"
|
|
289
|
+
start_line = node.start_point[0] + 1
|
|
290
|
+
ctx_name, ctx_type, ctx_line = self._get_parent_context(node)
|
|
291
|
+
variables.append(
|
|
292
|
+
{
|
|
293
|
+
"name": var_name,
|
|
294
|
+
"type": var_type,
|
|
295
|
+
"line_number": start_line,
|
|
296
|
+
"path": str(path),
|
|
297
|
+
"lang": self.language_name,
|
|
298
|
+
"context": ctx_name,
|
|
299
|
+
"class_context": ctx_name
|
|
300
|
+
if ctx_type and ctx_type in ("class", "instance")
|
|
301
|
+
else None,
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
# Type parameters like `a` in `f :: a -> b` appear as `variable` under the type subtree.
|
|
305
|
+
if type_node:
|
|
306
|
+
for tv in self._variables_in_type_ast(type_node):
|
|
307
|
+
tv_key = ("tv", tv.start_byte, tv.end_byte)
|
|
308
|
+
if tv_key in seen:
|
|
309
|
+
continue
|
|
310
|
+
seen.add(tv_key)
|
|
311
|
+
tctx_name, tctx_type, _ = self._get_parent_context(tv)
|
|
312
|
+
variables.append(
|
|
313
|
+
{
|
|
314
|
+
"name": self._get_node_text(tv),
|
|
315
|
+
"type": "type_variable",
|
|
316
|
+
"line_number": tv.start_point[0] + 1,
|
|
317
|
+
"path": str(path),
|
|
318
|
+
"lang": self.language_name,
|
|
319
|
+
"context": tctx_name,
|
|
320
|
+
"class_context": tctx_name
|
|
321
|
+
if tctx_type and tctx_type in ("class", "instance")
|
|
322
|
+
else None,
|
|
323
|
+
}
|
|
324
|
+
)
|
|
325
|
+
return variables
|
|
326
|
+
|
|
327
|
+
def _variables_in_type_ast(self, type_root: Any) -> List[Any]:
|
|
328
|
+
"""Collect `variable` nodes that appear in a type (tree-sitter-haskell type parameters)."""
|
|
329
|
+
found: List[Any] = []
|
|
330
|
+
|
|
331
|
+
def walk(n: Any) -> None:
|
|
332
|
+
if n.type == "variable":
|
|
333
|
+
found.append(n)
|
|
334
|
+
return
|
|
335
|
+
for c in n.children:
|
|
336
|
+
walk(c)
|
|
337
|
+
|
|
338
|
+
walk(type_root)
|
|
339
|
+
return found
|
|
340
|
+
|
|
341
|
+
def _parse_imports(self, captures: List[Tuple[Any, str]], source_code: str) -> List[Dict[str, Any]]:
|
|
342
|
+
imports: List[Dict[str, Any]] = []
|
|
343
|
+
for node, cap in captures:
|
|
344
|
+
if cap != "import" or node.type != "import":
|
|
345
|
+
continue
|
|
346
|
+
try:
|
|
347
|
+
mod = node.child_by_field_name("module")
|
|
348
|
+
path_str = self._get_node_text(mod).strip() if mod else ""
|
|
349
|
+
alias_node = node.child_by_field_name("alias")
|
|
350
|
+
alias = self._get_node_text(alias_node).strip() if alias_node else None
|
|
351
|
+
imports.append(
|
|
352
|
+
{
|
|
353
|
+
"name": path_str,
|
|
354
|
+
"full_import_name": path_str,
|
|
355
|
+
"line_number": node.start_point[0] + 1,
|
|
356
|
+
"alias": alias,
|
|
357
|
+
"context": (None, None),
|
|
358
|
+
"lang": self.language_name,
|
|
359
|
+
"is_dependency": False,
|
|
360
|
+
}
|
|
361
|
+
)
|
|
362
|
+
except Exception:
|
|
363
|
+
continue
|
|
364
|
+
return imports
|
|
365
|
+
|
|
366
|
+
def _parse_calls(
|
|
367
|
+
self, captures: List[Tuple[Any, str]], source_code: str, path: Path
|
|
368
|
+
) -> List[Dict[str, Any]]:
|
|
369
|
+
calls: List[Dict[str, Any]] = []
|
|
370
|
+
seen_calls: set = set()
|
|
371
|
+
|
|
372
|
+
for node, cap in captures:
|
|
373
|
+
if cap != "apply_node" or node.type != "apply":
|
|
374
|
+
continue
|
|
375
|
+
callee = node.child_by_field_name("function")
|
|
376
|
+
if not callee or callee.type != "variable":
|
|
377
|
+
continue
|
|
378
|
+
call_name = self._get_node_text(callee)
|
|
379
|
+
if not call_name:
|
|
380
|
+
continue
|
|
381
|
+
key = (node.start_byte, node.end_byte)
|
|
382
|
+
if key in seen_calls:
|
|
383
|
+
continue
|
|
384
|
+
seen_calls.add(key)
|
|
385
|
+
|
|
386
|
+
start_line = node.start_point[0] + 1
|
|
387
|
+
ctx_name, ctx_type, ctx_line = self._get_parent_context(node)
|
|
388
|
+
calls.append(
|
|
389
|
+
{
|
|
390
|
+
"name": call_name,
|
|
391
|
+
"full_name": call_name,
|
|
392
|
+
"line_number": start_line,
|
|
393
|
+
"args": [],
|
|
394
|
+
"inferred_obj_type": None,
|
|
395
|
+
"context": (ctx_name, ctx_type, ctx_line),
|
|
396
|
+
"class_context": (ctx_name, ctx_line)
|
|
397
|
+
if ctx_type and ctx_type in ("class", "instance")
|
|
398
|
+
else (None, None),
|
|
399
|
+
"lang": self.language_name,
|
|
400
|
+
"is_dependency": False,
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
return calls
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def pre_scan_haskell(files: list[Path], parser_wrapper) -> dict:
|
|
407
|
+
"""Map declared names to file paths using lightweight regex (no full parse)."""
|
|
408
|
+
name_to_files: dict = {}
|
|
409
|
+
patterns = [
|
|
410
|
+
(re.compile(r"^(\w+)\s*::", re.MULTILINE), None),
|
|
411
|
+
(re.compile(r"^data\s+(\w+)", re.MULTILINE), None),
|
|
412
|
+
(re.compile(r"^class\s+(\w+)", re.MULTILINE), None),
|
|
413
|
+
(re.compile(r"^newtype\s+(\w+)", re.MULTILINE), None),
|
|
414
|
+
(re.compile(r"^type\s+(\w+)", re.MULTILINE), None),
|
|
415
|
+
]
|
|
416
|
+
for path in files:
|
|
417
|
+
try:
|
|
418
|
+
with open(path, "r", encoding="utf-8", errors="ignore") as f:
|
|
419
|
+
content = f.read()
|
|
420
|
+
for rx, _ in patterns:
|
|
421
|
+
for m in rx.finditer(content):
|
|
422
|
+
name = m.group(1)
|
|
423
|
+
name_to_files.setdefault(name, []).append(str(path))
|
|
424
|
+
except Exception:
|
|
425
|
+
pass
|
|
426
|
+
return name_to_files
|