@azure-tools/typespec-go 0.8.1 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +7 -7
  2. package/dist/codegen.go/src/clientFactory.d.ts.map +1 -1
  3. package/dist/codegen.go/src/clientFactory.js +4 -0
  4. package/dist/codegen.go/src/clientFactory.js.map +1 -1
  5. package/dist/codegen.go/src/cloudConfig.d.ts +10 -0
  6. package/dist/codegen.go/src/cloudConfig.d.ts.map +1 -0
  7. package/dist/codegen.go/src/cloudConfig.js +65 -0
  8. package/dist/codegen.go/src/cloudConfig.js.map +1 -0
  9. package/dist/codegen.go/src/example.d.ts.map +1 -1
  10. package/dist/codegen.go/src/example.js +98 -109
  11. package/dist/codegen.go/src/example.js.map +1 -1
  12. package/dist/codegen.go/src/fake/factory.d.ts.map +1 -1
  13. package/dist/codegen.go/src/fake/factory.js +11 -2
  14. package/dist/codegen.go/src/fake/factory.js.map +1 -1
  15. package/dist/codegen.go/src/fake/servers.d.ts.map +1 -1
  16. package/dist/codegen.go/src/fake/servers.js +58 -65
  17. package/dist/codegen.go/src/fake/servers.js.map +1 -1
  18. package/dist/codegen.go/src/helpers.d.ts +36 -3
  19. package/dist/codegen.go/src/helpers.d.ts.map +1 -1
  20. package/dist/codegen.go/src/helpers.js +72 -17
  21. package/dist/codegen.go/src/helpers.js.map +1 -1
  22. package/dist/codegen.go/src/imports.d.ts +1 -1
  23. package/dist/codegen.go/src/imports.d.ts.map +1 -1
  24. package/dist/codegen.go/src/imports.js +4 -6
  25. package/dist/codegen.go/src/imports.js.map +1 -1
  26. package/dist/codegen.go/src/models.d.ts +0 -1
  27. package/dist/codegen.go/src/models.d.ts.map +1 -1
  28. package/dist/codegen.go/src/models.js +1 -7
  29. package/dist/codegen.go/src/models.js.map +1 -1
  30. package/dist/codegen.go/src/operations.d.ts.map +1 -1
  31. package/dist/codegen.go/src/operations.js +349 -141
  32. package/dist/codegen.go/src/operations.js.map +1 -1
  33. package/dist/codegen.go/src/responses.d.ts.map +1 -1
  34. package/dist/codegen.go/src/responses.js +2 -3
  35. package/dist/codegen.go/src/responses.js.map +1 -1
  36. package/dist/codemodel.go/src/client.d.ts +99 -35
  37. package/dist/codemodel.go/src/client.d.ts.map +1 -1
  38. package/dist/codemodel.go/src/client.js +53 -13
  39. package/dist/codemodel.go/src/client.js.map +1 -1
  40. package/dist/codemodel.go/src/examples.d.ts +3 -11
  41. package/dist/codemodel.go/src/examples.d.ts.map +1 -1
  42. package/dist/codemodel.go/src/examples.js +0 -7
  43. package/dist/codemodel.go/src/examples.js.map +1 -1
  44. package/dist/codemodel.go/src/index.d.ts.map +1 -1
  45. package/dist/codemodel.go/src/index.js +1 -0
  46. package/dist/codemodel.go/src/index.js.map +1 -1
  47. package/dist/codemodel.go/src/method.d.ts +44 -0
  48. package/dist/codemodel.go/src/method.d.ts.map +1 -0
  49. package/dist/codemodel.go/src/method.js +30 -0
  50. package/dist/codemodel.go/src/method.js.map +1 -0
  51. package/dist/codemodel.go/src/package.d.ts +2 -0
  52. package/dist/codemodel.go/src/package.d.ts.map +1 -1
  53. package/dist/codemodel.go/src/package.js +8 -0
  54. package/dist/codemodel.go/src/package.js.map +1 -1
  55. package/dist/codemodel.go/src/param.d.ts +67 -40
  56. package/dist/codemodel.go/src/param.d.ts.map +1 -1
  57. package/dist/codemodel.go/src/param.js +46 -25
  58. package/dist/codemodel.go/src/param.js.map +1 -1
  59. package/dist/codemodel.go/src/result.d.ts +1 -1
  60. package/dist/codemodel.go/src/result.d.ts.map +1 -1
  61. package/dist/codemodel.go/src/result.js +1 -1
  62. package/dist/codemodel.go/src/result.js.map +1 -1
  63. package/dist/codemodel.go/src/type.d.ts +53 -15
  64. package/dist/codemodel.go/src/type.d.ts.map +1 -1
  65. package/dist/codemodel.go/src/type.js +52 -18
  66. package/dist/codemodel.go/src/type.js.map +1 -1
  67. package/dist/typespec-go/src/emitter.d.ts +9 -0
  68. package/dist/typespec-go/src/emitter.d.ts.map +1 -1
  69. package/dist/typespec-go/src/emitter.js +37 -1
  70. package/dist/typespec-go/src/emitter.js.map +1 -1
  71. package/dist/typespec-go/src/lib.d.ts +1 -0
  72. package/dist/typespec-go/src/lib.d.ts.map +1 -1
  73. package/dist/typespec-go/src/lib.js +5 -0
  74. package/dist/typespec-go/src/lib.js.map +1 -1
  75. package/dist/typespec-go/src/tcgcadapter/adapter.d.ts.map +1 -1
  76. package/dist/typespec-go/src/tcgcadapter/adapter.js +4 -1
  77. package/dist/typespec-go/src/tcgcadapter/adapter.js.map +1 -1
  78. package/dist/typespec-go/src/tcgcadapter/clients.d.ts +19 -3
  79. package/dist/typespec-go/src/tcgcadapter/clients.d.ts.map +1 -1
  80. package/dist/typespec-go/src/tcgcadapter/clients.js +283 -87
  81. package/dist/typespec-go/src/tcgcadapter/clients.js.map +1 -1
  82. package/dist/typespec-go/src/tcgcadapter/types.d.ts +7 -0
  83. package/dist/typespec-go/src/tcgcadapter/types.d.ts.map +1 -1
  84. package/dist/typespec-go/src/tcgcadapter/types.js +17 -10
  85. package/dist/typespec-go/src/tcgcadapter/types.js.map +1 -1
  86. package/package.json +22 -21
