codemods/selectors/field.selector.ts

codemods/selectors/field.selector.ts is a file in GovLab Extension Host. 48 lines of code and 14 definitions.

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);
};