Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
32a3f6d
feat(engine): single-source logic engine generating TypeScript, Pytho…
claude Sep 21, 2026
cc817be
ci(engine): verify the engine and its generated targets on pull requests
claude Sep 21, 2026
61c3e12
style(config): wrap the lint ignore list to the formatter's width
claude Sep 21, 2026
63cc6f5
perf(engine): drop the option round trip and print a plain nil check
claude Sep 21, 2026
540f14f
refactor(core): name the directory each target's fixtures are written to
claude Sep 21, 2026
c56bfa0
fix(engine): escape pipes in the lowering table
claude Sep 21, 2026
6cb013f
fix(engine): keep the state carried by break and continue
claude Sep 21, 2026
6f6cb29
fix(engine): resolve the capabilities import from nested modules
claude Sep 21, 2026
d8a3546
chore(core): commit the generated output for the three targets
claude Sep 21, 2026
72c6c65
docs(engine): state what break and continue mean in the subset
claude Sep 21, 2026
86842d3
feat(core): generate CPF and CNPJ from the Random capability
claude Sep 21, 2026
acfaee2
fix(engine): make the generated Python read like Python
claude Sep 21, 2026
5b0da95
docs: re-derive the metrics after the generators landed
claude Sep 21, 2026
0d48ea9
ci(engine): pin the formatters the committed output depends on
claude Sep 21, 2026
7d25d5e
test(core): benchmark the generated code against each language's own …
claude Sep 21, 2026
fbe292f
perf(engine): compile each Go pattern once, at package scope
claude Sep 21, 2026
88b46b6
feat(engine): add Rust as a fourth target, std only
claude Sep 21, 2026
4a58408
perf(engine): compile each Rust pattern at generation time
claude Sep 21, 2026
052b8b8
docs: re-derive the metrics with Rust in the table
claude Sep 21, 2026
0605b99
perf(engine): compile each Python pattern once, at module level
claude Sep 21, 2026
afb7d55
docs(engine): say what a raw emission costs a target author
claude Sep 21, 2026
536b6fa
test(core): benchmark all nine utilities, not three
claude Sep 21, 2026
5928e1d
perf(engine): borrow the Rust parameters a pre-pass proves are only read
claude Sep 21, 2026
45faae1
fix(engine): draw randomness the way the published package documents
claude Sep 21, 2026
b1c7734
feat(engine): generate the published signature, not an injected one
claude Sep 21, 2026
743dda3
test(engine): generate random programs and run the pipeline against i…
claude Sep 21, 2026
62c9acc
docs(engine): measure how far the subset is from ordinary TypeScript
claude Sep 21, 2026
0bc275b
feat(engine): read ordinary TypeScript, not only the engine's namespaces
claude Sep 21, 2026
fc42a9a
docs(engine): describe the subset in the spelling authors will use
claude Sep 21, 2026
5f1d2de
feat(core): the source is TypeScript that actually runs
claude Sep 21, 2026
1373b40
docs(engine): keep the measured case for generating source
claude Sep 21, 2026
fb60bca
feat(engine): `xs[i] ?? fallback` is the author asking for the absent…
claude Sep 21, 2026
6269b0d
docs: write down why `??` decides the accessor, not provability
claude Sep 21, 2026
8d6c6f5
docs(core): correct the closing coverage numbers
claude Sep 21, 2026
27ac631
feat(engine): accept `number` and infer its range
claude Sep 21, 2026
7804c56
perf(engine): inline per target, and stop doing work the host already…
claude Sep 21, 2026
2ee021c
perf(engine): make inlining pay for itself, in bytes as well as time
claude Sep 22, 2026
70b1fe9
build(engine): the JavaScript bundle budget is zero growth, not five …
claude Sep 22, 2026
e19acd7
perf(rust): five lowerings, each measured in isolation first
claude Sep 22, 2026
75eb659
build(engine): gate brotli as well as gzip, and report what the brows…
claude Sep 22, 2026
321411a
docs(engine): the optional-parameter gap is a silent miscompile, conf…
claude Sep 22, 2026
ab4e22e
docs(bench): the loop that is smaller raw and bigger compressed, and …
claude Sep 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/engine.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Engine

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- "engine/**"
- "core/**"
- ".github/workflows/engine.yml"
push:
branches: [main]
paths:
- "engine/**"
- "core/**"
- ".github/workflows/engine.yml"

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
contents: read

