# core/resolvers/scope.resolver.ts

> 101 lines of code and 25 definitions.

Tree: GovLab Quality
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-resolvers-scope-resolver-ts
Source text: https://banes-lab.com/source/quality/core/resolvers/scope.resolver.ts.txt

Listed in [core/resolvers](https://banes-lab.com/api/source/quality/core/resolvers.md), after [core/resolvers/rule.resolver.ts](https://banes-lab.com/source/quality/core/resolvers/rule.resolver.ts.md) and before [core/resolvers/surface.resolver.ts](https://banes-lab.com/source/quality/core/resolvers/surface.resolver.ts.md).

## Definitions

- `scopeTargets` (lexical_declaration, line 59, exported)
- `detectEcosystems` (lexical_declaration, line 32, exported)
- `walkDir` (lexical_declaration, line 89)
- `resolveScopedFiles` (lexical_declaration, line 103, exported)
- `defaultPathsFor` (lexical_declaration, line 44, exported)
- `projectDirWithMarker` (lexical_declaration, line 48, exported)
- `posix` (lexical_declaration, line 80)
- `matchesExtension` (lexical_declaration, line 84)
- `scopedFiles` (lexical_declaration, line 112, exported)
- `registryEcosystems` (lexical_declaration, line 28)
- `GLOB_STAR_DOT` (lexical_declaration, line 17)
- `BRACE_OPEN` (lexical_declaration, line 18)
- `BRACE_CLOSE` (lexical_declaration, line 19)
- `NOT_FOUND` (lexical_declaration, line 20)
- `Scan` (interface_declaration, line 22)
- `known` (lexical_declaration, line 33, exported)
- `ecosystem` (lexical_declaration, line 36, exported)
- `found` (lexical_declaration, line 53, exported)
- `globExtensions` (lexical_declaration, line 65)
- `star` (lexical_declaration, line 66)
- `tail` (lexical_declaration, line 70)
- `dot` (lexical_declaration, line 85)
- `full` (lexical_declaration, line 91)
- `rel` (lexical_declaration, line 92)
- `exts` (lexical_declaration, line 108, exported)

## Contained in

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

## Uses

- [core/loaders/config.loader.ts](https://banes-lab.com/source/quality/core/loaders/config.loader.ts.md)
- [core/loaders/dependency.loader.ts](https://banes-lab.com/source/quality/core/loaders/dependency.loader.ts.md)
- [core/loaders/ecosystem.loader.ts](https://banes-lab.com/source/quality/core/loaders/ecosystem.loader.ts.md)
- [core/loaders/source.loader.ts](https://banes-lab.com/source/quality/core/loaders/source.loader.ts.md)
- [core/matchers/exclusions.matcher.ts](https://banes-lab.com/source/quality/core/matchers/exclusions.matcher.ts.md)
- [core/selectors/exclusions.selector.ts](https://banes-lab.com/source/quality/core/selectors/exclusions.selector.ts.md)

## Used by

- [core/adapters/tool.brakeman.adapter.ts](https://banes-lab.com/source/quality/core/adapters/tool.brakeman.adapter.ts.md)
- [core/adapters/tool.checkov.adapter.ts](https://banes-lab.com/source/quality/core/adapters/tool.checkov.adapter.ts.md)
- [core/adapters/tool.clippy.adapter.ts](https://banes-lab.com/source/quality/core/adapters/tool.clippy.adapter.ts.md)
- [core/adapters/tool.tflint.adapter.ts](https://banes-lab.com/source/quality/core/adapters/tool.tflint.adapter.ts.md)
- [core/adapters/tool.trivy.adapter.ts](https://banes-lab.com/source/quality/core/adapters/tool.trivy.adapter.ts.md)
- [core/coordinators/quality.coordinator.ts](https://banes-lab.com/source/quality/core/coordinators/quality.coordinator.ts.md)
- [runtime/entrypoints/invocation.entrypoint.ts](https://banes-lab.com/source/quality/runtime/entrypoints/invocation.entrypoint.ts.md)

## Linked from

- [core/adapters](https://banes-lab.com/anatomy/quality/folder-quality-core-adapters.md)
- [core/coordinators](https://banes-lab.com/anatomy/quality/folder-quality-core-coordinators.md)
- [core/loaders](https://banes-lab.com/anatomy/quality/folder-quality-core-loaders.md)
- [core/matchers](https://banes-lab.com/anatomy/quality/folder-quality-core-matchers.md)
- [core/resolvers](https://banes-lab.com/anatomy/quality/folder-quality-core-resolvers.md)
- [core/selectors](https://banes-lab.com/anatomy/quality/folder-quality-core-selectors.md)
- [runtime/entrypoints](https://banes-lab.com/anatomy/quality/folder-quality-runtime-entrypoints.md)

## Source

```typescript
import {
    CURRENT_DIRECTORY,
    DEFAULT_PATHS,
    FALLBACK_PATHS,
    PROFILE_ID_TO_ECOSYSTEM,
} from "#configuration/constants/tool.constants";
import { existsSync, readdirSync } from "node:fs";
import type { DetectedEcosystem } from "#types/quality.types";
import { detectProfiles } from "#core/loaders/ecosystem.loader";
import { isExcludedPath } from "#core/matchers/exclusions.matcher";
import { loadGovlabConfig } from "#core/loaders/config.loader";
import { loadInstallRegistry } from "#core/loaders/dependency.loader";
import { masterExcludeMarkers } from "#core/selectors/exclusions.selector";
import path from "node:path";
import { safeReaddir } from "#core/loaders/source.loader";

const GLOB_STAR_DOT = "*.";
const BRACE_OPEN = ".{";
const BRACE_CLOSE = "}";
const NOT_FOUND = -1;

interface Scan {
    root: string;
    exts: Set<string>;
    exclude: readonly string[];
}

const registryEcosystems = function registryEcosystems(): Set<string> {
    return new Set(loadInstallRegistry().records.map((record) => record.ecosystem));
};

export const detectEcosystems = function detectEcosystems(root: string): DetectedEcosystem[] {
    const known = registryEcosystems();
    const found = new Map<string, DetectedEcosystem>();
    for (const profile of detectProfiles(readdirSync(root))) {
        const ecosystem = PROFILE_ID_TO_ECOSYSTEM[profile.id] ?? profile.id;
        if (known.has(ecosystem) && !found.has(ecosystem)) {
            found.set(ecosystem, { ecosystem, languageId: profile.id });
        }
    }
    return [...found.values()];
};

export const defaultPathsFor = function defaultPathsFor(ecosystem: string): string[] {
    return [...(DEFAULT_PATHS[ecosystem] ?? FALLBACK_PATHS)];
};

export const projectDirWithMarker = function projectDirWithMarker(
    root: string,
    paths: readonly string[],
    marker: string,
): string {
    const found = paths
        .map((target) => (path.isAbsolute(target) ? target : path.join(root, target)))
        .find((abs) => existsSync(path.join(abs, marker)));
    return found ?? root;
};

export const scopeTargets = function scopeTargets(root: string, paths: readonly string[]): string[] {
    return (paths.length > 0 ? paths : [CURRENT_DIRECTORY]).map((target) =>
        path.isAbsolute(target) ? target : path.join(root, target),
    );
};

const globExtensions = function globExtensions(glob: string): string[] {
    const star = glob.lastIndexOf(GLOB_STAR_DOT);
    if (star === NOT_FOUND) {
        return [];
    }
    const tail = glob.slice(star + 1);
    if (tail.startsWith(BRACE_OPEN) && tail.endsWith(BRACE_CLOSE)) {
        return tail
            .slice(BRACE_OPEN.length, -BRACE_CLOSE.length)
            .split(",")
            .map((ext) => `.${ext}`);
    }
    return [tail];
};

const posix = function posix(value: string): string {
    return value.split(path.sep).join("/");
};

const matchesExtension = function matchesExtension(name: string, exts: Set<string>): boolean {
    const dot = name.lastIndexOf(".");
    return dot !== NOT_FOUND && exts.has(name.slice(dot));
};

const walkDir = function walkDir(scan: Scan, dir: string): string[] {
    return safeReaddir(dir).flatMap((entry) => {
        const full = path.join(dir, entry.name);
        const rel = path.relative(scan.root, full);
        if (isExcludedPath(rel, scan.exclude)) {
            return [];
        }
        if (entry.isDirectory()) {
            return walkDir(scan, full);
        }
        return matchesExtension(entry.name, scan.exts) ? [posix(rel)] : [];
    });
};

export const resolveScopedFiles = function resolveScopedFiles(
    root: string,
    globs: string[],
    exclude: readonly string[],
): string[] {
    const exts = new Set(globs.flatMap(globExtensions));
    return exts.size === 0 ? globs : walkDir({ exclude, exts, root }, root);
};

export const scopedFiles = async function scopedFiles(root: string, globs: string[]): Promise<string[]> {
    return resolveScopedFiles(root, globs, masterExcludeMarkers(await loadGovlabConfig(root)));
};
```
