# codemods/selectors/heritage.selector.ts

> 63 lines of code and 13 definitions.

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

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

## Definitions

- `clausesOfToken` (lexical_declaration, line 16, exported)
- `baseChain` (lexical_declaration, line 29, exported)
- `implementsClauses` (lexical_declaration, line 50, exported)
- `memberNamesOf` (lexical_declaration, line 61, exported)
- `FLAG_PARITY` (lexical_declaration, line 3)
- `FLAG_SET` (lexical_declaration, line 4)
- `resolveAlias` (lexical_declaration, line 6)
- `visited` (lexical_declaration, line 34, exported)
- `current` (lexical_declaration, line 35, exported)
- `[baseExpr]` (lexical_declaration, line 37, exported)
- `baseSymbol` (lexical_declaration, line 38, exported)
- `baseDecl` (lexical_declaration, line 39, exported)
- `out` (lexical_declaration, line 62, exported)

## Used by

- [codemods/analyzers/binding.analyzer.ts](https://banes-lab.com/source/governance/codemods/analyzers/binding.analyzer.ts.md)
- [codemods/predicates/binding.predicate.ts](https://banes-lab.com/source/governance/codemods/predicates/binding.predicate.ts.md)

## Source

```typescript
import ts from "typescript";

const FLAG_PARITY = 2;
const FLAG_SET = 1;

const resolveAlias = function resolveAlias(
    checker: ts.TypeChecker,
    symbol: ts.Symbol | undefined,
): ts.Symbol | undefined {
    if (symbol && Math.floor(symbol.flags / ts.SymbolFlags.Alias) % FLAG_PARITY === FLAG_SET) {
        return checker.getAliasedSymbol(symbol);
    }
    return symbol;
};

export const clausesOfToken = function clausesOfToken(
    node: ts.ClassLikeDeclaration,
    token: ts.SyntaxKind,
): ts.ExpressionWithTypeArguments[] {
    const out: ts.ExpressionWithTypeArguments[] = [];
    for (const clause of node.heritageClauses ?? []) {
        if (clause.token === token) {
            out.push(...clause.types);
        }
    }
    return out;
};

export const baseChain = function baseChain(
    checker: ts.TypeChecker,
    node: ts.ClassLikeDeclaration,
): ts.ClassLikeDeclaration[] {
    const out: ts.ClassLikeDeclaration[] = [];
    const visited = new Set<ts.ClassLikeDeclaration>([node]);
    let current: ts.ClassLikeDeclaration | null = node;
    while (current) {
        const [baseExpr] = clausesOfToken(current, ts.SyntaxKind.ExtendsKeyword);
        const baseSymbol = baseExpr ? resolveAlias(checker, checker.getSymbolAtLocation(baseExpr.expression)) : null;
        const baseDecl =
            (baseSymbol?.getDeclarations() ?? []).find((declaration) => ts.isClassLike(declaration)) ?? null;
        current = baseDecl && ts.isClassLike(baseDecl) && !visited.has(baseDecl) ? baseDecl : null;
        if (current) {
            visited.add(current);
            out.push(current);
        }
    }
    return out;
};

export const implementsClauses = function implementsClauses(
    checker: ts.TypeChecker,
    node: ts.ClassLikeDeclaration,
): ts.ExpressionWithTypeArguments[] {
    const out: ts.ExpressionWithTypeArguments[] = [...clausesOfToken(node, ts.SyntaxKind.ImplementsKeyword)];
    for (const base of baseChain(checker, node)) {
        out.push(...clausesOfToken(base, ts.SyntaxKind.ImplementsKeyword));
    }
    return out;
};

export const memberNamesOf = function memberNamesOf(node: ts.ClassLikeDeclaration): string[] {
    const out: string[] = [];
    for (const classMember of node.members) {
        if (classMember.name) {
            out.push(classMember.name.getText());
        }
    }
    return out;
};
```
