core/converters/search.converter.ts
core/converters/search.converter.ts is a file in Bane's Lab Build Scripts. 111 lines of code and 16 definitions.
import {
AMERICAN_WORDS,
IZE_STEMS,
IZE_SUFFIXES,
PLURAL_IES,
PLURAL_KEPT_AFTER,
PLURAL_MINIMUM_LENGTH,
PLURAL_SUFFIX,
SPELLING_PREFIXES,
} from "@govlab/constants";
import type { Identity, Leaf, Linker } from "#types/catalog.types";
import type { Phrase, SearchEntry, SearchRules, SearchSection } from "#types/search.types";
import { QUERY_ENDPOINT, QUERY_FUZZY, QUERY_LIMITS, SEARCH_KIND } from "#configuration/constants/catalog.constants";
import { QUERY_MESSAGES, QUERY_TITLE, queryParametersOf } from "#configuration/strings/catalog.strings";
import type { NamedSource } from "#types/source.types";
import type { WebModules } from "#types/loader.types";
import { groupedBy } from "#core/converters/base.converter";
import { queryIndex } from "#core/resolvers/catalog.resolver";
const QUERY_REF = "api:query";
type Words = (text: string) => readonly string[];
export const searchSections = async function searchSections(
web: Pick<WebModules, "analyzer" | "corpus" | "matcher" | "search">,
): Promise<readonly SearchSection[]> {
const index = web.search.indexOf(await web.corpus.loadCorpus());
return index.sources.flatMap((source) =>
source.tab.sections.map((section) => ({
href: web.analyzer.anchorPath(source, section.id),
position: web.search.positionOf(index, source, section),
words: web.analyzer.textsOf(section).flatMap((text) => web.matcher.markupWords(text)),
})),
);
};
export const searchRulesOf = function searchRulesOf(
web: Pick<WebModules, "searchConstants" | "vocabulary">,
): SearchRules {
return {
americanWords: AMERICAN_WORDS,
fuzzyMinimum: web.searchConstants.FUZZY_MIN_TERM_LENGTH,
izeStems: IZE_STEMS,
izeSuffixes: IZE_SUFFIXES,
pluralIes: PLURAL_IES,
pluralKeptAfter: [...PLURAL_KEPT_AFTER],
pluralMinimum: PLURAL_MINIMUM_LENGTH,
pluralSuffix: PLURAL_SUFFIX,
spellingPrefixes: SPELLING_PREFIXES,
wordCharacters: web.vocabulary.WORD_CHARACTERS,
};
};
const byPosition = function byPosition(left: SearchEntry, right: SearchEntry): number {
return (left.position ?? Number.POSITIVE_INFINITY) - (right.position ?? Number.POSITIVE_INFINITY);
};
export const sectionEntries = function sectionEntries(
sections: readonly SearchSection[],
linker: Linker,
): readonly SearchEntry[] {
return sections
.flatMap((section) => {
const identity = linker.byHref(section.href);
const position = Number.isFinite(section.position) ? section.position : null;
return identity === null ? [] : [{ identity, position, words: section.words }];
})
.toSorted(byPosition);
};
export const recordEntries = function recordEntries(
records: readonly Identity[],
phrases: readonly Phrase[],
words: Words,
): readonly SearchEntry[] {
const aliases = groupedBy(phrases, (phrase) => phrase.ref);
return records.map((identity) => ({
identity,
position: null,
words: [
identity.title,
identity.summary ?? "",
...(aliases.get(identity.ref) ?? []).map((alias) => alias.phrase),
].flatMap(words),
}));
};
export const fileEntries = function fileEntries(files: readonly NamedSource[], words: Words): readonly SearchEntry[] {
return files
.map(({ file, identity }) => ({
identity,
position: null,
words: [file.path, ...file.definitions.map((definition) => definition.name)].flatMap(words),
}))
.toSorted((left, right) => left.identity.title.localeCompare(right.identity.title));
};
const sortedUnique = function sortedUnique(values: readonly string[]): readonly string[] {
return [...new Set(values)].toSorted((left, right) => left.localeCompare(right));
};
export const queryLeaf = function queryLeaf(site: string, relations: readonly string[]): Leaf {
const ref = QUERY_REF;
const data = {
endpoint: site + QUERY_ENDPOINT,
fuzzy: QUERY_FUZZY,
index: site + queryIndex().json,
limits: QUERY_LIMITS,
messages: QUERY_MESSAGES,
parameters: queryParametersOf(QUERY_LIMITS),
ref,
relations: sortedUnique(relations),
site,
title: QUERY_TITLE,
};
return {
data,
identity: { address: queryIndex(), href: null, kind: SEARCH_KIND, ref, summary: null, title: QUERY_TITLE },
markdown: null,
};
};