victor-coding 0.14.0__tar.gz → 0.15.0__tar.gz
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.
- {victor_coding-0.14.0 → victor_coding-0.15.0}/PKG-INFO +1 -1
- {victor_coding-0.14.0 → victor_coding-0.15.0}/pyproject.toml +1 -1
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/base.py +92 -1
- victor_coding-0.15.0/victor_coding/languages/plugins/_ecmascript.py +208 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/additional.py +24 -117
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/cpp.py +22 -92
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/go.py +14 -39
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/java.py +0 -16
- victor_coding-0.15.0/victor_coding/languages/plugins/javascript.py +163 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/python.py +7 -50
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/rust.py +26 -57
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/typescript.py +10 -160
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding.egg-info/PKG-INFO +1 -1
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding.egg-info/SOURCES.txt +1 -0
- victor_coding-0.14.0/victor_coding/languages/plugins/javascript.py +0 -324
- {victor_coding-0.14.0 → victor_coding-0.15.0}/LICENSE +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/README.md +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/setup.cfg +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_api_router_provider.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_coding_capabilities.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_coding_handlers.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_coding_vertical_rl.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_coding_vertical_teams.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_coding_vertical_workflows.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_enhanced_integration.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_extension_cache.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_framework_lsp_adapter.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_graph_backend_marker.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_personas.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/tests/test_protocol_providers.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/api/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/api/router_provider.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/assistant.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/capabilities.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/architecture_analyzer.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/ccg_builder.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/chunker.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/embeddings/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/embeddings/chunker.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/graph/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/graph/registry.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/ignore_patterns.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/indexer.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/query_expander.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/symbol_extractor.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/symbol_resolver.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/symbol_store.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/tree_sitter_analysis.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/tree_sitter_extractor.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/tree_sitter_manager.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/tree_sitter_service.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase/unified_extractor.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/codebase_analyzer.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/compat/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/compat/settings.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/composed_chains.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/conversation_enhanced.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/coverage/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/coverage/manager.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/coverage/parser.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/coverage/parsers/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/coverage/protocol.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/coverage/visualizer.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/docgen/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/docgen/formatter.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/docgen/manager.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/docgen/parser.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/docgen/protocol.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/editing/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/enrichment.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/escape_hatches.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/handlers.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/manager.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/config.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/registry.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/languages/tiers.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/lsp/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/lsp/client.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/lsp/config.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/lsp/framework_adapter.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/lsp/manager.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/middleware.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/mode_config.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/native/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/performance/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/performance/factory.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/performance/protocols.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/performance/registry.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/performance/service_provider.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/performance/settings.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/performance/wrappers.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/plugin.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/prompts.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/protocols.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/refactor/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/refactor/analyzer.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/refactor/manager.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/refactor/protocol.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/refactor/transforms/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/refactor/transforms/base.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/refactor/transforms/extract.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/refactor/transforms/rename.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/review/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/review/analyzers.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/review/manager.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/review/protocol.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/review/rules.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/rl/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/rl/config.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/rl/hooks.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/safety.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/safety_enhanced.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/service_provider.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/skills.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/teams/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/teams/personas.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/teams/specs.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/testgen/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/testgen/analyzer.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/testgen/generator.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/testgen/manager.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/testgen/protocol.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/tool_dependencies.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/tools/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/tools/code_executor_tool.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/tools/code_intelligence_tool.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/tools/code_search_tool.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/tools/graph_tool.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/workflows/__init__.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/workflows/bugfix.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/workflows/feature.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/workflows/provider.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding/workflows/review.py +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding.egg-info/dependency_links.txt +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding.egg-info/entry_points.txt +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding.egg-info/requires.txt +0 -0
- {victor_coding-0.14.0 → victor_coding-0.15.0}/victor_coding.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: victor-coding
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: Coding vertical for Victor AI - Software development, debugging, and code generation
|
|
5
5
|
Author-email: Vijaykumar Singh <vijay@anvaiops.com>
|
|
6
6
|
Maintainer-email: Vijaykumar Singh <vijay@anvaiops.com>
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "victor-coding"
|
|
10
|
-
version = "0.
|
|
10
|
+
version = "0.15.0"
|
|
11
11
|
description = "Coding vertical for Victor AI - Software development, debugging, and code generation"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.12"
|
|
@@ -25,12 +25,16 @@ from abc import ABC, abstractmethod
|
|
|
25
25
|
from dataclasses import dataclass, field
|
|
26
26
|
from enum import Enum
|
|
27
27
|
from pathlib import Path
|
|
28
|
+
from types import MappingProxyType
|
|
28
29
|
from typing import (
|
|
29
30
|
TYPE_CHECKING,
|
|
31
|
+
AbstractSet,
|
|
30
32
|
Any,
|
|
33
|
+
Callable,
|
|
31
34
|
Dict,
|
|
32
35
|
Iterable,
|
|
33
36
|
List,
|
|
37
|
+
Mapping,
|
|
34
38
|
Optional,
|
|
35
39
|
Protocol,
|
|
36
40
|
Tuple,
|
|
@@ -42,6 +46,67 @@ if TYPE_CHECKING:
|
|
|
42
46
|
|
|
43
47
|
logger = logging.getLogger(__name__)
|
|
44
48
|
|
|
49
|
+
#: ``(leaf_types, nested_types)`` arguments for :func:`last_named_child`.
|
|
50
|
+
PathNameTypes = Tuple[AbstractSet[str], AbstractSet[str]]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def last_named_child(
|
|
54
|
+
node: "Node",
|
|
55
|
+
leaf_types: AbstractSet[str],
|
|
56
|
+
nested_types: AbstractSet[str],
|
|
57
|
+
get_text: Callable[["Node"], Optional[str]],
|
|
58
|
+
) -> Optional[str]:
|
|
59
|
+
"""Name at the right end of a dotted / scoped path node.
|
|
60
|
+
|
|
61
|
+
Scans ``node``'s children right to left. The first ``leaf_types`` child
|
|
62
|
+
wins and its text is returned; a ``nested_types`` child (the same path
|
|
63
|
+
shape one level down) is searched recursively and its result returned
|
|
64
|
+
when non-empty. For ``obj.a.method`` / ``std::mem::drop`` this yields
|
|
65
|
+
``method`` / ``drop``.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
node: The path node (attribute, field/selector expression, ...).
|
|
69
|
+
leaf_types: Child node types holding a name segment.
|
|
70
|
+
nested_types: Child node types to recurse into; empty disables recursion.
|
|
71
|
+
get_text: Node-text accessor (typically ``BaseLanguagePlugin._get_node_text``).
|
|
72
|
+
"""
|
|
73
|
+
for child in reversed(node.children):
|
|
74
|
+
if child.type in leaf_types:
|
|
75
|
+
return get_text(child)
|
|
76
|
+
if child.type in nested_types:
|
|
77
|
+
result = last_named_child(child, leaf_types, nested_types, get_text)
|
|
78
|
+
if result:
|
|
79
|
+
return result
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def declarator_name(
|
|
84
|
+
node: "Node",
|
|
85
|
+
name_types: AbstractSet[str],
|
|
86
|
+
get_text: Callable[["Node"], Optional[str]],
|
|
87
|
+
) -> Optional[str]:
|
|
88
|
+
"""Function name of a C-family ``function_definition`` node.
|
|
89
|
+
|
|
90
|
+
Looks in the ``function_declarator`` child first (also one level inside a
|
|
91
|
+
child typed ``declarator``), then falls back to a direct child of the
|
|
92
|
+
definition. ``name_types`` are the node types accepted as the name.
|
|
93
|
+
"""
|
|
94
|
+
for child in node.children:
|
|
95
|
+
if child.type == "function_declarator":
|
|
96
|
+
for grandchild in child.children:
|
|
97
|
+
if grandchild.type == "declarator":
|
|
98
|
+
for ggchild in grandchild.children:
|
|
99
|
+
if ggchild.type in name_types:
|
|
100
|
+
return get_text(ggchild)
|
|
101
|
+
elif grandchild.type in name_types:
|
|
102
|
+
return get_text(grandchild)
|
|
103
|
+
|
|
104
|
+
for child in node.children:
|
|
105
|
+
if child.type in name_types:
|
|
106
|
+
return get_text(child)
|
|
107
|
+
|
|
108
|
+
return None
|
|
109
|
+
|
|
45
110
|
|
|
46
111
|
# ---------------------------------------------------------------------------
|
|
47
112
|
# Tree-sitter Query Types
|
|
@@ -665,8 +730,34 @@ class BaseLanguagePlugin(ABC):
|
|
|
665
730
|
"""
|
|
666
731
|
return ()
|
|
667
732
|
|
|
733
|
+
#: Child node types whose own text is the callee name (``foo()``).
|
|
734
|
+
_callee_name_types: AbstractSet[str] = frozenset()
|
|
735
|
+
#: Child node type -> ``(leaf_types, nested_types)``: the callee is the
|
|
736
|
+
#: :func:`last_named_child` of that child (``obj.method()``, ``a::b()``).
|
|
737
|
+
_callee_path_types: Mapping[str, PathNameTypes] = MappingProxyType({})
|
|
738
|
+
#: Child node types wrapping another callee expression (``(fn)()``):
|
|
739
|
+
#: :meth:`_extract_callee_name` is re-entered on that child.
|
|
740
|
+
_callee_wrapper_types: AbstractSet[str] = frozenset()
|
|
741
|
+
|
|
668
742
|
def _extract_callee_name(self, call_node: "Node") -> Optional[str]:
|
|
669
|
-
"""Return the called symbol's name for ``call_node``, or ``None``.
|
|
743
|
+
"""Return the called symbol's name for ``call_node``, or ``None``.
|
|
744
|
+
|
|
745
|
+
Default: the first child of ``call_node`` whose type appears in
|
|
746
|
+
:attr:`_callee_name_types`, :attr:`_callee_path_types` or
|
|
747
|
+
:attr:`_callee_wrapper_types` decides the result (which may be
|
|
748
|
+
``None``); later children are not consulted. With the empty default
|
|
749
|
+
tables no callee is ever found.
|
|
750
|
+
"""
|
|
751
|
+
for child in call_node.children:
|
|
752
|
+
child_type = child.type
|
|
753
|
+
if child_type in self._callee_name_types:
|
|
754
|
+
return self._get_node_text(child)
|
|
755
|
+
path_types = self._callee_path_types.get(child_type)
|
|
756
|
+
if path_types is not None:
|
|
757
|
+
leaf_types, nested_types = path_types
|
|
758
|
+
return last_named_child(child, leaf_types, nested_types, self._get_node_text)
|
|
759
|
+
if child_type in self._callee_wrapper_types:
|
|
760
|
+
return self._extract_callee_name(child)
|
|
670
761
|
return None
|
|
671
762
|
|
|
672
763
|
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Copyright 2025 Vijaykumar Singh <vijay@anvaiops.com>
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Shared base for the ECMAScript-family (JavaScript/TypeScript) plugins.
|
|
16
|
+
|
|
17
|
+
Holds the logic both plugins share verbatim -- capabilities, package.json test
|
|
18
|
+
runner detection, prettier formatting, call-node traversal and callee/member
|
|
19
|
+
name extraction. The genuine differences are expressed as class-attribute
|
|
20
|
+
hooks that ``JavaScriptPlugin`` and ``TypeScriptPlugin`` override.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import ClassVar, List, Optional, Tuple, TYPE_CHECKING
|
|
25
|
+
|
|
26
|
+
from victor_coding.languages.base import (
|
|
27
|
+
BaseLanguagePlugin,
|
|
28
|
+
ConfigurableASTTraverser,
|
|
29
|
+
Formatter,
|
|
30
|
+
LanguageCapabilities,
|
|
31
|
+
TestRunner,
|
|
32
|
+
TraversalConfig,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from tree_sitter import Node
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class EcmaScriptPluginBase(BaseLanguagePlugin):
|
|
40
|
+
"""Common behaviour of the JavaScript and TypeScript plugins.
|
|
41
|
+
|
|
42
|
+
Subclasses provide ``_create_config``/``_create_tree_sitter_queries`` and
|
|
43
|
+
may override the class-attribute hooks below.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# --- Hooks --------------------------------------------------------------
|
|
47
|
+
_supports_type_checking: ClassVar[bool] = False
|
|
48
|
+
_test_file_pattern: ClassVar[str] = "*.test.js"
|
|
49
|
+
_vitest_parallel_args: ClassVar[Tuple[str, ...]] = ()
|
|
50
|
+
_jest_parallel_args: ClassVar[Tuple[str, ...]] = ()
|
|
51
|
+
_detects_mocha: ClassVar[bool] = False
|
|
52
|
+
# Node types whose name is the first property_identifier/identifier child.
|
|
53
|
+
_method_node_types: ClassVar[Tuple[str, ...]] = ("method_definition",)
|
|
54
|
+
_extra_function_types: ClassVar[Tuple[str, ...]] = ()
|
|
55
|
+
_class_types: ClassVar[Tuple[str, ...]] = ("class_declaration",)
|
|
56
|
+
_scope_body_types: ClassVar[Tuple[str, ...]] = ("class_body",)
|
|
57
|
+
|
|
58
|
+
def _create_capabilities(self) -> LanguageCapabilities:
|
|
59
|
+
return LanguageCapabilities(
|
|
60
|
+
supports_syntax_analysis=True,
|
|
61
|
+
supports_semantic_analysis=True,
|
|
62
|
+
supports_type_checking=self._supports_type_checking,
|
|
63
|
+
supports_rename=True,
|
|
64
|
+
supports_extract_function=True,
|
|
65
|
+
supports_inline=True,
|
|
66
|
+
supports_organize_imports=True,
|
|
67
|
+
supports_test_discovery=True,
|
|
68
|
+
supports_test_execution=True,
|
|
69
|
+
supports_coverage=True,
|
|
70
|
+
supports_debugging=True,
|
|
71
|
+
supports_breakpoints=True,
|
|
72
|
+
supports_step_debugging=True,
|
|
73
|
+
supports_formatting=True,
|
|
74
|
+
supports_linting=True,
|
|
75
|
+
supports_completion=True,
|
|
76
|
+
supports_control_flow_graph=True,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def get_test_runner(self, project_root: Path) -> Optional[TestRunner]:
|
|
80
|
+
"""Detect vitest, jest (or mocha, when enabled) from package.json; default jest."""
|
|
81
|
+
package_json = project_root / "package.json"
|
|
82
|
+
pattern = self._test_file_pattern
|
|
83
|
+
|
|
84
|
+
if package_json.exists():
|
|
85
|
+
content = package_json.read_text()
|
|
86
|
+
|
|
87
|
+
if '"vitest"' in content:
|
|
88
|
+
return TestRunner(
|
|
89
|
+
name="vitest",
|
|
90
|
+
command=["npx", "vitest"],
|
|
91
|
+
file_pattern=pattern,
|
|
92
|
+
run_args=["run"],
|
|
93
|
+
coverage_args=["--coverage"],
|
|
94
|
+
parallel_args=list(self._vitest_parallel_args),
|
|
95
|
+
output_format="json",
|
|
96
|
+
json_args=["--reporter=json"],
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if '"jest"' in content:
|
|
100
|
+
return TestRunner(
|
|
101
|
+
name="jest",
|
|
102
|
+
command=["npx", "jest"],
|
|
103
|
+
file_pattern=pattern,
|
|
104
|
+
coverage_args=["--coverage"],
|
|
105
|
+
parallel_args=list(self._jest_parallel_args),
|
|
106
|
+
output_format="json",
|
|
107
|
+
json_args=["--json"],
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if self._detects_mocha and '"mocha"' in content:
|
|
111
|
+
return TestRunner(
|
|
112
|
+
name="mocha",
|
|
113
|
+
command=["npx", "mocha"],
|
|
114
|
+
file_pattern=pattern,
|
|
115
|
+
run_args=["--recursive"],
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return TestRunner(
|
|
119
|
+
name="jest",
|
|
120
|
+
command=["npx", "jest"],
|
|
121
|
+
file_pattern=pattern,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def get_formatter(self, project_root: Path) -> Optional[Formatter]:
|
|
125
|
+
"""Get prettier formatter."""
|
|
126
|
+
return Formatter(
|
|
127
|
+
name="prettier",
|
|
128
|
+
command=["npx", "prettier", "--write", "."],
|
|
129
|
+
check_args=["--check"],
|
|
130
|
+
config_file=".prettierrc",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def _find_call_nodes(
|
|
134
|
+
self,
|
|
135
|
+
root: "Node",
|
|
136
|
+
) -> List[tuple["Node", str, Optional[int]]]:
|
|
137
|
+
"""Find all call nodes with their enclosing function context."""
|
|
138
|
+
config = TraversalConfig(
|
|
139
|
+
function_types=[
|
|
140
|
+
"function_declaration",
|
|
141
|
+
"function_expression",
|
|
142
|
+
"method_definition",
|
|
143
|
+
"arrow_function",
|
|
144
|
+
*self._extra_function_types,
|
|
145
|
+
],
|
|
146
|
+
class_types=list(self._class_types),
|
|
147
|
+
call_types=["call_expression", "new_expression"],
|
|
148
|
+
name_field="identifier",
|
|
149
|
+
scope_body_types=list(self._scope_body_types),
|
|
150
|
+
)
|
|
151
|
+
traverser = ConfigurableASTTraverser(config, self._get_node_text)
|
|
152
|
+
return traverser.find_call_nodes(root)
|
|
153
|
+
|
|
154
|
+
def _extract_function_name(self, node: "Node") -> Optional[str]:
|
|
155
|
+
"""Extract function name from a function node."""
|
|
156
|
+
if node.type == "function_declaration":
|
|
157
|
+
for child in node.children:
|
|
158
|
+
if child.type == "identifier":
|
|
159
|
+
return self._get_node_text(child)
|
|
160
|
+
|
|
161
|
+
if node.type in self._method_node_types:
|
|
162
|
+
for child in node.children:
|
|
163
|
+
if child.type in ("property_identifier", "identifier"):
|
|
164
|
+
return self._get_node_text(child)
|
|
165
|
+
|
|
166
|
+
if node.type == "function_expression":
|
|
167
|
+
found_function = False
|
|
168
|
+
for child in node.children:
|
|
169
|
+
if child.type == "identifier":
|
|
170
|
+
if found_function:
|
|
171
|
+
return self._get_node_text(child)
|
|
172
|
+
elif child.type == "function":
|
|
173
|
+
found_function = True
|
|
174
|
+
|
|
175
|
+
return None
|
|
176
|
+
|
|
177
|
+
def _extract_callee_name(self, call_node: "Node") -> Optional[str]:
|
|
178
|
+
"""Extract the name of the called function from a call node."""
|
|
179
|
+
for child in call_node.children:
|
|
180
|
+
if child.type == "member_expression":
|
|
181
|
+
return self._extract_member_name(child)
|
|
182
|
+
elif child.type == "identifier":
|
|
183
|
+
return self._get_node_text(child)
|
|
184
|
+
elif child.type == "subscript_expression":
|
|
185
|
+
return self._extract_subscript_name(child)
|
|
186
|
+
|
|
187
|
+
return None
|
|
188
|
+
|
|
189
|
+
def _extract_member_name(self, member_node: "Node") -> Optional[str]:
|
|
190
|
+
"""Extract member name from a member_expression node."""
|
|
191
|
+
for child in reversed(member_node.children):
|
|
192
|
+
if child.type == "property_identifier":
|
|
193
|
+
return self._get_node_text(child)
|
|
194
|
+
elif child.type == "member_expression":
|
|
195
|
+
result = self._extract_member_name(child)
|
|
196
|
+
if result:
|
|
197
|
+
return result
|
|
198
|
+
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
def _extract_subscript_name(self, subscript_node: "Node") -> Optional[str]:
|
|
202
|
+
"""Extract method name from subscript expression."""
|
|
203
|
+
for child in subscript_node.children:
|
|
204
|
+
if child.type == "string":
|
|
205
|
+
text = self._get_node_text(child)
|
|
206
|
+
if text:
|
|
207
|
+
return text.strip("\"'")
|
|
208
|
+
return None
|
|
@@ -32,6 +32,7 @@ These plugins support embedding-based indexing for:
|
|
|
32
32
|
- Markdown/reStructuredText
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
|
+
from types import MappingProxyType
|
|
35
36
|
from typing import Any, List, Optional, TYPE_CHECKING
|
|
36
37
|
|
|
37
38
|
from victor_coding.languages.base import (
|
|
@@ -41,6 +42,7 @@ from victor_coding.languages.base import (
|
|
|
41
42
|
LanguageConfig,
|
|
42
43
|
QueryPattern,
|
|
43
44
|
TreeSitterQueries,
|
|
45
|
+
declarator_name,
|
|
44
46
|
)
|
|
45
47
|
|
|
46
48
|
if TYPE_CHECKING:
|
|
@@ -50,6 +52,14 @@ if TYPE_CHECKING:
|
|
|
50
52
|
class CPlugin(BaseLanguagePlugin):
|
|
51
53
|
"""C language plugin."""
|
|
52
54
|
|
|
55
|
+
_function_name_types = frozenset({"identifier"})
|
|
56
|
+
# Callee hooks: foo() / ptr->method() (field_identifier of the outermost
|
|
57
|
+
# field_expression only; C does not recurse into nested field_expressions).
|
|
58
|
+
_callee_name_types = frozenset({"identifier"})
|
|
59
|
+
_callee_path_types = MappingProxyType(
|
|
60
|
+
{"field_expression": (frozenset({"field_identifier"}), frozenset())}
|
|
61
|
+
)
|
|
62
|
+
|
|
53
63
|
def _create_config(self) -> LanguageConfig:
|
|
54
64
|
return LanguageConfig(
|
|
55
65
|
name="c",
|
|
@@ -176,80 +186,25 @@ class CPlugin(BaseLanguagePlugin):
|
|
|
176
186
|
return results
|
|
177
187
|
|
|
178
188
|
def _extract_function_name_c(self, node: "Node") -> Optional[str]:
|
|
179
|
-
"""Extract function name from a function definition node.
|
|
180
|
-
|
|
181
|
-
Args:
|
|
182
|
-
node: Function definition node
|
|
183
|
-
|
|
184
|
-
Returns:
|
|
185
|
-
Function name or None
|
|
186
|
-
"""
|
|
187
|
-
# Look for function_declarator
|
|
188
|
-
for child in node.children:
|
|
189
|
-
if child.type == "function_declarator":
|
|
190
|
-
# Get the declarator (identifier)
|
|
191
|
-
for grandchild in child.children:
|
|
192
|
-
if grandchild.type == "declarator":
|
|
193
|
-
for ggchild in grandchild.children:
|
|
194
|
-
if ggchild.type == "identifier":
|
|
195
|
-
return self._get_node_text(ggchild)
|
|
196
|
-
elif grandchild.type == "identifier":
|
|
197
|
-
return self._get_node_text(grandchild)
|
|
198
|
-
|
|
199
|
-
# Fallback: look for identifier directly
|
|
200
|
-
for child in node.children:
|
|
201
|
-
if child.type == "identifier":
|
|
202
|
-
return self._get_node_text(child)
|
|
203
|
-
|
|
204
|
-
return None
|
|
205
|
-
|
|
206
|
-
def _extract_callee_name(self, call_node: "Node") -> Optional[str]:
|
|
207
|
-
"""Extract the name of the called function from a call node.
|
|
208
|
-
|
|
209
|
-
Handles:
|
|
210
|
-
- Simple calls: foo()
|
|
211
|
-
- Field expression calls: ptr->method()
|
|
212
|
-
|
|
213
|
-
Args:
|
|
214
|
-
call_node: Call expression node
|
|
215
|
-
|
|
216
|
-
Returns:
|
|
217
|
-
Callee name or None
|
|
218
|
-
"""
|
|
219
|
-
# Get the function part of the call
|
|
220
|
-
for child in call_node.children:
|
|
221
|
-
if child.type == "field_expression":
|
|
222
|
-
# ptr->method() -> extract "method"
|
|
223
|
-
return self._extract_field_name_c(child)
|
|
224
|
-
elif child.type == "identifier":
|
|
225
|
-
# foo() -> extract "foo"
|
|
226
|
-
return self._get_node_text(child)
|
|
227
|
-
|
|
228
|
-
return None
|
|
229
|
-
|
|
230
|
-
def _extract_field_name_c(self, field_node: "Node") -> Optional[str]:
|
|
231
|
-
"""Extract field name from a field_expression node.
|
|
232
|
-
|
|
233
|
-
For ptr->method, extracts "method".
|
|
234
|
-
|
|
235
|
-
Args:
|
|
236
|
-
field_node: Field expression node
|
|
237
|
-
|
|
238
|
-
Returns:
|
|
239
|
-
Field name or None
|
|
240
|
-
"""
|
|
241
|
-
# field_expression: argument . field: (field_identifier)
|
|
242
|
-
# or for pointer access: argument -> field: (field_identifier)
|
|
243
|
-
for child in reversed(field_node.children):
|
|
244
|
-
if child.type == "field_identifier":
|
|
245
|
-
return self._get_node_text(child)
|
|
246
|
-
|
|
247
|
-
return None
|
|
189
|
+
"""Extract function name from a function definition node."""
|
|
190
|
+
return declarator_name(node, self._function_name_types, self._get_node_text)
|
|
248
191
|
|
|
249
192
|
|
|
250
193
|
class KotlinPlugin(BaseLanguagePlugin):
|
|
251
194
|
"""Kotlin language plugin."""
|
|
252
195
|
|
|
196
|
+
# Callee hooks: foo() / obj?.a.method() (last identifier of a
|
|
197
|
+
# navigation_expression chain).
|
|
198
|
+
_callee_name_types = frozenset({"identifier"})
|
|
199
|
+
_callee_path_types = MappingProxyType(
|
|
200
|
+
{
|
|
201
|
+
"navigation_expression": (
|
|
202
|
+
frozenset({"identifier"}),
|
|
203
|
+
frozenset({"navigation_expression"}),
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
|
|
253
208
|
def _create_config(self) -> LanguageConfig:
|
|
254
209
|
return LanguageConfig(
|
|
255
210
|
name="kotlin",
|
|
@@ -412,54 +367,6 @@ class KotlinPlugin(BaseLanguagePlugin):
|
|
|
412
367
|
traverse(root)
|
|
413
368
|
return results
|
|
414
369
|
|
|
415
|
-
def _extract_callee_name(self, call_node: "Node") -> Optional[str]:
|
|
416
|
-
"""Extract the name of the called function from a call node.
|
|
417
|
-
|
|
418
|
-
Handles:
|
|
419
|
-
- Simple calls: foo()
|
|
420
|
-
- Navigation expressions: obj.method()
|
|
421
|
-
- Safe navigation: obj?.method()
|
|
422
|
-
|
|
423
|
-
Args:
|
|
424
|
-
call_node: Call expression node
|
|
425
|
-
|
|
426
|
-
Returns:
|
|
427
|
-
Callee name or None
|
|
428
|
-
"""
|
|
429
|
-
for child in call_node.children:
|
|
430
|
-
if child.type == "navigation_expression":
|
|
431
|
-
# obj.method() -> extract "method"
|
|
432
|
-
return self._extract_navigation_name(child)
|
|
433
|
-
elif child.type == "identifier":
|
|
434
|
-
# foo() -> extract "foo"
|
|
435
|
-
return self._get_node_text(child)
|
|
436
|
-
|
|
437
|
-
return None
|
|
438
|
-
|
|
439
|
-
def _extract_navigation_name(self, navigation_node: "Node") -> Optional[str]:
|
|
440
|
-
"""Extract method name from a navigation_expression node.
|
|
441
|
-
|
|
442
|
-
For obj.method, extracts "method".
|
|
443
|
-
Handles safe navigation: obj?.method
|
|
444
|
-
|
|
445
|
-
Args:
|
|
446
|
-
navigation_node: Navigation expression node
|
|
447
|
-
|
|
448
|
-
Returns:
|
|
449
|
-
Method name or None
|
|
450
|
-
"""
|
|
451
|
-
# navigation_expression can be nested: obj1.obj2.method
|
|
452
|
-
# We want the last identifier (not simple_identifier!)
|
|
453
|
-
for child in reversed(navigation_node.children):
|
|
454
|
-
if child.type == "identifier":
|
|
455
|
-
return self._get_node_text(child)
|
|
456
|
-
elif child.type == "navigation_expression":
|
|
457
|
-
result = self._extract_navigation_name(child)
|
|
458
|
-
if result:
|
|
459
|
-
return result
|
|
460
|
-
|
|
461
|
-
return None
|
|
462
|
-
|
|
463
370
|
|
|
464
371
|
class CSharpPlugin(BaseLanguagePlugin):
|
|
465
372
|
"""C# language plugin."""
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"""C++ language plugin."""
|
|
16
16
|
|
|
17
17
|
from pathlib import Path
|
|
18
|
+
from types import MappingProxyType
|
|
18
19
|
from typing import List, Optional, TYPE_CHECKING
|
|
19
20
|
|
|
20
21
|
from victor_coding.languages.base import (
|
|
@@ -29,6 +30,7 @@ from victor_coding.languages.base import (
|
|
|
29
30
|
QueryPattern,
|
|
30
31
|
TestRunner,
|
|
31
32
|
TreeSitterQueries,
|
|
33
|
+
declarator_name,
|
|
32
34
|
)
|
|
33
35
|
|
|
34
36
|
if TYPE_CHECKING:
|
|
@@ -45,6 +47,25 @@ class CppPlugin(BaseLanguagePlugin):
|
|
|
45
47
|
- Building: CMake, Make
|
|
46
48
|
"""
|
|
47
49
|
|
|
50
|
+
_function_name_types = frozenset({"identifier", "field_identifier"})
|
|
51
|
+
# Callee hooks: foo() / obj.a.method() / ns::Klass::create() (last name
|
|
52
|
+
# segment of the path) / foo<T>() (template_function re-entered: its only
|
|
53
|
+
# name child is the template identifier).
|
|
54
|
+
_callee_name_types = frozenset({"identifier"})
|
|
55
|
+
_callee_path_types = MappingProxyType(
|
|
56
|
+
{
|
|
57
|
+
"field_expression": (
|
|
58
|
+
frozenset({"field_identifier"}),
|
|
59
|
+
frozenset({"field_expression"}),
|
|
60
|
+
),
|
|
61
|
+
"qualified_identifier": (
|
|
62
|
+
frozenset({"identifier"}),
|
|
63
|
+
frozenset({"qualified_identifier"}),
|
|
64
|
+
),
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
_callee_wrapper_types = frozenset({"template_function"})
|
|
68
|
+
|
|
48
69
|
def _create_config(self) -> LanguageConfig:
|
|
49
70
|
return LanguageConfig(
|
|
50
71
|
name="cpp",
|
|
@@ -311,95 +332,4 @@ class CppPlugin(BaseLanguagePlugin):
|
|
|
311
332
|
|
|
312
333
|
C++ functions can have complex declarators. This handles the common cases.
|
|
313
334
|
"""
|
|
314
|
-
|
|
315
|
-
for child in node.children:
|
|
316
|
-
if child.type == "function_declarator":
|
|
317
|
-
# Get the declarator (identifier or field_identifier)
|
|
318
|
-
for grandchild in child.children:
|
|
319
|
-
if grandchild.type == "declarator":
|
|
320
|
-
for ggchild in grandchild.children:
|
|
321
|
-
if ggchild.type in ("identifier", "field_identifier"):
|
|
322
|
-
return self._get_node_text(ggchild)
|
|
323
|
-
elif grandchild.type in ("identifier", "field_identifier"):
|
|
324
|
-
return self._get_node_text(grandchild)
|
|
325
|
-
|
|
326
|
-
# Fallback: look for identifier directly
|
|
327
|
-
for child in node.children:
|
|
328
|
-
if child.type in ("identifier", "field_identifier"):
|
|
329
|
-
return self._get_node_text(child)
|
|
330
|
-
|
|
331
|
-
return None
|
|
332
|
-
|
|
333
|
-
def _extract_callee_name(self, call_node: "Node") -> Optional[str]:
|
|
334
|
-
"""Extract the name of the called function from a call node.
|
|
335
|
-
|
|
336
|
-
Handles:
|
|
337
|
-
- Simple calls: foo()
|
|
338
|
-
- Field access calls: obj.method()
|
|
339
|
-
- Template calls: foo<T>()
|
|
340
|
-
- Namespace-qualified calls: std::foo()
|
|
341
|
-
"""
|
|
342
|
-
# Get the function part of the call
|
|
343
|
-
for child in call_node.children:
|
|
344
|
-
if child.type == "field_expression":
|
|
345
|
-
# obj.method() -> extract "method"
|
|
346
|
-
return self._extract_field_name(child)
|
|
347
|
-
elif child.type == "template_function":
|
|
348
|
-
# foo<T>() -> extract "foo"
|
|
349
|
-
return self._extract_template_name(child)
|
|
350
|
-
elif child.type == "identifier":
|
|
351
|
-
# foo() -> extract "foo"
|
|
352
|
-
return self._get_node_text(child)
|
|
353
|
-
elif child.type == "qualified_identifier":
|
|
354
|
-
# std::foo -> extract "foo"
|
|
355
|
-
return self._extract_qualified_name(child)
|
|
356
|
-
|
|
357
|
-
return None
|
|
358
|
-
|
|
359
|
-
def _extract_field_name(self, field_node: "Node") -> Optional[str]:
|
|
360
|
-
"""Extract field name from a field_expression node.
|
|
361
|
-
|
|
362
|
-
For obj.method, extracts "method".
|
|
363
|
-
For obj.field1.field2, extracts "field2" (the final field).
|
|
364
|
-
"""
|
|
365
|
-
# field_expression: object (identifier or field_expression) . field: (field_identifier)
|
|
366
|
-
for child in reversed(field_node.children):
|
|
367
|
-
if child.type == "field_identifier":
|
|
368
|
-
return self._get_node_text(child)
|
|
369
|
-
elif child.type == "field_expression":
|
|
370
|
-
result = self._extract_field_name(child)
|
|
371
|
-
if result:
|
|
372
|
-
return result
|
|
373
|
-
|
|
374
|
-
return None
|
|
375
|
-
|
|
376
|
-
def _extract_template_name(self, template_node: "Node") -> Optional[str]:
|
|
377
|
-
"""Extract the base name from a template function.
|
|
378
|
-
|
|
379
|
-
For foo<T>(), extracts "foo".
|
|
380
|
-
"""
|
|
381
|
-
for child in template_node.children:
|
|
382
|
-
if child.type == "identifier":
|
|
383
|
-
return self._get_node_text(child)
|
|
384
|
-
elif child.type == "field_expression":
|
|
385
|
-
return self._extract_field_name(child)
|
|
386
|
-
|
|
387
|
-
return None
|
|
388
|
-
|
|
389
|
-
def _extract_qualified_name(self, qualified_node: "Node") -> Optional[str]:
|
|
390
|
-
"""Extract the final identifier from a qualified identifier.
|
|
391
|
-
|
|
392
|
-
For std::foo, extracts "foo".
|
|
393
|
-
For ns::Class::method, extracts "method".
|
|
394
|
-
"""
|
|
395
|
-
# qualified_identifier: identifier :: identifier (or nested)
|
|
396
|
-
# We want the last identifier
|
|
397
|
-
for child in reversed(qualified_node.children):
|
|
398
|
-
if child.type == "identifier":
|
|
399
|
-
return self._get_node_text(child)
|
|
400
|
-
elif child.type == "qualified_identifier":
|
|
401
|
-
result = self._extract_qualified_name(child)
|
|
402
|
-
if result:
|
|
403
|
-
return result
|
|
404
|
-
|
|
405
|
-
return None
|
|
335
|
+
return declarator_name(node, self._function_name_types, self._get_node_text)
|