@voodocs/cli 2.2.3 → 2.4.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 +113 -1693
- package/README.md +178 -0
- package/USAGE.md +138 -2
- package/lib/cli/companion.py +137 -0
- package/lib/cli/generate.py +53 -3
- package/lib/darkarts/companion_files.py +299 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -91,6 +91,160 @@ 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
|
+
|
|
168
|
+
## Companion Files for Compiled Languages
|
|
169
|
+
|
|
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**.
|
|
171
|
+
|
|
172
|
+
### What are Companion Files?
|
|
173
|
+
|
|
174
|
+
Companion files are `.voodocs.md` files that live alongside your source files, containing rich documentation without modifying the source code.
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
contracts/
|
|
178
|
+
├── SubdomainRegistry.sol ← Source code
|
|
179
|
+
├── SubdomainRegistry.voodocs.md ← Companion documentation
|
|
180
|
+
├── DomainMarketplace.sol ← Source code
|
|
181
|
+
├── DomainMarketplace.voodocs.md ← Companion documentation
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Creating Companion Files
|
|
185
|
+
|
|
186
|
+
Use the `companion` command to generate templates:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Create companion file for a single file
|
|
190
|
+
voodocs companion contracts/Registry.sol
|
|
191
|
+
|
|
192
|
+
# Create companion files for all Solidity files
|
|
193
|
+
voodocs companion contracts/ -r
|
|
194
|
+
|
|
195
|
+
# Preview what would be created
|
|
196
|
+
voodocs companion contracts/ -r --dry-run
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Companion File Format
|
|
200
|
+
|
|
201
|
+
Companion files use Markdown with VooDocs symbolic notation:
|
|
202
|
+
|
|
203
|
+
```markdown
|
|
204
|
+
# SubdomainRegistry.voodocs.md
|
|
205
|
+
|
|
206
|
+
## Purpose
|
|
207
|
+
⊢{4-level naming hierarchy with tiered subdomain allocation}
|
|
208
|
+
|
|
209
|
+
## Architecture
|
|
210
|
+
- **Depends On**: IPricingEngine, IERC721
|
|
211
|
+
- **Depended By**: ThreeNSFacet, DomainMarketplace
|
|
212
|
+
- **Storage**: PostgreSQL (cache), L1 (source of truth)
|
|
213
|
+
|
|
214
|
+
## Invariants
|
|
215
|
+
⊨{L1 is always the source of truth}
|
|
216
|
+
⊨{Personal names destroyed on subdomain transfer}
|
|
217
|
+
⊨{resolve() must check expiration before returning owner}
|
|
218
|
+
|
|
219
|
+
## Assumptions
|
|
220
|
+
⊲{Block timestamp is reliable for expiration checks}
|
|
221
|
+
⊲{Gas costs are acceptable for array operations}
|
|
222
|
+
|
|
223
|
+
## Critical Sections
|
|
224
|
+
- `_burnPersonalNames()` - Must be called before any transfer
|
|
225
|
+
- `resolve()` - Must check expiration before returning owner
|
|
226
|
+
|
|
227
|
+
## Security Considerations
|
|
228
|
+
⊨{Reentrancy protection on all external calls}
|
|
229
|
+
⊨{Owner validation before subdomain operations}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Generating Documentation with Companion Files
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
voodocs generate contracts/ docs/ --companion-files
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Benefits
|
|
239
|
+
|
|
240
|
+
✅ **No Compilation Issues** - Documentation lives in separate files
|
|
241
|
+
✅ **Rich Markdown** - Use tables, diagrams, code examples, links
|
|
242
|
+
✅ **Version Control** - Track documentation changes alongside code
|
|
243
|
+
✅ **IDE Friendly** - View source and docs side-by-side
|
|
244
|
+
✅ **AI-Ready** - Same context quality as inline annotations
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
94
248
|
## Symbolic Format Reference
|
|
95
249
|
|
|
96
250
|
### Module-Level Annotations
|
|
@@ -171,6 +325,29 @@ voodocs fix ./src --dry-run # Preview changes
|
|
|
171
325
|
voodocs fix ./src --backup # Create backups
|
|
172
326
|
```
|
|
173
327
|
|
|
328
|
+
### `voodocs companion`
|
|
329
|
+
|
|
330
|
+
Create companion documentation files for source files:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
voodocs companion contracts/ # Create for single file
|
|
334
|
+
voodocs companion contracts/ -r # Recursive
|
|
335
|
+
voodocs companion contracts/ --dry-run # Preview changes
|
|
336
|
+
voodocs companion contracts/ --force # Overwrite existing
|
|
337
|
+
```
|
|
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
|
+
|
|
174
351
|
### `voodocs generate`
|
|
175
352
|
|
|
176
353
|
Generate documentation from annotations:
|
|
@@ -179,6 +356,7 @@ Generate documentation from annotations:
|
|
|
179
356
|
voodocs generate ./src ./docs # Generate docs
|
|
180
357
|
voodocs generate ./src ./docs -r # Recursive
|
|
181
358
|
voodocs generate ./src ./docs --validate # Validate first
|
|
359
|
+
voodocs generate ./src ./docs --companion-files # Use companion files
|
|
182
360
|
voodocs generate ./src ./docs --format json # JSON output
|
|
183
361
|
```
|
|
184
362
|
|
package/USAGE.md
CHANGED
|
@@ -13,6 +13,7 @@ This guide provides a comprehensive overview of VooDocs, its commands, and best
|
|
|
13
13
|
- [CLI Commands](#cli-commands)
|
|
14
14
|
- [init](#init)
|
|
15
15
|
- [instruct](#instruct)
|
|
16
|
+
- [companion](#companion)
|
|
16
17
|
- [generate](#generate)
|
|
17
18
|
- [status](#status)
|
|
18
19
|
- [watch](#watch)
|
|
@@ -98,13 +99,81 @@ voodocs instruct [--assistant <name>] [--output <file>]
|
|
|
98
99
|
- `--assistant`: The AI assistant to generate instructions for (`cursor`, `claude`, `copilot`, `windsurf`, `generic`).
|
|
99
100
|
- `--output`: The output file path (defaults to `.cursorrules`, `.claude/instructions.md`, etc.).
|
|
100
101
|
|
|
102
|
+
### `companion`
|
|
103
|
+
|
|
104
|
+
**NEW in v2.3.0!** Create companion documentation files (`.voodocs.md`) for source files. Useful for compiled languages like Solidity, Rust, or C++ where inline annotations may interfere with compilation.
|
|
105
|
+
|
|
106
|
+
**Usage**:
|
|
107
|
+
```bash
|
|
108
|
+
voodocs companion <source> [options]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Arguments**:
|
|
112
|
+
- `<source>`: Source file or directory to create companion files for.
|
|
113
|
+
|
|
114
|
+
**Options**:
|
|
115
|
+
- `-r, --recursive`: Recursively process all files in subdirectories.
|
|
116
|
+
- `--force`: Overwrite existing companion files.
|
|
117
|
+
- `--dry-run`: Show what would be created without creating files.
|
|
118
|
+
|
|
119
|
+
**Examples**:
|
|
120
|
+
```bash
|
|
121
|
+
# Create companion file for a single Solidity contract
|
|
122
|
+
voodocs companion contracts/Registry.sol
|
|
123
|
+
|
|
124
|
+
# Create companion files for all Solidity contracts
|
|
125
|
+
voodocs companion contracts/ -r
|
|
126
|
+
|
|
127
|
+
# Preview what would be created
|
|
128
|
+
voodocs companion contracts/ -r --dry-run
|
|
129
|
+
|
|
130
|
+
# Force overwrite existing companion files
|
|
131
|
+
voodocs companion contracts/ -r --force
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Companion File Format**:
|
|
135
|
+
|
|
136
|
+
Companion files use Markdown with structured sections:
|
|
137
|
+
|
|
138
|
+
```markdown
|
|
139
|
+
# FileName.voodocs.md
|
|
140
|
+
|
|
141
|
+
## Purpose
|
|
142
|
+
⊢{Module purpose description}
|
|
143
|
+
|
|
144
|
+
## Architecture
|
|
145
|
+
- **Depends On**: Dependency1, Dependency2
|
|
146
|
+
- **Depended By**: Parent1, Parent2
|
|
147
|
+
- **Storage**: Storage information
|
|
148
|
+
|
|
149
|
+
## Invariants
|
|
150
|
+
⊨{Invariant 1}
|
|
151
|
+
⊨{Invariant 2}
|
|
152
|
+
|
|
153
|
+
## Assumptions
|
|
154
|
+
⊲{Assumption 1}
|
|
155
|
+
|
|
156
|
+
## Critical Sections
|
|
157
|
+
- `functionName()` - Description
|
|
158
|
+
|
|
159
|
+
## Security Considerations
|
|
160
|
+
⊨{Security requirement}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Benefits**:
|
|
164
|
+
- ✅ No compilation interference
|
|
165
|
+
- ✅ Rich Markdown formatting (tables, diagrams, links)
|
|
166
|
+
- ✅ Version control alongside source files
|
|
167
|
+
- ✅ IDE-friendly (side-by-side viewing)
|
|
168
|
+
- ✅ Same AI context quality as inline annotations
|
|
169
|
+
|
|
101
170
|
### `generate`
|
|
102
171
|
|
|
103
172
|
Generate docs, tests, and API specs from annotations.
|
|
104
173
|
|
|
105
174
|
**Usage**:
|
|
106
175
|
```bash
|
|
107
|
-
voodocs generate <path> [--output <dir>] [--docs-only] [--tests-only] [--api-only] [--verbose]
|
|
176
|
+
voodocs generate <path> [--output <dir>] [--docs-only] [--tests-only] [--api-only] [--companion-files] [--verbose]
|
|
108
177
|
```
|
|
109
178
|
|
|
110
179
|
**Arguments**:
|
|
@@ -113,8 +182,21 @@ voodocs generate <path> [--output <dir>] [--docs-only] [--tests-only] [--api-onl
|
|
|
113
182
|
- `--docs-only`: Generate only documentation.
|
|
114
183
|
- `--tests-only`: Generate only tests.
|
|
115
184
|
- `--api-only`: Generate only API specs.
|
|
185
|
+
- `--companion-files`: **NEW in v2.3.0!** Scan for and use `.voodocs.md` companion files alongside source files.
|
|
116
186
|
- `--verbose`: Show detailed output.
|
|
117
187
|
|
|
188
|
+
**Examples**:
|
|
189
|
+
```bash
|
|
190
|
+
# Generate documentation from inline annotations
|
|
191
|
+
voodocs generate src/ docs/
|
|
192
|
+
|
|
193
|
+
# Generate documentation using companion files (for Solidity, Rust, etc.)
|
|
194
|
+
voodocs generate contracts/ docs/ --companion-files
|
|
195
|
+
|
|
196
|
+
# Generate with validation
|
|
197
|
+
voodocs generate src/ docs/ --validate
|
|
198
|
+
```
|
|
199
|
+
|
|
118
200
|
### `status`
|
|
119
201
|
|
|
120
202
|
Show project status and statistics.
|
|
@@ -318,7 +400,61 @@ class BankAccount:
|
|
|
318
400
|
self.balance += amount
|
|
319
401
|
```
|
|
320
402
|
|
|
321
|
-
|
|
403
|
+
### Solidity Contract with Companion File
|
|
404
|
+
|
|
405
|
+
**NEW in v2.3.0!** For compiled languages, use companion files:
|
|
406
|
+
|
|
407
|
+
**contracts/SubdomainRegistry.sol**:
|
|
408
|
+
```solidity
|
|
409
|
+
// SPDX-License-Identifier: MIT
|
|
410
|
+
pragma solidity ^0.8.0;
|
|
411
|
+
|
|
412
|
+
contract SubdomainRegistry {
|
|
413
|
+
mapping(uint256 => address) public owners;
|
|
414
|
+
mapping(uint256 => uint256) public expirations;
|
|
415
|
+
|
|
416
|
+
function register(uint256 nameId, address owner, uint256 duration) public {
|
|
417
|
+
require(owners[nameId] == address(0), "Already registered");
|
|
418
|
+
owners[nameId] = owner;
|
|
419
|
+
expirations[nameId] = block.timestamp + duration;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function resolve(uint256 nameId) public view returns (address) {
|
|
423
|
+
require(block.timestamp < expirations[nameId], "Expired");
|
|
424
|
+
return owners[nameId];
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**contracts/SubdomainRegistry.voodocs.md**:
|
|
430
|
+
```markdown
|
|
431
|
+
# SubdomainRegistry.voodocs.md
|
|
432
|
+
|
|
433
|
+
## Purpose
|
|
434
|
+
⊢{Subdomain registry with expiration management}
|
|
435
|
+
|
|
436
|
+
## Invariants
|
|
437
|
+
⊨{Only one owner per subdomain}
|
|
438
|
+
⊨{resolve() must check expiration before returning owner}
|
|
439
|
+
⊨{Expired subdomains cannot be resolved}
|
|
440
|
+
|
|
441
|
+
## Assumptions
|
|
442
|
+
⊲{Block timestamp is reliable for expiration checks}
|
|
443
|
+
⊲{nameId is unique and generated off-chain}
|
|
444
|
+
|
|
445
|
+
## Security Considerations
|
|
446
|
+
⊨{Owner validation before subdomain operations}
|
|
447
|
+
⊨{Zero address checks for all owner parameters}
|
|
448
|
+
⊨{Expiration checks prevent stale data}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**Generate documentation**:
|
|
452
|
+
```bash
|
|
453
|
+
voodocs companion contracts/ -r
|
|
454
|
+
voodocs generate contracts/ docs/ --companion-files
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
See the `examples/` directory for more complete examples in Python, TypeScript, and Solidity.
|
|
322
458
|
|
|
323
459
|
---
|
|
324
460
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
⊢cli:companion
|
|
3
|
+
∂{click,pathlib,typing}
|
|
4
|
+
⚠{python≥3.7,click≥8.0}
|
|
5
|
+
⊨{∀template→valid_markdown}
|
|
6
|
+
🔒{write:files}
|
|
7
|
+
⚡{O(n)|n=files}
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
VooDocs CLI - Companion Command
|
|
12
|
+
|
|
13
|
+
Creates .voodocs.md companion files for source files.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import sys
|
|
17
|
+
import click
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import List
|
|
20
|
+
|
|
21
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
22
|
+
from darkarts.companion_files import CompanionFileScanner
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@click.command()
|
|
26
|
+
@click.argument('source', type=click.Path(exists=True), required=True)
|
|
27
|
+
@click.option('-r', '--recursive', is_flag=True, help='Recursively process all files')
|
|
28
|
+
@click.option('--force', is_flag=True, help='Overwrite existing companion files')
|
|
29
|
+
@click.option('--dry-run', is_flag=True, help='Show what would be created without creating files')
|
|
30
|
+
def companion(
|
|
31
|
+
source: str,
|
|
32
|
+
recursive: bool,
|
|
33
|
+
force: bool,
|
|
34
|
+
dry_run: bool
|
|
35
|
+
):
|
|
36
|
+
"""
|
|
37
|
+
Create .voodocs.md companion files for source files.
|
|
38
|
+
|
|
39
|
+
Companion files allow you to add rich documentation alongside source files
|
|
40
|
+
without modifying the source code. This is especially useful for compiled
|
|
41
|
+
languages like Solidity where inline annotations may interfere with compilation.
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
|
|
45
|
+
# Create companion file for a single file
|
|
46
|
+
voodocs companion contracts/Registry.sol
|
|
47
|
+
|
|
48
|
+
# Create companion files for all Solidity files
|
|
49
|
+
voodocs companion contracts/ -r
|
|
50
|
+
|
|
51
|
+
# Preview what would be created
|
|
52
|
+
voodocs companion contracts/ -r --dry-run
|
|
53
|
+
|
|
54
|
+
# Overwrite existing companion files
|
|
55
|
+
voodocs companion contracts/ -r --force
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
source_path = Path(source)
|
|
59
|
+
|
|
60
|
+
# Collect source files
|
|
61
|
+
files_to_process: List[Path] = []
|
|
62
|
+
|
|
63
|
+
if source_path.is_file():
|
|
64
|
+
files_to_process = [source_path]
|
|
65
|
+
elif source_path.is_dir():
|
|
66
|
+
extensions = ['*.py', '*.ts', '*.js', '*.jsx', '*.tsx', '*.sol']
|
|
67
|
+
|
|
68
|
+
if recursive:
|
|
69
|
+
for ext in extensions:
|
|
70
|
+
files_to_process.extend([f for f in source_path.glob(f"**/{ext}") if f.is_file()])
|
|
71
|
+
else:
|
|
72
|
+
for ext in extensions:
|
|
73
|
+
files_to_process.extend([f for f in source_path.glob(ext) if f.is_file()])
|
|
74
|
+
|
|
75
|
+
if not files_to_process:
|
|
76
|
+
click.secho("No source files found.", fg='yellow')
|
|
77
|
+
sys.exit(1)
|
|
78
|
+
|
|
79
|
+
click.echo(f"Found {len(files_to_process)} source file(s)")
|
|
80
|
+
click.echo()
|
|
81
|
+
|
|
82
|
+
if dry_run:
|
|
83
|
+
click.secho("DRY RUN MODE - No files will be created", fg='cyan')
|
|
84
|
+
click.echo()
|
|
85
|
+
|
|
86
|
+
created_count = 0
|
|
87
|
+
skipped_count = 0
|
|
88
|
+
|
|
89
|
+
for file_path in files_to_process:
|
|
90
|
+
companion_path = file_path.parent / f"{file_path.stem}{CompanionFileScanner.COMPANION_EXTENSION}"
|
|
91
|
+
|
|
92
|
+
if companion_path.exists() and not force:
|
|
93
|
+
click.echo(f"⏭️ {file_path.name} (companion already exists)")
|
|
94
|
+
skipped_count += 1
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
if dry_run:
|
|
98
|
+
if companion_path.exists():
|
|
99
|
+
click.echo(f"🔄 {file_path.name} → {companion_path.name} (would overwrite)")
|
|
100
|
+
else:
|
|
101
|
+
click.echo(f"✨ {file_path.name} → {companion_path.name} (would create)")
|
|
102
|
+
created_count += 1
|
|
103
|
+
else:
|
|
104
|
+
template = CompanionFileScanner.create_template(file_path)
|
|
105
|
+
companion_path.write_text(template, encoding='utf-8')
|
|
106
|
+
|
|
107
|
+
if force and companion_path.exists():
|
|
108
|
+
click.echo(f"🔄 {file_path.name} → {companion_path.name} (overwritten)")
|
|
109
|
+
else:
|
|
110
|
+
click.echo(f"✨ {file_path.name} → {companion_path.name}")
|
|
111
|
+
|
|
112
|
+
created_count += 1
|
|
113
|
+
|
|
114
|
+
click.echo()
|
|
115
|
+
click.echo("━" * 60)
|
|
116
|
+
|
|
117
|
+
if dry_run:
|
|
118
|
+
click.echo(f"Would create: {created_count}")
|
|
119
|
+
click.echo(f"Would skip: {skipped_count}")
|
|
120
|
+
else:
|
|
121
|
+
click.secho(f"Created: {created_count}", fg='green')
|
|
122
|
+
click.echo(f"Skipped: {skipped_count}")
|
|
123
|
+
|
|
124
|
+
click.echo("━" * 60)
|
|
125
|
+
|
|
126
|
+
if not dry_run and created_count > 0:
|
|
127
|
+
click.echo()
|
|
128
|
+
click.secho("✅ Companion files created!", fg='green')
|
|
129
|
+
click.echo()
|
|
130
|
+
click.echo("Next steps:")
|
|
131
|
+
click.echo(" 1. Edit the .voodocs.md files to add documentation")
|
|
132
|
+
click.echo(" 2. Run: voodocs generate --companion-files")
|
|
133
|
+
click.echo()
|
|
134
|
+
click.echo("Tip: Companion files support:")
|
|
135
|
+
click.echo(" • Rich Markdown formatting (tables, diagrams, links)")
|
|
136
|
+
click.echo(" • VooDocs symbolic notation (⊢{}, ⊨{}, ⊲{})")
|
|
137
|
+
click.echo(" • Version control alongside source files")
|
package/lib/cli/generate.py
CHANGED
|
@@ -33,6 +33,7 @@ from darkarts.validation.performance_wrapper import PerformanceTracker
|
|
|
33
33
|
@click.option('--strict', is_flag=True, help='Fail if validation fails')
|
|
34
34
|
@click.option('--format', type=click.Choice(['markdown', 'html', 'json']), default='markdown', help='Output format')
|
|
35
35
|
@click.option('--include-private', is_flag=True, help='Include private members in documentation')
|
|
36
|
+
@click.option('--companion-files', is_flag=True, help='Scan for .voodocs.md companion files alongside source files')
|
|
36
37
|
def generate(
|
|
37
38
|
source: str,
|
|
38
39
|
output: str,
|
|
@@ -40,7 +41,8 @@ def generate(
|
|
|
40
41
|
validate: bool,
|
|
41
42
|
strict: bool,
|
|
42
43
|
format: str,
|
|
43
|
-
include_private: bool
|
|
44
|
+
include_private: bool,
|
|
45
|
+
companion_files: bool
|
|
44
46
|
):
|
|
45
47
|
"""
|
|
46
48
|
Generate documentation from @darkarts annotations.
|
|
@@ -132,6 +134,29 @@ def generate(
|
|
|
132
134
|
|
|
133
135
|
click.echo(f"Found {len(files_to_process)} files to process")
|
|
134
136
|
|
|
137
|
+
# Scan for companion files if requested
|
|
138
|
+
companion_mapping = {}
|
|
139
|
+
if companion_files:
|
|
140
|
+
click.echo()
|
|
141
|
+
click.secho("Scanning for companion files (.voodocs.md)...", fg='cyan')
|
|
142
|
+
from darkarts.companion_files import CompanionFileScanner
|
|
143
|
+
|
|
144
|
+
companion_count = 0
|
|
145
|
+
for file_path in files_to_process:
|
|
146
|
+
companion = CompanionFileScanner.find_companion_file(file_path)
|
|
147
|
+
if companion:
|
|
148
|
+
companion_mapping[file_path] = companion
|
|
149
|
+
companion_count += 1
|
|
150
|
+
click.echo(f" 📄 {file_path.name} → {companion.name}")
|
|
151
|
+
|
|
152
|
+
click.echo()
|
|
153
|
+
if companion_count > 0:
|
|
154
|
+
click.secho(f"✅ Found {companion_count} companion file(s)", fg='green')
|
|
155
|
+
else:
|
|
156
|
+
click.secho("⚠️ No companion files found", fg='yellow')
|
|
157
|
+
click.echo(" Tip: Create .voodocs.md files alongside your source files")
|
|
158
|
+
click.echo(" Example: contracts/Registry.sol → contracts/Registry.voodocs.md")
|
|
159
|
+
|
|
135
160
|
# Validate if requested
|
|
136
161
|
if validate:
|
|
137
162
|
click.echo()
|
|
@@ -179,8 +204,14 @@ def generate(
|
|
|
179
204
|
generated_files = []
|
|
180
205
|
for file_path in files_to_process:
|
|
181
206
|
try:
|
|
207
|
+
# Parse companion file if available
|
|
208
|
+
companion_data = None
|
|
209
|
+
if companion_files and file_path in companion_mapping:
|
|
210
|
+
from darkarts.companion_files import CompanionFileScanner
|
|
211
|
+
companion_data = CompanionFileScanner.parse_companion_file(companion_mapping[file_path])
|
|
212
|
+
|
|
182
213
|
# Generate documentation for this file
|
|
183
|
-
doc_content = _generate_doc_for_file(file_path, format, include_private)
|
|
214
|
+
doc_content = _generate_doc_for_file(file_path, format, include_private, companion_data)
|
|
184
215
|
|
|
185
216
|
# Determine output filename
|
|
186
217
|
if source_path.is_dir():
|
|
@@ -291,7 +322,7 @@ def generate(
|
|
|
291
322
|
sys.exit(1)
|
|
292
323
|
|
|
293
324
|
|
|
294
|
-
def _generate_doc_for_file(file_path: Path, format: str, include_private: bool) -> str:
|
|
325
|
+
def _generate_doc_for_file(file_path: Path, format: str, include_private: bool, companion_data: dict = None) -> str:
|
|
295
326
|
"""Generate documentation for a single file."""
|
|
296
327
|
content = file_path.read_text(encoding='utf-8')
|
|
297
328
|
|
|
@@ -309,6 +340,25 @@ def _generate_doc_for_file(file_path: Path, format: str, include_private: bool)
|
|
|
309
340
|
security = _extract_section(annotation, '🔒')
|
|
310
341
|
performance = _extract_section(annotation, '⚡')
|
|
311
342
|
|
|
343
|
+
# Merge with companion file data if available
|
|
344
|
+
if companion_data:
|
|
345
|
+
if companion_data.get('purpose'):
|
|
346
|
+
module_id = companion_data['purpose']
|
|
347
|
+
if companion_data.get('dependencies'):
|
|
348
|
+
dependencies = ', '.join(companion_data['dependencies'])
|
|
349
|
+
if companion_data.get('invariants'):
|
|
350
|
+
inv_list = invariants.split('\n') if invariants else []
|
|
351
|
+
inv_list.extend(companion_data['invariants'])
|
|
352
|
+
invariants = '\n'.join(filter(None, inv_list))
|
|
353
|
+
if companion_data.get('assumptions'):
|
|
354
|
+
assume_list = assumptions.split('\n') if assumptions else []
|
|
355
|
+
assume_list.extend(companion_data['assumptions'])
|
|
356
|
+
assumptions = '\n'.join(filter(None, assume_list))
|
|
357
|
+
if companion_data.get('security'):
|
|
358
|
+
sec_list = security.split('\n') if security else []
|
|
359
|
+
sec_list.extend(companion_data['security'])
|
|
360
|
+
security = '\n'.join(filter(None, sec_list))
|
|
361
|
+
|
|
312
362
|
# Generate documentation based on format
|
|
313
363
|
if format == 'markdown':
|
|
314
364
|
return _generate_markdown(file_path, module_id, dependencies, assumptions, invariants, security, performance)
|