codemods/selectors/heritage.selector.ts
codemods/selectors/heritage.selector.ts is a file in GovLab Extension Host. 63 lines of code and 13 definitions.
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;
};