# core/factories/context.factory.ts

> 43 lines of code and 11 definitions.

Tree: GovLab Patterns
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/patterns#file-patterns-core-factories-context-factory-ts
Source text: https://banes-lab.com/source/patterns/core/factories/context.factory.ts.txt

Listed in [core/factories](https://banes-lab.com/api/source/patterns/core/factories.md), after [core/factories/axis.factory.ts](https://banes-lab.com/source/patterns/core/factories/axis.factory.ts.md) and before [core/factories/field.factory.ts](https://banes-lab.com/source/patterns/core/factories/field.factory.ts.md).

## Definitions

- `importEdges` (lexical_declaration, line 18)
- `buildContext` (lexical_declaration, line 30, exported)
- `PATH_SEP` (lexical_declaration, line 10)
- `importsOf` (lexical_declaration, line 12)
- `files` (lexical_declaration, line 13)
- `perFile` (lexical_declaration, line 14)
- `target` (lexical_declaration, line 24)
- `packageMap` (lexical_declaration, line 34, exported)
- `units` (lexical_declaration, line 35, exported)
- `repoRel` (lexical_declaration, line 36, exported)
- `emptyContext` (lexical_declaration, line 46, exported)

## Contained in

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

## Uses

- [core/analyzers/dependency.analyzer.ts](https://banes-lab.com/source/patterns/core/analyzers/dependency.analyzer.ts.md)
- [core/counters/dependency.counter.ts](https://banes-lab.com/source/patterns/core/counters/dependency.counter.ts.md)

## Linked from

- [core/analyzers](https://banes-lab.com/anatomy/patterns/folder-patterns-core-analyzers.md)
- [core/counters](https://banes-lab.com/anatomy/patterns/folder-patterns-core-counters.md)
- [core/factories](https://banes-lab.com/anatomy/patterns/folder-patterns-core-factories.md)

## Source

```typescript
import type { ModuleEdge, ModuleUnit } from "#types/code.types";
import type { ModuleScope, RepoContext } from "#types/package.types";
import { buildPackageMap, sourceFiles } from "#core/loaders/package.loader";
import { relative, sep } from "node:path";
import { crossModuleFanIn } from "#core/counters/dependency.counter";
import { ingestImports } from "#core/parsers/code.parser";
import { moduleImportCycleFindings } from "#core/analyzers/dependency.analyzer";
import { readSourceOrEmpty } from "#core/loaders/source.loader";

const PATH_SEP = "/";

const importsOf = async function importsOf(moduleDir: string, scope: ModuleScope): Promise<ModuleUnit> {
    const files = sourceFiles(moduleDir, scope.pruned);
    const perFile = await Promise.all(files.map(async (file) => ingestImports(readSourceOrEmpty(file), file)));
    return { imports: perFile.flat(), moduleDir };
};

const importEdges = function importEdges(
    units: readonly ModuleUnit[],
    packageMap: ReadonlyMap<string, string>,
): ModuleEdge[] {
    return units.flatMap((unit) =>
        unit.imports.flatMap((binding) => {
            const target = packageMap.get(binding.source);
            return target !== undefined && target !== unit.moduleDir ? [{ from: unit.moduleDir, to: target }] : [];
        }),
    );
};

export const buildContext = async function buildContext(
    modules: readonly string[],
    scope: ModuleScope,
): Promise<RepoContext> {
    const packageMap = buildPackageMap(modules);
    const units = await Promise.all(modules.map(async (moduleDir) => importsOf(moduleDir, scope)));
    const repoRel = function repoRel(file: string): string {
        return relative(scope.root, file).split(sep).join(PATH_SEP);
    };
    return {
        fanIn: crossModuleFanIn(units, packageMap),
        importCycles: moduleImportCycleFindings(importEdges(units, packageMap), repoRel),
        packageMap,
    };
};

export const emptyContext = function emptyContext(): RepoContext {
    return { fanIn: new Map(), importCycles: new Map(), packageMap: new Map() };
};
```
