From 29796f0f9d690a0892c1c49d93e12eaf15312c38 Mon Sep 17 00:00:00 2001 From: hermes Date: Wed, 14 Oct 2026 08:32:27 +0000 Subject: [PATCH] fix(financials): emit statement line items in stable order StatementSection.values was a HashMap, so `stocks financials -o json` printed line items in a different order on every run. Table output already sorted them alphabetically; JSON now matches via BTreeMap. Values are unchanged, and older cache entries deserialize as before. Found while capturing golden output, which needs deterministic bytes. Co-Authored-By: Claude Opus 5.5 --- src/api/msn/map.rs | 2 +- src/api/types.rs | 2 +- src/cli/stocks.rs | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/msn/map.rs b/src/api/msn/map.rs index 912e4ff..2889168 100644 --- a/src/api/msn/map.rs +++ b/src/api/msn/map.rs @@ -727,7 +727,7 @@ fn parse_statement_section(section: &RawStatementSection) -> StatementSection { "underlyingInstrument", "id", ]; - let mut values = std::collections::HashMap::new(); + let mut values = std::collections::BTreeMap::new(); for (k, v) in §ion.data { if skip_keys.contains(&k.as_str()) { diff --git a/src/api/types.rs b/src/api/types.rs index 5055235..d68d52b 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -144,7 +144,7 @@ pub struct InstrumentInfo { #[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct StatementSection { - pub values: std::collections::HashMap, + pub values: std::collections::BTreeMap, pub currency: String, pub report_date: String, pub end_date: String, diff --git a/src/cli/stocks.rs b/src/cli/stocks.rs index 676e327..a596706 100644 --- a/src/cli/stocks.rs +++ b/src/cli/stocks.rs @@ -1006,7 +1006,7 @@ fn sort_screener_quotes(quotes: &mut [Quote], filter: &str) { #[cfg(test)] mod tests { - use std::collections::HashMap; + use std::collections::BTreeMap; use chrono::{Days, NaiveDate}; @@ -1217,19 +1217,19 @@ mod tests { name: "BCA".into(), }, balance_sheet: Some(StatementSection { - values: HashMap::from([("assets".into(), 1.0)]), + values: BTreeMap::from([("assets".into(), 1.0)]), currency: "IDR".into(), report_date: "2026-01-01".into(), end_date: "2025-12-31".into(), }), cash_flow: Some(StatementSection { - values: HashMap::from([("cash".into(), 2.0)]), + values: BTreeMap::from([("cash".into(), 2.0)]), currency: "IDR".into(), report_date: "2026-01-01".into(), end_date: "2025-12-31".into(), }), income_statement: Some(StatementSection { - values: HashMap::from([("income".into(), 3.0)]), + values: BTreeMap::from([("income".into(), 3.0)]), currency: "IDR".into(), report_date: "2026-01-01".into(), end_date: "2025-12-31".into(),