core/resolvers/specifier.resolver.ts
core/resolvers/specifier.resolver.ts is a file in Project Scripts. 110 lines of code and 28 definitions.
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}`;
};