# core/resolvers/specifier.resolver.ts

> 110 lines of code and 28 definitions.

Tree: Project Scripts
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/scripts#file-scripts-core-resolvers-specifier-resolver-ts
Source text: https://banes-lab.com/source/scripts/core/resolvers/specifier.resolver.ts.txt

Listed in [core/resolvers](https://banes-lab.com/api/source/scripts/core/resolvers.md), after [core/resolvers/pattern.resolver.ts](https://banes-lab.com/source/scripts/core/resolvers/pattern.resolver.ts.md).

## Definitions

- `anchorPackageSpecifier` (lexical_declaration, line 70)
- `resolveSelfImport` (lexical_declaration, line 41, exported)
- `relativeSpecifier` (lexical_declaration, line 27, exported)
- `exportTargetOf` (lexical_declaration, line 62)
- `selfImportTargets` (lexical_declaration, line 18, exported)
- `anchorSpecifier` (lexical_declaration, line 102, exported)
- `SEPARATOR` (lexical_declaration, line 12)
- `HERE` (lexical_declaration, line 13)
- `UP` (lexical_declaration, line 14)
- `WILD_SEGMENT` (lexical_declaration, line 15)
- `WILD_FILE` (lexical_declaration, line 16)
- `from` (lexical_declaration, line 31, exported)
- `to` (lexical_declaration, line 32, exported)
- `shared` (lexical_declaration, line 33, exported)
- `up` (lexical_declaration, line 37, exported)
- `slash` (lexical_declaration, line 49, exported)
- `tail` (lexical_declaration, line 54, exported)
- `cut` (lexical_declaration, line 55, exported)
- `match` (lexical_declaration, line 66)
- `name` (lexical_declaration, line 71)
- `main` (lexical_declaration, line 72)
- `scoped` (lexical_declaration, line 82)
- `anchorSelfImport` (lexical_declaration, line 88)
- `relPath` (lexical_declaration, line 94)
- `resolved` (lexical_declaration, line 98)
- `relativeTarget` (lexical_declaration, line 109, exported)
- `absolute` (lexical_declaration, line 115, exported)
- `target` (lexical_declaration, line 116, exported)

## Contained in

- [core/resolvers](https://banes-lab.com/anatomy/scripts/folder-scripts-core-resolvers.md)

## Uses

- [core/selectors/manifest.selector.ts](https://banes-lab.com/source/scripts/core/selectors/manifest.selector.ts.md)

## Used by

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

## Linked from

- [core/analyzers](https://banes-lab.com/anatomy/scripts/folder-scripts-core-analyzers.md)
- [core/resolvers](https://banes-lab.com/anatomy/scripts/folder-scripts-core-resolvers.md)
- [core/selectors](https://banes-lab.com/anatomy/scripts/folder-scripts-core-selectors.md)

## Source

```typescript
import {
    PARENT_SEGMENT,
    RELATIVE_MARK,
    SELF_IMPORT_MARK,
    SOURCE_EXTENSION,
    WILDCARD,
} from "#configuration/constants/closure.constants";
import { dirname, relative, resolve } from "node:path";
import { exportPatternsOf, stringAt, stringRecordAt } from "#core/selectors/manifest.selector";
import { normalizePath } from "@ssot/govlab/shared/resolvers/anchor.resolver.ts";

const SEPARATOR = "/";
const HERE = "./";
const UP = "../";
const WILD_SEGMENT = `${SEPARATOR}${WILDCARD}`;
const WILD_FILE = `${WILD_SEGMENT}${SOURCE_EXTENSION}`;

export const selfImportTargets = function selfImportTargets(manifest: unknown): ReadonlyMap<string, string> {
    return new Map(
        Object.entries(stringRecordAt(manifest, "imports")).map(([key, target]) => [
            key.replace(WILD_SEGMENT, ""),
            target.replace(WILD_FILE, "").replace(HERE, ""),
        ]),
    );
};

export const relativeSpecifier = function relativeSpecifier(fromDir: string, target: string): string {
    if (fromDir === "") {
        return `${HERE}${target}`;
    }
    const from = fromDir.split(SEPARATOR);
    const to = target.split(SEPARATOR);
    let shared = 0;
    while (shared < from.length && shared < to.length && from[shared] === to[shared]) {
        shared += 1;
    }
    const up = from.length - shared;
    return `${up === 0 ? HERE : UP.repeat(up)}${to.slice(shared).join(SEPARATOR)}`;
};

export const resolveSelfImport = function resolveSelfImport(
    targets: ReadonlyMap<string, string>,
    specifier: string,
    relPath: string,
): string {
    if (!specifier.startsWith(SELF_IMPORT_MARK)) {
        return specifier;
    }
    const slash = specifier.indexOf(SEPARATOR);
    const target = targets.get(slash === -1 ? specifier : specifier.slice(0, slash));
    if (target === undefined) {
        return specifier;
    }
    const tail = slash === -1 ? "" : specifier.slice(slash + 1);
    const cut = relPath.lastIndexOf(SEPARATOR);
    return relativeSpecifier(
        cut === -1 ? "" : relPath.slice(0, cut),
        `${target}${SEPARATOR}${tail}${SOURCE_EXTENSION}`,
    );
};

const exportTargetOf = function exportTargetOf(
    patterns: readonly (readonly [string, string])[],
    subpath: string,
): string {
    const match = patterns.find(([prefix]) => subpath.startsWith(prefix));
    return match === undefined ? subpath : match[1].replace(WILDCARD, subpath.slice(match[0].length));
};

const anchorPackageSpecifier = function anchorPackageSpecifier(manifest: unknown, specifier: string): string {
    const name = stringAt(manifest, "name");
    const main = stringAt(manifest, "main");
    if (name === "") {
        return specifier;
    }
    if (specifier === name && main === "") {
        return specifier;
    }
    if (specifier === name) {
        return main.startsWith(HERE) ? main : `${HERE}${main}`;
    }
    const scoped = `${name}${SEPARATOR}`;
    return specifier.startsWith(scoped)
        ? exportTargetOf(exportPatternsOf(manifest), `${HERE}${specifier.slice(scoped.length)}`)
        : specifier;
};

const anchorSelfImport = function anchorSelfImport(
    root: string,
    manifest: unknown,
    filePath: string,
    specifier: string,
): string | null {
    const relPath = normalizePath(relative(root, filePath));
    if (relPath.startsWith(PARENT_SEGMENT)) {
        return null;
    }
    const resolved = resolveSelfImport(selfImportTargets(manifest), specifier, relPath);
    return resolved === specifier ? null : resolved;
};

export const anchorSpecifier = function anchorSpecifier(
    root: string,
    manifest: unknown,
    filePath: string,
    specifier: string,
): string {
    if (specifier.startsWith(SELF_IMPORT_MARK)) {
        const relativeTarget = anchorSelfImport(root, manifest, filePath, specifier);
        return relativeTarget === null ? specifier : anchorSpecifier(root, manifest, filePath, relativeTarget);
    }
    if (!specifier.startsWith(RELATIVE_MARK)) {
        return anchorPackageSpecifier(manifest, specifier);
    }
    const absolute = resolve(dirname(filePath), specifier);
    const target = normalizePath(relative(root, absolute));
    return target.startsWith(PARENT_SEGMENT) ? specifier : `${HERE}${target}`;
};
```
