@rustledger/wasm 1.0.0-rc.5

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 ADDED
@@ -0,0 +1,173 @@
1
+ # rustledger
2
+
3
+ A pure Rust implementation of [Beancount](https://beancount.github.io/), the double-entry bookkeeping language.
4
+
5
+ [![Crates.io](https://img.shields.io/crates/v/rustledger.svg)](https://crates.io/crates/rustledger)
6
+ [![Documentation](https://docs.rs/rustledger/badge.svg)](https://docs.rs/rustledger)
7
+ [![License](https://img.shields.io/crates/l/rustledger.svg)](LICENSE)
8
+
9
+ ## Features
10
+
11
+ - **Pure Rust** - No Python dependencies, compiles to native and WebAssembly
12
+ - **Full Beancount Syntax** - Parses all directive types with error recovery
13
+ - **Drop-in Replacement** - Compatible CLI commands for Python beancount users
14
+ - **7 Booking Methods** - STRICT, FIFO, LIFO, HIFO, AVERAGE, and more
15
+ - **14 Built-in Plugins** - implicit_prices, auto_accounts, pedantic, etc.
16
+ - **BQL Query Engine** - SQL-like queries on your ledger
17
+ - **Fast** - 10x faster than Python beancount
18
+
19
+ ## Installation
20
+
21
+ ### CLI Tools
22
+
23
+ ```bash
24
+ # Install with bean-* compatibility aliases (default)
25
+ cargo install rustledger
26
+
27
+ # Install only rledger-* commands (no bean-* aliases)
28
+ cargo install rustledger --no-default-features
29
+ ```
30
+
31
+ ### As a Library
32
+
33
+ ```bash
34
+ cargo add rustledger-core rustledger-parser rustledger-loader
35
+ ```
36
+
37
+ ## CLI Usage
38
+
39
+ ```bash
40
+ # Validate a ledger file
41
+ rledger-check ledger.beancount
42
+
43
+ # Format a ledger file
44
+ rledger-format ledger.beancount
45
+ rledger-format --in-place ledger.beancount
46
+
47
+ # Run a BQL query (one-shot or interactive)
48
+ rledger-query ledger.beancount "SELECT account, SUM(position) GROUP BY account"
49
+ rledger-query ledger.beancount # Interactive shell with readline/history
50
+
51
+ # Generate reports
52
+ rledger-report ledger.beancount balances
53
+ rledger-report ledger.beancount accounts
54
+ rledger-report ledger.beancount stats
55
+
56
+ # Debugging tools
57
+ rledger-doctor ledger.beancount context 42 # Show context around line 42
58
+ rledger-doctor ledger.beancount linked ^link-name # Find linked transactions
59
+ rledger-doctor ledger.beancount missing # Find missing Open directives
60
+ rledger-doctor ledger.beancount stats # Ledger statistics
61
+
62
+ # Use plugins
63
+ rledger-check --native-plugin auto_accounts ledger.beancount
64
+ rledger-check --native-plugin pedantic ledger.beancount
65
+ ```
66
+
67
+ ### Python Beancount Compatibility
68
+
69
+ For users migrating from Python beancount, the `bean-*` commands are also available:
70
+
71
+ ```bash
72
+ bean-check ledger.beancount
73
+ bean-format ledger.beancount
74
+ bean-query ledger.beancount "SELECT ..."
75
+ bean-report ledger.beancount balances
76
+ bean-doctor ledger.beancount context 42
77
+ ```
78
+
79
+ ## Library Usage
80
+
81
+ ```rust
82
+ use rustledger_loader::load;
83
+
84
+ fn main() -> anyhow::Result<()> {
85
+ let result = load("ledger.beancount")?;
86
+
87
+ println!("Loaded {} directives", result.directives.len());
88
+
89
+ for error in &result.errors {
90
+ eprintln!("{}", error);
91
+ }
92
+
93
+ Ok(())
94
+ }
95
+ ```
96
+
97
+ ## Crates
98
+
99
+ | Crate | Description |
100
+ |-------|-------------|
101
+ | [`rustledger-core`](crates/rustledger-core) | Core types: Amount, Position, Inventory, Directives |
102
+ | [`rustledger-parser`](crates/rustledger-parser) | Lexer and parser with error recovery |
103
+ | [`rustledger-loader`](crates/rustledger-loader) | File loading, includes, options |
104
+ | [`rustledger-booking`](crates/rustledger-booking) | Interpolation and booking engine |
105
+ | [`rustledger-validate`](crates/rustledger-validate) | 30 validation error codes |
106
+ | [`rustledger-query`](crates/rustledger-query) | BQL query engine |
107
+ | [`rustledger-plugin`](crates/rustledger-plugin) | Native and WASM plugin system |
108
+ | [`rustledger`](crates/rustledger) | Command-line tools |
109
+ | [`rustledger-wasm`](crates/rustledger-wasm) | WebAssembly library target |
110
+
111
+ ## Supported Features
112
+
113
+ ### Parser
114
+
115
+ - All 12 directive types (transaction, balance, open, close, etc.)
116
+ - Cost specifications: `{100 USD}`, `{{100 USD}}`, `{100 # 5 USD}`, `{*}`
117
+ - Price annotations: `@ 100 USD`, `@@ 1000 USD`
118
+ - Arithmetic expressions: `(40.00/3 + 5) USD`
119
+ - Multi-line strings: `"""..."""`
120
+ - All transaction flags: `* ! P S T C U R M`
121
+ - Metadata with 6 value types
122
+ - Error recovery (continues parsing after errors)
123
+
124
+ ### Booking Methods
125
+
126
+ - `STRICT` - Lots must match exactly (with total match exception)
127
+ - `STRICT_WITH_SIZE` - Exact-size matches accept oldest lot
128
+ - `FIFO` - First in, first out
129
+ - `LIFO` - Last in, first out
130
+ - `HIFO` - Highest cost first
131
+ - `AVERAGE` - Average cost basis
132
+ - `NONE` - No cost tracking
133
+
134
+ ### Built-in Plugins
135
+
136
+ | Plugin | Description |
137
+ |--------|-------------|
138
+ | `implicit_prices` | Generate price entries from costs |
139
+ | `check_commodity` | Validate commodity declarations |
140
+ | `auto_accounts` | Auto-generate Open directives |
141
+ | `leafonly` | Error on non-leaf postings |
142
+ | `noduplicates` | Hash-based duplicate detection |
143
+ | `onecommodity` | Single commodity per account |
144
+ | `unique_prices` | One price per day per pair |
145
+ | `check_closing` | Zero balance assertion on closing |
146
+ | `close_tree` | Close descendant accounts |
147
+ | `coherent_cost` | Enforce cost OR price consistency |
148
+ | `sellgains` | Cross-check gains against sales |
149
+ | `pedantic` | Enable all strict validations |
150
+ | `unrealized` | Calculate unrealized gains |
151
+
152
+ ### Options (28 supported)
153
+
154
+ - Account prefixes (`name_assets`, `name_liabilities`, etc.)
155
+ - Equity accounts (`account_previous_balances`, etc.)
156
+ - Tolerance settings (`inferred_tolerance_default` with wildcards)
157
+ - Booking method, documents directories, and more
158
+
159
+ ## Compatibility
160
+
161
+ rustledger is compatible with Python beancount. It can parse and validate any valid beancount file. The `bean-*` command aliases are included by default for easy migration.
162
+
163
+ ## Performance
164
+
165
+ Benchmarks show rustledger is approximately 10x faster than Python beancount for parsing and validation.
166
+
167
+ ## License
168
+
169
+ This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.
170
+
171
+ ## Contributing
172
+
173
+ Contributions are welcome! Please feel free to submit a Pull Request.
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": "1.0.0-rc.5",
9
+ "license": "GPL-3.0",
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
+ }
@@ -0,0 +1,413 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /** Error severity level. */
5
+ export type Severity = 'error' | 'warning';
6
+
7
+ /** Error with source location information. */
8
+ export interface BeancountError {
9
+ message: string;
10
+ line?: number;
11
+ column?: number;
12
+ severity: Severity;
13
+ }
14
+
15
+ /** Amount with number and currency. */
16
+ export interface Amount {
17
+ number: string;
18
+ currency: string;
19
+ }
20
+
21
+ /** Posting cost specification. */
22
+ export interface PostingCost {
23
+ number_per?: string;
24
+ currency?: string;
25
+ date?: string;
26
+ label?: string;
27
+ }
28
+
29
+ /** A posting within a transaction. */
30
+ export interface Posting {
31
+ account: string;
32
+ units?: Amount;
33
+ cost?: PostingCost;
34
+ price?: Amount;
35
+ }
36
+
37
+ /** Base directive with date. */
38
+ interface BaseDirective {
39
+ date: string;
40
+ }
41
+
42
+ /** Transaction directive. */
43
+ export interface TransactionDirective extends BaseDirective {
44
+ type: 'transaction';
45
+ flag: string;
46
+ payee?: string;
47
+ narration?: string;
48
+ tags: string[];
49
+ links: string[];
50
+ postings: Posting[];
51
+ }
52
+
53
+ /** Balance assertion directive. */
54
+ export interface BalanceDirective extends BaseDirective {
55
+ type: 'balance';
56
+ account: string;
57
+ amount: Amount;
58
+ }
59
+
60
+ /** Open account directive. */
61
+ export interface OpenDirective extends BaseDirective {
62
+ type: 'open';
63
+ account: string;
64
+ currencies: string[];
65
+ booking?: string;
66
+ }
67
+
68
+ /** Close account directive. */
69
+ export interface CloseDirective extends BaseDirective {
70
+ type: 'close';
71
+ account: string;
72
+ }
73
+
74
+ /** All directive types. */
75
+ export type Directive =
76
+ | TransactionDirective
77
+ | BalanceDirective
78
+ | OpenDirective
79
+ | CloseDirective
80
+ | { type: 'commodity'; date: string; currency: string }
81
+ | { type: 'pad'; date: string; account: string; source_account: string }
82
+ | { type: 'event'; date: string; event_type: string; value: string }
83
+ | { type: 'note'; date: string; account: string; comment: string }
84
+ | { type: 'document'; date: string; account: string; path: string }
85
+ | { type: 'price'; date: string; currency: string; amount: Amount }
86
+ | { type: 'query'; date: string; name: string; query_string: string }
87
+ | { type: 'custom'; date: string; custom_type: string };
88
+
89
+ /** Ledger options. */
90
+ export interface LedgerOptions {
91
+ operating_currencies: string[];
92
+ title?: string;
93
+ }
94
+
95
+ /** Parsed ledger. */
96
+ export interface Ledger {
97
+ directives: Directive[];
98
+ options: LedgerOptions;
99
+ }
100
+
101
+ /** Result of parsing a Beancount file. */
102
+ export interface ParseResult {
103
+ ledger?: Ledger;
104
+ errors: BeancountError[];
105
+ }
106
+
107
+ /** Result of validation. */
108
+ export interface ValidationResult {
109
+ valid: boolean;
110
+ errors: BeancountError[];
111
+ }
112
+
113
+ /** Cell value in query results. */
114
+ export type CellValue =
115
+ | null
116
+ | string
117
+ | number
118
+ | boolean
119
+ | Amount
120
+ | { units: Amount; cost?: { number: string; currency: string; date?: string; label?: string } }
121
+ | { positions: Array<{ units: Amount }> }
122
+ | string[];
123
+
124
+ /** Result of a BQL query. */
125
+ export interface QueryResult {
126
+ columns: string[];
127
+ rows: CellValue[][];
128
+ errors: BeancountError[];
129
+ }
130
+
131
+ /** Result of formatting. */
132
+ export interface FormatResult {
133
+ formatted?: string;
134
+ errors: BeancountError[];
135
+ }
136
+
137
+ /** Result of pad expansion. */
138
+ export interface PadResult {
139
+ directives: Directive[];
140
+ padding_transactions: Directive[];
141
+ errors: BeancountError[];
142
+ }
143
+
144
+ /** Result of running a plugin. */
145
+ export interface PluginResult {
146
+ directives: Directive[];
147
+ errors: BeancountError[];
148
+ }
149
+
150
+ /** Plugin information. */
151
+ export interface PluginInfo {
152
+ name: string;
153
+ description: string;
154
+ }
155
+
156
+ /** BQL completion suggestion. */
157
+ export interface Completion {
158
+ text: string;
159
+ category: string;
160
+ description?: string;
161
+ }
162
+
163
+ /** Result of BQL completion request. */
164
+ export interface CompletionResult {
165
+ completions: Completion[];
166
+ context: string;
167
+ }
168
+
169
+ /**
170
+ * A parsed and validated ledger that caches the parse result.
171
+ * Use this class when you need to perform multiple operations on the same
172
+ * source without re-parsing each time.
173
+ */
174
+ export class ParsedLedger {
175
+ constructor(source: string);
176
+ free(): void;
177
+
178
+ /** Check if the ledger is valid (no parse or validation errors). */
179
+ isValid(): boolean;
180
+
181
+ /** Get all errors (parse + validation). */
182
+ getErrors(): BeancountError[];
183
+
184
+ /** Get parse errors only. */
185
+ getParseErrors(): BeancountError[];
186
+
187
+ /** Get validation errors only. */
188
+ getValidationErrors(): BeancountError[];
189
+
190
+ /** Get the parsed directives. */
191
+ getDirectives(): Directive[];
192
+
193
+ /** Get the ledger options. */
194
+ getOptions(): LedgerOptions;
195
+
196
+ /** Get the number of directives. */
197
+ directiveCount(): number;
198
+
199
+ /** Run a BQL query on this ledger. */
200
+ query(queryStr: string): QueryResult;
201
+
202
+ /** Get account balances (shorthand for query("BALANCES")). */
203
+ balances(): QueryResult;
204
+
205
+ /** Format the ledger source. */
206
+ format(): FormatResult;
207
+
208
+ /** Expand pad directives. */
209
+ expandPads(): PadResult;
210
+
211
+ /** Run a native plugin on this ledger. */
212
+ runPlugin(pluginName: string): PluginResult;
213
+ }
214
+
215
+
216
+
217
+ export class ParsedLedger {
218
+ free(): void;
219
+ [Symbol.dispose](): void;
220
+ /**
221
+ * Get all errors (parse + validation).
222
+ */
223
+ getErrors(): any;
224
+ /**
225
+ * Run a native plugin on this ledger.
226
+ */
227
+ runPlugin(plugin_name: string): any;
228
+ /**
229
+ * Expand pad directives.
230
+ */
231
+ expandPads(): any;
232
+ /**
233
+ * Get the ledger options.
234
+ */
235
+ getOptions(): any;
236
+ /**
237
+ * Get the parsed directives.
238
+ */
239
+ getDirectives(): any;
240
+ /**
241
+ * Get the number of directives.
242
+ */
243
+ directiveCount(): number;
244
+ /**
245
+ * Get parse errors only.
246
+ */
247
+ getParseErrors(): any;
248
+ /**
249
+ * Get validation errors only.
250
+ */
251
+ getValidationErrors(): any;
252
+ /**
253
+ * Create a new `ParsedLedger` from source text.
254
+ *
255
+ * Parses, interpolates, and validates the source. Call `isValid()` to check for errors.
256
+ */
257
+ constructor(source: string);
258
+ /**
259
+ * Run a BQL query on this ledger.
260
+ */
261
+ query(query_str: string): any;
262
+ /**
263
+ * Format the ledger source.
264
+ */
265
+ format(): any;
266
+ /**
267
+ * Get account balances (shorthand for query("BALANCES")).
268
+ */
269
+ balances(): any;
270
+ /**
271
+ * Check if the ledger is valid (no parse or validation errors).
272
+ */
273
+ isValid(): boolean;
274
+ }
275
+
276
+ /**
277
+ * Calculate account balances.
278
+ *
279
+ * Shorthand for `query(source, "BALANCES")`.
280
+ */
281
+ export function balances(source: string): any;
282
+
283
+ /**
284
+ * Get BQL query completions at cursor position.
285
+ *
286
+ * Returns context-aware completions for the BQL query language.
287
+ */
288
+ export function bqlCompletions(partial_query: string, cursor_pos: number): any;
289
+
290
+ /**
291
+ * Process pad directives and expand them.
292
+ *
293
+ * Returns directives with pad-generated transactions included.
294
+ */
295
+ export function expandPads(source: string): any;
296
+
297
+ /**
298
+ * Format a Beancount source string.
299
+ *
300
+ * Parses and reformats with consistent alignment.
301
+ * Returns a `FormatResult` with the formatted source or errors.
302
+ */
303
+ export function format(source: string): any;
304
+
305
+ /**
306
+ * Initialize the WASM module.
307
+ *
308
+ * This sets up panic hooks for better error messages in the browser console.
309
+ * Call this once before using any other functions.
310
+ */
311
+ export function init(): void;
312
+
313
+ /**
314
+ * List available native plugins.
315
+ *
316
+ * Returns an array of `PluginInfo` objects with name and description.
317
+ */
318
+ export function listPlugins(): any;
319
+
320
+ /**
321
+ * Parse a Beancount source string.
322
+ *
323
+ * Returns a `ParseResult` with the parsed ledger and any errors.
324
+ */
325
+ export function parse(source: string): any;
326
+
327
+ /**
328
+ * Run a BQL query on a Beancount source string.
329
+ *
330
+ * Parses the source, interpolates, then executes the query.
331
+ * Returns a `QueryResult` with columns, rows, and any errors.
332
+ */
333
+ export function query(source: string, query_str: string): any;
334
+
335
+ /**
336
+ * Run a native plugin on the source.
337
+ *
338
+ * Available plugins can be listed with `listPlugins()`.
339
+ */
340
+ export function runPlugin(source: string, plugin_name: string): any;
341
+
342
+ /**
343
+ * Validate a Beancount source string.
344
+ *
345
+ * Parses, interpolates, and validates in one step.
346
+ * Returns a `ValidationResult` indicating whether the ledger is valid.
347
+ */
348
+ export function validateSource(source: string): any;
349
+
350
+ /**
351
+ * Get version information.
352
+ *
353
+ * Returns the version string of the rustledger-wasm package.
354
+ */
355
+ export function version(): string;
356
+
357
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
358
+
359
+ export interface InitOutput {
360
+ readonly memory: WebAssembly.Memory;
361
+ readonly __wbg_parsedledger_free: (a: number, b: number) => void;
362
+ readonly balances: (a: number, b: number, c: number) => void;
363
+ readonly bqlCompletions: (a: number, b: number, c: number, d: number) => void;
364
+ readonly expandPads: (a: number, b: number, c: number) => void;
365
+ readonly format: (a: number, b: number, c: number) => void;
366
+ readonly listPlugins: (a: number) => void;
367
+ readonly parse: (a: number, b: number, c: number) => void;
368
+ readonly parsedledger_balances: (a: number, b: number) => void;
369
+ readonly parsedledger_directiveCount: (a: number) => number;
370
+ readonly parsedledger_expandPads: (a: number, b: number) => void;
371
+ readonly parsedledger_format: (a: number, b: number) => void;
372
+ readonly parsedledger_getDirectives: (a: number, b: number) => void;
373
+ readonly parsedledger_getErrors: (a: number, b: number) => void;
374
+ readonly parsedledger_getOptions: (a: number, b: number) => void;
375
+ readonly parsedledger_getParseErrors: (a: number, b: number) => void;
376
+ readonly parsedledger_getValidationErrors: (a: number, b: number) => void;
377
+ readonly parsedledger_isValid: (a: number) => number;
378
+ readonly parsedledger_new: (a: number, b: number) => number;
379
+ readonly parsedledger_query: (a: number, b: number, c: number, d: number) => void;
380
+ readonly parsedledger_runPlugin: (a: number, b: number, c: number, d: number) => void;
381
+ readonly query: (a: number, b: number, c: number, d: number, e: number) => void;
382
+ readonly runPlugin: (a: number, b: number, c: number, d: number, e: number) => void;
383
+ readonly validateSource: (a: number, b: number, c: number) => void;
384
+ readonly version: (a: number) => void;
385
+ readonly init: () => void;
386
+ readonly __wbindgen_export: (a: number, b: number) => number;
387
+ readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
388
+ readonly __wbindgen_export3: (a: number, b: number, c: number) => void;
389
+ readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
390
+ readonly __wbindgen_start: () => void;
391
+ }
392
+
393
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
394
+
395
+ /**
396
+ * Instantiates the given `module`, which can either be bytes or
397
+ * a precompiled `WebAssembly.Module`.
398
+ *
399
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
400
+ *
401
+ * @returns {InitOutput}
402
+ */
403
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
404
+
405
+ /**
406
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
407
+ * for everything else, calls `WebAssembly.instantiate` directly.
408
+ *
409
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
410
+ *
411
+ * @returns {Promise<InitOutput>}
412
+ */
413
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;