refactor: 処理共通化

This commit is contained in:
kakkokari-gtyih 2025-05-25 23:50:05 +09:00
parent efb50f03d9
commit d8cd69e055
1 changed files with 49 additions and 68 deletions

View File

@ -13,88 +13,69 @@ import * as ts from 'typescript';
export function removeNeverPropertiesFromAST(astNodes: readonly ts.Node[]): ts.Node[] { export function removeNeverPropertiesFromAST(astNodes: readonly ts.Node[]): ts.Node[] {
const factory = ts.factory; const factory = ts.factory;
const typeNodeRecursiveVisitor = (node: ts.Node): ts.Node | undefined => { /**
if (ts.isTypeLiteralNode(node)) { * TypeLiteralNodeやInterfaceDeclarationのmembersからneverプロパティを除去し
const newMembers: ts.TypeElement[] = []; */
let hasTypeLiteralChanged = false; function removeNeverPropertiesFromMembers(
members: readonly ts.TypeElement[],
visitType: (node: ts.Node) => ts.Node | undefined,
): { newMembers: ts.TypeElement[]; hasChanged: boolean } {
const newMembers: ts.TypeElement[] = [];
let hasChanged = false;
for (const member of node.members) { for (const member of members) {
if (ts.isPropertySignature(member)) { if (ts.isPropertySignature(member)) {
if (member.type && member.type.kind === ts.SyntaxKind.NeverKeyword) { if (member.type && member.type.kind === ts.SyntaxKind.NeverKeyword) {
hasTypeLiteralChanged = true; hasChanged = true;
continue;
}
let updatedPropertySignature = member;
if (member.type) {
const visitedMemberType = ts.visitNode(member.type, visitType);
if (visitedMemberType && visitedMemberType !== member.type) {
updatedPropertySignature = factory.updatePropertySignature(
member,
member.modifiers,
member.name,
member.questionToken,
visitedMemberType as ts.TypeNode,
);
hasChanged = true;
} else if (visitedMemberType === undefined) {
// 子の型が消された場合、このプロパティも消す
hasChanged = true;
continue; continue;
} }
let updatedPropertySignature = member;
if (member.type) {
const visitedMemberType = ts.visitNode(member.type, typeNodeRecursiveVisitor);
if (visitedMemberType && visitedMemberType !== member.type) {
updatedPropertySignature = factory.updatePropertySignature(
member,
member.modifiers,
member.name,
member.questionToken,
visitedMemberType as ts.TypeNode
);
hasTypeLiteralChanged = true;
} else if (visitedMemberType === undefined) {
// 子の型が消された場合、このプロパティも消す
hasTypeLiteralChanged = true;
continue;
}
}
newMembers.push(updatedPropertySignature);
} else {
newMembers.push(member);
} }
newMembers.push(updatedPropertySignature);
} else {
newMembers.push(member);
} }
}
return { newMembers, hasChanged };
}
function typeNodeRecursiveVisitor(node: ts.Node): ts.Node | undefined {
if (ts.isTypeLiteralNode(node)) {
const { newMembers, hasChanged } = removeNeverPropertiesFromMembers(node.members, typeNodeRecursiveVisitor);
if (newMembers.length === 0) { if (newMembers.length === 0) {
// すべてのプロパティがneverで消された場合、このTypeLiteralNode自体も消す // すべてのプロパティがneverで消された場合、このTypeLiteralNode自体も消す
return undefined; return undefined;
} }
if (hasTypeLiteralChanged) { if (hasChanged) {
return factory.updateTypeLiteralNode(node, factory.createNodeArray(newMembers)); return factory.updateTypeLiteralNode(node, factory.createNodeArray(newMembers));
} }
return node; return node;
} }
return ts.visitEachChild(node, typeNodeRecursiveVisitor, undefined); return ts.visitEachChild(node, typeNodeRecursiveVisitor, undefined);
}; }
const interfaceRecursiveVisitor = (node: ts.Node): ts.Node | undefined => { function interfaceRecursiveVisitor(node: ts.Node): ts.Node | undefined {
if (ts.isInterfaceDeclaration(node)) { if (ts.isInterfaceDeclaration(node)) {
const newMembers: ts.TypeElement[] = []; const { newMembers, hasChanged } = removeNeverPropertiesFromMembers(node.members, typeNodeRecursiveVisitor);
let hasChanged = false;
for (const member of node.members) {
if (ts.isPropertySignature(member)) {
if (member.type && member.type.kind === ts.SyntaxKind.NeverKeyword) {
hasChanged = true;
continue;
}
let updatedPropertySignature = member;
if (member.type) {
const visitedMemberType = ts.visitNode(member.type, typeNodeRecursiveVisitor);
if (visitedMemberType && visitedMemberType !== member.type) {
updatedPropertySignature = factory.updatePropertySignature(
member,
member.modifiers,
member.name,
member.questionToken,
visitedMemberType as ts.TypeNode
);
hasChanged = true;
} else if (visitedMemberType === undefined) {
hasChanged = true;
continue;
}
}
newMembers.push(updatedPropertySignature);
} else {
newMembers.push(member);
}
}
if (newMembers.length === 0) { if (newMembers.length === 0) {
return undefined; return undefined;
@ -107,15 +88,15 @@ export function removeNeverPropertiesFromAST(astNodes: readonly ts.Node[]): ts.N
node.name, node.name,
node.typeParameters, node.typeParameters,
node.heritageClauses, node.heritageClauses,
newMembers newMembers,
); );
} }
return node; return node;
} }
return ts.visitEachChild(node, interfaceRecursiveVisitor, undefined); return ts.visitEachChild(node, interfaceRecursiveVisitor, undefined);
}; }
const topLevelVisitor = (node: ts.Node): ts.Node | undefined => { function topLevelVisitor(node: ts.Node): ts.Node | undefined {
if (ts.isTypeAliasDeclaration(node) && node.name.escapedText === 'paths') { if (ts.isTypeAliasDeclaration(node) && node.name.escapedText === 'paths') {
const newType = ts.visitNode(node.type, typeNodeRecursiveVisitor); const newType = ts.visitNode(node.type, typeNodeRecursiveVisitor);
if (newType && newType !== node.type) { if (newType && newType !== node.type) {
@ -124,7 +105,7 @@ export function removeNeverPropertiesFromAST(astNodes: readonly ts.Node[]): ts.N
node.modifiers, node.modifiers,
node.name, node.name,
node.typeParameters, node.typeParameters,
newType as ts.TypeNode newType as ts.TypeNode,
); );
} else if (newType === undefined) { } else if (newType === undefined) {
return undefined; return undefined;
@ -135,7 +116,7 @@ export function removeNeverPropertiesFromAST(astNodes: readonly ts.Node[]): ts.N
return result; return result;
} }
return ts.visitEachChild(node, topLevelVisitor, undefined); return ts.visitEachChild(node, topLevelVisitor, undefined);
}; }
const transformedNodes: ts.Node[] = []; const transformedNodes: ts.Node[] = [];
for (const astNode of astNodes) { for (const astNode of astNodes) {