Drop the (§2 carve-out) suffix from the describe block — no other test in this file references spec sections. Switch it() titles from 'emits X' to 'encodes X as Y' to match the existing converts/normalizes verb pattern.
- bump @toon-format/spec to ^3.3.0; update SPEC.md pointer and badges
- docs: align number-form prose with §2 carve-out (canonical in [1e-6, 1e21) or zero; exponent form permitted outside)
- docs/reference/spec.md: add lowercase booleans/null to encoder checklist; add Java to Appendix F language list
- docs/reference/efficiency-formalization.md: drop overstated "matching TOON's requirement" claim
- packages/toon/README.md: drop "What's New in v3.2" section (now stale)
All 593 tests pass (packages/toon: 497, packages/cli: 96). Encoder remains conformant by default under the v3.3 §2 carve-out via String(value).
Matches the lockfile bumped in d6c64d2; CI's frozen-lockfile install
fails until the manifest catches up. The dep was skip-worktree'd during
the v3.2 development window.
- packages/toon/README.md: drop two v3.1 bullets that crept into the
"What's new in v3.2" list (canonical empty-array form and \uXXXX
escape both landed in v3.1).
- docs/reference/api.md: rename "Delimiter mismatches" entry to
"Header delimiter mismatch" and cite §14.2 – the previous wording
invited the false reading that non-active delimiter chars in row
data are an error. Add §14.4 cross-ref to the duplicate-key entry.
- docs/reference/spec.md: include \uXXXX in the §7 escape list; soften
the charset MUST claim to match §17; en-dash the §-ranges in the
glance table.
- docs/reference/syntax-cheatsheet.md: rename "Strings with Active
Delimiter" to "Strings Containing Delimiters" and distinguish
active-delim (array scope) from document-delim (object field
values) per §11.1.
- docs/guide/format-overview.md: same active-vs-document distinction
in the delimiter paragraph; drop incorrect "strict mode" qualifier
from the unknown-escape error claim (§7.1 rejects unconditionally);
trim redundant "with leading zeros" parenthetical.
- docs/guide/llm-prompts.md: fix two broken anchors
(/reference/api#decode → #decode-input-options, similar for
encodelines); use -o instead of --output for CLI example
consistency.
- packages/cli/README.md: enumerate what --no-strict actually skips
in the options table; replace "delimiter consistency" with the
more specific "header delimiter mismatches" in the Lenient Decoding
prose to avoid the same false reading the api.md fix addresses.
The bracket-to-colon and bracket-to-fields checks previously trimmed
before comparing, so `items[2] :` and `items[2] {a,b}:` slipped through
strict mode. Tighten both checks to reject any non-empty gap and
distinguish whitespace-only gaps in the error message.
The README now flips the shields.io SPEC badge to v3.2 (the conformance
work just landed), adds a six-bullet "What's new in v3.2" subsection
between Key Features and Media Type, and fixes the stale §18.2 anchor
in the Media Type paragraph to point at §17 IANA Considerations.
In v3.2, --no-strict no longer just skips count/indent/delimiter
validation - it also applies last-write-wins on duplicate sibling
keys and tolerates malformed array headers as plain key-value lines.
The previous "faster processing" framing didn't reflect any of this.
- Lenient Decoding sections in cli docs and packages/cli/README spell
out which checks the decoder stops enforcing
- Options table description shifts from "Disable strict validation"
to "Skip decode validation; last-write-wins on duplicate keys"
- --strict help text in the CLI reads "Strict decode validation
(disable with --no-strict)"
- §17 IANA anchor fix in the cli docs media-type note
Updates the JSDoc `@example` blocks for `encode` and `decode` to reflect
v3.2 output: tabular header is `users[2]{id}:` not `users[]:`, and
empty arrays render as `tags: []`.
Widens decoder behavior to match v3.2 strict-mode normative rules:
- Accepts the canonical `[]` empty-array form on all decode paths
(root, key-value, list-item-after-hyphen — sync and async)
- §6: parseBracketSegment now uses an anchored regex for the length
(rejects 0x10, 01, 1e5, -0, etc.) and throws in strict mode on
malformed bracket segments
- §14.2: parser scans the fields segment for any unquoted candidate
delimiter that mismatches the bracket-declared one and throws in
strict mode
- §14.4: assertNoDuplicateKey rejects duplicate sibling keys in strict
mode at every nested object site (root, child objects, list-item
objects, tabular-first list items)
- Strict flag now threads through parseArrayHeaderLine so header
diagnostics surface as decode errors rather than silent fallthrough
- Multi-line root that starts with a bare token now errors in strict
mode with a clear diagnostic
Per §9.1 v3.2, empty arrays MUST emit as `key: []` (and `- []` after a
list-item marker), not as `key[0]:`. The header-only emission is now
reserved for non-empty arrays.
Per the v3.2 spec, control characters U+0000–U+001F outside of \n, \r, \t
encode as \uXXXX escapes and decode them back. Lone surrogates are rejected.
- escapeString emits \uXXXX for any remaining U+0000–U+001F byte
- unescapeString recognises \uXXXX (4 hex digits) and rejects D800–DFFF
- isSafeUnquoted widens the control-char check to cover the full range
Adds the [Tooner](https://github.com/chaindead/tooner) MCP proxy entry to the Tools & Integration list in the package README and to docs/ecosystem/tools-and-playgrounds.md.
* feat(docs): add YAML input to Playground with tests
- Add input format selector and YAML parsing (YAML 1.2, merge keys off)
- Extract parse/stringify helpers for testability and SPEC-aligned encoding
- Add Vitest for docs package and playground parse tests
- Update Playground copy in package README and ecosystem docs
* refactor(docs): simplify Playground YAML support
- Inline parse/stringify helpers into the component, drop the separate
parse-input module and its tests
- Rename input state from `jsonInput`/`formattedJson`/`jsonTokens` to
`inputText`/`formattedInput`/`inputTokens` so names no longer lie when
YAML is selected
- Hide the JSON Baseline selector in YAML mode and make the token-count
tooltip conditional on input format
- Store input under `state.input` with a fallback read of legacy
`state.json` so existing share URLs keep working
- Drop redundant YAML parse options (merge/version match library
defaults); use lineWidth: 0 for editor display so long scalars do not
fold mid-sentence
- Remove the duplicated vitest devDep, docs vitest.config.ts, and `test`
script – the playground is verified through the dev server
* chore(docs): tighten Playground wording and drop empty-string fallback
- "in real-time" → "in real time" (real-time only hyphenates as a
compound modifier before a noun)
- Header copy now matches the ecosystem page: "Convert JSON or YAML to
TOON in real time"
- Token-count tooltip unified across input formats; the JSON baseline
selector is right next to it and already communicates the format
- Drop `?? ''` fallback on state.input — decodeState already gates on
successful JSON parse; the chain falls through to the legacy
state.json field
---------
Co-authored-by: Sweta <sweta@Swetas-MacBook-Air.local>
Co-authored-by: Johann Schopplich <johann@schopplich.com>