@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.
- package/README.md +7 -7
- package/dist/codegen.go/src/clientFactory.d.ts.map +1 -1
- package/dist/codegen.go/src/clientFactory.js +4 -0
- package/dist/codegen.go/src/clientFactory.js.map +1 -1
- package/dist/codegen.go/src/cloudConfig.d.ts +10 -0
- package/dist/codegen.go/src/cloudConfig.d.ts.map +1 -0
- package/dist/codegen.go/src/cloudConfig.js +65 -0
- package/dist/codegen.go/src/cloudConfig.js.map +1 -0
- package/dist/codegen.go/src/example.d.ts.map +1 -1
- package/dist/codegen.go/src/example.js +98 -109
- package/dist/codegen.go/src/example.js.map +1 -1
- package/dist/codegen.go/src/fake/factory.d.ts.map +1 -1
- package/dist/codegen.go/src/fake/factory.js +11 -2
- package/dist/codegen.go/src/fake/factory.js.map +1 -1
- package/dist/codegen.go/src/fake/servers.d.ts.map +1 -1
- package/dist/codegen.go/src/fake/servers.js +58 -65
- package/dist/codegen.go/src/fake/servers.js.map +1 -1
- package/dist/codegen.go/src/helpers.d.ts +36 -3
- package/dist/codegen.go/src/helpers.d.ts.map +1 -1
- package/dist/codegen.go/src/helpers.js +72 -17
- package/dist/codegen.go/src/helpers.js.map +1 -1
- package/dist/codegen.go/src/imports.d.ts +1 -1
- package/dist/codegen.go/src/imports.d.ts.map +1 -1
- package/dist/codegen.go/src/imports.js +4 -6
- package/dist/codegen.go/src/imports.js.map +1 -1
- package/dist/codegen.go/src/models.d.ts +0 -1
- package/dist/codegen.go/src/models.d.ts.map +1 -1
- package/dist/codegen.go/src/models.js +1 -7
- package/dist/codegen.go/src/models.js.map +1 -1
- package/dist/codegen.go/src/operations.d.ts.map +1 -1
- package/dist/codegen.go/src/operations.js +349 -141
- package/dist/codegen.go/src/operations.js.map +1 -1
- package/dist/codegen.go/src/responses.d.ts.map +1 -1
- package/dist/codegen.go/src/responses.js +2 -3
- package/dist/codegen.go/src/responses.js.map +1 -1
- package/dist/codemodel.go/src/client.d.ts +99 -35
- package/dist/codemodel.go/src/client.d.ts.map +1 -1
- package/dist/codemodel.go/src/client.js +53 -13
- package/dist/codemodel.go/src/client.js.map +1 -1
- package/dist/codemodel.go/src/examples.d.ts +3 -11
- package/dist/codemodel.go/src/examples.d.ts.map +1 -1
- package/dist/codemodel.go/src/examples.js +0 -7
- package/dist/codemodel.go/src/examples.js.map +1 -1
- package/dist/codemodel.go/src/index.d.ts.map +1 -1
- package/dist/codemodel.go/src/index.js +1 -0
- package/dist/codemodel.go/src/index.js.map +1 -1
- package/dist/codemodel.go/src/method.d.ts +44 -0
- package/dist/codemodel.go/src/method.d.ts.map +1 -0
- package/dist/codemodel.go/src/method.js +30 -0
- package/dist/codemodel.go/src/method.js.map +1 -0
- package/dist/codemodel.go/src/package.d.ts +2 -0
- package/dist/codemodel.go/src/package.d.ts.map +1 -1
- package/dist/codemodel.go/src/package.js +8 -0
- package/dist/codemodel.go/src/package.js.map +1 -1
- package/dist/codemodel.go/src/param.d.ts +67 -40
- package/dist/codemodel.go/src/param.d.ts.map +1 -1
- package/dist/codemodel.go/src/param.js +46 -25
- package/dist/codemodel.go/src/param.js.map +1 -1
- package/dist/codemodel.go/src/result.d.ts +1 -1
- package/dist/codemodel.go/src/result.d.ts.map +1 -1
- package/dist/codemodel.go/src/result.js +1 -1
- package/dist/codemodel.go/src/result.js.map +1 -1
- package/dist/codemodel.go/src/type.d.ts +53 -15
- package/dist/codemodel.go/src/type.d.ts.map +1 -1
- package/dist/codemodel.go/src/type.js +52 -18
- package/dist/codemodel.go/src/type.js.map +1 -1
- package/dist/typespec-go/src/emitter.d.ts +9 -0
- package/dist/typespec-go/src/emitter.d.ts.map +1 -1
- package/dist/typespec-go/src/emitter.js +37 -1
- package/dist/typespec-go/src/emitter.js.map +1 -1
- package/dist/typespec-go/src/lib.d.ts +1 -0
- package/dist/typespec-go/src/lib.d.ts.map +1 -1
- package/dist/typespec-go/src/lib.js +5 -0
- package/dist/typespec-go/src/lib.js.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/adapter.d.ts.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/adapter.js +4 -1
- package/dist/typespec-go/src/tcgcadapter/adapter.js.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/clients.d.ts +19 -3
- package/dist/typespec-go/src/tcgcadapter/clients.d.ts.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/clients.js +283 -87
- package/dist/typespec-go/src/tcgcadapter/clients.js.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/types.d.ts +7 -0
- package/dist/typespec-go/src/tcgcadapter/types.d.ts.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/types.js +17 -10
- package/dist/typespec-go/src/tcgcadapter/types.js.map +1 -1
- 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
|
-
|
|
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,
|
|
20
|
+
constructor(ta, ctx) {
|
|
21
21
|
this.ta = ta;
|
|
22
|
-
this.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
//
|
|
115
|
-
//
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
adaptedParam.docs.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
181
|
-
|
|
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
|
-
|
|
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
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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.
|
|
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.
|
|
267
|
-
if (this.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
609
|
+
if (!method.receiver.type.parameters.find((v) => {
|
|
454
610
|
return v.name === adaptedParam.name;
|
|
455
611
|
})) {
|
|
456
|
-
method.
|
|
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
|
|
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(
|
|
485
|
-
if (
|
|
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(),
|
|
489
|
-
|
|
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
|
-
|
|
650
|
+
apiVersionParam = new go.HeaderScalarParameter('apiVersion', opParam.serializedName, paramType, paramStyle, true, paramLoc);
|
|
651
|
+
break;
|
|
492
652
|
case 'path':
|
|
493
|
-
|
|
653
|
+
apiVersionParam = new go.PathScalarParameter('apiVersion', opParam.serializedName, true, paramType, paramStyle, true, paramLoc);
|
|
654
|
+
break;
|
|
494
655
|
case 'query':
|
|
495
|
-
|
|
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 ${
|
|
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 (
|
|
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 `${
|
|
668
|
+
return `${opParam.name}-${opParam.kind}`;
|
|
505
669
|
};
|
|
506
|
-
|
|
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(
|
|
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
|
-
|
|
515
|
-
|
|
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(
|
|
519
|
-
const byVal = isTypePassedByValue(
|
|
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 (
|
|
698
|
+
switch (opParam.kind) {
|
|
522
699
|
case 'body':
|
|
523
700
|
// TODO: form data? (non-multipart)
|
|
524
|
-
if (
|
|
525
|
-
adaptedParam = new go.MultipartFormBodyParameter(paramName, this.ta.getWireType(
|
|
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(
|
|
529
|
-
let bodyType = this.ta.getWireType(
|
|
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(
|
|
709
|
+
bodyType = this.ta.getReadSeekCloser(methodParam.type.kind === 'array');
|
|
533
710
|
}
|
|
534
|
-
adaptedParam = new go.BodyParameter(paramName, contentType, `"${
|
|
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',
|
|
716
|
+
throw new AdapterError('UnsupportedTsp', 'unsupported parameter type cookie', opParam.__raw?.node ?? NoTarget);
|
|
540
717
|
case 'header':
|
|
541
|
-
if (
|
|
542
|
-
if (
|
|
543
|
-
throw new AdapterError('InternalError', `unexpected collection format ${
|
|
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(
|
|
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 ${
|
|
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,
|
|
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,
|
|
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,
|
|
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 (
|
|
561
|
-
const type = this.ta.getWireType(
|
|
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 ${
|
|
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,
|
|
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,
|
|
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(
|
|
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.
|
|
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.
|
|
599
|
-
if (this.
|
|
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.
|
|
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
|
-
|
|
829
|
-
if (
|
|
830
|
-
|
|
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.
|
|
1076
|
+
goExample.responseEnvelope = new go.ResponseEnvelopeExample(method.returns);
|
|
881
1077
|
for (const header of response.headers) {
|
|
882
|
-
const goHeader = method.
|
|
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.
|
|
892
|
-
switch (method.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|