import { MAX_ITEMS } from "../constants.ts"; import { normalizeSearch } from "../identity.ts"; import type { HelpState, IndexedItem, ResourceKind } from "../types.ts"; import { mergeItem } from "./migrate.ts"; export function sortItems(a: IndexedItem, b: IndexedItem): number { if ((a.pinned ? 1 : 0) !== (b.pinned ? 1 : 0)) return (b.pinned ? 1 : 0) - (a.pinned ? 1 : 0); if ((a.useCount ?? 0) !== (b.useCount ?? 0)) return (b.useCount ?? 0) - (a.useCount ?? 0); if ((a.lastUsedAt ?? 0) !== (b.lastUsedAt ?? 0)) return (b.lastUsedAt ?? 0) - (a.lastUsedAt ?? 0); return (a.displayName ?? a.name).localeCompare(b.displayName ?? b.name); } export function upsertItem(state: HelpState, item: IndexedItem): IndexedItem { const merged = mergeItem(state.items[item.key], item); state.items[item.key] = merged; return merged; } export function recordUsage(state: HelpState, key: string, now = Date.now()): void { const item = state.items[key]; if (!item) return; item.useCount = (item.useCount ?? 0) + 1; item.lastUsedAt = now; item.lastSeenAt = now; } export function recordUsageByName(state: HelpState, kind: ResourceKind, name: string, now = Date.now()): void { const matches = Object.values(state.items).filter((item) => item.kind === kind && (item.name === name || item.displayName === name)); if (matches.length === 0) return; const target = [...matches].sort(sortItems)[0]; if (!target) return; recordUsage(state, target.key, now); } export function findMatches(state: HelpState, query: string): IndexedItem[] { const normalizedQuery = normalizeSearch(query); if (!normalizedQuery) return []; return Object.values(state.items) .filter((item) => normalizeSearch([item.name, item.displayName, item.description, item.sourceLabel, item.packageName, item.sourceRef, item.kind].join(" ")).includes(normalizedQuery)) .sort(sortItems); } export function pruneState(state: HelpState): void { const items = Object.values(state.items); if (items.length <= MAX_ITEMS) return; const removable = items .filter((item) => !item.pinned) .sort((a, b) => { if ((a.useCount ?? 0) !== (b.useCount ?? 0)) { return (a.useCount ?? 0) - (b.useCount ?? 0); } return (a.lastUsedAt ?? 0) - (b.lastUsedAt ?? 0); }); while (Object.keys(state.items).length > MAX_ITEMS && removable.length > 0) { const victim = removable.shift(); if (victim) delete state.items[victim.key]; } }