393 lines
11 KiB
TypeScript
393 lines
11 KiB
TypeScript
import { describe, expect, it } from "bun:test";
|
|
import { __filingTaxonomyInternals } from "./filing-taxonomy";
|
|
|
|
describe("filing taxonomy snapshot normalization", () => {
|
|
it("normalizes legacy snake_case nested snapshot payloads in toSnapshotRecord", () => {
|
|
const record = __filingTaxonomyInternals.toSnapshotRecord({
|
|
id: 1,
|
|
filing_id: 10,
|
|
ticker: "MSFT",
|
|
filing_date: "2026-01-28",
|
|
filing_type: "10-Q",
|
|
parse_status: "ready",
|
|
parse_error: null,
|
|
source: "xbrl_instance",
|
|
parser_engine: "fiscal-xbrl",
|
|
parser_version: "0.1.0",
|
|
taxonomy_regime: "us-gaap",
|
|
fiscal_pack: "core",
|
|
periods: [
|
|
{
|
|
id: "fy-2025",
|
|
filing_id: 10,
|
|
accession_number: "0001",
|
|
filing_date: "2026-01-28",
|
|
period_start: "2025-01-01",
|
|
period_end: "2025-12-31",
|
|
filing_type: "10-Q",
|
|
period_label: "FY 2025",
|
|
},
|
|
],
|
|
faithful_rows: {
|
|
income: [
|
|
{
|
|
key: "revenue",
|
|
label: "Revenue",
|
|
concept_key: "us-gaap:Revenue",
|
|
qname: "us-gaap:Revenue",
|
|
namespace_uri: "http://fasb.org/us-gaap/2025",
|
|
local_name: "Revenue",
|
|
is_extension: false,
|
|
statement: "income",
|
|
role_uri: "income",
|
|
order: 10,
|
|
depth: 0,
|
|
parent_key: null,
|
|
values: { "fy-2025": 10 },
|
|
units: { "fy-2025": "iso4217:USD" },
|
|
has_dimensions: false,
|
|
source_fact_ids: [1],
|
|
},
|
|
],
|
|
balance: [],
|
|
cash_flow: [],
|
|
equity: [],
|
|
comprehensive_income: [],
|
|
},
|
|
statement_rows: null,
|
|
surface_rows: {
|
|
income: [
|
|
{
|
|
key: "revenue",
|
|
label: "Revenue",
|
|
category: "revenue",
|
|
template_section: "revenue",
|
|
order: 10,
|
|
unit: "currency",
|
|
values: { "fy-2025": 10 },
|
|
source_concepts: ["us-gaap:Revenue"],
|
|
source_row_keys: ["revenue"],
|
|
source_fact_ids: [1],
|
|
formula_key: null,
|
|
has_dimensions: false,
|
|
resolved_source_row_keys: { "fy-2025": "revenue" },
|
|
statement: "income",
|
|
detail_count: 1,
|
|
resolution_method: "direct",
|
|
confidence: "high",
|
|
warning_codes: ["legacy_surface"],
|
|
},
|
|
],
|
|
balance: [],
|
|
cash_flow: [],
|
|
equity: [],
|
|
comprehensive_income: [],
|
|
},
|
|
detail_rows: {
|
|
income: {
|
|
revenue: [
|
|
{
|
|
key: "revenue_detail",
|
|
parent_surface_key: "revenue",
|
|
label: "Revenue Detail",
|
|
concept_key: "us-gaap:RevenueDetail",
|
|
qname: "us-gaap:RevenueDetail",
|
|
namespace_uri: "http://fasb.org/us-gaap/2025",
|
|
local_name: "RevenueDetail",
|
|
unit: "iso4217:USD",
|
|
values: { "fy-2025": 10 },
|
|
source_fact_ids: [2],
|
|
is_extension: false,
|
|
dimensions_summary: ["region:americas"],
|
|
residual_flag: false,
|
|
},
|
|
],
|
|
},
|
|
balance: {},
|
|
cash_flow: {},
|
|
equity: {},
|
|
comprehensive_income: {},
|
|
},
|
|
kpi_rows: [
|
|
{
|
|
key: "cloud_growth",
|
|
label: "Cloud Growth",
|
|
category: "operating_kpi",
|
|
unit: "percent",
|
|
order: 10,
|
|
segment: null,
|
|
axis: null,
|
|
member: null,
|
|
values: { "fy-2025": 0.25 },
|
|
source_concepts: ["msft:CloudGrowth"],
|
|
source_fact_ids: [3],
|
|
provenance_type: "taxonomy",
|
|
has_dimensions: false,
|
|
},
|
|
],
|
|
computed_definitions: [
|
|
{
|
|
key: "gross_margin",
|
|
label: "Gross Margin",
|
|
category: "margins",
|
|
order: 10,
|
|
unit: "percent",
|
|
computation: {
|
|
type: "ratio",
|
|
numerator: "gross_profit",
|
|
denominator: "revenue",
|
|
},
|
|
supported_cadences: ["annual", "quarterly"],
|
|
requires_external_data: [],
|
|
},
|
|
],
|
|
derived_metrics: null,
|
|
validation_result: null,
|
|
normalization_summary: {
|
|
surface_row_count: 1,
|
|
detail_row_count: 1,
|
|
kpi_row_count: 1,
|
|
unmapped_row_count: 0,
|
|
material_unmapped_row_count: 0,
|
|
residual_primary_count: 0,
|
|
residual_disclosure_count: 0,
|
|
unsupported_concept_count: 0,
|
|
issuer_overlay_match_count: 0,
|
|
warnings: ["legacy_warning"],
|
|
},
|
|
facts_count: 3,
|
|
concepts_count: 3,
|
|
dimensions_count: 1,
|
|
created_at: "2026-01-28T00:00:00.000Z",
|
|
updated_at: "2026-01-28T00:00:00.000Z",
|
|
} as never);
|
|
|
|
expect(record.periods[0]).toMatchObject({
|
|
filingId: 10,
|
|
accessionNumber: "0001",
|
|
filingDate: "2026-01-28",
|
|
periodStart: "2025-01-01",
|
|
periodEnd: "2025-12-31",
|
|
periodLabel: "FY 2025",
|
|
});
|
|
expect(record.faithful_rows.income[0]).toMatchObject({
|
|
conceptKey: "us-gaap:Revenue",
|
|
namespaceUri: "http://fasb.org/us-gaap/2025",
|
|
localName: "Revenue",
|
|
roleUri: "income",
|
|
parentKey: null,
|
|
hasDimensions: false,
|
|
sourceFactIds: [1],
|
|
});
|
|
expect(record.surface_rows.income[0]).toMatchObject({
|
|
templateSection: "revenue",
|
|
sourceConcepts: ["us-gaap:Revenue"],
|
|
sourceRowKeys: ["revenue"],
|
|
sourceFactIds: [1],
|
|
formulaKey: null,
|
|
hasDimensions: false,
|
|
resolvedSourceRowKeys: { "fy-2025": "revenue" },
|
|
detailCount: 1,
|
|
resolutionMethod: "direct",
|
|
warningCodes: ["legacy_surface"],
|
|
});
|
|
expect(record.detail_rows.income.revenue?.[0]).toMatchObject({
|
|
parentSurfaceKey: "revenue",
|
|
conceptKey: "us-gaap:RevenueDetail",
|
|
namespaceUri: "http://fasb.org/us-gaap/2025",
|
|
sourceFactIds: [2],
|
|
dimensionsSummary: ["region:americas"],
|
|
residualFlag: false,
|
|
});
|
|
expect(record.kpi_rows[0]).toMatchObject({
|
|
sourceConcepts: ["msft:CloudGrowth"],
|
|
sourceFactIds: [3],
|
|
provenanceType: "taxonomy",
|
|
hasDimensions: false,
|
|
});
|
|
expect(record.computed_definitions).toEqual([
|
|
{
|
|
key: "gross_margin",
|
|
label: "Gross Margin",
|
|
category: "margins",
|
|
order: 10,
|
|
unit: "percent",
|
|
computation: {
|
|
type: "ratio",
|
|
numerator: "gross_profit",
|
|
denominator: "revenue",
|
|
},
|
|
supported_cadences: ["annual", "quarterly"],
|
|
requires_external_data: [],
|
|
},
|
|
]);
|
|
expect(record.normalization_summary).toEqual({
|
|
surfaceRowCount: 1,
|
|
detailRowCount: 1,
|
|
kpiRowCount: 1,
|
|
unmappedRowCount: 0,
|
|
materialUnmappedRowCount: 0,
|
|
residualPrimaryCount: 0,
|
|
residualDisclosureCount: 0,
|
|
unsupportedConceptCount: 0,
|
|
issuerOverlayMatchCount: 0,
|
|
warnings: ["legacy_warning"],
|
|
});
|
|
});
|
|
|
|
it("keeps mixed camelCase and snake_case payloads compatible", () => {
|
|
const normalized =
|
|
__filingTaxonomyInternals.normalizeFilingTaxonomySnapshotPayload({
|
|
periods: [
|
|
{
|
|
id: "fy-2025",
|
|
filingId: 10,
|
|
accessionNumber: "0001",
|
|
filingDate: "2026-01-28",
|
|
periodStart: "2025-01-01",
|
|
periodEnd: "2025-12-31",
|
|
filingType: "10-K",
|
|
periodLabel: "FY 2025",
|
|
},
|
|
],
|
|
faithful_rows: {
|
|
income: [
|
|
{
|
|
key: "revenue",
|
|
label: "Revenue",
|
|
conceptKey: "us-gaap:Revenue",
|
|
qname: "us-gaap:Revenue",
|
|
namespaceUri: "http://fasb.org/us-gaap/2025",
|
|
localName: "Revenue",
|
|
isExtension: false,
|
|
statement: "income",
|
|
roleUri: "income",
|
|
order: 10,
|
|
depth: 0,
|
|
parentKey: null,
|
|
values: { "fy-2025": 10 },
|
|
units: { "fy-2025": "iso4217:USD" },
|
|
hasDimensions: false,
|
|
sourceFactIds: [1],
|
|
},
|
|
],
|
|
balance: [],
|
|
cash_flow: [],
|
|
equity: [],
|
|
comprehensive_income: [],
|
|
},
|
|
statement_rows: null,
|
|
surface_rows: {
|
|
income: [
|
|
{
|
|
key: "revenue",
|
|
label: "Revenue",
|
|
category: "revenue",
|
|
order: 10,
|
|
unit: "currency",
|
|
values: { "fy-2025": 10 },
|
|
source_concepts: ["us-gaap:Revenue"],
|
|
source_row_keys: ["revenue"],
|
|
source_fact_ids: [1],
|
|
formula_key: null,
|
|
has_dimensions: false,
|
|
resolved_source_row_keys: { "fy-2025": "revenue" },
|
|
},
|
|
],
|
|
balance: [],
|
|
cash_flow: [],
|
|
equity: [],
|
|
comprehensive_income: [],
|
|
},
|
|
detail_rows: {
|
|
income: {
|
|
revenue: [
|
|
{
|
|
key: "revenue_detail",
|
|
parentSurfaceKey: "revenue",
|
|
label: "Revenue Detail",
|
|
conceptKey: "us-gaap:RevenueDetail",
|
|
qname: "us-gaap:RevenueDetail",
|
|
namespaceUri: "http://fasb.org/us-gaap/2025",
|
|
localName: "RevenueDetail",
|
|
unit: "iso4217:USD",
|
|
values: { "fy-2025": 10 },
|
|
sourceFactIds: [2],
|
|
isExtension: false,
|
|
dimensionsSummary: [],
|
|
residualFlag: false,
|
|
},
|
|
],
|
|
},
|
|
balance: {},
|
|
cash_flow: {},
|
|
equity: {},
|
|
comprehensive_income: {},
|
|
},
|
|
kpi_rows: [],
|
|
computed_definitions: [
|
|
{
|
|
key: "revenue_yoy",
|
|
label: "Revenue YoY",
|
|
category: "growth",
|
|
order: 20,
|
|
unit: "percent",
|
|
computation: {
|
|
type: "yoy_growth",
|
|
source: "revenue",
|
|
},
|
|
supportedCadences: ["annual"],
|
|
requiresExternalData: [],
|
|
},
|
|
],
|
|
normalization_summary: {
|
|
surfaceRowCount: 1,
|
|
detail_row_count: 1,
|
|
kpiRowCount: 0,
|
|
unmapped_row_count: 0,
|
|
materialUnmappedRowCount: 0,
|
|
residualPrimaryCount: 0,
|
|
residualDisclosureCount: 0,
|
|
unsupportedConceptCount: 0,
|
|
issuerOverlayMatchCount: 0,
|
|
warnings: [],
|
|
},
|
|
});
|
|
|
|
expect(normalized.periods[0]?.filingId).toBe(10);
|
|
expect(normalized.surface_rows.income[0]?.sourceConcepts).toEqual([
|
|
"us-gaap:Revenue",
|
|
]);
|
|
expect(normalized.detail_rows.income.revenue?.[0]?.parentSurfaceKey).toBe(
|
|
"revenue",
|
|
);
|
|
expect(normalized.normalization_summary).toEqual({
|
|
surfaceRowCount: 1,
|
|
detailRowCount: 1,
|
|
kpiRowCount: 0,
|
|
unmappedRowCount: 0,
|
|
materialUnmappedRowCount: 0,
|
|
residualPrimaryCount: 0,
|
|
residualDisclosureCount: 0,
|
|
unsupportedConceptCount: 0,
|
|
issuerOverlayMatchCount: 0,
|
|
warnings: [],
|
|
});
|
|
expect(normalized.computed_definitions).toEqual([
|
|
{
|
|
key: "revenue_yoy",
|
|
label: "Revenue YoY",
|
|
category: "growth",
|
|
order: 20,
|
|
unit: "percent",
|
|
computation: {
|
|
type: "yoy_growth",
|
|
source: "revenue",
|
|
},
|
|
supported_cadences: ["annual"],
|
|
requires_external_data: [],
|
|
},
|
|
]);
|
|
});
|
|
});
|