jobs:
verify:
name: Verify the engine and the core it generates
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

# The engine has its own toolchain: Node runs its TypeScript directly, and the generated
# Python and Go are compiled by the runner's own preinstalled toolchains.
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc

- name: Install the engine's dependencies
run: npm ci
working-directory: engine

# The generated output is committed, so the three formatters decide its bytes. Prettier and
# gofmt come with the engine's install and with Go; ruff is pinned to the version in
# `engine/toolchain.lock.json`, and `verify` fails outright if any of the three is missing.
- name: Install ruff, the Python formatter
run: pipx install ruff==0.15.8

- name: Verify
# Compiles, generates every target in both idiom modes, regenerates and diffs for
# determinism, runs each target's linters over the output, and runs the differential
# conformance harness against the published package and across the three targets.
run: node ../engine/scripts/verify.ts .
working-directory: core

- name: Check the committed output is what the engine emits
# `out/` is committed so it can be read in review; the verification above regenerated it,
# so a diff here means the sources changed without the output being regenerated.
run: git diff --exit-code --stat -- out
working-directory: core
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ reports/*
!reports/api/
reports/api/*
!reports/api/brazilian-utils.api.md

# Scratch git worktrees, created when a task is run in isolation from the checkout.
.claude/worktrees/
14 changes: 14 additions & 0 deletions core/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# The generated output of the four targets is committed on purpose: reading it is the point of
# this project, so a reviewer should see what the engine produces without having to run it.
# `npm run verify` regenerates it and fails if what is committed drifts from what the engine emits.
#
# The `--no-idioms` trees are a comparison the verification builds, not an artifact anyone reads,
# and the interpreter and build caches are not ours.
out/*-plain/
**/__pycache__/
out/**/.ruff_cache/
out/**/target/
node_modules

# Cargo build artifacts from the benchmark harness, the same as the generated crate above.
bench/rust/target/
47 changes: 47 additions & 0 deletions core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Brazilian Utils core

The single-source core of Brazilian Utils: each utility is written **once**, in the engine's
restricted subset, and generated for TypeScript, Python and Go.

```sh
npm run check # types, ranges, refinements, effects
npm run build # generate every target, in both idiom modes
npm run conformance # interpreter vs the npm package vs every target
npm run verify # all of it, plus linters and a determinism check
```

## Layout

```
source/
is-valid-cpf.ts one utility per file: one export, at the root
is-valid-cnpj.ts
format-cnpj.ts
get-holidays.ts
is-business-day.ts
get-address-info-by-cep.ts
format-currency.ts
generate-cpf.ts
generate-cnpj.ts
lib/ library code: check digits, masks, JSON, Easter, random
conformance/
cases.ts vectors, seeded inputs and the scripted Http
run.ts the differential runner
docs/
contracts.md what the published package does, measured
survey.md every utility of the package, by feature
out/ generated, and committed so it can be read in review
```

## What the core owes, and what the DX owes

The core takes already-normalized values and returns semantic ones. Coercion stays in the
handwritten DX of each language: reading a number as a string, defaulting an options object,
turning a host `Date` into a civil date. [`docs/contracts.md`](docs/contracts.md) records that
split for every pilot, with the behavior measured from `../src` rather than assumed.

## Status

Nine utilities, generated for three languages, verified against the published package on every
case that can be reproduced offline. [`docs/survey.md`](docs/survey.md) counts what the rest of
the package would need.
Loading
Loading