code2llm 0.5.116__tar.gz → 0.5.118__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.
- {code2llm-0.5.116 → code2llm-0.5.118}/PKG-INFO +2 -2
- {code2llm-0.5.116 → code2llm-0.5.118}/README.md +1 -1
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/__init__.py +1 -1
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/call_graph.py +2 -7
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/cfg.py +2 -7
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/data_analysis.py +87 -3
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/utils/__init__.py +2 -2
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/utils/ast_helpers.py +13 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/file_cache.py +7 -3
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/__init__.py +2 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/streaming/cache.py +3 -4
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/article_view.py +3 -7
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/base.py +16 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/context_view.py +3 -7
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/flow_constants.py +13 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/flow_exporter.py +2 -10
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/map_exporter.py +2 -9
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/toon_view.py +3 -7
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/generators/__init__.py +3 -0
- code2llm-0.5.118/code2llm/generators/_utils.py +15 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/generators/llm_flow.py +2 -9
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/generators/llm_task.py +2 -9
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/nlp/__init__.py +1 -1
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm.egg-info/PKG-INFO +2 -2
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm.egg-info/SOURCES.txt +1 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/pyproject.toml +1 -1
- {code2llm-0.5.116 → code2llm-0.5.118}/setup.py +1 -1
- {code2llm-0.5.116 → code2llm-0.5.118}/LICENSE +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/__main__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/__init__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/coupling.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/dfg.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/pipeline_detector.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/side_effects.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/smells.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/analysis/type_inference.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/api.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/cli.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/cli_analysis.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/cli_commands.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/cli_exports/__init__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/cli_exports/code2logic.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/cli_exports/formats.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/cli_exports/orchestrator.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/cli_exports/prompt.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/cli_parser.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/__init__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/analyzer.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/ast_registry.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/config.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/export_pipeline.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/file_analyzer.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/file_filter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/gitignore.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/incremental.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/base.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/cpp.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/csharp.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/generic.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/go_lang.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/java.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/php.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/ruby.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/rust.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/ts_extractors.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/ts_parser.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/lang/typescript.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/large_repo.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/models.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/persistent_cache.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/refactoring.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/repo_files.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/streaming/__init__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/streaming/incremental.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/streaming/prioritizer.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/streaming/scanner.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/streaming/strategies.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/streaming_analyzer.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/core/toon_size_manager.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/__init__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/context_exporter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/evolution_exporter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/flow_renderer.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/html_dashboard.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/index_generator.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/json_exporter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/llm_exporter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/mermaid_exporter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/mermaid_flow_helpers.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/project_yaml/__init__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/project_yaml/constants.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/project_yaml/core.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/project_yaml/evolution.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/project_yaml/health.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/project_yaml/hotspots.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/project_yaml/modules.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/project_yaml_exporter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/readme_exporter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/report_generators.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/toon/__init__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/toon/helpers.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/toon/metrics.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/toon/module_detail.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/toon/renderer.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/toon.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/validate_project.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/exporters/yaml_exporter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/generators/mermaid.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/nlp/config.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/nlp/entity_resolution.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/nlp/intent_matching.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/nlp/normalization.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/nlp/pipeline.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/patterns/__init__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/patterns/detector.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/refactor/__init__.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm/refactor/prompt_engine.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm.egg-info/dependency_links.txt +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm.egg-info/entry_points.txt +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm.egg-info/requires.txt +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/code2llm.egg-info/top_level.txt +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/setup.cfg +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_advanced_analysis.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_analyzer.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_calls_toon_export.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_deep_analysis.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_edge_cases.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_flow_exporter.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_format_quality.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_multilanguage_e2e.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_nlp_pipeline.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_nonpython_cc_calls.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_persistent_cache.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_pipeline_detector.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_project_toon_export.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_prompt_engine.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_prompt_txt.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_refactoring_engine.py +0 -0
- {code2llm-0.5.116 → code2llm-0.5.118}/tests/test_toon_v2.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2llm
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.118
|
|
4
4
|
Summary: High-performance Python code flow analysis with optimized TOON format - CFG, DFG, call graphs, and intelligent code queries
|
|
5
5
|
Home-page: https://github.com/wronai/stts
|
|
6
6
|
Author: STTS Project
|
|
@@ -67,7 +67,7 @@ Dynamic: requires-python
|
|
|
67
67
|
|
|
68
68
|
## AI Cost Tracking
|
|
69
69
|
|
|
70
|
-
    
