@azure-tools/typespec-go 0.1.0
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/LICENSE +21 -0
- package/README.md +16 -0
- package/dist/codegen.go/src/clientFactory.d.ts +3 -0
- package/dist/codegen.go/src/clientFactory.d.ts.map +1 -0
- package/dist/codegen.go/src/clientFactory.js +77 -0
- package/dist/codegen.go/src/clientFactory.js.map +1 -0
- package/dist/codegen.go/src/constants.d.ts +3 -0
- package/dist/codegen.go/src/constants.d.ts.map +1 -0
- package/dist/codegen.go/src/constants.js +59 -0
- package/dist/codegen.go/src/constants.js.map +1 -0
- package/dist/codegen.go/src/fake/factory.d.ts +3 -0
- package/dist/codegen.go/src/fake/factory.d.ts.map +1 -0
- package/dist/codegen.go/src/fake/factory.js +69 -0
- package/dist/codegen.go/src/fake/factory.js.map +1 -0
- package/dist/codegen.go/src/fake/internal.d.ts +14 -0
- package/dist/codegen.go/src/fake/internal.d.ts.map +1 -0
- package/dist/codegen.go/src/fake/internal.js +197 -0
- package/dist/codegen.go/src/fake/internal.js.map +1 -0
- package/dist/codegen.go/src/fake/servers.d.ts +14 -0
- package/dist/codegen.go/src/fake/servers.d.ts.map +1 -0
- package/dist/codegen.go/src/fake/servers.js +1255 -0
- package/dist/codegen.go/src/fake/servers.js.map +1 -0
- package/dist/codegen.go/src/gomod.d.ts +3 -0
- package/dist/codegen.go/src/gomod.d.ts.map +1 -0
- package/dist/codegen.go/src/gomod.js +55 -0
- package/dist/codegen.go/src/gomod.js.map +1 -0
- package/dist/codegen.go/src/helpers.d.ts +32 -0
- package/dist/codegen.go/src/helpers.d.ts.map +1 -0
- package/dist/codegen.go/src/helpers.js +586 -0
- package/dist/codegen.go/src/helpers.js.map +1 -0
- package/dist/codegen.go/src/imports.d.ts +11 -0
- package/dist/codegen.go/src/imports.d.ts.map +1 -0
- package/dist/codegen.go/src/imports.js +65 -0
- package/dist/codegen.go/src/imports.js.map +1 -0
- package/dist/codegen.go/src/interfaces.d.ts +3 -0
- package/dist/codegen.go/src/interfaces.d.ts.map +1 -0
- package/dist/codegen.go/src/interfaces.js +36 -0
- package/dist/codegen.go/src/interfaces.js.map +1 -0
- package/dist/codegen.go/src/models.d.ts +9 -0
- package/dist/codegen.go/src/models.d.ts.map +1 -0
- package/dist/codegen.go/src/models.js +849 -0
- package/dist/codegen.go/src/models.js.map +1 -0
- package/dist/codegen.go/src/operations.d.ts +9 -0
- package/dist/codegen.go/src/operations.d.ts.map +1 -0
- package/dist/codegen.go/src/operations.js +1337 -0
- package/dist/codegen.go/src/operations.js.map +1 -0
- package/dist/codegen.go/src/options.d.ts +3 -0
- package/dist/codegen.go/src/options.d.ts.map +1 -0
- package/dist/codegen.go/src/options.js +64 -0
- package/dist/codegen.go/src/options.js.map +1 -0
- package/dist/codegen.go/src/polymorphics.d.ts +3 -0
- package/dist/codegen.go/src/polymorphics.d.ts.map +1 -0
- package/dist/codegen.go/src/polymorphics.js +169 -0
- package/dist/codegen.go/src/polymorphics.js.map +1 -0
- package/dist/codegen.go/src/responses.d.ts +7 -0
- package/dist/codegen.go/src/responses.d.ts.map +1 -0
- package/dist/codegen.go/src/responses.js +167 -0
- package/dist/codegen.go/src/responses.js.map +1 -0
- package/dist/codegen.go/src/time.d.ts +8 -0
- package/dist/codegen.go/src/time.d.ts.map +1 -0
- package/dist/codegen.go/src/time.js +511 -0
- package/dist/codegen.go/src/time.js.map +1 -0
- package/dist/codemodel.go/src/client.d.ts +96 -0
- package/dist/codemodel.go/src/client.d.ts.map +1 -0
- package/dist/codemodel.go/src/client.js +114 -0
- package/dist/codemodel.go/src/client.js.map +1 -0
- package/dist/codemodel.go/src/index.d.ts +6 -0
- package/dist/codemodel.go/src/index.d.ts.map +1 -0
- package/dist/codemodel.go/src/index.js +10 -0
- package/dist/codemodel.go/src/index.js.map +1 -0
- package/dist/codemodel.go/src/package.d.ts +49 -0
- package/dist/codemodel.go/src/package.d.ts.map +1 -0
- package/dist/codemodel.go/src/package.js +86 -0
- package/dist/codemodel.go/src/package.js.map +1 -0
- package/dist/codemodel.go/src/param.d.ts +162 -0
- package/dist/codemodel.go/src/param.d.ts.map +1 -0
- package/dist/codemodel.go/src/param.js +189 -0
- package/dist/codemodel.go/src/param.js.map +1 -0
- package/dist/codemodel.go/src/result.d.ts +102 -0
- package/dist/codemodel.go/src/result.d.ts.map +1 -0
- package/dist/codemodel.go/src/result.js +119 -0
- package/dist/codemodel.go/src/result.js.map +1 -0
- package/dist/codemodel.go/src/type.d.ts +181 -0
- package/dist/codemodel.go/src/type.d.ts.map +1 -0
- package/dist/codemodel.go/src/type.js +242 -0
- package/dist/codemodel.go/src/type.js.map +1 -0
- package/dist/naming.go/src/mappings.d.ts +3 -0
- package/dist/naming.go/src/mappings.d.ts.map +1 -0
- package/dist/naming.go/src/mappings.js +128 -0
- package/dist/naming.go/src/mappings.js.map +1 -0
- package/dist/naming.go/src/naming.d.ts +10 -0
- package/dist/naming.go/src/naming.d.ts.map +1 -0
- package/dist/naming.go/src/naming.js +114 -0
- package/dist/naming.go/src/naming.js.map +1 -0
- package/dist/typespec-go/src/emitter.d.ts +5 -0
- package/dist/typespec-go/src/emitter.d.ts.map +1 -0
- package/dist/typespec-go/src/emitter.js +122 -0
- package/dist/typespec-go/src/emitter.js.map +1 -0
- package/dist/typespec-go/src/index.d.ts +3 -0
- package/dist/typespec-go/src/index.d.ts.map +1 -0
- package/dist/typespec-go/src/index.js +7 -0
- package/dist/typespec-go/src/index.js.map +1 -0
- package/dist/typespec-go/src/lib.d.ts +25 -0
- package/dist/typespec-go/src/lib.d.ts.map +1 -0
- package/dist/typespec-go/src/lib.js +36 -0
- package/dist/typespec-go/src/lib.js.map +1 -0
- package/dist/typespec-go/src/tcgcadapter/adapter.d.ts +5 -0
- package/dist/typespec-go/src/tcgcadapter/adapter.d.ts.map +1 -0
- package/dist/typespec-go/src/tcgcadapter/adapter.js +119 -0
- package/dist/typespec-go/src/tcgcadapter/adapter.js.map +1 -0
- package/dist/typespec-go/src/tcgcadapter/clients.d.ts +26 -0
- package/dist/typespec-go/src/tcgcadapter/clients.d.ts.map +1 -0
- package/dist/typespec-go/src/tcgcadapter/clients.js +621 -0
- package/dist/typespec-go/src/tcgcadapter/clients.js.map +1 -0
- package/dist/typespec-go/src/tcgcadapter/types.d.ts +29 -0
- package/dist/typespec-go/src/tcgcadapter/types.d.ts.map +1 -0
- package/dist/typespec-go/src/tcgcadapter/types.js +975 -0
- package/dist/typespec-go/src/tcgcadapter/types.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,1337 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import * as go from '../../codemodel.go/src/index.js';
|
|
6
|
+
import { capitalize, comment, uncapitalize } from '@azure-tools/codegen';
|
|
7
|
+
import { values } from '@azure-tools/linq';
|
|
8
|
+
import * as helpers from './helpers.js';
|
|
9
|
+
import { ImportManager } from './imports.js';
|
|
10
|
+
// represents the generated content for an operation group
|
|
11
|
+
export class OperationGroupContent {
|
|
12
|
+
constructor(name, content) {
|
|
13
|
+
this.name = name;
|
|
14
|
+
this.content = content;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// Creates the content for all <operation>.go files
|
|
18
|
+
export async function generateOperations(codeModel) {
|
|
19
|
+
// generate protocol operations
|
|
20
|
+
const operations = new Array();
|
|
21
|
+
if (codeModel.clients.length === 0) {
|
|
22
|
+
return operations;
|
|
23
|
+
}
|
|
24
|
+
const azureARM = codeModel.type === 'azure-arm';
|
|
25
|
+
for (const client of codeModel.clients) {
|
|
26
|
+
// the list of packages to import
|
|
27
|
+
const imports = new ImportManager();
|
|
28
|
+
if (client.methods.length > 0) {
|
|
29
|
+
// add standard imports for clients with methods.
|
|
30
|
+
// clients that are purely hierarchical (i.e. having no APIs) won't need them.
|
|
31
|
+
imports.add('net/http');
|
|
32
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/policy');
|
|
33
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime');
|
|
34
|
+
}
|
|
35
|
+
let clientPkg = 'azcore';
|
|
36
|
+
if (azureARM) {
|
|
37
|
+
clientPkg = 'arm';
|
|
38
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/arm');
|
|
39
|
+
client.constructors.push(createARMClientConstructor(client, imports));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore');
|
|
43
|
+
}
|
|
44
|
+
// generate client type
|
|
45
|
+
let clientText = '';
|
|
46
|
+
clientText += `${comment(`${client.description}`, '//', undefined, helpers.commentLength)}\n`;
|
|
47
|
+
clientText += '// Don\'t use this type directly, use ';
|
|
48
|
+
if (client.constructors.length === 1) {
|
|
49
|
+
clientText += `${client.constructors[0].name}() instead.\n`;
|
|
50
|
+
}
|
|
51
|
+
else if (client.parent) {
|
|
52
|
+
// find the accessor method
|
|
53
|
+
let accessorMethod;
|
|
54
|
+
for (const clientAccessor of client.parent.clientAccessors) {
|
|
55
|
+
if (clientAccessor.subClient === client) {
|
|
56
|
+
accessorMethod = clientAccessor.name;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!accessorMethod) {
|
|
61
|
+
throw new Error(`didn't find accessor method for client ${client.name} on parent client ${client.parent.name}`);
|
|
62
|
+
}
|
|
63
|
+
clientText += `[${client.parent.name}.${accessorMethod}] instead.\n`;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
clientText += 'a constructor function instead.\n';
|
|
67
|
+
}
|
|
68
|
+
clientText += `type ${client.name} struct {\n`;
|
|
69
|
+
clientText += `\tinternal *${clientPkg}.Client\n`;
|
|
70
|
+
// check for any optional host params
|
|
71
|
+
const optionalParams = new Array();
|
|
72
|
+
const isParamPointer = function (param) {
|
|
73
|
+
// for client params, only optional and flag types are passed by pointer
|
|
74
|
+
return param.kind === 'flag' || param.kind === 'optional';
|
|
75
|
+
};
|
|
76
|
+
// now emit any client params (non parameterized host params case)
|
|
77
|
+
if (client.parameters.length > 0) {
|
|
78
|
+
const addedGroups = new Set();
|
|
79
|
+
for (const clientParam of values(client.parameters)) {
|
|
80
|
+
if (go.isLiteralParameter(clientParam)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (clientParam.group) {
|
|
84
|
+
if (!addedGroups.has(clientParam.group.groupName)) {
|
|
85
|
+
clientText += `\t${uncapitalize(clientParam.group.groupName)} ${!isParamPointer(clientParam) ? '' : '*'}${clientParam.group.groupName}\n`;
|
|
86
|
+
addedGroups.add(clientParam.group.groupName);
|
|
87
|
+
}
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
clientText += `\t${clientParam.name} `;
|
|
91
|
+
if (!isParamPointer(clientParam)) {
|
|
92
|
+
clientText += `${go.getTypeDeclaration(clientParam.type)}\n`;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
clientText += `${helpers.formatParameterTypeName(clientParam)}\n`;
|
|
96
|
+
}
|
|
97
|
+
if (!go.isRequiredParameter(clientParam)) {
|
|
98
|
+
optionalParams.push(clientParam);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// end of client definition
|
|
103
|
+
clientText += '}\n\n';
|
|
104
|
+
if (azureARM && optionalParams.length > 0) {
|
|
105
|
+
throw new Error('optional client parameters for ARM is not supported');
|
|
106
|
+
}
|
|
107
|
+
// generate client constructors
|
|
108
|
+
clientText += generateConstructors(azureARM, client, imports);
|
|
109
|
+
// generate client accessors and operations
|
|
110
|
+
let opText = '';
|
|
111
|
+
for (const clientAccessor of client.clientAccessors) {
|
|
112
|
+
opText += `// ${clientAccessor.name} creates a new instance of [${clientAccessor.subClient.name}].\n`;
|
|
113
|
+
opText += `func (client *${client.name}) ${clientAccessor.name}() *${clientAccessor.subClient.name} {\n`;
|
|
114
|
+
opText += `\treturn &${clientAccessor.subClient.name}{\n`;
|
|
115
|
+
opText += '\t\tinternal: client.internal,\n';
|
|
116
|
+
// propagate all client params
|
|
117
|
+
for (const param of client.parameters) {
|
|
118
|
+
opText += `\t\t${param.name}: client.${param.name},\n`;
|
|
119
|
+
}
|
|
120
|
+
opText += '\t}\n}\n\n';
|
|
121
|
+
}
|
|
122
|
+
const nextPageMethods = new Array();
|
|
123
|
+
for (const method of client.methods) {
|
|
124
|
+
// protocol creation can add imports to the list so
|
|
125
|
+
// it must be done before the imports are written out
|
|
126
|
+
if (go.isLROMethod(method)) {
|
|
127
|
+
// generate Begin method
|
|
128
|
+
opText += generateLROBeginMethod(client, method, imports, codeModel.options.injectSpans, codeModel.options.generateFakes);
|
|
129
|
+
}
|
|
130
|
+
opText += generateOperation(client, method, imports, codeModel.options.injectSpans, codeModel.options.generateFakes);
|
|
131
|
+
opText += createProtocolRequest(azureARM, client, method, imports);
|
|
132
|
+
if (!go.isLROMethod(method) || go.isPageableMethod(method)) {
|
|
133
|
+
// LRO responses are handled elsewhere, with the exception of pageable LROs
|
|
134
|
+
opText += createProtocolResponse(client, method, imports);
|
|
135
|
+
}
|
|
136
|
+
if (go.isPageableMethod(method) && method.nextPageMethod && !nextPageMethods.includes(method.nextPageMethod)) {
|
|
137
|
+
// track the next page methods to generate as multiple operations can use the same next page operation
|
|
138
|
+
nextPageMethods.push(method.nextPageMethod);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
for (const method of nextPageMethods) {
|
|
142
|
+
opText += createProtocolRequest(azureARM, client, method, imports);
|
|
143
|
+
}
|
|
144
|
+
// stitch it all together
|
|
145
|
+
let text = helpers.contentPreamble(codeModel);
|
|
146
|
+
text += imports.text();
|
|
147
|
+
text += clientText;
|
|
148
|
+
text += opText;
|
|
149
|
+
operations.push(new OperationGroupContent(client.name, text));
|
|
150
|
+
}
|
|
151
|
+
return operations;
|
|
152
|
+
}
|
|
153
|
+
// generates all modeled client constructors
|
|
154
|
+
function generateConstructors(azureARM, client, imports) {
|
|
155
|
+
if (client.constructors.length === 0) {
|
|
156
|
+
return '';
|
|
157
|
+
}
|
|
158
|
+
let ctorText = '';
|
|
159
|
+
for (const constructor of client.constructors) {
|
|
160
|
+
const ctorParams = new Array();
|
|
161
|
+
const paramDocs = new Array();
|
|
162
|
+
constructor.parameters.sort(helpers.sortParametersByRequired);
|
|
163
|
+
for (const ctorParam of constructor.parameters) {
|
|
164
|
+
imports.addImportForType(ctorParam.type);
|
|
165
|
+
ctorParams.push(`${ctorParam.name} ${helpers.formatParameterTypeName(ctorParam)}`);
|
|
166
|
+
if (ctorParam.description) {
|
|
167
|
+
paramDocs.push(helpers.formatCommentAsBulletItem(`${ctorParam.name} - ${ctorParam.description}`));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// add client options last
|
|
171
|
+
ctorParams.push(`${client.options.name} ${helpers.formatParameterTypeName(client.options)}`);
|
|
172
|
+
paramDocs.push(helpers.formatCommentAsBulletItem(`${client.options.name} - ${client.options.description}`));
|
|
173
|
+
ctorText += `// ${constructor.name} creates a new instance of ${client.name} with the specified values.\n`;
|
|
174
|
+
for (const doc of paramDocs) {
|
|
175
|
+
ctorText += `${doc}\n`;
|
|
176
|
+
}
|
|
177
|
+
ctorText += `func ${constructor.name}(${ctorParams.join(', ')}) (*${client.name}, error) {\n`;
|
|
178
|
+
let clientType = 'azcore';
|
|
179
|
+
if (azureARM) {
|
|
180
|
+
clientType = 'arm';
|
|
181
|
+
}
|
|
182
|
+
ctorText += `\tcl, err := ${clientType}.NewClient(moduleName, moduleVersion, credential, options)\n`;
|
|
183
|
+
ctorText += '\tif err != nil {\n';
|
|
184
|
+
ctorText += '\t\treturn nil, err\n';
|
|
185
|
+
ctorText += '\t}\n';
|
|
186
|
+
// construct client literal
|
|
187
|
+
ctorText += `\tclient := &${client.name}{\n`;
|
|
188
|
+
for (const parameter of values(client.parameters)) {
|
|
189
|
+
// each client field will have a matching parameter with the same name
|
|
190
|
+
ctorText += `\t\t${parameter.name}: ${parameter.name},\n`;
|
|
191
|
+
}
|
|
192
|
+
ctorText += '\tinternal: cl,\n';
|
|
193
|
+
ctorText += '\t}\n';
|
|
194
|
+
ctorText += '\treturn client, nil\n';
|
|
195
|
+
ctorText += '}\n\n';
|
|
196
|
+
}
|
|
197
|
+
return ctorText;
|
|
198
|
+
}
|
|
199
|
+
// creates a modeled constructor for an ARM client
|
|
200
|
+
function createARMClientConstructor(client, imports) {
|
|
201
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/arm');
|
|
202
|
+
const ctor = new go.Constructor(`New${client.name}`);
|
|
203
|
+
// add any modeled parameter first, which should only be the subscriptionID, then add TokenCredential
|
|
204
|
+
for (const param of client.parameters) {
|
|
205
|
+
ctor.parameters.push(param);
|
|
206
|
+
}
|
|
207
|
+
const tokenCredParam = new go.Parameter('credential', new go.QualifiedType('TokenCredential', 'github.com/Azure/azure-sdk-for-go/sdk/azcore'), 'required', true, 'client');
|
|
208
|
+
tokenCredParam.description = 'used to authorize requests. Usually a credential from azidentity.';
|
|
209
|
+
ctor.parameters.push(tokenCredParam);
|
|
210
|
+
return ctor;
|
|
211
|
+
}
|
|
212
|
+
// use this to generate the code that will help process values returned in response headers
|
|
213
|
+
function formatHeaderResponseValue(headerResp, imports, respObj, zeroResp) {
|
|
214
|
+
// dictionaries are handled slightly different so we do that first
|
|
215
|
+
if (go.isHeaderMapResponse(headerResp)) {
|
|
216
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/to');
|
|
217
|
+
imports.add('strings');
|
|
218
|
+
const headerPrefix = headerResp.collectionPrefix;
|
|
219
|
+
let text = '\tfor hh := range resp.Header {\n';
|
|
220
|
+
text += `\t\tif len(hh) > len("${headerPrefix}") && strings.EqualFold(hh[:len("${headerPrefix}")], "${headerPrefix}") {\n`;
|
|
221
|
+
text += `\t\t\tif ${respObj}.${headerResp.fieldName} == nil {\n`;
|
|
222
|
+
text += `\t\t\t\t${respObj}.${headerResp.fieldName} = map[string]*string{}\n`;
|
|
223
|
+
text += '\t\t\t}\n';
|
|
224
|
+
text += `\t\t\t${respObj}.${headerResp.fieldName}[hh[len("${headerPrefix}"):]] = to.Ptr(resp.Header.Get(hh))\n`;
|
|
225
|
+
text += '\t\t}\n';
|
|
226
|
+
text += '\t}\n';
|
|
227
|
+
return text;
|
|
228
|
+
}
|
|
229
|
+
let text = `\tif val := resp.Header.Get("${headerResp.headerName}"); val != "" {\n`;
|
|
230
|
+
let name = uncapitalize(headerResp.fieldName);
|
|
231
|
+
let byRef = '&';
|
|
232
|
+
if (go.isConstantType(headerResp.type)) {
|
|
233
|
+
text += `\t\t${respObj}.${headerResp.fieldName} = (*${headerResp.type.name})(&val)\n`;
|
|
234
|
+
text += '\t}\n';
|
|
235
|
+
return text;
|
|
236
|
+
}
|
|
237
|
+
else if (go.isPrimitiveType(headerResp.type)) {
|
|
238
|
+
if (headerResp.type.typeName === 'bool') {
|
|
239
|
+
imports.add('strconv');
|
|
240
|
+
text += `\t\t${name}, err := strconv.ParseBool(val)\n`;
|
|
241
|
+
}
|
|
242
|
+
else if (headerResp.type.typeName === 'int32' || headerResp.type.typeName === 'int64') {
|
|
243
|
+
imports.add('strconv');
|
|
244
|
+
if (headerResp.type.typeName === 'int32') {
|
|
245
|
+
text += `\t\t${name}32, err := strconv.ParseInt(val, 10, 32)\n`;
|
|
246
|
+
text += `\t\t${name} := int32(${name}32)\n`;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
text += `\t\t${name}, err := strconv.ParseInt(val, 10, 64)\n`;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else if (headerResp.type.typeName === 'float32' || headerResp.type.typeName === 'float64') {
|
|
253
|
+
imports.add('strconv');
|
|
254
|
+
if (headerResp.type.typeName === 'float32') {
|
|
255
|
+
text += `\t\t${name}32, err := strconv.ParseFloat(val, 32)\n`;
|
|
256
|
+
text += `\t\t${name} := float32(${name}32)\n`;
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
text += `\t\t${name}, err := strconv.ParseFloat(val, 64)\n`;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else if (headerResp.type.typeName === 'string') {
|
|
263
|
+
text += `\t\t${respObj}.${headerResp.fieldName} = &val\n`;
|
|
264
|
+
text += '\t}\n';
|
|
265
|
+
return text;
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
throw new Error(`unhandled primitive type ${headerResp.type.typeName}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
else if (go.isTimeType(headerResp.type)) {
|
|
272
|
+
imports.add('time');
|
|
273
|
+
if (headerResp.type.dateTimeFormat === 'dateType') {
|
|
274
|
+
text += `\t\t${name}, err := time.Parse("${helpers.dateFormat}", val)\n`;
|
|
275
|
+
}
|
|
276
|
+
else if (headerResp.type.dateTimeFormat === 'timeRFC3339') {
|
|
277
|
+
text += `\t\t${name}, err := time.Parse("${helpers.timeRFC3339Format}", val)\n`;
|
|
278
|
+
}
|
|
279
|
+
else if (headerResp.type.dateTimeFormat === 'timeUnix') {
|
|
280
|
+
imports.add('strconv');
|
|
281
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/to');
|
|
282
|
+
text += '\t\tsec, err := strconv.ParseInt(val, 10, 64)\n';
|
|
283
|
+
name = 'to.Ptr(time.Unix(sec, 0))';
|
|
284
|
+
byRef = '';
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
let format = helpers.datetimeRFC3339Format;
|
|
288
|
+
if (headerResp.type.dateTimeFormat === 'dateTimeRFC1123') {
|
|
289
|
+
format = helpers.datetimeRFC1123Format;
|
|
290
|
+
}
|
|
291
|
+
text += `\t\t${name}, err := time.Parse(${format}, val)\n`;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
else if (go.isBytesType(headerResp.type)) {
|
|
295
|
+
// ByteArray is a base-64 encoded value in string format
|
|
296
|
+
imports.add('encoding/base64');
|
|
297
|
+
text += `\t\t${name}, err := base64.${helpers.formatBytesEncoding(headerResp.type.encoding)}Encoding.DecodeString(val)\n`;
|
|
298
|
+
byRef = '';
|
|
299
|
+
}
|
|
300
|
+
else if (go.isLiteralValue(headerResp.type)) {
|
|
301
|
+
text += `\t\t${respObj}.${headerResp.fieldName} = &val\n`;
|
|
302
|
+
text += '\t}\n';
|
|
303
|
+
return text;
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
throw new Error(`unsupported header type ${go.getTypeDeclaration(headerResp.type)}`);
|
|
307
|
+
}
|
|
308
|
+
text += '\t\tif err != nil {\n';
|
|
309
|
+
text += `\t\t\treturn ${zeroResp}, err\n`;
|
|
310
|
+
text += '\t\t}\n';
|
|
311
|
+
text += `\t\t${respObj}.${headerResp.fieldName} = ${byRef}${name}\n`;
|
|
312
|
+
text += '\t}\n';
|
|
313
|
+
return text;
|
|
314
|
+
}
|
|
315
|
+
function getZeroReturnValue(method, apiType) {
|
|
316
|
+
let returnType = `${method.responseEnvelope.name}{}`;
|
|
317
|
+
if (go.isLROMethod(method)) {
|
|
318
|
+
if (apiType === 'api' || apiType === 'op') {
|
|
319
|
+
// the api returns a *Poller[T]
|
|
320
|
+
// the operation returns an *http.Response
|
|
321
|
+
returnType = 'nil';
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return returnType;
|
|
325
|
+
}
|
|
326
|
+
function emitPagerDefinition(client, method, imports, injectSpans, generateFakes) {
|
|
327
|
+
imports.add('context');
|
|
328
|
+
let text = `runtime.NewPager(runtime.PagingHandler[${method.responseEnvelope.name}]{\n`;
|
|
329
|
+
text += `\t\tMore: func(page ${method.responseEnvelope.name}) bool {\n`;
|
|
330
|
+
// there is no advancer for single-page pagers
|
|
331
|
+
if (method.nextLinkName) {
|
|
332
|
+
text += `\t\t\treturn page.${method.nextLinkName} != nil && len(*page.${method.nextLinkName}) > 0\n`;
|
|
333
|
+
text += '\t\t},\n';
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
text += '\t\t\treturn false\n';
|
|
337
|
+
text += '\t\t},\n';
|
|
338
|
+
}
|
|
339
|
+
text += `\t\tFetcher: func(ctx context.Context, page *${method.responseEnvelope.name}) (${method.responseEnvelope.name}, error) {\n`;
|
|
340
|
+
const reqParams = helpers.getCreateRequestParameters(method);
|
|
341
|
+
if (generateFakes) {
|
|
342
|
+
text += `\t\tctx = context.WithValue(ctx, runtime.CtxAPINameKey{}, "${client.name}.${fixUpMethodName(method)}")\n`;
|
|
343
|
+
}
|
|
344
|
+
if (method.nextLinkName) {
|
|
345
|
+
let nextLinkVar;
|
|
346
|
+
if (!go.isLROMethod(method)) {
|
|
347
|
+
text += '\t\t\tnextLink := ""\n';
|
|
348
|
+
nextLinkVar = 'nextLink';
|
|
349
|
+
text += '\t\t\tif page != nil {\n';
|
|
350
|
+
text += `\t\t\t\tnextLink = *page.${method.nextLinkName}\n\t\t\t}\n`;
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
nextLinkVar = `*page.${method.nextLinkName}`;
|
|
354
|
+
}
|
|
355
|
+
text += `\t\t\tresp, err := runtime.FetcherForNextLink(ctx, client.internal.Pipeline(), ${nextLinkVar}, func(ctx context.Context) (*policy.Request, error) {\n`;
|
|
356
|
+
text += `\t\t\t\treturn client.${method.naming.requestMethod}(${reqParams})\n\t\t\t}, `;
|
|
357
|
+
// nextPageMethod might be absent in some cases, see https://github.com/Azure/autorest/issues/4393
|
|
358
|
+
if (method.nextPageMethod) {
|
|
359
|
+
const nextOpParams = helpers.getCreateRequestParametersSig(method.nextPageMethod).split(',');
|
|
360
|
+
// keep the parameter names from the name/type tuples and find nextLink param
|
|
361
|
+
for (let i = 0; i < nextOpParams.length; ++i) {
|
|
362
|
+
const paramName = nextOpParams[i].trim().split(' ')[0];
|
|
363
|
+
const paramType = nextOpParams[i].trim().split(' ')[1];
|
|
364
|
+
if (paramName.startsWith('next') && paramType === 'string') {
|
|
365
|
+
nextOpParams[i] = 'encodedNextLink';
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
nextOpParams[i] = paramName;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// add a definition for the nextReq func that uses the nextLinkOperation
|
|
372
|
+
text += '&runtime.FetcherForNextLinkOptions{\n\t\t\t\tNextReq: func(ctx context.Context, encodedNextLink string) (*policy.Request, error) {\n';
|
|
373
|
+
text += `\t\t\t\t\treturn client.${method.nextPageMethod.name}(${nextOpParams.join(', ')})\n\t\t\t\t},\n\t\t\t})\n`;
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
text += 'nil)\n';
|
|
377
|
+
}
|
|
378
|
+
text += `\t\t\tif err != nil {\n\t\t\t\treturn ${method.responseEnvelope.name}{}, err\n\t\t\t}\n`;
|
|
379
|
+
text += `\t\t\treturn client.${method.naming.responseMethod}(resp)\n`;
|
|
380
|
+
text += '\t\t\t},\n';
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
// this is the singular page case, no fetcher helper required
|
|
384
|
+
text += `\t\t\treq, err := client.${method.naming.requestMethod}(${reqParams})\n`;
|
|
385
|
+
text += '\t\t\tif err != nil {\n';
|
|
386
|
+
text += `\t\t\t\treturn ${method.responseEnvelope.name}{}, err\n`;
|
|
387
|
+
text += '\t\t\t}\n';
|
|
388
|
+
text += '\t\t\tresp, err := client.internal.Pipeline().Do(req)\n';
|
|
389
|
+
text += '\t\t\tif err != nil {\n';
|
|
390
|
+
text += `\t\t\t\treturn ${method.responseEnvelope.name}{}, err\n`;
|
|
391
|
+
text += '\t\t\t}\n';
|
|
392
|
+
text += '\t\t\tif !runtime.HasStatusCode(resp, http.StatusOK) {\n';
|
|
393
|
+
text += `\t\t\t\treturn ${method.responseEnvelope.name}{}, runtime.NewResponseError(resp)\n`;
|
|
394
|
+
text += '\t\t\t}\n';
|
|
395
|
+
text += `\t\t\treturn client.${method.naming.responseMethod}(resp)\n`;
|
|
396
|
+
text += '\t\t},\n';
|
|
397
|
+
}
|
|
398
|
+
if (injectSpans) {
|
|
399
|
+
text += '\t\tTracer: client.internal.Tracer(),\n';
|
|
400
|
+
}
|
|
401
|
+
text += '\t})\n';
|
|
402
|
+
return text;
|
|
403
|
+
}
|
|
404
|
+
function genApiVersionDoc(apiVersions) {
|
|
405
|
+
if (apiVersions.length === 0) {
|
|
406
|
+
return '';
|
|
407
|
+
}
|
|
408
|
+
return `//\n// Generated from API version ${apiVersions.join(', ')}\n`;
|
|
409
|
+
}
|
|
410
|
+
function genRespErrorDoc(method) {
|
|
411
|
+
if (!(method.responseEnvelope.result && go.isHeadAsBooleanResult(method.responseEnvelope.result)) && !go.isPageableMethod(method)) {
|
|
412
|
+
// when head-as-boolean is enabled, no error is returned for 4xx status codes.
|
|
413
|
+
// pager constructors don't return an error
|
|
414
|
+
return '// If the operation fails it returns an *azcore.ResponseError type.\n';
|
|
415
|
+
}
|
|
416
|
+
return '';
|
|
417
|
+
}
|
|
418
|
+
function generateOperation(client, method, imports, injectSpans, generateFakes) {
|
|
419
|
+
const params = getAPIParametersSig(method, imports);
|
|
420
|
+
const returns = generateReturnsInfo(method, 'op');
|
|
421
|
+
let methodName = method.name;
|
|
422
|
+
if (go.isPageableMethod(method) && !go.isLROMethod(method)) {
|
|
423
|
+
methodName = fixUpMethodName(method);
|
|
424
|
+
}
|
|
425
|
+
let text = '';
|
|
426
|
+
const respErrDoc = genRespErrorDoc(method);
|
|
427
|
+
const apiVerDoc = genApiVersionDoc(method.apiVersions);
|
|
428
|
+
if (method.description) {
|
|
429
|
+
text += `${comment(`${methodName} - ${method.description}`, '//', undefined, helpers.commentLength)}\n`;
|
|
430
|
+
}
|
|
431
|
+
else if (respErrDoc.length > 0 || apiVerDoc.length > 0) {
|
|
432
|
+
// if the method has no doc comment but we're adding other
|
|
433
|
+
// doc comments, add an empty method name comment. this preserves
|
|
434
|
+
// existing behavior and makes the docs look better overall.
|
|
435
|
+
text += `// ${methodName} -\n`;
|
|
436
|
+
}
|
|
437
|
+
text += respErrDoc;
|
|
438
|
+
text += apiVerDoc;
|
|
439
|
+
if (go.isLROMethod(method)) {
|
|
440
|
+
methodName = method.naming.internalMethod;
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
for (const param of values(helpers.getMethodParameters(method))) {
|
|
444
|
+
if (param.description) {
|
|
445
|
+
text += `${helpers.formatCommentAsBulletItem(`${param.name} - ${param.description}`)}\n`;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
text += `func (client *${client.name}) ${methodName}(${params}) (${returns.join(', ')}) {\n`;
|
|
450
|
+
const reqParams = helpers.getCreateRequestParameters(method);
|
|
451
|
+
if (go.isPageableMethod(method) && !go.isLROMethod(method)) {
|
|
452
|
+
text += '\treturn ';
|
|
453
|
+
text += emitPagerDefinition(client, method, imports, injectSpans, generateFakes);
|
|
454
|
+
text += '}\n\n';
|
|
455
|
+
return text;
|
|
456
|
+
}
|
|
457
|
+
text += '\tvar err error\n';
|
|
458
|
+
let operationName = `"${client.name}.${fixUpMethodName(method)}"`;
|
|
459
|
+
if (generateFakes && injectSpans) {
|
|
460
|
+
text += `\tconst operationName = ${operationName}\n`;
|
|
461
|
+
operationName = 'operationName';
|
|
462
|
+
}
|
|
463
|
+
if (generateFakes) {
|
|
464
|
+
text += `\tctx = context.WithValue(ctx, runtime.CtxAPINameKey{}, ${operationName})\n`;
|
|
465
|
+
}
|
|
466
|
+
if (injectSpans) {
|
|
467
|
+
text += `\tctx, endSpan := runtime.StartSpan(ctx, ${operationName}, client.internal.Tracer(), nil)\n`;
|
|
468
|
+
text += '\tdefer func() { endSpan(err) }()\n';
|
|
469
|
+
}
|
|
470
|
+
const zeroResp = getZeroReturnValue(method, 'op');
|
|
471
|
+
text += `\treq, err := client.${method.naming.requestMethod}(${reqParams})\n`;
|
|
472
|
+
text += '\tif err != nil {\n';
|
|
473
|
+
text += `\t\treturn ${zeroResp}, err\n`;
|
|
474
|
+
text += '\t}\n';
|
|
475
|
+
text += '\thttpResp, err := client.internal.Pipeline().Do(req)\n';
|
|
476
|
+
text += '\tif err != nil {\n';
|
|
477
|
+
text += `\t\treturn ${zeroResp}, err\n`;
|
|
478
|
+
text += '\t}\n';
|
|
479
|
+
text += `\tif !runtime.HasStatusCode(httpResp, ${helpers.formatStatusCodes(method.httpStatusCodes)}) {\n`;
|
|
480
|
+
text += '\t\terr = runtime.NewResponseError(httpResp)\n';
|
|
481
|
+
text += `\t\treturn ${zeroResp}, err\n`;
|
|
482
|
+
text += '\t}\n';
|
|
483
|
+
// HAB with headers response is handled in protocol responder
|
|
484
|
+
if (method.responseEnvelope.result && go.isHeadAsBooleanResult(method.responseEnvelope.result) && method.responseEnvelope.headers.length === 0) {
|
|
485
|
+
text += `\treturn ${method.responseEnvelope.name}{${method.responseEnvelope.result.fieldName}: httpResp.StatusCode >= 200 && httpResp.StatusCode < 300}, nil\n`;
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
if (go.isLROMethod(method)) {
|
|
489
|
+
text += '\treturn httpResp, nil\n';
|
|
490
|
+
}
|
|
491
|
+
else if (needsResponseHandler(method)) {
|
|
492
|
+
// also cheating here as at present the only param to the responder is an http.Response
|
|
493
|
+
text += `\tresp, err := client.${method.naming.responseMethod}(httpResp)\n`;
|
|
494
|
+
text += '\treturn resp, err\n';
|
|
495
|
+
}
|
|
496
|
+
else if (method.responseEnvelope.result && go.isBinaryResult(method.responseEnvelope.result)) {
|
|
497
|
+
text += `\treturn ${method.responseEnvelope.name}{${method.responseEnvelope.result.fieldName}: httpResp.Body}, nil\n`;
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
text += `\treturn ${method.responseEnvelope.name}{}, nil\n`;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
text += '}\n\n';
|
|
504
|
+
return text;
|
|
505
|
+
}
|
|
506
|
+
function createProtocolRequest(azureARM, client, method, imports) {
|
|
507
|
+
var _a, _b;
|
|
508
|
+
let name = method.name;
|
|
509
|
+
if (go.isMethod(method)) {
|
|
510
|
+
name = method.naming.requestMethod;
|
|
511
|
+
}
|
|
512
|
+
for (const param of values(method.parameters)) {
|
|
513
|
+
if (param.location !== 'method' || !go.isRequiredParameter(param)) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
imports.addImportForType(param.type);
|
|
517
|
+
}
|
|
518
|
+
const returns = ['*policy.Request', 'error'];
|
|
519
|
+
let text = `${comment(name, '// ')} creates the ${method.name} request.\n`;
|
|
520
|
+
text += `func (client *${client.name}) ${name}(${helpers.getCreateRequestParametersSig(method)}) (${returns.join(', ')}) {\n`;
|
|
521
|
+
const hostParams = new Array();
|
|
522
|
+
for (const parameter of client.parameters) {
|
|
523
|
+
if (go.isURIParameter(parameter)) {
|
|
524
|
+
hostParams.push(parameter);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
let hostParam;
|
|
528
|
+
if (azureARM) {
|
|
529
|
+
hostParam = 'client.internal.Endpoint()';
|
|
530
|
+
}
|
|
531
|
+
else if (client.templatedHost) {
|
|
532
|
+
imports.add('strings');
|
|
533
|
+
// we have a templated host
|
|
534
|
+
text += `\thost := "${client.host}"\n`;
|
|
535
|
+
// get all the host params on the client
|
|
536
|
+
for (const hostParam of hostParams) {
|
|
537
|
+
text += `\thost = strings.ReplaceAll(host, "{${hostParam.uriPathSegment}}", ${helpers.formatValue(`client.${hostParam.name}`, hostParam.type, imports)})\n`;
|
|
538
|
+
}
|
|
539
|
+
// check for any method local host params
|
|
540
|
+
for (const param of values(method.parameters)) {
|
|
541
|
+
if (param.location === 'method' && go.isURIParameter(param)) {
|
|
542
|
+
text += `\thost = strings.ReplaceAll(host, "{${param.uriPathSegment}}", ${helpers.formatValue(helpers.getParamName(param), param.type, imports)})\n`;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
hostParam = 'host';
|
|
546
|
+
}
|
|
547
|
+
else if (hostParams.length === 1) {
|
|
548
|
+
// simple parameterized host case
|
|
549
|
+
hostParam = 'client.' + hostParams[0].name;
|
|
550
|
+
}
|
|
551
|
+
else if (client.host) {
|
|
552
|
+
// swagger defines a host, use its const
|
|
553
|
+
hostParam = '\thost';
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
throw new Error(`no host or endpoint defined for method ${client.name}.${method.name}`);
|
|
557
|
+
}
|
|
558
|
+
const hasPathParams = values(method.parameters).where((each) => { return go.isPathParameter(each); }).any();
|
|
559
|
+
// storage needs the client.u to be the source-of-truth for the full path.
|
|
560
|
+
// however, swagger requires that all operations specify a path, which is at odds with storage.
|
|
561
|
+
// to work around this, storage specifies x-ms-path paths with path params but doesn't
|
|
562
|
+
// actually reference the path params (i.e. no params with which to replace the tokens).
|
|
563
|
+
// so, if a path contains tokens but there are no path params, skip emitting the path.
|
|
564
|
+
const pathStr = method.httpPath;
|
|
565
|
+
const pathContainsParms = pathStr.includes('{');
|
|
566
|
+
if (hasPathParams || (!pathContainsParms && pathStr.length > 1)) {
|
|
567
|
+
// there are path params, or the path doesn't contain tokens and is not "/" so emit it
|
|
568
|
+
text += `\turlPath := "${method.httpPath}"\n`;
|
|
569
|
+
hostParam = `runtime.JoinPaths(${hostParam}, urlPath)`;
|
|
570
|
+
}
|
|
571
|
+
if (hasPathParams) {
|
|
572
|
+
// swagger defines path params, emit path and replace tokens
|
|
573
|
+
imports.add('strings');
|
|
574
|
+
// replace path parameters
|
|
575
|
+
for (const pp of values(method.parameters)) {
|
|
576
|
+
if (!go.isPathParameter(pp)) {
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
// emit check to ensure path param isn't an empty string. we only need
|
|
580
|
+
// to do this for params that have an underlying type of string.
|
|
581
|
+
const choiceIsString = function (type) {
|
|
582
|
+
if (!go.isConstantType(type)) {
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
return type.type === 'string';
|
|
586
|
+
};
|
|
587
|
+
if (((go.isPrimitiveType(pp.type) && pp.type.typeName === 'string') || choiceIsString(pp.type)) && pp.isEncoded) {
|
|
588
|
+
const paramName = helpers.getParamName(pp);
|
|
589
|
+
imports.add('errors');
|
|
590
|
+
text += `\tif ${paramName} == "" {\n`;
|
|
591
|
+
text += `\t\treturn nil, errors.New("parameter ${paramName} cannot be empty")\n`;
|
|
592
|
+
text += '\t}\n';
|
|
593
|
+
}
|
|
594
|
+
let paramValue = helpers.formatParamValue(pp, imports);
|
|
595
|
+
if (pp.isEncoded) {
|
|
596
|
+
imports.add('net/url');
|
|
597
|
+
paramValue = `url.PathEscape(${helpers.formatParamValue(pp, imports)})`;
|
|
598
|
+
}
|
|
599
|
+
text += `\turlPath = strings.ReplaceAll(urlPath, "{${pp.pathSegment}}", ${paramValue})\n`;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
text += `\treq, err := runtime.NewRequest(ctx, http.Method${capitalize(method.httpMethod)}, ${hostParam})\n`;
|
|
603
|
+
text += '\tif err != nil {\n';
|
|
604
|
+
text += '\t\treturn nil, err\n';
|
|
605
|
+
text += '\t}\n';
|
|
606
|
+
// helper to build nil checks for param groups
|
|
607
|
+
const emitParamGroupCheck = function (param) {
|
|
608
|
+
if (!param.group) {
|
|
609
|
+
throw new Error(`emitParamGroupCheck called for ungrouped parameter ${param.name}`);
|
|
610
|
+
}
|
|
611
|
+
let client = '';
|
|
612
|
+
if (param.location === 'client') {
|
|
613
|
+
client = 'client.';
|
|
614
|
+
}
|
|
615
|
+
const paramGroupName = uncapitalize(param.group.name);
|
|
616
|
+
let optionalParamGroupCheck = `${client}${paramGroupName} != nil && `;
|
|
617
|
+
if (param.group.required) {
|
|
618
|
+
optionalParamGroupCheck = '';
|
|
619
|
+
}
|
|
620
|
+
return `\tif ${optionalParamGroupCheck}${client}${paramGroupName}.${capitalize(param.name)} != nil {\n`;
|
|
621
|
+
};
|
|
622
|
+
// add query parameters
|
|
623
|
+
const encodedParams = new Array();
|
|
624
|
+
const unencodedParams = new Array();
|
|
625
|
+
for (const qp of values(method.parameters)) {
|
|
626
|
+
if (!go.isQueryParameter(qp)) {
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
if (qp.isEncoded) {
|
|
630
|
+
encodedParams.push(qp);
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
unencodedParams.push(qp);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
const emitQueryParam = function (qp, setter) {
|
|
637
|
+
let qpText = '';
|
|
638
|
+
if (qp.location === 'method' && go.isClientSideDefault(qp.kind)) {
|
|
639
|
+
qpText = emitClientSideDefault(qp, qp.kind, (name, val) => { return `\treqQP.Set(${name}, ${val})`; }, imports);
|
|
640
|
+
}
|
|
641
|
+
else if (go.isRequiredParameter(qp) || go.isLiteralParameter(qp) || (qp.location === 'client' && go.isClientSideDefault(qp.kind))) {
|
|
642
|
+
qpText = `\t${setter}\n`;
|
|
643
|
+
}
|
|
644
|
+
else if (qp.location === 'client' && !qp.group) {
|
|
645
|
+
// global optional param
|
|
646
|
+
qpText = `\tif client.${qp.name} != nil {\n`;
|
|
647
|
+
qpText += `\t\t${setter}\n`;
|
|
648
|
+
qpText += '\t}\n';
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
qpText = emitParamGroupCheck(qp);
|
|
652
|
+
qpText += `\t\t${setter}\n`;
|
|
653
|
+
qpText += '\t}\n';
|
|
654
|
+
}
|
|
655
|
+
return qpText;
|
|
656
|
+
};
|
|
657
|
+
// emit encoded params first
|
|
658
|
+
if (encodedParams.length > 0) {
|
|
659
|
+
text += '\treqQP := req.Raw().URL.Query()\n';
|
|
660
|
+
for (const qp of values(encodedParams.sort((a, b) => { return helpers.sortAscending(a.queryParameter, b.queryParameter); }))) {
|
|
661
|
+
let setter;
|
|
662
|
+
if (go.isQueryCollectionParameter(qp) && qp.collectionFormat === 'multi') {
|
|
663
|
+
setter = `\tfor _, qv := range ${helpers.getParamName(qp)} {\n`;
|
|
664
|
+
// emit a type conversion for the qv based on the array's element type
|
|
665
|
+
let queryVal;
|
|
666
|
+
const arrayQP = qp.type;
|
|
667
|
+
if (go.isConstantType(arrayQP.elementType)) {
|
|
668
|
+
const ch = arrayQP.elementType;
|
|
669
|
+
// only string and number types are supported for enums
|
|
670
|
+
if (ch.type === 'string') {
|
|
671
|
+
queryVal = 'string(qv)';
|
|
672
|
+
}
|
|
673
|
+
else {
|
|
674
|
+
imports.add('fmt');
|
|
675
|
+
queryVal = 'fmt.Sprintf("%d", qv)';
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
else if (go.isPrimitiveType(arrayQP.elementType) && arrayQP.elementType.typeName === 'string') {
|
|
679
|
+
queryVal = 'qv';
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
imports.add('fmt');
|
|
683
|
+
queryVal = 'fmt.Sprintf("%v", qv)';
|
|
684
|
+
}
|
|
685
|
+
setter += `\t\treqQP.Add("${qp.queryParameter}", ${queryVal})\n`;
|
|
686
|
+
setter += '\t}';
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
// cannot initialize setter to this value as helpers.formatParamValue() can change imports
|
|
690
|
+
setter = `reqQP.Set("${qp.queryParameter}", ${helpers.formatParamValue(qp, imports)})`;
|
|
691
|
+
}
|
|
692
|
+
text += emitQueryParam(qp, setter);
|
|
693
|
+
}
|
|
694
|
+
text += '\treq.Raw().URL.RawQuery = reqQP.Encode()\n';
|
|
695
|
+
}
|
|
696
|
+
// tack on any unencoded params to the end
|
|
697
|
+
if (unencodedParams.length > 0) {
|
|
698
|
+
if (encodedParams.length > 0) {
|
|
699
|
+
text += '\tunencodedParams := []string{req.Raw().URL.RawQuery}\n';
|
|
700
|
+
}
|
|
701
|
+
else {
|
|
702
|
+
text += '\tunencodedParams := []string{}\n';
|
|
703
|
+
}
|
|
704
|
+
for (const qp of values(unencodedParams.sort((a, b) => { return helpers.sortAscending(a.queryParameter, b.queryParameter); }))) {
|
|
705
|
+
let setter;
|
|
706
|
+
if (go.isQueryCollectionParameter(qp) && qp.collectionFormat === 'multi') {
|
|
707
|
+
setter = `\tfor _, qv := range ${helpers.getParamName(qp)} {\n`;
|
|
708
|
+
setter += `\t\tunencodedParams = append(unencodedParams, "${qp.queryParameter}="+qv)\n`;
|
|
709
|
+
setter += '\t}';
|
|
710
|
+
}
|
|
711
|
+
else {
|
|
712
|
+
setter = `unencodedParams = append(unencodedParams, "${qp.queryParameter}="+${helpers.formatParamValue(qp, imports)})`;
|
|
713
|
+
}
|
|
714
|
+
text += emitQueryParam(qp, setter);
|
|
715
|
+
}
|
|
716
|
+
imports.add('strings');
|
|
717
|
+
text += '\treq.Raw().URL.RawQuery = strings.Join(unencodedParams, "&")\n';
|
|
718
|
+
}
|
|
719
|
+
if (go.isMethod(method) && method.responseEnvelope.result && go.isBinaryResult(method.responseEnvelope.result)) {
|
|
720
|
+
// skip auto-body downloading for binary stream responses
|
|
721
|
+
text += '\truntime.SkipBodyDownload(req)\n';
|
|
722
|
+
}
|
|
723
|
+
// add specific request headers
|
|
724
|
+
const emitHeaderSet = function (headerParam, prefix) {
|
|
725
|
+
if (headerParam.location === 'method' && go.isClientSideDefault(headerParam.kind)) {
|
|
726
|
+
return emitClientSideDefault(headerParam, headerParam.kind, (name, val) => {
|
|
727
|
+
return `${prefix}req.Raw().Header[${name}] = []string{${val}}`;
|
|
728
|
+
}, imports);
|
|
729
|
+
}
|
|
730
|
+
else if (go.isHeaderMapParameter(headerParam)) {
|
|
731
|
+
let headerText = `${prefix}for k, v := range ${helpers.getParamName(headerParam)} {\n`;
|
|
732
|
+
headerText += `${prefix}\tif v != nil {\n`;
|
|
733
|
+
headerText += `${prefix}\t\treq.Raw().Header["${headerParam.collectionPrefix}"+k] = []string{*v}\n`;
|
|
734
|
+
headerText += `${prefix}}\n`;
|
|
735
|
+
headerText += `${prefix}}\n`;
|
|
736
|
+
return headerText;
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
return `${prefix}req.Raw().Header["${headerParam.headerName}"] = []string{${helpers.formatParamValue(headerParam, imports)}}\n`;
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
const headerParams = new Array();
|
|
743
|
+
for (const param of values(method.parameters)) {
|
|
744
|
+
if (go.isHeaderParameter(param)) {
|
|
745
|
+
headerParams.push(param);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
for (const param of headerParams.sort((a, b) => { return helpers.sortAscending(a.headerName, b.headerName); })) {
|
|
749
|
+
if (param.headerName.match(/^content-type$/)) {
|
|
750
|
+
// canonicalize content-type as req.SetBody checks for it via its canonicalized name :(
|
|
751
|
+
param.headerName = 'Content-Type';
|
|
752
|
+
}
|
|
753
|
+
if (go.isRequiredParameter(param) || go.isLiteralParameter(param) || go.isClientSideDefault(param.kind)) {
|
|
754
|
+
text += emitHeaderSet(param, '\t');
|
|
755
|
+
}
|
|
756
|
+
else if (param.location === 'client' && !param.group) {
|
|
757
|
+
// global optional param
|
|
758
|
+
text += `\tif client.${param.name} != nil {\n`;
|
|
759
|
+
text += emitHeaderSet(param, '\t');
|
|
760
|
+
text += '\t}\n';
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
text += emitParamGroupCheck(param);
|
|
764
|
+
text += emitHeaderSet(param, '\t\t');
|
|
765
|
+
text += '\t}\n';
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
const partialBodyParams = values(method.parameters).where((param) => { return go.isPartialBodyParameter(param); }).toArray();
|
|
769
|
+
const bodyParam = values(method.parameters).where((each) => { return go.isBodyParameter(each) || go.isFormBodyParameter(each) || go.isMultipartFormBodyParameter(each); }).first();
|
|
770
|
+
const emitSetBodyWithErrCheck = function (setBodyParam) {
|
|
771
|
+
return `if err := ${setBodyParam}; err != nil {\n\treturn nil, err\n}\n`;
|
|
772
|
+
};
|
|
773
|
+
if (partialBodyParams.length > 0) {
|
|
774
|
+
// partial body params are discrete params that are all fields within an internal struct.
|
|
775
|
+
// define and instantiate an instance of the wire type, using the values from each param.
|
|
776
|
+
text += '\tbody := struct {\n';
|
|
777
|
+
for (const partialBodyParam of partialBodyParams) {
|
|
778
|
+
text += `\t\t${capitalize(partialBodyParam.serializedName)} ${helpers.star(partialBodyParam)}${go.getTypeDeclaration(partialBodyParam.type)} \`${partialBodyParam.format.toLowerCase()}:"${partialBodyParam.serializedName}"\`\n`;
|
|
779
|
+
}
|
|
780
|
+
text += '\t}{\n';
|
|
781
|
+
for (const partialBodyParam of partialBodyParams) {
|
|
782
|
+
let addr = '&';
|
|
783
|
+
if (go.isRequiredParameter(partialBodyParam)) {
|
|
784
|
+
addr = '';
|
|
785
|
+
}
|
|
786
|
+
text += `\t\t${capitalize(partialBodyParam.serializedName)}: ${addr}${uncapitalize(partialBodyParam.name)},\n`;
|
|
787
|
+
}
|
|
788
|
+
text += '\t}\n\tif err := runtime.MarshalAsJSON(req, body); err != nil {\n\t\treturn nil, err\n\t}\n';
|
|
789
|
+
text += '\treturn req, nil\n';
|
|
790
|
+
}
|
|
791
|
+
else if (!bodyParam) {
|
|
792
|
+
text += '\treturn req, nil\n';
|
|
793
|
+
}
|
|
794
|
+
else if (bodyParam.bodyFormat === 'JSON' || bodyParam.bodyFormat === 'XML') {
|
|
795
|
+
// default to the body param name
|
|
796
|
+
let body = helpers.getParamName(bodyParam);
|
|
797
|
+
if (go.isLiteralValue(bodyParam.type)) {
|
|
798
|
+
// if the value is constant, embed it directly
|
|
799
|
+
body = helpers.formatLiteralValue(bodyParam.type, true);
|
|
800
|
+
}
|
|
801
|
+
else if (bodyParam.bodyFormat === 'XML' && go.isSliceType(bodyParam.type)) {
|
|
802
|
+
// for XML payloads, create a wrapper type if the payload is an array
|
|
803
|
+
imports.add('encoding/xml');
|
|
804
|
+
text += '\ttype wrapper struct {\n';
|
|
805
|
+
let tagName = go.getTypeDeclaration(bodyParam.type);
|
|
806
|
+
if ((_a = bodyParam.xml) === null || _a === void 0 ? void 0 : _a.name) {
|
|
807
|
+
tagName = bodyParam.xml.name;
|
|
808
|
+
}
|
|
809
|
+
text += `\t\tXMLName xml.Name \`xml:"${tagName}"\`\n`;
|
|
810
|
+
const fieldName = capitalize(bodyParam.name);
|
|
811
|
+
let tag = go.getTypeDeclaration(bodyParam.type.elementType);
|
|
812
|
+
if (go.isModelType(bodyParam.type.elementType) && ((_b = bodyParam.type.elementType.xml) === null || _b === void 0 ? void 0 : _b.name)) {
|
|
813
|
+
tag = bodyParam.type.elementType.xml.name;
|
|
814
|
+
}
|
|
815
|
+
text += `\t\t${fieldName} *${go.getTypeDeclaration(bodyParam.type)} \`xml:"${tag}"\`\n`;
|
|
816
|
+
text += '\t}\n';
|
|
817
|
+
let addr = '&';
|
|
818
|
+
if (!go.isRequiredParameter(bodyParam) && !bodyParam.byValue) {
|
|
819
|
+
addr = '';
|
|
820
|
+
}
|
|
821
|
+
body = `wrapper{${fieldName}: ${addr}${body}}`;
|
|
822
|
+
}
|
|
823
|
+
else if (go.isTimeType(bodyParam.type) && bodyParam.type.dateTimeFormat !== 'dateTimeRFC3339') {
|
|
824
|
+
// wrap the body in the internal time type
|
|
825
|
+
// no need for dateTimeRFC3339 as the JSON marshaler defaults to that.
|
|
826
|
+
body = `${bodyParam.type.dateTimeFormat}(${body})`;
|
|
827
|
+
}
|
|
828
|
+
else if (isArrayOfDateTimeForMarshalling(bodyParam.type)) {
|
|
829
|
+
const timeInfo = isArrayOfDateTimeForMarshalling(bodyParam.type);
|
|
830
|
+
let elementPtr = '*';
|
|
831
|
+
if (timeInfo === null || timeInfo === void 0 ? void 0 : timeInfo.elemByVal) {
|
|
832
|
+
elementPtr = '';
|
|
833
|
+
}
|
|
834
|
+
text += `\taux := make([]${elementPtr}${timeInfo === null || timeInfo === void 0 ? void 0 : timeInfo.format}, len(${body}))\n`;
|
|
835
|
+
text += `\tfor i := 0; i < len(${body}); i++ {\n`;
|
|
836
|
+
text += `\t\taux[i] = (${elementPtr}${timeInfo === null || timeInfo === void 0 ? void 0 : timeInfo.format})(${body}[i])\n`;
|
|
837
|
+
text += '\t}\n';
|
|
838
|
+
body = 'aux';
|
|
839
|
+
}
|
|
840
|
+
else if (isMapOfDateTime(bodyParam.type)) {
|
|
841
|
+
const timeType = isMapOfDateTime(bodyParam.type);
|
|
842
|
+
text += `\taux := map[string]*${timeType}{}\n`;
|
|
843
|
+
text += `\tfor k, v := range ${body} {\n`;
|
|
844
|
+
text += `\t\taux[k] = (*${timeType})(v)\n`;
|
|
845
|
+
text += '\t}\n';
|
|
846
|
+
body = 'aux';
|
|
847
|
+
}
|
|
848
|
+
let setBody = `runtime.MarshalAs${getMediaFormat(bodyParam.type, bodyParam.bodyFormat, `req, ${body}`)}`;
|
|
849
|
+
if (go.isSliceType(bodyParam.type) && bodyParam.type.rawJSONAsBytes) {
|
|
850
|
+
imports.add('bytes');
|
|
851
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming');
|
|
852
|
+
setBody = `req.SetBody(streaming.NopCloser(bytes.NewReader(${body})), "application/${bodyParam.bodyFormat.toLowerCase()}")`;
|
|
853
|
+
}
|
|
854
|
+
if (go.isRequiredParameter(bodyParam) || go.isLiteralParameter(bodyParam)) {
|
|
855
|
+
text += `\t${emitSetBodyWithErrCheck(setBody)}`;
|
|
856
|
+
text += '\treturn req, nil\n';
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
text += emitParamGroupCheck(bodyParam);
|
|
860
|
+
text += `\t${emitSetBodyWithErrCheck(setBody)}`;
|
|
861
|
+
text += '\t\treturn req, nil\n';
|
|
862
|
+
text += '\t}\n';
|
|
863
|
+
text += '\treturn req, nil\n';
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
else if (bodyParam.bodyFormat === 'binary') {
|
|
867
|
+
if (go.isRequiredParameter(bodyParam)) {
|
|
868
|
+
text += `\t${emitSetBodyWithErrCheck(`req.SetBody(${bodyParam.name}, ${bodyParam.contentType})`)}`;
|
|
869
|
+
text += '\treturn req, nil\n';
|
|
870
|
+
}
|
|
871
|
+
else {
|
|
872
|
+
text += emitParamGroupCheck(bodyParam);
|
|
873
|
+
text += `\t${emitSetBodyWithErrCheck(`req.SetBody(${helpers.getParamName(bodyParam)}, ${bodyParam.contentType})`)}`;
|
|
874
|
+
text += '\treturn req, nil\n';
|
|
875
|
+
text += '\t}\n';
|
|
876
|
+
text += '\treturn req, nil\n';
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
else if (bodyParam.bodyFormat === 'Text') {
|
|
880
|
+
imports.add('strings');
|
|
881
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming');
|
|
882
|
+
const bodyParam = values(method.parameters).where((each) => { return go.isBodyParameter(each); }).first();
|
|
883
|
+
if (go.isRequiredParameter(bodyParam)) {
|
|
884
|
+
text += `\tbody := streaming.NopCloser(strings.NewReader(${bodyParam.name}))\n`;
|
|
885
|
+
text += `\t${emitSetBodyWithErrCheck(`req.SetBody(body, ${bodyParam.contentType})`)}`;
|
|
886
|
+
text += '\treturn req, nil\n';
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
text += emitParamGroupCheck(bodyParam);
|
|
890
|
+
text += `\tbody := streaming.NopCloser(strings.NewReader(${helpers.getParamName(bodyParam)}))\n`;
|
|
891
|
+
text += `\t${emitSetBodyWithErrCheck(`req.SetBody(body, ${bodyParam.contentType})`)}`;
|
|
892
|
+
text += '\treturn req, nil\n';
|
|
893
|
+
text += '\t}\n';
|
|
894
|
+
text += '\treturn req, nil\n';
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
else if (go.isMultipartFormBodyParameter(bodyParam)) {
|
|
898
|
+
if (go.isModelType(bodyParam.type) && bodyParam.type.annotations.multipartFormData) {
|
|
899
|
+
text += `\tformData, err := ${bodyParam.name}.toMultipartFormData()\n`;
|
|
900
|
+
text += '\tif err != nil {\n\t\treturn nil, err\n\t}\n';
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
text += '\tformData := map[string]any{}\n';
|
|
904
|
+
for (const param of values(method.parameters)) {
|
|
905
|
+
if (!go.isMultipartFormBodyParameter(param)) {
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
const setter = `formData["${param.name}"] = ${helpers.getParamName(param)}`;
|
|
909
|
+
if (go.isRequiredParameter(param)) {
|
|
910
|
+
text += `\t${setter}\n`;
|
|
911
|
+
}
|
|
912
|
+
else {
|
|
913
|
+
text += emitParamGroupCheck(param);
|
|
914
|
+
text += `\t${setter}\n\t}\n`;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
text += '\tif err := runtime.SetMultipartFormData(req, formData); err != nil {\n\t\treturn nil, err\n\t}\n';
|
|
919
|
+
text += '\treturn req, nil\n';
|
|
920
|
+
}
|
|
921
|
+
else if (go.isFormBodyParameter(bodyParam)) {
|
|
922
|
+
const emitFormData = function (param, setter) {
|
|
923
|
+
let formDataText = '';
|
|
924
|
+
if (go.isRequiredParameter(param)) {
|
|
925
|
+
formDataText = `\t${setter}\n`;
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
formDataText = emitParamGroupCheck(param);
|
|
929
|
+
formDataText += `\t\t${setter}\n`;
|
|
930
|
+
formDataText += '\t}\n';
|
|
931
|
+
}
|
|
932
|
+
return formDataText;
|
|
933
|
+
};
|
|
934
|
+
imports.add('net/url');
|
|
935
|
+
imports.add('strings');
|
|
936
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming');
|
|
937
|
+
text += '\tformData := url.Values{}\n';
|
|
938
|
+
// find all the form body params
|
|
939
|
+
for (const param of values(method.parameters)) {
|
|
940
|
+
if (go.isFormBodyParameter(param)) {
|
|
941
|
+
const setter = `formData.Set("${param.formDataName}", ${helpers.formatParamValue(param, imports)})`;
|
|
942
|
+
text += emitFormData(param, setter);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
text += '\tbody := streaming.NopCloser(strings.NewReader(formData.Encode()))\n';
|
|
946
|
+
text += `\t${emitSetBodyWithErrCheck('req.SetBody(body, "application/x-www-form-urlencoded")')}`;
|
|
947
|
+
text += '\treturn req, nil\n';
|
|
948
|
+
}
|
|
949
|
+
else {
|
|
950
|
+
text += '\treturn req, nil\n';
|
|
951
|
+
}
|
|
952
|
+
text += '}\n\n';
|
|
953
|
+
return text;
|
|
954
|
+
}
|
|
955
|
+
function emitClientSideDefault(param, csd, setterFormat, imports) {
|
|
956
|
+
const defaultVar = uncapitalize(param.name) + 'Default';
|
|
957
|
+
let text = `\t${defaultVar} := ${helpers.formatLiteralValue(csd.defaultValue, true)}\n`;
|
|
958
|
+
text += `\tif options != nil && options.${capitalize(param.name)} != nil {\n`;
|
|
959
|
+
text += `\t\t${defaultVar} = *options.${capitalize(param.name)}\n`;
|
|
960
|
+
text += '}\n';
|
|
961
|
+
let serializedName;
|
|
962
|
+
if (go.isHeaderParameter(param)) {
|
|
963
|
+
serializedName = param.headerName;
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
serializedName = param.queryParameter;
|
|
967
|
+
}
|
|
968
|
+
text += setterFormat(`"${serializedName}"`, helpers.formatValue(defaultVar, param.type, imports)) + '\n';
|
|
969
|
+
return text;
|
|
970
|
+
}
|
|
971
|
+
function getMediaFormat(type, mediaType, param) {
|
|
972
|
+
let marshaller = mediaType;
|
|
973
|
+
let format = '';
|
|
974
|
+
if (go.isBytesType(type)) {
|
|
975
|
+
marshaller = 'ByteArray';
|
|
976
|
+
format = `, runtime.Base64${type.encoding}Format`;
|
|
977
|
+
}
|
|
978
|
+
return `${marshaller}(${param}${format})`;
|
|
979
|
+
}
|
|
980
|
+
function isArrayOfDateTimeForMarshalling(paramType) {
|
|
981
|
+
if (!go.isSliceType(paramType)) {
|
|
982
|
+
return undefined;
|
|
983
|
+
}
|
|
984
|
+
if (!go.isTimeType(paramType.elementType)) {
|
|
985
|
+
return undefined;
|
|
986
|
+
}
|
|
987
|
+
switch (paramType.elementType.dateTimeFormat) {
|
|
988
|
+
case 'dateType':
|
|
989
|
+
case 'dateTimeRFC1123':
|
|
990
|
+
case 'timeRFC3339':
|
|
991
|
+
case 'timeUnix':
|
|
992
|
+
return {
|
|
993
|
+
format: paramType.elementType.dateTimeFormat,
|
|
994
|
+
elemByVal: paramType.elementTypeByValue
|
|
995
|
+
};
|
|
996
|
+
default:
|
|
997
|
+
// dateTimeRFC3339 uses the default marshaller
|
|
998
|
+
return undefined;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
// returns true if the method requires a response handler.
|
|
1002
|
+
// this is used to unmarshal the response body, parse response headers, or both.
|
|
1003
|
+
function needsResponseHandler(method) {
|
|
1004
|
+
return helpers.hasSchemaResponse(method) || method.responseEnvelope.headers.length > 0;
|
|
1005
|
+
}
|
|
1006
|
+
function generateResponseUnmarshaller(method, type, format, unmarshalTarget) {
|
|
1007
|
+
let unmarshallerText = '';
|
|
1008
|
+
const zeroValue = getZeroReturnValue(method, 'handler');
|
|
1009
|
+
if (go.isTimeType(type)) {
|
|
1010
|
+
// use the designated time type for unmarshalling
|
|
1011
|
+
unmarshallerText += `\tvar aux *${type.dateTimeFormat}\n`;
|
|
1012
|
+
unmarshallerText += `\tif err := runtime.UnmarshalAs${format}(resp, &aux); err != nil {\n`;
|
|
1013
|
+
unmarshallerText += `\t\treturn ${zeroValue}, err\n`;
|
|
1014
|
+
unmarshallerText += '\t}\n';
|
|
1015
|
+
unmarshallerText += `\tresult.${helpers.getResultFieldName(method)} = (*time.Time)(aux)\n`;
|
|
1016
|
+
return unmarshallerText;
|
|
1017
|
+
}
|
|
1018
|
+
else if (isArrayOfDateTime(type)) {
|
|
1019
|
+
// unmarshalling arrays of date/time is a little more involved
|
|
1020
|
+
const timeInfo = isArrayOfDateTime(type);
|
|
1021
|
+
let elementPtr = '*';
|
|
1022
|
+
if (timeInfo === null || timeInfo === void 0 ? void 0 : timeInfo.elemByVal) {
|
|
1023
|
+
elementPtr = '';
|
|
1024
|
+
}
|
|
1025
|
+
unmarshallerText += `\tvar aux []${elementPtr}${timeInfo === null || timeInfo === void 0 ? void 0 : timeInfo.format}\n`;
|
|
1026
|
+
unmarshallerText += `\tif err := runtime.UnmarshalAs${format}(resp, &aux); err != nil {\n`;
|
|
1027
|
+
unmarshallerText += `\t\treturn ${zeroValue}, err\n`;
|
|
1028
|
+
unmarshallerText += '\t}\n';
|
|
1029
|
+
unmarshallerText += `\tcp := make([]${elementPtr}time.Time, len(aux))\n`;
|
|
1030
|
+
unmarshallerText += '\tfor i := 0; i < len(aux); i++ {\n';
|
|
1031
|
+
unmarshallerText += `\t\tcp[i] = (${elementPtr}time.Time)(aux[i])\n`;
|
|
1032
|
+
unmarshallerText += '\t}\n';
|
|
1033
|
+
unmarshallerText += `\tresult.${helpers.getResultFieldName(method)} = cp\n`;
|
|
1034
|
+
return unmarshallerText;
|
|
1035
|
+
}
|
|
1036
|
+
else if (isMapOfDateTime(type)) {
|
|
1037
|
+
unmarshallerText += `\taux := map[string]*${isMapOfDateTime(type)}{}\n`;
|
|
1038
|
+
unmarshallerText += `\tif err := runtime.UnmarshalAs${format}(resp, &aux); err != nil {\n`;
|
|
1039
|
+
unmarshallerText += `\t\treturn ${zeroValue}, err\n`;
|
|
1040
|
+
unmarshallerText += '\t}\n';
|
|
1041
|
+
unmarshallerText += '\tcp := map[string]*time.Time{}\n';
|
|
1042
|
+
unmarshallerText += '\tfor k, v := range aux {\n';
|
|
1043
|
+
unmarshallerText += '\t\tcp[k] = (*time.Time)(v)\n';
|
|
1044
|
+
unmarshallerText += '\t}\n';
|
|
1045
|
+
unmarshallerText += `\tresult.${helpers.getResultFieldName(method)} = cp\n`;
|
|
1046
|
+
return unmarshallerText;
|
|
1047
|
+
}
|
|
1048
|
+
if (format === 'JSON' || format === 'XML') {
|
|
1049
|
+
if (go.isSliceType(type) && type.rawJSONAsBytes) {
|
|
1050
|
+
unmarshallerText += '\tbody, err := runtime.Payload(resp)\n';
|
|
1051
|
+
unmarshallerText += '\tif err != nil {\n';
|
|
1052
|
+
unmarshallerText += `\t\treturn ${zeroValue}, err\n`;
|
|
1053
|
+
unmarshallerText += '\t}\n';
|
|
1054
|
+
unmarshallerText += `\t${unmarshalTarget} = body\n`;
|
|
1055
|
+
}
|
|
1056
|
+
else {
|
|
1057
|
+
unmarshallerText += `\tif err := runtime.UnmarshalAs${getMediaFormat(type, format, `resp, &${unmarshalTarget}`)}; err != nil {\n`;
|
|
1058
|
+
unmarshallerText += `\t\treturn ${zeroValue}, err\n`;
|
|
1059
|
+
unmarshallerText += '\t}\n';
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
else if (format === 'Text') {
|
|
1063
|
+
unmarshallerText += '\tbody, err := runtime.Payload(resp)\n';
|
|
1064
|
+
unmarshallerText += '\tif err != nil {\n';
|
|
1065
|
+
unmarshallerText += `\t\treturn ${zeroValue}, err\n`;
|
|
1066
|
+
unmarshallerText += '\t}\n';
|
|
1067
|
+
unmarshallerText += '\ttxt := string(body)\n';
|
|
1068
|
+
unmarshallerText += `\t${unmarshalTarget} = &txt\n`;
|
|
1069
|
+
}
|
|
1070
|
+
else {
|
|
1071
|
+
// the remaining formats should have been handled elsewhere
|
|
1072
|
+
throw new Error(`unhandled format ${format} for operation ${method.client.name}.${method.name}`);
|
|
1073
|
+
}
|
|
1074
|
+
return unmarshallerText;
|
|
1075
|
+
}
|
|
1076
|
+
function createProtocolResponse(client, method, imports) {
|
|
1077
|
+
if (!needsResponseHandler(method)) {
|
|
1078
|
+
return '';
|
|
1079
|
+
}
|
|
1080
|
+
const name = method.naming.responseMethod;
|
|
1081
|
+
let text = `${comment(name, '// ')} handles the ${method.name} response.\n`;
|
|
1082
|
+
text += `func (client *${client.name}) ${name}(resp *http.Response) (${generateReturnsInfo(method, 'handler').join(', ')}) {\n`;
|
|
1083
|
+
const addHeaders = function (headers) {
|
|
1084
|
+
for (const header of values(headers)) {
|
|
1085
|
+
text += formatHeaderResponseValue(header, imports, 'result', `${method.responseEnvelope.name}{}`);
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
const result = method.responseEnvelope.result;
|
|
1089
|
+
if (!result) {
|
|
1090
|
+
// only headers
|
|
1091
|
+
text += `\tresult := ${method.responseEnvelope.name}{}\n`;
|
|
1092
|
+
addHeaders(method.responseEnvelope.headers);
|
|
1093
|
+
}
|
|
1094
|
+
else if (go.isAnyResult(result)) {
|
|
1095
|
+
imports.add('fmt');
|
|
1096
|
+
text += `\tresult := ${method.responseEnvelope.name}{}\n`;
|
|
1097
|
+
addHeaders(method.responseEnvelope.headers);
|
|
1098
|
+
text += '\tswitch resp.StatusCode {\n';
|
|
1099
|
+
for (const statusCode of method.httpStatusCodes) {
|
|
1100
|
+
text += `\tcase ${helpers.formatStatusCodes([statusCode])}:\n`;
|
|
1101
|
+
const resultType = result.httpStatusCodeType[statusCode];
|
|
1102
|
+
if (!resultType) {
|
|
1103
|
+
// the operation contains a mix of schemas and non-schema responses
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
text += `\tvar val ${go.getTypeDeclaration(resultType)}\n`;
|
|
1107
|
+
text += generateResponseUnmarshaller(method, resultType, result.format, 'val');
|
|
1108
|
+
text += '\tresult.Value = val\n';
|
|
1109
|
+
}
|
|
1110
|
+
text += '\tdefault:\n';
|
|
1111
|
+
text += `\t\treturn ${getZeroReturnValue(method, 'handler')}, fmt.Errorf("unhandled HTTP status code %d", resp.StatusCode)\n`;
|
|
1112
|
+
text += '\t}\n';
|
|
1113
|
+
}
|
|
1114
|
+
else if (go.isBinaryResult(result)) {
|
|
1115
|
+
text += `\tresult := ${method.responseEnvelope.name}{${result.fieldName}: resp.Body}\n`;
|
|
1116
|
+
addHeaders(method.responseEnvelope.headers);
|
|
1117
|
+
}
|
|
1118
|
+
else if (go.isHeadAsBooleanResult(result)) {
|
|
1119
|
+
text += `\tresult := ${method.responseEnvelope.name}{${result.fieldName}: resp.StatusCode >= 200 && resp.StatusCode < 300}\n`;
|
|
1120
|
+
addHeaders(method.responseEnvelope.headers);
|
|
1121
|
+
}
|
|
1122
|
+
else if (go.isMonomorphicResult(result)) {
|
|
1123
|
+
text += `\tresult := ${method.responseEnvelope.name}{}\n`;
|
|
1124
|
+
addHeaders(method.responseEnvelope.headers);
|
|
1125
|
+
let target = `result.${helpers.getResultFieldName(method)}`;
|
|
1126
|
+
// when unmarshalling a wrapped XML array, unmarshal into the response envelope
|
|
1127
|
+
if (result.format === 'XML' && go.isSliceType(result.monomorphicType)) {
|
|
1128
|
+
target = 'result';
|
|
1129
|
+
}
|
|
1130
|
+
text += generateResponseUnmarshaller(method, result.monomorphicType, result.format, target);
|
|
1131
|
+
}
|
|
1132
|
+
else if (go.isPolymorphicResult(result)) {
|
|
1133
|
+
text += `\tresult := ${method.responseEnvelope.name}{}\n`;
|
|
1134
|
+
addHeaders(method.responseEnvelope.headers);
|
|
1135
|
+
text += generateResponseUnmarshaller(method, result.interfaceType, result.format, 'result');
|
|
1136
|
+
}
|
|
1137
|
+
else if (go.isModelResult(result)) {
|
|
1138
|
+
text += `\tresult := ${method.responseEnvelope.name}{}\n`;
|
|
1139
|
+
addHeaders(method.responseEnvelope.headers);
|
|
1140
|
+
text += generateResponseUnmarshaller(method, result.modelType, result.format, `result.${helpers.getResultFieldName(method)}`);
|
|
1141
|
+
}
|
|
1142
|
+
else {
|
|
1143
|
+
throw new Error(`unhandled result type for ${client.name}.${method.name}`);
|
|
1144
|
+
}
|
|
1145
|
+
text += '\treturn result, nil\n';
|
|
1146
|
+
text += '}\n\n';
|
|
1147
|
+
return text;
|
|
1148
|
+
}
|
|
1149
|
+
function isArrayOfDateTime(paramType) {
|
|
1150
|
+
if (!go.isSliceType(paramType)) {
|
|
1151
|
+
return undefined;
|
|
1152
|
+
}
|
|
1153
|
+
if (!go.isTimeType(paramType.elementType)) {
|
|
1154
|
+
return undefined;
|
|
1155
|
+
}
|
|
1156
|
+
return {
|
|
1157
|
+
format: paramType.elementType.dateTimeFormat,
|
|
1158
|
+
elemByVal: paramType.elementTypeByValue
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
function isMapOfDateTime(paramType) {
|
|
1162
|
+
if (!go.isMapType(paramType)) {
|
|
1163
|
+
return undefined;
|
|
1164
|
+
}
|
|
1165
|
+
if (!go.isTimeType(paramType.valueType)) {
|
|
1166
|
+
return undefined;
|
|
1167
|
+
}
|
|
1168
|
+
return paramType.valueType.dateTimeFormat;
|
|
1169
|
+
}
|
|
1170
|
+
// returns the parameters for the public API
|
|
1171
|
+
// e.g. "ctx context.Context, i int, s string"
|
|
1172
|
+
function getAPIParametersSig(method, imports, pkgName) {
|
|
1173
|
+
const methodParams = helpers.getMethodParameters(method);
|
|
1174
|
+
const params = new Array();
|
|
1175
|
+
if (!go.isPageableMethod(method) || go.isLROMethod(method)) {
|
|
1176
|
+
imports.add('context');
|
|
1177
|
+
params.push('ctx context.Context');
|
|
1178
|
+
}
|
|
1179
|
+
for (const methodParam of values(methodParams)) {
|
|
1180
|
+
params.push(`${uncapitalize(methodParam.name)} ${helpers.formatParameterTypeName(methodParam, pkgName)}`);
|
|
1181
|
+
}
|
|
1182
|
+
return params.join(', ');
|
|
1183
|
+
}
|
|
1184
|
+
// returns the return signature where each entry is the type name
|
|
1185
|
+
// e.g. [ '*string', 'error' ]
|
|
1186
|
+
// apiType describes where the return sig is used.
|
|
1187
|
+
// api - for the API definition
|
|
1188
|
+
// op - for the operation
|
|
1189
|
+
// handler - for the response handler
|
|
1190
|
+
function generateReturnsInfo(method, apiType) {
|
|
1191
|
+
let returnType = method.responseEnvelope.name;
|
|
1192
|
+
if (go.isLROMethod(method)) {
|
|
1193
|
+
switch (apiType) {
|
|
1194
|
+
case 'api':
|
|
1195
|
+
if (go.isPageableMethod(method)) {
|
|
1196
|
+
returnType = `*runtime.Poller[*runtime.Pager[${returnType}]]`;
|
|
1197
|
+
}
|
|
1198
|
+
else {
|
|
1199
|
+
returnType = `*runtime.Poller[${returnType}]`;
|
|
1200
|
+
}
|
|
1201
|
+
break;
|
|
1202
|
+
case 'handler':
|
|
1203
|
+
// we only have a handler for operations that return a schema
|
|
1204
|
+
if (!go.isPageableMethod(method)) {
|
|
1205
|
+
throw new Error(`handler being generated for non-pageable LRO ${method.name} which is unexpected`);
|
|
1206
|
+
}
|
|
1207
|
+
break;
|
|
1208
|
+
case 'op':
|
|
1209
|
+
returnType = '*http.Response';
|
|
1210
|
+
break;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
else if (go.isPageableMethod(method)) {
|
|
1214
|
+
switch (apiType) {
|
|
1215
|
+
case 'api':
|
|
1216
|
+
case 'op':
|
|
1217
|
+
// pager operations don't return an error
|
|
1218
|
+
return [`*runtime.Pager[${returnType}]`];
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return [returnType, 'error'];
|
|
1222
|
+
}
|
|
1223
|
+
function generateLROBeginMethod(client, method, imports, injectSpans, generateFakes) {
|
|
1224
|
+
const params = getAPIParametersSig(method, imports);
|
|
1225
|
+
const returns = generateReturnsInfo(method, 'api');
|
|
1226
|
+
imports.add('github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime');
|
|
1227
|
+
let text = '';
|
|
1228
|
+
if (method.description) {
|
|
1229
|
+
text += `${comment(`${fixUpMethodName(method)} - ${method.description}`, '//', undefined, helpers.commentLength)}\n`;
|
|
1230
|
+
text += genRespErrorDoc(method);
|
|
1231
|
+
text += genApiVersionDoc(method.apiVersions);
|
|
1232
|
+
}
|
|
1233
|
+
const zeroResp = getZeroReturnValue(method, 'api');
|
|
1234
|
+
const methodParams = helpers.getMethodParameters(method);
|
|
1235
|
+
for (const param of values(methodParams)) {
|
|
1236
|
+
if (param.description) {
|
|
1237
|
+
text += `${helpers.formatCommentAsBulletItem(`${param.name} - ${param.description}`)}\n`;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
text += `func (client *${client.name}) ${fixUpMethodName(method)}(${params}) (${returns.join(', ')}) {\n`;
|
|
1241
|
+
let pollerType = 'nil';
|
|
1242
|
+
let pollerTypeParam = `[${method.responseEnvelope.name}]`;
|
|
1243
|
+
if (go.isPageableMethod(method)) {
|
|
1244
|
+
// for paged LROs, we construct a pager and pass it to the LRO ctor.
|
|
1245
|
+
pollerTypeParam = `[*runtime.Pager${pollerTypeParam}]`;
|
|
1246
|
+
pollerType = '&pager';
|
|
1247
|
+
text += '\tpager := ';
|
|
1248
|
+
text += emitPagerDefinition(client, method, imports, injectSpans, generateFakes);
|
|
1249
|
+
}
|
|
1250
|
+
text += '\tif options == nil || options.ResumeToken == "" {\n';
|
|
1251
|
+
// creating the poller from response branch
|
|
1252
|
+
const opName = method.naming.internalMethod;
|
|
1253
|
+
text += `\t\tresp, err := client.${opName}(${helpers.getCreateRequestParameters(method)})\n`;
|
|
1254
|
+
text += '\t\tif err != nil {\n';
|
|
1255
|
+
text += `\t\t\treturn ${zeroResp}, err\n`;
|
|
1256
|
+
text += '\t\t}\n';
|
|
1257
|
+
let finalStateVia = '';
|
|
1258
|
+
// LRO operation might have a special configuration set in x-ms-long-running-operation-options
|
|
1259
|
+
// which indicates a specific url to perform the final Get operation on
|
|
1260
|
+
if (method.finalStateVia) {
|
|
1261
|
+
switch (method.finalStateVia) {
|
|
1262
|
+
case 'azure-async-operation':
|
|
1263
|
+
finalStateVia = 'runtime.FinalStateViaAzureAsyncOp';
|
|
1264
|
+
break;
|
|
1265
|
+
case 'location':
|
|
1266
|
+
finalStateVia = 'runtime.FinalStateViaLocation';
|
|
1267
|
+
break;
|
|
1268
|
+
case 'original-uri':
|
|
1269
|
+
finalStateVia = 'runtime.FinalStateViaOriginalURI';
|
|
1270
|
+
break;
|
|
1271
|
+
case 'operation-location':
|
|
1272
|
+
finalStateVia = 'runtime.FinalStateViaOpLocation';
|
|
1273
|
+
break;
|
|
1274
|
+
default:
|
|
1275
|
+
throw new Error(`unhandled final-state-via value ${finalStateVia}`);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
text += '\t\tpoller, err := runtime.NewPoller';
|
|
1279
|
+
if (finalStateVia === '' && pollerType === 'nil' && !injectSpans) {
|
|
1280
|
+
// the generic type param is redundant when it's also specified in the
|
|
1281
|
+
// options struct so we only include it when there's no options.
|
|
1282
|
+
text += pollerTypeParam;
|
|
1283
|
+
}
|
|
1284
|
+
text += '(resp, client.internal.Pipeline(), ';
|
|
1285
|
+
if (finalStateVia === '' && pollerType === 'nil' && !injectSpans) {
|
|
1286
|
+
// no options
|
|
1287
|
+
text += 'nil)\n';
|
|
1288
|
+
}
|
|
1289
|
+
else {
|
|
1290
|
+
// at least one option
|
|
1291
|
+
text += `&runtime.NewPollerOptions${pollerTypeParam}{\n`;
|
|
1292
|
+
if (finalStateVia !== '') {
|
|
1293
|
+
text += `\t\t\tFinalStateVia: ${finalStateVia},\n`;
|
|
1294
|
+
}
|
|
1295
|
+
if (pollerType !== 'nil') {
|
|
1296
|
+
text += `\t\t\tResponse: ${pollerType},\n`;
|
|
1297
|
+
}
|
|
1298
|
+
if (injectSpans) {
|
|
1299
|
+
text += '\t\t\tTracer: client.internal.Tracer(),\n';
|
|
1300
|
+
}
|
|
1301
|
+
text += '\t\t})\n';
|
|
1302
|
+
}
|
|
1303
|
+
text += '\t\treturn poller, err\n';
|
|
1304
|
+
text += '\t} else {\n';
|
|
1305
|
+
// creating the poller from resume token branch
|
|
1306
|
+
text += '\t\treturn runtime.NewPollerFromResumeToken';
|
|
1307
|
+
if (pollerType === 'nil' && !injectSpans) {
|
|
1308
|
+
text += pollerTypeParam;
|
|
1309
|
+
}
|
|
1310
|
+
text += '(options.ResumeToken, client.internal.Pipeline(), ';
|
|
1311
|
+
if (pollerType === 'nil' && !injectSpans) {
|
|
1312
|
+
text += 'nil)\n';
|
|
1313
|
+
}
|
|
1314
|
+
else {
|
|
1315
|
+
text += `&runtime.NewPollerFromResumeTokenOptions${pollerTypeParam}{\n`;
|
|
1316
|
+
if (pollerType !== 'nil') {
|
|
1317
|
+
text += `\t\t\tResponse: ${pollerType},\n`;
|
|
1318
|
+
}
|
|
1319
|
+
if (injectSpans) {
|
|
1320
|
+
text += '\t\t\tTracer: client.internal.Tracer(),\n';
|
|
1321
|
+
}
|
|
1322
|
+
text += '\t\t})\n';
|
|
1323
|
+
}
|
|
1324
|
+
text += '\t}\n';
|
|
1325
|
+
text += '}\n\n';
|
|
1326
|
+
return text;
|
|
1327
|
+
}
|
|
1328
|
+
export function fixUpMethodName(method) {
|
|
1329
|
+
if (go.isLROMethod(method)) {
|
|
1330
|
+
return `Begin${method.name}`;
|
|
1331
|
+
}
|
|
1332
|
+
else if (go.isPageableMethod(method)) {
|
|
1333
|
+
return `New${method.name}Pager`;
|
|
1334
|
+
}
|
|
1335
|
+
return method.name;
|
|
1336
|
+
}
|
|
1337
|
+
//# sourceMappingURL=operations.js.map
|