99} from "@typespec/http-client-csharp" ;
1010import {
1111 calculateResourceTypeFromPath ,
12+ convertMethodMetadataToArguments ,
1213 convertResourceMetadataToArguments ,
14+ NonResourceMethod ,
1315 ResourceMetadata ,
1416 ResourceOperationKind ,
1517 ResourceScope
@@ -32,6 +34,7 @@ import {
3234 armResourceListName ,
3335 armResourceReadName ,
3436 armResourceUpdateName ,
37+ nonResourceMethodMetadata ,
3538 parentResourceName ,
3639 resourceGroupResource ,
3740 resourceMetadata ,
@@ -72,6 +75,7 @@ export async function updateClients(
7275 } as ResourceMetadata
7376 ] )
7477 ) ;
78+ const nonResourceMethods : Map < string , NonResourceMethod > = new Map ( ) ;
7579
7680 // first we flatten all possible clients in the code model
7781 const clients = getAllClients ( codeModel ) ;
@@ -100,25 +104,44 @@ export async function updateClients(
100104 if ( entry && ! entry . resourceIdPattern && isCRUDKind ( kind ) ) {
101105 entry . resourceIdPattern = method . operation . path ;
102106 }
107+ } else {
108+ // we add a methodMetadata decorator to this method
109+ nonResourceMethods . set ( method . crossLanguageDefinitionId , {
110+ methodId : method . crossLanguageDefinitionId ,
111+ operationPath : method . operation . path ,
112+ operationScope : getOperationScope ( method . operation . path )
113+ } ) ;
103114 }
104115 }
105116 }
106117
107118 // after the resourceIdPattern has been populated, we can set the parentResourceId
108119 for ( const [ modelId , metadata ] of resourceModelToMetadataMap ) {
109- const parentResourceModelId = getParentResourceModelId ( sdkContext , models . get ( modelId ) ) ;
120+ const parentResourceModelId = getParentResourceModelId (
121+ sdkContext ,
122+ models . get ( modelId )
123+ ) ;
110124 if ( parentResourceModelId ) {
111- metadata . parentResourceId = resourceModelToMetadataMap . get ( parentResourceModelId ) ?. resourceIdPattern ;
125+ metadata . parentResourceId = resourceModelToMetadataMap . get (
126+ parentResourceModelId
127+ ) ?. resourceIdPattern ;
112128 }
113129 }
114130
115131 // the last step, add the decorator to the resource model
116132 for ( const model of resourceModels ) {
117- const metadata = resourceModelToMetadataMap . get ( model . crossLanguageDefinitionId ) ;
133+ const metadata = resourceModelToMetadataMap . get (
134+ model . crossLanguageDefinitionId
135+ ) ;
118136 if ( metadata ) {
119137 addResourceMetadata ( sdkContext , model , metadata ) ;
120138 }
121139 }
140+ // and add the methodMetadata decorator to the non-resource methods
141+ addNonResourceMethodDecorators (
142+ codeModel ,
143+ Array . from ( nonResourceMethods . values ( ) )
144+ ) ;
122145}
123146
124147function isCRUDKind ( kind : ResourceOperationKind ) : boolean {
@@ -211,35 +234,26 @@ export function getAllSdkClients(
211234) : SdkClientType < SdkServiceOperation > [ ] {
212235 const clients : SdkClientType < SdkServiceOperation > [ ] = [ ] ;
213236 for ( const client of sdkContext . sdkPackage . clients ) {
214- traverseClient ( client ) ;
237+ traverseClient ( client , clients ) ;
215238 }
216239
217240 return clients ;
218-
219- function traverseClient ( client : SdkClientType < SdkServiceOperation > ) {
220- clients . push ( client ) ;
221- if ( client . children ) {
222- for ( const child of client . children ) {
223- traverseClient ( child ) ;
224- }
225- }
226- }
227241}
228242
229243export function getAllClients ( codeModel : CodeModel ) : InputClient [ ] {
230244 const clients : InputClient [ ] = [ ] ;
231245 for ( const client of codeModel . clients ) {
232- traverseClient ( client ) ;
246+ traverseClient ( client , clients ) ;
233247 }
234248
235249 return clients ;
250+ }
236251
237- function traverseClient ( client : InputClient ) {
238- clients . push ( client ) ;
239- if ( client . children ) {
240- for ( const child of client . children ) {
241- traverseClient ( child ) ;
242- }
252+ function traverseClient < T extends { children ?: T [ ] } > ( client : T , clients : T [ ] ) {
253+ clients . push ( client ) ;
254+ if ( client . children ) {
255+ for ( const child of client . children ) {
256+ traverseClient ( child , clients ) ;
243257 }
244258 }
245259}
@@ -277,6 +291,31 @@ function getResourceScope(model: InputModelType): ResourceScope {
277291 return ResourceScope . ResourceGroup ; // all the templates work as if there is a resource group decorator when there is no such decorator
278292}
279293
294+ // TODO -- this logic needs to be refined in the near future.
295+ function getOperationScope ( path : string ) : ResourceScope {
296+ if (
297+ path . startsWith (
298+ "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/"
299+ )
300+ ) {
301+ return ResourceScope . ResourceGroup ;
302+ } else if ( path . startsWith ( "/subscriptions/{subscriptionId}/" ) ) {
303+ return ResourceScope . Subscription ;
304+ }
305+ return ResourceScope . Tenant ; // all the templates work as if there is a tenant decorator when there is no such decorator
306+ }
307+
308+ function addNonResourceMethodDecorators (
309+ codeModel : CodeModel ,
310+ metadata : NonResourceMethod [ ]
311+ ) {
312+ codeModel . clients [ 0 ] . decorators ??= [ ] ;
313+ codeModel . clients [ 0 ] . decorators . push ( {
314+ name : nonResourceMethodMetadata ,
315+ arguments : convertMethodMetadataToArguments ( metadata )
316+ } ) ;
317+ }
318+
280319function addResourceMetadata (
281320 sdkContext : CSharpEmitterContext ,
282321 model : InputModelType ,
0 commit comments