diff --git a/packages/http-client-csharp/emitter/src/emitter.ts b/packages/http-client-csharp/emitter/src/emitter.ts index 5181521c8c..a60cae1774 100644 --- a/packages/http-client-csharp/emitter/src/emitter.ts +++ b/packages/http-client-csharp/emitter/src/emitter.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -import { createSdkContext, UsageFlags } from "@azure-tools/typespec-client-generator-core"; +import { createSdkContext, SdkClientType, SdkHttpOperation, SdkServiceMethod, UsageFlags } from "@azure-tools/typespec-client-generator-core"; import { EmitContext, getDirectoryPath, @@ -23,6 +23,9 @@ import { Logger } from "./lib/logger.js"; import { NetEmitterOptions, resolveOptions, resolveOutputFolder } from "./options.js"; import { defaultSDKContextOptions } from "./sdk-context-options.js"; import { Configuration } from "./type/configuration.js"; +import { CodeModel } from "./type/code-model.js"; +import { InputClient } from "./type/input-client.js"; +import { InputOperation } from "./type/input-operation.js"; /** * Look for the project root by looking up until a `package.json` is found. @@ -44,7 +47,75 @@ function findProjectRoot(path: string): string | undefined { } } -export async function $onEmit(context: EmitContext) { +/** Start: all these in azure emitter */ +interface AzureCodeModel extends CodeModel { + AzureStuff: string; +} + +interface AzureInputClient extends InputClient { + AzureStuff: string; +} + +interface AzureInputOperation extends InputOperation { + AzureStuff: string; +} + +interface ResoureceMetadata { + models?: { + operations: string[] + } +} + +type AzureModelType = { + client: AzureInputClient; + operation: AzureInputOperation; + resources: ResoureceMetadata; +} + +const azureHook: Hook = { + emitClient: (client: SdkClientType, unbrandingClient: InputClient) => { + // Get something from TCGC client raw. + const azureStuff = "hello azure"; + return { + ...unbrandingClient, + AzureStuff: azureStuff + }; + }, + emitOperation: (method: SdkServiceMethod, unbrandingOperation: InputOperation) => { + // Get something from TCGC operation raw. + const azureStuff = "hello azure"; + return { + ...unbrandingOperation, + AzureStuff: azureStuff + }; + }, + emitResources: () => { + // Get data from arm + return { "models": { "operations": []} }; + } +} + +export async function $onEmitInAzureEmitter(context: EmitContext) { + $onEmit({ + ...context, + "hook": azureHook + }); +} +/** End: all these in azure emitter */ + + +export type CodeModelType = Record<"client"| "operation" | "resources", any>; // I think "resources" should be renamed to something like "others", just telling unbranding emitter just append these data. + +export interface Hook { + emitClient?: (client: SdkClientType, unbrandingClient: InputClient) => T["client"]; + emitOperation?: (method: SdkServiceMethod, unbrandingOperation: InputOperation) => T["operation"]; + emitResources?: () => T["resources"]; +} + +export type ContextType = EmitContext & {"hook"?: Hook}; + +export async function $onEmit(context: ContextType) { + context.hook = azureHook as Hook; // Ignore this line. Test purpose const program: Program = context.program; const options = resolveOptions(context); const outputFolder = resolveOutputFolder(context); @@ -59,7 +130,7 @@ export async function $onEmit(context: EmitContext) { "@typespec/http-client-csharp", defaultSDKContextOptions, ); - const root = createModel(sdkContext); + const root = createModel(sdkContext, context.hook); // context.hook is already in sdkContext. We should change createSdkContext signature to somehow accept hook type if ( context.program.diagnostics.length > 0 && context.program.diagnostics.filter((digs) => digs.severity === "error").length > 0 diff --git a/packages/http-client-csharp/emitter/src/lib/client-model-builder.ts b/packages/http-client-csharp/emitter/src/lib/client-model-builder.ts index 880631124a..787826a144 100644 --- a/packages/http-client-csharp/emitter/src/lib/client-model-builder.ts +++ b/packages/http-client-csharp/emitter/src/lib/client-model-builder.ts @@ -25,8 +25,9 @@ import { Logger } from "./logger.js"; import { navigateModels } from "./model.js"; import { fromSdkServiceMethod, getParameterDefaultValue } from "./operation-converter.js"; import { processServiceAuthentication } from "./service-authentication.js"; +import { CodeModelType, Hook } from "../emitter.js"; -export function createModel(sdkContext: SdkContext): CodeModel { +export function createModel(sdkContext: SdkContext, hook?: Hook): CodeModel { const sdkPackage = sdkContext.sdkPackage; const sdkTypeMap: SdkTypeMap = { @@ -49,6 +50,7 @@ export function createModel(sdkContext: SdkContext): CodeMode sdkPackage.clients.filter((c) => c.initialization.access === "public"), inputClients, [], + hook ); const clientModel: CodeModel = { @@ -61,30 +63,31 @@ export function createModel(sdkContext: SdkContext): CodeMode }; return clientModel; - function fromSdkClients( + function fromSdkClients( clients: SdkClientType[], inputClients: InputClient[], parentClientNames: string[], + hook?: Hook ) { for (const client of clients) { - const inputClient = emitClient(client, parentClientNames); + const inputClient = emitClient(client, parentClientNames, hook); inputClients.push(inputClient); const subClients = client.methods .filter((m) => m.kind === "clientaccessor") .map((m) => m.response as SdkClientType); parentClientNames.push(inputClient.Name); - fromSdkClients(subClients, inputClients, parentClientNames); + fromSdkClients(subClients, inputClients, parentClientNames, hook); parentClientNames.pop(); } } - function emitClient(client: SdkClientType, parentNames: string[]): InputClient { + function emitClient(client: SdkClientType, parentNames: string[], hook?: Hook): InputClient { const endpointParameter = client.initialization.properties.find( (p) => p.kind === "endpoint", ) as SdkEndpointParameter; const uri = getMethodUri(endpointParameter); const clientParameters = fromSdkEndpointParameter(endpointParameter); - return { + const unbrandingClient = { Name: getClientName(client, parentNames), Description: client.description, Operations: client.methods @@ -97,6 +100,7 @@ export function createModel(sdkContext: SdkContext): CodeMode rootApiVersions, sdkContext, sdkTypeMap, + hook ), ), Protocol: {}, @@ -104,6 +108,7 @@ export function createModel(sdkContext: SdkContext): CodeMode Parameters: clientParameters, Decorators: client.decorators, }; + return hook?.emitClient ? hook.emitClient(client, unbrandingClient) : unbrandingClient; } function getClientName( diff --git a/packages/http-client-csharp/emitter/src/lib/operation-converter.ts b/packages/http-client-csharp/emitter/src/lib/operation-converter.ts index 92bc515e78..a56a297d0e 100644 --- a/packages/http-client-csharp/emitter/src/lib/operation-converter.ts +++ b/packages/http-client-csharp/emitter/src/lib/operation-converter.ts @@ -41,14 +41,16 @@ import { fromSdkHttpExamples } from "./example-converter.js"; import { Logger } from "./logger.js"; import { getInputType } from "./model.js"; import { capitalize, isSdkPathParameter } from "./utils.js"; +import { CodeModelType, Hook } from "../emitter.js"; -export function fromSdkServiceMethod( +export function fromSdkServiceMethod( method: SdkServiceMethod, uri: string, clientParameters: InputParameter[], rootApiVersions: string[], sdkContext: SdkContext, typeMap: SdkTypeMap, + hook?: Hook ): InputOperation { let generateConvenience = shouldGenerateConvenient(sdkContext, method.operation.__raw.operation); if (method.operation.verb === "patch" && generateConvenience) { @@ -69,7 +71,7 @@ export function fromSdkServiceMethod( sdkContext, typeMap, ); - return { + const unbrandingOperation = { Name: method.name, ResourceName: getResourceOperation(sdkContext.program, method.operation.__raw.operation)?.resourceType @@ -106,6 +108,7 @@ export function fromSdkServiceMethod( ) : undefined, }; + return hook?.emitOperation ? hook.emitOperation(method, unbrandingOperation) : unbrandingOperation; } export function getParameterDefaultValue( diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/tspCodeModel.json b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/tspCodeModel.json index c8f4572fc3..8b43fa1453 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/tspCodeModel.json +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/tspCodeModel.json @@ -1997,7 +1997,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.sayHi", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "205", @@ -2151,7 +2152,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.helloAgain", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "218", @@ -2306,7 +2308,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": false, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.noContentType", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "231", @@ -2371,7 +2374,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.helloDemo2", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "236", @@ -2484,7 +2488,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.createLiteral", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "245", @@ -2630,7 +2635,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.helloLiteral", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "259", @@ -2724,7 +2730,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.topAction", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "267", @@ -2789,7 +2796,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": false, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.topAction2", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "272", @@ -2902,7 +2910,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": false, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.patchAction", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "281", @@ -3015,7 +3024,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.anonymousBody", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "290", @@ -3128,7 +3138,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.friendlyModel", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "299", @@ -3188,7 +3199,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.addTimeHeader", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "304", @@ -3301,7 +3313,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.projectedNameModel", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "313", @@ -3366,7 +3379,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.returnsAnonymousModel", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "318", @@ -3442,7 +3456,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.getUnknownValue", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "324", @@ -3555,7 +3570,8 @@ "GenerateProtocolMethod": false, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.internalProtocol", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "333", @@ -3587,7 +3603,8 @@ "GenerateProtocolMethod": false, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.stillConvenient", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "335", @@ -3640,7 +3657,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.headAsBoolean", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" }, { "$id": "339", @@ -3724,7 +3742,8 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "UnbrandedTypeSpec.WithApiVersion", - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" } ], "Protocol": { @@ -3735,7 +3754,8 @@ "$ref": "193" } ], - "Decorators": [] + "Decorators": [], + "AzureStuff": "hello azure" } ], "Auth": {