UNPKG

sec-edgar-toolkit

Version:

Open source toolkit to facilitate working with the SEC EDGAR database

377 lines 15 kB
"use strict"; /** * XBRL instance class providing comprehensive financial data analysis */ Object.defineProperty(exports, "__esModule", { value: true }); exports.XBRLInstance = void 0; class XBRLInstance { constructor(filing, api) { // Cache for XBRL data this._facts = null; this._usGaapFacts = null; this._deiFacts = null; this._api = api || filing.api; this.filing = filing; this.cik = filing.cik; } /** * Get all XBRL facts for the company */ async getFacts() { if (!this._facts) { this._facts = await this._api.xbrl.getCompanyFacts(this.cik); } return this._facts; } /** * Get US-GAAP facts */ async getUsGaap() { if (!this._usGaapFacts) { const facts = await this.getFacts(); this._usGaapFacts = facts?.facts?.['us-gaap'] || {}; } return this._usGaapFacts; } /** * Get DEI (Document Entity Information) facts */ async getDei() { if (!this._deiFacts) { const facts = await this.getFacts(); this._deiFacts = facts?.facts?.dei || {}; } return this._deiFacts; } /** * Query XBRL facts with filtering */ async query(options = {}) { const { concept, taxonomy = 'us-gaap', unit, period } = options; const results = []; // Get facts for the specified taxonomy let taxonomyFacts; if (taxonomy === 'us-gaap') { taxonomyFacts = await this.getUsGaap(); } else if (taxonomy === 'dei') { taxonomyFacts = await this.getDei(); } else { const facts = await this.getFacts(); taxonomyFacts = facts?.facts?.[taxonomy] || {}; } // If concept is specified, filter to that concept if (concept) { if (concept in taxonomyFacts) { const conceptData = taxonomyFacts[concept]; results.push(...this.processConceptData(concept, conceptData, unit, period)); } } else { // Query all concepts for (const [conceptName, conceptData] of Object.entries(taxonomyFacts)) { results.push(...this.processConceptData(conceptName, conceptData, unit, period)); } } return results; } /** * Process concept data and apply filters */ processConceptData(conceptName, conceptData, unitFilter, periodFilter) { const results = []; const units = conceptData.units || {}; for (const [unit, unitData] of Object.entries(units)) { // Apply unit filter if (unitFilter && unit !== unitFilter) { continue; } if (Array.isArray(unitData)) { for (const fact of unitData) { // Apply period filter if (periodFilter) { // Check if the filter matches the end date or period fields const matchesEndDate = fact.end === periodFilter; const matchesInstant = fact.instant === periodFilter; const factPeriod = fact.fy || fact.fp || fact.frame || ''; const matchesPeriod = String(factPeriod).includes(periodFilter); if (!matchesEndDate && !matchesInstant && !matchesPeriod) { continue; } } // Create standardized fact record const factRecord = { concept: conceptName, taxonomy: 'us-gaap', value: fact.val, unit: unit, period: fact.frame || `FY${fact.fy || ''}${fact.fp || ''}`, fiscal_year: fact.fy, fiscal_period: fact.fp, start_date: fact.start, end_date: fact.end, filed: fact.filed, accession_number: fact.accn, form: fact.form, }; results.push(factRecord); } } } return results; } /** * Find and extract a specific financial statement */ async findStatement(statementType, period) { switch (statementType) { case 'balance_sheet': return await this.extractBalanceSheet(period); case 'income_statement': return await this.extractIncomeStatement(period); case 'cash_flow': return await this.extractCashFlowStatement(period); default: console.warn(`Unknown statement type: ${statementType}`); return null; } } /** * Extract balance sheet data */ async extractBalanceSheet(period) { const concepts = [ 'Assets', 'AssetsCurrent', 'AssetsNoncurrent', 'Liabilities', 'LiabilitiesCurrent', 'LiabilitiesNoncurrent', 'StockholdersEquity', 'RetainedEarningsAccumulatedDeficit' ]; const statementData = {}; for (const concept of concepts) { const facts = await this.query({ concept, unit: 'USD', period }); if (facts.length > 0) { // Get most recent fact const latestFact = facts.reduce((prev, current) => (current.filed || '') > (prev.filed || '') ? current : prev); statementData[concept] = latestFact; } } return { statement_type: 'balance_sheet', period, data: statementData, }; } /** * Extract income statement data */ async extractIncomeStatement(period) { const concepts = [ 'Revenues', 'RevenueFromContractWithCustomerExcludingAssessedTax', 'CostOfRevenue', 'GrossProfit', 'OperatingIncomeLoss', 'IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest', 'NetIncomeLoss', 'EarningsPerShareBasic', 'EarningsPerShareDiluted' ]; const statementData = {}; for (const concept of concepts) { const facts = await this.query({ concept, unit: 'USD', period }); if (facts.length > 0) { // Get most recent fact const latestFact = facts.reduce((prev, current) => (current.filed || '') > (prev.filed || '') ? current : prev); statementData[concept] = latestFact; } } return { statement_type: 'income_statement', period, data: statementData, }; } /** * Extract cash flow statement data */ async extractCashFlowStatement(period) { const concepts = [ 'NetCashProvidedByUsedInOperatingActivities', 'NetCashProvidedByUsedInInvestingActivities', 'NetCashProvidedByUsedInFinancingActivities', 'CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalents' ]; const statementData = {}; for (const concept of concepts) { const facts = await this.query({ concept, unit: 'USD', period }); if (facts.length > 0) { // Get most recent fact const latestFact = facts.reduce((prev, current) => (current.filed || '') > (prev.filed || '') ? current : prev); statementData[concept] = latestFact; } } return { statement_type: 'cash_flow', period, data: statementData, }; } /** * Get structured balance sheet */ async getBalanceSheet(period) { const statement = await this.extractBalanceSheet(period); const data = statement.data; // Helper to convert XbrlFact to BalanceSheetItem const toBalanceSheetItem = (fact) => ({ label: fact.concept, value: typeof fact.value === 'number' ? fact.value : parseFloat(fact.value), units: fact.unit, period: fact.period, filed: new Date(fact.filed || '') }); const assets = { current_assets: data.AssetsCurrent ? [toBalanceSheetItem(data.AssetsCurrent)] : [], non_current_assets: data.AssetsNoncurrent ? [toBalanceSheetItem(data.AssetsNoncurrent)] : [], total_assets: data.Assets ? toBalanceSheetItem(data.Assets) : undefined }; const liabilities = { current_liabilities: data.LiabilitiesCurrent ? [toBalanceSheetItem(data.LiabilitiesCurrent)] : [], non_current_liabilities: data.LiabilitiesNoncurrent ? [toBalanceSheetItem(data.LiabilitiesNoncurrent)] : [], total_liabilities: data.Liabilities ? toBalanceSheetItem(data.Liabilities) : undefined }; const equity = { total_equity: data.StockholdersEquity ? toBalanceSheetItem(data.StockholdersEquity) : undefined, retained_earnings: data.RetainedEarningsAccumulatedDeficit ? toBalanceSheetItem(data.RetainedEarningsAccumulatedDeficit) : undefined }; return { assets, liabilities, equity }; } /** * Get structured income statement */ async getIncomeStatement(period) { const statement = await this.extractIncomeStatement(period); const data = statement.data; // Helper to convert XbrlFact to IncomeStatementItem const toIncomeStatementItem = (fact) => ({ label: fact.concept, value: typeof fact.value === 'number' ? fact.value : parseFloat(fact.value), units: fact.unit, period: fact.period, filed: new Date(fact.filed || '') }); return { revenue: data.Revenues || data.RevenueFromContractWithCustomerExcludingAssessedTax ? toIncomeStatementItem(data.Revenues || data.RevenueFromContractWithCustomerExcludingAssessedTax) : undefined, gross_profit: data.GrossProfit ? toIncomeStatementItem(data.GrossProfit) : undefined, operating_income: data.OperatingIncomeLoss ? toIncomeStatementItem(data.OperatingIncomeLoss) : undefined, net_income: data.NetIncomeLoss ? toIncomeStatementItem(data.NetIncomeLoss) : undefined, earnings_per_share: data.EarningsPerShareBasic ? toIncomeStatementItem(data.EarningsPerShareBasic) : undefined, operating_expenses: [] }; } /** * Get structured cash flow statement */ async getCashFlowStatement(period) { const statement = await this.extractCashFlowStatement(period); const data = statement.data; // Helper to convert XbrlFact to CashFlowItem const toCashFlowItem = (fact) => ({ label: fact.concept, value: typeof fact.value === 'number' ? fact.value : parseFloat(fact.value), units: fact.unit, period: fact.period, filed: new Date(fact.filed || '') }); return { operating_activities: data.NetCashProvidedByUsedInOperatingActivities ? [toCashFlowItem(data.NetCashProvidedByUsedInOperatingActivities)] : [], investing_activities: data.NetCashProvidedByUsedInInvestingActivities ? [toCashFlowItem(data.NetCashProvidedByUsedInInvestingActivities)] : [], financing_activities: data.NetCashProvidedByUsedInFinancingActivities ? [toCashFlowItem(data.NetCashProvidedByUsedInFinancingActivities)] : [], net_cash_flow: data.CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalents ? toCashFlowItem(data.CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalents) : undefined }; } /** * Get a single value for a specific concept */ async getConceptValue(concept, taxonomy = 'us-gaap', unit = 'USD', period) { const facts = await this.query({ concept, taxonomy, unit, period }); if (facts.length > 0) { // Return the most recent value const latestFact = facts.reduce((prev, current) => (current.filed || '') > (prev.filed || '') ? current : prev); return typeof latestFact.value === 'number' ? latestFact.value : parseFloat(latestFact.value); } return null; } /** * Get all facts for a specific concept */ async getFactsByConcept(concept, taxonomy = 'us-gaap') { const facts = await this.getFacts(); const taxonomyFacts = facts?.facts?.[taxonomy]; if (!taxonomyFacts || !taxonomyFacts[concept]) { return []; } const conceptData = taxonomyFacts[concept]; const results = []; // Process all units for (const [unit, values] of Object.entries(conceptData.units || {})) { if (Array.isArray(values)) { for (const value of values) { results.push({ concept, taxonomy, value: value.val, unit, period: value.end || value.instant || '', fiscal_year: value.fy, fiscal_period: value.fp, start_date: value.start, end_date: value.end, filed: value.filed, accession_number: value.accn, form: value.form, }); } } } return results; } /** * List all available concepts in a taxonomy */ async listConcepts(taxonomy = 'us-gaap') { let taxonomyFacts; if (taxonomy === 'us-gaap') { taxonomyFacts = await this.getUsGaap(); } else if (taxonomy === 'dei') { taxonomyFacts = await this.getDei(); } else { const facts = await this.getFacts(); taxonomyFacts = facts?.facts?.[taxonomy] || {}; } return Object.keys(taxonomyFacts); } /** * Convert XBRL data to plain object */ async toObject(options = {}) { const facts = await this.query(options); return { metadata: { cik: this.cik, filing_date: this.filing.filingDate, form_type: this.filing.formType, }, facts: facts, }; } toString() { return `XBRL instance for ${this.filing.formType} filing (CIK: ${this.cik})`; } } exports.XBRLInstance = XBRLInstance; //# sourceMappingURL=xbrl.js.map