# Changelog

All notable changes to this project are recorded here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
[semantic versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.0] - 2026-09-28

### Added

- Multi-statement files: `parse_document` returns a `Document` whose statements
  are diagnosed separately, plus `account_labels()`, `currencies()`, `period()`,
  `statement_for_account()`, `transactions()`, `investments()` and
  `total_minor_units()`. A file with no statement wrapper is still read as one
  statement, so fragments keep working.
- Balances: `LEDGERBAL`/`AVAILBAL` become `Balance` values on the statement, and
  `reconcile` checks an opening balance plus the transactions against a closing
  balance, reporting the signed difference. It returns nothing rather than
  guessing when an amount will not convert or a sum would overflow.
- Sign-on: `Signon` and `Status` read `SONRS`, `FI` and `STATUS`, including the
  server instant, the institution and its id, and a status the document itself
  labels `ERROR`, which is now raised as a diagnostic instead of passing
  unnoticed.
- A common investment subset: `Investment` and `InvestmentKind` read
  `BUYSTOCK`/`BUYMF`, `SELLSTOCK`/`SELLMF`, `INCOME`, `REINVEST`,
  `INVBANKTRAN`, `TRANSFER`, `MARGININTEREST` and `INVEXPENSE`, with the security
  identifier, units, unit price, commissions, fees and taxes, and
  `proceeds_minor_units` for the amount after costs.
- ISO 4217 currency scales: `minor_unit_scale`, `amount_in_currency`,
  `amount_from_currency`, `currency_label`, `minor_unit_name` and
  `is_known_currency`, so a yen statement is not converted as if it had cents.
- Date arithmetic: `is_leap_year`, `month_length`, `is_valid_ofx_date`,
  `PostedDate::of`/`at_utc`, `to_epoch_seconds`, `compare`, `same_instant`,
  `weekday`, `weekday_name`, `add_days`, `days_between`, `to_ofx_date`,
  `to_ofx_stamp`, `date_range` and `parse_period_date`.
- Rendering: `csv_escape`, `Statement::to_csv`, `Document::to_csv`,
  `investments_to_csv`, `render_table`, `Statement::render_report` and
  `Document::render_report`.
- Money helpers: `checked_add`, `checked_sub` and `sum_amounts`.
- New diagnostic codes: `invalid-status-code`, `invalid-server-date`,
  `signon-status-error`, `invalid-balance-amount`, `invalid-balance-date`.
- The example now also shows `parse_document` and the CSV export.

### Changed

- `parse_statement` is now a thin wrapper over the same per-statement pass that
  `parse_document` uses, so a one-statement export and a thirty-statement one
  are read by identical rules. Its behaviour is unchanged.

## [0.2.1] - 2026-09-27

### Fixed

- A document that starts with a UTF-8 byte-order mark lost its whole header
  block, because the first key was read as `\u{FEFF}OFXHEADER`: `OFXHEADER`,
  `VERSION` and `CHARSET` came back empty and a complete OFX 1.x file degraded
  to `missing-header` plus `unknown-header-line` warnings.
- A self-closing empty element such as `<STMTTRN/>` opened an aggregate scope
  and then raised `mismatched-aggregate` when its enclosing aggregate closed.
  That is an error on well-formed XML, which made `ok()` false and made a
  caller that gates on `ok()` refuse a valid document.
- A rejected numeric character reference was reported at `&##xD800;` rather
  than at the `&#xD800;` the file actually contains.

### Added

- Regression tests for all three fixes, plus CRLF documents, an angle bracket
  inside an attribute value, `CDATA` mixed with an entity in one value, and a
  stray closing tag. The suite is 65 tests.

## [0.2.0] - 2026-09-27

### Added

- `Header` and `Statement::header`, read from both the OFX 1.x `KEY:VALUE`
  prologue and the OFX 2.x XML declaration plus `<?OFX ...?>` processing
  instruction, with `is_xml()`, `is_empty()` and `render()`.
- `Diagnostic`, `Severity` and `diagnostic_codes()`, replacing the previous
  plain-string diagnostics with `severity:code[:location]` values that carry
  the tag and 1-based line that produced them.
- Transaction fields `user_date`, `check_number`, `ref_number`, `payee_id` and
  `sic`, plus `Transaction::direction()` and `Transaction::amount_minor_units()`.
- `PostedDate` and `parse_posted_date`, with `date_string()`, `to_utc_string()`
  and `to_iso_string()`, plus `Transaction::posted_date()` and
  `Transaction::utc_posted()`.
- `minor_units_to_amount`, `normalize_amount`, and the public
  `is_valid_amount` check.
- `Statement::bank_id`, `branch_id`, `account_type`, `start_date` and
  `end_date`, taken from the `BANKACCTFROM`/`CCACCTFROM` and `BANKTRANLIST`
  aggregates.
- Aggregate nesting awareness with the codes `mismatched-aggregate`,
  `unclosed-aggregate`, `conflicting-value`, `missing-acctid` and
  `missing-curdef`.
- A lexer that consumes comments, processing instructions, DOCTYPE, CDATA and
  tag attributes, matches tag names without regard to case, and reports
  `unclosed-comment`, `unclosed-cdata` and `empty-tag`.
- Entity decoding for the five XML predefined entities, `&nbsp;` and numeric
  references, with `unknown-entity` and `malformed-entity` warnings for
  anything it cannot decode.
- README with the complete diagnostic table, a CHANGELOG, and CI that runs
  check, build, test and the example on wasm, wasm-gc, js and native.

### Changed

- `moon.mod` names the module `mengshi-12/moon-ofx-importer` and records the
  repository.
- A document with an `<OFX>` aggregate but no header, no account or no currency
  is now reported instead of importing silently.
- `parse_statement` keeps the first declared account or currency and reports
  later different values, rather than letting the last one win.
- `moon.pkg` states that the package depends on the standard library only.

### Fixed

- A numeric character reference above `U+10FFFF` or equal to zero no longer
  produces a replacement character.
- A tag carrying attributes no longer keeps them in its name, and a
  self-closing tag is no longer read as a field with the next tag's text.
- `amount_to_minor_units` refuses a scale outside `0` to `6` in both
  directions.

## [0.1.0] - 2026-09-24

### Added

- Initial release: `parse_statement`, `amount_to_minor_units`, the `Statement`
  and `Transaction` types, an `examples/demo` walkthrough, black-box tests, a
  GitHub Actions check workflow and the MIT license.

[0.2.1]: https://github.com/mengshi-12/moon-ofx-importer/releases/tag/v0.2.1
[0.2.0]: https://github.com/mengshi-12/moon-ofx-importer/releases/tag/v0.2.0
[0.1.0]: https://github.com/mengshi-12/moon-ofx-importer/commits/main
