# core/selectors/construct.selector.ts

> 47 lines of code and 10 definitions.

Tree: GovLab Quality
Language: typescript
Layer: application
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-selectors-construct-selector-ts
Source text: https://banes-lab.com/source/quality/core/selectors/construct.selector.ts.txt

Listed in [core/selectors](https://banes-lab.com/api/source/quality/core/selectors.md), after [core/selectors/config.selector.ts](https://banes-lab.com/source/quality/core/selectors/config.selector.ts.md) and before [core/selectors/context.fragment.selector.ts](https://banes-lab.com/source/quality/core/selectors/context.fragment.selector.ts.md).

## Definitions

- `constructsOf` (lexical_declaration, line 31, exported)
- `asConstructNode` (lexical_declaration, line 8, exported)
- `variableConstructs` (lexical_declaration, line 20)
- `collectLocalConstructs` (lexical_declaration, line 44, exported)
- `isConstructNode` (lexical_declaration, line 4)
- `namedConstruct` (lexical_declaration, line 12)
- `out` (lexical_declaration, line 21)
- `{ id }` (lexical_declaration, line 23)
- `names` (lexical_declaration, line 45, exported)
- `declaration` (lexical_declaration, line 47, exported)

## Contained in

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

## Uses

- [core/predicates/construct.predicate.ts](https://banes-lab.com/source/quality/core/predicates/construct.predicate.ts.md)

## Used by

- [core/quality/eslint/require-test-coverage.eslint.rule.ts](https://banes-lab.com/source/quality/core/quality/eslint/require-test-coverage.eslint.rule.ts.md)

## Linked from

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

## Source

```typescript
import type { Construct, ConstructNode } from "#types/construct.types";
import { isConstructInit } from "#core/predicates/construct.predicate";

const isConstructNode = function isConstructNode(value: unknown): value is ConstructNode {
    return typeof value === "object" && value !== null && "type" in value;
};

export const asConstructNode = function asConstructNode(value: unknown): ConstructNode | null {
    return isConstructNode(value) ? value : null;
};

const namedConstruct = function namedConstruct(node: ConstructNode): Construct[] {
    const { id } = node;
    if (id && typeof id.name === "string") {
        return [{ name: id.name, node: id }];
    }
    return [];
};

const variableConstructs = function variableConstructs(node: ConstructNode): Construct[] {
    const out: Construct[] = [];
    for (const decl of node.declarations ?? []) {
        const { id } = decl;
        if (id?.type === "Identifier" && typeof id.name === "string" && isConstructInit(decl.init)) {
            out.push({ name: id.name, node: id });
        }
    }
    return out;
};

export const constructsOf = function constructsOf(declaration: ConstructNode | null | undefined): Construct[] {
    if (!declaration) {
        return [];
    }
    if (declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") {
        return namedConstruct(declaration);
    }
    if (declaration.type === "VariableDeclaration") {
        return variableConstructs(declaration);
    }
    return [];
};

export const collectLocalConstructs = function collectLocalConstructs(body: ConstructNode[]): Set<string> {
    const names = new Set<string>();
    for (const statement of body) {
        const declaration = statement.type === "ExportNamedDeclaration" ? statement.declaration : statement;
        for (const construct of constructsOf(declaration)) {
            names.add(construct.name);
        }
    }
    return names;
};
```
