@rustledger/wasm 0.1.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/README.md +419 -0
- package/package.json +32 -0
- package/rustledger_wasm.d.ts +413 -0
- package/rustledger_wasm.js +828 -0
- package/rustledger_wasm_bg.wasm +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
# rustledger
|
|
2
|
+
|
|
3
|
+
A pure Rust implementation of [Beancount](https://beancount.github.io/), the double-entry bookkeeping language.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/rustledger/rustledger/actions/workflows/ci.yml)
|
|
6
|
+
[](https://crates.io/crates/rustledger)
|
|
7
|
+
[](https://docs.rs/rustledger)
|
|
8
|
+
[](https://codecov.io/gh/rustledger/rustledger)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
[](https://github.com/rustledger/rustledger/releases)
|
|
12
|
+
[](https://www.npmjs.com/package/@rustledger/wasm)
|
|
13
|
+
[](https://aur.archlinux.org/packages/rustledger)
|
|
14
|
+
[](https://copr.fedorainfracloud.org/coprs/robcohen/rustledger/)
|
|
15
|
+
[](https://repology.org/project/rustledger/versions)
|
|
16
|
+
|
|
17
|
+
## Why rustledger?
|
|
18
|
+
|
|
19
|
+
- **10x faster** than Python beancount - parse and validate large ledgers in milliseconds
|
|
20
|
+
- **Pure Rust** - No Python dependencies, single binary, compiles to native and WebAssembly
|
|
21
|
+
- **Drop-in replacement** - Compatible `bean-*` CLI commands for easy migration
|
|
22
|
+
- **Formally verified** - Core algorithms verified with 19 TLA+ specifications
|
|
23
|
+
- **Full compatibility** - Parses any valid beancount file
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Install
|
|
29
|
+
cargo install rustledger
|
|
30
|
+
|
|
31
|
+
# Validate your ledger
|
|
32
|
+
rledger-check ledger.beancount
|
|
33
|
+
|
|
34
|
+
# Query your data
|
|
35
|
+
rledger-query ledger.beancount "SELECT account, SUM(position) GROUP BY account"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Example output:
|
|
39
|
+
```
|
|
40
|
+
$ rledger-check example.beancount
|
|
41
|
+
Loaded 1,247 directives in 12ms
|
|
42
|
+
✓ No errors found
|
|
43
|
+
|
|
44
|
+
$ rledger-query example.beancount "BALANCES WHERE account ~ 'Assets:'"
|
|
45
|
+
account balance
|
|
46
|
+
------------------------- ----------------
|
|
47
|
+
Assets:Bank:Checking 2,450.00 USD
|
|
48
|
+
Assets:Bank:Savings 15,000.00 USD
|
|
49
|
+
Assets:Investments 5,230.50 USD
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
### Quick Install (Linux/macOS)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
curl -sSfL rustledger.github.io/i | sh
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Homebrew (macOS/Linux)
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
brew install rustledger/rustledger/rustledger
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Scoop (Windows)
|
|
67
|
+
|
|
68
|
+
```powershell
|
|
69
|
+
scoop bucket add rustledger https://github.com/rustledger/scoop-rustledger
|
|
70
|
+
scoop install rustledger
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Cargo
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Pre-built binary (fast)
|
|
77
|
+
cargo binstall rustledger
|
|
78
|
+
|
|
79
|
+
# Build from source
|
|
80
|
+
cargo install rustledger
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Nix
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Run directly
|
|
87
|
+
nix run github:rustledger/rustledger -- rledger-check ledger.beancount
|
|
88
|
+
|
|
89
|
+
# Install to profile
|
|
90
|
+
nix profile install github:rustledger/rustledger
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Arch Linux (AUR)
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Pre-built binary (recommended)
|
|
97
|
+
yay -S rustledger-bin
|
|
98
|
+
|
|
99
|
+
# Or build from source
|
|
100
|
+
yay -S rustledger
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Docker
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Validate a ledger file
|
|
107
|
+
docker run --rm -v "$PWD:/data" ghcr.io/rustledger/rustledger /data/ledger.beancount
|
|
108
|
+
|
|
109
|
+
# Run queries
|
|
110
|
+
docker run --rm -v "$PWD:/data" --entrypoint rledger-query ghcr.io/rustledger/rustledger \
|
|
111
|
+
/data/ledger.beancount "SELECT account, SUM(position) GROUP BY account"
|
|
112
|
+
|
|
113
|
+
# Use a specific version
|
|
114
|
+
docker run --rm -v "$PWD:/data" ghcr.io/rustledger/rustledger:1.0.0 /data/ledger.beancount
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Pre-built Binaries
|
|
118
|
+
|
|
119
|
+
Download from [GitHub Releases](https://github.com/rustledger/rustledger/releases) for:
|
|
120
|
+
- Linux (x86_64, ARM64, glibc and musl)
|
|
121
|
+
- macOS (Intel and Apple Silicon)
|
|
122
|
+
- Windows (x86_64, ARM64)
|
|
123
|
+
|
|
124
|
+
### As a Library
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
cargo add rustledger-core rustledger-parser rustledger-loader
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### WebAssembly (npm)
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npm install @rustledger/wasm
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### MCP Server
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npm install -g @rustledger/mcp-server
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## CLI Commands
|
|
143
|
+
|
|
144
|
+
| Command | Description |
|
|
145
|
+
|---------|-------------|
|
|
146
|
+
| `rledger-check` | Validate ledger files with detailed error messages |
|
|
147
|
+
| `rledger-format` | Auto-format beancount files |
|
|
148
|
+
| `rledger-query` | Run BQL queries (interactive shell or one-shot) |
|
|
149
|
+
| `rledger-report` | Generate balance, account, and statistics reports |
|
|
150
|
+
| `rledger-doctor` | Debugging tools: context, linked transactions, missing opens |
|
|
151
|
+
| `rledger-extract` | Import transactions from CSV/OFX bank statements |
|
|
152
|
+
| `rledger-price` | Fetch commodity prices from online sources |
|
|
153
|
+
|
|
154
|
+
### Examples
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Validate with plugins
|
|
158
|
+
rledger-check --native-plugin auto_accounts ledger.beancount
|
|
159
|
+
rledger-check --native-plugin pedantic ledger.beancount
|
|
160
|
+
|
|
161
|
+
# Format in place
|
|
162
|
+
rledger-format --in-place ledger.beancount
|
|
163
|
+
|
|
164
|
+
# Interactive query shell with readline and history
|
|
165
|
+
rledger-query ledger.beancount
|
|
166
|
+
|
|
167
|
+
# One-shot query
|
|
168
|
+
rledger-query ledger.beancount "SELECT date, narration WHERE account ~ 'Expenses:Food'"
|
|
169
|
+
|
|
170
|
+
# Reports
|
|
171
|
+
rledger-report ledger.beancount balances
|
|
172
|
+
rledger-report ledger.beancount accounts
|
|
173
|
+
rledger-report ledger.beancount stats
|
|
174
|
+
|
|
175
|
+
# Debugging
|
|
176
|
+
rledger-doctor ledger.beancount context 42 # Show context around line 42
|
|
177
|
+
rledger-doctor ledger.beancount linked ^trip-2024 # Find linked transactions
|
|
178
|
+
rledger-doctor ledger.beancount missing # Find missing Open directives
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Python Beancount Compatibility
|
|
182
|
+
|
|
183
|
+
For users migrating from Python beancount, the `bean-*` commands are also available:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
bean-check ledger.beancount
|
|
187
|
+
bean-format ledger.beancount
|
|
188
|
+
bean-query ledger.beancount "SELECT ..."
|
|
189
|
+
bean-report ledger.beancount balances
|
|
190
|
+
bean-doctor ledger.beancount context 42
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Shell Completions
|
|
194
|
+
|
|
195
|
+
All CLI commands support generating shell completions:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Bash (add to ~/.bashrc)
|
|
199
|
+
rledger-check --generate-completions bash >> ~/.bashrc
|
|
200
|
+
|
|
201
|
+
# Zsh (add to ~/.zshrc)
|
|
202
|
+
rledger-check --generate-completions zsh >> ~/.zshrc
|
|
203
|
+
|
|
204
|
+
# Fish
|
|
205
|
+
rledger-check --generate-completions fish > ~/.config/fish/completions/rledger-check.fish
|
|
206
|
+
|
|
207
|
+
# PowerShell
|
|
208
|
+
rledger-check --generate-completions powershell >> $PROFILE
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Generate completions for each command you use (`rledger-check`, `rledger-query`, etc.).
|
|
212
|
+
|
|
213
|
+
## Library Usage
|
|
214
|
+
|
|
215
|
+
```rust
|
|
216
|
+
use rustledger_loader::load;
|
|
217
|
+
use std::path::Path;
|
|
218
|
+
|
|
219
|
+
fn main() -> anyhow::Result<()> {
|
|
220
|
+
let result = load(Path::new("ledger.beancount"))?;
|
|
221
|
+
|
|
222
|
+
println!("Loaded {} directives", result.directives.len());
|
|
223
|
+
|
|
224
|
+
for error in &result.errors {
|
|
225
|
+
eprintln!("{}", error);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
Ok(())
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Importing Bank Statements
|
|
233
|
+
|
|
234
|
+
rustledger includes an import framework for extracting transactions from CSV and OFX files:
|
|
235
|
+
|
|
236
|
+
```rust
|
|
237
|
+
use rustledger_importer::ImporterConfig;
|
|
238
|
+
|
|
239
|
+
let config = ImporterConfig::csv()
|
|
240
|
+
.account("Assets:Bank:Checking")
|
|
241
|
+
.currency("USD")
|
|
242
|
+
.date_column("Date")
|
|
243
|
+
.narration_column("Description")
|
|
244
|
+
.amount_column("Amount")
|
|
245
|
+
.date_format("%m/%d/%Y")
|
|
246
|
+
.build();
|
|
247
|
+
|
|
248
|
+
let result = config.extract_from_string(csv_content)?;
|
|
249
|
+
for directive in result.directives {
|
|
250
|
+
println!("{}", directive);
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Supports:
|
|
255
|
+
- CSV with configurable columns, delimiters, date formats
|
|
256
|
+
- Separate debit/credit columns
|
|
257
|
+
- OFX/QFX bank statement files
|
|
258
|
+
- Currency symbols, parentheses for negatives, thousand separators
|
|
259
|
+
|
|
260
|
+
## Crates
|
|
261
|
+
|
|
262
|
+
| Crate | Description |
|
|
263
|
+
|-------|-------------|
|
|
264
|
+
| [`rustledger-core`](crates/rustledger-core) | Core types: Amount, Position, Inventory, Directives |
|
|
265
|
+
| [`rustledger-parser`](crates/rustledger-parser) | Lexer and parser with error recovery |
|
|
266
|
+
| [`rustledger-loader`](crates/rustledger-loader) | File loading, includes, options |
|
|
267
|
+
| [`rustledger-booking`](crates/rustledger-booking) | Interpolation and booking engine |
|
|
268
|
+
| [`rustledger-validate`](crates/rustledger-validate) | 30 validation error codes |
|
|
269
|
+
| [`rustledger-query`](crates/rustledger-query) | BQL query engine |
|
|
270
|
+
| [`rustledger-plugin`](crates/rustledger-plugin) | Native and WASM plugin system |
|
|
271
|
+
| [`rustledger-importer`](crates/rustledger-importer) | CSV/OFX import framework |
|
|
272
|
+
| [`rustledger`](crates/rustledger) | Command-line tools |
|
|
273
|
+
| [`rustledger-wasm`](crates/rustledger-wasm) | WebAssembly library target |
|
|
274
|
+
|
|
275
|
+
## Features
|
|
276
|
+
|
|
277
|
+
### Parser
|
|
278
|
+
|
|
279
|
+
- All 12 directive types (transaction, balance, open, close, commodity, pad, event, query, note, document, custom, price)
|
|
280
|
+
- Cost specifications: `{100 USD}`, `{{100 USD}}`, `{100 # 5 USD}`, `{*}`
|
|
281
|
+
- Price annotations: `@ 100 USD`, `@@ 1000 USD`
|
|
282
|
+
- Arithmetic expressions: `(40.00/3 + 5) USD`
|
|
283
|
+
- Multi-line strings with `"""..."""`
|
|
284
|
+
- All transaction flags: `* ! P S T C U R M`
|
|
285
|
+
- Metadata with 6 value types
|
|
286
|
+
- Error recovery (continues parsing after errors)
|
|
287
|
+
|
|
288
|
+
### Booking Methods
|
|
289
|
+
|
|
290
|
+
| Method | Description |
|
|
291
|
+
|--------|-------------|
|
|
292
|
+
| `STRICT` | Lots must match exactly (default) |
|
|
293
|
+
| `STRICT_WITH_SIZE` | Exact-size matches accept oldest lot |
|
|
294
|
+
| `FIFO` | First in, first out |
|
|
295
|
+
| `LIFO` | Last in, first out |
|
|
296
|
+
| `HIFO` | Highest cost first |
|
|
297
|
+
| `AVERAGE` | Average cost basis |
|
|
298
|
+
| `NONE` | No cost tracking |
|
|
299
|
+
|
|
300
|
+
### Built-in Plugins (14)
|
|
301
|
+
|
|
302
|
+
| Plugin | Description |
|
|
303
|
+
|--------|-------------|
|
|
304
|
+
| `implicit_prices` | Generate price entries from transaction costs |
|
|
305
|
+
| `check_commodity` | Validate commodity declarations |
|
|
306
|
+
| `auto_accounts` | Auto-generate Open directives |
|
|
307
|
+
| `leafonly` | Error on postings to non-leaf accounts |
|
|
308
|
+
| `noduplicates` | Hash-based duplicate transaction detection |
|
|
309
|
+
| `onecommodity` | Single commodity per account |
|
|
310
|
+
| `unique_prices` | One price per day per commodity pair |
|
|
311
|
+
| `check_closing` | Zero balance assertion on account close |
|
|
312
|
+
| `close_tree` | Close descendant accounts |
|
|
313
|
+
| `coherent_cost` | Enforce cost OR price (not both) |
|
|
314
|
+
| `sellgains` | Cross-check capital gains against sales |
|
|
315
|
+
| `pedantic` | Enable all strict validations |
|
|
316
|
+
| `unrealized` | Calculate unrealized gains |
|
|
317
|
+
| `nounused` | Warn on unused accounts |
|
|
318
|
+
|
|
319
|
+
### Options (28 supported)
|
|
320
|
+
|
|
321
|
+
- Account prefixes (`name_assets`, `name_liabilities`, etc.)
|
|
322
|
+
- Equity accounts (`account_previous_balances`, `account_unrealized_gains`, etc.)
|
|
323
|
+
- Tolerance settings (`inferred_tolerance_default` with wildcards)
|
|
324
|
+
- Booking method, document directories, and more
|
|
325
|
+
|
|
326
|
+
## Performance
|
|
327
|
+
|
|
328
|
+
rustledger is approximately **10x faster** than Python beancount:
|
|
329
|
+
|
|
330
|
+
| Operation | Python beancount | rustledger | Speedup |
|
|
331
|
+
|-----------|------------------|------------|---------|
|
|
332
|
+
| Parse 10K transactions | ~800ms | ~80ms | 10x |
|
|
333
|
+
| Full validation | ~1.2s | ~120ms | 10x |
|
|
334
|
+
| BQL query | ~200ms | ~20ms | 10x |
|
|
335
|
+
|
|
336
|
+
*Benchmarks on M1 MacBook Pro with a real-world 10,000 transaction ledger.*
|
|
337
|
+
|
|
338
|
+
## Formal Verification
|
|
339
|
+
|
|
340
|
+
Core algorithms are formally specified and verified using TLA+:
|
|
341
|
+
|
|
342
|
+
- **19 TLA+ specifications** covering inventory management, booking methods, validation rules
|
|
343
|
+
- **Inductive invariants** prove conservation of units across all operations
|
|
344
|
+
- **Model checking** explores millions of states to find edge cases
|
|
345
|
+
- **Refinement proofs** verify Rust implementation matches specifications
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# Run all TLA+ model checks
|
|
349
|
+
just tla-all
|
|
350
|
+
|
|
351
|
+
# Check specific specification
|
|
352
|
+
just tla-check Conservation
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Development
|
|
356
|
+
|
|
357
|
+
### With Nix (recommended)
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# Enter development shell with all tools
|
|
361
|
+
nix develop
|
|
362
|
+
|
|
363
|
+
# Run tests
|
|
364
|
+
cargo test --all-features
|
|
365
|
+
|
|
366
|
+
# Run lints
|
|
367
|
+
cargo clippy --all-features
|
|
368
|
+
|
|
369
|
+
# Format code
|
|
370
|
+
cargo fmt
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Without Nix
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
# Install Rust
|
|
377
|
+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
378
|
+
|
|
379
|
+
# Clone and build
|
|
380
|
+
git clone https://github.com/rustledger/rustledger
|
|
381
|
+
cd rustledger
|
|
382
|
+
cargo build --release
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Running Tests
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# All tests
|
|
389
|
+
cargo test --all-features
|
|
390
|
+
|
|
391
|
+
# Specific crate
|
|
392
|
+
cargo test -p rustledger-parser
|
|
393
|
+
|
|
394
|
+
# With coverage
|
|
395
|
+
cargo llvm-cov --all-features
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Compatibility
|
|
399
|
+
|
|
400
|
+
rustledger is fully compatible with Python beancount. It can parse and validate any valid beancount file. The `bean-*` command aliases are included by default for easy migration.
|
|
401
|
+
|
|
402
|
+
Known differences:
|
|
403
|
+
- Some edge cases in expression evaluation may differ slightly
|
|
404
|
+
- Plugin system uses native Rust or WASM (Python plugins not supported)
|
|
405
|
+
|
|
406
|
+
## License
|
|
407
|
+
|
|
408
|
+
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.
|
|
409
|
+
|
|
410
|
+
## Contributing
|
|
411
|
+
|
|
412
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
413
|
+
|
|
414
|
+
Before submitting:
|
|
415
|
+
1. Run `cargo test --all-features`
|
|
416
|
+
2. Run `cargo clippy --all-features`
|
|
417
|
+
3. Run `cargo fmt`
|
|
418
|
+
|
|
419
|
+
See [CLAUDE.md](CLAUDE.md) for code standards and architecture overview.
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rustledger/wasm",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"collaborators": [
|
|
5
|
+
"Rustledger Contributors"
|
|
6
|
+
],
|
|
7
|
+
"description": "Beancount WebAssembly bindings for JavaScript/TypeScript",
|
|
8
|
+
"version": "0.1.0",
|
|
9
|
+
"license": "GPL-3.0-only",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/rustledger/rustledger"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"rustledger_wasm_bg.wasm",
|
|
16
|
+
"rustledger_wasm.js",
|
|
17
|
+
"rustledger_wasm.d.ts"
|
|
18
|
+
],
|
|
19
|
+
"main": "rustledger_wasm.js",
|
|
20
|
+
"homepage": "https://rustledger.github.io",
|
|
21
|
+
"types": "rustledger_wasm.d.ts",
|
|
22
|
+
"sideEffects": [
|
|
23
|
+
"./snippets/*"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"beancount",
|
|
27
|
+
"accounting",
|
|
28
|
+
"finance",
|
|
29
|
+
"double-entry",
|
|
30
|
+
"ledger"
|
|
31
|
+
]
|
|
32
|
+
}
|