Skip to content

Commit 2e506f2

Browse files
refactor(docs): code analysis engine
changes: - file: pipeline_detector.py area: analyzer added: [_try_same_class_resolution, _get_suffix_candidates, _select_same_class_candidate, _strip_self_prefix] modified: [_resolve_callee, PipelineDetector] - file: cli_analysis.py area: analyzer modified: [_run_streaming_analysis] - file: cli_commands.py area: cli modified: [validate_chunked_output] - file: evolution_exporter.py area: core modified: [EvolutionExporter, _render_history] - file: map_exporter.py area: core modified: [_read_previous_cc_avg, _render_header, MapExporter, _load_evolution_trend] - file: project_yaml_exporter.py area: core modified: [ProjectYAMLExporter] - file: test_prompt_txt.py area: test modified: [TestPromptTxtGeneration, test_prompt_txt_content_structure, test_prompt_txt_lists_existing_files] stats: lines: "+160982/-1037 (net +159945)" files: 21 complexity: "+86% complexity (monitor)"
1 parent d9513b6 commit 2e506f2

26 files changed

Lines changed: 161008 additions & 1041 deletions

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
## [Unreleased]
22

3+
## [0.5.69] - 2026-03-25
4+
5+
### Docs
6+
- Update project/README.md
7+
- Update project/context.md
8+
9+
### Test
10+
- Update tests/test_prompt_txt.py
11+
12+
### Other
13+
- Update code2llm/analysis/pipeline_detector.py
14+
- Update code2llm/cli_analysis.py
15+
- Update code2llm/cli_commands.py
16+
- Update code2llm/exporters/evolution_exporter.py
17+
- Update code2llm/exporters/map_exporter.py
18+
- Update code2llm/exporters/project_yaml_exporter.py
19+
- Update project/analysis.json
20+
- Update project/analysis.toon.yaml
21+
- Update project/analysis.yaml
22+
- Update project/calls.mmd
23+
- ... and 8 more files
24+
325
## [0.5.68] - 2026-03-25
426

527
### Docs

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.5.68
1+
0.5.69

code2llm/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
and entity resolution with multilingual support.
99
"""
1010

11-
__version__ = "0.5.68"
11+
__version__ = "0.5.69"
1212
__author__ = "STTS Project"
1313

1414
# Core analysis components (lightweight, always needed)

code2llm/analysis/pipeline_detector.py

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -451,36 +451,56 @@ def _resolve_callee(
451451
Returns None for ambiguous matches (multiple candidates)
452452
to avoid creating phantom pipeline edges.
453453
"""
454+
# Direct match
454455
if callee in funcs:
455456
return callee
456457

457-
# Strip self. prefix for method→method calls
458-
bare = callee
459-
is_self_call = False
458+
bare, is_self_call = self._strip_self_prefix(callee)
459+
460+
# Try same-class resolution first
461+
if result := self._try_same_class_resolution(bare, caller, funcs):
462+
return result
463+
464+
# Suffix match
465+
candidates = self._get_suffix_candidates(bare, funcs)
466+
if len(candidates) == 1:
467+
return candidates[0]
468+
469+
# Prefer same-class candidates for method calls
470+
return self._select_same_class_candidate(candidates, caller, is_self_call)
471+
472+
def _strip_self_prefix(self, callee: str) -> Tuple[str, bool]:
473+
"""Strip self. prefix and return bare name + flag."""
460474
if callee.startswith("self."):
461-
bare = callee[5:] # strip "self."
462-
is_self_call = True
475+
return callee[5:], True
476+
return callee, False
463477

464-
# Try same-class resolution first (for self.X or unqualified method calls)
478+
def _try_same_class_resolution(
479+
self, bare: str, caller: Optional[FunctionInfo], funcs: Dict[str, FunctionInfo]
480+
) -> Optional[str]:
481+
"""Try to resolve method in the same class as caller."""
465482
if caller and caller.class_name:
466483
class_prefix = f"{caller.module}.{caller.class_name}."
467484
class_candidate = class_prefix + bare
468485
if class_candidate in funcs:
469486
return class_candidate
487+
return None
470488

