Simplify convertToMappedObjectType (#24360)

This commit is contained in:
Andy 2018-05-23 16:01:52 -07:00 committed by GitHub
parent 10ac8b47e5
commit b61d4858d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -6,89 +6,51 @@ namespace ts.codefix {
type FixableDeclaration = InterfaceDeclaration | TypeAliasDeclaration;
interface Info {
indexSignature: IndexSignatureDeclaration;
container: FixableDeclaration;
otherMembers: ReadonlyArray<TypeElement>;
parameterName: Identifier;
parameterType: TypeNode;
}
registerCodeFix({
errorCodes,
getCodeActions: context => {
const { sourceFile, span } = context;
const info = getFixableSignatureAtPosition(sourceFile, span.start);
if (!info) return;
const { indexSignature, container, otherMembers, parameterName, parameterType } = info;
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, indexSignature, container, otherMembers, parameterName, parameterType));
return [createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_mapped_object_type, idText(container.name)], fixId, [Diagnostics.Convert_0_to_mapped_object_type, idText(container.name)])];
const info = getInfo(sourceFile, span.start);
if (!info) return undefined;
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info));
const name = idText(info.container.name);
return [createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_mapped_object_type, name], fixId, [Diagnostics.Convert_0_to_mapped_object_type, name])];
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const info = getFixableSignatureAtPosition(diag.file, diag.start);
if (!info) return;
const { indexSignature, container, otherMembers, parameterName, parameterType } = info;
doChange(changes, context.sourceFile, indexSignature, container, otherMembers, parameterName, parameterType);
const info = getInfo(diag.file, diag.start);
if (info) doChange(changes, diag.file, info);
})
});
function isFixableParameterName(node: Node): boolean {
return node && node.parent && node.parent.parent && node.parent.parent.parent && !isClassDeclaration(node.parent.parent.parent);
}
function getFixableSignatureAtPosition(sourceFile: SourceFile, pos: number): Info | undefined {
interface Info { readonly indexSignature: IndexSignatureDeclaration; readonly container: FixableDeclaration; }
function getInfo(sourceFile: SourceFile, pos: number): Info | undefined {
const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false);
if (!isFixableParameterName(token)) return undefined;
const indexSignature = cast(token.parent.parent, isIndexSignatureDeclaration);
if (isClassDeclaration(indexSignature.parent)) return undefined;
const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : cast(indexSignature.parent.parent, isTypeAliasDeclaration);
return { indexSignature, container };
}
const indexSignature = <IndexSignatureDeclaration>token.parent.parent;
const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : <TypeAliasDeclaration>indexSignature.parent.parent;
function createTypeAliasFromInterface(declaration: FixableDeclaration, type: TypeNode): TypeAliasDeclaration {
return createTypeAliasDeclaration(declaration.decorators, declaration.modifiers, declaration.name, declaration.typeParameters, type);
}
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { indexSignature, container }: Info): void {
const members = isInterfaceDeclaration(container) ? container.members : (<TypeLiteralNode>container.type).members;
const otherMembers = filter(members, member => !isIndexSignatureDeclaration(member));
const otherMembers = members.filter(member => !isIndexSignatureDeclaration(member));
const parameter = first(indexSignature.parameters);
return {
indexSignature,
container,
otherMembers,
parameterName: <Identifier>parameter.name,
parameterType: parameter.type!
};
}
function getInterfaceHeritageClauses(declaration: FixableDeclaration): NodeArray<ExpressionWithTypeArguments> | undefined {
if (!isInterfaceDeclaration(declaration)) return undefined;
const heritageClause = getHeritageClause(declaration.heritageClauses, SyntaxKind.ExtendsKeyword);
return heritageClause && heritageClause.types;
}
function createTypeAliasFromInterface(indexSignature: IndexSignatureDeclaration, declaration: FixableDeclaration, otherMembers: ReadonlyArray<TypeElement>, parameterName: Identifier, parameterType: TypeNode) {
const heritageClauses = getInterfaceHeritageClauses(declaration);
const mappedTypeParameter = createTypeParameterDeclaration(parameterName, parameterType);
const mappedTypeParameter = createTypeParameterDeclaration(cast(parameter.name, isIdentifier), parameter.type);
const mappedIntersectionType = createMappedTypeNode(
hasReadonlyModifier(indexSignature) ? createModifier(SyntaxKind.ReadonlyKeyword) : undefined,
mappedTypeParameter,
indexSignature.questionToken,
indexSignature.type);
return createTypeAliasDeclaration(
declaration.decorators,
declaration.modifiers,
declaration.name,
declaration.typeParameters,
createIntersectionTypeNode(
concatenate(
heritageClauses,
append<TypeNode>([mappedIntersectionType], otherMembers.length ? createTypeLiteralNode(otherMembers) : undefined)
)
)
);
}
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, indexSignature: IndexSignatureDeclaration, declaration: FixableDeclaration, otherMembers: ReadonlyArray<TypeElement>, parameterName: Identifier, parameterType: TypeNode) {
changes.replaceNode(sourceFile, declaration, createTypeAliasFromInterface(indexSignature, declaration, otherMembers, parameterName, parameterType));
const intersectionType = createIntersectionTypeNode([
...getAllSuperTypeNodes(container),
mappedIntersectionType,
...(otherMembers.length ? [createTypeLiteralNode(otherMembers)] : emptyArray),
]);
changes.replaceNode(sourceFile, container, createTypeAliasFromInterface(container, intersectionType));
}
}