# codemods/selectors/field.selector.ts

> 48 lines of code and 14 definitions.

Tree: Governance tree
Language: typescript
Layer: application
Canonical: https://banes-lab.com/anatomy/governance#file-governance-codemods-selectors-field-selector-ts
Source text: https://banes-lab.com/source/governance/codemods/selectors/field.selector.ts.txt

Listed in [codemods/selectors](https://banes-lab.com/api/source/governance/codemods/selectors.md), after [codemods/selectors/edit.selector.ts](https://banes-lab.com/source/governance/codemods/selectors/edit.selector.ts.md) and before [codemods/selectors/heritage.selector.ts](https://banes-lab.com/source/governance/codemods/selectors/heritage.selector.ts.md).

## Definitions

- `innerTypes` (lexical_declaration, line 26, exported)
- `within` (lexical_declaration, line 4, exported)
- `posix` (lexical_declaration, line 5, exported)
- `keyOf` (lexical_declaration, line 9, exported)
- `owner` (lexical_declaration, line 13, exported)
- `{ name: property }` (lexical_declaration, line 14, exported)
- `name` (lexical_declaration, line 18, exported)
- `element` (lexical_declaration, line 30, exported)
- `callbackOf` (lexical_declaration, line 34)
- `node` (lexical_declaration, line 35)
- `holder` (lexical_declaration, line 39, exported)
- `declaredTarget` (lexical_declaration, line 43, exported)
- `callback` (lexical_declaration, line 47, exported)
- `call` (lexical_declaration, line 48, exported)

## Used by

- [codemods/analyzers/field.analyzer.ts](https://banes-lab.com/source/governance/codemods/analyzers/field.analyzer.ts.md)
- [codemods/analyzers/field.reference.analyzer.ts](https://banes-lab.com/source/governance/codemods/analyzers/field.reference.analyzer.ts.md)
- [codemods/analyzers/field.vocabulary.analyzer.ts](https://banes-lab.com/source/governance/codemods/analyzers/field.vocabulary.analyzer.ts.md)

## Source

```typescript
import { toPosix } from "./program.selector.ts";
import ts from "typescript";

export const within = function within(file: string, roots: readonly string[]): boolean {
    const posix = toPosix(file);
    return roots.some((root) => posix.startsWith(toPosix(root)));
};

export const keyOf = function keyOf(declaration: ts.Node): string | null {
    if (!ts.isPropertySignature(declaration)) {
        return null;
    }
    const owner = declaration.parent;
    const { name: property } = declaration;
    if (!("text" in property)) {
        return null;
    }
    const name = property.text;
    if (ts.isInterfaceDeclaration(owner)) {
        return `${owner.name.text}.${name}`;
    }
    const holder = ts.isTypeLiteralNode(owner) ? keyOf(owner.parent) : null;
    return holder === null ? null : `${holder}.${name}`;
};

export const innerTypes = function innerTypes(checker: ts.TypeChecker, type: ts.Type): readonly ts.Type[] {
    if (type.isUnion() || type.isIntersection()) {
        return type.types.flatMap((part) => innerTypes(checker, part));
    }
    const element = checker.isArrayType(type) ? type.getNumberIndexType() : undefined;
    return element === undefined ? [type] : innerTypes(checker, element);
};

const callbackOf = function callbackOf(literal: ts.Node): ts.ArrowFunction | null {
    let node = literal;
    while (ts.isParenthesizedExpression(node.parent)) {
        node = node.parent;
    }
    const holder = node.parent;
    return ts.isArrowFunction(holder) && holder.body === node ? holder : null;
};

export const declaredTarget = function declaredTarget(
    checker: ts.TypeChecker,
    literal: ts.ObjectLiteralExpression,
): ts.Type | undefined {
    const callback = callbackOf(literal);
    const call = callback?.parent;
    if (callback !== null && call !== undefined && ts.isCallExpression(call) && call.arguments.includes(callback)) {
        return checker.getContextualType(call) ?? checker.getContextualType(literal);
    }
    return checker.getContextualType(literal);
};
```
