# core/loaders/code.loader.ts

> 72 lines of code and 15 definitions.

Tree: GovLab Stats
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/stats#file-stats-core-loaders-code-loader-ts
Source text: https://banes-lab.com/source/stats/core/loaders/code.loader.ts.txt

Listed in [core/loaders](https://banes-lab.com/api/source/stats/core/loaders.md), after [core/loaders/catalog.loader.ts](https://banes-lab.com/source/stats/core/loaders/catalog.loader.ts.md) and before [core/loaders/config.loader.ts](https://banes-lab.com/source/stats/core/loaders/config.loader.ts.md).

## Definitions

- `flowCounts` (lexical_declaration, line 46)
- `sumOf` (lexical_declaration, line 54)
- `readModuleAnalysis` (lexical_declaration, line 29)
- `collectAnalysis` (lexical_declaration, line 58, exported)
- `findAnalysisFiles` (lexical_declaration, line 12)
- `hexDir` (lexical_declaration, line 13)
- `entries` (lexical_declaration, line 14)
- `here` (lexical_declaration, line 15)
- `deeper` (lexical_declaration, line 21)
- `data` (lexical_declaration, line 30)
- `summary` (lexical_declaration, line 34)
- `counts` (lexical_declaration, line 47)
- `modules` (lexical_declaration, line 59, exported)
- `edges` (lexical_declaration, line 62, exported)
- `unresolvedCalls` (lexical_declaration, line 63, exported)

## Contained in

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

## Uses

- [core/predicates/record.predicate.ts](https://banes-lab.com/source/stats/core/predicates/record.predicate.ts.md)
- [core/selectors/field.selector.ts](https://banes-lab.com/source/stats/core/selectors/field.selector.ts.md)

## Linked from

- [core/loaders](https://banes-lab.com/anatomy/stats/folder-stats-core-loaders.md)
- [core/predicates](https://banes-lab.com/anatomy/stats/folder-stats-core-predicates.md)
- [core/selectors](https://banes-lab.com/anatomy/stats/folder-stats-core-selectors.md)

## Source

```typescript
import type { AnalysisStats, ModuleAnalysis } from "#types/code.types";
import { arrayField, field, numberField, stringField } from "#core/selectors/field.selector";
import { ANALYSIS_SEARCH_DEPTH } from "#configuration/constants/code.constants";
import type { PathExclusion } from "@govlab/quality/config";
import { TOP_MODULES } from "#configuration/constants/metric.constants";
import { isRecord } from "#core/predicates/record.predicate";
import path from "node:path";
import { readJson } from "#core/loaders/data.loader";
import { readdirSafe } from "#core/loaders/folder.loader";
import { relativePath } from "@ssot/paths";

const findAnalysisFiles = function findAnalysisFiles(absDir: string, depth: number, ignore: PathExclusion): string[] {
    const hexDir = relativePath("moduleInfo.root");
    const entries = readdirSafe(absDir);
    const here = entries.some((entry) => entry.isDirectory() && entry.name === hexDir)
        ? [path.join(absDir, relativePath("moduleInfo.analysis"))]
        : [];
    if (depth > ANALYSIS_SEARCH_DEPTH) {
        return here;
    }
    const deeper = entries
        .filter((entry) => entry.isDirectory() && entry.name !== hexDir)
        .map((entry) => path.join(absDir, entry.name))
        .filter((dir) => !ignore(dir))
        .flatMap((dir) => findAnalysisFiles(dir, depth + 1, ignore));
    return [...here, ...deeper];
};

const readModuleAnalysis = function readModuleAnalysis(file: string): ModuleAnalysis | null {
    const data = readJson(file);
    if (!isRecord(data)) {
        return null;
    }
    const summary = field(data, "summary");
    return {
        definitions: numberField(summary, "definitions", 0),
        edges: numberField(summary, "edges", 0),
        flows: arrayField(data, "definitions")
            .map((definition) => stringField(definition, "flow"))
            .filter((flow) => flow.length > 0),
        module: stringField(data, "module"),
        unresolvedCalls: numberField(summary, "unresolvedCalls", 0),
    };
};

const flowCounts = function flowCounts(modules: readonly ModuleAnalysis[]): Map<string, number> {
    const counts = new Map<string, number>();
    for (const flow of modules.flatMap((module) => module.flows)) {
        counts.set(flow, (counts.get(flow) ?? 0) + 1);
    }
    return counts;
};

const sumOf = function sumOf(modules: readonly ModuleAnalysis[], pick: (module: ModuleAnalysis) => number): number {
    return modules.reduce((total, module) => total + pick(module), 0);
};

export const collectAnalysis = function collectAnalysis(root: string, ignore: PathExclusion): AnalysisStats {
    const modules = findAnalysisFiles(root, 0, ignore)
        .map((file) => readModuleAnalysis(file))
        .filter((module): module is ModuleAnalysis => module !== null);
    const edges = sumOf(modules, (module) => module.edges);
    const unresolvedCalls = sumOf(modules, (module) => module.unresolvedCalls);
    return {
        byFlow: flowCounts(modules),
        definitions: sumOf(modules, (module) => module.definitions),
        edges,
        modulesAnalyzed: modules.length,
        producer: relativePath("govlab.patterns"),
        resolutionRate: edges > 0 ? (edges - unresolvedCalls) / edges : 0,
        topByDefinitions: modules
            .toSorted((left, right) => right.definitions - left.definitions)
            .slice(0, TOP_MODULES)
            .map((module) => ({ definitions: module.definitions, module: module.module })),
        unresolvedCalls,
    };
};
```
