@@ -4,6 +4,15 @@ import type {
FinancialUnit ,
RatioRow
} from '@/lib/types' ;
import {
type ComputedDefinition ,
type SurfaceDefinition ,
ALL_COMPUTED ,
INCOME_SURFACES ,
BALANCE_SURFACES ,
CASH_FLOW_SURFACES ,
RATIO_CATEGORIES
} from '@/lib/generated' ;
export type GraphableFinancialSurfaceKind = Extract <
FinancialSurfaceKind ,
@@ -16,8 +25,6 @@ export type StatementMetricDefinition = {
category : string ;
order : number ;
unit : FinancialUnit ;
localNames? : readonly string [ ] ;
labelIncludes? : readonly string [ ] ;
} ;
export type RatioMetricDefinition = {
@@ -37,113 +44,44 @@ export const GRAPHABLE_FINANCIAL_SURFACES: readonly GraphableFinancialSurfaceKin
'ratios'
] as const ;
export const INCOME_STATEMENT_METRIC_DEFINITIONS : StatementMetricDefinition[ ] = [
{ key : 'revenue' , label : 'Revenue' , category : 'revenue' , order : 10 , unit : 'currency' , localNames : [ 'RevenueFromContractWithCustomerExcludingAssessedTax' , 'Revenues' , 'SalesRevenueNet' , 'TotalRevenuesAndOtherIncome' ] , labelIncludes : [ 'revenue' , 'sales' ] } ,
{ key : 'cost_of_revenue' , label : 'Cost of Revenue' , category : 'expense' , order : 20 , unit : 'currency' , localNames : [ 'CostOfRevenue' , 'CostOfGoodsSold' , 'CostOfSales' , 'CostOfProductsSold' , 'CostOfServices' ] , labelIncludes : [ 'cost of revenue' , 'cost of sales' , 'cost of goods sold' ] } ,
{ key : 'gross_profit' , label : 'Gross Profit' , category : 'profit' , order : 30 , unit : 'currency' , localNames : [ 'GrossProfit' ] } ,
{ key : 'gross_margin' , label : 'Gross Margin' , category : 'margin' , order : 40 , unit : 'percent' , labelIncludes : [ 'gross margin' ] } ,
{ key : 'operating_expenses' , label : 'Operating Expenses' , category : 'opex' , order : 50 , unit : 'currency' , localNames : [ 'OperatingExpenses' ] , labelIncludes : [ 'operating expenses' ] } ,
{ key : 'selling_general_and_administrative' , label : 'Selling, General & Administrative' , category : 'opex' , order : 60 , unit : 'currency' , localNames : [ 'SellingGeneralAndAdministrativeExpense' ] , labelIncludes : [ 'selling, general' , 'selling general' ] } ,
{ key : 'research_and_development' , label : 'Research Expense' , category : 'opex' , order : 70 , unit : 'currency' , localNames : [ 'ResearchAndDevelopmentExpense' ] , labelIncludes : [ 'research and development' , 'research expense' ] },
{ key : 'other_operating_expense' , label : 'Other Expense' , category : 'opex' , order : 80 , unit : 'currency' , localNames : [ 'OtherOperatingExpense' ] , labelIncludes : [ 'other operating expense' , 'other expense' ] } ,
{ key : 'operating_income' , label : 'Operating Income' , category : 'profit' , order : 90 , unit : 'currency' , localNames : [ 'OperatingIncomeLoss' , 'IncomeLossFromOperations' ] , labelIncludes : [ 'operating income' ] } ,
{ key : 'sales_and_marketing' , label : 'Sales & Marketing' , category : 'opex' , order : 100 , unit : 'currency' , localNames : [ 'SellingAndMarketingExpense' ] , labelIncludes : [ 'sales and marketing' , 'selling and marketing' ] } ,
{ key : 'general_and_administrative' , label : 'General & Administrative' , category : 'opex' , order : 110 , unit : 'currency' , localNames : [ 'GeneralAndAdministrativeExpense' ] , labelIncludes : [ 'general and administrative' ] } ,
{ key : 'operating_margin' , label : 'Operating Margin' , category : 'margin' , order : 120 , unit : 'percent' , labelIncludes : [ 'operating margin' ] } ,
{ key : 'interest_income' , label : 'Interest Income' , category : 'non_operating' , order : 130 , unit : 'currency' , localNames : [ 'InterestIncomeExpenseNonoperatingNet' , 'InterestIncomeOther' , 'InvestmentIncomeInterest' ] , labelIncludes : [ 'interest income' ] } ,
{ key : 'interest_expense' , label : 'Interest Expense' , category : 'non_operating' , order : 140 , unit : 'currency' , localNames : [ 'InterestExpense' , 'InterestAndDebtExpense' ] , labelIncludes : [ 'interest expense' ] } ,
{ key : 'other_non_operating_income' , label : 'Other Non-Operating Income' , category : 'non_operating' , order : 150 , unit : 'currency' , localNames : [ 'OtherNonoperatingIncomeExpense' , 'NonoperatingIncomeExpense' ] , labelIncludes : [ 'other non-operating' , 'non-operating income' ] } ,
{ key : 'pretax_income' , label : 'Pretax Income' , category : 'profit' , order : 160 , unit : 'currency' , localNames : [ 'IncomeBeforeTaxExpenseBenefit' , 'PretaxIncome' ] , labelIncludes : [ 'income before taxes' , 'pretax income' ] } ,
{ key : 'income_tax_expense' , label : 'Income Tax Expense' , category : 'tax' , order : 170 , unit : 'currency' , localNames : [ 'IncomeTaxExpenseBenefit' ] , labelIncludes : [ 'income tax' ] } ,
{ key : 'effective_tax_rate' , label : 'Effective Tax Rate' , category : 'tax' , order : 180 , unit : 'percent' , labelIncludes : [ 'effective tax rate' ] } ,
{ key : 'net_income' , label : 'Net Income' , category : 'profit' , order : 190 , unit : 'currency' , localNames : [ 'NetIncomeLoss' , 'ProfitLoss' ] , labelIncludes : [ 'net income' ] } ,
{ key : 'diluted_eps' , label : 'Diluted EPS' , category : 'per_share' , order : 200 , unit : 'currency' , localNames : [ 'EarningsPerShareDiluted' , 'DilutedEarningsPerShare' ] , labelIncludes : [ 'diluted eps' , 'diluted earnings per share' ] } ,
{ key : 'basic_eps' , label : 'Basic EPS' , category : 'per_share' , order : 210 , unit : 'currency' , localNames : [ 'EarningsPerShareBasic' , 'BasicEarningsPerShare' ] , labelIncludes : [ 'basic eps' , 'basic earnings per share' ] } ,
{ key : 'diluted_shares' , label : 'Diluted Shares' , category : 'shares' , order : 220 , unit : 'shares' , localNames : [ 'WeightedAverageNumberOfDilutedSharesOutstanding' , 'WeightedAverageNumberOfShareOutstandingDiluted' ] , labelIncludes : [ 'diluted shares' , 'weighted average diluted' ] } ,
{ key : 'basic_shares' , label : 'Basic Shares' , category : 'shares' , order : 230 , unit : 'shares' , localNames : [ 'WeightedAverageNumberOfSharesOutstandingBasic' , 'WeightedAverageNumberOfShareOutstandingBasicAndDiluted' ] , labelIncludes : [ 'basic shares' , 'weighted average basic' ] } ,
{ key : 'depreciation_and_amortization' , label : 'Depreciation & Amortization' , category : 'non_cash' , order : 240 , unit : 'currency' , localNames : [ 'DepreciationDepletionAndAmortization' , 'DepreciationAmortizationAndAccretionNet' , 'DepreciationAndAmortization' ] , labelIncludes : [ 'depreciation' , 'amortization' ] } ,
{ key : 'ebitda' , label : 'EBITDA' , category : 'profit' , order : 250 , unit : 'currency' , localNames : [ 'OperatingIncomeLoss' ] , labelIncludes : [ 'ebitda' ] } ,
{ key : 'stock_based_compensation' , label : 'Stock-Based Compensation' , category : 'non_cash' , order : 260 , unit : 'currency' , localNames : [ 'ShareBasedCompensation' , 'AllocatedShareBasedCompensationExpense' ] , labelIncludes : [ 'stock-based compensation' , 'share-based compensation' ] }
] as const satisfies StatementMetricDefinition [ ] ;
function surfaceToMetric ( surface : SurfaceDefinition ) : StatementMetricDefinition {
return {
key : surface.surface_key ,
label : surface.label ,
category : surface.category ,
order : surface.order ,
unit : surface.unit
} ;
}
export const BALANCE_SHEET_METRIC_DEFINITIONS : Statement MetricDefinition[ ] = [
{ key : 'cash_and_equivalents' , label : 'Cash & Equivalents' , category : 'asset' , order : 10 , unit : 'currency' , localNames : [ 'CashAndCashEquivalentsAtCarryingValue' , 'CashCashEquivalentsAndShortTermInvestments' , 'CashAndShortTermInvestments' ] , labelIncludes : [ 'cash and cash equivalents' ] } ,
{ key : 'short_term_investments' , label : 'Short-Term Investments' , category : 'asset' , order : 20 , unit : 'currency' , localNames : [ 'AvailableForSaleSecuritiesCurrent' , 'ShortTermInvestments' ] , labelIncludes : [ 'short-term investments' , 'marketable securities' ] } ,
{ key : 'accounts_receivable' , label : 'Accounts Receivable' , category : 'asset' , order : 30 , unit : 'currency' , localNames : [ 'AccountsReceivableNetCurrent' , 'ReceivablesNetCurrent' ] , labelIncludes : [ 'accounts receivable' ] } ,
{ key : 'inventory' , label : 'Inventory' , category : 'asset' , order : 40 , unit : 'currency' , localNames : [ 'InventoryNet' ] , labelIncludes : [ 'inventory' ] } ,
{ key : 'other_current_assets' , label : 'Other Current Assets' , category : 'asset' , order : 50 , unit : 'currency' , localNames : [ 'OtherAssetsCurrent' ] , labelIncludes : [ 'other current assets' ] } ,
{ key : 'current_assets' , label : 'Current Assets' , category : 'asset' , order : 60 , unit : 'currency' , localNames : [ 'AssetsCurrent' ] , labelIncludes : [ 'current assets' ] } ,
{ key : 'property_plant_equipment' , label : 'Property, Plant & Equipment' , category : 'asset' , order : 70 , unit : 'currency' , localNames : [ 'PropertyPlantAndEquipmentNet' ] , labelIncludes : [ 'property, plant and equipment' , 'property and equipment' ] } ,
{ key : 'goodwill' , label : 'Goodwill' , category : 'asset' , order : 80 , unit : 'currency' , localNames : [ 'Goodwill' ] , labelIncludes : [ 'goodwill' ] } ,
{ key : 'intangible_assets' , label : 'Intangible Assets' , category : 'asset' , order : 90 , unit : 'currency' , localNames : [ 'FiniteLivedIntangibleAssetsNet' , 'IndefiniteLivedIntangibleAssetsExcludingGoodwill' , 'IntangibleAssetsNetExcludingGoodwill' ] , labelIncludes : [ 'intangible assets' ] } ,
{ key : 'total_assets' , label : 'Total Assets' , category : 'asset' , order : 100 , unit : 'currency' , localNames : [ 'Assets' ] , labelIncludes : [ 'total assets' ] } ,
{ key : 'accounts_payable' , label : 'Accounts Payable' , category : 'liability' , order : 110 , unit : 'currency' , localNames : [ 'AccountsPayableCurrent' ] , labelIncludes : [ 'accounts payable' ] } ,
{ key : 'accrued_liabilities' , label : 'Accrued Liabilities' , category : 'liability' , order : 120 , unit : 'currency' , localNames : [ 'AccruedLiabilitiesCurrent' ] , labelIncludes : [ 'accrued liabilities' ] } ,
{ key : 'deferred_revenue_current' , label : 'Deferred Revenue, Current' , category : 'liability' , order : 130 , unit : 'currency' , localNames : [ 'ContractWithCustomerLiabilityCurrent' , 'DeferredRevenueCurrent' ] , labelIncludes : [ 'deferred revenue current' , 'current deferred revenue' ] } ,
{ key : 'current_liabilities' , label : 'Current Liabilities' , category : 'liability' , order : 140 , unit : 'currency' , localNames : [ 'LiabilitiesCurrent' ] , labelIncludes : [ 'current liabilities' ] } ,
{ key : 'long_term_debt' , label : 'Long-Term Debt' , category : 'liability' , order : 150 , unit : 'currency' , localNames : [ 'LongTermDebtNoncurrent' , 'LongTermDebt' , 'DebtNoncurrent' , 'LongTermDebtAndCapitalLeaseObligations' ] , labelIncludes : [ 'long-term debt' ] } ,
{ key : 'current_debt' , label : 'Current Debt' , category : 'liability' , order : 160 , unit : 'currency' , localNames : [ 'DebtCurrent' , 'ShortTermBorrowings' , 'LongTermDebtCurrent' ] , labelIncludes : [ 'current debt' , 'short-term debt' ] } ,
{ key : 'lease_liabilities' , label : 'Lease Liabilities' , category : 'liability' , order : 170 , unit : 'currency' , localNames : [ 'OperatingLeaseLiabilityNoncurrent' , 'FinanceLeaseLiabilityNoncurrent' , 'LesseeOperatingLeaseLiability' ] , labelIncludes : [ 'lease liabilities' ] } ,
{ key : 'total_debt' , label : 'Total Debt' , category : 'liability' , order : 180 , unit : 'currency' , localNames : [ 'DebtAndFinanceLeaseLiabilities' , 'Debt' ] , labelIncludes : [ 'total debt' ] } ,
{ key : 'deferred_revenue_noncurrent' , label : 'Deferred Revenue, Noncurrent' , category : 'liability' , order : 190 , unit : 'currency' , localNames : [ 'ContractWithCustomerLiabilityNoncurrent' , 'DeferredRevenueNoncurrent' ] , labelIncludes : [ 'deferred revenue noncurrent' ] } ,
{ key : 'total_liabilities' , label : 'Total Liabilities' , category : 'liability' , order : 200 , unit : 'currency' , localNames : [ 'Liabilities' ] , labelIncludes : [ 'total liabilities' ] } ,
{ key : 'retained_earnings' , label : 'Retained Earnings' , category : 'equity' , order : 210 , unit : 'currency' , localNames : [ 'RetainedEarningsAccumulatedDeficit' ] , labelIncludes : [ 'retained earnings' , 'accumulated deficit' ] } ,
{ key : 'total_equity' , label : 'Total Equity' , category : 'equity' , order : 220 , unit : 'currency' , localNames : [ 'StockholdersEquity' , 'StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest' , 'PartnersCapital' ] , labelIncludes : [ 'total equity' , 'stockholders’ equity' , 'stockholders equity' ] } ,
{ key : 'net_cash_position' , label : 'Net Cash Position' , category : 'liquidity' , order : 230 , unit : 'currency' , labelIncludes : [ 'net cash position' ] }
] as const satisfies StatementMetricDefinition [ ] ;
function computedToRatioMetric ( computed : ComputedDefinition ) : Ratio MetricDefinition {
const denominatorKey = computed . computation . type === 'ratio'
? computed.computation.denominator
: computed.computation.type === 'per_share'
? computed.computation.shares_key
: null ;
export const CASH_FLOW_STATEMENT_METRIC_DEFINITIONS : StatementMetricDefinition [ ] = [
{ key : 'operating_cash_flow' , label : 'Operating Cash Flow' , category : 'cash_flow' , order : 10 , unit : 'currency' , localNames : [ 'NetCashProvidedByUsedInOperatingActivities' , 'NetCashProvidedByUsedInOperatingActivitiesContinuingOperations' ] , labelIncludes : [ 'operating cash flow' ] } ,
{ key : 'capital_expenditures' , label : 'Capital Expenditures' , category : 'cash_flow' , order : 20 , unit : 'currency' , localNames : [ 'PaymentsToAcquirePropertyPlantAndEquipment' , 'CapitalExpendituresIncurredButNotYetPaid' ] , labelIncludes : [ 'capital expenditures' , 'capital expenditure' ] } ,
{ key : 'free_cash_flow' , label : 'Free Cash Flow' , category : 'cash_flow' , order : 30 , unit : 'currency' , labelIncludes : [ 'free cash flow' ] } ,
{ key : 'stock_based_compensation' , label : 'Stock-Based Compensation' , category : 'non_cash' , order : 40 , unit : 'currency' , localNames : [ 'ShareBasedCompensation' , 'AllocatedShareBasedCompensationExpense' ] , labelIncludes : [ 'stock-based compensation' , 'share-based compensation' ] } ,
{ key : 'acquisitions' , label : 'Acquisitions' , category : 'investing' , order : 50 , unit : 'currency' , localNames : [ 'PaymentsToAcquireBusinessesNetOfCashAcquired' ] , labelIncludes : [ 'acquisitions' ] } ,
{ key : 'share_repurchases' , label : 'Share Repurchases' , category : 'financing' , order : 60 , unit : 'currency' , localNames : [ 'PaymentsForRepurchaseOfCommonStock' , 'PaymentsForRepurchaseOfEquity' ] , labelIncludes : [ 'share repurchases' , 'repurchase of common stock' ] } ,
{ key : 'dividends_paid' , label : 'Dividends Paid' , category : 'financing' , order : 70 , unit : 'currency' , localNames : [ 'PaymentsOfDividends' , 'PaymentsOfDividendsCommonStock' ] , labelIncludes : [ 'dividends paid' ] } ,
{ key : 'debt_issued' , label : 'Debt Issued' , category : 'financing' , order : 80 , unit : 'currency' , localNames : [ 'ProceedsFromIssuanceOfLongTermDebt' ] , labelIncludes : [ 'debt issued' ] },
{ key : 'debt_repaid' , label : 'Debt Repaid' , category : 'financing' , order : 90 , unit : 'currency' , localNames : [ 'RepaymentsOfLongTermDebt' , 'RepaymentsOfDebt' ] , labelIncludes : [ 'debt repaid' , 'repayment of debt' ] }
] as const satisfies StatementMetricDefinition [ ] ;
return {
key : computed.key ,
label : computed.label ,
category : computed.category ,
order : computed.order ,
unit : computed.unit as RatioRow [ 'unit' ] ,
denominatorKey ,
supportedCadences : computed.supported_cadences as readonly FinancialCadence [ ] | undefined
} ;
}
export const RATIO _DEFINITIONS : Ratio MetricDefinition[ ] = [
{ key : 'gross_margin' , label : 'Gross Margin' , category : 'margins' , order : 10 , unit : 'percent' , denominatorKey : 'revenue' } ,
{ key : 'operating_margin' , label : 'Operating Margin' , category : 'margins' , order : 20 , unit : 'percent' , denominatorKey : 'revenue' } ,
{ key : 'ebitda_margin' , label : 'EBITDA Margin' , category : 'margins' , order : 30 , unit : 'percent' , denominatorKey : 'revenue' } ,
{ key : 'net_margin' , label : 'Net Margin' , category : 'margins' , order : 40 , unit : 'percent' , denominatorKey : 'revenue' } ,
{ key : 'fcf_margin' , label : 'FCF Margin' , category : 'margins' , order : 50 , unit : 'percent' , denominatorKey : 'revenue' } ,
{ key : 'roa' , label : 'ROA' , category : 'returns' , order : 60 , unit : 'percent' , denominatorKey : 'total_assets' } ,
{ key : 'roe' , label : 'ROE' , category : 'returns' , order : 70 , unit : 'percent' , denominatorKey : 'total_equity' } ,
{ key : 'roic' , label : 'ROIC' , category : 'returns' , order : 80 , unit : 'percent' , denominatorKey : 'average_invested_capital' } ,
{ key : 'roce' , label : 'ROCE' , category : 'returns' , order : 90 , unit : 'percent' , denominatorKey : 'average_capital_employed' } ,
{ key : 'debt_to_equity' , label : 'Debt to Equity' , category : 'financial_health' , order : 100 , unit : 'ratio' , denominatorKey : 'total_equity' } ,
{ key : 'net_debt_to_ebitda' , label : 'Net Debt to EBITDA' , category : 'financial_health' , order : 110 , unit : 'ratio' , denominatorKey : 'ebitda' } ,
{ key : 'cash_to_debt' , label : 'Cash to Debt' , category : 'financial_health' , order : 120 , unit : 'ratio' , denominatorKey : 'total_debt' } ,
{ key : 'current_ratio' , label : 'Current Ratio' , category : 'financial_health' , order : 130 , unit : 'ratio' , denominatorKey : 'current_liabilities' } ,
{ key : 'revenue_per_share' , label : 'Revenue per Share' , category : 'per_share' , order : 140 , unit : 'currency' , denominatorKey : 'diluted_shares' } ,
{ key : 'fcf_per_share' , label : 'FCF per Share' , category : 'per_share' , order : 150 , unit : 'currency' , denominatorKey : 'diluted_shares' } ,
{ key : 'book_value_per_share' , label : 'Book Value per Share' , category : 'per_share' , order : 160 , unit : 'currency' , denominatorKey : 'diluted_shares' } ,
{ key : 'revenue_yoy' , label : 'Revenue YoY' , category : 'growth' , order : 170 , unit : 'percent' , denominatorKey : 'revenue' } ,
{ key : 'net_income_yoy' , label : 'Net Income YoY' , category : 'growth' , order : 180 , unit : 'percent' , denominatorKey : 'net_income' } ,
{ key : 'eps_yoy' , label : 'EPS YoY' , category : 'growth' , order : 190 , unit : 'percent' , denominatorKey : 'diluted_eps' } ,
{ key : 'fcf_yoy' , label : 'FCF YoY' , category : 'growth' , order : 200 , unit : 'percent' , denominatorKey : 'free_cash_flow' } ,
{ key : '3y_revenue_cagr' , label : '3Y Revenue CAGR' , category : 'growth' , order : 210 , unit : 'percent' , denominatorKey : 'revenue' , supportedCadences : [ 'annual' ] } ,
{ key : '5y_revenue_cagr' , label : '5Y Revenue CAGR' , category : 'growth' , order : 220 , unit : 'percent' , denominatorKey : 'revenue' , supportedCadences : [ 'annual' ] } ,
{ key : '3y_eps_cagr' , label : '3Y EPS CAGR' , category : 'growth' , order : 230 , unit : 'percent' , denominatorKey : 'diluted_eps' , supportedCadences : [ 'annual' ] } ,
{ key : '5y_eps_cagr' , label : '5Y EPS CAGR' , category : 'growth' , order : 240 , unit : 'percent' , denominatorKey : 'diluted_eps' , supportedCadences : [ 'annual' ] } ,
{ key : 'market_cap' , label : 'Market Cap' , category : 'valuation' , order : 250 , unit : 'currency' , denominatorKey : null } ,
{ key : 'enterprise_value' , label : 'Enterprise Value' , category : 'valuation' , order : 260 , unit : 'currency' , denominatorKey : null } ,
{ key : 'price_to_earnings' , label : 'Price to Earnings' , category : 'valuation' , order : 270 , unit : 'ratio' , denominatorKey : 'diluted_eps' } ,
{ key : 'price_to_fcf' , label : 'Price to FCF' , category : 'valuation' , order : 280 , unit : 'ratio' , denominatorKey : 'free_cash_flow' } ,
{ key : 'price_to_book' , label : 'Price to Book' , category : 'valuation' , order : 290 , unit : 'ratio' , denominatorKey : 'total_equity' } ,
{ key : 'ev_to_sales' , label : 'EV to Sales' , category : 'valuation' , order : 300 , unit : 'ratio' , denominatorKey : 'revenue' } ,
{ key : 'ev_to_ebitda' , label : 'EV to EBITDA' , category : 'valuation' , order : 310 , unit : 'ratio' , denominatorKey : 'ebitda' } ,
{ key : 'ev_to_fcf' , label : 'EV to FCF' , category : 'valuation' , order : 320 , unit : 'ratio' , denominatorKey : 'free_cash_flow' }
] as const satisfies RatioMetricDefinition [ ] ;
export const INCOME_STATEMENT_METRIC _DEFINITIONS : Statement MetricDefinition[ ] =
INCOME_SURFACES . map ( surfaceToMetric ) ;
export const RATIO_CATEGORY_ORDER = [
'margins' ,
'returns' ,
'financial_health' ,
'per_share' ,
'growth' ,
'valuation'
] as const ;
export const BALANCE_SHEET_METRIC_DEFINITIONS : StatementMetricDefinition [ ] =
BALANCE_SURFACES . map ( surfaceToMetric ) ;
export const CASH_FLOW_STATEMENT_METRIC_DEFINITIONS : StatementMetricDefinition [ ] =
CASH_FLOW_SURFACES . map ( surfaceToMetric ) ;
export const RATIO_DEFINITIONS : RatioMetricDefinition [ ] =
ALL_COMPUTED . map ( computedToRatioMetric ) ;
export { RATIO_CATEGORIES , type RatioCategory } from '@/lib/generated' ;