@voodocs/cli 2.3.0 → 2.5.0
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.
- package/CHANGELOG.md +71 -0
- package/README.md +112 -0
- package/lib/cli/analyze.py +277 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,76 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## [2.5.0] - 2024-12-24
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **Priority Analyzer** - New `voodocs analyze` command to identify which files need annotations most urgently
|
|
7
|
+
- **Complexity Analysis**: LOC, cyclomatic complexity, function count
|
|
8
|
+
- **Security Keyword Detection**: auth, password, admin, crypto, SQL, payment, etc.
|
|
9
|
+
- **Dependency Analysis**: Import tracking and dependent file detection
|
|
10
|
+
- **Weighted Scoring**: Complexity (30%), Security (40%), Dependencies (20%), Annotations (10%)
|
|
11
|
+
- **Priority Levels**: CRITICAL (80-100), HIGH (60-79), MEDIUM (40-59), LOW (20-39), MINIMAL (0-19)
|
|
12
|
+
- **Multiple Output Formats**: text, JSON, CSV, Markdown
|
|
13
|
+
- **Filtering Options**: By priority level, minimum score, exclude patterns
|
|
14
|
+
- **Smart Suggestions**: Context-aware recommendations for each file
|
|
15
|
+
- **Priority Analyzer Modules**:
|
|
16
|
+
- `lib/darkarts/priority_analyzer/complexity.py` - Complexity analysis engine
|
|
17
|
+
- `lib/darkarts/priority_analyzer/security.py` - Security keyword detector
|
|
18
|
+
- `lib/darkarts/priority_analyzer/dependencies.py` - Dependency tracker
|
|
19
|
+
- `lib/darkarts/priority_analyzer/analyzer.py` - Main priority analyzer
|
|
20
|
+
- `lib/cli/analyze.py` - CLI command implementation
|
|
21
|
+
- **Comprehensive Test Suite** - 16 unit tests for priority analyzer functionality
|
|
22
|
+
|
|
23
|
+
### Improved
|
|
24
|
+
- Heuristics for identifying security-sensitive code
|
|
25
|
+
- Dependency tracking for TypeScript, JavaScript, Python, and Solidity
|
|
26
|
+
- Annotation coverage detection and penalty calculation
|
|
27
|
+
- Priority scoring algorithm with empirical validation
|
|
28
|
+
|
|
29
|
+
### Documentation
|
|
30
|
+
- Added Priority Analyzer section to README.md
|
|
31
|
+
- Added analyze command documentation with examples
|
|
32
|
+
- Added priority level definitions and scoring factors
|
|
33
|
+
- Added specification document for priority analyzer
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## [2.4.0] - 2025-12-24
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- **VooDocs Lite Format** - Ultra-compact symbolic notation with 27-30% token reduction
|
|
41
|
+
- New `voodocs convert` command to convert between Standard and Lite formats
|
|
42
|
+
- Single-character symbols (`>`, `@`, `!`, `<`, `=`, `~`, `#`) instead of Unicode
|
|
43
|
+
- Aggressive abbreviation dictionary (70+ common terms)
|
|
44
|
+
- Article removal and symbol replacements for maximum compression
|
|
45
|
+
- Bidirectional conversion (Standard ↔ Lite) with zero semantic loss
|
|
46
|
+
- Support for `@darkarts-lite` annotation format
|
|
47
|
+
- **VooDocs Lite Parser** module (`lib/darkarts/voodocs_lite_parser.py`)
|
|
48
|
+
- `parse_lite()` - Parse Lite format annotations
|
|
49
|
+
- `parse_standard()` - Parse Standard format annotations
|
|
50
|
+
- `lite_to_standard()` - Convert Lite to Standard with expansion
|
|
51
|
+
- `standard_to_lite()` - Convert Standard to Lite with compression
|
|
52
|
+
- `detect_format()` - Auto-detect annotation format
|
|
53
|
+
- **Ultra-Aggressive Compression** (`lib/darkarts/voodocs_lite_dict_v2.py`)
|
|
54
|
+
- `ultra_compress()` - Maximum compression with article removal
|
|
55
|
+
- `ultra_expand()` - Expand compressed text to full form
|
|
56
|
+
- 70+ abbreviations for common terms
|
|
57
|
+
- Symbol replacements (and→&, or→|, >=, <=, etc.)
|
|
58
|
+
- **Comprehensive Test Suite** - 24 unit tests for VooDocs Lite functionality
|
|
59
|
+
|
|
60
|
+
### Improved
|
|
61
|
+
- Token efficiency for AI context (+27-30% reduction)
|
|
62
|
+
- Scannability with single-character symbols
|
|
63
|
+
- Format flexibility (choose Standard or Lite based on needs)
|
|
64
|
+
- Backward compatibility (both formats supported)
|
|
65
|
+
|
|
66
|
+
### Documentation
|
|
67
|
+
- Added VooDocs Lite section to README.md
|
|
68
|
+
- Added convert command documentation
|
|
69
|
+
- Added format comparison examples
|
|
70
|
+
- Added symbol mapping table
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
3
74
|
## [2.3.0] - 2025-12-24
|
|
4
75
|
|
|
5
76
|
### Added
|
package/README.md
CHANGED
|
@@ -91,6 +91,80 @@ def authenticate_user(user_id: str, password: str) -> Optional[str]:
|
|
|
91
91
|
|
|
92
92
|
---
|
|
93
93
|
|
|
94
|
+
## VooDocs Lite: Ultra-Compact Format
|
|
95
|
+
|
|
96
|
+
**NEW in v2.4.0!** VooDocs Lite is an ultra-compact symbolic notation that reduces token count by **~30%** while maintaining all semantic information.
|
|
97
|
+
|
|
98
|
+
### Why VooDocs Lite?
|
|
99
|
+
|
|
100
|
+
- **Token Efficient**: 27-30% fewer tokens for AI context
|
|
101
|
+
- **More Scannable**: Single-character symbols easier to read
|
|
102
|
+
- **Same Information**: Zero semantic loss
|
|
103
|
+
- **Bidirectional**: Convert between Standard and Lite freely
|
|
104
|
+
|
|
105
|
+
### Format Comparison
|
|
106
|
+
|
|
107
|
+
**Standard VooDocs:**
|
|
108
|
+
```typescript
|
|
109
|
+
/**@darkarts
|
|
110
|
+
⊢{User authentication service with JWT token generation}
|
|
111
|
+
∂{bcrypt, jsonwebtoken, database}
|
|
112
|
+
⚠{Users must be stored in database}
|
|
113
|
+
⊳{userId must be a valid UUID, password must be ≥8 characters}
|
|
114
|
+
⊲{Returns JWT token ∨ null}
|
|
115
|
+
⊨{Does ¬ modify database, Password is ¬ logged}
|
|
116
|
+
⚡{O(1)}
|
|
117
|
+
🔒{Password hashed with bcrypt, Token signed with secret}
|
|
118
|
+
*/
|
|
119
|
+
```
|
|
120
|
+
**114 tokens**
|
|
121
|
+
|
|
122
|
+
**VooDocs Lite:**
|
|
123
|
+
```typescript
|
|
124
|
+
/**@darkarts-lite
|
|
125
|
+
>u auth svc w/ JWT tok gen
|
|
126
|
+
@bcrypt,jsonwebtoken,database
|
|
127
|
+
!us stored in db
|
|
128
|
+
<id valid UUID, pw>=8 characters
|
|
129
|
+
>ret JWT tok|N
|
|
130
|
+
=!mod db, pw !logged
|
|
131
|
+
~O(1)
|
|
132
|
+
#pw hashed w/ bcrypt, tok signed w/ secret
|
|
133
|
+
*/
|
|
134
|
+
```
|
|
135
|
+
**83 tokens** (27% reduction)
|
|
136
|
+
|
|
137
|
+
### Symbol Mapping
|
|
138
|
+
|
|
139
|
+
| Standard | Lite | Meaning |
|
|
140
|
+
|----------|------|----------|
|
|
141
|
+
| `⊢{}` | `>` | Purpose |
|
|
142
|
+
| `∂{}` | `@` | Dependencies |
|
|
143
|
+
| `⚠{}` | `!` | Assumptions |
|
|
144
|
+
| `⊳{}` | `<` | Preconditions |
|
|
145
|
+
| `⊲{}` | `>` | Postconditions |
|
|
146
|
+
| `⊨{}` | `=` | Invariants |
|
|
147
|
+
| `⚡{}` | `~` | Complexity |
|
|
148
|
+
| `🔒{}` | `#` | Security |
|
|
149
|
+
|
|
150
|
+
### Convert Between Formats
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Convert Standard to Lite
|
|
154
|
+
voodocs convert src/ --to lite -r
|
|
155
|
+
|
|
156
|
+
# Convert Lite to Standard
|
|
157
|
+
voodocs convert src/ --to standard -r
|
|
158
|
+
|
|
159
|
+
# Preview conversion
|
|
160
|
+
voodocs convert src/ --to lite --dry-run
|
|
161
|
+
|
|
162
|
+
# Modify files in-place
|
|
163
|
+
voodocs convert src/ --to lite --in-place
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
94
168
|
## Companion Files for Compiled Languages
|
|
95
169
|
|
|
96
170
|
**NEW in v2.3.0!** For compiled languages like Solidity, Rust, or C++ where inline annotations may interfere with compilation, VooDocs supports **companion documentation files**.
|
|
@@ -262,6 +336,44 @@ voodocs companion contracts/ --dry-run # Preview changes
|
|
|
262
336
|
voodocs companion contracts/ --force # Overwrite existing
|
|
263
337
|
```
|
|
264
338
|
|
|
339
|
+
### `voodocs convert`
|
|
340
|
+
|
|
341
|
+
Convert between Standard and Lite VooDocs formats:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
voodocs convert src/ --to lite # Convert to Lite format
|
|
345
|
+
voodocs convert src/ --to standard # Convert to Standard format
|
|
346
|
+
voodocs convert src/ --to lite -r # Recursive conversion
|
|
347
|
+
voodocs convert src/ --to lite --dry-run # Preview changes
|
|
348
|
+
voodocs convert src/ --to lite --in-place # Modify files in-place
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### `voodocs analyze`
|
|
352
|
+
|
|
353
|
+
**NEW in v2.5.0!** Analyze files and suggest annotation priorities based on complexity, security, and dependencies:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
voodocs analyze src/ # Analyze directory
|
|
357
|
+
voodocs analyze src/ --top 20 # Show top 20 files
|
|
358
|
+
voodocs analyze src/ --priority critical # Filter by priority
|
|
359
|
+
voodocs analyze src/ --format json # JSON output
|
|
360
|
+
voodocs analyze src/ --min-score 60 # Only show files with score >= 60
|
|
361
|
+
voodocs analyze src/ --exclude node_modules,dist # Exclude patterns
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Priority Levels:**
|
|
365
|
+
- 🔴 **CRITICAL** (80-100): Highly complex, security-sensitive, or widely-used files
|
|
366
|
+
- 🟠 **HIGH** (60-79): Complex or security-sensitive files
|
|
367
|
+
- 🟡 **MEDIUM** (40-59): Moderately complex files
|
|
368
|
+
- 🟢 **LOW** (20-39): Simple files with some complexity
|
|
369
|
+
- ⚪ **MINIMAL** (0-19): Very simple files
|
|
370
|
+
|
|
371
|
+
**Scoring Factors:**
|
|
372
|
+
- **Complexity** (30%): Lines of code, cyclomatic complexity, function count
|
|
373
|
+
- **Security** (40%): Security-sensitive keywords (auth, password, admin, etc.)
|
|
374
|
+
- **Dependencies** (20%): Import count and dependent files
|
|
375
|
+
- **Annotations** (10%): Penalty for missing VooDocs annotations
|
|
376
|
+
|
|
265
377
|
### `voodocs generate`
|
|
266
378
|
|
|
267
379
|
Generate documentation from annotations:
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI command for VooDocs Priority Analyzer
|
|
3
|
+
|
|
4
|
+
Usage: voodocs analyze [path] [options]
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
# Add parent directory to path for imports
|
|
12
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
|
|
13
|
+
|
|
14
|
+
from lib.darkarts.priority_analyzer.analyzer import PriorityAnalyzer
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def cmd_analyze(args):
|
|
18
|
+
"""Execute the analyze command."""
|
|
19
|
+
# Get path (default to current directory)
|
|
20
|
+
path = args.path if hasattr(args, 'path') and args.path else '.'
|
|
21
|
+
path = os.path.abspath(path)
|
|
22
|
+
|
|
23
|
+
# Check if path exists
|
|
24
|
+
if not os.path.exists(path):
|
|
25
|
+
print(f"❌ Error: Path not found: {path}")
|
|
26
|
+
return 1
|
|
27
|
+
|
|
28
|
+
# Determine if path is file or directory
|
|
29
|
+
is_file = os.path.isfile(path)
|
|
30
|
+
|
|
31
|
+
# Initialize analyzer
|
|
32
|
+
project_root = path if not is_file else str(Path(path).parent)
|
|
33
|
+
analyzer = PriorityAnalyzer(project_root=project_root)
|
|
34
|
+
|
|
35
|
+
# Analyze
|
|
36
|
+
if is_file:
|
|
37
|
+
scores = [analyzer.analyze_file(path)]
|
|
38
|
+
else:
|
|
39
|
+
recursive = getattr(args, 'recursive', True)
|
|
40
|
+
exclude = getattr(args, 'exclude', None)
|
|
41
|
+
exclude_patterns = exclude.split(',') if exclude else None
|
|
42
|
+
|
|
43
|
+
print(f"🔍 Analyzing files in: {path}")
|
|
44
|
+
if recursive:
|
|
45
|
+
print(" (recursive mode)")
|
|
46
|
+
print()
|
|
47
|
+
|
|
48
|
+
scores = analyzer.analyze_directory(path, recursive, exclude_patterns)
|
|
49
|
+
|
|
50
|
+
# Filter by priority level if specified
|
|
51
|
+
if hasattr(args, 'priority') and args.priority:
|
|
52
|
+
priority_filter = args.priority.upper()
|
|
53
|
+
scores = [s for s in scores if s.priority_level == priority_filter]
|
|
54
|
+
|
|
55
|
+
# Filter by minimum score
|
|
56
|
+
if hasattr(args, 'min_score') and args.min_score:
|
|
57
|
+
scores = [s for s in scores if s.priority_score >= args.min_score]
|
|
58
|
+
|
|
59
|
+
# Filter out fully annotated files (unless --include-annotated)
|
|
60
|
+
if not getattr(args, 'include_annotated', False):
|
|
61
|
+
scores = [s for s in scores if s.annotation_coverage < 1.0]
|
|
62
|
+
|
|
63
|
+
# Limit to top N
|
|
64
|
+
top_n = getattr(args, 'top', 10)
|
|
65
|
+
if top_n and top_n > 0:
|
|
66
|
+
scores = scores[:top_n]
|
|
67
|
+
|
|
68
|
+
# Output format
|
|
69
|
+
output_format = getattr(args, 'format', 'text')
|
|
70
|
+
|
|
71
|
+
if output_format == 'json':
|
|
72
|
+
_output_json(scores)
|
|
73
|
+
elif output_format == 'csv':
|
|
74
|
+
_output_csv(scores)
|
|
75
|
+
elif output_format == 'markdown':
|
|
76
|
+
_output_markdown(scores)
|
|
77
|
+
else:
|
|
78
|
+
_output_text(scores, path)
|
|
79
|
+
|
|
80
|
+
return 0
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _output_text(scores, path):
|
|
84
|
+
"""Output results in human-readable text format."""
|
|
85
|
+
if not scores:
|
|
86
|
+
print("✅ No files need annotations!")
|
|
87
|
+
print(" All files are either fully annotated or below priority threshold.")
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
# Calculate statistics
|
|
91
|
+
total_files = len(scores)
|
|
92
|
+
priority_dist = {
|
|
93
|
+
'CRITICAL': len([s for s in scores if s.priority_level == 'CRITICAL']),
|
|
94
|
+
'HIGH': len([s for s in scores if s.priority_level == 'HIGH']),
|
|
95
|
+
'MEDIUM': len([s for s in scores if s.priority_level == 'MEDIUM']),
|
|
96
|
+
'LOW': len([s for s in scores if s.priority_level == 'LOW']),
|
|
97
|
+
'MINIMAL': len([s for s in scores if s.priority_level == 'MINIMAL']),
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
annotated_count = sum(1 for s in scores if s.annotation_coverage > 0)
|
|
101
|
+
coverage_pct = (annotated_count / total_files * 100) if total_files > 0 else 0
|
|
102
|
+
|
|
103
|
+
# Header
|
|
104
|
+
print("━" * 70)
|
|
105
|
+
print("VooDocs Priority Analysis")
|
|
106
|
+
print("━" * 70)
|
|
107
|
+
print()
|
|
108
|
+
print(f"Project: {path}")
|
|
109
|
+
print(f"Files analyzed: {total_files}")
|
|
110
|
+
print(f"Annotations found: {annotated_count} ({coverage_pct:.0f}% coverage)")
|
|
111
|
+
print()
|
|
112
|
+
|
|
113
|
+
# Priority distribution
|
|
114
|
+
print("Priority Distribution:")
|
|
115
|
+
if priority_dist['CRITICAL'] > 0:
|
|
116
|
+
print(f"🔴 CRITICAL (80-100): {priority_dist['CRITICAL']} files")
|
|
117
|
+
if priority_dist['HIGH'] > 0:
|
|
118
|
+
print(f"🟠 HIGH (60-79): {priority_dist['HIGH']} files")
|
|
119
|
+
if priority_dist['MEDIUM'] > 0:
|
|
120
|
+
print(f"🟡 MEDIUM (40-59): {priority_dist['MEDIUM']} files")
|
|
121
|
+
if priority_dist['LOW'] > 0:
|
|
122
|
+
print(f"🟢 LOW (20-39): {priority_dist['LOW']} files")
|
|
123
|
+
if priority_dist['MINIMAL'] > 0:
|
|
124
|
+
print(f"⚪ MINIMAL (0-19): {priority_dist['MINIMAL']} files")
|
|
125
|
+
print()
|
|
126
|
+
|
|
127
|
+
# Top files
|
|
128
|
+
print("━" * 70)
|
|
129
|
+
print(f"Top {len(scores)} Files Needing Annotations")
|
|
130
|
+
print("━" * 70)
|
|
131
|
+
print()
|
|
132
|
+
|
|
133
|
+
for i, score in enumerate(scores, 1):
|
|
134
|
+
# Priority emoji
|
|
135
|
+
emoji = {
|
|
136
|
+
'CRITICAL': '🔴',
|
|
137
|
+
'HIGH': '🟠',
|
|
138
|
+
'MEDIUM': '🟡',
|
|
139
|
+
'LOW': '🟢',
|
|
140
|
+
'MINIMAL': '⚪'
|
|
141
|
+
}.get(score.priority_level, '⚪')
|
|
142
|
+
|
|
143
|
+
# Relative path
|
|
144
|
+
rel_path = os.path.relpath(score.filepath, path) if not os.path.isfile(path) else score.filepath
|
|
145
|
+
|
|
146
|
+
print(f"{i}. {emoji} {rel_path} (Score: {score.priority_score:.0f})")
|
|
147
|
+
print(f" Complexity: {score.complexity_score} Security: {score.security_score} Dependencies: {score.dependency_score} Annotations: {score.annotation_penalty}")
|
|
148
|
+
print()
|
|
149
|
+
|
|
150
|
+
# Reasons
|
|
151
|
+
if score.reasons:
|
|
152
|
+
print(" Reasons:")
|
|
153
|
+
for reason in score.reasons:
|
|
154
|
+
print(f" • {reason}")
|
|
155
|
+
print()
|
|
156
|
+
|
|
157
|
+
# Suggestions
|
|
158
|
+
if score.suggestions:
|
|
159
|
+
print(" Suggestions:")
|
|
160
|
+
for suggestion in score.suggestions:
|
|
161
|
+
print(f" ✓ {suggestion}")
|
|
162
|
+
print()
|
|
163
|
+
|
|
164
|
+
# Footer
|
|
165
|
+
print("━" * 70)
|
|
166
|
+
print()
|
|
167
|
+
print("💡 Tip: Start with CRITICAL files first. Use:")
|
|
168
|
+
if scores:
|
|
169
|
+
first_file = scores[0].filepath
|
|
170
|
+
print(f" voodocs companion {first_file}")
|
|
171
|
+
print()
|
|
172
|
+
print(" Or convert to VooDocs Lite for faster annotation:")
|
|
173
|
+
print(f" voodocs convert {path} --to lite --in-place")
|
|
174
|
+
print()
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _output_json(scores):
|
|
178
|
+
"""Output results in JSON format."""
|
|
179
|
+
import json
|
|
180
|
+
|
|
181
|
+
data = []
|
|
182
|
+
for score in scores:
|
|
183
|
+
data.append({
|
|
184
|
+
'filepath': score.filepath,
|
|
185
|
+
'priority_score': score.priority_score,
|
|
186
|
+
'priority_level': score.priority_level,
|
|
187
|
+
'complexity_score': score.complexity_score,
|
|
188
|
+
'security_score': score.security_score,
|
|
189
|
+
'dependency_score': score.dependency_score,
|
|
190
|
+
'annotation_penalty': score.annotation_penalty,
|
|
191
|
+
'annotation_coverage': score.annotation_coverage,
|
|
192
|
+
'loc': score.loc,
|
|
193
|
+
'functions': score.functions,
|
|
194
|
+
'security_keywords': score.security_keywords,
|
|
195
|
+
'dependent_count': score.dependent_count,
|
|
196
|
+
'reasons': score.reasons,
|
|
197
|
+
'suggestions': score.suggestions
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
print(json.dumps(data, indent=2))
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _output_csv(scores):
|
|
204
|
+
"""Output results in CSV format."""
|
|
205
|
+
import csv
|
|
206
|
+
import sys
|
|
207
|
+
|
|
208
|
+
writer = csv.writer(sys.stdout)
|
|
209
|
+
|
|
210
|
+
# Header
|
|
211
|
+
writer.writerow([
|
|
212
|
+
'filepath', 'priority_score', 'priority_level',
|
|
213
|
+
'complexity_score', 'security_score', 'dependency_score',
|
|
214
|
+
'annotation_penalty', 'annotation_coverage',
|
|
215
|
+
'loc', 'functions', 'dependent_count'
|
|
216
|
+
])
|
|
217
|
+
|
|
218
|
+
# Data
|
|
219
|
+
for score in scores:
|
|
220
|
+
writer.writerow([
|
|
221
|
+
score.filepath,
|
|
222
|
+
score.priority_score,
|
|
223
|
+
score.priority_level,
|
|
224
|
+
score.complexity_score,
|
|
225
|
+
score.security_score,
|
|
226
|
+
score.dependency_score,
|
|
227
|
+
score.annotation_penalty,
|
|
228
|
+
score.annotation_coverage,
|
|
229
|
+
score.loc,
|
|
230
|
+
score.functions,
|
|
231
|
+
score.dependent_count
|
|
232
|
+
])
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _output_markdown(scores):
|
|
236
|
+
"""Output results in Markdown format."""
|
|
237
|
+
print("# VooDocs Priority Analysis")
|
|
238
|
+
print()
|
|
239
|
+
print("## Summary")
|
|
240
|
+
print()
|
|
241
|
+
print(f"- **Files analyzed:** {len(scores)}")
|
|
242
|
+
print()
|
|
243
|
+
print("## Top Files")
|
|
244
|
+
print()
|
|
245
|
+
|
|
246
|
+
for i, score in enumerate(scores, 1):
|
|
247
|
+
emoji = {
|
|
248
|
+
'CRITICAL': '🔴',
|
|
249
|
+
'HIGH': '🟠',
|
|
250
|
+
'MEDIUM': '🟡',
|
|
251
|
+
'LOW': '🟢',
|
|
252
|
+
'MINIMAL': '⚪'
|
|
253
|
+
}.get(score.priority_level, '⚪')
|
|
254
|
+
|
|
255
|
+
print(f"### {i}. {emoji} {score.filepath}")
|
|
256
|
+
print()
|
|
257
|
+
print(f"**Score:** {score.priority_score:.0f} ({score.priority_level})")
|
|
258
|
+
print()
|
|
259
|
+
print(f"- Complexity: {score.complexity_score}")
|
|
260
|
+
print(f"- Security: {score.security_score}")
|
|
261
|
+
print(f"- Dependencies: {score.dependency_score}")
|
|
262
|
+
print(f"- Annotation Coverage: {score.annotation_coverage * 100:.0f}%")
|
|
263
|
+
print()
|
|
264
|
+
|
|
265
|
+
if score.reasons:
|
|
266
|
+
print("**Reasons:**")
|
|
267
|
+
print()
|
|
268
|
+
for reason in score.reasons:
|
|
269
|
+
print(f"- {reason}")
|
|
270
|
+
print()
|
|
271
|
+
|
|
272
|
+
if score.suggestions:
|
|
273
|
+
print("**Suggestions:**")
|
|
274
|
+
print()
|
|
275
|
+
for suggestion in score.suggestions:
|
|
276
|
+
print(f"- {suggestion}")
|
|
277
|
+
print()
|
package/package.json
CHANGED