import * as Data from "effect/Data"; import * as Effect from "effect/Effect"; import { Atom } from "effect/unstable/reactivity"; import { highlightSourceFile, type ReviewDiffTheme, type ReviewHighlightedToken, } from "../review/shikiReviewHighlighter"; const SOURCE_HIGHLIGHT_IDLE_TTL_MS = 5 * 60_000; export interface SourceHighlightInput { readonly path: string; readonly contents: string; readonly theme: ReviewDiffTheme; } export type SourceHighlightTokens = ReadonlyArray>; type SourceHighlighter = (input: SourceHighlightInput) => Promise; class SourceHighlightCacheKey extends Data.Class {} class SourceHighlightError extends Data.TaggedError("SourceHighlightError")<{ readonly cause: unknown; }> {} export function createSourceHighlightAtomFamily(options?: { readonly highlight?: SourceHighlighter; readonly idleTtlMs?: number; }) { const highlight = options?.highlight ?? highlightSourceFile; const idleTtlMs = options?.idleTtlMs ?? SOURCE_HIGHLIGHT_IDLE_TTL_MS; const family = Atom.family((request: SourceHighlightCacheKey) => Atom.make( Effect.tryPromise({ try: () => highlight(request), catch: (cause) => new SourceHighlightError({ cause }), }), ).pipe( Atom.setIdleTTL(idleTtlMs), Atom.withLabel(`mobile:source-highlight:${request.theme}:${request.path}`), ), ); return (input: SourceHighlightInput) => family(new SourceHighlightCacheKey(input)); } export const sourceHighlightAtom = createSourceHighlightAtomFamily();