Dependency Analysis Service
August 6, 2026 · View on GitHub
Purpose
The Dependency Analysis Service is the orchestration layer that turns a raw repository (local folder or a
GitHub URL) into a structured, language-aware call graph: a set of Node objects (functions, methods,
classes, ...) and CallRelationship edges between them. It is the entry point used by higher-level components
—most notably DependencyParser in Dependency_Analyzer_Core and the
Backend_LLM_&_Documentation_Services documentation pipeline—to
obtain the data that ultimately feeds LLM-driven documentation generation.
The module has three responsibilities, each owned by one component:
| Component | File | Responsibility |
|---|---|---|
AnalysisService | analysis/analysis_service.py | Top-level orchestrator: clone/locate a repo, drive structure analysis, drive call-graph analysis, assemble the final AnalysisResult, and clean up temporary state. |
RepoAnalyzer / GitIgnoreFilter | analysis/repo_analyzer.py | Walk the file system, build a filtered file tree (include/exclude glob patterns + Git ignore semantics), and compute summary statistics. |
CallGraphAnalyzer | analysis/call_graph_analyzer.py | Dispatch each discovered source file to the appropriate per-language analyzer (see Language_Analyzers), collect functions/relationships, resolve cross-file/cross-language calls, and produce visualization-ready data. |
Architecture Overview
flowchart TB
subgraph Consumers
DP["DependencyParser<br/>(Dependency_Analyzer_Core)"]
DG["DocumentationGenerator<br/>(Backend_LLM_&_Documentation_Services)"]
end
subgraph DAS["Dependency Analysis Service"]
AS["AnalysisService<br/>(orchestrator)"]
RA["RepoAnalyzer / GitIgnoreFilter<br/>(file tree + filtering)"]
CGA["CallGraphAnalyzer<br/>(call graph construction)"]
end
subgraph LA["Language_Analyzers"]
PY["PythonASTAnalyzer"]
JS["TreeSitterJSAnalyzer / TS"]
JVM["Java / Kotlin / C# analyzers"]
CFAM["C / C++ analyzers"]
PHP["PHP analyzer"]
end
Cloning["cloning.py<br/>clone_repository / parse_github_url"]
DP --> AS
DG -.-> DP
AS --> Cloning
AS --> RA
AS --> CGA
CGA --> PY
CGA --> JS
CGA --> JVM
CGA --> CFAM
CGA --> PHP
AS --> Result["AnalysisResult<br/>(Dependency_Analyzer_Core models)"]
Data Flow: Full Repository Analysis
AnalysisService.analyze_repository_full is the richest entry point. It performs cloning, structure discovery,
call-graph construction, and packages everything into an AnalysisResult (defined in
Dependency_Analyzer_Core).
sequenceDiagram
participant Caller
participant AS as AnalysisService
participant Clone as cloning.py
participant RA as RepoAnalyzer
participant CGA as CallGraphAnalyzer
participant LangA as Language Analyzer
Caller->>AS: analyze_repository_full(github_url)
AS->>Clone: clone_repository(github_url)
Clone-->>AS: temp_dir
AS->>RA: analyze_repository_structure(temp_dir)
RA-->>AS: file_tree + summary
AS->>CGA: extract_code_files(file_tree)
CGA-->>AS: code_files (filtered by extension)
AS->>CGA: analyze_code_files(code_files, temp_dir)
loop for each source file
CGA->>LangA: analyze_<language>_file(path, content)
LangA-->>CGA: (functions, relationships)
end
CGA->>CGA: resolve_call_relationships()
CGA->>CGA: deduplicate_relationships()
CGA-->>AS: functions, relationships, visualization
AS->>AS: read README, build Repository + AnalysisResult
AS->>Clone: cleanup_repository(temp_dir)
AS-->>Caller: AnalysisResult
Component Details
AnalysisService
Central façade exposing three analysis modes:
analyze_repository_full(github_url, ...)— clones a remote repository, runs structure + call-graph analysis, reads the README, and returns a fully populatedAnalysisResult(functions, relationships, file tree, summary, Cytoscape visualization data). Cleans up the temporary clone directory afterward (also tracked in_temp_directoriesand cleaned viacleanup_all()/__del__as a safety net).analyze_repository_structure_only(github_url, ...)— lightweight variant that skips call-graph generation, useful for quick previews of repository layout.analyze_local_repository(repo_path, ...)— analyzes a folder already present on disk (no cloning), used for local/offline workflows; returns a simplified dict (nodes,relationships,summary) rather than a fullAnalysisResult.
Internally it composes a RepoAnalyzer (structure) and a CallGraphAnalyzer (call graph), and delegates
repository acquisition to cloning.py helpers (clone_repository, cleanup_repository, parse_github_url).
It also filters files down to the set of currently supported languages (Python, JavaScript, TypeScript, Java,
C#, C, C++, PHP, Kotlin) before invoking the call-graph analyzer.
Two module-level functions, analyze_repository and analyze_repository_structure_only, are kept as
backward-compatible wrappers around a freshly constructed AnalysisService.
classDiagram
class AnalysisService {
+call_graph_analyzer: CallGraphAnalyzer
+analyze_local_repository(repo_path, max_files, languages, use_gitignore)
+analyze_repository_full(github_url, include_patterns, exclude_patterns, use_gitignore) AnalysisResult
+analyze_repository_structure_only(github_url, ...) Dict
-_clone_repository(github_url) str
-_analyze_structure(repo_dir, ...) Dict
-_analyze_call_graph(file_tree, repo_dir) Dict
-_filter_supported_languages(code_files) List
-_cleanup_repository(temp_dir)
+cleanup_all()
}
class RepoAnalyzer
class CallGraphAnalyzer
AnalysisService --> RepoAnalyzer : uses
AnalysisService --> CallGraphAnalyzer : uses
RepoAnalyzer and GitIgnoreFilter
RepoAnalyzer.analyze_repository_structure(repo_dir) recursively walks a directory into a nested file_tree
dict (type, name, path, extension/children), applying:
- Include patterns (
fnmatch-style globs) — if provided, they replace the defaults (DEFAULT_INCLUDE_PATTERNS); otherwise all files are eligible for inclusion. - Exclude patterns — merged with
DEFAULT_IGNORE_PATTERNS; matched against full relative path, filename, and path segments. - Git ignore semantics via
GitIgnoreFilter, which prefers shelling out togit ls-files --others --ignored --exclude-standard(so nested.gitignorefiles, global excludes, and tracked-file rules behave exactly like Git) and falls back to apathspec-based scan of every.gitignorefile in the tree when Git is unavailable or the folder isn't a Git worktree.
Symlinks and paths that resolve outside the repository root are rejected defensively while building the tree.
The result also includes a summary (total_files, total_size_kb).
flowchart LR
Start["analyze_repository_structure(repo_dir)"] --> Filter["Build GitIgnoreFilter\n(git ls-files or pathspec fallback)"]
Filter --> Walk["Recursively walk directory"]
Walk --> Exclude{"_should_exclude_path?\n(exclude patterns / gitignore / symlink)"}
Exclude -- yes --> Skip["Drop node"]
Exclude -- no --> Include{"file? _should_include_file?"}
Include -- file & matches --> Leaf["Add file node"]
Include -- directory --> Recurse["Recurse into children"]
Leaf --> Tree["file_tree"]
Recurse --> Tree
Tree --> Summary["total_files / total_size_kb"]
CallGraphAnalyzer
The multi-language orchestrator. Given a list of code files (already filtered to supported extensions via
extract_code_files), it:
- Routes ambiguous
.hheaders (_route_contextual_headers) to either C or C++ based on content signals (namespaces, classes, templates,::, or known C++ standard headers) and repository composition. - Collects Python module names up front (
_collect_python_modules) to support accurate project-vs-external import classification later. - Dispatches each file to the language-specific analyzer function based on
file_info["language"], delegating to the implementations documented in Language_Analyzers:python→analyzers/python.py::analyze_python_filejavascript/typescript→ tree-sitter analyzers inanalyzers/javascript.py/typescript.pyjava,kotlin,csharp,c,cpp,php→ respective tree-sitter analyzers Each file is analyzed under a 30-second timeout guard (timeoutcontext manager, POSIXSIGALRM-based, no-op on Windows) so a pathological file cannot stall the whole run.
- Resolves call relationships (
_resolve_call_relationships): builds global and per-language exact/ simple-name lookup indexes (_build_resolution_indexes) fromid,component_id,qualified_name, andname, then attempts to match each unresolvedCallRelationship.callee— preferring matches within the caller's own language, falling back to language-qualified/simple-name matching, and finally dropping relationships that are provably external (standard library calls, C/C++ macros, or third-party package/module calls) viais_external_symbol/is_macro_nameand dotted-package/module heuristics. - Deduplicates relationships on
(caller, callee)pairs. - Generates visualization data: a Cytoscape.js-compatible
{elements: [...]}structure with per-language CSS classes (lang-python,lang-cpp, ...) and node/edge classification, plus a resolution summary (total_nodes,total_edges,unresolved_calls).
It also exposes generate_llm_format() (a compact, LLM-friendly functions/relationships view) and
_select_most_connected_nodes(target_count) (degree-centrality-based pruning for very large graphs).
flowchart TB
Files["code_files (filtered by language)"] --> Route["_route_contextual_headers\n(.h -> c/cpp)"]
Route --> PyMods["_collect_python_modules"]
PyMods --> Loop["For each file: _analyze_code_file\n(30s timeout guard)"]
Loop -->|python| PyA["analyzers.python"]
Loop -->|js/ts| JsA["analyzers.javascript / typescript"]
Loop -->|java/kotlin/csharp| JvmA["analyzers.java / kotlin / csharp"]
Loop -->|c/cpp| CA["analyzers.c / cpp"]
Loop -->|php| PhpA["analyzers.php"]
PyA & JsA & JvmA & CA & PhpA --> Collect["functions{} + call_relationships[]"]
Collect --> Resolve["_resolve_call_relationships\n(exact/simple name indexes,\nlanguage-aware, external filtering)"]
Resolve --> Dedup["_deduplicate_relationships"]
Dedup --> Viz["_generate_visualization_data\n(Cytoscape elements)"]
Viz --> Out["{call_graph, functions, relationships, visualization}"]
Key Data Structures
The service produces/consumes model types defined in Dependency_Analyzer_Core:
Node— a single code component (function, method, class, ...) with identity (id,component_id,qualified_name), location (file_path,relative_path,start_line/end_line), documentation (docstring), and its outgoingdepends_onset.CallRelationship— a directed edgecaller -> callee, withcall_lineand anis_resolvedflag set onceCallGraphAnalyzermatches the callee to a concreteNode.Repository— metadata about the analyzed repo (url,name,clone_path,analysis_id).AnalysisResult— the full output bundle:repository,functions(list ofNode),relationships(list ofCallRelationship),file_tree,summary,visualization, and optionalreadme_content.
Position in the Overall System
flowchart LR
User["End user / API request"] --> DG["DocumentationGenerator<br/>(Backend_LLM_&_Documentation_Services)"]
DG --> DP["DependencyParser + DependencyGraphBuilder<br/>(Dependency_Analyzer_Core)"]
DP --> DAS["Dependency Analysis Service<br/>(this module)"]
DAS --> LA["Language_Analyzers"]
DAS -->|Node / CallRelationship models| DP
DP -->|leaf-node components + graph| DG
DG -->|documentation content| FE["Frontend_Web_App / CLI"]
- Dependency_Analyzer_Core consumes this service directly:
DependencyParser.parse_repository()instantiates anAnalysisService, calls its private_analyze_structure/_analyze_call_graphhelpers, and converts the resulting functions/relationships dicts intoNodeobjects withdepends_onedges, whichDependencyGraphBuilderthen turns into a traversable dependency graph and a set of "leaf" components. - Language_Analyzers supplies every per-language
analyze_*_filefunction thatCallGraphAnalyzerdispatches to; this module is language-agnostic and treats each analyzer as a pluggable strategy returning(functions, relationships[, extra]). - Backend_LLM_&_Documentation_Services sits above
Dependency_Analyzer_Coreand uses the resulting component graph as the substrate for LLM-driven documentation generation (seeDocumentationGenerator). - Repository acquisition (
git clone, URL parsing) is handled byanalysis/cloning.py, a small internal helper module used exclusively byAnalysisService.
Design Notes
- Fail-safe cleanup: every cloning path is wrapped in try/except blocks that clean up the temporary
directory on failure, and
AnalysisServicealso tracks all created temp dirs for a finalcleanup_all()/__del__safety net. - Security-conscious file reads: file content and README lookups go through
safe_open_text/assert_safe_pathto guard against path traversal outside the repository root. - Language extensibility: adding a new language mainly requires (a) a new
analyze_<lang>_filefunction in Language_Analyzers, (b) a dispatch branch inCallGraphAnalyzer._analyze_code_file, and (c) adding the language toAnalysisService._filter_supported_languages/_get_supported_languages. - Resolution favors precision over recall: relationships that cannot be confidently resolved to a known
project
Node— and are provably external (stdlib, macros, third-party imports) — are dropped rather than kept as noisy unresolved edges, keeping the resulting call graph focused on in-repository architecture.