Ledger-cli functionality implemented in Rust
A brand new attempt at Ledger, starting from blank slate.
[Early Work In Progress!]
This library is aiming to implement the plain-text accounting principles, as demonstrated by Ledger-cli, Hledger, Beancount, etc. The base for development is Ledger-cli, from which the underlying model and concepts were applied.
Part of the Rusty Ledger project.
While still early work-in-progress, the basic functionality is there. Simple Ledger journal files with transactions are being parsed. The basic functionality allows retrieving the parsed entities (Transactions, Posts, Accounts, Cost, Amounts), which allow the very basic reports to be provided.
The functionality will now be expanded. The direction will be tracked through work items (issues) in the repository.
Any kind of contribution is wellcome, from using the library and providing feedback, to participating in discussions and submitting pull-requests with implementations and improvements.
After a few attempts at rewriting (pieces of) Ledger, the following conclusions seemed to crystalize:
-
One package While trying to create just a parser, it became clear that there is no need to separate the parser from the rest of the application (model, reports). They can coexist in the same crate. The parser can still be used independently of other functionality. The model and the reports are easier to include in the same crate from the beginning. These can be separated if ever needed.
-
Clean Rust Trying to convert the C++ structure into Rust just doesn't make much sense. The pointer arithmetic in the original Ledger seems next to impossible to create and maintain in Rust. The references and lifetimes make development a nightmare in Rust. A clean start, applying idiomatic Rust concepts should apply.
-
Start minimal Ledger really contains a lot of features. Start from a minimal working version and expand from there.
-
Define clear goals Trying to rewrite the whole application seems a neverending task. Rather, define clear and small, attainable goals and implement them.
The goals beyond the initial requirements, which served as a proof-of-concept, will be tracked as issues in the source repository.
The immediate goals are:
- Parse a minimal working transaction sample
- Create a minimal working reports:
- Accounts
- Balance
- Compile a working WASM version
- that interacts with JavaScript
- that works in console
These should provide initial insights into Ledger's inner workings and concepts.
- Fast execution
- Test coverage
- Permanent storage (sqlite?) as a base for the reporting layer
To compile to Wasm for execution in WASI, run
cargo build --target wasm32-wasi
then go to the target/wasm32-wasi/debug
folder and run
wasmer run --dir tests target/wasm32-wasi/debug/ledger-rs-lib.wasm -- -f tests/minimal.ledger
This will run the CLI's main() method. With WASI, the filesystem access permission has to be given explicitly. This is done with --dir
argument.
Note that Wasmer is using --
to separate application switches like -f
.
You need to have the prerequisites install - the compilation target (wasm32-wasi) and a Wasm runtime (i.e. wasmer).
The library can be compiled into WASM for use in web apps.
cargo install wasm-pack
wasm-pack build --target web
The folder wwwroot
contains the code that uses the wasm.
Serve with a web server. I.e. using Deno's file server:
deno install --allow-net --allow-read https://deno.land/std/http/file_server.ts
file_server wwwroot
Add the deno plugin location to path.
- Ledger for Developers
- Journal Format
- Ledger source code repo
I will try to document the Ledger's Journal format in a syntax diagram. This is the Extended Backus–Naur Form (EBNF) diagram source.
The original specs from Ledger's documentation:
Transaction header
DATE[=EDATE] [*|!] [(CODE)] DESC
Posting
ACCOUNT AMOUNT [; NOTE]
Price
P DATE SYMBOL PRICE
The price of a commodity is stored in commodity annotations (amount.h
).
annotate_commodity(amount_t price, [datetime_t date, string tag])