# domain/converters/search.index.converter.ts

> 52 lines of code and 16 definitions.

Tree: Site tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/tree#file-domain-converters-search-index-converter-ts
Source text: https://banes-lab.com/assets/sources/source.d8b57bba765ddc6f85712d58628f40fb98301c40fd62f4739587d050a20e01a4.generated.txt

## Definitions

- `tabbedSources` (lexical_declaration, line 7)
- `positionOf` (lexical_declaration, line 56, exported)
- `sourcesOf` (lexical_declaration, line 20, exported)
- `layout` (lexical_declaration, line 9)
- `label` (lexical_declaration, line 13)
- `{ content, id, title }` (lexical_declaration, line 21, exported)
- `tab` (lexical_declaration, line 28, exported)
- `firstTabsOf` (lexical_declaration, line 32)
- `first` (lexical_declaration, line 35)
- `heldIndexes` (lexical_declaration, line 41)
- `indexOf` (lexical_declaration, line 43, exported)
- `held` (lexical_declaration, line 44, exported)
- `sources` (lexical_declaration, line 48, exported)
- `route` (lexical_declaration, line 49, exported)
- `evidence` (lexical_declaration, line 50, exported)
- `index` (lexical_declaration, line 51, exported)

## Uses

- [core/analyzers/search.analyzer.ts](https://banes-lab.com/source/tree/core/analyzers/search.analyzer.ts.md)

## Source

```typescript
import type { SearchCorpus, SearchIndex, SearchPage, SearchSource } from "#types/search.types";
import { anchorPath, anchorsOf, evidenceOf, linksOf, placeOf, routeOf } from "#core/analyzers/search.analyzer";
import type { Section } from "#types/document.types";
import { TITLE_SEPARATOR } from "#configuration/strings/page.strings";
import type { TabbedContent } from "#types/page.types";

const tabbedSources = function tabbedSources(page: SearchPage, content: TabbedContent): SearchSource[] {
    return content.tabs.flatMap((tab, index) => {
        const layout = tab.layout ?? content.layout;
        if (layout === "tree") {
            return [];
        }
        const label = page.definition.title + TITLE_SEPARATOR + tab.label;
        return [
            { first: index === 0, icon: tab.icon, label, layout, page: page.definition.id, tab, tone: content.tone },
        ];
    });
};

export const sourcesOf = function sourcesOf(page: SearchPage): readonly SearchSource[] {
    const { content, id, title } = page.definition;
    if (content.kind === "tabbed") {
        return tabbedSources(page, content);
    }
    if (content.kind === "home") {
        return [];
    }
    const tab = { icon: page.icon, id, label: content.meta.title, sections: content.sections };
    return [{ first: true, icon: page.icon, label: title, layout: "document", page: id, tab, tone: null }];
};

const firstTabsOf = function firstTabsOf(pages: readonly SearchPage[]): ReadonlyMap<string, string> {
    return new Map(
        pages.flatMap(({ definition }) => {
            const first = definition.content.kind === "tabbed" ? definition.content.tabs[0] : undefined;
            return first === undefined ? [] : [[definition.id, first.id] as const];
        }),
    );
};

const heldIndexes = new WeakMap<SearchCorpus, SearchIndex>();

export const indexOf = function indexOf(corpus: SearchCorpus): SearchIndex {
    const held = heldIndexes.get(corpus);
    if (held !== undefined) {
        return held;
    }
    const sources = corpus.pages.flatMap(sourcesOf);
    const route = routeOf(corpus.route);
    const evidence = evidenceOf(corpus.evidence, route, firstTabsOf(corpus.pages));
    const index = { evidence, links: linksOf(sources, route), route, sources };
    heldIndexes.set(corpus, index);
    return index;
};

export const positionOf = function positionOf(index: SearchIndex, source: SearchSource, section: Section): number {
    return index.route.get(anchorPath(source, section.id)) ?? placeOf(anchorsOf(section), index.links);
};
```
