# core/loaders/base.loader.ts

> 40 lines of code and 8 definitions.

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

Listed in [core/loaders](https://banes-lab.com/api/source/docs/core/loaders.md), before [core/loaders/code.loader.ts](https://banes-lab.com/source/docs/core/loaders/code.loader.ts.md).

## Definitions

- `readDirSafe` (lexical_declaration, line 28, exported)
- `readTextSafe` (lexical_declaration, line 5, exported)
- `isDirectory` (lexical_declaration, line 24, exported)
- `walkFiles` (lexical_declaration, line 38, exported)
- `sortedNames` (lexical_declaration, line 32, exported)
- `readJsonSafe` (lexical_declaration, line 9, exported)
- `text` (lexical_declaration, line 10, exported)
- `full` (lexical_declaration, line 40, exported)

## Contained in

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

## Uses

- [core/factories/environment.factory.ts](https://banes-lab.com/source/docs/core/factories/environment.factory.ts.md)

## Used by

- [core/analyzers/package.analyzer.ts](https://banes-lab.com/source/docs/core/analyzers/package.analyzer.ts.md)
- [core/coordinators/document.coordinator.ts](https://banes-lab.com/source/docs/core/coordinators/document.coordinator.ts.md)
- [core/coordinators/index.coordinator.ts](https://banes-lab.com/source/docs/core/coordinators/index.coordinator.ts.md)
- [core/counters/source.counter.ts](https://banes-lab.com/source/docs/core/counters/source.counter.ts.md)
- [core/factories/environment.factory.ts](https://banes-lab.com/source/docs/core/factories/environment.factory.ts.md)
- [core/loaders/manifest.loader.ts](https://banes-lab.com/source/docs/core/loaders/manifest.loader.ts.md)
- [core/loaders/package.loader.ts](https://banes-lab.com/source/docs/core/loaders/package.loader.ts.md)
- [core/loaders/system.loader.ts](https://banes-lab.com/source/docs/core/loaders/system.loader.ts.md)
- [core/matchers/segment.matcher.ts](https://banes-lab.com/source/docs/core/matchers/segment.matcher.ts.md)
- [core/persistence/document.persistence.ts](https://banes-lab.com/source/docs/core/persistence/document.persistence.ts.md)
- [core/resolvers/barrel.resolver.ts](https://banes-lab.com/source/docs/core/resolvers/barrel.resolver.ts.md)

## Linked from

- [core/analyzers](https://banes-lab.com/anatomy/docs/folder-docs-core-analyzers.md)
- [core/coordinators](https://banes-lab.com/anatomy/docs/folder-docs-core-coordinators.md)
- [core/counters](https://banes-lab.com/anatomy/docs/folder-docs-core-counters.md)
- [core/factories](https://banes-lab.com/anatomy/docs/folder-docs-core-factories.md)
- [core/loaders](https://banes-lab.com/anatomy/docs/folder-docs-core-loaders.md)
- [core/matchers](https://banes-lab.com/anatomy/docs/folder-docs-core-matchers.md)
- [core/persistence](https://banes-lab.com/anatomy/docs/folder-docs-core-persistence.md)
- [core/resolvers](https://banes-lab.com/anatomy/docs/folder-docs-core-resolvers.md)

## Source

```typescript
import { type Dirent, existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import type { PathExclusion } from "@govlab/quality/config";
import { join } from "node:path";

export const readTextSafe = function readTextSafe(path: string): string | null {
    return existsSync(path) && statSync(path).isFile() ? readFileSync(path, "utf8") : null;
};

export const readJsonSafe = function readJsonSafe(path: string): unknown {
    const text = readTextSafe(path);
    if (text === null) {
        return null;
    }
    try {
        return JSON.parse(text);
    } catch (error) {
        if (!(error instanceof SyntaxError)) {
            throw error;
        }
        return null;
    }
};

export const isDirectory = function isDirectory(path: string): boolean {
    return existsSync(path) && statSync(path).isDirectory();
};

export const readDirSafe = function readDirSafe(dir: string): Dirent[] {
    return isDirectory(dir) ? readdirSync(dir, { withFileTypes: true }) : [];
};

export const sortedNames = function sortedNames(dir: string): string[] {
    return readDirSafe(dir)
        .map((entry) => entry.name)
        .toSorted((left, right) => left.localeCompare(right));
};

export const walkFiles = function walkFiles(dir: string, excluded: PathExclusion): string[] {
    return readDirSafe(dir).flatMap((entry): string[] => {
        const full = join(dir, entry.name);
        if (entry.isDirectory()) {
            return excluded(full) ? [] : walkFiles(full, excluded);
        }
        return entry.isFile() ? [full] : [];
    });
};
```
