90 lines
3.0 KiB
TypeScript
90 lines
3.0 KiB
TypeScript
import path from "path"
|
|
import { Global } from "@/global"
|
|
import { onMount } from "solid-js"
|
|
import { createStore } from "solid-js/store"
|
|
import { createSimpleContext } from "../../context/helper"
|
|
import { appendFile } from "fs/promises"
|
|
|
|
function calculateFrecency(entry?: { frequency: number; lastOpen: number }): number {
|
|
if (!entry) return 0
|
|
const daysSince = (Date.now() - entry.lastOpen) / 86400000 // ms per day
|
|
const weight = 1 / (1 + daysSince)
|
|
return entry.frequency * weight
|
|
}
|
|
|
|
const MAX_FRECENCY_ENTRIES = 1000
|
|
|
|
export const { use: useFrecency, provider: FrecencyProvider } = createSimpleContext({
|
|
name: "Frecency",
|
|
init: () => {
|
|
const frecencyFile = Bun.file(path.join(Global.Path.state, "frecency.jsonl"))
|
|
onMount(async () => {
|
|
const text = await frecencyFile.text().catch(() => "")
|
|
const lines = text
|
|
.split("\n")
|
|
.filter(Boolean)
|
|
.map((line) => {
|
|
try {
|
|
return JSON.parse(line) as { path: string; frequency: number; lastOpen: number }
|
|
} catch {
|
|
return null
|
|
}
|
|
})
|
|
.filter((line): line is { path: string; frequency: number; lastOpen: number } => line !== null)
|
|
|
|
const latest = lines.reduce(
|
|
(acc, entry) => {
|
|
acc[entry.path] = entry
|
|
return acc
|
|
},
|
|
{} as Record<string, { path: string; frequency: number; lastOpen: number }>,
|
|
)
|
|
|
|
const sorted = Object.values(latest)
|
|
.sort((a, b) => b.lastOpen - a.lastOpen)
|
|
.slice(0, MAX_FRECENCY_ENTRIES)
|
|
|
|
setStore(
|
|
"data",
|
|
Object.fromEntries(
|
|
sorted.map((entry) => [entry.path, { frequency: entry.frequency, lastOpen: entry.lastOpen }]),
|
|
),
|
|
)
|
|
|
|
if (sorted.length > 0) {
|
|
const content = sorted.map((entry) => JSON.stringify(entry)).join("\n") + "\n"
|
|
Bun.write(frecencyFile, content).catch(() => {})
|
|
}
|
|
})
|
|
|
|
const [store, setStore] = createStore({
|
|
data: {} as Record<string, { frequency: number; lastOpen: number }>,
|
|
})
|
|
|
|
function updateFrecency(filePath: string) {
|
|
const absolutePath = path.resolve(process.cwd(), filePath)
|
|
const newEntry = {
|
|
frequency: (store.data[absolutePath]?.frequency || 0) + 1,
|
|
lastOpen: Date.now(),
|
|
}
|
|
setStore("data", absolutePath, newEntry)
|
|
appendFile(frecencyFile.name!, JSON.stringify({ path: absolutePath, ...newEntry }) + "\n").catch(() => {})
|
|
|
|
if (Object.keys(store.data).length > MAX_FRECENCY_ENTRIES) {
|
|
const sorted = Object.entries(store.data)
|
|
.sort(([, a], [, b]) => b.lastOpen - a.lastOpen)
|
|
.slice(0, MAX_FRECENCY_ENTRIES)
|
|
setStore("data", Object.fromEntries(sorted))
|
|
const content = sorted.map(([path, entry]) => JSON.stringify({ path, ...entry })).join("\n") + "\n"
|
|
Bun.write(frecencyFile, content).catch(() => {})
|
|
}
|
|
}
|
|
|
|
return {
|
|
getFrecency: (filePath: string) => calculateFrecency(store.data[path.resolve(process.cwd(), filePath)]),
|
|
updateFrecency,
|
|
data: () => store.data,
|
|
}
|
|
},
|
|
})
|