From 979fc784029e0884ffadf868f00d92d228b5aae8 Mon Sep 17 00:00:00 2001 From: Gerardo Lecaros Date: Mon, 6 Nov 2023 08:59:48 -0800 Subject: [PATCH] Adding call signature customization support. (#27653) ### Packages impacted by this PR dev-tool ### Issues associated with this PR This change adds support for customizing interface call signatures. It also fixes an issue with the property removal functionality. ### Describe the problem that is addressed by this PR ### What are the possible designs available to address the problem? If there are more than one possible design, why was the one in this PR chosen? ### Are there test cases added in this PR? _(If not, why?)_ ### Provide a list of related PRs _(if any)_ ### Command used to generate this PR:**_(Applicable only to SDK release request PRs)_ ### Checklists - [ ] Added impacted package name to the issue description - [ ] Does this PR needs any fixes in the SDK Generator?** _(If so, create an Issue in the [Autorest/typescript](https://github.com/Azure/autorest.typescript) repository and link it here)_ - [ ] Added a changelog (if necessary) --- .../util/customization/helpers/annotations.ts | 7 +- .../src/util/customization/interfaces.ts | 76 ++++++++++++++++++- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/common/tools/dev-tool/src/util/customization/helpers/annotations.ts b/common/tools/dev-tool/src/util/customization/helpers/annotations.ts index b79309bc7bae..79de20242b4e 100644 --- a/common/tools/dev-tool/src/util/customization/helpers/annotations.ts +++ b/common/tools/dev-tool/src/util/customization/helpers/annotations.ts @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license -import { PropertySignature } from "ts-morph"; +import { CallSignatureDeclaration, PropertySignature } from "ts-morph"; import { Declaration } from "../common"; export type Annotation = "Remove"; export function getAnnotation( - declaration: Declaration | PropertySignature + declaration: Declaration | PropertySignature | CallSignatureDeclaration ): Annotation | undefined { // Check if the property has a `// @azsdk-remove` comment const leadingCommentRanges = declaration.getLeadingCommentRanges(); @@ -21,8 +21,7 @@ export function getAnnotation( if (annotation === "@azsdk-remove") { return "Remove"; } - - return undefined; } } + return undefined; } diff --git a/common/tools/dev-tool/src/util/customization/interfaces.ts b/common/tools/dev-tool/src/util/customization/interfaces.ts index 3d2f6d9778dc..4fadb2738710 100644 --- a/common/tools/dev-tool/src/util/customization/interfaces.ts +++ b/common/tools/dev-tool/src/util/customization/interfaces.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license -import { InterfaceDeclaration, SourceFile } from "ts-morph"; +import { CallSignatureDeclaration, InterfaceDeclaration, SourceFile, Type } from "ts-morph"; import { getAnnotation } from "./helpers/annotations"; export function augmentInterfaces( @@ -31,6 +31,12 @@ export function augmentInterface( // Merge the properties from the custom interface into the original interface mergeProperties(customInterface, originalInterface); + + // Remove any call signatures marked with // @azsdk-remove + removeCallSignatures(customInterface, originalInterface); + + // Merge the call signatures from the custom interface into the original interface + mergeCallSignatures(customInterface, originalInterface); } export function mergeProperties( @@ -39,6 +45,10 @@ export function mergeProperties( ) { const customProperties = customInterface.getProperties(); for (const customProperty of customProperties) { + if (getAnnotation(customProperty) === "Remove") { + /* If the property has a `// @azsdk-remove` comment, we don't need to re-add it */ + continue; + } const propertyName = customProperty.getName(); const originalProperty = originalInterface.getProperty(propertyName); @@ -68,3 +78,67 @@ export function removeProperties( } } } + +function findCallSignature( + interfaceDeclaration: InterfaceDeclaration, + callSignature: CallSignatureDeclaration +): CallSignatureDeclaration | undefined { + function typeEquals(a: Type, b: Type) { + // Need to handle cases where the type is imported + const aStr = a?.getText()?.replace(/import\(\".+\"\)\./, ""); + const bStr = b?.getText()?.replace(/import\(\".+\"\)\./, ""); + return aStr && bStr && aStr === bStr; + } + return interfaceDeclaration.getCallSignature((signature) => { + if (signature.getParameters().length !== callSignature.getParameters().length) { + return false; + } + signature.getReturnTypeNode; + if (!typeEquals(signature.getReturnType(), callSignature.getReturnType())) { + return false; + } + + for (let i = 0; i < signature.getParameters().length; i++) { + if ( + !typeEquals( + signature.getParameters()[i].getType(), + callSignature.getParameters()[i].getType() + ) + ) { + return false; + } + } + return true; + }); +} + +export function mergeCallSignatures( + customInterface: InterfaceDeclaration, + originalInterface: InterfaceDeclaration +) { + const customCallSignatures = customInterface.getCallSignatures(); + for (const customCallSignature of customCallSignatures) { + if (getAnnotation(customCallSignature) === "Remove") { + /* If the call signature has a `// @azsdk-remove` comment, we don't need to re-add it */ + continue; + } + const originalCallSignature = findCallSignature(originalInterface, customCallSignature); + if (originalCallSignature) { + originalCallSignature.remove(); + } + originalInterface.addCallSignature(customCallSignature.getStructure()); + } +} + +export function removeCallSignatures( + customInterface: InterfaceDeclaration, + originalInterface: InterfaceDeclaration +) { + const customCallSignatures = customInterface.getCallSignatures(); + for (const customCallSignature of customCallSignatures) { + // Check if the signature has a `// @azsdk-remove` comment + if (getAnnotation(customCallSignature) === "Remove") { + findCallSignature(originalInterface, customCallSignature)?.remove(); + } + } +}