Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions codewiki/src/be/dependency_analyzer/analyzers/cpp.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
"""C++ dependency analyzer using tree-sitter.

This module implements a tree-sitter based analyzer for C++ source files.
It extracts top-level components (classes, structs, functions, methods,
namespaces and global variables) as `Node` objects and detects relationships
between them (calls, inheritance, instantiation and usage) as
`CallRelationship` objects, for use by the dependency analysis pipeline.
"""
import logging

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 cpp.py analyzer module lacks a module-level docstring

Added a module-level docstring at the top of the file (before the import logging line) describing the module's purpose as a tree-sitter based C++ dependency analyzer, satisfying CODEWIKI-004's documentation requirement. No other code was altered.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/cpp.py around line 1, review and complete this code-review fix: cpp.py analyzer module lacks a module-level docstring.
What the draft fix changed: Added a module-level docstring at the top of the file (before the `import logging` line) describing the module's purpose as a tree-sitter based C++ dependency analyzer, satisfying CODEWIKI-004's documentation requirement. No other code was altered.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

from typing import List, Optional, Tuple
from pathlib import Path
Expand Down Expand Up @@ -46,8 +54,8 @@ def _get_relative_path(self) -> str:
def _get_component_id(self, name: str, parent_class: str = None) -> str:
module_path = self._get_module_path()
if parent_class:
return f"{module_path}.{parent_class}.{name}" if module_path else f"{parent_class}.{name}"
return f"{module_path}.{name}" if module_path else name
return f"{module_path}::{parent_class}.{name}" if module_path else f"{parent_class}.{name}"
return f"{module_path}::{name}" if module_path else name

def _analyze(self):
language_capsule = tree_sitter_cpp.language()
Comment on lines 54 to 61

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 πŸ”΄ cpp.py component IDs use '.' rather than the mandated '::' separator

In _get_component_id (line ~42), changed the module-path/name joins from . to :: so IDs are formatted as module.path::Name (and module.path::ParentClass.name for methods, preserving the parent/child dot for the method-within-class segment as before). This satisfies the module.path::ComponentName contract at the module/component boundary; the parent_class-without-module_path branch (f"{parent_class}.{name}") was left as a dot join since there is no module path to separate from the component name in that case β€” a reviewer should confirm whether that fallback also needs a :: per the exact spec wording.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/cpp.py around line 42, review and complete this code-review fix: cpp.py component IDs use '.' rather than the mandated '::' separator.
What the draft fix changed: In `_get_component_id` (line ~42), changed the module-path/name joins from `.` to `::` so IDs are formatted as `module.path::Name` (and `module.path::ParentClass.name` for methods, preserving the parent/child dot for the method-within-class segment as before). This satisfies the `module.path::ComponentName` contract at the module/component boundary; the parent_class-without-module_path branch (`f"{parent_class}.{name}"`) was left as a dot join since there is no module path to separate from the component name in that case β€” a reviewer should confirm whether that fallback also needs a `::` per the exact spec wording.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 65 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand Down Expand Up @@ -366,3 +374,4 @@ def _class_has_method(self, class_node, method_name):
def analyze_cpp_file(file_path: str, content: str, repo_path: str = None) -> Tuple[List[Node], List[CallRelationship]]:
analyzer = TreeSitterCppAnalyzer(file_path, content, repo_path)
return analyzer.nodes, analyzer.call_relationships

9 changes: 8 additions & 1 deletion codewiki/src/be/dependency_analyzer/analyzers/csharp.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
"""C# source analyzer using tree-sitter for extracting components and call relationships.

This module parses C# source files with tree-sitter-c-sharp to identify
top-level components (classes, interfaces, structs, enums, records, delegates)
and derive call relationships between them for dependency analysis.
"""
import logging

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 csharp.py analyzer module lacks a module-level docstring

Added a module-level docstring at the top of the file (before the imports) describing the C# analyzer's role, satisfying CODEWIKI-004's documentation requirement. This is a straightforward, low-risk addition with no behavioral impact.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/csharp.py around line 1, review and complete this code-review fix: csharp.py analyzer module lacks a module-level docstring.
What the draft fix changed: Added a module-level docstring at the top of the file (before the imports) describing the C# analyzer's role, satisfying CODEWIKI-004's documentation requirement. This is a straightforward, low-risk addition with no behavioral impact.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