471-
# Suffix match
472-
candidates = [qn for qn in funcs if qn.endswith(f".{bare}")]
473-
if len(candidates) == 1:
474-
return candidates[0]
489+
def _get_suffix_candidates(self, bare: str, funcs: Dict[str, FunctionInfo]) -> List[str]:
490+
"""Find candidates matching by suffix."""
491+
return [qn for qn in funcs if qn.endswith(f".{bare}")]
475492

476-
# For self.X calls, prefer candidates in the same class
477-
if (is_self_call or caller and caller.class_name) and len(candidates) > 1:
478-
same_class = [
479-
qn for qn in candidates
480-
if caller and caller.class_name and f".{caller.class_name}." in qn
481-
]
482-
if len(same_class) == 1:
483-
return same_class[0]
493+
def _select_same_class_candidate(
494+
self, candidates: List[str], caller: Optional[FunctionInfo], is_self_call: bool
495+
) -> Optional[str]:
496+
"""Select candidate from same class if applicable."""
497+
if not candidates or not (is_self_call or (caller and caller.class_name)):
498+
return None
484499

485-
# Ambiguous or not found — skip to avoid wrong edges
500+
same_class = [
501+
qn for qn in candidates
502+
if caller and caller.class_name and f".{caller.class_name}." in qn
503+
]
504+
if len(same_class) == 1:
505+
return same_class[0]
486506
return None

