# core/converters/code.converter.ts

> 128 lines of code and 31 definitions.

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

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

## Definitions

- `targetsOf` (lexical_declaration, line 94)
- `nameTarget` (lexical_declaration, line 76)
- `targetIn` (lexical_declaration, line 134, exported)
- `codeReferencesOf` (lexical_declaration, line 110, exported)
- `spanTarget` (lexical_declaration, line 85)
- `unquoted` (lexical_declaration, line 44, exported)
- `WORD_CHARS` (lexical_declaration, line 12)
- `wordsOf` (lexical_declaration, line 14, exported)
- `parts` (lexical_declaration, line 15, exported)
- `current` (lexical_declaration, line 16, exported)
- `word` (lexical_declaration, line 17, exported)
- `isWord` (lexical_declaration, line 19, exported)
- `quotedIn` (lexical_declaration, line 30)
- `at` (lexical_declaration, line 32)
- `mark` (lexical_declaration, line 34)
- `close` (lexical_declaration, line 35)
- `trimmed` (lexical_declaration, line 45, exported)
- `first` (lexical_declaration, line 46, exported)
- `last` (lexical_declaration, line 47, exported)
- `proseOf` (lexical_declaration, line 53)
- `locations` (lexical_declaration, line 77)
- `[only]` (lexical_declaration, line 78)
- `file` (lexical_declaration, line 86)
- `folder` (lexical_declaration, line 90)
- `out` (lexical_declaration, line 98)
- `found` (lexical_declaration, line 100)
- `NO_LOOKUPS` (lexical_declaration, line 108)
- `bindings` (lexical_declaration, line 117, exported)
- `words` (lexical_declaration, line 118, exported)
- `spans` (lexical_declaration, line 119, exported)
- `{ sites, targets }` (lexical_declaration, line 120, exported)

## Uses

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

## Used by

- [presentation/components/source.component.ts](https://banes-lab.com/source/tree/presentation/components/source.component.ts.md)
- [vite.config.ts](https://banes-lab.com/source/tree/vite.config.ts.md)

## Source

```typescript
import type { CodeTarget, ReferenceLookups, SourceReferences } from "#types/code.types";
import { DIGITS, LETTERS } from "#configuration/constants/syntax.constants";
import type { DefinitionIndex } from "#types/definition.types";
import { LINE_BREAK } from "#configuration/constants/code.constants";
import type { MarkdownNode } from "#types/markdown.types";
import { QUOTE_MARKS } from "#configuration/constants/anatomy.constants";
import { bindingSitesOf } from "#core/converters/binding.converter";
import { inlineCode } from "#core/normalizers/markdown.normalizer";
import { literalTarget } from "#core/converters/literal.converter";
import { parseMarkdown } from "#core/converters/markdown.converter";

const WORD_CHARS = LETTERS + DIGITS;

export const wordsOf = function wordsOf(text: string): string[] {
    const parts: string[] = [];
    let current = "";
    let word = false;
    for (const char of text) {
        const isWord = WORD_CHARS.includes(char);
        if (current.length > 0 && isWord !== word) {
            parts.push(current);
            current = "";
        }
        current += char;
        word = isWord;
    }
    return current.length === 0 ? parts : [...parts, current];
};

const quotedIn = function quotedIn(line: string): string[] {
    const found: string[] = [];
    let at = 0;
    while (at < line.length) {
        const mark = line.charAt(at);
        const close = QUOTE_MARKS.includes(mark) ? line.indexOf(mark, at + 1) : -1;
        if (close !== -1) {
            found.push(line.slice(at + 1, close));
        }
        at = close === -1 ? at + 1 : close + 1;
    }
    return found;
};

export const unquoted = function unquoted(text: string): string {
    const trimmed = text.trim();
    const first = trimmed.charAt(0);
    const last = trimmed.slice(-1);
    return first.length > 0 && QUOTE_MARKS.includes(first) && QUOTE_MARKS.includes(last)
        ? trimmed.slice(1, -1)
        : trimmed;
};

const proseOf = function proseOf(node: MarkdownNode): readonly string[] {
    switch (node.kind) {
        case "list": {
            return node.items;
        }
        case "paragraph":
        case "quote": {
            return [node.text];
        }
        case "table": {
            return [...node.headers, ...node.rows.flat()];
        }
        case "code":
        case "heading":
        case "rule": {
            return [];
        }
        default: {
            return [];
        }
    }
};

const nameTarget = function nameTarget(index: DefinitionIndex, name: string, path: string): CodeTarget | null {
    const locations = index.moduleDefinitionsNamedFrom(name, path);
    const [only] = locations;
    if (locations.length === 1 && only !== undefined) {
        return { kind: "definition", location: only };
    }
    return locations.length > 1 ? { kind: "candidates", locations } : null;
};

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

const targetsOf = function targetsOf(
    texts: Iterable<string>,
    target: (text: string) => CodeTarget | null,
): Record<string, CodeTarget> {
    const out = new Map<string, CodeTarget>();
    for (const text of new Set(texts)) {
        const found = target(text);
        if (found !== null) {
            out.set(text, found);
        }
    }
    return Object.fromEntries(out);
};

const NO_LOOKUPS: ReferenceLookups = { bindings: () => null, records: new Set(), ruleRecord: () => null };

export const codeReferencesOf = function codeReferencesOf(
    index: DefinitionIndex,
    path: string,
    text: string,
    document: boolean,
    lookups: ReferenceLookups = NO_LOOKUPS,
): SourceReferences {
    const bindings = document ? null : lookups.bindings(path);
    const words = bindings === null ? wordsOf(text).filter((part) => WORD_CHARS.includes(part.charAt(0))) : [];
    const spans = document ? parseMarkdown(text).flatMap(proseOf).flatMap(inlineCode) : [];
    const { sites, targets } = bindingSitesOf(index, bindings ?? []);
    return {
        sites,
        spans: targetsOf(spans, (span) =>
            lookups.records.has(span) ? { kind: "record", ref: span } : spanTarget(index, span, path),
        ),
        strings: targetsOf(text.split(LINE_BREAK).flatMap(quotedIn), (quoted) =>
            literalTarget(index, lookups, quoted, path, text),
        ),
        targets,
        words: targetsOf(words, (word) => nameTarget(index, word, path)),
    };
};

export const targetIn = function targetIn(
    targets: Readonly<Record<string, CodeTarget>>,
    text: string,
): CodeTarget | null {
    return Object.hasOwn(targets, text) ? (targets[text] ?? null) : null;
};
```