|
|
71
71
|
  
|
|
72
72
|
|
|
73
73
|
- 🤖 **LLM usage:** $7.5000 (166 commits)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
## AI Cost Tracking
|
|
5
5
|
|
|
6
|
-
    
|
|
7
7
|
  
|
|
8
8
|
|
|
9
9
|
- 🤖 **LLM usage:** $7.5000 (166 commits)
|
|
@@ -8,7 +8,7 @@ Includes NLP Processing Pipeline for query normalization, intent matching,
|
|
|
8
8
|
and entity resolution with multilingual support.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
__version__ = "0.5.
|
|
11
|
+
__version__ = "0.5.118"
|
|
12
12
|
__author__ = "STTS Project"
|
|
13
13
|
|
|
14
14
|
# Core analysis components (lightweight, always needed)
|
|
@@ -5,7 +5,7 @@ from typing import Optional, Set, List, Dict
|
|
|
5
5
|
|
|
6
6
|
from code2llm.core.config import Config
|
|
7
7
|
from code2llm.core.models import AnalysisResult, FlowEdge
|
|
8
|
-
from code2llm.analysis.utils import ast_unparse
|
|
8
|
+
from code2llm.analysis.utils import ast_unparse, qualified_name
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class CallGraphExtractor(ast.NodeVisitor):
|
|
@@ -140,12 +140,7 @@ class CallGraphExtractor(ast.NodeVisitor):
|
|
|
140
140
|
self.generic_visit(node)
|
|
141
141
|
|
|
142
142
|
def _qualified_name(self, name: str) -> str:
|
|
143
|
-
|
|
144
|
-
parts = [self.module_name]
|
|
145
|
-
if self.class_stack:
|
|
146
|
-
parts.append(self.class_stack[-1])
|
|
147
|
-
parts.append(name)
|
|
148
|
-
return '.'.join(parts)
|
|
143
|
+
return qualified_name(self.module_name, self.class_stack, name)
|
|
149
144
|
|
|
150
145
|
def _resolve_call(self, node: ast.AST) -> Optional[str]:
|
|
151
146
|
"""Resolve a call to its full name."""
|
|
@@ -6,7 +6,7 @@ from typing import Optional
|
|
|
6
6
|
|
|
7
7
|
from code2llm.core.config import Config
|
|
8
8
|
from code2llm.core.models import AnalysisResult, FlowNode, FlowEdge, FunctionInfo
|
|
9
|
-
from code2llm.analysis.utils import ast_unparse
|
|
9
|
+
from code2llm.analysis.utils import ast_unparse, qualified_name
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class CFGExtractor(ast.NodeVisitor):
|
|
@@ -261,12 +261,7 @@ class CFGExtractor(ast.NodeVisitor):
|
|
|
261
261
|
self.generic_visit(node)
|
|
262
262
|
|
|
263
263
|
def _qualified_name(self, name: str) -> str:
|
|
264
|
-
|
|
265
|
-
parts = [self.module_name]
|
|
266
|
-
if self.class_stack:
|
|
267
|
-
parts.append(self.class_stack[-1])
|
|
268
|
-
parts.append(name)
|
|
269
|
-
return '.'.join(parts)
|
|
264
|
+
return qualified_name(self.module_name, self.class_stack, name)
|
|
270
265
|
|
|
271
266
|
def _extract_condition(self, node: ast.AST) -> str:
|
|
272
267
|
"""Extract condition as string."""
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
"""Data Analysis logic for code2llm -
|
|
1
|
+
"""Data Analysis logic for code2llm - split into focused analyzers.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This module provides three analyzers:
|
|
4
|
+
- DataFlowAnalyzer: data pipelines, state patterns, dependencies, event flows
|
|
5
|
+
- OptimizationAdvisor: data types, optimization opportunities, process patterns
|
|
6
|
+
- DataAnalyzer: facade combining both analyzers (backward compatibility)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any, Dict, List, Tuple
|
|
4
10
|
from code2llm.core.models import AnalysisResult
|
|
5
11
|
|
|
6
12
|
|
|
@@ -10,7 +16,7 @@ _OUTPUT_INDICATORS = ['serialize', 'format', 'write', 'save', 'send', 'output',
|
|
|
10
16
|
_MAX_PIPELINES = 15
|
|
11
17
|
|
|
12
18
|
|
|
13
|
-
def _categorize_functions(result: 'AnalysisResult'):
|
|
19
|
+
def _categorize_functions(result: 'AnalysisResult') -> Tuple[list, list, list]:
|
|
14
20
|
"""Categorize functions into input/transform/output based on name patterns."""
|
|
15
21
|
input_funcs, transform_funcs, output_funcs = [], [], []
|
|
16
22
|
for func_name, func in result.functions.items():
|
|
@@ -284,3 +290,81 @@ class DataAnalyzer:
|
|
|
284
290
|
opt['hub_optimization'].append({'function': hub['id'], 'connections': hub['in_degree'] + hub['out_degree'], 'optimization_type': 'split' if hub['out_degree'] > 10 else 'cache'})
|
|
285
291
|
opt['potential_score'] = (len(opt['type_consolidation']) * 10 + len(opt['process_consolidation']) * 15 + len(opt['hub_optimization']) * 5) / 100.0
|
|
286
292
|
return opt
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
# ---------------------------------------------------------------------------
|
|
296
|
+
# New focused analyzer classes (Step 5 refactoring)
|
|
297
|
+
# ---------------------------------------------------------------------------
|
|
298
|
+
|
|
299
|
+
class DataFlowAnalyzer:
|
|
300
|
+
"""Analyze data flows: pipelines, state patterns, dependencies, and event flows.
|
|
301
|
+
|
|
302
|
+
Extracted from DataAnalyzer to provide focused data flow analysis.
|
|
303
|
+
"""
|
|
304
|
+
|
|
305
|
+
def analyze(self, result: AnalysisResult) -> Dict[str, Any]:
|
|
306
|
+
"""Perform complete data flow analysis."""
|
|
307
|
+
return {
|
|
308
|
+
'data_pipelines': self.find_data_pipelines(result),
|
|
309
|
+
'state_patterns': self.find_state_patterns(result),
|
|
310
|
+
'data_dependencies': self.find_data_dependencies(result),
|
|
311
|
+
'event_flows': self.find_event_flows(result),
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
def find_data_pipelines(self, result: AnalysisResult) -> list:
|
|
315
|
+
"""Find data transformation pipelines (wrapper for backward compat)."""
|
|
316
|
+
# Delegate to the module-level helper via DataAnalyzer instance
|
|
317
|
+
return DataAnalyzer()._find_data_pipelines(result)
|
|
318
|
+
|
|
319
|
+
def find_state_patterns(self, result: AnalysisResult) -> list:
|
|
320
|
+
"""Find state management patterns."""
|
|
321
|
+
return DataAnalyzer()._find_state_patterns(result)
|
|
322
|
+
|
|
323
|
+
def find_data_dependencies(self, result: AnalysisResult) -> list:
|
|
324
|
+
"""Find cross-module data dependencies."""
|
|
325
|
+
return DataAnalyzer()._find_data_dependencies(result)
|
|
326
|
+
|
|
327
|
+
def find_event_flows(self, result: AnalysisResult) -> list:
|
|
328
|
+
"""Find event-driven patterns."""
|
|
329
|
+
return DataAnalyzer()._find_event_flows(result)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
class OptimizationAdvisor:
|
|
333
|
+
"""Analyze optimization opportunities: data types and process patterns.
|
|
334
|
+
|
|
335
|
+
Extracted from DataAnalyzer to provide focused optimization analysis.
|
|
336
|
+
"""
|
|
337
|
+
|
|
338
|
+
def analyze(self, result: AnalysisResult) -> Dict[str, Any]:
|
|
339
|
+
"""Perform complete optimization analysis."""
|
|
340
|
+
data_types = self.analyze_data_types(result)
|
|
341
|
+
data_flow_graph = self.build_data_flow_graph(result)
|
|
342
|
+
process_patterns = self.identify_process_patterns(result)
|
|
343
|
+
optimization_analysis = self.analyze_optimization_opportunities(
|
|
344
|
+
result, data_types, data_flow_graph
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
'data_types': data_types,
|
|
349
|
+
'data_flow_graph': data_flow_graph,
|
|
350
|
+
'process_patterns': process_patterns,
|
|
351
|
+
'optimization_analysis': optimization_analysis,
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
def analyze_data_types(self, result: AnalysisResult) -> list:
|
|
355
|
+
"""Analyze data types and usage."""
|
|
356
|
+
return DataAnalyzer()._analyze_data_types(result)
|
|
357
|
+
|
|
358
|
+
def build_data_flow_graph(self, result: AnalysisResult) -> dict:
|
|
359
|
+
"""Build data flow graph from function relationships."""
|
|
360
|
+
return DataAnalyzer()._build_data_flow_graph(result)
|
|
361
|
+
|
|
362
|
+
def identify_process_patterns(self, result: AnalysisResult) -> list:
|
|
363
|
+
"""Identify common data processing patterns."""
|
|
364
|
+
return DataAnalyzer()._identify_process_patterns(result)
|
|
365
|
+
|
|
366
|
+
def analyze_optimization_opportunities(
|
|
367
|
+
self, result: AnalysisResult, data_types: list, dfg: dict
|
|
368
|
+
) -> dict:
|
|
369
|
+
"""Analyze optimization opportunities in data handling."""
|
|
370
|
+
return DataAnalyzer()._analyze_optimization_opportunities(result, data_types, dfg)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""Shared AST utilities for analysis modules."""
|
|
2
2
|
|
|
3
|
-
from .ast_helpers import get_ast, find_function_node, expr_to_str, ast_unparse
|
|
3
|
+
from .ast_helpers import get_ast, find_function_node, expr_to_str, ast_unparse, qualified_name
|
|
4
4
|
|
|
5
|
-
__all__ = ["get_ast", "find_function_node", "expr_to_str", "ast_unparse"]
|
|
5
|
+
__all__ = ["get_ast", "find_function_node", "expr_to_str", "ast_unparse", "qualified_name"]
|
|
@@ -57,6 +57,19 @@ def ast_unparse(node: Optional[ast.AST], default_none: str = "None") -> str:
|
|
|
57
57
|
return str(node)
|
|
58
58
|
|
|
59
59
|
|
|
60
|
+
def qualified_name(module_name: str, class_stack: list, name: str) -> str:
|
|
61
|
+
"""Build a fully-qualified dotted name from module, optional class scope, and name.
|
|
62
|
+
|
|
63
|
+
Shared replacement for the identical ``_qualified_name`` methods in
|
|
64
|
+
``CallGraphExtractor`` and ``CFGExtractor``.
|
|
65
|
+
"""
|
|
66
|
+
parts = [module_name]
|
|
67
|
+
if class_stack:
|
|
68
|
+
parts.append(class_stack[-1])
|
|
69
|
+
parts.append(name)
|
|
70
|
+
return '.'.join(parts)
|
|
71
|
+
|
|
72
|
+
|
|
60
73
|
def expr_to_str(node: ast.expr) -> Optional[str]:
|
|
61
74
|
"""Convert an AST expression to a dotted string (for call-name extraction).
|
|
62
75
|
|
|
@@ -9,6 +9,12 @@ from typing import Any, Optional, Tuple
|
|
|
9
9
|
import ast
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
def make_cache_key(file_path: str, content: str) -> str:
|
|
13
|
+
"""Generate a cache key from file stem and MD5 of content."""
|
|
14
|
+
content_hash = hashlib.md5(content.encode()).hexdigest()[:16]
|
|
15
|
+
return f"{Path(file_path).stem}_{content_hash}"
|
|
16
|
+
|
|
17
|
+
|
|
12
18
|
class FileCache:
|
|
13
19
|
"""Cache for parsed AST files."""
|
|
14
20
|
|
|
@@ -26,9 +32,7 @@ class FileCache:
|
|
|
26
32
|
return f"{Path(file_path).stem}_unknown"
|
|
27
33
|
|
|
28
34
|
def _get_cache_key(self, file_path: str, content: str) -> str:
|
|
29
|
-
|
|
30
|
-
content_hash = hashlib.md5(content.encode()).hexdigest()[:16]
|
|
31
|
-
return f"{Path(file_path).stem}_{content_hash}"
|
|
35
|
+
return make_cache_key(file_path, content)
|
|
32
36
|
|
|
33
37
|
def _get_cache_path(self, cache_key: str) -> Path:
|
|
34
38
|
"""Get cache file path."""
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"""Memory-efficient streaming cache with LRU eviction."""
|
|
2
2
|
|
|
3
3
|
import ast
|
|
4
|
-
import hashlib
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
from typing import Dict, List, Optional, Tuple
|
|
7
6
|
|
|
7
|
+
from code2llm.core.file_cache import make_cache_key
|
|
8
|
+
|
|
8
9
|
|
|
9
10
|
class StreamingFileCache:
|
|
10
11
|
"""Memory-efficient cache with LRU eviction."""
|
|
@@ -17,9 +18,7 @@ class StreamingFileCache:
|
|
|
17
18
|
self._access_order: List[str] = []
|
|
18
19
|
|
|
19
20
|
def _get_cache_key(self, file_path: str, content: str) -> str:
|
|
20
|
-
|
|
21
|
-
content_hash = hashlib.md5(content.encode()).hexdigest()[:16]
|
|
22
|
-
return f"{Path(file_path).stem}_{content_hash}"
|
|
21
|
+
return make_cache_key(file_path, content)
|
|
23
22
|
|
|
24
23
|
def _evict_if_needed(self) -> None:
|
|
25
24
|
"""Evict oldest entries if cache is full."""
|
|
@@ -7,15 +7,11 @@ from datetime import datetime
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any, Dict, List
|
|
9
9
|
|
|
10
|
+
from code2llm.exporters.base import ViewGeneratorMixin
|
|
10
11
|
|
|
11
|
-
class ArticleViewGenerator:
|
|
12
|
-
"""Generate status.md — publishable project health article."""
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
|
17
|
-
with open(output_path, "w", encoding="utf-8") as f:
|
|
18
|
-
f.write("\n".join(lines) + "\n")
|
|
13
|
+
class ArticleViewGenerator(ViewGeneratorMixin):
|
|
14
|
+
"""Generate status.md — publishable project health article."""
|
|
19
15
|
|
|
20
16
|
def _render(self, data: Dict[str, Any]) -> List[str]:
|
|
21
17
|
proj = data.get("project", {})
|
|
@@ -94,6 +94,22 @@ class BaseExporter(ABC):
|
|
|
94
94
|
Exporter = BaseExporter
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
class ViewGeneratorMixin:
|
|
98
|
+
"""Mixin providing the shared ``generate`` implementation for view generators.
|
|
99
|
+
|
|
100
|
+
Eliminates the identical ``generate`` method duplicated across
|
|
101
|
+
``ArticleViewGenerator``, ``ContextViewGenerator``, and ``ToonViewGenerator``.
|
|
102
|
+
|
|
103
|
+
Subclasses must implement ``_render(data) -> List[str]``.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
def generate(self, data: Dict[str, Any], output_path: str) -> None:
|
|
107
|
+
lines = self._render(data)
|
|
108
|
+
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
|
109
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
110
|
+
f.write("\n".join(lines) + "\n")
|
|
111
|
+
|
|
112
|
+
|
|
97
113
|
# Export registry: format_name -> exporter_class
|
|
98
114
|
EXPORT_REGISTRY: Dict[str, Type[BaseExporter]] = {}
|
|
99
115
|
|
|
@@ -6,15 +6,11 @@ Generates context.md from project.yaml data.
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any, Dict, List
|
|
8
8
|
|
|
9
|
+
from code2llm.exporters.base import ViewGeneratorMixin
|
|
9
10
|
|
|
10
|
-
class ContextViewGenerator:
|
|
11
|
-
"""Generate context.md from project.yaml data."""
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
|
16
|
-
with open(output_path, "w", encoding="utf-8") as f:
|
|
17
|
-
f.write("\n".join(lines) + "\n")
|
|
12
|
+
class ContextViewGenerator(ViewGeneratorMixin):
|
|
13
|
+
"""Generate context.md from project.yaml data."""
|
|
18
14
|
|
|
19
15
|
def _render(self, data: Dict[str, Any]) -> List[str]:
|
|
20
16
|
proj = data.get("project", {})
|
|
@@ -15,6 +15,19 @@ EXCLUDE_PATTERNS = {
|
|
|
15
15
|
'dist', 'build', 'egg-info', '.tox', '.mypy_cache',
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
def is_excluded_path(path: str) -> bool:
|
|
19
|
+
"""Return True if *path* matches any standard exclusion pattern (venv, cache, etc.)."""
|
|
20
|
+
if not path:
|
|
21
|
+
return False
|
|
22
|
+
path_lower = path.lower().replace('\\', '/')
|
|
23
|
+
for pattern in EXCLUDE_PATTERNS:
|
|
24
|
+
if f'/{pattern}/' in path_lower or path_lower.startswith(f'{pattern}/'):
|
|
25
|
+
return True
|
|
26
|
+
if pattern in path_lower.split('/'):
|
|
27
|
+
return True
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
|
|
18
31
|
# Rekomendacje podziału typów hub: typ -> sugerowane pod-interfejsy
|
|
19
32
|
HUB_SPLIT_RECOMMENDATIONS = {
|
|
20
33
|
"AnalysisResult": [
|
|
@@ -17,7 +17,7 @@ from pathlib import Path
|
|
|
17
17
|
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
18
18
|
|
|
19
19
|
from .base import BaseExporter, export_format
|
|
20
|
-
from .flow_constants import CC_HIGH, FAN_OUT_THRESHOLD, EXCLUDE_PATTERNS, HUB_SPLIT_RECOMMENDATIONS, HUB_TYPE_THRESHOLD
|
|
20
|
+
from .flow_constants import CC_HIGH, FAN_OUT_THRESHOLD, EXCLUDE_PATTERNS, HUB_SPLIT_RECOMMENDATIONS, HUB_TYPE_THRESHOLD, is_excluded_path
|
|
21
21
|
from .flow_renderer import FlowRenderer
|
|
22
22
|
from code2llm.core.models import (
|
|
23
23
|
AnalysisResult, FunctionInfo, ClassInfo, ModuleInfo, FlowNode
|
|
@@ -382,12 +382,4 @@ class FlowExporter(BaseExporter):
|
|
|
382
382
|
# utility helpers
|
|
383
383
|
# ------------------------------------------------------------------
|
|
384
384
|
def _is_excluded(self, path: str) -> bool:
|
|
385
|
-
|
|
386
|
-
return False
|
|
387
|
-
path_lower = path.lower().replace('\\', '/')
|
|
388
|
-
for pattern in EXCLUDE_PATTERNS:
|
|
389
|
-
if f'/{pattern}/' in path_lower or path_lower.startswith(f'{pattern}/'):
|
|
390
|
-
return True
|
|
391
|
-
if pattern in path_lower.split('/'):
|
|
392
|
-
return True
|
|
393
|
-
return False
|
|
385
|
+
return is_excluded_path(path)
|
|
@@ -16,6 +16,7 @@ from pathlib import Path
|
|
|
16
16
|
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
17
17
|
|
|
18
18
|
from .base import BaseExporter, export_format
|
|
19
|
+
from .flow_constants import is_excluded_path
|
|
19
20
|
from code2llm.core.models import AnalysisResult, FunctionInfo, ClassInfo, ModuleInfo
|
|
20
21
|
from code2llm.core.config import LANGUAGE_EXTENSIONS
|
|
21
22
|
from typing import Optional
|
|
@@ -315,15 +316,7 @@ class MapExporter(BaseExporter):
|
|
|
315
316
|
return f"{fi.name}({args_str}){ret}"
|
|
316
317
|
|
|
317
318
|
def _is_excluded(self, path: str) -> bool:
|
|
318
|
-
|
|
319
|
-
return False
|
|
320
|
-
path_lower = path.lower().replace('\\', '/')
|
|
321
|
-
for pattern in EXCLUDE_PATTERNS:
|
|
322
|
-
if f'/{pattern}/' in path_lower or path_lower.startswith(f'{pattern}/'):
|
|
323
|
-
return True
|
|
324
|
-
if pattern in path_lower.split('/'):
|
|
325
|
-
return True
|
|
326
|
-
return False
|
|
319
|
+
return is_excluded_path(path)
|
|
327
320
|
|
|
328
321
|
def _rel_path(self, fpath: str, project_path: str) -> str:
|
|
329
322
|
if not project_path or not fpath:
|
|
@@ -7,6 +7,8 @@ from collections import defaultdict
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any, Dict, List
|
|
9
9
|
|
|
10
|
+
from code2llm.exporters.base import ViewGeneratorMixin
|
|
11
|
+
|
|
10
12
|
# Language detection from file extensions
|
|
11
13
|
_LANG_EXT_MAP = {
|
|
12
14
|
'.py': 'python', '.ts': 'typescript', '.tsx': 'typescript',
|
|
@@ -21,15 +23,9 @@ _LANG_EXT_MAP = {
|
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
|
|
24
|
-
class ToonViewGenerator:
|
|
26
|
+
class ToonViewGenerator(ViewGeneratorMixin):
|
|
25
27
|
"""Generate project.toon.yaml from project.yaml data."""
|
|
26
28
|
|
|
27
|
-
def generate(self, data: Dict[str, Any], output_path: str) -> None:
|
|
28
|
-
lines = self._render(data)
|
|
29
|
-
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
|
30
|
-
with open(output_path, "w", encoding="utf-8") as f:
|
|
31
|
-
f.write("\n".join(lines) + "\n")
|
|
32
|
-
|
|
33
29
|
def _render(self, data: Dict[str, Any]) -> List[str]:
|
|
34
30
|
proj = data.get("project", {})
|
|
35
31
|
health = data.get("health", {})
|
|
@@ -5,8 +5,11 @@ Generators for LLM flow summaries, task breakdowns, and Mermaid diagrams.
|
|
|
5
5
|
|
|
6
6
|
from .llm_flow import main as llm_flow_main
|
|
7
7
|
from .mermaid import generate_pngs
|
|
8
|
+
from ._utils import dump_yaml
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
__all__ = [
|
|
10
12
|
'llm_flow_main',
|
|
11
13
|
'generate_pngs',
|
|
14
|
+
'dump_yaml',
|
|
12
15
|
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Shared utilities for generators — avoids circular imports."""
|
|
2
|
+
|
|
3
|
+
import yaml
|
|
4
|
+
from typing import Any, Dict
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def dump_yaml(data: Dict[str, Any]) -> str:
|
|
8
|
+
"""Shared YAML serialiser (sort_keys=False, unicode, width=100)."""
|
|
9
|
+
return yaml.safe_dump(
|
|
10
|
+
data,
|
|
11
|
+
sort_keys=False,
|
|
12
|
+
allow_unicode=True,
|
|
13
|
+
width=100,
|
|
14
|
+
default_flow_style=False,
|
|
15
|
+
)
|
|
@@ -8,6 +8,8 @@ from typing import Any, Dict, Iterable, List, Optional, Set, Tuple
|
|
|
8
8
|
|
|
9
9
|
import yaml
|
|
10
10
|
|
|
11
|
+
from ._utils import dump_yaml
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
_FUNC_LABEL_PREFIX = "FUNC:"
|
|
13
15
|
_CALL_LABEL_PREFIX = "CALL "
|
|
@@ -402,15 +404,6 @@ def render_llm_flow_md(flow: Dict[str, Any]) -> str:
|
|
|
402
404
|
return "\n".join(lines).rstrip() + "\n"
|
|
403
405
|
|
|
404
406
|
|
|
405
|
-
def dump_yaml(data: Dict[str, Any]) -> str:
|
|
406
|
-
return yaml.safe_dump(
|
|
407
|
-
data,
|
|
408
|
-
sort_keys=False,
|
|
409
|
-
allow_unicode=True,
|
|
410
|
-
width=100,
|
|
411
|
-
default_flow_style=False,
|
|
412
|
-
)
|
|
413
|
-
|
|
414
407
|
|
|
415
408
|
def create_parser() -> argparse.ArgumentParser:
|
|
416
409
|
p = argparse.ArgumentParser(
|
|
@@ -5,6 +5,8 @@ from typing import Any, Dict, List, Optional, Tuple
|
|
|
5
5
|
|
|
6
6
|
import yaml
|
|
7
7
|
|
|
8
|
+
from ._utils import dump_yaml
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
def _strip_bom(text: str) -> str:
|
|
10
12
|
return text[1:] if text.startswith("\ufeff") else text
|
|
@@ -230,15 +232,6 @@ def load_input(path: Path) -> Dict[str, Any]:
|
|
|
230
232
|
return parse_llm_task_text(raw)
|
|
231
233
|
|
|
232
234
|
|
|
233
|
-
def dump_yaml(data: Dict[str, Any]) -> str:
|
|
234
|
-
return yaml.safe_dump(
|
|
235
|
-
data,
|
|
236
|
-
sort_keys=False,
|
|
237
|
-
allow_unicode=True,
|
|
238
|
-
width=100,
|
|
239
|
-
default_flow_style=False,
|
|
240
|
-
)
|
|
241
|
-
|
|
242
235
|
|
|
243
236
|
def create_parser() -> argparse.ArgumentParser:
|
|
244
237
|
p = argparse.ArgumentParser(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2llm
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.118
|
|
4
4
|
Summary: High-performance Python code flow analysis with optimized TOON format - CFG, DFG, call graphs, and intelligent code queries
|
|
5
5
|
Home-page: https://github.com/wronai/stts
|
|
6
6
|
Author: STTS Project
|
|
@@ -67,7 +67,7 @@ Dynamic: requires-python
|
|
|
67
67
|
|
|
68
68
|
## AI Cost Tracking
|
|
69
69
|
|
|
70
|
-
    
|
|
71
71
|
  
|
|
72
72
|
|
|
73
73
|
- 🤖 **LLM usage:** $7.5000 (166 commits)
|
|
@@ -104,6 +104,7 @@ code2llm/exporters/toon/metrics.py
|
|
|
104
104
|
code2llm/exporters/toon/module_detail.py
|
|
105
105
|
code2llm/exporters/toon/renderer.py
|
|
106
106
|
code2llm/generators/__init__.py
|
|
107
|
+
code2llm/generators/_utils.py
|
|
107
108
|
code2llm/generators/llm_flow.py
|
|
108
109
|
code2llm/generators/llm_task.py
|
|
109
110
|
code2llm/generators/mermaid.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code2llm"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.118"
|
|
8
8
|
description = "High-performance Python code flow analysis with optimized TOON format - CFG, DFG, call graphs, and intelligent code queries"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|