Remove dead code in app and XBRL loader

This commit is contained in:
2026-03-21 13:03:12 -04:00
parent 7d2816e3c4
commit dd289968b8
22 changed files with 22 additions and 796 deletions

View File

@@ -331,47 +331,6 @@ textarea {
color: #ff9f9f;
}
.filter-chip {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.25rem 0.5rem;
border-radius: 0.5rem;
border: 1px solid var(--line-weak);
background: var(--panel-soft);
font-size: 0.6875rem;
font-family: var(--font-mono), monospace;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--terminal-bright);
transition:
border-color 0.15s,
background-color 0.15s;
}
.filter-chip:hover {
border-color: var(--line-strong);
}
.filter-chip .remove {
display: flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
border-radius: 3px;
cursor: pointer;
opacity: 0.6;
transition:
opacity 0.15s,
background-color 0.15s;
}
.filter-chip .remove:hover {
opacity: 1;
background: rgba(255, 255, 255, 0.1);
}
.section-divider {
border-top: 1px solid var(--line-weak);
margin-top: 1rem;

View File

@@ -1,36 +0,0 @@
import type { CompanyValuationSnapshot } from '@/lib/types';
import { formatCompactCurrency, formatScaledNumber } from '@/lib/format';
type ValuationStatGridProps = {
valuation: CompanyValuationSnapshot;
};
function formatRatio(value: number | null) {
return value === null ? 'n/a' : `${value.toFixed(2)}x`;
}
function formatShares(value: number | null) {
return value === null ? 'n/a' : formatScaledNumber(value, { maximumFractionDigits: 2 });
}
export function ValuationStatGrid(props: ValuationStatGridProps) {
const items = [
{ label: 'Market cap', value: props.valuation.marketCap === null ? 'n/a' : formatCompactCurrency(props.valuation.marketCap) },
{ label: 'Enterprise value', value: props.valuation.enterpriseValue === null ? 'n/a' : formatCompactCurrency(props.valuation.enterpriseValue) },
{ label: 'Shares out.', value: formatShares(props.valuation.sharesOutstanding) },
{ label: 'Trailing P/E', value: formatRatio(props.valuation.trailingPe) },
{ label: 'EV / Revenue', value: formatRatio(props.valuation.evToRevenue) },
{ label: 'EV / EBITDA', value: formatRatio(props.valuation.evToEbitda) }
];
return (
<div className="grid gap-3 sm:grid-cols-2">
{items.map((item) => (
<div key={item.label} className="rounded-2xl border border-[color:var(--line-weak)] bg-[color:var(--panel-soft)] p-3">
<p className="text-xs uppercase tracking-[0.14em] text-[color:var(--terminal-muted)]">{item.label}</p>
<p className="mt-2 text-lg font-semibold text-[color:var(--terminal-bright)]">{item.value}</p>
</div>
))}
</div>
);
}

View File

@@ -1,44 +0,0 @@
import { useState, useCallback } from 'react';
import type { ChartZoomState } from '@/lib/types';
export function useChartZoom(dataLength: number) {
const [zoomState, setZoomState] = useState<ChartZoomState>({
startIndex: 0,
endIndex: Math.max(0, dataLength - 1),
isZoomed: false
});
const handleZoomChange = useCallback(
(brushData: { startIndex?: number; endIndex?: number }) => {
if (
brushData.startIndex === undefined ||
brushData.endIndex === undefined
) {
return;
}
setZoomState({
startIndex: brushData.startIndex,
endIndex: brushData.endIndex,
isZoomed:
brushData.startIndex !== 0 ||
brushData.endIndex !== dataLength - 1
});
},
[dataLength]
);
const resetZoom = useCallback(() => {
setZoomState({
startIndex: 0,
endIndex: Math.max(0, dataLength - 1),
isZoomed: false
});
}, [dataLength]);
return {
zoomState,
handleZoomChange,
resetZoom
};
}

View File

@@ -1,71 +0,0 @@
import {
ComposedChart,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
Scatter
} from 'recharts';
import type { ChartDataPoint } from '@/lib/types';
import { getChartColors } from '../utils/chart-colors';
import { ChartTooltip } from '../primitives/chart-tooltip';
import { CandlestickShape } from '../utils/candlestick-shapes';
import { isOHLCVData } from '../utils/chart-data-transformers';
type CandlestickChartViewProps = {
data: ChartDataPoint[];
formatters?: {
price?: (value: number) => string;
date?: (value: string) => string;
volume?: (value: number) => string;
};
};
export function CandlestickChartView({
data,
formatters
}: CandlestickChartViewProps) {
const colors = getChartColors();
const ohlcvData = data.filter(isOHLCVData);
if (ohlcvData.length === 0) {
return (
<div className="flex h-full items-center justify-center text-sm text-[color:var(--terminal-muted)]">
Candlestick chart requires OHLCV data
</div>
);
}
return (
<ResponsiveContainer width="100%" height="100%">
<ComposedChart data={ohlcvData}>
<CartesianGrid strokeDasharray="2 2" stroke={colors.grid} />
<XAxis
dataKey="date"
stroke={colors.muted}
fontSize={11}
tickFormatter={formatters?.date}
minTickGap={32}
/>
<YAxis
stroke={colors.muted}
fontSize={11}
tickFormatter={formatters?.price}
width={60}
domain={['auto', 'auto']}
/>
<Tooltip
content={(tooltipProps) => <ChartTooltip {...tooltipProps} formatters={formatters} />}
cursor={{ stroke: colors.muted, strokeDasharray: '3 3' }}
/>
<Scatter
dataKey="close"
shape={<CandlestickShape />}
isAnimationActive={false}
/>
</ComposedChart>
</ResponsiveContainer>
);
}

View File

@@ -1,68 +0,0 @@
import { getPriceChangeColor } from './chart-colors';
type CandlestickShapeProps = {
cx?: number;
payload?: {
open: number;
high: number;
low: number;
close: number;
};
};
/**
* Custom candlestick shape component for Recharts
* Renders candlestick with wick and body
*/
export function CandlestickShape(props: CandlestickShapeProps) {
const { cx, payload } = props;
if (!payload || !cx) return null;
const { open, high, low, close } = payload;
const isPositive = close >= open;
const color = getPriceChangeColor(close - open);
// Calculate positions
const bodyTop = Math.min(open, close);
const bodyBottom = Math.max(open, close);
const bodyHeight = Math.max(bodyBottom - bodyTop, 1);
// Candlestick width
const width = 8;
return (
<g>
{/* Upper wick */}
<line
x1={cx}
y1={high}
x2={cx}
y2={bodyTop}
stroke={color}
strokeWidth={1}
/>
{/* Body */}
<rect
x={cx - width / 2}
y={bodyTop}
width={width}
height={bodyHeight}
fill={isPositive ? 'transparent' : color}
stroke={color}
strokeWidth={1}
/>
{/* Lower wick */}
<line
x1={cx}
y1={bodyBottom}
x2={cx}
y2={low}
stroke={color}
strokeWidth={1}
/>
</g>
);
}

View File

@@ -19,14 +19,6 @@ export function getChartColors(): ChartColorPalette {
};
}
/**
* Get color for price change (positive/negative)
*/
export function getPriceChangeColor(change: number): string {
const colors = getChartColors();
return change >= 0 ? colors.positive : colors.negative;
}
/**
* Convert CSS variable to computed color value
* Used for chart export since html-to-image can't render CSS variables

View File

@@ -1,87 +0,0 @@
import { cn } from "@/lib/utils";
type MetricCardSize = "default" | "compact" | "inline";
type MetricCardProps = {
label: string;
value: string;
delta?: string;
positive?: boolean;
className?: string;
size?: MetricCardSize;
};
export function MetricCard({
label,
value,
delta,
positive = true,
className,
size = "default",
}: MetricCardProps) {
if (size === "inline") {
return (
<div className={cn("index-card", className)}>
<p className="label">{label}</p>
<p className="value">{value}</p>
{delta ? (
<p className={cn("delta", positive ? "positive" : "negative")}>
{delta}
</p>
) : null}
</div>
);
}
if (size === "compact") {
return (
<div
className={cn(
"min-w-0 border-t border-[color:var(--line-weak)] pt-2",
className,
)}
>
<p className="text-[11px] text-[color:var(--terminal-muted)]">
{label}
</p>
<p className="mt-1 text-xl font-semibold text-[color:var(--terminal-bright)]">
{value}
</p>
{delta ? (
<p
className={cn(
"mt-1 text-[10px]",
positive ? "text-[#96f5bf]" : "text-[#ff9898]",
)}
>
{delta}
</p>
) : null}
</div>
);
}
return (
<div
className={cn(
"min-w-0 border-t border-[color:var(--line-weak)] pt-3",
className,
)}
>
<p className="text-xs text-[color:var(--terminal-muted)]">{label}</p>
<p className="mt-2 text-2xl font-semibold text-[color:var(--terminal-bright)]">
{value}
</p>
{delta ? (
<p
className={cn(
"mt-2 text-xs",
positive ? "text-[#96f5bf]" : "text-[#ff9898]",
)}
>
{delta}
</p>
) : null}
</div>
);
}

View File

@@ -1,102 +0,0 @@
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
type ControlButtonVariant = "primary" | "ghost" | "secondary" | "danger";
export type FinancialControlOption = {
value: string;
label: string;
disabled?: boolean;
};
export type FinancialControlSection = {
id: string;
label: string;
value: string;
options: FinancialControlOption[];
onChange: (value: string) => void;
};
export type FinancialControlAction = {
id: string;
label: string;
onClick: () => void;
disabled?: boolean;
variant?: ControlButtonVariant;
};
type FinancialControlBarProps = {
title?: string;
subtitle?: string;
sections: FinancialControlSection[];
actions?: FinancialControlAction[];
className?: string;
};
export function FinancialControlBar({
title = "Control Bar",
subtitle,
sections,
actions,
className,
}: FinancialControlBarProps) {
return (
<section
className={cn("border-t border-[color:var(--line-weak)] pt-4", className)}
>
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<div className="min-w-0">
<h3 className="text-base font-semibold text-[color:var(--terminal-bright)]">
{title}
</h3>
{subtitle ? (
<p className="mt-1 text-sm text-[color:var(--terminal-muted)]">
{subtitle}
</p>
) : null}
</div>
{actions && actions.length > 0 ? (
<div className="grid w-full grid-cols-1 gap-2 sm:flex sm:w-auto sm:flex-wrap sm:items-center sm:justify-end">
{actions.map((action) => (
<Button
key={action.id}
type="button"
variant={action.variant ?? "secondary"}
disabled={action.disabled}
className="px-2 py-1 text-xs sm:min-h-9"
onClick={action.onClick}
>
{action.label}
</Button>
))}
</div>
) : null}
</div>
<div className="mt-4 grid grid-cols-1 gap-3">
{sections.map((section) => (
<div key={section.id} className="data-surface px-3 py-3">
<span className="mb-2 block text-[11px] text-[color:var(--terminal-muted)]">
{section.label}
</span>
<div className="flex flex-wrap items-center gap-1.5">
{section.options.map((option) => (
<Button
key={`${section.id}-${option.value}`}
type="button"
variant={option.value === section.value ? "primary" : "ghost"}
disabled={option.disabled}
className="px-2 py-1 text-xs sm:min-h-9"
onClick={() => section.onChange(option.value)}
>
{option.label}
</Button>
))}
</div>
</div>
))}
</div>
</section>
);
}

View File

@@ -1,26 +0,0 @@
"use client";
import { X } from "lucide-react";
import { cn } from "@/lib/utils";
type FilterChipProps = {
label: string;
onRemove: () => void;
className?: string;
};
export function FilterChip({ label, onRemove, className }: FilterChipProps) {
return (
<span className={cn("filter-chip", className)}>
<span className="truncate">{label}</span>
<button
type="button"
onClick={onRemove}
className="remove"
aria-label={`Remove ${label} filter`}
>
<X className="size-3" />
</button>
</span>
);
}

View File

@@ -254,7 +254,7 @@ Rules:
- use delta text only for meaningful comparison or trend context
- reserve green and red text for clearly directional values
Reference implementation: `components/dashboard/metric-card.tsx`
Reference implementation: `components/dashboard/index-card-row.tsx`
### Tables

View File

@@ -1,64 +0,0 @@
'use client';
import { useEffect, useRef, useState } from 'react';
import { getTask } from '@/lib/api';
import type { Task } from '@/lib/types';
type UseTaskPollerInput = {
taskId: string | null;
intervalMs?: number;
onTerminalState?: (task: Task) => void;
};
export function useTaskPoller({ taskId, intervalMs = 2200, onTerminalState }: UseTaskPollerInput) {
const [task, setTask] = useState<Task | null>(null);
const onTerminalStateRef = useRef(onTerminalState);
useEffect(() => {
onTerminalStateRef.current = onTerminalState;
}, [onTerminalState]);
useEffect(() => {
if (!taskId) {
setTask(null);
return;
}
let stopped = false;
let timer: ReturnType<typeof setTimeout> | null = null;
const poll = async () => {
try {
const { task: latest } = await getTask(taskId);
if (stopped) {
return;
}
setTask(latest);
if (latest.status === 'completed' || latest.status === 'failed') {
onTerminalStateRef.current?.(latest);
return;
}
} catch {
if (stopped) {
return;
}
}
timer = setTimeout(poll, intervalMs);
};
void poll();
return () => {
stopped = true;
if (timer) {
clearTimeout(timer);
}
};
}, [taskId, intervalMs]);
return task;
}

View File

@@ -1,5 +1,8 @@
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"entry": [
"test/bun-test-shim.ts"
],
"tags": [
"-lintignore"
]

View File

@@ -1,33 +0,0 @@
import type {
FinancialStatementKind,
FinancialUnit
} from '@/lib/types';
import {
INCOME_SURFACES,
BALANCE_SURFACES,
CASH_FLOW_SURFACES
} from '@/lib/generated';
export type CanonicalRowDefinition = {
key: string;
label: string;
category: string;
order: number;
unit: FinancialUnit;
};
function toCanonicalRow(surface: { surface_key: string; label: string; category: string; order: number; unit: string }) {
return {
key: surface.surface_key,
label: surface.label,
category: surface.category,
order: surface.order,
unit: surface.unit as FinancialUnit
};
}
export const CANONICAL_ROW_DEFINITIONS: Record<Extract<FinancialStatementKind, 'income' | 'balance' | 'cash_flow'>, CanonicalRowDefinition[]> = {
income: INCOME_SURFACES.map(toCanonicalRow),
balance: BALANCE_SURFACES.map(toCanonicalRow),
cash_flow: CASH_FLOW_SURFACES.map(toCanonicalRow)
};

View File

@@ -9,11 +9,15 @@ import type {
IssuerOverlayDiagnostics,
IssuerOverlayStats,
} from "@/lib/server/db/schema";
import {
ensureIssuerOverlayRow,
getIssuerOverlay,
listIssuerOverlayRevisions,
publishIssuerOverlayRevision,
} from "./issuer-overlays";
let tempDir: string | null = null;
let sqliteClient: Database | null = null;
let overlayRepo: typeof import("./issuer-overlays") | null = null;
function resetDbSingletons() {
const globalState = globalThis as typeof globalThis & {
__fiscalSqliteClient?: Database;
@@ -90,8 +94,6 @@ describe("issuer overlay repo", () => {
};
globalState.__fiscalSqliteClient = sqliteClient;
globalState.__fiscalDrizzleDb = undefined;
overlayRepo = await import("./issuer-overlays");
});
afterAll(() => {
@@ -108,35 +110,27 @@ describe("issuer overlay repo", () => {
});
it("creates an empty overlay row on ensure", async () => {
if (!overlayRepo) {
throw new Error("overlay repo not initialized");
}
const overlay = await overlayRepo.ensureIssuerOverlayRow("aapl");
const overlay = await ensureIssuerOverlayRow("aapl");
expect(overlay?.ticker).toBe("AAPL");
expect(overlay?.status).toBe("empty");
expect(overlay?.active_revision).toBeNull();
});
it("publishes and deduplicates overlay revisions by content hash", async () => {
if (!overlayRepo) {
throw new Error("overlay repo not initialized");
}
const first = await overlayRepo.publishIssuerOverlayRevision({
const first = await publishIssuerOverlayRevision({
ticker: "AAPL",
definition: sampleDefinition(),
diagnostics: sampleDiagnostics(),
stats: sampleStats(),
});
const second = await overlayRepo.publishIssuerOverlayRevision({
const second = await publishIssuerOverlayRevision({
ticker: "AAPL",
definition: sampleDefinition(),
diagnostics: sampleDiagnostics(),
stats: sampleStats(),
});
const overlay = await overlayRepo.getIssuerOverlay("AAPL");
const revisions = await overlayRepo.listIssuerOverlayRevisions("AAPL");
const overlay = await getIssuerOverlay("AAPL");
const revisions = await listIssuerOverlayRevisions("AAPL");
expect(first.published).toBe(true);
expect(second.published).toBe(false);

View File

@@ -11,7 +11,7 @@ import {
type IssuerOverlayStats,
} from "@/lib/server/db/schema";
export type IssuerOverlayRevisionRecord = {
type IssuerOverlayRevisionRecord = {
id: number;
ticker: string;
revision_number: number;
@@ -22,7 +22,7 @@ export type IssuerOverlayRevisionRecord = {
created_at: string;
};
export type IssuerOverlayRecord = {
type IssuerOverlayRecord = {
ticker: string;
status: "empty" | "active" | "error";
active_revision_id: number | null;

View File

@@ -1,53 +0,0 @@
import type { FinancialStatementKind } from '@/lib/types';
export function classifyStatementRole(roleUri: string): FinancialStatementKind | null {
const normalized = roleUri.toLowerCase();
if (/cash\s*flow|statementsof?cashflows|netcash/.test(normalized)) {
return 'cash_flow';
}
if (/shareholders?|stockholders?|equity|retainedearnings/.test(normalized)) {
return 'equity';
}
if (/comprehensive\s*income/.test(normalized)) {
return 'comprehensive_income';
}
if (/balance\s*sheet|financial\s*position|assets?andliabilities/.test(normalized)) {
return 'balance';
}
if (/operations|income\s*statement|statementsofincome|profit/.test(normalized)) {
return 'income';
}
return null;
}
export function conceptStatementFallback(localName: string): FinancialStatementKind | null {
const normalized = localName.toLowerCase();
if (/cash|operatingactivities|investingactivities|financingactivities/.test(normalized)) {
return 'cash_flow';
}
if (/equity|retainedearnings|additionalpaidincapital/.test(normalized)) {
return 'equity';
}
if (/comprehensiveincome/.test(normalized)) {
return 'comprehensive_income';
}
if (/asset|liabilit|debt/.test(normalized)) {
return 'balance';
}
if (/revenue|income|profit|expense|costof/.test(normalized)) {
return 'income';
}
return null;
}

View File

@@ -232,11 +232,6 @@ export type TaxonomyHydrationInput = {
issuerOverlay?: IssuerOverlayDefinition | null;
};
export type TickerAutomationRequest = {
ticker: string;
source: TickerAutomationSource;
};
export type TaxonomyHydrationResult = {
filing_id: number;
ticker: string;

View File

@@ -1,22 +0,0 @@
export {
normalizeTicker,
normalizeTickerOrNull,
normalizeTags,
normalizeTagsOrNull,
normalizeOptionalString,
normalizeRecord,
normalizePositiveInteger,
nowIso,
todayIso
} from './normalize';
export {
asRecord,
asOptionalRecord,
asPositiveNumber,
asBoolean,
asStringArray,
asEnum
} from './validation';
export { withRetry, type RetryOptions } from './retry';

View File

@@ -1,51 +0,0 @@
export function normalizeTicker(ticker: string): string {
return ticker.trim().toUpperCase();
}
export function normalizeTickerOrNull(ticker: unknown): string | null {
if (typeof ticker !== 'string') return null;
const normalized = ticker.trim().toUpperCase();
return normalized || null;
}
export function normalizeTags(tags?: unknown): string[] {
if (!Array.isArray(tags)) return [];
const unique = new Set<string>();
for (const entry of tags) {
if (typeof entry !== 'string') continue;
const tag = entry.trim();
if (tag) unique.add(tag);
}
return [...unique];
}
export function normalizeTagsOrNull(tags?: unknown): string[] | null {
const result = normalizeTags(tags);
return result.length > 0 ? result : null;
}
export function normalizeOptionalString(value?: unknown): string | null {
if (typeof value !== 'string') return null;
const normalized = value.trim();
return normalized || null;
}
export function normalizeRecord(value?: unknown): Record<string, unknown> | null {
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
return value as Record<string, unknown>;
}
export function normalizePositiveInteger(value?: unknown): number | null {
if (value === null || value === undefined || !Number.isFinite(value as number)) return null;
const normalized = Math.trunc(value as number);
return normalized > 0 ? normalized : null;
}
export function nowIso(): string {
return new Date().toISOString();
}
export function todayIso(): string {
return new Date().toISOString().slice(0, 10);
}

View File

@@ -1,10 +1,10 @@
export interface RetryOptions {
type RetryOptions = {
maxRetries: number;
baseDelayMs: number;
maxDelayMs: number;
jitterFactor: number;
retryableErrors: RegExp[];
}
};
const DEFAULT_RETRY_OPTIONS: RetryOptions = {
maxRetries: 3,

View File

@@ -1,56 +0,0 @@
export function asRecord(value: unknown): Record<string, unknown> {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return {};
}
return value as Record<string, unknown>;
}
export function asOptionalRecord(value: unknown): Record<string, unknown> | null {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return null;
}
return value as Record<string, unknown>;
}
export function asPositiveNumber(value: unknown): number | null {
const parsed = typeof value === 'number' ? value : Number(value);
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
}
export function asBoolean(value: unknown, fallback = false): boolean {
if (typeof value === 'boolean') {
return value;
}
if (typeof value === 'string') {
const normalized = value.trim().toLowerCase();
if (normalized === 'true' || normalized === '1' || normalized === 'yes') {
return true;
}
if (normalized === 'false' || normalized === '0' || normalized === 'no') {
return false;
}
}
return fallback;
}
export function asStringArray(value: unknown): string[] {
const source = Array.isArray(value)
? value
: typeof value === 'string'
? value.split(',')
: [];
const unique = new Set<string>();
for (const entry of source) {
if (typeof entry !== 'string') continue;
const tag = entry.trim();
if (tag) unique.add(tag);
}
return [...unique];
}
export function asEnum<T extends string>(value: unknown, allowed: readonly T[]): T | undefined {
return allowed.includes(value as T) ? (value as T) : undefined;
}

View File

@@ -281,10 +281,6 @@ pub fn resolve_taxonomy_dir() -> Result<PathBuf> {
})
}
pub fn load_surface_pack(pack: FiscalPack) -> Result<SurfacePackFile> {
load_surface_pack_with_overlays(pack, None, None)
}
pub fn load_surface_pack_with_overlays(
pack: FiscalPack,
ticker: Option<&str>,
@@ -651,8 +647,8 @@ mod tests {
resolve_taxonomy_dir().expect("taxonomy dir should resolve during tests");
assert!(taxonomy_dir.exists());
let surface_pack =
load_surface_pack(FiscalPack::Core).expect("core surface pack should load");
let surface_pack = load_surface_pack_with_overlays(FiscalPack::Core, None, None)
.expect("core surface pack should load");
assert_eq!(surface_pack.pack, "core");
assert!(!surface_pack.surfaces.is_empty());
@@ -704,7 +700,7 @@ mod tests {
];
for pack in packs {
let surface_pack = load_surface_pack(pack)
let surface_pack = load_surface_pack_with_overlays(pack, None, None)
.unwrap_or_else(|error| panic!("surface pack {} failed: {error}", pack.as_str()));
assert_eq!(surface_pack.pack, pack.as_str());
assert!(