メインコンテンツへスキップ

Migrating from 0.x to 1.0

ROADMAP gate G19. Every behavior change across 0.x that can affect an existing template or host, with what to do about it.

Short version

If your templates convert cleanly on 0.11.0, 1.0 changes nothing for you. 1.0 is a stability commitment, not a redesign — it freezes the surface that 0.11.0 already has.

The work of migrating is therefore getting to 0.11.0, not getting from 0.11.0 to 1.0. Two things to do:

  1. If you are on @jinyoung4478/xl3, switch to @xl3-lang/xl3 (install name only — see Package rename).
  2. Run convert() over your real templates on 0.11.0. If they all succeed and the output looks right, you are done.

The pattern worth knowing

Almost every behavior change in 0.x did the same thing: replaced silently-wrong output with a stable error code.

That shapes the risk. Upgrading is unlikely to quietly change a report — it is likely to make a bad template start failing, at convert time, with a code naming the cell. A template that was producing plausible but wrong numbers is the one that breaks, which is the outcome you want.

Three changes are the exception and can alter output without raising anything. Those are worth reading closely.

Changes that alter output without erroring

These are the only ones that can change a report you already trust. Check these first.

Division by zero renders #DIV/0! (0.2.0, ADR-0025)

A zero divisor used to render 0. It now produces an Excel-style #DIV/0! error cell. The workbook still renders and the other rows are unaffected — only that cell carries the error.

What to do: if a 0 in a computed column was actually a divide-by-zero, it will now be visible. That is a correction, but downstream consumers that sum the column will see an error cell instead of a zero. Guard the divisor in the template (IF([Qty] = 0, 0, [Total] / [Qty])) if you want the old value.

Empty group key renders (blank) (0.3.0, ADR-0026)

When a file- or sheet-name template substitutes a group key whose value is empty:

  • File names used to fail with xl3/filename/empty. They now emit the literal token (blank), matching Excel's pivot convention.
  • Sheet names used to fall back to the literal Sheet. They now emit (blank) too.

What to do: nothing, unless you were relying on the failure to catch empty keys upstream. A conversion that used to stop now produces a file named with (blank) in it.

Whitespace around a single block makes it a single-expression cell (0.7.0, ADR-0052)

A cell containing ␣␣{{ [Amount] }}␣␣ — one block with surrounding whitespace and nothing else — used to count as mixed text, so the template cell's number format did not apply and the result was a string. It is now a single-expression cell: the value keeps its type and the cell's number format coerces it.

What to do: this usually fixes such cells rather than breaking them. But if a template relied on getting a string out of a number-formatted cell, the output type changes. Search your templates for blocks with stray leading or trailing spaces.

Formula cached results are no longer scanned for markers (0.10.0, ADR-0073)

A native formula cell whose cached <v> result happened to look like {{ … }} — a common Excel/LibreOffice round-trip artifact — could silently demote a @subtotal row. Marker recognition now ignores formula cells entirely.

What to do: nothing. Templates affected by this rendered wrongly before and render correctly now.

Changes that turn silent-wrong into an error

Each of these used to produce output. It now raises at parse or eval time, naming the cell. If none of them fire on your templates, none of them affect you.

VersionWhat changedRaises
0.2.0Wrong argument count on IF, ROUND, XLOOKUP, SUM, … — previously a silent string fallback or a crashxl3/eval/arity-mismatch
0.2.0Non-numeric string in arithmetic ("abc" + 5) — previously coerced to 0xl3/eval/operand-coercion
0.3.0Source column named like an internal context key (Rows, __rownum, __activeSource__, __joinedRow__, or any __name__) — previously shadowed silently and rendered [object Object]xl3/source/reserved-column-name
0.3.0Empty or malformed directive body ({{ @filter }}, {{ @sort foo }}) — previously no-opped, so the directive silently did nothingxl3/directive/invalid-syntax
0.3.0Unary operator on a non-literal (-[col], +5, -(expr)) — previously rendered the expression literallyxl3/eval/unsupported-syntax
0.6.0__inputs__ default / label / description / options cells containing {{ … }} are now evaluated, not passed through as literal textvaries by expression
0.7.0Leading-zero directive forms (@top 05, @repeat right 05)parse error
0.7.0Non-column-ref aggregate argument (SUM(literal), SUM([a] + [b])) — previously produced literal × row_countxl3/eval/bad-aggregate-arg
0.7.0{{ __lists__[x] }} outside @filter in / !in — previously stringified the underlying arrayxl3/lists/invalid-use
0.7.0String coercion of "0x10", "0b101", "0o17" — previously parsed via JavaScript Number(). Scientific notation ("1e5") is still acceptedxl3/eval/operand-coercion
0.10.0A @subtotal row that also carries a current-row [Column] reference outside an aggregate — previously rendered the subtotal band after every data row with grand-total valuesxl3/subtotal/mixed-row
0.10.0@group / @subtotal on a sheet using explicit @block declarations — previously the subtotal band was silently omitted entirelyxl3/subtotal/explicit-block-unsupported

For the 0.6.0 __inputs__ change specifically: the prior behavior showed the host UI {{ TODAY() }} verbatim, which was reported as a bug every time. If you genuinely need literal curly braces there, split them across two cells or post-process in the host.

Package rename (0.10.0)

@jinyoung4478/xl3@xl3-lang/xl3, matching the xl3-lang GitHub organization the repository moved to.

npm uninstall @jinyoung4478/xl3
npm install @xl3-lang/xl3

Install name only. The public API, the xl3-conformance bin, and all behavior are identical. The old package is deprecated on npm with a pointer to the new one.

For porters and spec consumers

Two changes affect implementations rather than templates.

0.5.0 tightened feature preservation from advisory to normative. evaluation.md "Styles and Workbook Structure" previously listed preserved features "where possible"; that was replaced with an explicit MUST-preserve table (ADR-0036). A port that treated the old wording as best-effort now has a concrete list to satisfy. evaluation.md "Source Data Model" also gained merged-header rules (ADR-0033) and the merge data-row broadcast paragraph (ADR-0035) in the same release.

0.6.0 retired an ADR status string. accepted (informational + process-level normative) became process-normative. If your tooling matches on ADR status text, update it. No template is affected.

How to check before upgrading

npm install @xl3-lang/xl3@0.11

Then run convert() over your real templates with real data. The errors above all fire at parse or eval time and name the offending cell, so a clean run over representative templates is a strong signal.

Worth doing on the output as well as the exit code, because of the four changes in the section above — those do not raise. In particular, diff a before/after workbook if any of your templates divide, group on a column that can be empty, or have blocks with stray whitespace.

What 1.0 itself changes

Nothing in the areas above. 1.0 freezes:

  • the public API surface (spec/STABILITY.md "Public API surface")
  • the error code catalog (ADR-0015) — additive only after 1.0
  • the ADR set listed under spec/STABILITY.md "What 1.0 freezes"

Additions after 1.0 remain possible; removals, renames, and signature changes become 2.0-only. See spec/STABILITY.md for the full policy and ROADMAP.md for what still gates the 1.0 cut.