core/selectors/code.typescript.selector.ts

core/selectors/code.typescript.selector.ts is a file in GovLab Docs. 70 lines of code and 17 definitions.

import { hasSymbolFlag } from "#core/predicates/program.predicate";
import { isFunctionLike } from "#core/predicates/code.typescript.predicate";
import ts from "typescript";

const MIN_UNION_MEMBERS = 3;
const ANONYMOUS = "anonymous";
const CONSTRUCTOR = "constructor";
const PRIVATE_MARK = "#";

export const communicationObjName = function communicationObjName(objExpr: ts.Expression): string | null {
    if (ts.isIdentifier(objExpr)) {
        return objExpr.text;
    }
    if (ts.isPropertyAccessExpression(objExpr) && objExpr.expression.kind === ts.SyntaxKind.ThisKeyword) {
        const { text } = objExpr.name;
        return text.startsWith(PRIVATE_MARK) ? text.slice(1) : text;
    }
    return null;
};

export const unionStringLiterals = function unionStringLiterals(typeNode: ts.TypeNode): string[] | null {
    if (!ts.isUnionTypeNode(typeNode)) {
        return null;
    }
    const out: string[] = [];
    for (const member of typeNode.types) {
        if (!ts.isLiteralTypeNode(member) || !ts.isStringLiteral(member.literal)) {
            return null;
        }
        out.push(member.literal.text);
    }
    return out.length >= MIN_UNION_MEMBERS ? out : null;
};

const initializerFunction = function initializerFunction(decl: ts.Node): ts.FunctionLikeDeclaration | null {
    if (!ts.isVariableDeclaration(decl) || !decl.initializer) {
        return null;
    }
    const init = decl.initializer;
    return ts.isArrowFunction(init) || ts.isFunctionExpression(init) ? init : null;
};

export const functionOf = function functionOf(decl: ts.Node | null | undefined): ts.FunctionLikeDeclaration | null {
    if (!decl) {
        return null;
    }
    return isFunctionLike(decl) ? decl : initializerFunction(decl);
};

export const declName = function declName(decl: ts.Declaration): string {
    const name = ts.getNameOfDeclaration(decl);
    if (name && ts.isIdentifier(name)) {
        return name.text;
    }
    const { parent } = decl;
    if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
        return parent.name.text;
    }
    if (ts.isVariableDeclaration(decl) && ts.isIdentifier(decl.name)) {
        return decl.name.text;
    }
    return ANONYMOUS;
};

export const firstDeclaration = function firstDeclaration(
    symbol: ts.Symbol,
    checker: ts.TypeChecker,
): ts.Declaration | null {
    const target = hasSymbolFlag(symbol.flags, ts.SymbolFlags.Alias) ? checker.getAliasedSymbol(symbol) : symbol;
    return target.declarations?.[0] ?? null;
};

export const memberName = function memberName(member: ts.ClassElement): string | null {
    if (ts.isConstructorDeclaration(member)) {
        return CONSTRUCTOR;
    }
    return member.name && ts.isIdentifier(member.name) ? member.name.text : null;
};