https://github.com/libraz/formulon
Headless Excel 365 calculation engine (C++17) — WASM, Python, and native CLI.
https://github.com/libraz/formulon
calculation-engine cpp cpp17 excel excel-formulas formula headless nodejs npm-package office-365 ooxml python spreadsheet wasm webassembly xlsx
Last synced: about 1 month ago
JSON representation
Headless Excel 365 calculation engine (C++17) — WASM, Python, and native CLI.
- Host: GitHub
- URL: https://github.com/libraz/formulon
- Owner: libraz
- License: apache-2.0
- Created: 2026-05-11T05:16:36.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-17T09:07:13.000Z (about 2 months ago)
- Last Synced: 2026-05-17T09:15:26.545Z (about 2 months ago)
- Topics: calculation-engine, cpp, cpp17, excel, excel-formulas, formula, headless, nodejs, npm-package, office-365, ooxml, python, spreadsheet, wasm, webassembly, xlsx
- Language: C++
- Homepage: https://formulon.libraz.net
- Size: 6.94 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Notice: NOTICE
Awesome Lists containing this project
README
# Formulon
[](https://github.com/libraz/formulon/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/@libraz/formulon)
[](https://pypi.org/project/formulon/)
[](https://codecov.io/gh/libraz/formulon)
[](https://github.com/libraz/formulon/blob/main/LICENSE)
[](https://en.cppreference.com/w/cpp/17)
[](https://github.com/libraz/formulon)
[](https://formulon.libraz.net)
Formulon is a headless, Excel-compatible calculation engine — a C++17 core that defaults to the **Windows Excel 365 (ja-JP)** behavior profile, with every known divergence explicitly tracked against Excel oracle data. The same engine is packaged for the browser (WebAssembly), for Python, and for native command-line use, so a workbook recalculates to the same values wherever it runs.
No Excel installation, no Microsoft runtime, no COM automation required. The WASM build runs in browsers, Node, and Python through `wasmtime`; native CLI packages currently ship for `darwin-arm64`, `linux-x64`, and `linux-arm64`.
## Why Formulon
- **Strict oracle, not aspirational compatibility.** The runtime default is `win-365-ja_JP`, and profile-specific oracle suites pin observed Excel behavior. The primary checked-in oracle remains Mac Excel 365 (ja-JP), while Windows Excel 365 (ja-JP) is verified through variant goldens. Outputs are checked for bit-level parity against golden data regenerated from the real product; every accepted divergence (transcendental ulp drift, volatile-function snapshots, Excel quirks where Formulon deliberately keeps a saner answer) is recorded case-by-case in [`tests/divergence.yaml`](tests/divergence.yaml) with a reason and the last verified Excel build.
- **One C++ core, identical results everywhere.** JS-only competitors re-run the logic in the browser and the logic on the server. Formulon ships one engine to every surface (WASM, Python, CLI) so there is no second implementation to drift.
- **Strict WASM size budget.** Target **1.65 MB uncompressed / 530 KB Brotli**, hard ceiling **1.9 MB / 600 KB Brotli**. The budget is enforced in CI, not aspirational; features ship within the budget or do not ship.
- **Small dependency set.** Engine deps: `miniz` (zip/deflate), `pugixml` (XML + XPath 1.0), `PCRE2` (Excel-compatible regex for `REGEX*`), `double-conversion` (Grisu3 shortest-roundtrip `dtoa`). Linear algebra, UTF-8 handling, and most number coercion are in-tree.
- **Readable, reviewable code.** `Expected` error handling, RAII, `-fno-exceptions -fno-rtti`, Google C++ style.
## What it is useful for
Anywhere a spreadsheet needs to be computed without booting Excel:
- running `.xlsx` workbooks headlessly in batch jobs or data pipelines,
- evaluating Excel-style formulas inside a web application, in the browser,
- embedding calculation into internal tools, bots, or notebooks,
- validating formulas and migrating legacy spreadsheets.
## Non-goals (by design)
Formulon deliberately does **not** cover:
| Area | Reason |
|------|--------|
| VBA execution | Security. `vbaProject.bin` is preserved byte-for-byte, never executed. |
| Legacy `.xls` (BIFF8, Excel 97–2003) | Out of scope for Excel 365 compatibility. |
| Chart / drawing rendering | Belongs to a rendering layer, not the engine. |
| PowerQuery (M) / DAX | Separate engine, separate problem domain. |
| Pivot cache recomputation | Structurally preserved; recomputation is out of scope. |
| Spreadsheet UI | A thin UI integration layer is planned; rendering is yours. |
These are **permanent** non-goals, not "not yet." The scope is finite on purpose.
## Packaging
| Surface | Name | Notes |
|---------|------|-------|
| npm | `@libraz/formulon` | WASM ESM module, type definitions included. Node 18+, browsers, workers. |
| PyPI | `formulon` | Python 3.9+ `py3-none-any` wheel that bundles `formulon_capi.wasm` plus a pure-Python wrapper. `pip` resolves the platform-specific `wasmtime` runtime. |
| GitHub Releases | `formulon-cli-` | Standalone CLI binaries (`eval`, `recalc`, `dump`) for `darwin-arm64`, `linux-x64`, `linux-arm64`. |
## Status
**All 522 catalogued Excel functions are recognized**, but recognition is not the same as full Excel-compatible execution. The function catalog exposes availability explicitly; `make function-status` reports the current split.
| Availability | Count | Meaning | Examples |
|--------------|-------|---------|----------|
| Real implementation | 507 | Evaluates inside the normal calculation engine and is covered by unit and/or oracle tests. | Math, statistics, lookup, text, dynamic arrays |
| Implemented, verification ongoing | 0 | Implemented, but still waiting for additional oracle confirmation on Excel edge cases. | None currently |
| Environment-bound | 2 | Depends on host or workbook state, so a fixed golden cannot fully describe it. | `INFO`, `CELL` |
| Unavailable stub | 15 | Requires external services, network I/O, COM providers, or OLAP connections that Formulon does not embed; returns a fixed unavailable error surface. | `PY`, `WEBSERVICE`, `STOCKHISTORY`, `IMAGE`, `RTD`, `TRANSLATE`, `DETECTLANGUAGE`, `COPILOT`, `CUBE*` |
**92 oracle categories** are defined and regenerated from Mac Excel 365 ja-JP, with Windows Excel 365 ja-JP covered by the `win-365-ja_JP` variant goldens. Current local verification is `14342/14342` fast tests passing, `4026/4026` primary formula oracle cases passing with `166` documented skips. Every remaining skip is an explicit divergence, host-service dependency, volatile/environment-bound case, or driver limitation, not a silent stub. Of the 522 catalogued functions, `515` satisfy all six closure conditions (`behaviors_declared` / `cases_cover_behaviors` / `golden_present` / `divergence_documented` / `not_in_pilot` / `behavior_drift`); the remaining `7` (`FILTERXML`, `ARRAYTOTEXT`, `CONCAT`, `CHAR`, `TRUE`, `GETPIVOTDATA`, `PHONETIC`) are blocked on oracle metadata gaps — missing goldens or under-specified behavior taxonomies — rather than implementation gaps.
Beyond formula results, **pivot tables and print areas / pagination** have a dedicated **workbook oracle track** whose primary is `win-365-ja_JP` (reliable PivotTable automation needs Windows Excel COM). Goldens are captured end-to-end: the pivot suites close at `28/28`, and the `print_basic`, `print_pagination`, `print_fit`, and `print_matrix` suites pass `35/41` cases via the `formulon_workbook_oracle_tests` harness with `6` documented divergence-skip entries scoped to `win-365-ja_JP` for a known Excel PageBreakPreview COM quirk at `PageSetup.Zoom <= 50` (low-zoom column auto-breaks invert the intuitive shrink-to-fit rule; the engine emits no break, matching the geometric model rather than Excel's PBP overlay).
New workbooks use the `win-365-ja_JP` formula profile by default; callers can switch with the profile-id API (`mac-365-ja_JP`, `win-365-ja_JP`). English-locale profiles are intentionally not exposed until matching EN oracle data and verified locale-specific behavior are available. A bytecode compiler and stack-machine VM run in parallel with the tree-walker for parity verification. The OOXML reader/writer round-trips sheets, styles, conditional formatting, comments, hyperlinks, merges, data validations, defined names, tables, and pivot tables; an MS-XLSB reader/writer is in place. Workbook-level operations (sheet add / rename / move, row/column insert / delete with formula rewriting, partial recalc, iterative-solver progress callbacks) are wired through the C ABI and exposed in the WASM, Python, and CLI surfaces.
Feedback, issue reports, and oracle divergence reports are very welcome.
## Contributing
The fastest way to help right now is to **donate Excel oracle data from your locale**. If you have Excel 365 in any locale beyond Mac ja-JP, one command (`make oracle-contribute`) drives Excel, captures goldens, and walks you through the PR. See [CONTRIBUTING.md](CONTRIBUTING.md) for the full flow and the rationale for why this is community-driven.
## License
Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).