# core/converters/literal.converter.ts

> 89 lines of code and 20 definitions.

Tree: Site tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/tree#file-core-converters-literal-converter-ts
Source text: https://banes-lab.com/source/tree/core/converters/literal.converter.ts.txt

Listed in [core/converters](https://banes-lab.com/api/source/tree/core/converters.md), after [core/converters/grammar.converter.ts](https://banes-lab.com/source/tree/core/converters/grammar.converter.ts.md) and before [core/converters/markdown.converter.ts](https://banes-lab.com/source/tree/core/converters/markdown.converter.ts.md).

## Definitions

- `exactTarget` (lexical_declaration, line 27)
- `literalTarget` (lexical_declaration, line 79, exported)
- `openTarget` (lexical_declaration, line 37)
- `isPathShaped` (lexical_declaration, line 18)
- `slotTarget` (lexical_declaration, line 58)
- `ruleTarget` (lexical_declaration, line 68)
- `catalogTarget` (lexical_declaration, line 74)
- `at` (lexical_declaration, line 19)
- `specified` (lexical_declaration, line 28)
- `folder` (lexical_declaration, line 33)
- `literals` (lexical_declaration, line 38)
- `matches` (lexical_declaration, line 42)
- `[only]` (lexical_declaration, line 43)
- `isSlotArgument` (lexical_declaration, line 52)
- `declaration` (lexical_declaration, line 64)
- `id` (lexical_declaration, line 69)
- `file` (lexical_declaration, line 70)
- `ref` (lexical_declaration, line 75)
- `parts` (lexical_declaration, line 86, exported)
- `folded` (lexical_declaration, line 95, exported)

## Used by

- [core/converters/code.converter.ts](https://banes-lab.com/source/tree/core/converters/code.converter.ts.md)

## Source

```typescript
import {
    CALL_OPEN,
    EXTENSION_SEPARATOR,
    LOCAL_RULE_PREFIX,
    NON_PATH_CHARS,
    PATH_SEPARATOR,
    RULE_FILE_SUFFIX,
    SLOT_CALLEES,
    SLOT_DECLARATION,
    SLOT_QUOTES,
} from "#configuration/constants/anatomy.constants";
import type { CodeTarget, ReferenceLookups, TemplateParts } from "#types/code.types";
import { foldedOf, templatePartsOf } from "#core/converters/template.converter";
import { CONFIG_TAB } from "#core/ids/anatomy.ids";
import type { DefinitionIndex } from "#types/definition.types";
import { treeOf } from "#core/converters/folder.converter";

const isPathShaped = function isPathShaped(text: string): boolean {
    for (let at = 0; at < text.length; at += 1) {
        if (NON_PATH_CHARS.includes(text.charAt(at))) {
            return false;
        }
    }
    return text.includes(PATH_SEPARATOR) || text.includes(EXTENSION_SEPARATOR);
};

const exactTarget = function exactTarget(index: DefinitionIndex, text: string, path: string): CodeTarget | null {
    const specified = index.resolveSpecifier(text, path);
    const file = specified ?? (isPathShaped(text) ? index.resolveOwnPath(text, path) : null);
    if (file !== null) {
        return { kind: "file", path: file };
    }
    const folder = isPathShaped(text) ? index.resolveFolder(text, path) : null;
    return folder === null ? null : { kind: "folder", path: folder };
};

const openTarget = function openTarget(index: DefinitionIndex, parts: TemplateParts, path: string): CodeTarget | null {
    const literals = parts.literals.filter((literal) => literal.length > 0);
    if (!isPathShaped(literals.join(""))) {
        return null;
    }
    const matches = index.filesMatching(literals, path);
    const [only] = matches;
    if (matches.length === 1 && only !== undefined) {
        return { kind: "file", path: only };
    }
    return matches.length > 1
        ? { kind: "candidates", locations: matches.map((file) => ({ file, line: null, name: file })) }
        : null;
};

const isSlotArgument = function isSlotArgument(source: string, text: string): boolean {
    return SLOT_CALLEES.some((callee) =>
        SLOT_QUOTES.some((mark) => source.includes(callee + CALL_OPEN + mark + text + mark)),
    );
};

const slotTarget = function slotTarget(
    index: DefinitionIndex,
    text: string,
    path: string,
    source: string,
): CodeTarget | null {
    const declaration = isSlotArgument(source, text) ? index.resolveOwnPath(SLOT_DECLARATION, path) : null;
    return declaration === null ? null : { kind: "file", path: declaration };
};

const ruleTarget = function ruleTarget(index: DefinitionIndex, text: string): CodeTarget | null {
    const id = text.startsWith(LOCAL_RULE_PREFIX) ? text.slice(LOCAL_RULE_PREFIX.length) : "";
    const file = id.length === 0 ? null : index.resolvePath(id + RULE_FILE_SUFFIX);
    return file === null ? null : { kind: "file", path: file };
};

const catalogTarget = function catalogTarget(lookups: ReferenceLookups, text: string, path: string): CodeTarget | null {
    const ref = treeOf(path) === CONFIG_TAB ? lookups.ruleRecord(text) : null;
    return ref === null ? null : { kind: "record", ref };
};

export const literalTarget = function literalTarget(
    index: DefinitionIndex,
    lookups: ReferenceLookups,
    text: string,
    path: string,
    source: string,
): CodeTarget | null {
    const parts = templatePartsOf(text);
    if (parts === null) {
        return (
            exactTarget(index, text, path) ??
            slotTarget(index, text, path, source) ??
            ruleTarget(index, text) ??
            catalogTarget(lookups, text, path)
        );
    }
    const folded = foldedOf(parts, source);
    return folded === null ? openTarget(index, parts, path) : exactTarget(index, folded, path);
};
```
