# rules/eslint/no-runtime-absent-member.eslint.rule.ts

> 52 lines of code and 9 definitions.

Tree: GovLab Extension Host
Language: typescript
Canonical: https://banes-lab.com/anatomy/governance#file-governance-rules-eslint-no-runtime-absent-member-eslint-rule-ts
Source text: https://banes-lab.com/source/governance/rules/eslint/no-runtime-absent-member.eslint.rule.ts.txt

Listed in [rules/eslint](https://banes-lab.com/api/source/governance/rules/eslint.md), after [rules/eslint/no-redundant-type-shim.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/no-redundant-type-shim.eslint.rule.ts.md) and before [rules/eslint/no-secret-value.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/no-secret-value.eslint.rule.ts.md).

## Definitions

- `memberName` (lexical_declaration, line 19)
- `create` (method_definition, line 25, exported)
- `memberExpression` (method_definition, line 32, exported)
- `BOUND` (lexical_declaration, line 10)
- `runtimeOf` (lexical_declaration, line 15)
- `property` (lexical_declaration, line 20)
- `runtime` (lexical_declaration, line 26, exported)
- `absent` (lexical_declaration, line 27, exported)
- `member` (lexical_declaration, line 33, exported)

## Contained in

- [rules/eslint](https://banes-lab.com/anatomy/governance/folder-governance-rules-eslint.md)

## Uses

- [shared/factories/listener.factory.ts](https://banes-lab.com/source/governance/shared/factories/listener.factory.ts.md)
- [shared/selectors/syntax.selector.ts](https://banes-lab.com/source/governance/shared/selectors/syntax.selector.ts.md)

## Enforces

- [Environment Parity](https://banes-lab.com/records/architecture/environment-parity.md)
- [Portability](https://banes-lab.com/records/architecture/portability.md)

## Linked from

- [shared/factories](https://banes-lab.com/anatomy/governance/folder-governance-shared-factories.md)
- [shared/selectors](https://banes-lab.com/anatomy/governance/folder-governance-shared-selectors.md)

## Source

```typescript
import { ABSENT_MEMBERS, RUNTIME_BINDINGS } from "../../shared/manifests/target.manifest.ts";
import type { LocalRule, RuleContext, RuleListener } from "../../types/rule.types.ts";
import { booleanAt, literalString, locOf, nameOf, nodeAt } from "../../shared/selectors/syntax.selector.ts";
import type { AstNode } from "../../types/syntax.types.ts";
import { absolutePath } from "@ssot/paths";
import { defineCheck } from "@govlab/context/check";
import { listener } from "../../shared/factories/listener.factory.ts";
import { normalizePath } from "../../shared/resolvers/anchor.resolver.ts";

const BOUND = RUNTIME_BINDINGS.map((binding) => ({
    folder: `${normalizePath(absolutePath(binding.pathKey))}/`,
    runtime: binding.runtime,
}));

const runtimeOf = function runtimeOf(filename: string): string | null {
    return BOUND.find((binding) => filename.startsWith(binding.folder))?.runtime ?? null;
};

const memberName = function memberName(view: AstNode): string | null {
    const property = nodeAt(view, "property");
    return booleanAt(view, "computed") ? literalString(property) : nameOf(property);
};

export default {
    create(context: RuleContext): RuleListener {
        const runtime = runtimeOf(normalizePath(context.filename));
        const absent = runtime === null ? undefined : ABSENT_MEMBERS.get(runtime);
        if (runtime === null || absent === undefined) {
            return {};
        }
        return listener({
            memberExpression(view) {
                const member = memberName(view);
                if (member !== null && absent.has(member)) {
                    context.report({ data: { member, runtime }, loc: locOf(view), messageId: "absentMember" });
                }
            },
        });
    },
    meta: {
        docs: {
            checks: defineCheck({
                detects: [],
                enforces: ["architecture:environment-parity", "architecture:portability"],
            }),
            description:
                "A script that runs under a constrained runtime uses only what that runtime provides. The registry binds a folder, by its paths key, to the runtime its scripts run under, and lists the members that runtime lacks. A tool that runs the script under a fuller runtime, such as a test runner, does not see the missing member, so the call fails only in production. The rule refuses any member access, dotted or computed with a literal, to a listed member in a bound folder.",
        },
        messages: {
            absentMember:
                "This script runs under {{runtime}}, which does not provide {{member}}, so the call throws there although it passes under a fuller runtime. Replace it with an operation the runtime provides.",
        },
        schema: [],
        type: "problem",
    },
} satisfies LocalRule;
```
