Fix financial taxonomy snapshot normalization

This commit is contained in:
2026-03-13 19:01:56 -04:00
parent b1c9c0ef08
commit 30977dc15f
16 changed files with 1273 additions and 156 deletions

View File

@@ -45,6 +45,7 @@ import {
type NumberScaleUnit
} from '@/lib/format';
import { buildGraphingHref } from '@/lib/graphing/catalog';
import { mergeFinancialPages } from '@/lib/financials/page-merge';
import {
buildStatementTree,
resolveStatementSelection,
@@ -63,7 +64,6 @@ import type {
RatioRow,
StandardizedFinancialRow,
StructuredKpiRow,
SurfaceDetailMap,
SurfaceFinancialRow,
TaxonomyStatementRow,
TrendSeries
@@ -345,90 +345,6 @@ function groupRows(rows: FlatDisplayRow[], categories: CompanyFinancialStatement
.filter((group) => group.rows.length > 0);
}
function mergeDetailMaps(base: SurfaceDetailMap | null, next: SurfaceDetailMap | null) {
if (!base) {
return next;
}
if (!next) {
return base;
}
const merged: SurfaceDetailMap = structuredClone(base);
for (const [surfaceKey, detailRows] of Object.entries(next)) {
const existingRows = merged[surfaceKey] ?? [];
const rowMap = new Map(existingRows.map((row) => [row.key, row]));
for (const detailRow of detailRows) {
const existing = rowMap.get(detailRow.key);
if (!existing) {
rowMap.set(detailRow.key, structuredClone(detailRow));
continue;
}
existing.values = {
...existing.values,
...detailRow.values
};
existing.sourceFactIds = [...new Set([...existing.sourceFactIds, ...detailRow.sourceFactIds])];
existing.dimensionsSummary = [...new Set([...existing.dimensionsSummary, ...detailRow.dimensionsSummary])];
}
merged[surfaceKey] = [...rowMap.values()];
}
return merged;
}
function mergeFinancialPages(
base: CompanyFinancialStatementsResponse | null,
next: CompanyFinancialStatementsResponse
) {
if (!base) {
return next;
}
const periods = [...base.periods, ...next.periods]
.filter((period, index, list) => list.findIndex((item) => item.id === period.id) === index)
.sort((left, right) => Date.parse(left.periodEnd ?? left.filingDate) - Date.parse(right.periodEnd ?? right.filingDate));
const mergeRows = <T extends { key: string; values: Record<string, number | null> }>(rows: T[]) => {
const map = new Map<string, T>();
for (const row of rows) {
const existing = map.get(row.key);
if (!existing) {
map.set(row.key, structuredClone(row));
continue;
}
existing.values = {
...existing.values,
...row.values
};
}
return [...map.values()];
};
return {
...next,
periods,
statementRows: next.statementRows && base.statementRows
? {
faithful: mergeRows([...base.statementRows.faithful, ...next.statementRows.faithful]),
standardized: mergeRows([...base.statementRows.standardized, ...next.statementRows.standardized])
}
: next.statementRows,
statementDetails: mergeDetailMaps(base.statementDetails, next.statementDetails),
ratioRows: next.ratioRows && base.ratioRows ? mergeRows([...base.ratioRows, ...next.ratioRows]) : next.ratioRows,
kpiRows: next.kpiRows && base.kpiRows ? mergeRows([...base.kpiRows, ...next.kpiRows]) : next.kpiRows,
trendSeries: next.trendSeries,
categories: next.categories,
dimensionBreakdown: next.dimensionBreakdown ?? base.dimensionBreakdown
};
}
function ChartFrame({ children }: { children: React.ReactNode }) {
const containerRef = useRef<HTMLDivElement | null>(null);
const [ready, setReady] = useState(false);
@@ -1185,11 +1101,11 @@ function FinancialsPageContent() {
{isDerivedRow(selectedRow) ? (
<div className="rounded-lg border border-[color:var(--line-weak)] bg-[color:var(--panel-soft)] px-3 py-2">
<p className="text-[color:var(--terminal-muted)]">Source Row Keys</p>
<p className="font-semibold text-[color:var(--terminal-bright)]">{selectedRow.sourceRowKeys.join(', ') || 'n/a'}</p>
<p className="font-semibold text-[color:var(--terminal-bright)]">{(selectedRow.sourceRowKeys ?? []).join(', ') || 'n/a'}</p>
<p className="mt-2 text-[color:var(--terminal-muted)]">Source Concepts</p>
<p className="font-semibold text-[color:var(--terminal-bright)]">{selectedRow.sourceConcepts.join(', ') || 'n/a'}</p>
<p className="font-semibold text-[color:var(--terminal-bright)]">{(selectedRow.sourceConcepts ?? []).join(', ') || 'n/a'}</p>
<p className="mt-2 text-[color:var(--terminal-muted)]">Source Fact IDs</p>
<p className="font-semibold text-[color:var(--terminal-bright)]">{selectedRow.sourceFactIds.join(', ') || 'n/a'}</p>
<p className="font-semibold text-[color:var(--terminal-bright)]">{(selectedRow.sourceFactIds ?? []).join(', ') || 'n/a'}</p>
</div>
) : null}
@@ -1271,7 +1187,7 @@ function FinancialsPageContent() {
surfaceKind
})}</td>
<td>{check.status}</td>
<td>{check.evidencePages.join(', ') || 'n/a'}</td>
<td>{(check.evidencePages ?? []).join(', ') || 'n/a'}</td>
</tr>
))}
</tbody>