@voodocs/cli 0.1.1 → 0.1.2
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
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## [0.1.2] - 2025-12-19
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
- Fixed bug in documentation generator where `class_invariants` was incorrectly referenced as `invariants` on line 570
|
|
5
|
+
- Function-level invariants now render correctly in generated documentation
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Comprehensive example file demonstrating function-level invariants (`examples/test_function_invariants.py`)
|
|
9
|
+
- Examples showing `transfer_funds()`, `binary_search()`, and `BankAccount` class with invariants
|
|
10
|
+
- Documentation in USAGE.md clarifying when to use `invariants` vs `class_invariants`
|
|
11
|
+
- Real-world examples of conservation laws and state constraints using invariants
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Updated USAGE.md annotation fields table to clarify `invariants` usage
|
|
15
|
+
- Added "Function with Invariants" and "Class with Invariants" examples to USAGE.md
|
|
16
|
+
|
|
17
|
+
### Documentation
|
|
18
|
+
- Clarified that `invariants` can be used at function level for execution-time properties
|
|
19
|
+
- Clarified that `class_invariants` should be used for object state constraints
|
|
20
|
+
- Added examples showing both use cases
|
|
21
|
+
|
|
1
22
|
## [0.1.1] - 2025-12-19
|
|
2
23
|
|
|
3
24
|
### Fixed
|
package/USAGE.md
CHANGED
|
@@ -247,7 +247,7 @@ function myFunction(x: number): number {
|
|
|
247
247
|
| `assumptions` | Assumptions made by the module. |
|
|
248
248
|
| `preconditions` | Conditions that must be true before a function is called. |
|
|
249
249
|
| `postconditions` | Conditions that must be true after a function returns. |
|
|
250
|
-
| `invariants` |
|
|
250
|
+
| `invariants` | Properties that remain unchanged throughout execution. For functions: conditions that hold during execution. For classes: use `class_invariants` for object state constraints. |
|
|
251
251
|
| `complexity` | Time and space complexity of an algorithm. |
|
|
252
252
|
| `error_cases` | How the function behaves in error scenarios. |
|
|
253
253
|
| `security_model` | Security implications and threat model. |
|
|
@@ -268,7 +268,57 @@ The DarkArts language is a formal notation used in annotations. It includes:
|
|
|
268
268
|
|
|
269
269
|
## Examples
|
|
270
270
|
|
|
271
|
-
|
|
271
|
+
### Function with Invariants
|
|
272
|
+
|
|
273
|
+
**Python**:
|
|
274
|
+
```python
|
|
275
|
+
def transfer_funds(from_account, to_account, amount):
|
|
276
|
+
"""@voodocs
|
|
277
|
+
preconditions: [
|
|
278
|
+
"from_account.balance >= amount",
|
|
279
|
+
"amount > 0",
|
|
280
|
+
"from_account != to_account"
|
|
281
|
+
]
|
|
282
|
+
postconditions: [
|
|
283
|
+
"from_account.balance = from_account.balance₀ - amount",
|
|
284
|
+
"to_account.balance = to_account.balance₀ + amount"
|
|
285
|
+
]
|
|
286
|
+
invariants: [
|
|
287
|
+
"total_balance = from_account.balance + to_account.balance (conservation)",
|
|
288
|
+
"from_account.balance >= 0",
|
|
289
|
+
"to_account.balance >= 0"
|
|
290
|
+
]
|
|
291
|
+
complexity: "O(1)"
|
|
292
|
+
"""
|
|
293
|
+
from_account.balance -= amount
|
|
294
|
+
to_account.balance += amount
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Class with Invariants
|
|
298
|
+
|
|
299
|
+
**Python**:
|
|
300
|
+
```python
|
|
301
|
+
class BankAccount:
|
|
302
|
+
"""@voodocs
|
|
303
|
+
class_invariants: [
|
|
304
|
+
"balance >= 0 (no overdrafts)",
|
|
305
|
+
"account_id is unique and immutable"
|
|
306
|
+
]
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
def deposit(self, amount):
|
|
310
|
+
"""@voodocs
|
|
311
|
+
preconditions: ["amount > 0"]
|
|
312
|
+
postconditions: ["self.balance = self.balance₀ + amount"]
|
|
313
|
+
invariants: [
|
|
314
|
+
"self.balance >= 0 (class invariant maintained)",
|
|
315
|
+
"self.account_id unchanged"
|
|
316
|
+
]
|
|
317
|
+
"""
|
|
318
|
+
self.balance += amount
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
See the `examples/` directory for more complete examples in Python and TypeScript.
|
|
272
322
|
|
|
273
323
|
---
|
|
274
324
|
|
package/cli.py
CHANGED
|
@@ -137,7 +137,7 @@ Documentation: https://github.com/3vilEnterprises/vooodooo-magic/tree/main/packa
|
|
|
137
137
|
parser.add_argument(
|
|
138
138
|
"--version",
|
|
139
139
|
action="version",
|
|
140
|
-
version="VooDocs 0.1.
|
|
140
|
+
version="VooDocs 0.1.2"
|
|
141
141
|
)
|
|
142
142
|
|
|
143
143
|
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
@@ -435,7 +435,7 @@ def cmd_init(args):
|
|
|
435
435
|
config = {
|
|
436
436
|
"project_name": project_name,
|
|
437
437
|
"language": language,
|
|
438
|
-
"version": "0.1.
|
|
438
|
+
"version": "0.1.2",
|
|
439
439
|
"output_dir": "./voodocs-output",
|
|
440
440
|
"test_framework": "pytest",
|
|
441
441
|
"api_format": "openapi",
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Example demonstrating function-level invariants in VooDocs.
|
|
3
|
+
|
|
4
|
+
This file shows how to use invariants at the function level to document
|
|
5
|
+
properties that must hold throughout the function's execution.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def transfer_funds(from_account, to_account, amount):
|
|
10
|
+
"""@voodocs
|
|
11
|
+
preconditions: [
|
|
12
|
+
"from_account.balance >= amount",
|
|
13
|
+
"amount > 0",
|
|
14
|
+
"from_account != to_account"
|
|
15
|
+
]
|
|
16
|
+
postconditions: [
|
|
17
|
+
"from_account.balance = from_account.balance₀ - amount",
|
|
18
|
+
"to_account.balance = to_account.balance₀ + amount",
|
|
19
|
+
"total_balance = from_account.balance + to_account.balance = total_balance₀"
|
|
20
|
+
]
|
|
21
|
+
invariants: [
|
|
22
|
+
"total_balance = from_account.balance + to_account.balance (conservation of funds)",
|
|
23
|
+
"from_account.balance >= 0 (no negative balances)",
|
|
24
|
+
"to_account.balance >= 0 (no negative balances)",
|
|
25
|
+
"amount remains constant throughout execution"
|
|
26
|
+
]
|
|
27
|
+
side_effects: [
|
|
28
|
+
"Modifies from_account.balance",
|
|
29
|
+
"Modifies to_account.balance",
|
|
30
|
+
"Logs transaction to audit trail"
|
|
31
|
+
]
|
|
32
|
+
complexity: "O(1)"
|
|
33
|
+
"""
|
|
34
|
+
# Verify preconditions
|
|
35
|
+
if from_account.balance < amount:
|
|
36
|
+
raise ValueError("Insufficient funds")
|
|
37
|
+
if amount <= 0:
|
|
38
|
+
raise ValueError("Amount must be positive")
|
|
39
|
+
if from_account == to_account:
|
|
40
|
+
raise ValueError("Cannot transfer to same account")
|
|
41
|
+
|
|
42
|
+
# Perform transfer (invariants hold throughout)
|
|
43
|
+
from_account.balance -= amount
|
|
44
|
+
to_account.balance += amount
|
|
45
|
+
|
|
46
|
+
# Log transaction
|
|
47
|
+
print(f"Transferred {amount} from {from_account.id} to {to_account.id}")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def binary_search(arr, target):
|
|
51
|
+
"""@voodocs
|
|
52
|
+
preconditions: [
|
|
53
|
+
"arr is sorted in ascending order",
|
|
54
|
+
"∀ i, j: 0 ≤ i < j < len(arr) ⇒ arr[i] ≤ arr[j]"
|
|
55
|
+
]
|
|
56
|
+
postconditions: [
|
|
57
|
+
"result ≥ 0 ⇒ arr[result] = target",
|
|
58
|
+
"result = -1 ⇒ target ∉ arr"
|
|
59
|
+
]
|
|
60
|
+
invariants: [
|
|
61
|
+
"0 ≤ left ≤ right < len(arr) (search bounds)",
|
|
62
|
+
"target ∈ arr ⇒ target ∈ arr[left:right+1] (target in search range)",
|
|
63
|
+
"arr remains unchanged (no side effects on input)"
|
|
64
|
+
]
|
|
65
|
+
complexity: "O(log n) where n = len(arr)"
|
|
66
|
+
"""
|
|
67
|
+
left, right = 0, len(arr) - 1
|
|
68
|
+
|
|
69
|
+
while left <= right:
|
|
70
|
+
mid = (left + right) // 2
|
|
71
|
+
|
|
72
|
+
if arr[mid] == target:
|
|
73
|
+
return mid
|
|
74
|
+
elif arr[mid] < target:
|
|
75
|
+
left = mid + 1
|
|
76
|
+
else:
|
|
77
|
+
right = mid - 1
|
|
78
|
+
|
|
79
|
+
return -1
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class BankAccount:
|
|
83
|
+
"""@voodocs
|
|
84
|
+
class_invariants: [
|
|
85
|
+
"balance >= 0 (no overdrafts)",
|
|
86
|
+
"account_id is unique and immutable",
|
|
87
|
+
"len(transaction_history) >= 0"
|
|
88
|
+
]
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self, account_id, initial_balance=0):
|
|
92
|
+
"""@voodocs
|
|
93
|
+
preconditions: [
|
|
94
|
+
"initial_balance >= 0",
|
|
95
|
+
"account_id is not None"
|
|
96
|
+
]
|
|
97
|
+
postconditions: [
|
|
98
|
+
"self.balance = initial_balance",
|
|
99
|
+
"self.account_id = account_id",
|
|
100
|
+
"len(self.transaction_history) = 0"
|
|
101
|
+
]
|
|
102
|
+
invariants: [
|
|
103
|
+
"self.balance >= 0 (established at initialization)"
|
|
104
|
+
]
|
|
105
|
+
"""
|
|
106
|
+
self.account_id = account_id
|
|
107
|
+
self.balance = initial_balance
|
|
108
|
+
self.transaction_history = []
|
|
109
|
+
|
|
110
|
+
def deposit(self, amount):
|
|
111
|
+
"""@voodocs
|
|
112
|
+
preconditions: [
|
|
113
|
+
"amount > 0"
|
|
114
|
+
]
|
|
115
|
+
postconditions: [
|
|
116
|
+
"self.balance = self.balance₀ + amount",
|
|
117
|
+
"len(self.transaction_history) = len(self.transaction_history₀) + 1"
|
|
118
|
+
]
|
|
119
|
+
invariants: [
|
|
120
|
+
"self.balance >= 0 (class invariant maintained)",
|
|
121
|
+
"amount remains constant",
|
|
122
|
+
"self.account_id unchanged"
|
|
123
|
+
]
|
|
124
|
+
side_effects: [
|
|
125
|
+
"Modifies self.balance",
|
|
126
|
+
"Appends to self.transaction_history"
|
|
127
|
+
]
|
|
128
|
+
complexity: "O(1)"
|
|
129
|
+
"""
|
|
130
|
+
if amount <= 0:
|
|
131
|
+
raise ValueError("Deposit amount must be positive")
|
|
132
|
+
|
|
133
|
+
self.balance += amount
|
|
134
|
+
self.transaction_history.append(("deposit", amount))
|
|
@@ -567,7 +567,7 @@ class DocumentationGenerator:
|
|
|
567
567
|
|
|
568
568
|
# Documentation coverage badge
|
|
569
569
|
total_items = len(parsed.module.classes) + len(parsed.get_all_functions())
|
|
570
|
-
annotated_items = sum(1 for _ in parsed.module.classes if _.
|
|
570
|
+
annotated_items = sum(1 for _ in parsed.module.classes if _.class_invariants or _.state_transitions)
|
|
571
571
|
annotated_items += sum(1 for f in parsed.get_all_functions() if f.preconditions or f.postconditions)
|
|
572
572
|
|
|
573
573
|
if total_items > 0:
|
|
@@ -20,7 +20,7 @@ SUPABASE_URL = os.getenv("VOODOCS_SUPABASE_URL", "https://sjatkayudkbkmipubhfy.s
|
|
|
20
20
|
SUPABASE_ANON_KEY = os.getenv("VOODOCS_SUPABASE_ANON_KEY", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InNqYXRrYXl1ZGtia21pcHViaGZ5Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjYxNjE0MTMsImV4cCI6MjA4MTczNzQxM30.Wj3dbokjKPsmWTgbPw77aPnCoZCsE5hrFfIH-R_ErzI")
|
|
21
21
|
|
|
22
22
|
# VooDocs version
|
|
23
|
-
VERSION = "0.1.
|
|
23
|
+
VERSION = "0.1.2"
|
|
24
24
|
|
|
25
25
|
class TelemetryClient:
|
|
26
26
|
"""Anonymous telemetry client for VooDocs CLI."""
|
package/package.json
CHANGED