code-graph-builder 0.2.0__py3-none-any.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.
- code_graph_builder/__init__.py +82 -0
- code_graph_builder/builder.py +366 -0
- code_graph_builder/cgb_cli.py +32 -0
- code_graph_builder/cli.py +564 -0
- code_graph_builder/commands_cli.py +1288 -0
- code_graph_builder/config.py +340 -0
- code_graph_builder/constants.py +708 -0
- code_graph_builder/embeddings/__init__.py +40 -0
- code_graph_builder/embeddings/qwen3_embedder.py +573 -0
- code_graph_builder/embeddings/vector_store.py +584 -0
- code_graph_builder/examples/__init__.py +0 -0
- code_graph_builder/examples/example_configuration.py +276 -0
- code_graph_builder/examples/example_kuzu_usage.py +109 -0
- code_graph_builder/examples/example_semantic_search_full.py +347 -0
- code_graph_builder/examples/generate_wiki.py +915 -0
- code_graph_builder/examples/graph_export_example.py +100 -0
- code_graph_builder/examples/rag_example.py +206 -0
- code_graph_builder/examples/test_cli_demo.py +129 -0
- code_graph_builder/examples/test_embedding_api.py +153 -0
- code_graph_builder/examples/test_kuzu_local.py +190 -0
- code_graph_builder/examples/test_rag_redis.py +390 -0
- code_graph_builder/graph_updater.py +605 -0
- code_graph_builder/guidance/__init__.py +1 -0
- code_graph_builder/guidance/agent.py +123 -0
- code_graph_builder/guidance/prompts.py +74 -0
- code_graph_builder/guidance/toolset.py +264 -0
- code_graph_builder/language_spec.py +536 -0
- code_graph_builder/mcp/__init__.py +21 -0
- code_graph_builder/mcp/api_doc_generator.py +764 -0
- code_graph_builder/mcp/file_editor.py +207 -0
- code_graph_builder/mcp/pipeline.py +777 -0
- code_graph_builder/mcp/server.py +161 -0
- code_graph_builder/mcp/tools.py +1800 -0
- code_graph_builder/models.py +115 -0
- code_graph_builder/parser_loader.py +344 -0
- code_graph_builder/parsers/__init__.py +7 -0
- code_graph_builder/parsers/call_processor.py +306 -0
- code_graph_builder/parsers/call_resolver.py +139 -0
- code_graph_builder/parsers/definition_processor.py +796 -0
- code_graph_builder/parsers/factory.py +119 -0
- code_graph_builder/parsers/import_processor.py +293 -0
- code_graph_builder/parsers/structure_processor.py +145 -0
- code_graph_builder/parsers/type_inference.py +143 -0
- code_graph_builder/parsers/utils.py +134 -0
- code_graph_builder/rag/__init__.py +68 -0
- code_graph_builder/rag/camel_agent.py +429 -0
- code_graph_builder/rag/client.py +298 -0
- code_graph_builder/rag/config.py +239 -0
- code_graph_builder/rag/cypher_generator.py +67 -0
- code_graph_builder/rag/llm_backend.py +210 -0
- code_graph_builder/rag/markdown_generator.py +352 -0
- code_graph_builder/rag/prompt_templates.py +440 -0
- code_graph_builder/rag/rag_engine.py +640 -0
- code_graph_builder/rag/review_report.md +172 -0
- code_graph_builder/rag/tests/__init__.py +3 -0
- code_graph_builder/rag/tests/test_camel_agent.py +313 -0
- code_graph_builder/rag/tests/test_client.py +221 -0
- code_graph_builder/rag/tests/test_config.py +177 -0
- code_graph_builder/rag/tests/test_markdown_generator.py +240 -0
- code_graph_builder/rag/tests/test_prompt_templates.py +160 -0
- code_graph_builder/services/__init__.py +39 -0
- code_graph_builder/services/graph_service.py +465 -0
- code_graph_builder/services/kuzu_service.py +665 -0
- code_graph_builder/services/memory_service.py +171 -0
- code_graph_builder/settings.py +75 -0
- code_graph_builder/tests/ACCEPTANCE_CRITERIA_PHASE2.md +401 -0
- code_graph_builder/tests/__init__.py +1 -0
- code_graph_builder/tests/run_acceptance_check.py +378 -0
- code_graph_builder/tests/test_api_find.py +231 -0
- code_graph_builder/tests/test_api_find_integration.py +226 -0
- code_graph_builder/tests/test_basic.py +78 -0
- code_graph_builder/tests/test_c_api_extraction.py +388 -0
- code_graph_builder/tests/test_call_resolution_scenarios.py +504 -0
- code_graph_builder/tests/test_embedder.py +411 -0
- code_graph_builder/tests/test_integration_semantic.py +434 -0
- code_graph_builder/tests/test_mcp_protocol.py +298 -0
- code_graph_builder/tests/test_mcp_user_flow.py +190 -0
- code_graph_builder/tests/test_rag.py +404 -0
- code_graph_builder/tests/test_settings.py +135 -0
- code_graph_builder/tests/test_step1_graph_build.py +264 -0
- code_graph_builder/tests/test_step2_api_docs.py +323 -0
- code_graph_builder/tests/test_step3_embedding.py +278 -0
- code_graph_builder/tests/test_vector_store.py +552 -0
- code_graph_builder/tools/__init__.py +40 -0
- code_graph_builder/tools/graph_query.py +495 -0
- code_graph_builder/tools/semantic_search.py +387 -0
- code_graph_builder/types.py +333 -0
- code_graph_builder/utils/__init__.py +0 -0
- code_graph_builder/utils/path_utils.py +30 -0
- code_graph_builder-0.2.0.dist-info/METADATA +321 -0
- code_graph_builder-0.2.0.dist-info/RECORD +93 -0
- code_graph_builder-0.2.0.dist-info/WHEEL +4 -0
- code_graph_builder-0.2.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Code Graph Builder - Data Models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import TYPE_CHECKING, Callable, NamedTuple
|
|
8
|
+
|
|
9
|
+
from .constants import SupportedLanguage
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from tree_sitter import Node
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class LanguageSpec:
|
|
17
|
+
"""Specification for a programming language."""
|
|
18
|
+
|
|
19
|
+
language: SupportedLanguage | str
|
|
20
|
+
file_extensions: tuple[str, ...]
|
|
21
|
+
function_node_types: tuple[str, ...]
|
|
22
|
+
class_node_types: tuple[str, ...]
|
|
23
|
+
module_node_types: tuple[str, ...]
|
|
24
|
+
call_node_types: tuple[str, ...] = ()
|
|
25
|
+
import_node_types: tuple[str, ...] = ()
|
|
26
|
+
import_from_node_types: tuple[str, ...] = ()
|
|
27
|
+
name_field: str = "name"
|
|
28
|
+
body_field: str = "body"
|
|
29
|
+
package_indicators: tuple[str, ...] = ()
|
|
30
|
+
function_query: str | None = None
|
|
31
|
+
class_query: str | None = None
|
|
32
|
+
call_query: str | None = None
|
|
33
|
+
typedef_query: str | None = None
|
|
34
|
+
macro_query: str | None = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class FQNSpec(NamedTuple):
|
|
38
|
+
"""Specification for building fully qualified names."""
|
|
39
|
+
|
|
40
|
+
scope_node_types: frozenset[str]
|
|
41
|
+
function_node_types: frozenset[str]
|
|
42
|
+
get_name: Callable[["Node"], str | None]
|
|
43
|
+
file_to_module_parts: Callable[[Path, Path], list[str]]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class Dependency:
|
|
48
|
+
"""Represents a project dependency."""
|
|
49
|
+
|
|
50
|
+
name: str
|
|
51
|
+
spec: str
|
|
52
|
+
properties: dict[str, str] = field(default_factory=dict)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class GraphNode:
|
|
57
|
+
"""Represents a node in the graph."""
|
|
58
|
+
|
|
59
|
+
node_id: int
|
|
60
|
+
labels: list[str]
|
|
61
|
+
properties: dict[str, PropertyValue]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass
|
|
65
|
+
class GraphRelationship:
|
|
66
|
+
"""Represents a relationship in the graph."""
|
|
67
|
+
|
|
68
|
+
from_id: int
|
|
69
|
+
to_id: int
|
|
70
|
+
type: str
|
|
71
|
+
properties: dict[str, PropertyValue]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class FunctionInfo:
|
|
76
|
+
"""Information about a function."""
|
|
77
|
+
|
|
78
|
+
name: str
|
|
79
|
+
qualified_name: str
|
|
80
|
+
start_line: int
|
|
81
|
+
end_line: int
|
|
82
|
+
docstring: str | None
|
|
83
|
+
decorators: list[str]
|
|
84
|
+
is_method: bool
|
|
85
|
+
parent_class: str | None
|
|
86
|
+
return_type: str | None = None
|
|
87
|
+
parameters: list[str] | None = None
|
|
88
|
+
signature: str | None = None
|
|
89
|
+
visibility: str | None = None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class ClassInfo:
|
|
94
|
+
"""Information about a class."""
|
|
95
|
+
|
|
96
|
+
name: str
|
|
97
|
+
qualified_name: str
|
|
98
|
+
start_line: int
|
|
99
|
+
end_line: int
|
|
100
|
+
parent_classes: list[str]
|
|
101
|
+
decorators: list[str]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@dataclass
|
|
105
|
+
class CallInfo:
|
|
106
|
+
"""Information about a function call."""
|
|
107
|
+
|
|
108
|
+
caller_qualified_name: str
|
|
109
|
+
callee_name: str
|
|
110
|
+
callee_qualified_name: str | None
|
|
111
|
+
line_number: int
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# Type alias for property values
|
|
115
|
+
PropertyValue = str | int | float | bool | list[str] | None
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"""Code Graph Builder - Parser Loader."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from loguru import logger
|
|
13
|
+
from tree_sitter import Language, Parser, Query
|
|
14
|
+
|
|
15
|
+
from . import constants as cs
|
|
16
|
+
from .language_spec import LANGUAGE_SPECS, LanguageSpec
|
|
17
|
+
from .types import LanguageImport, LanguageLoader, LanguageQueries
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Log messages
|
|
24
|
+
BUILDING_BINDINGS = "Building Python bindings for {lang}..."
|
|
25
|
+
BUILD_FAILED = "Failed to build {lang} bindings: stdout={stdout}, stderr={stderr}"
|
|
26
|
+
BUILD_SUCCESS = "Successfully built {lang} bindings"
|
|
27
|
+
IMPORTING_MODULE = "Attempting to import module: {module}"
|
|
28
|
+
LOADED_FROM_SUBMODULE = "Successfully loaded {lang} from submodule bindings using {attr}"
|
|
29
|
+
NO_LANG_ATTR = "Module {module} imported but has no language attribute. Available: {available}"
|
|
30
|
+
SUBMODULE_LOAD_FAILED = "Failed to load {lang} from submodule bindings: {error}"
|
|
31
|
+
LIB_NOT_AVAILABLE = "Tree-sitter library for {lang} not available."
|
|
32
|
+
LOCALS_QUERY_FAILED = "Failed to create locals query for {lang}: {error}"
|
|
33
|
+
GRAMMAR_LOADED = "Successfully loaded {lang} grammar."
|
|
34
|
+
GRAMMAR_LOAD_FAILED = "Failed to load {lang} grammar: {error}"
|
|
35
|
+
INITIALIZED_PARSERS = "Initialized parsers for: {languages}"
|
|
36
|
+
NO_LANGUAGES = "No language parsers could be loaded. Please install tree-sitter language packages."
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _try_load_from_submodule(lang_name: cs.SupportedLanguage) -> LanguageLoader:
|
|
40
|
+
"""Try to load language from submodule bindings."""
|
|
41
|
+
submodule_path = Path(cs.GRAMMARS_DIR) / f"{cs.TREE_SITTER_PREFIX}{lang_name}"
|
|
42
|
+
python_bindings_path = (
|
|
43
|
+
submodule_path / cs.BINDINGS_DIR / cs.SupportedLanguage.PYTHON
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if not python_bindings_path.exists():
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
python_bindings_str = str(python_bindings_path)
|
|
50
|
+
try:
|
|
51
|
+
if python_bindings_str not in sys.path:
|
|
52
|
+
sys.path.insert(0, python_bindings_str)
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
module_name = f"{cs.TREE_SITTER_MODULE_PREFIX}{lang_name.replace('-', '_')}"
|
|
56
|
+
|
|
57
|
+
setup_py_path = submodule_path / cs.SETUP_PY
|
|
58
|
+
if setup_py_path.exists():
|
|
59
|
+
logger.debug(BUILDING_BINDINGS.format(lang=lang_name))
|
|
60
|
+
result = subprocess.run(
|
|
61
|
+
[sys.executable, cs.SETUP_PY, cs.BUILD_EXT_CMD, cs.INPLACE_FLAG],
|
|
62
|
+
check=False,
|
|
63
|
+
cwd=str(submodule_path),
|
|
64
|
+
capture_output=True,
|
|
65
|
+
text=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if result.returncode != 0:
|
|
69
|
+
logger.debug(
|
|
70
|
+
BUILD_FAILED.format(
|
|
71
|
+
lang=lang_name, stdout=result.stdout, stderr=result.stderr
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
return None
|
|
75
|
+
logger.debug(BUILD_SUCCESS.format(lang=lang_name))
|
|
76
|
+
|
|
77
|
+
logger.debug(IMPORTING_MODULE.format(module=module_name))
|
|
78
|
+
module = importlib.import_module(module_name)
|
|
79
|
+
|
|
80
|
+
language_attrs: list[str] = [
|
|
81
|
+
cs.QUERY_LANGUAGE,
|
|
82
|
+
f"{cs.LANG_ATTR_PREFIX}{lang_name}",
|
|
83
|
+
f"{cs.LANG_ATTR_PREFIX}{lang_name.replace('-', '_')}",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
for attr_name in language_attrs:
|
|
87
|
+
if hasattr(module, attr_name):
|
|
88
|
+
logger.debug(
|
|
89
|
+
LOADED_FROM_SUBMODULE.format(lang=lang_name, attr=attr_name)
|
|
90
|
+
)
|
|
91
|
+
loader: LanguageLoader = getattr(module, attr_name)
|
|
92
|
+
return loader
|
|
93
|
+
|
|
94
|
+
logger.debug(
|
|
95
|
+
NO_LANG_ATTR.format(module=module_name, available=dir(module))
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
finally:
|
|
99
|
+
if python_bindings_str in sys.path:
|
|
100
|
+
sys.path.remove(python_bindings_str)
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.debug(SUBMODULE_LOAD_FAILED.format(lang=lang_name, error=e))
|
|
104
|
+
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _try_import_language(
|
|
109
|
+
module_path: str, attr_name: str, lang_name: cs.SupportedLanguage
|
|
110
|
+
) -> LanguageLoader:
|
|
111
|
+
"""Try to import language from pip package."""
|
|
112
|
+
try:
|
|
113
|
+
module = importlib.import_module(module_path)
|
|
114
|
+
loader: LanguageLoader = getattr(module, attr_name)
|
|
115
|
+
return loader
|
|
116
|
+
except ImportError:
|
|
117
|
+
return _try_load_from_submodule(lang_name)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _import_language_loaders() -> dict[cs.SupportedLanguage, LanguageLoader]:
|
|
121
|
+
"""Import all language loaders."""
|
|
122
|
+
language_imports: list[LanguageImport] = [
|
|
123
|
+
LanguageImport(
|
|
124
|
+
cs.SupportedLanguage.PYTHON,
|
|
125
|
+
cs.TreeSitterModule.PYTHON,
|
|
126
|
+
cs.QUERY_LANGUAGE,
|
|
127
|
+
cs.SupportedLanguage.PYTHON,
|
|
128
|
+
),
|
|
129
|
+
LanguageImport(
|
|
130
|
+
cs.SupportedLanguage.JS,
|
|
131
|
+
cs.TreeSitterModule.JS,
|
|
132
|
+
cs.QUERY_LANGUAGE,
|
|
133
|
+
cs.SupportedLanguage.JS,
|
|
134
|
+
),
|
|
135
|
+
LanguageImport(
|
|
136
|
+
cs.SupportedLanguage.TS,
|
|
137
|
+
cs.TreeSitterModule.TS,
|
|
138
|
+
cs.LANG_ATTR_TYPESCRIPT,
|
|
139
|
+
cs.SupportedLanguage.TS,
|
|
140
|
+
),
|
|
141
|
+
LanguageImport(
|
|
142
|
+
cs.SupportedLanguage.RUST,
|
|
143
|
+
cs.TreeSitterModule.RUST,
|
|
144
|
+
cs.QUERY_LANGUAGE,
|
|
145
|
+
cs.SupportedLanguage.RUST,
|
|
146
|
+
),
|
|
147
|
+
LanguageImport(
|
|
148
|
+
cs.SupportedLanguage.GO,
|
|
149
|
+
cs.TreeSitterModule.GO,
|
|
150
|
+
cs.QUERY_LANGUAGE,
|
|
151
|
+
cs.SupportedLanguage.GO,
|
|
152
|
+
),
|
|
153
|
+
LanguageImport(
|
|
154
|
+
cs.SupportedLanguage.SCALA,
|
|
155
|
+
cs.TreeSitterModule.SCALA,
|
|
156
|
+
cs.QUERY_LANGUAGE,
|
|
157
|
+
cs.SupportedLanguage.SCALA,
|
|
158
|
+
),
|
|
159
|
+
LanguageImport(
|
|
160
|
+
cs.SupportedLanguage.JAVA,
|
|
161
|
+
cs.TreeSitterModule.JAVA,
|
|
162
|
+
cs.QUERY_LANGUAGE,
|
|
163
|
+
cs.SupportedLanguage.JAVA,
|
|
164
|
+
),
|
|
165
|
+
LanguageImport(
|
|
166
|
+
cs.SupportedLanguage.C,
|
|
167
|
+
cs.TreeSitterModule.C,
|
|
168
|
+
cs.QUERY_LANGUAGE,
|
|
169
|
+
cs.SupportedLanguage.C,
|
|
170
|
+
),
|
|
171
|
+
LanguageImport(
|
|
172
|
+
cs.SupportedLanguage.CPP,
|
|
173
|
+
cs.TreeSitterModule.CPP,
|
|
174
|
+
cs.QUERY_LANGUAGE,
|
|
175
|
+
cs.SupportedLanguage.CPP,
|
|
176
|
+
),
|
|
177
|
+
LanguageImport(
|
|
178
|
+
cs.SupportedLanguage.LUA,
|
|
179
|
+
cs.TreeSitterModule.LUA,
|
|
180
|
+
cs.QUERY_LANGUAGE,
|
|
181
|
+
cs.SupportedLanguage.LUA,
|
|
182
|
+
),
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
loaders: dict[cs.SupportedLanguage, LanguageLoader] = {
|
|
186
|
+
lang_import.lang_key: _try_import_language(
|
|
187
|
+
lang_import.module_path,
|
|
188
|
+
lang_import.attr_name,
|
|
189
|
+
lang_import.submodule_name,
|
|
190
|
+
)
|
|
191
|
+
for lang_import in language_imports
|
|
192
|
+
}
|
|
193
|
+
for lang_key in LANGUAGE_SPECS:
|
|
194
|
+
lang_name = cs.SupportedLanguage(lang_key)
|
|
195
|
+
if lang_name not in loaders or loaders[lang_name] is None:
|
|
196
|
+
loaders[lang_name] = _try_load_from_submodule(lang_name)
|
|
197
|
+
|
|
198
|
+
return loaders
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
_language_loaders = _import_language_loaders()
|
|
202
|
+
|
|
203
|
+
LANGUAGE_LIBRARIES: dict[cs.SupportedLanguage, LanguageLoader] = _language_loaders
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _build_query_pattern(node_types: tuple[str, ...], capture_name: str) -> str:
|
|
207
|
+
"""Build a query pattern for the given node types."""
|
|
208
|
+
return " ".join([f"({node_type}) @{capture_name}" for node_type in node_types])
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _get_locals_pattern(lang_name: cs.SupportedLanguage) -> str | None:
|
|
212
|
+
"""Get the locals query pattern for a language."""
|
|
213
|
+
match lang_name:
|
|
214
|
+
case cs.SupportedLanguage.JS:
|
|
215
|
+
return cs.JS_LOCALS_PATTERN
|
|
216
|
+
case cs.SupportedLanguage.TS:
|
|
217
|
+
return cs.TS_LOCALS_PATTERN
|
|
218
|
+
case _:
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _build_combined_import_pattern(lang_config: LanguageSpec) -> str:
|
|
223
|
+
"""Build combined import pattern for a language."""
|
|
224
|
+
import_patterns = _build_query_pattern(
|
|
225
|
+
lang_config.import_node_types, cs.CAPTURE_IMPORT
|
|
226
|
+
)
|
|
227
|
+
import_from_patterns = _build_query_pattern(
|
|
228
|
+
lang_config.import_from_node_types, cs.CAPTURE_IMPORT_FROM
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
all_patterns: list[str] = []
|
|
232
|
+
if import_patterns.strip():
|
|
233
|
+
all_patterns.append(import_patterns)
|
|
234
|
+
if import_from_patterns.strip() and import_from_patterns != import_patterns:
|
|
235
|
+
all_patterns.append(import_from_patterns)
|
|
236
|
+
return " ".join(all_patterns)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _create_optional_query(language: Language, pattern: str | None) -> Query | None:
|
|
240
|
+
"""Create a query if pattern is provided."""
|
|
241
|
+
return Query(language, pattern) if pattern else None
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _create_locals_query(
|
|
245
|
+
language: Language, lang_name: cs.SupportedLanguage
|
|
246
|
+
) -> Query | None:
|
|
247
|
+
"""Create a locals query for a language."""
|
|
248
|
+
locals_pattern = _get_locals_pattern(lang_name)
|
|
249
|
+
if not locals_pattern:
|
|
250
|
+
return None
|
|
251
|
+
try:
|
|
252
|
+
return Query(language, locals_pattern)
|
|
253
|
+
except Exception as e:
|
|
254
|
+
logger.debug(LOCALS_QUERY_FAILED.format(lang=lang_name, error=e))
|
|
255
|
+
return None
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _create_language_queries(
|
|
259
|
+
language: Language,
|
|
260
|
+
parser: Parser,
|
|
261
|
+
lang_config: LanguageSpec,
|
|
262
|
+
lang_name: cs.SupportedLanguage,
|
|
263
|
+
) -> LanguageQueries:
|
|
264
|
+
"""Create all queries for a language."""
|
|
265
|
+
function_patterns = lang_config.function_query or _build_query_pattern(
|
|
266
|
+
lang_config.function_node_types, cs.CAPTURE_FUNCTION
|
|
267
|
+
)
|
|
268
|
+
class_patterns = lang_config.class_query or _build_query_pattern(
|
|
269
|
+
lang_config.class_node_types, cs.CAPTURE_CLASS
|
|
270
|
+
)
|
|
271
|
+
call_patterns = lang_config.call_query or _build_query_pattern(
|
|
272
|
+
lang_config.call_node_types, cs.CAPTURE_CALL
|
|
273
|
+
)
|
|
274
|
+
combined_import_patterns = _build_combined_import_pattern(lang_config)
|
|
275
|
+
|
|
276
|
+
# Build optional typedef/macro queries (currently C-specific)
|
|
277
|
+
typedef_query = _create_optional_query(language, lang_config.typedef_query)
|
|
278
|
+
macro_query = _create_optional_query(language, lang_config.macro_query)
|
|
279
|
+
|
|
280
|
+
return LanguageQueries(
|
|
281
|
+
functions=_create_optional_query(language, function_patterns),
|
|
282
|
+
classes=_create_optional_query(language, class_patterns),
|
|
283
|
+
calls=_create_optional_query(language, call_patterns),
|
|
284
|
+
imports=_create_optional_query(language, combined_import_patterns),
|
|
285
|
+
locals=_create_locals_query(language, lang_name),
|
|
286
|
+
typedefs=typedef_query,
|
|
287
|
+
macros=macro_query,
|
|
288
|
+
config=lang_config,
|
|
289
|
+
language=language,
|
|
290
|
+
parser=parser,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _process_language(
|
|
295
|
+
lang_name: cs.SupportedLanguage,
|
|
296
|
+
lang_config: LanguageSpec,
|
|
297
|
+
parsers: dict[cs.SupportedLanguage, Parser],
|
|
298
|
+
queries: dict[cs.SupportedLanguage, LanguageQueries],
|
|
299
|
+
) -> bool:
|
|
300
|
+
"""Process a single language and add to parsers/queries dicts."""
|
|
301
|
+
lang_lib = LANGUAGE_LIBRARIES.get(lang_name)
|
|
302
|
+
if not lang_lib:
|
|
303
|
+
logger.debug(LIB_NOT_AVAILABLE.format(lang=lang_name))
|
|
304
|
+
return False
|
|
305
|
+
|
|
306
|
+
try:
|
|
307
|
+
language = Language(lang_lib())
|
|
308
|
+
parser = Parser(language)
|
|
309
|
+
parsers[lang_name] = parser
|
|
310
|
+
queries[lang_name] = _create_language_queries(
|
|
311
|
+
language, parser, lang_config, lang_name
|
|
312
|
+
)
|
|
313
|
+
logger.success(GRAMMAR_LOADED.format(lang=lang_name))
|
|
314
|
+
return True
|
|
315
|
+
except Exception as e:
|
|
316
|
+
logger.warning(GRAMMAR_LOAD_FAILED.format(lang=lang_name, error=e))
|
|
317
|
+
return False
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def load_parsers() -> tuple[
|
|
321
|
+
dict[cs.SupportedLanguage, Parser], dict[cs.SupportedLanguage, LanguageQueries]
|
|
322
|
+
]:
|
|
323
|
+
"""Load all available Tree-sitter parsers.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
Tuple of (parsers dict, queries dict)
|
|
327
|
+
|
|
328
|
+
Raises:
|
|
329
|
+
RuntimeError: If no language parsers could be loaded
|
|
330
|
+
"""
|
|
331
|
+
parsers: dict[cs.SupportedLanguage, Parser] = {}
|
|
332
|
+
queries: dict[cs.SupportedLanguage, LanguageQueries] = {}
|
|
333
|
+
available_languages: list[cs.SupportedLanguage] = []
|
|
334
|
+
|
|
335
|
+
for lang_key, lang_config in deepcopy(LANGUAGE_SPECS).items():
|
|
336
|
+
lang_name = cs.SupportedLanguage(lang_key)
|
|
337
|
+
if _process_language(lang_name, lang_config, parsers, queries):
|
|
338
|
+
available_languages.append(lang_name)
|
|
339
|
+
|
|
340
|
+
if not available_languages:
|
|
341
|
+
raise RuntimeError(NO_LANGUAGES)
|
|
342
|
+
|
|
343
|
+
logger.info(INITIALIZED_PARSERS.format(languages=", ".join(available_languages)))
|
|
344
|
+
return parsers, queries
|