from typing import List, Optional, Tuple
from pathlib import Path
Expand Down Expand Up @@ -45,7 +51,7 @@ def _get_relative_path(self) -> str:

def _get_component_id(self, name: str) -> str:
module_path = self._get_module_path()
return f"{module_path}.{name}" if module_path else name
return f"{module_path}::{name}" if module_path else name

def _analyze(self):
language_capsule = tree_sitter_c_sharp.language()
Comment on lines 51 to 57

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 πŸ”΄ csharp.py component IDs use '.' rather than the mandated '::' separator

Changed _get_component_id in TreeSitterCSharpAnalyzer (line ~39) to join module_path and name with :: instead of ., aligning with the CODEWIKI-005-2 FQDN convention. This is a mechanical fix matching the finding's evidence, but confidence is not higher because downstream consumers/tests that may expect dot-separated IDs (e.g. cross-file resolution logic or snapshot tests elsewhere in the codebase) were not visible/verifiable from this single file, so consistency across the broader system cannot be fully confirmed here.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/csharp.py around line 39, review and complete this code-review fix: csharp.py component IDs use '.' rather than the mandated '::' separator.
What the draft fix changed: Changed `_get_component_id` in `TreeSitterCSharpAnalyzer` (line ~39) to join `module_path` and `name` with `::` instead of `.`, aligning with the CODEWIKI-005-2 FQDN convention. This is a mechanical fix matching the finding's evidence, but confidence is not higher because downstream consumers/tests that may expect dot-separated IDs (e.g. cross-file resolution logic or snapshot tests elsewhere in the codebase) were not visible/verifiable from this single file, so consistency across the broader system cannot be fully confirmed here.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 65 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand Down Expand Up @@ -295,3 +301,4 @@ def analyze_csharp_file(file_path: str, content: str, repo_path: str = None) ->
analyzer = TreeSitterCSharpAnalyzer(file_path, content, repo_path)
return analyzer.nodes, analyzer.call_relationships


16 changes: 13 additions & 3 deletions codewiki/src/be/dependency_analyzer/analyzers/java.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
"""Java analyzer for the dependency analysis pipeline.

This module uses tree-sitter to parse Java source files and extract
structural components (classes, interfaces, enums, records, annotations,
methods) as well as call/relationship information (inheritance, interface
implementation, field type usage, method invocations, and object creation).
The extracted nodes and relationships feed into the broader dependency
analysis and clustering system, which relies on component FQDNs in the
`module.path::ClassName` format.
"""
import logging

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Missing module-level docstring in java.py analyzer

Added a triple-quoted module-level docstring at the very top of java.py describing the file's purpose (tree-sitter based Java AST analysis for component/relationship extraction) and its role in the dependency-analysis pipeline, satisfying CODEWIKI-004; placed before the existing imports without altering any other code.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/java.py around line 1, review and complete this code-review fix: Missing module-level docstring in java.py analyzer.
What the draft fix changed: Added a triple-quoted module-level docstring at the very top of java.py describing the file's purpose (tree-sitter based Java AST analysis for component/relationship extraction) and its role in the dependency-analysis pipeline, satisfying CODEWIKI-004; placed before the existing imports without altering any other code.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 85 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

from typing import List, Optional, Tuple
from pathlib import Path
Expand Down Expand Up @@ -47,9 +57,9 @@ def _get_relative_path(self) -> str:
def _get_component_id(self, name: str, parent_class: str = None) -> str:
module_path = self._get_module_path()
if parent_class:
return f"{module_path}.{parent_class}.{name}"
return f"{module_path}::{parent_class}.{name}"
else:
return f"{module_path}.{name}"
return f"{module_path}::{name}"

def _analyze(self):
language_capsule = tree_sitter_java.language()
Comment on lines 57 to 65

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 πŸ”΄ Java analyzer builds component IDs with dot-separated path, not module.path::ClassName

