mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-25 00:11:26 -07:00
87 lines
3.0 KiB
TypeScript
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),
|
|
};
|
|
}
|