Module reference¶
bxp-core modules¶
What each module is responsible for, and — the column that used to rot — where
its code actually lives. Nine are files in bxp-core/src/; the rest are pinned
upstream dependencies, either modules of the zig-libs collection or standalone
fetch dependencies. Three of the zig-libs entries are re-exports bxp-core never
imports itself: they are published here only so bxp-gui-bridge and bxp-mcp
share this package's single pin.
| Module | Source | Responsibility |
|---|---|---|
expr |
expr.zig |
Expression evaluator. Recursive-descent parser into an evaluator; a per-row Context holds the field values, the named maps and the pre-pass lookup. eval() returns a Value (string / decimal / bool), evalString() coerces to string. Each built-in carries a co-located FnDoc entry that docs.zig consumes. |
config |
config.zig |
Reads bxp-cli.json through the json5 preprocessor, then std.json. Returns a Config owning all heap memory; BrokerConfig.validate() checks the semantic constraints. Each struct carries a co-located FieldDoc table that docs.zig consumes. |
xlsx |
xlsx.zig |
Converts .xlsx to an intermediate .csv. Reads ZIP+XML, resolves shared strings, formula results and dates (via styles.xml numFmtId). Worksheets stream with no whole-file size cap; only the shared-strings table is capped (XLSX_SHARED_STRINGS_CAP, 1 GiB). |
json |
json.zig |
Reads a JSON array-of-objects into a flat row representation. Builds the union of all keys across all objects and fills the missing ones with an empty string. |
btrace |
btrace.zig |
Binary BXTB trace Writer / Reader for bxp-cli --trace. Carries metadata only — per-row source byte offsets, errors, the pre_pass dump, stats; per-row drill-down is recomputed on demand by the GUI through the bridge. |
unicode |
unicode.zig |
UTF-8 case mapping and diacritic stripping behind UPPER / LOWER / UNACCENT, over the uucode tables. Imported file-relative by expr.zig. |
docs |
docs.zig |
Aggregates the expr.zig FnDoc catalog and the config.zig FieldDoc tables into the docs catalog JSON, and carries the shared Markdown table renderer. Single source for the GUI at startup and for the generated reference pages. |
inspect |
inspect.zig |
The shared stateless inspection core — config validation, expression validation / eval / trace, expr-batch, schema and docs emission, template list and fetch. Pure: never reads argv, never writes stdout, never exits. Wrapped by bxp-mcp, bxp-gui-bridge and the wasm build. |
wasm |
wasm.zig |
wasm32 export wrapper (bxp_eval_batch / bxp_docs) over inspect.evalBatchIo — the engine behind the docs site's expression scratchpad, which makes the browser a fourth consumer of the one evaluator. Opt-in target (zig build wasm), never part of install; the .wasm it emits is an untracked build artifact. |
csvstream |
(zig-libs) | CSV record model plus streaming reader. LineIterator yields records from an in-memory chunk and splitFields() unquotes them (spaces preserved, trimmed at access time in expr.Context); ChunkReader feeds it, splitting input on '\n' boundaries for the parallel pipeline. Lazy quotes by design — a '\n' always ends a record, deliberately not RFC 4180 §2.6, which is what makes any newline a safe chunk boundary. |
zipstream |
(zig-libs) | Streaming ZIP reader — central-directory walk plus per-entry inflate, with CRC-32 verified at end of stream. Shared primitive behind xlsx ingest and bxp-cli's parallel zipPrePass; consumer memory is O(one inflate window). Store and deflate only. |
datefmt |
(zig-libs) | Date core — parse, format, civil arithmetic — behind DATE_CONVERT and every calendar built-in. Pre-1970 dates are supported (pure parse to format, no epoch round-trip). |
tz |
(zig-libs) | IANA time-zone UTC-offset lookup behind TO_UTC / TZ_OFFSET / TZ_CONVERT / IS_DST, including the DST transition rules. The zone tables are compiled into the module, so there is no runtime tzdata on the host. Imports datefmt internally, which is why both must come off the same b.dependency handle. |
decimal |
(zig-libs) | Fixed-point i128 at scale 1e12 (12 fractional digits): exact + −, half-away-from-zero × ÷ and ROUND. The core behind Value.decimal, shared by the csv / json / xlsx input paths so an identical numeric string parses identically everywhere. Fallible operations return Error!Decimal, and toString writes into a caller buffer. |
numparse |
(zig-libs) | Grouped-number parser (1,234.56 / 1.234,56) behind expr.zig's numeric-coercion fallback, its GREATEST / LEAST diagnostics and the decimal_sep_in locale normalisation. Returns the same decimal the module above supplies. The one piece extracted from below file level — it was never its own file here, only a function inside expr.zig. |
encoding |
(zig-libs) | Layer-0 single-byte code page to UTF-8 transcode (Win-1250/1252, Latin-1/2/9) behind csv_input_encoding / csv_output_encoding. 256-entry tables, no uucode. |
json5 |
(zig-libs) | Single-pass tokenizer converting JSON5 to standard JSON: strips comments, quotes bare keys, removes trailing commas, normalises single-quoted strings. Imported by config, docs and inspect. |
diagnostics |
(zig-libs) | Structured validation collector: Severity (error / warning / info), Diagnostic (path, position, code, message, suggest) and the Diagnostics collector. Used by the config validator's deep validation; bxp-cli passes a null sink. |
minisign |
(zig-libs) re-export only |
Minisign signature format (Ed25519 + Blake2b-512) behind the GUI updater's authenticity check. bxp-core never imports it — re-published so bxp-gui-bridge shares this package's single zig-libs pin. |
procrun |
(zig-libs) re-export only |
Reap-race-tolerant child wait behind the bridge's bxp-cli spawns (the Dart VM's own reaper would otherwise trip std's ECHILD panic). Re-published for the same single-pin reason. |
mcp |
(zig-libs) re-export only |
JSON-RPC 2.0 / MCP transport behind bxp-mcp — the one module that came back: upstream's copy is this repo's former bxp-mcp/src/server.zig, extracted there and hardened. Re-published for the same single-pin reason. |
uucode |
(fetch dep) | Field-selected Unicode case-mapping and decomposition tables behind UPPER / LOWER / UNACCENT. Only the tables unicode.zig asks for are generated and compiled in. |
regex |
(fetch dep) | The Pike-VM engine (quangd/regex.zig, linear time, zero transitive deps) behind REGEX_MATCH / REGEX_EXTRACT. |
bxp-cli internals¶
main.zig - entry point:
- Parses run flags:
--config,--template,--data,--dry-run,--debug(+=json),--quiet,--fresh,--trace(+--trace-file),--check-fs,--version,--help. - Validates file paths (rejects shell metacharacters, limits
../depth). - Loads and validates all templates in config (
config.validate()). - Calls
pipeline.xlsxPrePass()for any templates that reference.xlsxfiles. - Calls
pipeline.processBroker()for each selected template. - Exits with code
0(success),1(error), or2(warnings).
pipeline.zig - processing engine:
xlsxPrePass()- iterates all templates withxlsx_sheetdefined, converts each.xlsxfile to an intermediate.csv. Templates sharing the samedata_dirshare the extraction pass (each file extracted once).processBroker()- the main processing loop (intentionally monolithic):- Reads input files (CSV, JSON, or intermediate CSV from xlsx pre-pass).
- Runs
pre_passif defined: one full iteration over all rows building a lookup map. - Main loop: evaluates
input_schemaexpressions, matchesrow_rules, rendersoutput_schemato produce output rows. - Writes RFC 4180-compliant CSV to
.csvxoutput files. Output- thin wrapper around stdout that respects--quietand--debugflags.SectionStats- accumulates warning/error counts and elapsed time across templates.
Deeper detail: bxp-cli/CLAUDE.md.
inspect core (stateless surface)¶
Everything that isn't "run a conversion" — config validation, expression
validation / evaluation / trace, expr-batch, schema/docs emission, template
list/fetch — lives in one stateless module, bxp-core/src/inspect.zig. It is
pure: it never reads argv, never writes stdout/stderr, never exits; callers own
all I/O and the arena. Two thin adapters wrap it: bxp-mcp (MCP/stdio for
agents) and bxp-gui-bridge (FFI for the GUI). A former bxp-fmt CLI adapter
wrapped the same calls argv→stdout and was removed once both covered every op.
| inspect function | Backed by | Purpose |
|---|---|---|
annotateRaw |
config.load + config.validateCollect |
Annotated JSON with $err_<N> / $warn_<N> / $info_<N> siblings, from config text held in memory. |
annotateConfigFromFile |
annotateRaw |
The same, reading the config off disk. |
validateExpr |
expr.eval + static FnArgDoc lint |
Authoring-time validation of one expression; null when it is clean. |
validateExprJson |
validateExpr |
The same, serialised as JSON for a wire adapter. |
evalExpr |
expr.evalString |
Lenient runtime value of one expression against one row. |
evalTrace |
expr.eval (trace_writer) |
Per-call NDJSON trace stream for the expression debugger. |
evalBatch |
expr.evalString ×N |
Evaluate N expressions against one row in a single call; {results:[…]}. |
evalBatchIo |
evalBatch |
The same with an explicit std.Io, which is what lets the wasm build supply the browser's clock and RNG. |
docsJson |
docs.writeDocs |
Full FnDoc / FieldDoc catalog — the single source the GUI reads at startup. |
listTemplates |
config.load |
{templates:[{id, data_dir, file_pattern_in/out, file_type_in/out, description}]} from config text. |
listTemplatesValue |
listTemplates |
The same from an already-parsed JSON value. |
listTemplatesFromFile |
listTemplates |
The same, reading the config off disk. |
fetchTemplate |
config.load |
One template re-serialised as a JSON object. |
fetchTemplateValue |
fetchTemplate |
The same from an already-parsed JSON value. |
fetchTemplateFromFile |
fetchTemplate |
The same, reading the config off disk. |
templateIo |
config.load |
Just one template's input/output shape — what a caller needs to stage files before a run. |
That table is the module's entire public surface, held there by a compile-time
check in inspect.zig: a new pub fn without an entry — or an entry naming a
function that was renamed away — fails the build.
Adding an op: write the pure function in inspect.zig, describe it in
module_docs.inspect_ops, then expose it from each adapter (a bxp-mcp tool in
bxp-mcp/src/tools.zig + a bridge_* entry in bxp-gui-bridge/src/main.zig).
No business logic lives in the adapters.
Deeper detail: bxp-mcp/CLAUDE.md,
bxp-gui-bridge/CLAUDE.md.