# tools/core/resolvers/dependency.resolver.ts

> 162 lines of code and 30 definitions.

Tree: Coordination tree
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-resolvers-dependency-resolver-ts
Source text: https://banes-lab.com/assets/sources/source.061042f5db541161407afcf253082d6e8c86048a98ca807ca2adf38e65a9f3e0.generated.txt

## Definitions

- `dependencyReach` (lexical_declaration, line 137, exported)
- `scriptTokens` (lexical_declaration, line 74)
- `record` (lexical_declaration, line 27)
- `reachedBySpecifier` (lexical_declaration, line 117)
- `reachedAsTypePackage` (lexical_declaration, line 130)
- `corpusLiterals` (lexical_declaration, line 92)
- `parse` (lexical_declaration, line 34)
- `DependencyReach` (interface_declaration, line 19, exported)
- `declaredDependencies` (lexical_declaration, line 42, exported)
- `held` (lexical_declaration, line 45, exported)
- `invocableNames` (lexical_declaration, line 56)
- `installed` (lexical_declaration, line 57)
- `bin` (lexical_declaration, line 62)
- `map` (lexical_declaration, line 67)
- `scripts` (lexical_declaration, line 75)
- `out` (lexical_declaration, line 80, exported)
- `literals` (lexical_declaration, line 96)
- `tokens` (lexical_declaration, line 97)
- `corpus` (lexical_declaration, line 98)
- `skip` (lexical_declaration, line 99)
- `scoped` (lexical_declaration, line 121)
- `manifest` (lexical_declaration, line 138, exported)
- `declared` (lexical_declaration, line 143, exported)
- `{ literals, tokens, corpus }` (lexical_declaration, line 144, exported)
- `reached` (lexical_declaration, line 149, exported)
- `unreached` (lexical_declaration, line 150, exported)
- `undetermined` (lexical_declaration, line 151, exported)
- `invocable` (lexical_declaration, line 159, exported)
- `found` (lexical_declaration, line 165, exported)
- `installRootPresent` (lexical_declaration, line 184, exported)

## Uses

