Files
SubMiner/src/main/frequency-dictionary-runtime.ts
2026-03-01 02:36:51 -08:00

87 lines
3.0 KiB
TypeScript

import * as path from 'path';
import type { FrequencyDictionaryLookup } from '../types';
import { createFrequencyDictionaryLookup } from '../core/services';
export interface FrequencyDictionarySearchPathDeps {
getDictionaryRoots: () => string[];
getSourcePath?: () => string | undefined;
}
export interface FrequencyDictionaryRuntimeDeps {
isFrequencyDictionaryEnabled: () => boolean;
getSearchPaths: () => string[];
setFrequencyRankLookup: (lookup: FrequencyDictionaryLookup) => void;
log: (message: string) => void;
}
let frequencyDictionaryLookupInitialized = false;
let frequencyDictionaryLookupInitialization: Promise<void> | null = null;
// Frequency dictionary services are initialized lazily as a process-wide singleton.
// Initialization is idempotent and intentionally shared across callers.
export function getFrequencyDictionarySearchPaths(
deps: FrequencyDictionarySearchPathDeps,
): string[] {
const dictionaryRoots = deps.getDictionaryRoots();
const sourcePath = deps.getSourcePath?.();
const rawSearchPaths: string[] = [];
// User-provided path takes precedence over bundled/default roots.
// Root list should include default installed frequency-dictionary locations in callers.
if (sourcePath && sourcePath.trim()) {
rawSearchPaths.push(sourcePath.trim());
rawSearchPaths.push(path.join(sourcePath.trim(), 'frequency-dictionary'));
rawSearchPaths.push(path.join(sourcePath.trim(), 'vendor', 'frequency-dictionary'));
}
for (const dictionaryRoot of dictionaryRoots) {
rawSearchPaths.push(dictionaryRoot);
rawSearchPaths.push(path.join(dictionaryRoot, 'frequency-dictionary'));
rawSearchPaths.push(path.join(dictionaryRoot, 'vendor', 'frequency-dictionary'));
}
return [...new Set(rawSearchPaths)];
}
export async function initializeFrequencyDictionaryLookup(
deps: FrequencyDictionaryRuntimeDeps,
): Promise<void> {
const lookup = await createFrequencyDictionaryLookup({
searchPaths: deps.getSearchPaths(),
log: deps.log,
});
deps.setFrequencyRankLookup(lookup);
}
export async function ensureFrequencyDictionaryLookup(
deps: FrequencyDictionaryRuntimeDeps,
): Promise<void> {
if (!deps.isFrequencyDictionaryEnabled()) {
return;
}
if (frequencyDictionaryLookupInitialized) {
return;
}
if (!frequencyDictionaryLookupInitialization) {
frequencyDictionaryLookupInitialization = initializeFrequencyDictionaryLookup(deps)
.then(() => {
frequencyDictionaryLookupInitialized = true;
})
.catch((error) => {
frequencyDictionaryLookupInitialized = true;
deps.log(`Failed to initialize frequency dictionary: ${String(error)}`);
deps.setFrequencyRankLookup(() => null);
});
}
await frequencyDictionaryLookupInitialization;
}
export function createFrequencyDictionaryRuntimeService(deps: FrequencyDictionaryRuntimeDeps): {
ensureFrequencyDictionaryLookup: () => Promise<void>;
} {
return {
ensureFrequencyDictionaryLookup: () => ensureFrequencyDictionaryLookup(deps),
};
}