# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.4.0] - 2026-11-02
### Added
- `CanonicalValue` type: format-agnostic intermediate representation that
replaces the JSON string hub. Every reader produces a `CanonicalValue`;
every writer consumes one.
- XML support via `quick-xml` (pure Rust, streaming, no C dependencies):
`xml_to_json`, `json_to_xml`.
- Cross-format XML wrappers: `csv_to_xml`, `tsv_to_xml`, `yaml_to_xml`,
`xml_to_csv`, `xml_to_tsv`, `xml_to_yaml`.
- CLI subcommands for every new conversion route.
### Changed
- The hub is no longer a serialized JSON string. Conversions between formats
that are not JSON compose through `CanonicalValue`, so adding a new format
now costs one reader and one writer, not `N-1` pairwise converters.
### Notes
- XML documents are represented as a single-key object whose key is the root
element name. Attributes use `@name` keys; text uses `#text`. Repeated
sibling elements become arrays. `xml_to_csv` and `xml_to_tsv` extract the
tabular array when the XML follows `<root><item>...</item></root>`.
## [0.3.1] - 2026-11-02
### Fixed
- `yaml_to_json` now treats `!!binary`-tagged scalars as literal strings instead
of silently base64-decoding them, preventing value corruption for annotated
YAML documents.
### Added
- Regression tests for ragged-row rejection in CSV/TSV and `!!binary`
string preservation.
- Documented that non-string YAML keys are stringified, matching mainstream
YAML-to-JSON converters.
## [0.3.0] - 2026-11-02
### Added
- YAML output for all tabular sources: `csv_to_yaml`, `tsv_to_yaml`, `json_to_yaml`.
- YAML input for all tabular targets: `yaml_to_csv`, `yaml_to_tsv`, `yaml_to_json`.
- Direct `csv_to_tsv` and `tsv_to_csv` conversions.
- CLI subcommands for every new route.
- YAML support uses `serde-saphyr` (pure Rust, YAML 1.2, no C dependency).
### Fixed
- `csv_to_json` / `tsv_to_json` now strip UTF-8 BOM before parsing, so
Excel-exported files no longer produce headers like `\u{feff}name`.
- `yaml_to_json` uses `strict_booleans` to avoid the YAML 1.1 "Norway problem":
`yes`/`no`/`on`/`off` are kept as strings, matching YAML 1.2 semantics.
- `json_to_yaml` and `yaml_to_json` preserve `null` values instead of
stringifying them.
- `json_to_csv` / `json_to_tsv` build the header from the union of all object
keys in first-appearance order, guaranteeing stable round-trips regardless
of per-object key ordering.
- `json_to_tsv` correctly quotes cells containing tab characters, preventing
line-splitting corruption.
- Dependencies pinned to `serde-saphyr` `0.0.29` (pure Rust, YAML 1.2, no C
dependency) to keep the crate portable to Android/Termux.
## [0.2.0] - 2026-11-02
### Added
- `tsv_to_json` and `json_to_tsv` library functions.
- `tsv-to-json` and `json-to-tsv` CLI subcommands.
- TSV support reuses the same lossless conversion engine as CSV, with
identical duplicate-header and nested-value rejection rules.
## [0.1.2] - 2026-11-02
### Fixed
- `csv_to_json` now errors on duplicate CSV headers instead of silently
dropping columns.
- `json_to_csv` now collects the union of keys across all objects instead
of using only the first object's keys, which silently dropped data.
- `json_to_csv` now errors on nested JSON objects/arrays instead of
stringifying them and corrupting round-trips.
## [0.1.1] - 2026-11-02
### Changed
- Rename crate from `sheeter` to `sheeter-engine` to avoid collision with an
existing crate on crates.io. Import path changes from `sheeter::` to
`sheeter_engine::`.
## [0.1.0] - 2026-11-02
### Added
- Initial release of Sheeter CLI.
- CSV to JSON conversion.
- JSON to CSV conversion.
- Support for reading from and writing to files.