Prioritize SEC financials for 10-K/10-Q and keep other filings qualitative

This commit is contained in:
2026-03-01 00:37:47 -05:00
parent 953d7c0099
commit 2a5b548d89
11 changed files with 773 additions and 149 deletions

View File

@@ -1,5 +1,6 @@
import { describe, expect, it, mock } from 'bun:test';
import {
fetchFilingMetricsForFilings,
fetchPrimaryFilingText,
normalizeSecDocumentText,
resolvePrimaryFilingUrl,
@@ -81,4 +82,111 @@ describe('sec filing text helpers', () => {
expect(result?.truncated).toBe(true);
expect(result?.text.length).toBeLessThanOrEqual(1_000);
});
it('maps SEC companyfacts metrics to each filing by accession', async () => {
const fetchMock = mock(async (_input: RequestInfo | URL, _init?: RequestInit) => {
return new Response(JSON.stringify({
facts: {
'us-gaap': {
Revenues: {
units: {
USD: [
{ accn: '0000320193-25-000010', val: 101_000, filed: '2025-11-01', form: '10-Q' },
{ accn: '0000320193-25-000020', val: 111_000, filed: '2026-02-01', form: '10-Q' }
]
}
},
NetIncomeLoss: {
units: {
USD: [
{ accn: '0000320193-25-000010', val: 21_000, filed: '2025-11-01', form: '10-Q' },
{ accn: '0000320193-25-000020', val: 25_000, filed: '2026-02-01', form: '10-Q' }
]
}
},
Assets: {
units: {
USD: [
{ accn: '0000320193-25-000010', val: 405_000, filed: '2025-11-01', form: '10-Q' },
{ accn: '0000320193-25-000020', val: 410_000, filed: '2026-02-01', form: '10-Q' }
]
}
},
CashAndCashEquivalentsAtCarryingValue: {
units: {
USD: [
{ accn: '0000320193-25-000010', val: 65_000, filed: '2025-11-01', form: '10-Q' },
{ accn: '0000320193-25-000020', val: 70_000, filed: '2026-02-01', form: '10-Q' }
]
}
},
LongTermDebt: {
units: {
USD: [
{ accn: '0000320193-25-000010', val: 95_000, filed: '2025-11-01', form: '10-Q' },
{ accn: '0000320193-25-000020', val: 98_000, filed: '2026-02-01', form: '10-Q' }
]
}
}
}
}
}), { status: 200 });
}) as unknown as typeof fetch;
const originalFetch = globalThis.fetch;
globalThis.fetch = fetchMock;
try {
const map = await fetchFilingMetricsForFilings('0000320193', 'AAPL', [
{
accessionNumber: '0000320193-25-000010',
filingDate: '2025-11-01',
filingType: '10-Q'
},
{
accessionNumber: '0000320193-25-000020',
filingDate: '2026-02-01',
filingType: '10-Q'
}
]);
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(map.get('0000320193-25-000010')?.revenue).toBe(101_000);
expect(map.get('0000320193-25-000010')?.netIncome).toBe(21_000);
expect(map.get('0000320193-25-000020')?.revenue).toBe(111_000);
expect(map.get('0000320193-25-000020')?.cash).toBe(70_000);
} finally {
globalThis.fetch = originalFetch;
}
});
it('returns null-valued metrics when companyfacts lookup fails', async () => {
const fetchMock = mock(async (_input: RequestInfo | URL, _init?: RequestInit) => {
return new Response('error', { status: 500 });
}) as unknown as typeof fetch;
const originalFetch = globalThis.fetch;
globalThis.fetch = fetchMock;
try {
const map = await fetchFilingMetricsForFilings('0000320193', 'AAPL', [
{
accessionNumber: '0000320193-25-000010',
filingDate: '2025-11-01',
filingType: '10-Q'
}
]);
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(map.get('0000320193-25-000010')).toEqual({
revenue: null,
netIncome: null,
totalAssets: null,
cash: null,
debt: null
});
} finally {
globalThis.fetch = originalFetch;
}
});
});