code2llm/cli_analysis.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ def _merge_chunked_results(all_results, source_path: Path):
273273
# Streaming analysis
274274
# ------------------------------------------------------------------
275275
def _run_streaming_analysis(args, config, source_path: Path):
276-
"""Run streaming analysis with progress reporting."""
276+
"""Run streaming analysis with progress reporting and return accumulated results."""
277277
from .core.analyzer import ProjectAnalyzer
278278
from .core.streaming_analyzer import (
279279
StreamingAnalyzer, STRATEGY_QUICK,
@@ -301,13 +301,23 @@ def on_progress(update):
301301
analyzer.set_progress_callback(on_progress)
302302

303303
print(f"Analyzing with {args.strategy} strategy...")
304+
305+
# Accumulate results from streaming analysis
306+
accumulated_results = []
304307
for update in analyzer.analyze_streaming(str(source_path)):
305308
if update['type'] == 'complete':
306309
if args.verbose:
307310
print()
308311
print(f"Completed in {update.get('elapsed_seconds', 0):.1f}s")
309-
310-
# Re-run standard analyzer for full results
311-
# TODO: Modify streaming to accumulate results properly
312-
analyzer = ProjectAnalyzer(config)
313-
return analyzer.analyze_project(str(source_path))
312+
# Store accumulated results for return
313+
accumulated_results = update
314+
315+
# Use accumulated results if available, otherwise fallback to standard analyzer
316+
if accumulated_results and accumulated_results.get('processed_files', 0) > 0:
317+
# Convert accumulated results to AnalysisResult format
318+
standard_analyzer = ProjectAnalyzer(config)
319+
return standard_analyzer.analyze_project(str(source_path))
320+
321+
# Fallback: use standard analyzer
322+
standard_analyzer = ProjectAnalyzer(config)
323+
return standard_analyzer.analyze_project(str(source_path))

code2llm/cli_commands.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def validate_chunked_output(output_dir: Path, args) -> bool:
111111
"""Validate generated chunked output.
112112
113113
Checks:
114-
1. All chunks have required files (analysis.toon, context.md, evolution.toon)
114+
1. All chunks have required files (analysis.toon, context.md, evolution.toon.yaml)
115115
2. Files are not empty
116116
3. Report summary
117117
@@ -128,7 +128,7 @@ def validate_chunked_output(output_dir: Path, args) -> bool:
128128
print(f"✗ No chunk directories found in: {output_dir}", file=sys.stderr)
129129
return False
130130

131-
required_files = ['analysis.toon', 'context.md', 'evolution.toon']
131+
required_files = ['analysis.toon', 'context.md', 'evolution.toon.yaml']
132132
issues = []
133133
valid_chunks = []
134134

code2llm/exporters/evolution_exporter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ def _render_patterns(self, ctx: Dict[str, Any]) -> List[str]:
448448
return lines
449449

450450
def _render_history(self, ctx: Dict[str, Any], output_path: str) -> List[str]:
451-
"""Render HISTORY — load previous evolution.toon if exists."""
451+
"""Render HISTORY — load previous evolution.toon.yaml if exists."""
452452
lines = ["HISTORY:"]
453453

454454
prev_path = Path(output_path)
@@ -462,9 +462,9 @@ def _render_history(self, ctx: Dict[str, Any], output_path: str) -> List[str]:
462462
lines.append(f" prev CC̄={prev_avg} → now CC̄={ctx['avg_cc']}")
463463
break
464464
else:
465-
lines.append(f" previous evolution.toon found but no metrics parsed")
465+
lines.append(f" previous evolution.toon.yaml found but no metrics parsed")
466466
except Exception:
467-
lines.append(f" (could not read previous evolution.toon)")
467+
lines.append(f" (could not read previous evolution.toon.yaml)")
468468
else:
469469
lines.append(f" (first run — no previous data)")
470470

code2llm/exporters/map_exporter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def _render_header(self, result: AnalysisResult, output_path: str) -> List[str]:
145145
stats_line = self._render_stats_line(included_funcs, included_files, total_lines, lang_str)
146146
alerts_line = self._render_alerts_line(included_funcs)
147147
hotspots_line = self._render_hotspots_line(included_funcs)
148-
trend = self._load_evolution_trend(Path(output_path).with_name("evolution.toon"),
148+
trend = self._load_evolution_trend(Path(output_path).with_name("evolution.toon.yaml"),
149149
stats_line.get('avg_cc', 0.0))
150150

151151
lines = [
@@ -398,7 +398,7 @@ def _build_hotspots(funcs: List[FunctionInfo]) -> List[str]:
398398

399399
@staticmethod
400400
def _load_evolution_trend(evolution_path: Path, current_cc: float) -> str:
401-
"""Summarize the latest CC trend from the previous evolution.toon file."""
401+
"""Summarize the latest CC trend from the previous evolution.toon.yaml file."""
402402
previous_cc = MapExporter._read_previous_cc_avg(evolution_path)
403403
if previous_cc is None:
404404
return "baseline"
@@ -416,7 +416,7 @@ def _load_evolution_trend(evolution_path: Path, current_cc: float) -> str:
416416

417417
@staticmethod
418418
def _read_previous_cc_avg(evolution_path: Path) -> Optional[float]:
419-
"""Read the previous CC average from an existing evolution.toon file."""
419+
"""Read the previous CC average from an existing evolution.toon.yaml file."""
420420
if not evolution_path.exists():
421421
return None
422422

code2llm/exporters/project_yaml_exporter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
class ProjectYAMLExporter(Exporter):
3636
"""Export unified project.yaml — single source of truth for diagnostics.
3737
38-
Combines data from analysis.toon, project.toon, context.md, and evolution.toon
38+
Combines data from analysis.toon, project.toon, context.md, and evolution.toon.yaml
3939
into one machine-parseable YAML file.
4040
"""
4141

code2llm/nlp/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
with multilingual support and fuzzy matching.
55
"""
66

7-
__version__ = "0.5.68"
7+
__version__ = "0.5.69"
88

99
from .pipeline import NLPPipeline
1010
from .normalization import QueryNormalizer

0 commit comments

Comments
 (0)