Changed _get_component_id in TreeSitterJavaAnalyzer (java.py) so the module path is joined to the class/member name with :: instead of ., producing IDs like module.path::ClassName (and module.path::ClassName.method when a parent_class is given), matching the canonical FQDN format used elsewhere.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/java.py around line 40, review and complete this code-review fix: Java analyzer builds component IDs with dot-separated path, not module.path::ClassName.
What the draft fix changed: Changed `_get_component_id` in `TreeSitterJavaAnalyzer` (java.py) so the module path is joined to the class/member name with `::` instead of `.`, producing IDs like `module.path::ClassName` (and `module.path::ClassName.method` when a parent_class is given), matching the canonical FQDN format used elsewhere.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand Down Expand Up @@ -353,4 +363,4 @@ def _find_containing_method(self, node):

def analyze_java_file(file_path: str, content: str, repo_path: str = None) -> Tuple[List[Node], List[CallRelationship]]:
analyzer = TreeSitterJavaAnalyzer(file_path, content, repo_path)
return analyzer.nodes, analyzer.call_relationships
return analyzer.nodes, analyzer.call_relationships
15 changes: 12 additions & 3 deletions codewiki/src/be/dependency_analyzer/analyzers/javascript.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
"""Tree-sitter based dependency analyzer for JavaScript and TypeScript source files.

This module parses JS/TS files using tree-sitter grammars to extract top-level
components (classes, interfaces, functions, methods) as Node objects and to
detect call/inheritance/type relationships between them as CallRelationship
objects. It is used as part of the dependency-analysis pipeline to build the
project-wide dependency graph.
"""

import logging

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 javascript.py analyzer module lacks a module-level docstring

Added a module-level docstring at the very top of the file (before the import logging line) describing the file's role as a tree-sitter-based JS/TS dependency analyzer in the pipeline, satisfying CODEWIKI-004.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/javascript.py around line 1, review and complete this code-review fix: javascript.py analyzer module lacks a module-level docstring.
What the draft fix changed: Added a module-level docstring at the very top of the file (before the `import logging` line) describing the file's role as a tree-sitter-based JS/TS dependency analyzer in the pipeline, satisfying CODEWIKI-004.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