@@ -12,20 +12,20 @@ import { isTypePassedByValue } from './types.js';
12
12
  // used to convert SDK clients and their methods to Go code model types
13
13
  export class clientAdapter {
14
14
  ta;
15
- opts;
15
+ ctx;
16
16
  // track all of the client and parameter group params across all operations
17
17
  // as not every option might contain them, and parameter groups can be shared
18
18
  // across multiple operations
19
19
  clientParams;
20
- constructor(ta, opts) {
20
+ constructor(ta, ctx) {
21
21
  this.ta = ta;
22
- this.opts = opts;
22
+ this.ctx = ctx;
23
23
  this.clientParams = new Map();
24
24
  }
25
25
  // converts all clients and their methods to Go code model types.
26
26
  // this includes parameter groups/options types and response envelopes.
27
27
  adaptClients(sdkPackage) {
28
- if (this.opts['single-client'] && sdkPackage.clients.length > 1) {
28
+ if (this.ctx.options['single-client'] && sdkPackage.clients.length > 1) {
29
29
  throw new AdapterError('InvalidArgument', 'single-client cannot be enabled when there are multiple clients', NoTarget);
30
30
  }
31
31
  for (const sdkClient of sdkPackage.clients) {
@@ -78,14 +78,98 @@ export class clientAdapter {
78
78
  // the client name is simply "Client"
79
79
  docs.summary = `${clientName} contains the methods for the service.`;
80
80
  }
81
- const goClient = new go.Client(clientName, docs, go.newClientOptions(this.ta.codeModel.type, clientName));
81
+ const goClient = new go.Client(clientName, docs);
82
82
  goClient.parent = parent;
83
+ // NOTE: per tcgc convention, if there is no param of kind credential
84
+ // it means that the client doesn't require any kind of authentication.
85
+ // HOWEVER, if there *is* a credential param, then the client *does not*
86
+ // automatically support unauthenticated requests. a credential with
87
+ // the noAuth scheme indicates support for unauthenticated requests.
88
+ // bit flags for auth types
89
+ let AuthTypes;
90
+ (function (AuthTypes) {
91
+ AuthTypes[AuthTypes["Default"] = 0] = "Default";
92
+ AuthTypes[AuthTypes["NoAuth"] = 1] = "NoAuth";
93
+ AuthTypes[AuthTypes["WithAuth"] = 2] = "WithAuth";
94
+ AuthTypes[AuthTypes["OmitAuth"] = 4] = "OmitAuth";
95
+ })(AuthTypes || (AuthTypes = {}));
96
+ // we skip generating client constructors when emitting into
97
+ // an existing module. this is because the constructor(s) require
98
+ // the module name and version info, and we can't make any
99
+ // assumptions about the names/location.
100
+ let authType = (this.ta.codeModel.options.omitConstructors || this.ta.codeModel.options.containingModule) ? AuthTypes.OmitAuth : AuthTypes.Default;
101
+ if (!this.ta.codeModel.options.omitConstructors && this.ta.codeModel.options.containingModule) {
102
+ // emit a diagnostic indicating that no ctors will be emitted due to containing-module.
103
+ this.ctx.program.reportDiagnostic({
104
+ code: 'UnsupportedConfiguration',
105
+ severity: 'warning',
106
+ message: 'cannot emit client constructors when containing-module is set',
107
+ target: sdkClient.__raw.type ?? NoTarget,
108
+ });
109
+ }
110
+ /**
111
+ * processes a credendial, potentially adding its supporting client constructor
112
+ *
113
+ * @param goClient the Go client for which to add the constructor
114
+ * @param constructable the constructable for the current Go client
115
+ * @param cred the credential type to process
116
+ * @returns the AuthTypes enum for the credential that was handled, or AuthTypes.Default if none were specified/handled
117
+ */
118
+ const processCredential = (goClient, constructable, cred) => {
119
+ switch (cred.type) {
120
+ case 'noAuth':
121
+ return AuthTypes.NoAuth;
122
+ case 'oauth2': {
123
+ constructable.constructors.push(this.createTokenCredentialCtor(goClient, cred));
124
+ return AuthTypes.WithAuth;
125
+ }
126
+ default:
127
+ this.ctx.program.reportDiagnostic({
128
+ code: 'UnsupportedAuthenticationScheme',
129
+ severity: 'warning',
130
+ message: `unsupported authentication scheme ${cred.type} will be omitted`,
131
+ target: sdkClient.__raw.type ?? NoTarget,
132
+ });
133
+ // return WithAuth as the tsp specifies authentication.
134
+ // this is to avoid adding a WithNoCredential() ctor to
135
+ // clients that might not support it.
136
+ return AuthTypes.WithAuth;
137
+ }
138
+ };
139
+ if (this.ta.codeModel.type === 'azure-arm') {
140
+ // to keep compat with pre-tsp codegen we
141
+ // treat all ARM clients as instantiable.
142
+ sdkClient.clientInitialization.initializedBy |= tcgc.InitializedByFlags.Individually;
143
+ }
83
144
  // anything other than public means non-instantiable client
84
145
  if (sdkClient.clientInitialization.initializedBy & tcgc.InitializedByFlags.Individually) {
146
+ goClient.instance = new go.Constructable(go.newClientOptions(this.ta.codeModel.type, clientName));
85
147
  for (const param of sdkClient.clientInitialization.parameters) {
86
148
  switch (param.kind) {
87
149
  case 'credential':
88
- // skip this for now as we don't generate client constructors
150
+ if (authType === AuthTypes.OmitAuth) {
151
+ continue;
152
+ }
153
+ switch (param.type.kind) {
154
+ case 'credential':
155
+ authType |= processCredential(goClient, goClient.instance, param.type.scheme);
156
+ break;
157
+ case 'union': {
158
+ const variantKinds = new Array();
159
+ for (const variantType of param.type.variantTypes) {
160
+ variantKinds.push(variantType.scheme.type);
161
+ // emit the support credential kinds and skip any unsupported ones.
162
+ // this prevents emitting the WithNoCredential constructor in cases
163
+ // where it might not actually be supported.
164
+ authType |= processCredential(goClient, goClient.instance, variantType.scheme);
165
+ }
166
+ // no supported credential types were specified
167
+ if (authType === AuthTypes.Default) {
168
+ throw new AdapterError('UnsupportedTsp', `credential scheme types ${variantKinds.join()} NYI`, param.__raw?.node ?? NoTarget);
169
+ }
170
+ continue;
171
+ }
172
+ }
89
173
  continue;
90
174
  case 'endpoint': {
91
175
  if (this.ta.codeModel.type === 'azure-arm') {
@@ -111,25 +195,29 @@ export class clientAdapter {
111
195
  const templateArg = endpointType.templateArguments[i];
112
196
  if (i === 0) {
113
197
  // the first template arg is always the endpoint parameter.
114
- // note that the types of the param and the field are different.
115
- // NOTE: we use param.name here instead of templateArg.name as
116
- // the former has the fixed name "endpoint" which is what we want.
117
- const adaptedParam = this.adaptURIParam(templateArg);
118
- adaptedParam.docs.summary = templateArg.summary;
119
- adaptedParam.docs.description = templateArg.doc;
198
+ // NOTE: we force the endpoint param to be required, omitting
199
+ // any potential for client-side default.
200
+ const adaptedParam = this.adaptURIParam(templateArg, true);
201
+ adaptedParam.docs.summary = param.summary;
202
+ adaptedParam.docs.description = param.doc;
120
203
  goClient.parameters.push(adaptedParam);
121
204
  // if the server's URL is *only* the endpoint parameter then we're done.
122
205
  // this is the param.type.kind === 'endpoint' case.
123
206
  if (endpointType.serverUrl === `{${templateArg.serializedName}}`) {
124
207
  break;
125
208
  }
126
- goClient.templatedHost = endpointType.serverUrl;
209
+ // there's either a suffix on the endpoint param, more template arguments, or both.
210
+ // either way we need to create supplemental info on the constructable.
211
+ // strip off the first segment which corresponds to the endpoint param as it's not needed.
212
+ const serverUrl = endpointType.serverUrl.replace(`{${templateArg.serializedName}}/`, '');
213
+ goClient.instance.endpoint = new go.SupplementalEndpoint(serverUrl);
127
214
  continue;
128
215
  }
129
- const adaptedParam = this.adaptURIParam(templateArg);
216
+ const adaptedParam = this.adaptURIParam(templateArg, false);
130
217
  adaptedParam.docs.summary = templateArg.summary;
131
218
  adaptedParam.docs.description = templateArg.doc;
132
- goClient.parameters.push(adaptedParam);
219
+ adaptedParam.isApiVersion = templateArg.isApiVersionParam;
220
+ goClient.instance.endpoint?.parameters.push(adaptedParam);
133
221
  }
134
222
  break;
135
223
  }
@@ -139,15 +227,38 @@ export class clientAdapter {
139
227
  // e.g. op withQueryApiVersion(@query("api-version") apiVersion: string)
140
228
  // these get propagated to sdkMethod.operation.parameters thus they
141
229
  // will be adapted in adaptMethodParameters()
230
+ // for path-based API version params, we need to emit the field on the client
231
+ // and handle it like a regular client parameter.
232
+ //
233
+ // for header/query API version params, we need to emit the correct values
234
+ // for the APIVersionOptions{} struct so the policy can work. in this case,
235
+ // no field should be emitted on the client.
142
236
  continue;
143
237
  }
144
238
  }
239
+ // if no authentication type was specified, or the noAuth scheme was
240
+ // explicitly specified, then include the WithNoCredential constructor
241
+ if (authType === AuthTypes.Default || (authType & AuthTypes.NoAuth) === AuthTypes.NoAuth) {
242
+ goClient.instance.constructors.push(new go.Constructor(`New${clientName}WithNoCredential`, new go.NoAuthentication()));
243
+ }
244
+ // propagate optional params to the optional params group
245
+ for (const param of goClient.parameters) {
246
+ if (!go.isRequiredParameter(param.style) && !go.isLiteralParameter(param.style) && goClient.instance.options.kind === 'clientOptions') {
247
+ goClient.instance.options.params.push(param);
248
+ }
249
+ }
250
+ // if we created constructors, propagate the persisted client params to them
251
+ for (const constructor of goClient.instance.constructors) {
252
+ constructor.parameters = goClient.parameters;
253
+ }
145
254
  }
146
255
  else if (parent) {
147
256
  // this is a sub-client. it will share the client/host params of the parent.
148
257
  // NOTE: we must propagate parant params before a potential recursive call
149
258
  // to create a child client that will need to inherit our client params.
150
- goClient.templatedHost = parent.templatedHost;
259
+ if (parent.instance?.kind === 'templatedHost') {
260
+ goClient.instance = parent.instance;
261
+ }
151
262
  // make a copy of the client params. this is to prevent
152
263
  // client method params from being shared across clients
153
264
  // as not all client method params might be uniform.
@@ -177,11 +288,47 @@ export class clientAdapter {
177
288
  }
178
289
  return goClient;
179
290
  }
180
- adaptURIParam(sdkParam) {
181
- const paramType = this.ta.getWireType(sdkParam.type, true, false);
291
+ /**
292
+ * creates a new Go client constructor using token credential authentication
293
+ *
294
+ * @param goClient the Go client for which to create the constructor
295
+ * @param cred the token credential type
296
+ * @returns a new Go client constructor using token credential authentication
297
+ */
298
+ createTokenCredentialCtor(goClient, cred) {
299
+ if (cred.flows.length === 0) {
300
+ throw new AdapterError('InternalError', `no flows defined for credential type ${cred.type}`, cred.model);
301
+ }
302
+ else if (cred.flows[0].scopes.length === 0) {
303
+ throw new AdapterError('InternalError', `no scopes defined for credential type ${cred.type}`, cred.model);
304
+ }
305
+ else if (cred.flows[0].scopes.length > 1) {
306
+ throw new AdapterError('InternalError', `too many scopes defined for credential type ${cred.type}`, cred.model);
307
+ }
308
+ return new go.Constructor(`New${goClient.name}`, new go.TokenAuthentication(cred.flows[0].scopes.map(each => each.value)));
309
+ }
310
+ /**
311
+ * creates a new Go URI parameter from the specified tcgc path parameter
312
+ *
313
+ * @param sdkParam the tcgc parameter to adapt
314
+ * @param forceRequired when true, the parameter is not optional regardless of authoring
315
+ * @returns the adapted URI parameter
316
+ */
317
+ adaptURIParam(sdkParam, forceRequired) {
318
+ let paramType;
319
+ if (sdkParam.isApiVersionParam) {
320
+ paramType = new go.String();
321
+ }
322
+ else {
323
+ paramType = this.ta.getWireType(sdkParam.type, true, false);
324
+ }
182
325
  if (go.isURIParameterType(paramType)) {
326
+ const style = forceRequired ? 'required' : this.adaptParameterStyle(sdkParam);
183
327
  // TODO: follow up with tcgc if serializedName should actually be optional
184
- return new go.URIParameter(sdkParam.name, sdkParam.serializedName ? sdkParam.serializedName : sdkParam.name, paramType, this.adaptParameterStyle(sdkParam), isTypePassedByValue(sdkParam.type) || !sdkParam.optional, 'client');
328
+ const uriParam = new go.URIParameter(sdkParam.name, sdkParam.serializedName ? sdkParam.serializedName : sdkParam.name, paramType, style, isTypePassedByValue(sdkParam.type) || !sdkParam.optional, 'client');
329
+ uriParam.docs.summary = sdkParam.summary;
330
+ uriParam.docs.description = sdkParam.doc;
331
+ return uriParam;
185
332
  }
186
333
  throw new AdapterError('UnsupportedTsp', `unsupported URI parameter type ${paramType.kind}`, sdkParam.__raw?.node ?? NoTarget);
187
334
  }
@@ -205,13 +352,17 @@ export class clientAdapter {
205
352
  };
206
353
  let methodName = capitalize(ensureNameCase(sdkMethod.name));
207
354
  if (sdkMethod.access === 'internal') {
208
- // we add internal to the extra list so we don't end up with a method named "internal"
209
- // which will collide with an unexported field with the same name.
210
- methodName = getEscapedReservedName(uncapitalize(methodName), 'Method', ['internal']);
355
+ methodName = uncapitalize(methodName);
356
+ if (sdkMethod.kind === 'basic') {
357
+ // we add internal to the extra list so we don't end up with a method named "internal"
358
+ // which will collide with an unexported field with the same name. we don't need to
359
+ // do this for pagers/pollers as those methods get extra naming.
360
+ methodName = getEscapedReservedName(methodName, 'Method', ['internal']);
361
+ }
211
362
  }
212
363
  const statusCodes = getStatusCodes(sdkMethod.operation);
213
364
  if (sdkMethod.kind === 'basic') {
214
- method = new go.Method(methodName, goClient, sdkMethod.operation.path, sdkMethod.operation.verb, statusCodes, naming);
365
+ method = new go.SyncMethod(methodName, goClient, sdkMethod.operation.path, sdkMethod.operation.verb, statusCodes, naming);
215
366
  }
216
367
  else if (sdkMethod.kind === 'paging') {
217
368
  if (sdkMethod.pagingMetadata.nextLinkReInjectedParametersSegments !== undefined && sdkMethod.pagingMetadata.nextLinkReInjectedParametersSegments.length > 0) {
@@ -263,8 +414,8 @@ export class clientAdapter {
263
414
  if (method.kind === 'nextPageMethod') {
264
415
  throw new AdapterError('UnsupportedTsp', `unsupported method kind ${sdkMethod.kind}`, sdkMethod.__raw?.node ?? NoTarget);
265
416
  }
266
- let prefix = method.client.name;
267
- if (this.opts['single-client']) {
417
+ let prefix = method.receiver.type.name;
418
+ if (this.ctx.options['single-client']) {
268
419
  prefix = '';
269
420
  }
270
421
  if (go.isLROMethod(method)) {
@@ -285,7 +436,7 @@ export class clientAdapter {
285
436
  }
286
437
  method.optionalParamsGroup = new go.ParameterGroup(optsGroupName, optionalParamsGroupName, false, 'method');
287
438
  method.optionalParamsGroup.docs.summary = createOptionsTypeDescription(optionalParamsGroupName, this.getMethodNameForDocComment(method));
288
- method.responseEnvelope = this.adaptResponseEnvelope(sdkMethod, method);
439
+ method.returns = this.adaptResponseEnvelope(sdkMethod, method);
289
440
  // find the api version param to use for the doc comment.
290
441
  // we can't use sdkMethod.apiVersions as that includes all
291
442
  // of the api versions supported by the service.
@@ -362,13 +513,16 @@ export class clientAdapter {
362
513
  // a flag which isn't what we want. so, we mark it as required. we ONLY do this
363
514
  // if the content-type is a constant (i.e. literal value).
364
515
  // the content-type will be conditionally set based on the requiredness of the body.
365
- opParam.optional = false;
516
+ // NOTE: we set this on the corresponding method param as it's used when adapting the style.
517
+ // header param will only have one corresponding method param.
518
+ opParam.correspondingMethodParams[0].optional = false;
366
519
  }
367
520
  let adaptedParam;
368
521
  if (opParam.kind === 'body' && opParam.type.kind === 'model' && opParam.type.kind !== param.type.kind) {
369
522
  const paramStyle = this.adaptParameterStyle(param);
370
523
  const paramName = getEscapedReservedName(ensureNameCase(param.name, paramStyle === 'required'), 'Param');
371
- const byVal = isTypePassedByValue(param.type);
524
+ // if the param is required then it's always passed by value
525
+ const byVal = go.isRequiredParameter(paramStyle) ? true : isTypePassedByValue(param.type);
372
526
  const contentType = this.adaptContentType(opParam.defaultContentType);
373
527
  const getSerializedNameFromProperty = function (property) {
374
528
  if (contentType === 'JSON') {
@@ -444,16 +598,18 @@ export class clientAdapter {
444
598
  paramMapping.get(opParam)?.push(adaptedParam);
445
599
  // if the adapted client param is a literal then don't add it to
446
600
  // the array of client params as it's not a formal parameter.
447
- if (go.isLiteralParameter(adaptedParam)) {
601
+ // the only exception is any api version parameter as we need this
602
+ // for generating client constructors.
603
+ if (go.isLiteralParameter(adaptedParam.style) && !go.isAPIVersionParameter(adaptedParam)) {
448
604
  continue;
449
605
  }
450
606
  // we must check via param name and not reference equality. this is because a client param
451
607
  // can be used in multiple ways. e.g. a client param "apiVersion" that's used as a path param
452
608
  // in one method and a query param in another.
453
- if (!method.client.parameters.find((v) => {
609
+ if (!method.receiver.type.parameters.find((v) => {
454
610
  return v.name === adaptedParam.name;
455
611
  })) {
456
- method.client.parameters.push(adaptedParam);
612
+ method.receiver.type.parameters.push(adaptedParam);
457
613
  }
458
614
  }
459
615
  }
@@ -477,103 +633,124 @@ export class clientAdapter {
477
633
  /**
478
634
  * adapts the provided operation parameter to a Go method parameter
479
635
  *
480
- * @param param the operation parameter to adapt
636
+ * @param opParam the operation parameter to adapt
481
637
  * @param verb the HTTP verb used for the operation to which the parameter belongs
482
638
  * @returns the adapted Go method parameter
483
639
  */
484
- adaptMethodParameter(param, verb) {
485
- if (param.isApiVersionParam && param.clientDefaultValue) {
640
+ adaptMethodParameter(opParam, verb) {
641
+ if (opParam.isApiVersionParam) {
486
642
  // we emit the api version param inline as a literal, never as a param.
487
643
  // the ClientOptions.APIVersion setting is used to change the version.
488
- const paramType = new go.Literal(new go.String(), param.clientDefaultValue);
489
- switch (param.kind) {
644
+ const paramType = opParam.clientDefaultValue ? new go.Literal(new go.String(), opParam.clientDefaultValue) : new go.String();
645
+ const paramStyle = opParam.clientDefaultValue ? 'literal' : opParam.optional ? 'optional' : 'required';
646
+ const paramLoc = opParam.onClient ? 'client' : 'method';
647
+ let apiVersionParam;
648
+ switch (opParam.kind) {
490
649
  case 'header':
491
- return new go.HeaderScalarParameter(param.name, param.serializedName, paramType, 'literal', true, 'method');
650
+ apiVersionParam = new go.HeaderScalarParameter('apiVersion', opParam.serializedName, paramType, paramStyle, true, paramLoc);
651
+ break;
492
652
  case 'path':
493
- return new go.PathScalarParameter(param.name, param.serializedName, true, paramType, 'literal', true, 'method');
653
+ apiVersionParam = new go.PathScalarParameter('apiVersion', opParam.serializedName, true, paramType, paramStyle, true, paramLoc);
654
+ break;
494
655
  case 'query':
495
- return new go.QueryScalarParameter(param.name, param.serializedName, true, paramType, 'literal', true, 'method');
656
+ apiVersionParam = new go.QueryScalarParameter('apiVersion', opParam.serializedName, true, paramType, paramStyle, true, paramLoc);
657
+ break;
496
658
  default:
497
- throw new AdapterError('UnsupportedTsp', `unsupported API version param kind ${param.kind}`, param.__raw?.node ?? NoTarget);
659
+ throw new AdapterError('UnsupportedTsp', `unsupported API version param kind ${opParam.kind}`, opParam.__raw?.node ?? NoTarget);
498
660
  }
661
+ apiVersionParam.isApiVersion = true;
662
+ return apiVersionParam;
499
663
  }
500
664
  let location = 'method';
501
- const getClientParamsKey = function (param) {
665
+ const getClientParamsKey = function (opParam) {
502
666
  // include the param kind in the key name as a client param can be used
503
667
  // in different places across methods (path/query)
504
- return `${param.name}-${param.kind}`;
668
+ return `${opParam.name}-${opParam.kind}`;
505
669
  };
506
- if (param.onClient) {
670
+ // note that client params only show up in the operation
671
+ // params which is why we check opParam.onClient.
672
+ if (opParam.onClient) {
507
673
  // check if we've already adapted this client parameter
508
- const clientParam = this.clientParams.get(getClientParamsKey(param));
674
+ const clientParam = this.clientParams.get(getClientParamsKey(opParam));
509
675
  if (clientParam) {
510
676
  return clientParam;
511
677
  }
512
678
  location = 'client';
513
679
  }
514
- let paramStyle = this.adaptParameterStyle(param);
515
- if (param.kind === 'body' && (verb === 'patch' || verb === 'put')) {
680
+ // we use the operation param's corresponding method
681
+ // param as the source of truth during adaptation.
682
+ // however, note that some things are only on the
683
+ // operation param.
684
+ if (opParam.correspondingMethodParams.length > 1) {
685
+ // this is only applicable to spread params
686
+ // which should have been handled earlier.
687
+ // so, if we get here, we have a bug elsewhere
688
+ throw new AdapterError('InternalError', `unexpected correspondingMethodParams.length of ${opParam.correspondingMethodParams.length}`, opParam.__raw?.node ?? NoTarget);
689
+ }
690
+ const methodParam = opParam.correspondingMethodParams[0];
691
+ let paramStyle = this.adaptParameterStyle(methodParam);
692
+ if (opParam.kind === 'body' && (verb === 'patch' || verb === 'put')) {
516
693
  paramStyle = 'required';
517
694
  }
518
- const paramName = getEscapedReservedName(ensureNameCase(param.name, paramStyle === 'required'), 'Param');
519
- const byVal = isTypePassedByValue(param.type);
695
+ const paramName = getEscapedReservedName(ensureNameCase(methodParam.name, paramStyle === 'required'), 'Param');
696
+ const byVal = go.isRequiredParameter(paramStyle) ? true : isTypePassedByValue(methodParam.type);
520
697
  let adaptedParam;
521
- switch (param.kind) {
698
+ switch (opParam.kind) {
522
699
  case 'body':
523
700
  // TODO: form data? (non-multipart)
524
- if (param.defaultContentType.match(/multipart/i)) {
525
- adaptedParam = new go.MultipartFormBodyParameter(paramName, this.ta.getWireType(param.type, false, true), paramStyle, byVal);
701
+ if (opParam.defaultContentType.match(/multipart/i)) {
702
+ adaptedParam = new go.MultipartFormBodyParameter(paramName, this.ta.getWireType(methodParam.type, false, true), paramStyle, byVal);
526
703
  }
527
704
  else {
528
- const contentType = this.adaptContentType(param.defaultContentType);
529
- let bodyType = this.ta.getWireType(param.type, false, true);
705
+ const contentType = this.adaptContentType(opParam.defaultContentType);
706
+ let bodyType = this.ta.getWireType(methodParam.type, false, true);
530
707
  if (contentType === 'binary') {
531
708
  // tcgc models binary params as 'bytes' but we want an io.ReadSeekCloser
532
- bodyType = this.ta.getReadSeekCloser(param.type.kind === 'array');
709
+ bodyType = this.ta.getReadSeekCloser(methodParam.type.kind === 'array');
533
710
  }
534
- adaptedParam = new go.BodyParameter(paramName, contentType, `"${param.defaultContentType}"`, bodyType, paramStyle, byVal);
711
+ adaptedParam = new go.BodyParameter(paramName, contentType, `"${opParam.defaultContentType}"`, bodyType, paramStyle, byVal);
535
712
  }
536
713
  break;
537
714
  case 'cookie':
538
715
  // TODO: currently we don't have Azure service using cookie parameter. need to add support if needed in the future.
539
- throw new AdapterError('UnsupportedTsp', 'unsupported parameter type cookie', param.__raw?.node ?? NoTarget);
716
+ throw new AdapterError('UnsupportedTsp', 'unsupported parameter type cookie', opParam.__raw?.node ?? NoTarget);
540
717
  case 'header':
541
- if (param.collectionFormat) {
542
- if (param.collectionFormat === 'multi' || param.collectionFormat === 'form') {
543
- throw new AdapterError('InternalError', `unexpected collection format ${param.collectionFormat} for HeaderCollectionParameter`, param.__raw?.node ?? NoTarget);
718
+ if (opParam.collectionFormat) {
719
+ if (opParam.collectionFormat === 'multi' || opParam.collectionFormat === 'form') {
720
+ throw new AdapterError('InternalError', `unexpected collection format ${opParam.collectionFormat} for HeaderCollectionParameter`, opParam.__raw?.node ?? NoTarget);
544
721
  }
545
722
  // TODO: is hard-coded false for element type by value correct?
546
- const type = this.ta.getWireType(param.type, true, false);
723
+ const type = this.ta.getWireType(methodParam.type, true, false);
547
724
  if (type.kind !== 'slice') {
548
- throw new AdapterError('InternalError', `unexpected type ${go.getTypeDeclaration(type)} for HeaderCollectionParameter ${param.name}`, param.__raw?.node ?? NoTarget);
725
+ throw new AdapterError('InternalError', `unexpected type ${go.getTypeDeclaration(type)} for HeaderCollectionParameter ${methodParam.name}`, opParam.__raw?.node ?? NoTarget);
549
726
  }
550
- adaptedParam = new go.HeaderCollectionParameter(paramName, param.serializedName, type, param.collectionFormat === 'simple' ? 'csv' : param.collectionFormat, paramStyle, byVal, location);
727
+ adaptedParam = new go.HeaderCollectionParameter(paramName, opParam.serializedName, type, opParam.collectionFormat === 'simple' ? 'csv' : opParam.collectionFormat, paramStyle, byVal, location);
551
728
  }
552
729
  else {
553
- adaptedParam = new go.HeaderScalarParameter(paramName, param.serializedName, this.adaptHeaderScalarType(param.type, true), paramStyle, byVal, location);
730
+ adaptedParam = new go.HeaderScalarParameter(paramName, opParam.serializedName, this.adaptHeaderScalarType(methodParam.type, true), paramStyle, byVal, location);
554
731
  }
555
732
  break;
556
733
  case 'path':
557
- adaptedParam = new go.PathScalarParameter(paramName, param.serializedName, !param.allowReserved, this.adaptPathScalarParameterType(param.type), paramStyle, byVal, location);
734
+ adaptedParam = new go.PathScalarParameter(paramName, opParam.serializedName, !opParam.allowReserved, this.adaptPathScalarParameterType(methodParam.type), paramStyle, byVal, location);
558
735
  break;
559
736
  case 'query':
560
- if (param.collectionFormat) {
561
- const type = this.ta.getWireType(param.type, true, false);
737
+ if (opParam.collectionFormat) {
738
+ const type = this.ta.getWireType(methodParam.type, true, false);
562
739
  if (type.kind !== 'slice') {
563
- throw new AdapterError('InternalError', `unexpected type ${go.getTypeDeclaration(type)} for QueryCollectionParameter ${param.name}`, param.__raw?.node ?? NoTarget);
740
+ throw new AdapterError('InternalError', `unexpected type ${go.getTypeDeclaration(type)} for QueryCollectionParameter ${methodParam.name}`, opParam.__raw?.node ?? NoTarget);
564
741
  }
565
742
  // TODO: unencoded query param
566
- adaptedParam = new go.QueryCollectionParameter(paramName, param.serializedName, true, type, param.collectionFormat === 'simple' ? 'csv' : (param.collectionFormat === 'form' ? 'multi' : param.collectionFormat), paramStyle, byVal, location);
743
+ adaptedParam = new go.QueryCollectionParameter(paramName, opParam.serializedName, true, type, opParam.collectionFormat === 'simple' ? 'csv' : (opParam.collectionFormat === 'form' ? 'multi' : opParam.collectionFormat), paramStyle, byVal, location);
567
744
  }
568
745
  else {
569
746
  // TODO: unencoded query param
570
- adaptedParam = new go.QueryScalarParameter(paramName, param.serializedName, true, this.adaptQueryScalarParameterType(param.type), paramStyle, byVal, location);
747
+ adaptedParam = new go.QueryScalarParameter(paramName, opParam.serializedName, true, this.adaptQueryScalarParameterType(methodParam.type), paramStyle, byVal, location);
571
748
  }
572
749
  break;
573
750
  }
574
751
  if (adaptedParam.location === 'client') {
575
752
  // track client parameter for later use
576
- this.clientParams.set(getClientParamsKey(param), adaptedParam);
753
+ this.clientParams.set(getClientParamsKey(opParam), adaptedParam);
577
754
  }
578
755
  return adaptedParam;
579
756
  }
@@ -591,12 +768,12 @@ export class clientAdapter {
591
768
  methodName = `New${method.name}Pager`;
592
769
  break;
593
770
  }
594
- return `${method.client.name}.${methodName}`;
771
+ return `${method.receiver.type.name}.${methodName}`;
595
772
  }
596
773
  adaptResponseEnvelope(sdkMethod, method) {
597
774
  // TODO: add Envelope suffix if name collides with existing type
598
- let prefix = method.client.name;
599
- if (this.opts['single-client']) {
775
+ let prefix = method.receiver.type.name;
776
+ if (this.ctx.options['single-client']) {
600
777
  prefix = '';
601
778
  }
602
779
  let respEnvName = `${prefix}${method.name}Response`;
@@ -626,7 +803,7 @@ export class clientAdapter {
626
803
  }
627
804
  let sdkResponseType = sdkMethod.response.type;
628
805
  // since HEAD requests don't return a type, we must check this before checking sdkResponseType
629
- if (method.httpMethod === 'head' && this.opts['head-as-boolean'] === true) {
806
+ if (method.httpMethod === 'head' && this.ctx.options['head-as-boolean'] === true) {
630
807
  respEnv.result = new go.HeadAsBooleanResult('Success');
631
808
  respEnv.result.docs.summary = 'Success indicates if the operation succeeded or failed.';
632
809
  }
@@ -825,10 +1002,29 @@ export class clientAdapter {
825
1002
  return 'literal';
826
1003
  }
827
1004
  else if (param.clientDefaultValue) {
828
- const adaptedType = this.ta.getWireType(param.type, false, false);
829
- if (!go.isLiteralValueType(adaptedType)) {
830
- throw new AdapterError('InternalError', `unexpected client side default type ${go.getTypeDeclaration(adaptedType)} for parameter ${param.name}`, param.__raw?.node ?? NoTarget);
1005
+ let adaptedType;
1006
+ if (param.isApiVersionParam) {
1007
+ // we force the API version param type to a string
1008
+ // so it matches the ClientOptions.APIVersion type
1009
+ adaptedType = new go.String();
1010
+ }
1011
+ else {
1012
+ const adaptedWireType = this.ta.getWireType(param.type, false, false);
1013
+ if (!go.isLiteralValueType(adaptedWireType)) {
1014
+ throw new AdapterError('InternalError', `unexpected client side default type ${go.getTypeDeclaration(adaptedWireType)} for parameter ${param.name}`, param.__raw?.node ?? NoTarget);
1015
+ }
1016
+ adaptedType = adaptedWireType;
1017
+ }
1018
+ if (adaptedType.kind === 'constant') {
1019
+ // find the matching constant for the clientDefaultValue
1020
+ for (const constValue of adaptedType.values) {
1021
+ if (constValue.value === param.clientDefaultValue) {
1022
+ return new go.ClientSideDefault(new go.Literal(adaptedType, constValue));
1023
+ }
1024
+ }
1025
+ throw new AdapterError('InternalError', `didn't find clientDefaultValue constant with value ${param.clientDefaultValue} for parameter`, param.__raw?.node ?? NoTarget);
831
1026
  }
1027
+ // non-constant clientDefaultValue
832
1028
  return new go.ClientSideDefault(new go.Literal(adaptedType, param.clientDefaultValue));
833
1029
  }
834
1030
  else if (param.optional) {
@@ -839,7 +1035,7 @@ export class clientAdapter {
839
1035
  }
840
1036
  }
841
1037
  adaptHttpOperationExamples(sdkMethod, method, paramMapping) {
842
- if (sdkMethod.operation.examples) {
1038
+ if (sdkMethod.operation.examples && sdkMethod.access !== 'internal') {
843
1039
  for (const example of sdkMethod.operation.examples) {
844
1040
  const goExample = new go.MethodExample(example.name, { summary: example.doc }, example.filePath);
845
1041
  for (const param of example.parameters) {
@@ -877,9 +1073,9 @@ export class clientAdapter {
877
1073
  // only handle 200 response
878
1074
  const response = example.responses.find((v) => { return v.statusCode === 200; });
879
1075
  if (response) {
880
- goExample.responseEnvelope = new go.ResponseEnvelopeExample(method.responseEnvelope);
1076
+ goExample.responseEnvelope = new go.ResponseEnvelopeExample(method.returns);
881
1077
  for (const header of response.headers) {
882
- const goHeader = method.responseEnvelope.headers.find(h => h.headerName === header.header.serializedName);
1078
+ const goHeader = method.returns.headers.find(h => h.headerName === header.header.serializedName);
883
1079
  if (!goHeader) {
884
1080
  throw new AdapterError('InternalError', `can not find go header for example header ${header.header.serializedName}`, NoTarget);
885
1081
  }
@@ -888,8 +1084,8 @@ export class clientAdapter {
888
1084
  // there are some problems with LROs at present which can cause the result
889
1085
  // to be undefined even though the operation returns a response.
890
1086
  // TODO: https://github.com/Azure/typespec-azure/issues/1688
891
- if (response.bodyValue && method.responseEnvelope.result) {
892
- switch (method.responseEnvelope.result.kind) {
1087
+ if (response.bodyValue && method.returns.result) {
1088
+ switch (method.returns.result.kind) {
893
1089
  case 'anyResult':
894
1090
  goExample.responseEnvelope.result = this.adaptExampleType(response.bodyValue, new go.Any());
895
1091
  break;
@@ -897,13 +1093,13 @@ export class clientAdapter {
897
1093
  goExample.responseEnvelope.result = this.adaptExampleType(response.bodyValue, new go.Scalar('byte', false));
898
1094
  break;
899
1095
  case 'modelResult':
900
- goExample.responseEnvelope.result = this.adaptExampleType(response.bodyValue, method.responseEnvelope.result.modelType);
1096
+ goExample.responseEnvelope.result = this.adaptExampleType(response.bodyValue, method.returns.result.modelType);
901
1097
  break;
902
1098
  case 'monomorphicResult':
903
- goExample.responseEnvelope.result = this.adaptExampleType(response.bodyValue, method.responseEnvelope.result.monomorphicType);
1099
+ goExample.responseEnvelope.result = this.adaptExampleType(response.bodyValue, method.returns.result.monomorphicType);
904
1100
  break;
905
1101
  case 'polymorphicResult':
906
- goExample.responseEnvelope.result = this.adaptExampleType(response.bodyValue, method.responseEnvelope.result.interface);
1102
+ goExample.responseEnvelope.result = this.adaptExampleType(response.bodyValue, method.returns.result.interface);
907
1103
  break;
908
1104
  }
909
1105
  }
@@ -918,12 +1114,11 @@ export class clientAdapter {
918
1114
  switch (goType.kind) {
919
1115
  case 'constant':
920
1116
  case 'encodedBytes':
1117
+ case 'etag':
921
1118
  case 'literal':
922
1119
  case 'string':
923
1120
  case 'time':
924
1121
  return new go.StringExample(exampleType.value, goType);
925
- case 'qualifiedType':
926
- return new go.QualifiedExample(goType, exampleType.value);
927
1122
  }
928
1123
  break;
929
1124
  case 'number':
@@ -1014,4 +1209,5 @@ export class clientAdapter {
1014
1209
  function isHttpStatusCodeRange(statusCode) {
1015
1210
  return statusCode.start !== undefined;
1016
1211
  }
1212
+ ;
1017
1213
  //# sourceMappingURL=clients.js.map