diff --git a/biome.json b/biome.json index 20c89a522..779b9a417 100644 --- a/biome.json +++ b/biome.json @@ -59,6 +59,8 @@ }, "complexity": { "noForEach": "off", + "noImportantStyles": "off", + "useLiteralKeys": "off", "useFlatMap": "warn", "noUselessSwitchCase": "warn", "noUselessConstructor": "warn", diff --git a/scripts/ais-relay.cjs b/scripts/ais-relay.cjs index f6283ba71..ef1211987 100644 --- a/scripts/ais-relay.cjs +++ b/scripts/ais-relay.cjs @@ -2596,7 +2596,7 @@ const CLASSIFY_LLM_PROVIDERS = [ }, ]; -function classifyFetchLlmSingle(titles, apiKey, apiUrl, model, headers, extraBody, timeout) { +function classifyFetchLlmSingle(titles, _apiKey, apiUrl, model, headers, extraBody, timeout) { return new Promise((resolve) => { const sanitized = titles.map((t) => t.replace(/[\n\r]/g, ' ').replace(/\|/g, '/').slice(0, 200).trim()); const prompt = sanitized.map((t, i) => `${i}|${t}`).join('\n'); diff --git a/scripts/seed-conflict-intel.mjs b/scripts/seed-conflict-intel.mjs index d5d008a0e..6f847b0db 100755 --- a/scripts/seed-conflict-intel.mjs +++ b/scripts/seed-conflict-intel.mjs @@ -203,7 +203,7 @@ async function fetchPizzintStatus() { const open = locations.filter(l => !l.isClosedNow); const spikes = locations.filter(l => l.isSpike).length; const avgPop = open.length > 0 ? open.reduce((s, l) => s + l.currentPopularity, 0) / open.length : 0; - let adjusted = Math.min(100, avgPop + spikes * 10); + const adjusted = Math.min(100, avgPop + spikes * 10); let defconLevel = 5, defconLabel = 'Normal Activity'; if (adjusted >= 85) { defconLevel = 1; defconLabel = 'Maximum Activity'; } else if (adjusted >= 70) { defconLevel = 2; defconLabel = 'High Activity'; } diff --git a/scripts/seed-economy.mjs b/scripts/seed-economy.mjs index b198f0cc6..04017c3e6 100755 --- a/scripts/seed-economy.mjs +++ b/scripts/seed-economy.mjs @@ -96,7 +96,7 @@ async function fetchCapacityForSource(sourceCode, apiKey, startYear) { for (const row of rows) { if (row.period == null || row.capability == null) continue; const year = parseInt(row.period, 10); - if (isNaN(year)) continue; + if (Number.isNaN(year)) continue; const mw = typeof row.capability === 'number' ? row.capability : parseFloat(String(row.capability)); if (!Number.isFinite(mw)) continue; yearTotals.set(year, (yearTotals.get(year) ?? 0) + mw); @@ -172,7 +172,7 @@ async function fetchFredSeries() { const obsData = await obsResp.value.json(); const observations = (obsData.observations || []) - .map((o) => { const v = parseFloat(o.value); return isNaN(v) || o.value === '.' ? null : { date: o.date, value: v }; }) + .map((o) => { const v = parseFloat(o.value); return Number.isNaN(v) || o.value === '.' ? null : { date: o.date, value: v }; }) .filter(Boolean) .reverse(); diff --git a/scripts/seed-forecasts.mjs b/scripts/seed-forecasts.mjs index 0260bea80..54aeb438b 100644 --- a/scripts/seed-forecasts.mjs +++ b/scripts/seed-forecasts.mjs @@ -2363,7 +2363,7 @@ async function callForecastLLM(systemPrompt, userPrompt) { const text = json.choices?.[0]?.message?.content?.trim(); if (!text || text.length < 20) continue; return { text, model: json.model || provider.model, provider: provider.name }; - } catch (err) { console.warn(` [LLM] ${provider.name}: ${err.message}`); continue; } + } catch (err) { console.warn(` [LLM] ${provider.name}: ${err.message}`); } } return null; } diff --git a/scripts/seed-research.mjs b/scripts/seed-research.mjs index cb9e02e57..e119cfc80 100755 --- a/scripts/seed-research.mjs +++ b/scripts/seed-research.mjs @@ -176,7 +176,7 @@ async function fetchTechEvents() { if (!title) continue; const dateMatch = desc.match(/on\s+(\w+\s+\d{1,2},?\s+\d{4})/i); let startDate = null; - if (dateMatch) { const p = new Date(dateMatch[1]); if (!isNaN(p.getTime())) startDate = p.toISOString().split('T')[0]; } + if (dateMatch) { const p = new Date(dateMatch[1]); if (!Number.isNaN(p.getTime())) startDate = p.toISOString().split('T')[0]; } if (!startDate || startDate < today) continue; events.push({ id: guid || `dev-${title.slice(0, 20)}`, title, type: 'conference', diff --git a/scripts/seed-supply-chain-trade.mjs b/scripts/seed-supply-chain-trade.mjs index e4352032a..9bddc752f 100755 --- a/scripts/seed-supply-chain-trade.mjs +++ b/scripts/seed-supply-chain-trade.mjs @@ -60,7 +60,7 @@ async function fetchShippingRates() { if (!resp.ok) { console.warn(` FRED ${cfg.seriesId}: HTTP ${resp.status}`); continue; } const data = await resp.json(); const observations = (data.observations || []) - .map(o => { const v = parseFloat(o.value); return isNaN(v) || o.value === '.' ? null : { date: o.date, value: v }; }) + .map(o => { const v = parseFloat(o.value); return Number.isNaN(v) || o.value === '.' ? null : { date: o.date, value: v }; }) .filter(Boolean).reverse(); if (observations.length === 0) continue; const current = observations[observations.length - 1].value; @@ -148,7 +148,7 @@ async function fetchBDI() { let articleDate = new Date().toISOString().slice(0, 10); if (dateMatch) { const parsed = new Date(`${dateMatch[2]} ${dateMatch[1]}, ${dateMatch[3]}`); - if (!isNaN(parsed.getTime())) articleDate = parsed.toISOString().slice(0, 10); + if (!Number.isNaN(parsed.getTime())) articleDate = parsed.toISOString().slice(0, 10); } const indices = []; @@ -254,7 +254,7 @@ function parseFlowRows(data, indicator) { return dataset.map(row => { const year = parseInt(row.Year ?? row.year ?? '', 10); const value = parseFloat(row.Value ?? row.value ?? ''); - return !isNaN(year) && !isNaN(value) ? { year, indicator, value } : null; + return !Number.isNaN(year) && !Number.isNaN(value) ? { year, indicator, value } : null; }).filter(Boolean); } @@ -336,7 +336,7 @@ async function fetchTradeBarriers() { const year = parseInt(row.Year ?? row.year ?? '0', 10); const value = parseFloat(row.Value ?? row.value ?? ''); const cc = String(row.ReportingEconomyCode ?? ''); - return !isNaN(year) && !isNaN(value) && cc ? { country: WTO_MEMBER_CODES[cc] ?? '', countryCode: cc, year, value } : null; + return !Number.isNaN(year) && !Number.isNaN(value) && cc ? { country: WTO_MEMBER_CODES[cc] ?? '', countryCode: cc, year, value } : null; }).filter(Boolean); }; @@ -400,7 +400,7 @@ async function fetchTradeRestrictions() { const restrictions = [...latestByCountry.values()].map(row => { const value = parseFloat(row.Value ?? row.value ?? ''); - if (isNaN(value)) return null; + if (Number.isNaN(value)) return null; const cc = String(row.ReportingEconomyCode ?? ''); const year = String(row.Year ?? row.year ?? ''); return { @@ -438,7 +438,7 @@ async function fetchTariffTrends() { const datapoints = dataset.map(row => { const year = parseInt(row.Year ?? row.year ?? '', 10); const tariffRate = parseFloat(row.Value ?? row.value ?? ''); - if (isNaN(year) || isNaN(tariffRate)) return null; + if (Number.isNaN(year) || Number.isNaN(tariffRate)) return null; return { reportingCountry: WTO_MEMBER_CODES[reporter] ?? reporter, partnerCountry: 'World', productSector: 'All products', diff --git a/src/app/data-loader.ts b/src/app/data-loader.ts index 88aff4c6f..2ba829682 100644 --- a/src/app/data-loader.ts +++ b/src/app/data-loader.ts @@ -766,7 +766,7 @@ export class DataLoaderManager implements AppModule { // Digest branch: server already aggregated feeds — map proto items to client types if (digest?.categories && category in digest.categories) { - let items = (digest.categories[category]?.items ?? []) + const items = (digest.categories[category]?.items ?? []) .map(protoItemToNewsItem) .filter(i => enabledNames.has(i.source)); diff --git a/src/components/TelegramIntelPanel.ts b/src/components/TelegramIntelPanel.ts index faa7701b1..9ccbaf137 100644 --- a/src/components/TelegramIntelPanel.ts +++ b/src/components/TelegramIntelPanel.ts @@ -95,7 +95,7 @@ export class TelegramIntelPanel extends Panel { private buildItem(item: TelegramItem): HTMLElement { const timeAgo = formatTelegramTime(item.ts); const itemDate = new Date(item.ts).getTime(); - const isLive = !isNaN(itemDate) && (Date.now() - itemDate) < LIVE_THRESHOLD_MS; + const isLive = !Number.isNaN(itemDate) && (Date.now() - itemDate) < LIVE_THRESHOLD_MS; const raw = item.text || ''; const escaped = raw .replace(/&/g, '&') diff --git a/src/services/parallel-analysis.ts b/src/services/parallel-analysis.ts index 3ae87d76e..0f065d4d9 100644 --- a/src/services/parallel-analysis.ts +++ b/src/services/parallel-analysis.ts @@ -75,12 +75,8 @@ const BUSINESS_DEMOTE = [ class ParallelAnalysisService { private lastReport: AnalysisReport | null = null; private recentEmbeddings: Map = new Map(); - private analysisCount = 0; - async analyzeHeadlines(clusters: ClusteredEvent[]): Promise { - this.analysisCount++; - const analyzed: AnalyzedHeadline[] = []; const titles = clusters.map(c => c.primaryTitle); @@ -415,7 +411,7 @@ class ParallelAnalysisService { const scores = perspectives.map(p => p.score); const mean = scores.reduce((a, b) => a + b, 0) / scores.length; - const variance = scores.reduce((sum, s) => sum + Math.pow(s - mean, 2), 0) / scores.length; + const variance = scores.reduce((sum, s) => sum + (s - mean) ** 2, 0) / scores.length; const disagreement = Math.sqrt(variance); return { diff --git a/src/services/storage.ts b/src/services/storage.ts index e91b9b039..ae7992ccc 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -142,7 +142,7 @@ export function calculateDeviation(current: number, baseline: BaselineEntry): { return { zScore: 0, percentChange: 0, level: 'normal' }; } - const variance = counts.reduce((sum, c) => sum + Math.pow(c - avg, 2), 0) / counts.length; + const variance = counts.reduce((sum, c) => sum + (c - avg) ** 2, 0) / counts.length; const stdDev = Math.sqrt(variance) || 1; const zScore = (current - avg) / stdDev; diff --git a/src/utils/transit-chart.ts b/src/utils/transit-chart.ts index 6df32f660..d21691558 100644 --- a/src/utils/transit-chart.ts +++ b/src/utils/transit-chart.ts @@ -104,7 +104,7 @@ export class TransitChart { const dpr = window.devicePixelRatio || 1; const rect = canvas.getBoundingClientRect(); const W = rect.width; - const H = parseInt(canvas.style.height) || 140; + const H = parseInt(canvas.style.height, 10) || 140; canvas.width = W * dpr; canvas.height = H * dpr; diff --git a/tests/seed-warm-ping-origin.test.mjs b/tests/seed-warm-ping-origin.test.mjs index fb4dcaaeb..1de0eff72 100644 --- a/tests/seed-warm-ping-origin.test.mjs +++ b/tests/seed-warm-ping-origin.test.mjs @@ -18,7 +18,7 @@ describe('warm-ping seed scripts', () => { assert.match(src, /method:\s*'POST'/); }); - it('sends the app Origin header for military\/maritime warm-pings', () => { + it('sends the app Origin header for military/maritime warm-pings', () => { const src = readScript('scripts/seed-military-maritime-news.mjs'); assert.match(src, /Origin:\s*'https:\/\/worldmonitor\.app'/); assert.match(src, /method:\s*'POST'/);