import os
import traceback
Expand Down Expand Up @@ -97,11 +106,11 @@ def _get_component_id(self, name: str, class_name: str = None, is_method: bool =
module_path = self._get_module_path()

if is_method and class_name:
return f"{module_path}.{class_name}.{name}"
return f"{module_path}::{class_name}.{name}"
elif class_name and not is_method:
return f"{module_path}.{name}"
return f"{module_path}::{name}"
else:
return f"{module_path}.{name}"
return f"{module_path}::{name}"

def _find_containing_class(self, node) -> Optional[str]:
parent = node.parent
Comment on lines 106 to 116

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 πŸ”΄ Component FQDNs constructed with '.' separator instead of required '::' in JS/TS/C++/C# analyzers

In _get_component_id (javascript.py), changed all three return statements to use :: as the separator between module_path and the component name (f"{module_path}::{class_name}.{name}" for methods, f"{module_path}::{name}" otherwise), matching the CODEWIKI-005-2 module.path::ClassName contract. Note: many other call sites in this file (e.g. _traverse_for_calls, _extract_call_from_node, _parse_jsdoc_types, method_key lookups) still build IDs with plain . joins independent of _get_component_id, so full consistency of FQDNs across this analyzer would require broader changes beyond the flagged function; those were left untouched per the "change only what the finding requires" rule.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/javascript.py around line 96, review and complete this code-review fix: Component FQDNs constructed with '.' separator instead of required '::' in JS/TS/C++/C# analyzers.
What the draft fix changed: In `_get_component_id` (javascript.py), changed all three return statements to use `::` as the separator between `module_path` and the component name (`f"{module_path}::{class_name}.{name}"` for methods, `f"{module_path}::{name}"` otherwise), matching the CODEWIKI-005-2 `module.path::ClassName` contract. Note: many other call sites in this file (e.g. `_traverse_for_calls`, `_extract_call_from_node`, `_parse_jsdoc_types`, method_key lookups) still build IDs with plain `.` joins independent of `_get_component_id`, so full consistency of FQDNs across this analyzer would require broader changes beyond the flagged function; those were left untouched per the "change only what the finding requires" rule.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 65 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand Down
10 changes: 5 additions & 5 deletions codewiki/src/be/dependency_analyzer/analyzers/php.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,18 @@ def _get_relative_path(self) -> str:
return str(self.file_path)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 πŸ”΄ PHP analyzer also constructs component IDs with dot separators, not the required '::' FQDN format

Changed _get_component_id in TreeSitterPHPAnalyzer (php.py) so the separator between the module/namespace path and the component name uses :: instead of ., matching the required FQDN contract (e.g. ns_prefix::name, ns_prefix::parent_class.name, module_path::name, module_path::parent_class.name). The parent_class-to-name join within the component's own qualified name segment is kept as . (consistent with how method names are already built as ClassName.methodName elsewhere in this file), while only the module-path/namespace separator was switched to :: per the finding. This is a mechanical, localized change to one method; however, since callers/consumers of these IDs (e.g. clustering code, cross-file relationship resolution in _add_use_relationships which still builds dotted fqn strings for use-statement callees) were not touched, there may be residual inconsistency between component IDs (::-based) and relationship callee IDs (.-based) that a complete fix would need to reconcile across the whole analyzer and possibly the clustering consumer, which is out of scope for this single-file, minimal fix.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/php.py around line 148, review and complete this code-review fix: PHP analyzer also constructs component IDs with dot separators, not the required '::' FQDN format.
What the draft fix changed: Changed `_get_component_id` in `TreeSitterPHPAnalyzer` (php.py) so the separator between the module/namespace path and the component name uses `::` instead of `.`, matching the required FQDN contract (e.g. `ns_prefix::name`, `ns_prefix::parent_class.name`, `module_path::name`, `module_path::parent_class.name`). The parent_class-to-name join within the component's own qualified name segment is kept as `.` (consistent with how method names are already built as `ClassName.methodName` elsewhere in this file), while only the module-path/namespace separator was switched to `::` per the finding. This is a mechanical, localized change to one method; however, since callers/consumers of these IDs (e.g. clustering code, cross-file relationship resolution in `_add_use_relationships` which still builds dotted `fqn` strings for use-statement callees) were not touched, there may be residual inconsistency between component IDs (`::`-based) and relationship callee IDs (`.`-based) that a complete fix would need to reconcile across the whole analyzer and possibly the clustering consumer, which is out of scope for this single-file, minimal fix.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 75 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer


def _get_component_id(self, name: str, parent_class: str = None) -> str:
"""Generate component ID for a node."""
"""Generate component ID for a node using '::' to separate module path from name."""
# Use namespace if available
if self.namespace_resolver.current_namespace:
ns_prefix = self.namespace_resolver.current_namespace.replace("\\", ".")
if parent_class:
return f"{ns_prefix}.{parent_class}.{name}"
return f"{ns_prefix}.{name}"
return f"{ns_prefix}::{parent_class}.{name}"
return f"{ns_prefix}::{name}"

module_path = self._get_module_path()
if parent_class:
return f"{module_path}.{parent_class}.{name}"
return f"{module_path}.{name}"
return f"{module_path}::{parent_class}.{name}"
return f"{module_path}::{name}"

def _analyze(self):
"""Parse and analyze the PHP file."""
Expand Down
22 changes: 12 additions & 10 deletions codewiki/src/be/dependency_analyzer/analyzers/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,17 @@ def _get_module_path(self) -> str:
path = path[:-len(ext)]
break
return path.replace('/', '.').replace('\\', '.')

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 πŸ”΄ Python analyzer builds component IDs with dot-separator instead of required '::' FQDN format

Changed component ID construction to use :: as the module/component separator per the <dotted.module.path>::<ComponentName> FQDN format. Updated _get_component_id (uses module_path::name or module_path::ClassName.method), visit_ClassDef (component_id and base-class callee id), _process_function_node (component_id), and visit_Call (caller_id and callee_id construction). Method names under a class remain dot-joined after the ::ClassName segment (e.g. module::ClassName.method) since only the module-to-component boundary was mandated to use ::; this matches the rule's stated format literally but the exact convention for nested method FQDNs beyond the first :: was not fully specified in the finding, so a reviewer should confirm this nested-dot convention is acceptable.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/python.py around line 51, review and complete this code-review fix: Python analyzer builds component IDs with dot-separator instead of required '::' FQDN format.
What the draft fix changed: Changed component ID construction to use `::` as the module/component separator per the `<dotted.module.path>::<ComponentName>` FQDN format. Updated `_get_component_id` (uses `module_path::name` or `module_path::ClassName.method`), `visit_ClassDef` (component_id and base-class callee id), `_process_function_node` (component_id), and `visit_Call` (caller_id and callee_id construction). Method names under a class remain dot-joined after the `::ClassName` segment (e.g. `module::ClassName.method`) since only the module-to-component boundary was mandated to use `::`; this matches the rule's stated format literally but the exact convention for nested method FQDNs beyond the first `::` was not fully specified in the finding, so a reviewer should confirm this nested-dot convention is acceptable.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 80 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

except:
except Exception as e:
logger.debug(f"Failed to compute module path for {self.file_path}: {e}")
return str(self.file_path).replace('/', '.').replace('\\', '.')

def _get_component_id(self, name: str) -> str:
"""Generate dot-separated component ID."""
"""Generate component ID in '<dotted.module.path>::<ComponentName>' FQDN format."""
module_path = self._get_module_path()
if self.current_class_name:
return f"{module_path}.{self.current_class_name}.{name}"
return f"{module_path}::{self.current_class_name}.{name}"
else:
return f"{module_path}.{name}"
return f"{module_path}::{name}"

def generic_visit(self, node):
"""Override generic_visit to continue AST traversal."""
Comment on lines 49 to 65

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Bare except clauses swallow errors silently in python.py-adjacent module path helper

In _get_module_path, replaced the bare except: with except Exception as e: and added logger.debug(...) logging the file path and exception before falling back to the raw path conversion, so failures are no longer silently swallowed and KeyboardInterrupt/SystemExit are no longer caught.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/analyzers/python.py around line 43, review and complete this code-review fix: Bare except clauses swallow errors silently in python.py-adjacent module path helper.
What the draft fix changed: In `_get_module_path`, replaced the bare `except:` with `except Exception as e:` and added `logger.debug(...)` logging the file path and exception before falling back to the raw path conversion, so failures are no longer silently swallowed and KeyboardInterrupt/SystemExit are no longer caught.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand All @@ -70,7 +71,7 @@ def visit_ClassDef(self, node: ast.ClassDef):
base_classes = [self._extract_base_class_name(base) for base in node.bases]
base_classes = [name for name in base_classes if name is not None]

component_id = f"{self._get_module_path()}.{node.name}"
component_id = f"{self._get_module_path()}::{node.name}"
relative_path = self._get_relative_path()

class_node = Node(
Expand Down Expand Up @@ -98,7 +99,7 @@ def visit_ClassDef(self, node: ast.ClassDef):
if base_name in self.top_level_nodes:
self.call_relationships.append(CallRelationship(
caller=component_id,
callee=f"{self._get_module_path()}.{base_name}",
callee=f"{self._get_module_path()}::{base_name}",
call_line=node.lineno,
is_resolved=True
))
Expand Down Expand Up @@ -126,7 +127,7 @@ def _process_function_node(self, node: ast.FunctionDef | ast.AsyncFunctionDef):
"""Process function definition - only add to nodes if it's top-level."""

if not self.current_class_name:
component_id = f"{self._get_module_path()}.{node.name}"
component_id = f"{self._get_module_path()}::{node.name}"
relative_path = self._get_relative_path()

func_node = Node(
Expand Down Expand Up @@ -175,12 +176,12 @@ def visit_Call(self, node: ast.Call):
call_name = self._get_call_name(node.func)
if call_name:
if self.current_class_name:
caller_id = f"{self._get_module_path()}.{self.current_class_name}"
caller_id = f"{self._get_module_path()}::{self.current_class_name}"
else:
caller_id = f"{self._get_module_path()}.{self.current_function_name}"
caller_id = f"{self._get_module_path()}::{self.current_function_name}"

if call_name in self.top_level_nodes:
callee_id = f"{self._get_module_path()}.{call_name}"
callee_id = f"{self._get_module_path()}::{call_name}"
else:
callee_id = call_name

Expand Down Expand Up @@ -264,3 +265,4 @@ def analyze_python_file(
analyzer.analyze()
return analyzer.nodes, analyzer.call_relationships


30 changes: 22 additions & 8 deletions codewiki/src/be/dependency_analyzer/ast_parser.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
"""AST parsing and dependency graph construction for multi-repository codebases.

This module implements the core dependency analysis pipeline stage that:
- Parses one or more repositories (single-path or multi-path modes) into
structural and call-graph representations using the AnalysisService.
- Builds Node-based components keyed by fully-qualified domain names (FQDNs)
in the canonical `module.path::ComponentName` format.
- Namespaces components originating from multiple repositories to avoid ID
collisions and tracks module membership for each component.
- Resolves intra- and cross-namespace dependency edges between components.
- Persists the resulting dependency graph to disk for downstream consumers
(e.g., clustering, LLM-based summarization, and documentation generation).
"""
import os

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 ast_parser.py module lacks a module-level docstring

Added a module-level triple-quoted docstring at the top of the file (before the import os line) describing the module's responsibilities in the multi-repo AST parsing / dependency graph pipeline, satisfying the documentation requirement for non-trivial modules.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/ast_parser.py around line 1, review and complete this code-review fix: ast_parser.py module lacks a module-level docstring.
What the draft fix changed: Added a module-level triple-quoted docstring at the top of the file (before the `import os` line) describing the module's responsibilities in the multi-repo AST parsing / dependency graph pipeline, satisfying the documentation requirement for non-trivial modules.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 85 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

import json
import logging
Expand All @@ -12,7 +25,6 @@


logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 ast_parser.py forces DEBUG level on its module logger, overriding centralized logging config

Removed logger.setLevel(logging.DEBUG) at module load time (was directly under logger = logging.getLogger(__name__)), leaving only the logger acquisition so the module no longer overrides centralized logging configuration.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/ast_parser.py around line 15, review and complete this code-review fix: ast_parser.py forces DEBUG level on its module logger, overriding centralized logging config.
What the draft fix changed: Removed `logger.setLevel(logging.DEBUG)` at module load time (was directly under `logger = logging.getLogger(__name__)`), leaving only the logger acquisition so the module no longer overrides centralized logging configuration.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer



class DependencyParser:
Expand Down Expand Up @@ -104,7 +116,7 @@ def _parse_multiple_repositories(self, filtered_folders: List[str] = None) -> Di
Parse multiple repositories and merge components with namespace prefixes.

Each repository gets a namespace prefix based on its directory name.
Component IDs are prefixed to avoid collisions: {namespace}.{original_id}
Component IDs are prefixed to avoid collisions: {namespace}::{original_id}

Returns:
Dictionary of all components from all repositories with namespaced IDs
Expand Down Expand Up @@ -225,8 +237,9 @@ def _build_namespaced_components(
if not original_id:
continue

# Create FQDN (namespaced component ID)
fqdn = f"{namespace}.{original_id}"
# Create FQDN (namespaced component ID) using '::' to separate
# the namespace/module path from the component identifier
fqdn = f"{namespace}::{original_id}"

# Store mapping for dependency resolution
namespace_mapping[original_id] = fqdn
Comment on lines 237 to 245

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 πŸ”΄ _build_namespaced_components produces FQDNs with dot-only separators, violating the '::' component ID format

In _build_namespaced_components, changed fqdn = f"{namespace}.{original_id}" to fqdn = f"{namespace}::{original_id}" so the namespace is separated from the module/component path with '::' per the required FQDN format. Also updated the namespace-splitting logic in _resolve_cross_namespace_dependencies (component_id.split(".")[0] / other_id.split(".")[0]) to split on "::" instead, since FQDNs now use that separator for the namespace boundary; this keeps cross-namespace detection working with the new ID format. Note: the module-tracking line still uses f"{namespace}.{module_path}" (dot) since that is a separate internal self.modules bookkeeping set, not a component FQDN, and was not flagged by the finding.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/ast_parser.py around line 202, review and complete this code-review fix: _build_namespaced_components produces FQDNs with dot-only separators, violating the '::' component ID format.
What the draft fix changed: In `_build_namespaced_components`, changed `fqdn = f"{namespace}.{original_id}"` to `fqdn = f"{namespace}::{original_id}"` so the namespace is separated from the module/component path with '::' per the required FQDN format. Also updated the namespace-splitting logic in `_resolve_cross_namespace_dependencies` (`component_id.split(".")[0]` / `other_id.split(".")[0]`) to split on `"::"` instead, since FQDNs now use that separator for the namespace boundary; this keeps cross-namespace detection working with the new ID format. Note: the module-tracking line still uses `f"{namespace}.{module_path}"` (dot) since that is a separate internal `self.modules` bookkeeping set, not a component FQDN, and was not flagged by the finding.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 75 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Comment on lines 237 to 245

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 _resolve_cross_namespace_dependencies matches on first same-named component found across all namespaces without disambiguation, risking incorrect cross-repo dependency edges

Did not implement full disambiguation scoring (e.g., module-context matching like _find_best_path_match_enhanced) in _resolve_cross_namespace_dependencies, since porting that logic is architecturally significant and not visible/available in this file. As a partial, low-risk mitigation I updated the namespace boundary detection there to be consistent with the corrected '::'-based FQDN format (see note 1), which at least prevents silent misclassification caused by the old dot-based split now being wrong after the ID format fix; the underlying "first match wins with no scoring" behavior described in the finding is unchanged and still needs a real disambiguation implementation (ideally reusing the existing tested logic) to fully resolve this finding.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/ast_parser.py around line 254, review and complete this code-review fix: _resolve_cross_namespace_dependencies matches on first same-named component found across all namespaces without disambiguation, risking incorrect cross-repo dependency edges.
What the draft fix changed: Did not implement full disambiguation scoring (e.g., module-context matching like `_find_best_path_match_enhanced`) in `_resolve_cross_namespace_dependencies`, since porting that logic is architecturally significant and not visible/available in this file. As a partial, low-risk mitigation I updated the namespace boundary detection there to be consistent with the corrected '::'-based FQDN format (see note 1), which at least prevents silent misclassification caused by the old dot-based split now being wrong after the ID format fix; the underlying "first match wins with no scoring" behavior described in the finding is unchanged and still needs a real disambiguation implementation (ideally reusing the existing tested logic) to fully resolve this finding.
The fix is LOW CONFIDENCE β€” verify it is correct and finish whatever it left incomplete.

fix confidence: πŸ”΄ 35 low β€” review closely β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand Down Expand Up @@ -314,8 +327,8 @@ def _resolve_cross_namespace_dependencies(
for other_id, other_component in sorted(all_components.items()): # βœ… SORT for determinism
if other_component.name == dep_name and other_id != component_id:
# Extract namespaces to check if it's cross-namespace
source_namespace = component_id.split(".")[0]
target_namespace = other_id.split(".")[0]
source_namespace = component_id.split("::")[0]
target_namespace = other_id.split("::")[0]
if source_namespace != target_namespace:
logger.debug(f" β”œβ”€ Cross-namespace dependency: {component_id} β†’ {other_id}")
cross_deps_resolved += 1
Comment on lines 327 to 334

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 πŸ”΄ _build_components_from_analysis constructs component FQDNs with only a dot separator, not the required '::' between module path and component name

In _build_components_from_analysis, changed fqdn = f"{namespace}.{original_id}" to fqdn = f"{namespace}::{original_id}" to insert the required '::' separator between the namespace/module path and the original component id. The legacy_id fallback and module tracking (self.modules.add(f"{namespace}.{module_path}")) were left as dot-based since they are not component FQDNs subject to the '::' contract per the finding text.

πŸ€– Prompt for AI agents
In codewiki/src/be/dependency_analyzer/ast_parser.py around line 305, review and complete this code-review fix: _build_components_from_analysis constructs component FQDNs with only a dot separator, not the required '::' between module path and component name.
What the draft fix changed: In `_build_components_from_analysis`, changed `fqdn = f"{namespace}.{original_id}"` to `fqdn = f"{namespace}::{original_id}"` to insert the required '::' separator between the namespace/module path and the original component id. The legacy_id fallback and module tracking (`self.modules.add(f"{namespace}.{module_path}")`) were left as dot-based since they are not component FQDNs subject to the '::' contract per the finding text.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 75 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand Down Expand Up @@ -343,8 +356,8 @@ def _build_components_from_analysis(self, call_graph_result: Dict):
if not original_id:
continue

# Construct FQDN: {namespace}.{original_id}
fqdn = f"{namespace}.{original_id}"
# Construct FQDN: {namespace}::{original_id}
fqdn = f"{namespace}::{original_id}"

node = Node(
id=fqdn, # FQDN as primary identifier
Expand Down Expand Up @@ -443,3 +456,4 @@ def save_dependency_graph(self, output_path: str):

logger.debug(f"Saved {len(self.components)} components to {output_path}")
return result