diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..80202a2 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,201 @@ +# postcss-calc v11 Roadmap + +Spec-first rewrite of the plugin's internals, targeting [CSS Values and Units Module Level 4 §10](https://www.w3.org/TR/css-values-4/#calc-notation). The public plugin API (options, plugin shape) is preserved; every consumer on v10.x should upgrade without code changes. + +## Why v11 + +Current state (v10.1.1) has known gaps that the spec closes: + +- No `min()` / `max()` / `clamp()` support — treated as opaque blobs. +- Typed division (`calc(100vw / 1px)`) throws *"Cannot divide by 'px', number expected"*. +- No folding of `pi` / `e` / `infinity` / `NaN` into arithmetic. +- JISON-generated LR parser is hard to extend: every new math function requires editing the grammar and regenerating. +- Ad-hoc reducer reinvents a weaker version of the spec's simplification algorithm, which means every edge case is discovered by users instead of derived from the standard. + +v11 replaces the parser + reducer + stringifier with direct transcriptions of the spec. The existing 190 regression tests become the contract we ship against. + +## Non-goals (deliberate deferrals) + +- **Relative color math** (`lch(from X l c calc(h + 80))`) — channel-keyword scope is out-of-band; requires caller context the plugin doesn't have at transform time. +- **`calc-size()`** — separate, evolving spec; continue to leave as-is. +- **Property-context percentage resolution** — a PostCSS transform has no property-type info; spec explicitly allows plugins to leave percentages unresolved. +- **Transpiling modern math functions to legacy `calc()`** — a separate concern; belongs in a companion plugin if wanted. + +## Architecture + +Five modules, each one-to-one with a spec section. Every module file starts with the exact spec URL it implements, so a contributor (or reviewer) can check conformance section-by-section. + +| Module | Spec section | Purpose | +|---|---|---| +| `tokenizer.ts` | [§10.1](https://www.w3.org/TR/css-values-4/#calc-syntax) | Numbers, dimensions (incl. `1px-2` single-token rule), idents, punct | +| `parser.ts` | [§10.1](https://www.w3.org/TR/css-values-4/#calc-syntax) | Pratt parser + parselet registry → AST | +| `type.ts` | [§10.2](https://www.w3.org/TR/css-values-4/#calc-type-checking) | Calculation-type arithmetic (unit × power maps) | +| `simplify.ts` | [§10.10](https://www.w3.org/TR/css-values-4/#calc-simplification) | Post-order simplification | +| `serialize.ts` | [§10.12](https://www.w3.org/TR/css-values-4/#serialize-a-calculation-tree) | AST → CSS text with correct `calc()` wrapping | + +## Current status + +**Done** (on `master`, in `playground/pratt/`): + +- Pratt parser skeleton in TypeScript, parselet registries for prefix + infix. +- Tokenizer for numbers / idents / punct. +- Evaluator harness (number-only) proving the parser works for `min`/`max`/`clamp`/`pow`/trig/stepped-value/etc. as generic call nodes. +- 48 tests covering precedence, associativity, unary stacking, function calls, and negative-syntax / pinned-behavior cases. +- `tsx` runtime + strict `tsconfig.json` for the playground; `pnpm test:pratt` runs the TS suite directly. + +The playground has validated the parser design on a clean slate. What remains is dimensions, the type system, simplification, and serialization — the three load-bearing spec pieces plus tokenizer extension. + +--- + +## Release plan + +Each release is scoped to ship on its own. Earlier releases do **not** block on later ones. + +### v11.0 — Foundation + +**Goal:** spec-correct parser + simplification core with `min`/`max`/`clamp` + typed division. Ships 80% of real-world value. + +**Scope:** + +- Replace `parser.jison` with the Pratt parser from the playground, promoted into `src/`. +- Drop `jison-gho` devDep; delete `parser.jison`; remove `build` script. +- Dimension token rule including spec-required `1px-2` single-token behavior. +- Calculation type system (§10.2). +- `simplify()` core covering: + - Nested `calc()` flattening (inner calc → bare parens). + - Like-term combination across `+` / `-`. + - Numeric folding for resolvable subtrees. + - Unit conversion within a family (port `src/lib/convertUnit.js`). + - Opaque-leaf preservation: `var()`, `env()`, `attr()`, and unknown functions are AST leaves that simplification flows around. +- `min()`, `max()`, `clamp()` as first-class AST nodes with spec-correct reduction. +- Typed division: ` / `, `