code2llm 0.5.59__tar.gz → 0.5.61__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.59 → code2llm-0.5.61}/PKG-INFO +1 -1
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/__init__.py +1 -1
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/index_generator.py +70 -1
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/map_exporter.py +1 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/toon/__init__.py +6 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/toon/renderer.py +86 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/nlp/__init__.py +1 -1
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm.egg-info/PKG-INFO +1 -1
- {code2llm-0.5.59 → code2llm-0.5.61}/pyproject.toml +1 -1
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_format_quality.py +8 -2
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_toon_v2.py +2 -2
- {code2llm-0.5.59 → code2llm-0.5.61}/LICENSE +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/README.md +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/__main__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/call_graph.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/cfg.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/coupling.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/data_analysis.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/dfg.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/pipeline_detector.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/side_effects.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/smells.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/analysis/type_inference.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/api.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/cli.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/cli_analysis.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/cli_commands.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/cli_exports/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/cli_exports/code2logic.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/cli_exports/formats.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/cli_exports/orchestrator.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/cli_exports/prompt.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/cli_parser.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/analyzer.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/config.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/file_analyzer.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/file_cache.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/file_filter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/base.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/cpp.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/csharp.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/generic.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/go_lang.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/java.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/php.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/ruby.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/rust.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/lang/typescript.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/core/refactoring.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/gitignore.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/large_repo.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/models.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/repo_files.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/streaming/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/streaming/cache.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/streaming/incremental.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/streaming/prioritizer.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/streaming/scanner.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/streaming/strategies.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/streaming_analyzer.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/core/toon_size_manager.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/article_view.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/base.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/context_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/context_view.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/evolution_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/flow_constants.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/flow_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/flow_renderer.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/html_dashboard.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/json_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/llm_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/mermaid_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/project_yaml_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/readme_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/report_generators.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/toon/helpers.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/toon/metrics.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/toon/module_detail.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/toon.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/toon_view.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/validate_project.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/exporters/yaml_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/generators/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/generators/llm_flow.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/generators/llm_task.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/generators/mermaid.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/nlp/config.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/nlp/entity_resolution.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/nlp/intent_matching.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/nlp/normalization.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/nlp/pipeline.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/patterns/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/patterns/detector.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/refactor/__init__.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm/refactor/prompt_engine.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm.egg-info/SOURCES.txt +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm.egg-info/dependency_links.txt +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm.egg-info/entry_points.txt +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm.egg-info/requires.txt +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/code2llm.egg-info/top_level.txt +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/setup.cfg +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/setup.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_advanced_analysis.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_analyzer.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_deep_analysis.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_edge_cases.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_flow_exporter.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_multilanguage_e2e.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_nlp_pipeline.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_nonpython_cc_calls.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_pipeline_detector.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_prompt_engine.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_prompt_txt.py +0 -0
- {code2llm-0.5.59 → code2llm-0.5.61}/tests/test_refactoring_engine.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.61
|
|
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
|
|
@@ -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.61"
|
|
12
12
|
__author__ = "STTS Project"
|
|
13
13
|
|
|
14
14
|
# Core analysis components (lightweight, always needed)
|
|
@@ -28,6 +28,12 @@ class IndexHTMLGenerator:
|
|
|
28
28
|
'.go': {'icon': '🐹', 'type': 'code', 'name': 'Go'},
|
|
29
29
|
'.rs': {'icon': '🦀', 'type': 'code', 'name': 'Rust'},
|
|
30
30
|
'.java': {'icon': '☕', 'type': 'code', 'name': 'Java'},
|
|
31
|
+
'.png': {'icon': '🖼️', 'type': 'image', 'name': 'Image'},
|
|
32
|
+
'.jpg': {'icon': '🖼️', 'type': 'image', 'name': 'Image'},
|
|
33
|
+
'.jpeg': {'icon': '🖼️', 'type': 'image', 'name': 'Image'},
|
|
34
|
+
'.gif': {'icon': '🖼️', 'type': 'image', 'name': 'Image'},
|
|
35
|
+
'.svg': {'icon': '🖼️', 'type': 'image', 'name': 'Image'},
|
|
36
|
+
'.webp': {'icon': '🖼️', 'type': 'image', 'name': 'Image'},
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
def __init__(self, output_dir: Path):
|
|
@@ -120,6 +126,11 @@ class IndexHTMLGenerator:
|
|
|
120
126
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
121
127
|
<title>code2llm Analysis Results</title>
|
|
122
128
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
129
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
|
130
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
|
|
131
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
|
132
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/json.min.js"></script>
|
|
133
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/yaml.min.js"></script>
|
|
123
134
|
<style>
|
|
124
135
|
:root {{
|
|
125
136
|
--bg: #0f172a;
|
|
@@ -517,6 +528,36 @@ class IndexHTMLGenerator:
|
|
|
517
528
|
margin: 1.5rem 0;
|
|
518
529
|
}}
|
|
519
530
|
|
|
531
|
+
/* Mermaid diagram styles */
|
|
532
|
+
.mermaid-content {{
|
|
533
|
+
display: flex;
|
|
534
|
+
justify-content: center;
|
|
535
|
+
padding: 1rem;
|
|
536
|
+
background: var(--surface);
|
|
537
|
+
border-radius: 0.5rem;
|
|
538
|
+
border: 1px solid var(--border);
|
|
539
|
+
}}
|
|
540
|
+
|
|
541
|
+
.mermaid-content .mermaid {{
|
|
542
|
+
background: transparent;
|
|
543
|
+
}}
|
|
544
|
+
|
|
545
|
+
/* Image preview styles */
|
|
546
|
+
.image-preview {{
|
|
547
|
+
display: flex;
|
|
548
|
+
justify-content: center;
|
|
549
|
+
align-items: center;
|
|
550
|
+
height: 100%;
|
|
551
|
+
padding: 1rem;
|
|
552
|
+
background: var(--surface);
|
|
553
|
+
border-radius: 0.5rem;
|
|
554
|
+
border: 1px solid var(--border);
|
|
555
|
+
}}
|
|
556
|
+
|
|
557
|
+
.image-preview img {{
|
|
558
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
559
|
+
}}
|
|
560
|
+
|
|
520
561
|
/* Mobile responsive */
|
|
521
562
|
@media (max-width: 768px) {{
|
|
522
563
|
.container {{
|
|
@@ -603,6 +644,9 @@ class IndexHTMLGenerator:
|
|
|
603
644
|
</div>
|
|
604
645
|
|
|
605
646
|
<script>
|
|
647
|
+
// Initialize mermaid
|
|
648
|
+
mermaid.initialize({{ startOnLoad: false, theme: 'dark' }});
|
|
649
|
+
|
|
606
650
|
const files = {files_json};
|
|
607
651
|
let currentFile = null;
|
|
608
652
|
|
|
@@ -673,13 +717,38 @@ class IndexHTMLGenerator:
|
|
|
673
717
|
}} else if (file.type === 'html') {{
|
|
674
718
|
// For HTML files, show in iframe for safety
|
|
675
719
|
body.innerHTML = `<iframe src="${{file.rel_path}}" style="width:100%;height:100%;border:none;border-radius:0.5rem;"></iframe>`;
|
|
720
|
+
}} else if (file.type === 'image') {{
|
|
721
|
+
// For images, display the actual image
|
|
722
|
+
body.innerHTML = `<div class="image-preview"><img src="${{file.rel_path}}" alt="${{file.name}}" style="max-width:100%;max-height:100%;object-fit:contain;border-radius:0.5rem;"></div>`;
|
|
723
|
+
}} else if (file.type === 'mermaid') {{
|
|
724
|
+
// Render mermaid diagram
|
|
725
|
+
const diagramId = 'mermaid-diagram-' + Date.now();
|
|
726
|
+
body.innerHTML = `<div class="mermaid-content"><pre class="mermaid" id="${{diagramId}}">${{file.content}}</pre></div>`;
|
|
727
|
+
// Initialize mermaid on the new element
|
|
728
|
+
setTimeout(() => {{
|
|
729
|
+
mermaid.init(undefined, document.getElementById(diagramId));
|
|
730
|
+
}}, 0);
|
|
676
731
|
}} else if (file.type === 'json') {{
|
|
677
732
|
try {{
|
|
678
733
|
const json = JSON.parse(file.content.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'));
|
|
679
|
-
|
|
734
|
+
const formatted = JSON.stringify(json, null, 2);
|
|
735
|
+
body.innerHTML = `<pre><code class="language-json">${{formatted.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')}}</code></pre>`;
|
|
736
|
+
hljs.highlightElement(body.querySelector('code'));
|
|
680
737
|
}} catch {{
|
|
681
738
|
body.innerHTML = `<pre>${{file.content}}</pre>`;
|
|
682
739
|
}}
|
|
740
|
+
}} else if (file.type === 'yaml') {{
|
|
741
|
+
// YAML with syntax highlighting
|
|
742
|
+
body.innerHTML = `<pre><code class="language-yaml">${{file.content.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')}}</code></pre>`;
|
|
743
|
+
hljs.highlightElement(body.querySelector('code'));
|
|
744
|
+
}} else if (file.type === 'toon') {{
|
|
745
|
+
// TOON with simple highlighting (use ini as closest match for key: value format)
|
|
746
|
+
body.innerHTML = `<pre><code class="language-ini">${{file.content.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')}}</code></pre>`;
|
|
747
|
+
hljs.highlightElement(body.querySelector('code'));
|
|
748
|
+
}} else if (file.type === 'code') {{
|
|
749
|
+
// Code files with auto-highlighting
|
|
750
|
+
body.innerHTML = `<pre><code>${{file.content.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')}}</code></pre>`;
|
|
751
|
+
hljs.highlightElement(body.querySelector('code'));
|
|
683
752
|
}} else {{
|
|
684
753
|
body.innerHTML = `<pre>${{file.content}}</pre>`;
|
|
685
754
|
}}
|
|
@@ -38,9 +38,15 @@ class ToonExporter:
|
|
|
38
38
|
sections.append("")
|
|
39
39
|
sections.extend(self.renderer.render_health(ctx))
|
|
40
40
|
sections.append("")
|
|
41
|
+
sections.extend(self.renderer.render_refactor(ctx))
|
|
42
|
+
sections.append("")
|
|
43
|
+
sections.extend(self.renderer.render_pipelines(ctx))
|
|
44
|
+
sections.append("")
|
|
41
45
|
sections.extend(self.renderer.render_layers(ctx))
|
|
42
46
|
sections.append("")
|
|
43
47
|
sections.extend(self.renderer.render_coupling(ctx))
|
|
48
|
+
sections.append("")
|
|
49
|
+
sections.extend(self.renderer.render_external(ctx))
|
|
44
50
|
|
|
45
51
|
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
|
46
52
|
with open(output_path, "w", encoding="utf-8") as f:
|
|
@@ -383,3 +383,89 @@ class ToonRenderer:
|
|
|
383
383
|
)
|
|
384
384
|
|
|
385
385
|
return lines
|
|
386
|
+
|
|
387
|
+
def render_pipelines(self, ctx: Dict[str, Any]) -> List[str]:
|
|
388
|
+
"""Render PIPELINES section - data flow pipelines from entry points."""
|
|
389
|
+
result: AnalysisResult = ctx["result"]
|
|
390
|
+
|
|
391
|
+
# Find entry points and their downstream pipelines
|
|
392
|
+
pipelines = []
|
|
393
|
+
for func_name, func_info in result.functions.items():
|
|
394
|
+
# Entry points: functions with no callers but have calls
|
|
395
|
+
if not func_info.called_by and func_info.calls:
|
|
396
|
+
chain = self._trace_pipeline(func_name, result, depth=0)
|
|
397
|
+
if chain:
|
|
398
|
+
pipelines.append({
|
|
399
|
+
"entry": func_name.split(".")[-1],
|
|
400
|
+
"chain": chain,
|
|
401
|
+
"purity": self._calculate_purity(chain, result),
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
if not pipelines:
|
|
405
|
+
return ["PIPELINES[0]: none detected"]
|
|
406
|
+
|
|
407
|
+
lines = [f"PIPELINES[{len(pipelines)}]:"]
|
|
408
|
+
for i, pipe in enumerate(pipelines[:5], 1): # Max 5 pipelines
|
|
409
|
+
purity_pct = int(pipe["purity"] * 100)
|
|
410
|
+
chain_str = " → ".join(pipe["chain"][:4]) # Show first 4 steps
|
|
411
|
+
if len(pipe["chain"]) > 4:
|
|
412
|
+
chain_str += f" → ...({len(pipe['chain']) - 4} more)"
|
|
413
|
+
lines.append(f" [{i}] Src [{pipe['entry']}]: {chain_str}")
|
|
414
|
+
lines.append(f" PURITY: {purity_pct}% pure")
|
|
415
|
+
|
|
416
|
+
return lines
|
|
417
|
+
|
|
418
|
+
def _trace_pipeline(self, start_func: str, result: AnalysisResult, depth: int) -> List[str]:
|
|
419
|
+
"""Trace a pipeline starting from an entry point."""
|
|
420
|
+
if depth > 10: # Prevent infinite recursion
|
|
421
|
+
return []
|
|
422
|
+
|
|
423
|
+
chain = []
|
|
424
|
+
current = start_func
|
|
425
|
+
visited = set()
|
|
426
|
+
|
|
427
|
+
while current and current not in visited and len(chain) < 20:
|
|
428
|
+
visited.add(current)
|
|
429
|
+
func_info = result.functions.get(current)
|
|
430
|
+
if not func_info:
|
|
431
|
+
break
|
|
432
|
+
|
|
433
|
+
chain.append(current.split(".")[-1])
|
|
434
|
+
|
|
435
|
+
# Follow the first call that's not a builtin
|
|
436
|
+
next_func = None
|
|
437
|
+
for callee in func_info.calls:
|
|
438
|
+
if callee in result.functions:
|
|
439
|
+
next_func = callee
|
|
440
|
+
break
|
|
441
|
+
|
|
442
|
+
current = next_func
|
|
443
|
+
|
|
444
|
+
return chain
|
|
445
|
+
|
|
446
|
+
def _calculate_purity(self, chain: List[str], result: AnalysisResult) -> float:
|
|
447
|
+
"""Calculate purity ratio (functions without side effects)."""
|
|
448
|
+
if not chain:
|
|
449
|
+
return 0.0
|
|
450
|
+
|
|
451
|
+
pure_count = 0
|
|
452
|
+
for func_name in chain:
|
|
453
|
+
full_name = None
|
|
454
|
+
for qname, fi in result.functions.items():
|
|
455
|
+
if fi.name == func_name:
|
|
456
|
+
full_name = qname
|
|
457
|
+
break
|
|
458
|
+
|
|
459
|
+
if full_name:
|
|
460
|
+
func_info = result.functions.get(full_name)
|
|
461
|
+
if func_info and not getattr(func_info, 'has_side_effects', False):
|
|
462
|
+
pure_count += 1
|
|
463
|
+
|
|
464
|
+
return pure_count / len(chain)
|
|
465
|
+
|
|
466
|
+
def render_external(self, ctx: Dict[str, Any]) -> List[str]:
|
|
467
|
+
"""Render EXTERNAL section - cross-references to other tools."""
|
|
468
|
+
lines = ["EXTERNAL:"]
|
|
469
|
+
lines.append(" validation: run `vallm batch .` → validation.toon")
|
|
470
|
+
lines.append(" duplication: run `redup scan .` → duplication.toon")
|
|
471
|
+
return lines
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2llm
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.61
|
|
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
|
|
@@ -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.61"
|
|
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"
|
|
@@ -53,11 +53,15 @@ def ground_truth_project(tmp_path_factory) -> Path:
|
|
|
53
53
|
return Result(errors=["empty"])
|
|
54
54
|
if not isinstance(data, list):
|
|
55
55
|
return Result(errors=["not list"])
|
|
56
|
+
if len(data) > config.max_items:
|
|
57
|
+
return Result(errors=["too many items"])
|
|
56
58
|
filtered = []
|
|
57
59
|
for item in data:
|
|
58
60
|
if isinstance(item, dict):
|
|
59
61
|
if "id" in item:
|
|
60
62
|
if item.get("active", True):
|
|
63
|
+
if config.debug:
|
|
64
|
+
print(f"Adding active: {item['id']}")
|
|
61
65
|
filtered.append(item)
|
|
62
66
|
elif config.debug:
|
|
63
67
|
filtered.append(item)
|
|
@@ -184,7 +188,7 @@ class TestAnalysisToon:
|
|
|
184
188
|
assert "HEALTH[" in toon_content
|
|
185
189
|
|
|
186
190
|
def test_has_refactor_section(self, toon_content):
|
|
187
|
-
assert "REFACTOR["
|
|
191
|
+
assert "REFACTOR[" in toon_content
|
|
188
192
|
|
|
189
193
|
def test_has_coupling_section(self, toon_content):
|
|
190
194
|
assert "COUPLING" in toon_content
|
|
@@ -336,7 +340,9 @@ class TestCrossFormat:
|
|
|
336
340
|
assert "HEALTH[" in toon
|
|
337
341
|
assert "LAYERS" in toon
|
|
338
342
|
assert "COUPLING" in toon
|
|
339
|
-
assert "REFACTOR["
|
|
343
|
+
assert "REFACTOR[" in toon
|
|
344
|
+
assert "PIPELINES" in toon
|
|
345
|
+
assert "EXTERNAL" in toon
|
|
340
346
|
|
|
341
347
|
def test_project_map_has_unique_structure_info(self, all_formats):
|
|
342
348
|
"""map.toon should have the structural import/signature map."""
|
|
@@ -105,13 +105,13 @@ class TestToonExporterV2:
|
|
|
105
105
|
assert "HEALTH[" in content
|
|
106
106
|
|
|
107
107
|
def test_refactor_section(self, sample_result, tmp_path):
|
|
108
|
-
"""REFACTOR section should
|
|
108
|
+
"""REFACTOR section should be present in analysis.toon with actionable steps."""
|
|
109
109
|
exporter = ToonExporter()
|
|
110
110
|
output_file = tmp_path / "test.toon"
|
|
111
111
|
exporter.export(sample_result, str(output_file))
|
|
112
112
|
|
|
113
113
|
content = output_file.read_text()
|
|
114
|
-
assert "REFACTOR["
|
|
114
|
+
assert "REFACTOR[" in content
|
|
115
115
|
|
|
116
116
|
def test_layers_section(self, sample_result, tmp_path):
|
|
117
117
|
"""Test LAYERS section shows package structure."""
|
|
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
|