- [tools/core/predicates/literal.predicate.ts](https://banes-lab.com/source/coordination/tools/core/predicates/literal.predicate.ts.md)
- [tools/core/predicates/text.predicate.ts](https://banes-lab.com/source/coordination/tools/core/predicates/text.predicate.ts.md)

## Used by

- [tools/core/inspectors/manifest.inspector.ts](https://banes-lab.com/source/coordination/tools/core/inspectors/manifest.inspector.ts.md)

## Source

```typescript
import {
    BIN_FIELD,
    DEPENDENCY_FIELDS,
    INSTALL_ROOT,
    REACH_EXTENSIONS,
    SCRIPTS_FIELD,
    SPECIFIER_SEPARATOR,
    TYPE_PACKAGE_PREFIX,
} from "../constants/dependency.constants.ts";
import { basename, resolve } from "node:path";

import { existsSync, readFileSync } from "node:fs";
import { hasPrefix, splitWords } from "../predicates/text.predicate.ts";
import { NODE_MODULES } from "../constants/path.constants.ts";
import { slotText } from "../../../config/surface.config.ts";
import { stringLiterals } from "../predicates/literal.predicate.ts";
import { walk } from "../iterators/file.iterator.ts";

export interface DependencyReach {
    readonly declared: readonly string[];
    readonly reached: readonly string[];
    readonly unreached: readonly string[];
    readonly undetermined: readonly string[];
    readonly corpus: readonly string[];
}

const record = function record(value: unknown): Record<string, unknown> | null {
    if (typeof value !== "object" || value === null || Array.isArray(value)) {
        return null;
    }
    return value as Record<string, unknown>;
};

const parse = function parse(path: string): Record<string, unknown> | null {
    try {
        return record(JSON.parse(readFileSync(path, "utf8")));
    } catch {
        return null;
    }
};

export const declaredDependencies = function declaredDependencies(manifest: Record<string, unknown>): string[] {
    const out: string[] = [];
    for (const field of DEPENDENCY_FIELDS) {
        const held = record(manifest[field]);
        if (held === null) {
            continue;
        }
        for (const name of Object.keys(held)) {
            out.push(name);
        }
    }
    return out;
};

const invocableNames = function invocableNames(packageDir: string, name: string): string[] | null {
    const installed = parse(resolve(packageDir, INSTALL_ROOT, ...name.split(SPECIFIER_SEPARATOR), "package.json"));
    if (installed === null) {
        return null;
    }

    const bin = installed[BIN_FIELD];
    if (typeof bin === "string") {
        return [basename(bin), name];
    }

    const map = record(bin);
    if (map === null) {
        return [name];
    }
    return [...Object.keys(map), name];
};

const scriptTokens = function scriptTokens(manifest: Record<string, unknown>): string[] {
    const scripts = record(manifest[SCRIPTS_FIELD]);
    if (scripts === null) {
        return [];
    }

    const out: string[] = [];
    for (const command of Object.values(scripts)) {
        if (typeof command !== "string") {
            continue;
        }
        for (const token of splitWords(command)) {
            out.push(token);
        }
    }
    return out;
};

const corpusLiterals = function corpusLiterals(
    packageDir: string,
    manifestPath: string,
): { literals: Set<string>; tokens: Set<string>; corpus: string[] } {
    const literals = new Set<string>();
    const tokens = new Set<string>();
    const corpus: string[] = [];
    const skip = [NODE_MODULES, ".git", slotText("surface", "generated")];

    for (const file of walk({ extensions: REACH_EXTENSIONS, ignored: skip, root: packageDir })) {
        if (file === manifestPath) {
            continue;
        }
        corpus.push(file);
        for (const literal of stringLiterals(readFileSync(file, "utf8"))) {
            literals.add(literal.value);
            for (const word of splitWords(literal.value)) {
                tokens.add(word);
            }
        }
    }

    return { corpus, literals, tokens };
};

const reachedBySpecifier = function reachedBySpecifier(literals: ReadonlySet<string>, name: string): boolean {
    if (literals.has(name)) {
        return true;
    }
    const scoped = name + SPECIFIER_SEPARATOR;
    for (const literal of literals) {
        if (hasPrefix(literal, scoped)) {
            return true;
        }
    }
    return false;
};

const reachedAsTypePackage = function reachedAsTypePackage(literals: ReadonlySet<string>, name: string): boolean {
    if (!hasPrefix(name, TYPE_PACKAGE_PREFIX)) {
        return false;
    }
    return literals.has(name.slice(TYPE_PACKAGE_PREFIX.length));
};

export const dependencyReach = function dependencyReach(packageDir: string, manifestPath: string): DependencyReach {
    const manifest = parse(manifestPath);
    if (manifest === null) {
        return { corpus: [], declared: [], reached: [], undetermined: [], unreached: [] };
    }

    const declared = declaredDependencies(manifest);
    const { literals, tokens, corpus } = corpusLiterals(packageDir, manifestPath);
    for (const token of scriptTokens(manifest)) {
        tokens.add(token);
    }

    const reached: string[] = [];
    const unreached: string[] = [];
    const undetermined: string[] = [];

    for (const name of declared) {
        if (reachedBySpecifier(literals, name) || reachedAsTypePackage(literals, name) || tokens.has(name)) {
            reached.push(name);
            continue;
        }

        const invocable = invocableNames(packageDir, name);
        if (invocable === null) {
            undetermined.push(name);
            continue;
        }

        let found = false;
        for (const invocation of invocable) {
            if (!tokens.has(invocation)) {
                continue;
            }
            found = true;
            break;
        }

        if (found) {
            reached.push(name);
        } else {
            unreached.push(name);
        }
    }

    return { corpus, declared, reached, undetermined, unreached };
};

export const installRootPresent = function installRootPresent(packageDir: string): boolean {
    return existsSync(resolve(packageDir, INSTALL_ROOT));
};
```
