@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,975 @@
|
|
|
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 naming from '../../../naming.go/src/naming.js';
|
|
6
|
+
import * as go from '../../../codemodel.go/src/index.js';
|
|
7
|
+
import * as tcgc from '@azure-tools/typespec-client-generator-core';
|
|
8
|
+
import * as tsp from '@typespec/compiler';
|
|
9
|
+
import * as http from '@typespec/http';
|
|
10
|
+
import { values } from '@azure-tools/linq';
|
|
11
|
+
import { uncapitalize } from '@azure-tools/codegen';
|
|
12
|
+
// used to convert SDK types to Go code model types
|
|
13
|
+
export class typeAdapter {
|
|
14
|
+
constructor(codeModel) {
|
|
15
|
+
this.codeModel = codeModel;
|
|
16
|
+
this.types = new Map();
|
|
17
|
+
this.constValues = new Map();
|
|
18
|
+
this.unreferencedEnums = new Set();
|
|
19
|
+
this.unreferencedModels = new Set();
|
|
20
|
+
}
|
|
21
|
+
// converts all model/enum SDK types to Go code model types
|
|
22
|
+
adaptTypes(sdkContext, removeUnreferencedTypes) {
|
|
23
|
+
if (removeUnreferencedTypes) {
|
|
24
|
+
// this is a superset of flagUnreferencedBaseModels
|
|
25
|
+
this.flagUnreferencedTypes(sdkContext);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
this.flagUnreferencedBaseModels(sdkContext);
|
|
29
|
+
}
|
|
30
|
+
for (const enumType of sdkContext.experimental_sdkPackage.enums) {
|
|
31
|
+
if (enumType.usage === tcgc.UsageFlags.ApiVersionEnum) {
|
|
32
|
+
// we have a pipeline policy for controlling the api-version
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
else if (this.unreferencedEnums.has(enumType.name)) {
|
|
36
|
+
// skip unreferenced type
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const constType = this.getConstantType(enumType);
|
|
40
|
+
this.codeModel.constants.push(constType);
|
|
41
|
+
}
|
|
42
|
+
// we must adapt all interface/model types first. this is because models can contain cyclic references
|
|
43
|
+
const modelTypes = new Array();
|
|
44
|
+
const ifaceTypes = new Array();
|
|
45
|
+
for (const modelType of sdkContext.experimental_sdkPackage.models) {
|
|
46
|
+
if (this.unreferencedModels.has(modelType.name)) {
|
|
47
|
+
// skip unreferenced type
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (modelType.discriminatedSubtypes) {
|
|
51
|
+
// this is a root discriminated type
|
|
52
|
+
const iface = this.getInterfaceType(modelType);
|
|
53
|
+
this.codeModel.interfaceTypes.push(iface);
|
|
54
|
+
ifaceTypes.push({ go: iface, tcgc: modelType });
|
|
55
|
+
}
|
|
56
|
+
// TODO: what's the equivalent of x-ms-external?
|
|
57
|
+
const model = this.getModel(modelType);
|
|
58
|
+
modelTypes.push({ go: model, tcgc: modelType });
|
|
59
|
+
}
|
|
60
|
+
// add the synthesized models from TCGC for paged results
|
|
61
|
+
const pagedResponses = this.getPagedResponses(sdkContext);
|
|
62
|
+
for (const pagedResponse of pagedResponses) {
|
|
63
|
+
// tsp allows custom paged responses, so we must check both the synthesized list and the models list
|
|
64
|
+
if (values(modelTypes).any(each => { return each.tcgc.name === pagedResponse.name; })) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const model = this.getModel(pagedResponse);
|
|
68
|
+
modelTypes.push({ go: model, tcgc: pagedResponse });
|
|
69
|
+
}
|
|
70
|
+
// now that the interface/model types have been generated, we can populate the rootType and possibleTypes
|
|
71
|
+
for (const ifaceType of ifaceTypes) {
|
|
72
|
+
ifaceType.go.rootType = this.getModel(ifaceType.tcgc);
|
|
73
|
+
for (const subType of values(ifaceType.tcgc.discriminatedSubtypes)) {
|
|
74
|
+
const possibleType = this.getModel(subType);
|
|
75
|
+
ifaceType.go.possibleTypes.push(possibleType);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// now adapt model fields
|
|
79
|
+
for (const modelType of modelTypes) {
|
|
80
|
+
const content = aggregateProperties(modelType.tcgc);
|
|
81
|
+
for (const prop of values(content.props)) {
|
|
82
|
+
if (prop.kind === 'header') {
|
|
83
|
+
// the common case here is the @header decorator specifying
|
|
84
|
+
// the content-type for the model. we can just skip it.
|
|
85
|
+
// TODO: follow up with tcgc to see if we can remove the entry.
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const field = this.getModelField(prop, modelType.tcgc);
|
|
89
|
+
modelType.go.fields.push(field);
|
|
90
|
+
}
|
|
91
|
+
if (content.addlProps) {
|
|
92
|
+
const annotations = new go.ModelFieldAnnotations(false, false, true, false);
|
|
93
|
+
const addlPropsType = new go.MapType(this.getPossibleType(content.addlProps, false, false), isTypePassedByValue(content.addlProps));
|
|
94
|
+
const addlProps = new go.ModelField('AdditionalProperties', addlPropsType, true, '', annotations);
|
|
95
|
+
modelType.go.fields.push(addlProps);
|
|
96
|
+
}
|
|
97
|
+
this.codeModel.models.push(modelType.go);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// returns the synthesized paged response types
|
|
101
|
+
getPagedResponses(sdkContext) {
|
|
102
|
+
const pagedResponses = new Array();
|
|
103
|
+
const recursiveWalkClients = function (client) {
|
|
104
|
+
for (const sdkMethod of client.methods) {
|
|
105
|
+
if (sdkMethod.kind === 'clientaccessor') {
|
|
106
|
+
recursiveWalkClients(sdkMethod.response);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
else if (sdkMethod.kind !== 'paging') {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
for (const httpResp of sdkMethod.operation.responses.values()) {
|
|
113
|
+
if (!httpResp.type || httpResp.type.kind !== 'model') {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (!values(pagedResponses).any(each => { return each.name === httpResp.type.name; })) {
|
|
117
|
+
pagedResponses.push(httpResp.type);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
for (const sdkClient of sdkContext.experimental_sdkPackage.clients) {
|
|
123
|
+
recursiveWalkClients(sdkClient);
|
|
124
|
+
}
|
|
125
|
+
return pagedResponses;
|
|
126
|
+
}
|
|
127
|
+
// returns the Go code model type for the specified SDK type.
|
|
128
|
+
// the operation is idempotent, so getting the same type multiple times
|
|
129
|
+
// returns the same instance of the converted type.
|
|
130
|
+
getPossibleType(type, elementTypeByValue, substituteDiscriminator) {
|
|
131
|
+
switch (type.kind) {
|
|
132
|
+
case 'any':
|
|
133
|
+
case 'armId':
|
|
134
|
+
case 'azureLocation':
|
|
135
|
+
case 'boolean':
|
|
136
|
+
case 'bytes':
|
|
137
|
+
case 'decimal':
|
|
138
|
+
case 'decimal128':
|
|
139
|
+
case 'eTag':
|
|
140
|
+
case 'float':
|
|
141
|
+
case 'float32':
|
|
142
|
+
case 'float64':
|
|
143
|
+
case 'guid':
|
|
144
|
+
case 'int8':
|
|
145
|
+
case 'int16':
|
|
146
|
+
case 'int32':
|
|
147
|
+
case 'int64':
|
|
148
|
+
case 'uint8':
|
|
149
|
+
case 'uint16':
|
|
150
|
+
case 'uint32':
|
|
151
|
+
case 'uint64':
|
|
152
|
+
case 'plainDate':
|
|
153
|
+
case 'plainTime':
|
|
154
|
+
case 'string':
|
|
155
|
+
case 'uri':
|
|
156
|
+
case 'url':
|
|
157
|
+
case 'uuid':
|
|
158
|
+
return this.getBuiltInType(type);
|
|
159
|
+
case 'array': {
|
|
160
|
+
let elementType = type.valueType;
|
|
161
|
+
let nullable = false;
|
|
162
|
+
if (elementType.kind === 'nullable') {
|
|
163
|
+
// unwrap the nullable type
|
|
164
|
+
elementType = elementType.type;
|
|
165
|
+
nullable = true;
|
|
166
|
+
}
|
|
167
|
+
// prefer elementTypeByValue. if false, then if the array elements have been explicitly marked as nullable then prefer that, else fall back to our usual algorithm
|
|
168
|
+
const myElementTypeByValue = elementTypeByValue ? true : nullable ? false : this.codeModel.options.sliceElementsByval || isTypePassedByValue(elementType);
|
|
169
|
+
const keyName = recursiveKeyName(`array-${myElementTypeByValue}`, elementType, substituteDiscriminator);
|
|
170
|
+
let arrayType = this.types.get(keyName);
|
|
171
|
+
if (arrayType) {
|
|
172
|
+
return arrayType;
|
|
173
|
+
}
|
|
174
|
+
arrayType = new go.SliceType(this.getPossibleType(elementType, elementTypeByValue, substituteDiscriminator), myElementTypeByValue);
|
|
175
|
+
this.types.set(keyName, arrayType);
|
|
176
|
+
return arrayType;
|
|
177
|
+
}
|
|
178
|
+
case 'endpoint': {
|
|
179
|
+
const stringKey = 'string';
|
|
180
|
+
let stringType = this.types.get(stringKey);
|
|
181
|
+
if (stringType) {
|
|
182
|
+
return stringType;
|
|
183
|
+
}
|
|
184
|
+
stringType = new go.PrimitiveType('string');
|
|
185
|
+
this.types.set(stringKey, stringType);
|
|
186
|
+
return stringType;
|
|
187
|
+
}
|
|
188
|
+
case 'enum':
|
|
189
|
+
return this.getConstantType(type);
|
|
190
|
+
case 'constant':
|
|
191
|
+
case 'enumvalue':
|
|
192
|
+
return this.getLiteralValue(type);
|
|
193
|
+
case 'offsetDateTime':
|
|
194
|
+
return this.getTimeType(type.encode, false);
|
|
195
|
+
case 'utcDateTime':
|
|
196
|
+
return this.getTimeType(type.encode, true);
|
|
197
|
+
case 'dict': {
|
|
198
|
+
const valueTypeByValue = isTypePassedByValue(type.valueType);
|
|
199
|
+
const keyName = recursiveKeyName(`dict-${valueTypeByValue}`, type.valueType, substituteDiscriminator);
|
|
200
|
+
let mapType = this.types.get(keyName);
|
|
201
|
+
if (mapType) {
|
|
202
|
+
return mapType;
|
|
203
|
+
}
|
|
204
|
+
mapType = new go.MapType(this.getPossibleType(type.valueType, elementTypeByValue, substituteDiscriminator), valueTypeByValue);
|
|
205
|
+
this.types.set(keyName, mapType);
|
|
206
|
+
return mapType;
|
|
207
|
+
}
|
|
208
|
+
case 'duration': {
|
|
209
|
+
switch (type.wireType.kind) {
|
|
210
|
+
case 'float':
|
|
211
|
+
case 'float32':
|
|
212
|
+
case 'float64':
|
|
213
|
+
case 'int32':
|
|
214
|
+
case 'int64':
|
|
215
|
+
case 'string':
|
|
216
|
+
return this.getBuiltInType(type.wireType);
|
|
217
|
+
default:
|
|
218
|
+
throw new Error(`unhandled duration wireType.kind ${type.wireType.kind}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
case 'model':
|
|
222
|
+
if (type.discriminatedSubtypes && substituteDiscriminator) {
|
|
223
|
+
return this.getInterfaceType(type);
|
|
224
|
+
}
|
|
225
|
+
return this.getModel(type);
|
|
226
|
+
case 'nullable':
|
|
227
|
+
return this.getPossibleType(type.type, elementTypeByValue, substituteDiscriminator);
|
|
228
|
+
default:
|
|
229
|
+
throw new Error(`unhandled property kind ${type.kind}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
getTimeType(encode, utc) {
|
|
233
|
+
const encoding = getDateTimeEncoding(encode);
|
|
234
|
+
let datetime = this.types.get(encoding);
|
|
235
|
+
if (datetime) {
|
|
236
|
+
return datetime;
|
|
237
|
+
}
|
|
238
|
+
datetime = new go.TimeType(encoding, utc);
|
|
239
|
+
this.types.set(encoding, datetime);
|
|
240
|
+
return datetime;
|
|
241
|
+
}
|
|
242
|
+
// returns the Go code model type for an io.ReadSeekCloser
|
|
243
|
+
getReadSeekCloser(sliceOf) {
|
|
244
|
+
let keyName = 'io-readseekcloser';
|
|
245
|
+
if (sliceOf) {
|
|
246
|
+
keyName = 'sliceof-' + keyName;
|
|
247
|
+
}
|
|
248
|
+
let rsc = this.types.get(keyName);
|
|
249
|
+
if (!rsc) {
|
|
250
|
+
rsc = new go.QualifiedType('ReadSeekCloser', 'io');
|
|
251
|
+
if (sliceOf) {
|
|
252
|
+
rsc = new go.SliceType(rsc, true);
|
|
253
|
+
}
|
|
254
|
+
this.types.set(keyName, rsc);
|
|
255
|
+
}
|
|
256
|
+
return rsc;
|
|
257
|
+
}
|
|
258
|
+
// returns the Go code model type for streaming.MultipartContent
|
|
259
|
+
getMultipartContent(sliceOf) {
|
|
260
|
+
let keyName = 'streaming-multipartcontent';
|
|
261
|
+
if (sliceOf) {
|
|
262
|
+
keyName = 'sliceof-' + keyName;
|
|
263
|
+
}
|
|
264
|
+
let rsc = this.types.get(keyName);
|
|
265
|
+
if (!rsc) {
|
|
266
|
+
rsc = new go.QualifiedType('MultipartContent', 'github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming');
|
|
267
|
+
if (sliceOf) {
|
|
268
|
+
rsc = new go.SliceType(rsc, true);
|
|
269
|
+
}
|
|
270
|
+
this.types.set(keyName, rsc);
|
|
271
|
+
}
|
|
272
|
+
return rsc;
|
|
273
|
+
}
|
|
274
|
+
getBuiltInType(type) {
|
|
275
|
+
switch (type.kind) {
|
|
276
|
+
case 'any': {
|
|
277
|
+
if (this.codeModel.options.rawJSONAsBytes) {
|
|
278
|
+
const anyRawJSONKey = 'any-raw-json';
|
|
279
|
+
let anyRawJSON = this.types.get(anyRawJSONKey);
|
|
280
|
+
if (anyRawJSON) {
|
|
281
|
+
return anyRawJSON;
|
|
282
|
+
}
|
|
283
|
+
anyRawJSON = new go.SliceType(new go.PrimitiveType('byte'), true);
|
|
284
|
+
anyRawJSON.rawJSONAsBytes = true;
|
|
285
|
+
this.types.set(anyRawJSONKey, anyRawJSON);
|
|
286
|
+
return anyRawJSON;
|
|
287
|
+
}
|
|
288
|
+
let anyType = this.types.get('any');
|
|
289
|
+
if (anyType) {
|
|
290
|
+
return anyType;
|
|
291
|
+
}
|
|
292
|
+
anyType = new go.PrimitiveType('any');
|
|
293
|
+
this.types.set('any', anyType);
|
|
294
|
+
return anyType;
|
|
295
|
+
}
|
|
296
|
+
case 'boolean': {
|
|
297
|
+
const boolKey = 'boolean';
|
|
298
|
+
let primitiveBool = this.types.get(boolKey);
|
|
299
|
+
if (primitiveBool) {
|
|
300
|
+
return primitiveBool;
|
|
301
|
+
}
|
|
302
|
+
primitiveBool = new go.PrimitiveType('bool');
|
|
303
|
+
this.types.set(boolKey, primitiveBool);
|
|
304
|
+
return primitiveBool;
|
|
305
|
+
}
|
|
306
|
+
case 'bytes':
|
|
307
|
+
return this.adaptBytesType(type);
|
|
308
|
+
case 'plainDate': {
|
|
309
|
+
const dateKey = 'dateType';
|
|
310
|
+
let date = this.types.get(dateKey);
|
|
311
|
+
if (date) {
|
|
312
|
+
return date;
|
|
313
|
+
}
|
|
314
|
+
date = new go.TimeType('dateType', false);
|
|
315
|
+
this.types.set(dateKey, date);
|
|
316
|
+
return date;
|
|
317
|
+
}
|
|
318
|
+
case 'decimal':
|
|
319
|
+
case 'decimal128': {
|
|
320
|
+
const decimalKey = 'float64';
|
|
321
|
+
let decimalType = this.types.get(decimalKey);
|
|
322
|
+
if (decimalType) {
|
|
323
|
+
return decimalType;
|
|
324
|
+
}
|
|
325
|
+
decimalType = new go.PrimitiveType(decimalKey);
|
|
326
|
+
this.types.set(decimalKey, decimalType);
|
|
327
|
+
return decimalType;
|
|
328
|
+
}
|
|
329
|
+
case 'eTag': {
|
|
330
|
+
const etagKey = 'etag';
|
|
331
|
+
let etag = this.types.get(etagKey);
|
|
332
|
+
if (etag) {
|
|
333
|
+
return etag;
|
|
334
|
+
}
|
|
335
|
+
etag = new go.QualifiedType('ETag', 'github.com/Azure/azure-sdk-for-go/sdk/azcore');
|
|
336
|
+
this.types.set(etagKey, etag);
|
|
337
|
+
return etag;
|
|
338
|
+
}
|
|
339
|
+
case 'float': // C# and Java define float as 32 bits so we're following suit
|
|
340
|
+
case 'float32': {
|
|
341
|
+
const float32Key = 'float32';
|
|
342
|
+
let float32 = this.types.get(float32Key);
|
|
343
|
+
if (float32) {
|
|
344
|
+
return float32;
|
|
345
|
+
}
|
|
346
|
+
float32 = new go.PrimitiveType(float32Key);
|
|
347
|
+
this.types.set(float32Key, float32);
|
|
348
|
+
return float32;
|
|
349
|
+
}
|
|
350
|
+
case 'float64': {
|
|
351
|
+
const float64Key = 'float64';
|
|
352
|
+
let float64 = this.types.get(float64Key);
|
|
353
|
+
if (float64) {
|
|
354
|
+
return float64;
|
|
355
|
+
}
|
|
356
|
+
float64 = new go.PrimitiveType(float64Key);
|
|
357
|
+
this.types.set(float64Key, float64);
|
|
358
|
+
return float64;
|
|
359
|
+
}
|
|
360
|
+
case 'int8':
|
|
361
|
+
case 'int16':
|
|
362
|
+
case 'int32':
|
|
363
|
+
case 'int64':
|
|
364
|
+
case 'uint8':
|
|
365
|
+
case 'uint16':
|
|
366
|
+
case 'uint32':
|
|
367
|
+
case 'uint64': {
|
|
368
|
+
const keyName = type.kind;
|
|
369
|
+
let intType = this.types.get(keyName);
|
|
370
|
+
if (intType) {
|
|
371
|
+
return intType;
|
|
372
|
+
}
|
|
373
|
+
intType = new go.PrimitiveType(type.kind);
|
|
374
|
+
this.types.set(keyName, intType);
|
|
375
|
+
return intType;
|
|
376
|
+
}
|
|
377
|
+
case 'armId':
|
|
378
|
+
case 'azureLocation':
|
|
379
|
+
case 'guid':
|
|
380
|
+
case 'string':
|
|
381
|
+
case 'uuid':
|
|
382
|
+
case 'uri':
|
|
383
|
+
case 'url': {
|
|
384
|
+
const stringKey = 'string';
|
|
385
|
+
let stringType = this.types.get(stringKey);
|
|
386
|
+
if (stringType) {
|
|
387
|
+
return stringType;
|
|
388
|
+
}
|
|
389
|
+
stringType = new go.PrimitiveType('string');
|
|
390
|
+
this.types.set(stringKey, stringType);
|
|
391
|
+
return stringType;
|
|
392
|
+
}
|
|
393
|
+
case 'plainTime': {
|
|
394
|
+
if (type.encode !== 'rfc3339') {
|
|
395
|
+
throw new Error(`unsupported time encoding ${type.encode}`);
|
|
396
|
+
}
|
|
397
|
+
const encoding = 'timeRFC3339';
|
|
398
|
+
let time = this.types.get(encoding);
|
|
399
|
+
if (time) {
|
|
400
|
+
return time;
|
|
401
|
+
}
|
|
402
|
+
time = new go.TimeType(encoding, false);
|
|
403
|
+
this.types.set(encoding, time);
|
|
404
|
+
return time;
|
|
405
|
+
}
|
|
406
|
+
default:
|
|
407
|
+
throw new Error(`unhandled property kind ${type.kind}`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
// converts an SdkEnumType to a go.ConstantType
|
|
411
|
+
getConstantType(enumType) {
|
|
412
|
+
let constTypeName = naming.ensureNameCase(enumType.name);
|
|
413
|
+
if (enumType.access === 'internal') {
|
|
414
|
+
constTypeName = naming.getEscapedReservedName(uncapitalize(constTypeName), 'Type');
|
|
415
|
+
}
|
|
416
|
+
let constType = this.types.get(constTypeName);
|
|
417
|
+
if (constType) {
|
|
418
|
+
return constType;
|
|
419
|
+
}
|
|
420
|
+
constType = new go.ConstantType(constTypeName, getPrimitiveType(enumType.valueType.kind), `Possible${constTypeName}Values`);
|
|
421
|
+
constType.values = this.getConstantValues(constType, enumType.values);
|
|
422
|
+
constType.description = enumType.description;
|
|
423
|
+
this.types.set(constTypeName, constType);
|
|
424
|
+
return constType;
|
|
425
|
+
}
|
|
426
|
+
getInterfaceType(model, parent) {
|
|
427
|
+
if (model.name.length === 0) {
|
|
428
|
+
throw new Error('unnamed model');
|
|
429
|
+
}
|
|
430
|
+
if (!model.discriminatedSubtypes) {
|
|
431
|
+
throw new Error(`type ${model.name} isn't a discriminator root`);
|
|
432
|
+
}
|
|
433
|
+
let ifaceName = naming.createPolymorphicInterfaceName(naming.ensureNameCase(model.name));
|
|
434
|
+
if (model.access === 'internal') {
|
|
435
|
+
ifaceName = uncapitalize(ifaceName);
|
|
436
|
+
}
|
|
437
|
+
let iface = this.types.get(ifaceName);
|
|
438
|
+
if (iface) {
|
|
439
|
+
return iface;
|
|
440
|
+
}
|
|
441
|
+
// find the discriminator field
|
|
442
|
+
let discriminatorField;
|
|
443
|
+
for (const prop of model.properties) {
|
|
444
|
+
if (prop.kind === 'property' && prop.discriminator) {
|
|
445
|
+
discriminatorField = prop.serializedName;
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (!discriminatorField) {
|
|
450
|
+
throw new Error(`failed to find discriminator field for type ${model.name}`);
|
|
451
|
+
}
|
|
452
|
+
iface = new go.InterfaceType(ifaceName, discriminatorField);
|
|
453
|
+
if (parent) {
|
|
454
|
+
iface.parent = parent;
|
|
455
|
+
}
|
|
456
|
+
this.types.set(ifaceName, iface);
|
|
457
|
+
return iface;
|
|
458
|
+
}
|
|
459
|
+
// converts an SdkModelType to a go.ModelType or go.PolymorphicType if the model is polymorphic
|
|
460
|
+
getModel(model) {
|
|
461
|
+
let modelName = model.name;
|
|
462
|
+
if (modelName.length === 0) {
|
|
463
|
+
throw new Error('unnamed model');
|
|
464
|
+
}
|
|
465
|
+
modelName = naming.ensureNameCase(modelName);
|
|
466
|
+
if (model.access === 'internal') {
|
|
467
|
+
modelName = naming.getEscapedReservedName(uncapitalize(modelName), 'Model');
|
|
468
|
+
}
|
|
469
|
+
let modelType = this.types.get(modelName);
|
|
470
|
+
if (modelType) {
|
|
471
|
+
return modelType;
|
|
472
|
+
}
|
|
473
|
+
let usage = go.UsageFlags.None;
|
|
474
|
+
if (model.usage & tsp.UsageFlags.Input) {
|
|
475
|
+
usage = go.UsageFlags.Input;
|
|
476
|
+
}
|
|
477
|
+
if (model.usage & tsp.UsageFlags.Output) {
|
|
478
|
+
usage |= go.UsageFlags.Output;
|
|
479
|
+
}
|
|
480
|
+
const annotations = new go.ModelAnnotations(false, model.isFormDataType);
|
|
481
|
+
if (model.discriminatedSubtypes || model.discriminatorValue) {
|
|
482
|
+
let iface;
|
|
483
|
+
let discriminatorLiteral;
|
|
484
|
+
if (model.discriminatedSubtypes) {
|
|
485
|
+
// root type, we can get the InterfaceType directly from it
|
|
486
|
+
iface = this.getInterfaceType(model);
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
// walk the parents until we find the first root type
|
|
490
|
+
let parent = model.baseModel;
|
|
491
|
+
while (parent) {
|
|
492
|
+
if (parent.discriminatedSubtypes) {
|
|
493
|
+
iface = this.getInterfaceType(parent);
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
parent = parent.baseModel;
|
|
497
|
+
}
|
|
498
|
+
if (!iface) {
|
|
499
|
+
throw new Error(`failed to find discriminator interface name for type ${model.name}`);
|
|
500
|
+
}
|
|
501
|
+
// find the discriminator property and create the discriminator literal based on it
|
|
502
|
+
for (const prop of model.properties) {
|
|
503
|
+
if (prop.kind === 'property' && prop.discriminator) {
|
|
504
|
+
discriminatorLiteral = this.getDiscriminatorLiteral(prop);
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
modelType = new go.PolymorphicType(modelName, iface, annotations, usage);
|
|
510
|
+
modelType.discriminatorValue = discriminatorLiteral;
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
// TODO: hard-coded format
|
|
514
|
+
modelType = new go.ModelType(modelName, 'json', annotations, usage);
|
|
515
|
+
// polymorphic types don't have XMLInfo
|
|
516
|
+
// TODO: XMLInfo
|
|
517
|
+
}
|
|
518
|
+
if (model.description) {
|
|
519
|
+
modelType.description = model.description;
|
|
520
|
+
if (!modelType.description.startsWith(modelName)) {
|
|
521
|
+
modelType.description = `${modelName} - ${modelType.description}`;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
this.types.set(modelName, modelType);
|
|
525
|
+
return modelType;
|
|
526
|
+
}
|
|
527
|
+
getDiscriminatorLiteral(sdkProp) {
|
|
528
|
+
switch (sdkProp.type.kind) {
|
|
529
|
+
case 'constant':
|
|
530
|
+
case 'enumvalue':
|
|
531
|
+
return this.getLiteralValue(sdkProp.type);
|
|
532
|
+
default:
|
|
533
|
+
throw new Error(`unhandled kind ${sdkProp.type.kind} for discriminator property ${sdkProp.name}`);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
getModelField(prop, modelType) {
|
|
537
|
+
if (prop.kind !== 'path' && prop.kind !== 'property') {
|
|
538
|
+
throw new Error(`unexpected kind ${prop.kind} for property ${prop.name} in model ${modelType.name}`);
|
|
539
|
+
}
|
|
540
|
+
const annotations = new go.ModelFieldAnnotations(prop.optional === false, false, false, false);
|
|
541
|
+
// for multipart/form data containing models, default to fields not being pointer-to-type as we
|
|
542
|
+
// don't have to deal with JSON patch shenanigans. only the optional fields will be pointer-to-type.
|
|
543
|
+
const isMultipartFormData = (modelType.usage & tcgc.UsageFlags.MultipartFormData) === tcgc.UsageFlags.MultipartFormData;
|
|
544
|
+
let fieldByValue = isMultipartFormData ? true : isTypePassedByValue(prop.type);
|
|
545
|
+
if (isMultipartFormData && prop.kind === 'property' && prop.optional) {
|
|
546
|
+
fieldByValue = false;
|
|
547
|
+
}
|
|
548
|
+
let type = this.getPossibleType(prop.type, isMultipartFormData, true);
|
|
549
|
+
if (prop.kind === 'property') {
|
|
550
|
+
if (prop.isMultipartFileInput) {
|
|
551
|
+
type = this.getMultipartContent(prop.type.kind === 'array');
|
|
552
|
+
}
|
|
553
|
+
if (prop.visibility) {
|
|
554
|
+
// the field is read-only IFF the only visibility attribute present is Read.
|
|
555
|
+
// a field can have Read & Create set which means it's required on input and
|
|
556
|
+
// returned on output.
|
|
557
|
+
if (prop.visibility.length === 1 && prop.visibility[0] === http.Visibility.Read) {
|
|
558
|
+
annotations.readOnly = true;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
const field = new go.ModelField(naming.capitalize(naming.ensureNameCase(prop.name)), type, fieldByValue, prop.serializedName, annotations);
|
|
563
|
+
field.description = prop.description;
|
|
564
|
+
if (prop.kind === 'path') {
|
|
565
|
+
// for ARM resources, a property of kind path is usually the model
|
|
566
|
+
// key and will be exposed as a discrete method parameter. this also
|
|
567
|
+
// means that the value is read-only.
|
|
568
|
+
annotations.readOnly = true;
|
|
569
|
+
}
|
|
570
|
+
else if (prop.discriminator && modelType.discriminatorValue) {
|
|
571
|
+
// the presence of modelType.discriminatorValue tells us that this
|
|
572
|
+
// property is on a model that's not the root discriminator
|
|
573
|
+
annotations.isDiscriminator = true;
|
|
574
|
+
field.defaultValue = this.getDiscriminatorLiteral(prop);
|
|
575
|
+
}
|
|
576
|
+
// TODO: XMLInfo
|
|
577
|
+
//field.xml = adaptXMLInfo(prop.schema);
|
|
578
|
+
return field;
|
|
579
|
+
}
|
|
580
|
+
getConstantValues(type, valueTypes) {
|
|
581
|
+
const values = new Array();
|
|
582
|
+
for (const valueType of valueTypes) {
|
|
583
|
+
let valueTypeName = `${type.name}${naming.ensureNameCase(valueType.name)}`;
|
|
584
|
+
if (valueType.enumType.access === 'internal') {
|
|
585
|
+
valueTypeName = naming.getEscapedReservedName(uncapitalize(valueTypeName), 'Type');
|
|
586
|
+
}
|
|
587
|
+
let value = this.constValues.get(valueTypeName);
|
|
588
|
+
if (!value) {
|
|
589
|
+
value = new go.ConstantValue(valueTypeName, type, valueType.value);
|
|
590
|
+
value.description = valueType.description;
|
|
591
|
+
this.constValues.set(valueTypeName, value);
|
|
592
|
+
}
|
|
593
|
+
values.push(value);
|
|
594
|
+
}
|
|
595
|
+
return values;
|
|
596
|
+
}
|
|
597
|
+
adaptBytesType(sdkType) {
|
|
598
|
+
let format = 'Std';
|
|
599
|
+
if (sdkType.encode === 'base64url') {
|
|
600
|
+
format = 'URL';
|
|
601
|
+
}
|
|
602
|
+
const keyName = `bytes-${format}`;
|
|
603
|
+
let bytesType = this.types.get(keyName);
|
|
604
|
+
if (bytesType) {
|
|
605
|
+
return bytesType;
|
|
606
|
+
}
|
|
607
|
+
bytesType = new go.BytesType(format);
|
|
608
|
+
this.types.set(keyName, bytesType);
|
|
609
|
+
return bytesType;
|
|
610
|
+
}
|
|
611
|
+
getLiteralValue(constType) {
|
|
612
|
+
if (constType.kind === 'enumvalue') {
|
|
613
|
+
const valueName = `${naming.ensureNameCase(constType.enumType.name)}${naming.ensureNameCase(constType.name)}`;
|
|
614
|
+
const keyName = `literal-${valueName}`;
|
|
615
|
+
let literalConst = this.types.get(keyName);
|
|
616
|
+
if (literalConst) {
|
|
617
|
+
return literalConst;
|
|
618
|
+
}
|
|
619
|
+
const constValue = this.constValues.get(valueName);
|
|
620
|
+
if (!constValue) {
|
|
621
|
+
throw new Error(`failed to find const value for ${constType.name} in enum ${constType.enumType.name}`);
|
|
622
|
+
}
|
|
623
|
+
literalConst = new go.LiteralValue(this.getConstantType(constType.enumType), constValue);
|
|
624
|
+
this.types.set(keyName, literalConst);
|
|
625
|
+
return literalConst;
|
|
626
|
+
}
|
|
627
|
+
switch (constType.valueType.kind) {
|
|
628
|
+
case 'boolean': {
|
|
629
|
+
const keyName = `literal-boolean-${constType.value}`;
|
|
630
|
+
let literalBool = this.types.get(keyName);
|
|
631
|
+
if (literalBool) {
|
|
632
|
+
return literalBool;
|
|
633
|
+
}
|
|
634
|
+
literalBool = new go.LiteralValue(new go.PrimitiveType('bool'), constType.value);
|
|
635
|
+
this.types.set(keyName, literalBool);
|
|
636
|
+
return literalBool;
|
|
637
|
+
}
|
|
638
|
+
case 'bytes': {
|
|
639
|
+
const keyName = `literal-bytes-${constType.value}`;
|
|
640
|
+
let literalByteArray = this.types.get(keyName);
|
|
641
|
+
if (literalByteArray) {
|
|
642
|
+
return literalByteArray;
|
|
643
|
+
}
|
|
644
|
+
literalByteArray = new go.LiteralValue(this.adaptBytesType(constType.valueType), constType.value);
|
|
645
|
+
this.types.set(keyName, literalByteArray);
|
|
646
|
+
return literalByteArray;
|
|
647
|
+
}
|
|
648
|
+
case 'decimal':
|
|
649
|
+
case 'decimal128': {
|
|
650
|
+
const keyName = `literal-${constType.valueType.kind}-${constType.value}`;
|
|
651
|
+
let literalDecimal = this.types.get(keyName);
|
|
652
|
+
if (literalDecimal) {
|
|
653
|
+
return literalDecimal;
|
|
654
|
+
}
|
|
655
|
+
literalDecimal = new go.LiteralValue(new go.PrimitiveType('float64'), constType.value);
|
|
656
|
+
this.types.set(keyName, literalDecimal);
|
|
657
|
+
return literalDecimal;
|
|
658
|
+
}
|
|
659
|
+
/*case 'date':
|
|
660
|
+
case 'datetime': {
|
|
661
|
+
// TODO: tcgc doesn't expose the encoding for date/datetime constant types
|
|
662
|
+
const encoding = getDateTimeEncoding(constType.encode);
|
|
663
|
+
const keyName = `literal-${encoding}-${constType.value}`;
|
|
664
|
+
let literalTime = this.types.get(keyName);
|
|
665
|
+
if (literalTime) {
|
|
666
|
+
return <go.LiteralValue>literalTime;
|
|
667
|
+
}
|
|
668
|
+
literalTime = new go.LiteralValue(new go.TimeType(encoding), constType.value);
|
|
669
|
+
this.types.set(keyName, literalTime);
|
|
670
|
+
return literalTime;
|
|
671
|
+
}*/
|
|
672
|
+
case 'int8':
|
|
673
|
+
case 'int16':
|
|
674
|
+
case 'int32':
|
|
675
|
+
case 'int64':
|
|
676
|
+
case 'uint8':
|
|
677
|
+
case 'uint16':
|
|
678
|
+
case 'uint32':
|
|
679
|
+
case 'uint64': {
|
|
680
|
+
const keyName = `literal-${constType.valueType.kind}-${constType.value}`;
|
|
681
|
+
let literalInt = this.types.get(keyName);
|
|
682
|
+
if (literalInt) {
|
|
683
|
+
return literalInt;
|
|
684
|
+
}
|
|
685
|
+
literalInt = new go.LiteralValue(new go.PrimitiveType(constType.valueType.kind), constType.value);
|
|
686
|
+
this.types.set(keyName, literalInt);
|
|
687
|
+
return literalInt;
|
|
688
|
+
}
|
|
689
|
+
case 'float32':
|
|
690
|
+
case 'float64': {
|
|
691
|
+
const keyName = `literal-${constType.valueType.kind}-${constType.value}`;
|
|
692
|
+
let literalFloat = this.types.get(keyName);
|
|
693
|
+
if (literalFloat) {
|
|
694
|
+
return literalFloat;
|
|
695
|
+
}
|
|
696
|
+
literalFloat = new go.LiteralValue(new go.PrimitiveType(constType.valueType.kind), constType.value);
|
|
697
|
+
this.types.set(keyName, literalFloat);
|
|
698
|
+
return literalFloat;
|
|
699
|
+
}
|
|
700
|
+
case 'string':
|
|
701
|
+
case 'guid':
|
|
702
|
+
case 'uuid':
|
|
703
|
+
case 'uri':
|
|
704
|
+
case 'url': {
|
|
705
|
+
const keyName = `literal-string-${constType.value}`;
|
|
706
|
+
let literalString = this.types.get(keyName);
|
|
707
|
+
if (literalString) {
|
|
708
|
+
return literalString;
|
|
709
|
+
}
|
|
710
|
+
literalString = new go.LiteralValue(new go.PrimitiveType('string'), constType.value);
|
|
711
|
+
this.types.set(keyName, literalString);
|
|
712
|
+
return literalString;
|
|
713
|
+
}
|
|
714
|
+
default:
|
|
715
|
+
throw new Error(`unsupported kind ${constType.valueType.kind} for LiteralValue`);
|
|
716
|
+
}
|
|
717
|
+
// TODO: tcgc doesn't support duration as a literal value
|
|
718
|
+
}
|
|
719
|
+
// updates this.unreferencedEnums and this.unreferencedModels
|
|
720
|
+
flagUnreferencedTypes(sdkContext) {
|
|
721
|
+
const referencedEnums = new Set();
|
|
722
|
+
const referencedModels = new Set();
|
|
723
|
+
const recursiveAddReferencedType = function (type) {
|
|
724
|
+
switch (type.kind) {
|
|
725
|
+
case 'array':
|
|
726
|
+
case 'dict':
|
|
727
|
+
recursiveAddReferencedType(type.valueType);
|
|
728
|
+
break;
|
|
729
|
+
case 'enum':
|
|
730
|
+
if (!referencedEnums.has(type.name)) {
|
|
731
|
+
referencedEnums.add(type.name);
|
|
732
|
+
}
|
|
733
|
+
break;
|
|
734
|
+
case 'enumvalue':
|
|
735
|
+
if (!referencedEnums.has(type.enumType.name)) {
|
|
736
|
+
referencedEnums.add(type.enumType.name);
|
|
737
|
+
}
|
|
738
|
+
break;
|
|
739
|
+
case 'model':
|
|
740
|
+
if (!referencedModels.has(type.name)) {
|
|
741
|
+
referencedModels.add(type.name);
|
|
742
|
+
const aggregateProps = aggregateProperties(type);
|
|
743
|
+
for (const prop of aggregateProps.props) {
|
|
744
|
+
recursiveAddReferencedType(prop.type);
|
|
745
|
+
}
|
|
746
|
+
if (aggregateProps.addlProps) {
|
|
747
|
+
recursiveAddReferencedType(aggregateProps.addlProps);
|
|
748
|
+
}
|
|
749
|
+
if (type.discriminatedSubtypes) {
|
|
750
|
+
for (const subType of values(type.discriminatedSubtypes)) {
|
|
751
|
+
recursiveAddReferencedType(subType);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
break;
|
|
756
|
+
case 'nullable':
|
|
757
|
+
return recursiveAddReferencedType(type.type);
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
const recursiveWalkClients = function (client) {
|
|
761
|
+
for (const method of client.methods) {
|
|
762
|
+
if (method.kind === 'clientaccessor') {
|
|
763
|
+
recursiveWalkClients(method.response);
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
for (const param of method.parameters) {
|
|
767
|
+
recursiveAddReferencedType(param.type);
|
|
768
|
+
}
|
|
769
|
+
if (method.response.type) {
|
|
770
|
+
recursiveAddReferencedType(method.response.type);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
};
|
|
774
|
+
// traverse all client initialization params and methods to find the set of referenced enums and models
|
|
775
|
+
for (const client of sdkContext.experimental_sdkPackage.clients) {
|
|
776
|
+
for (const param of client.initialization.properties) {
|
|
777
|
+
if (param.kind === 'endpoint' && param.type.kind === 'endpoint') {
|
|
778
|
+
for (const templateArg of param.type.templateArguments) {
|
|
779
|
+
recursiveAddReferencedType(templateArg.type);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
recursiveWalkClients(client);
|
|
784
|
+
}
|
|
785
|
+
const pagedResponses = this.getPagedResponses(sdkContext);
|
|
786
|
+
for (const pagedResponse of pagedResponses) {
|
|
787
|
+
recursiveAddReferencedType(pagedResponse);
|
|
788
|
+
}
|
|
789
|
+
// now that we have the referenced set, update the unreferenced set
|
|
790
|
+
for (const sdkEnum of sdkContext.experimental_sdkPackage.enums) {
|
|
791
|
+
if (!referencedEnums.has(sdkEnum.name)) {
|
|
792
|
+
this.unreferencedEnums.add(sdkEnum.name);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
for (const model of sdkContext.experimental_sdkPackage.models) {
|
|
796
|
+
if (!referencedModels.has(model.name)) {
|
|
797
|
+
this.unreferencedModels.add(model.name);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
// updates this.unreferencedModels
|
|
802
|
+
flagUnreferencedBaseModels(sdkContext) {
|
|
803
|
+
const baseModels = new Set();
|
|
804
|
+
const referencedBaseModels = new Set();
|
|
805
|
+
const visitedModels = new Set(); // avoids infinite recursion
|
|
806
|
+
const recursiveAddReferencedBaseModel = function (type) {
|
|
807
|
+
switch (type.kind) {
|
|
808
|
+
case 'array':
|
|
809
|
+
case 'dict':
|
|
810
|
+
recursiveAddReferencedBaseModel(type.valueType);
|
|
811
|
+
break;
|
|
812
|
+
case 'model':
|
|
813
|
+
if (baseModels.has(type.name)) {
|
|
814
|
+
if (!referencedBaseModels.has(type.name)) {
|
|
815
|
+
referencedBaseModels.add(type.name);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
else if (!visitedModels.has(type.name)) {
|
|
819
|
+
visitedModels.add(type.name);
|
|
820
|
+
const aggregateProps = aggregateProperties(type);
|
|
821
|
+
for (const prop of aggregateProps.props) {
|
|
822
|
+
recursiveAddReferencedBaseModel(prop.type);
|
|
823
|
+
}
|
|
824
|
+
if (aggregateProps.addlProps) {
|
|
825
|
+
recursiveAddReferencedBaseModel(aggregateProps.addlProps);
|
|
826
|
+
}
|
|
827
|
+
if (type.discriminatedSubtypes) {
|
|
828
|
+
for (const subType of values(type.discriminatedSubtypes)) {
|
|
829
|
+
recursiveAddReferencedBaseModel(subType);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
break;
|
|
834
|
+
case 'nullable':
|
|
835
|
+
return recursiveAddReferencedBaseModel(type.type);
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
// collect all the base model types
|
|
839
|
+
for (const model of sdkContext.experimental_sdkPackage.models) {
|
|
840
|
+
let parent = model.baseModel;
|
|
841
|
+
while (parent) {
|
|
842
|
+
// exclude any polymorphic root type from the check
|
|
843
|
+
// as we always need to include the root type even
|
|
844
|
+
// if it's not referenced.
|
|
845
|
+
if (!parent.discriminatedSubtypes && !baseModels.has(parent.name)) {
|
|
846
|
+
baseModels.add(parent.name);
|
|
847
|
+
}
|
|
848
|
+
parent = parent.baseModel;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
// traverse all methods to find any references to a base model type.
|
|
852
|
+
// NOTE: it's possible for there to be no base types.
|
|
853
|
+
if (baseModels.size > 0) {
|
|
854
|
+
const recursiveWalkClients = function (client) {
|
|
855
|
+
for (const method of client.methods) {
|
|
856
|
+
if (method.kind === 'clientaccessor') {
|
|
857
|
+
recursiveWalkClients(method.response);
|
|
858
|
+
continue;
|
|
859
|
+
}
|
|
860
|
+
for (const param of method.parameters) {
|
|
861
|
+
recursiveAddReferencedBaseModel(param.type);
|
|
862
|
+
}
|
|
863
|
+
if (method.response.type) {
|
|
864
|
+
recursiveAddReferencedBaseModel(method.response.type);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
for (const client of sdkContext.experimental_sdkPackage.clients) {
|
|
869
|
+
recursiveWalkClients(client);
|
|
870
|
+
}
|
|
871
|
+
const pagedResponses = this.getPagedResponses(sdkContext);
|
|
872
|
+
for (const pagedResponse of pagedResponses) {
|
|
873
|
+
recursiveAddReferencedBaseModel(pagedResponse);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
// now that we have the referenced set, update the unreferenced set
|
|
877
|
+
for (const baseModel of baseModels) {
|
|
878
|
+
if (!referencedBaseModels.has(baseModel)) {
|
|
879
|
+
this.unreferencedModels.add(baseModel);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
function getPrimitiveType(kind) {
|
|
885
|
+
switch (kind) {
|
|
886
|
+
case 'boolean':
|
|
887
|
+
return 'bool';
|
|
888
|
+
case 'float32':
|
|
889
|
+
case 'float64':
|
|
890
|
+
case 'int32':
|
|
891
|
+
case 'int64':
|
|
892
|
+
case 'string':
|
|
893
|
+
return kind;
|
|
894
|
+
default:
|
|
895
|
+
throw new Error(`unhandled tcgc.SdkBuiltInKinds: ${kind}`);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
function getDateTimeEncoding(encoding) {
|
|
899
|
+
switch (encoding) {
|
|
900
|
+
case 'rfc3339':
|
|
901
|
+
return 'dateTimeRFC3339';
|
|
902
|
+
case 'rfc7231':
|
|
903
|
+
return 'dateTimeRFC1123';
|
|
904
|
+
case 'unixTimestamp':
|
|
905
|
+
return 'timeUnix';
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
function recursiveKeyName(root, obj, substituteDiscriminator) {
|
|
909
|
+
switch (obj.kind) {
|
|
910
|
+
case 'array':
|
|
911
|
+
return recursiveKeyName(`${root}-array`, obj.valueType, substituteDiscriminator);
|
|
912
|
+
case 'enum':
|
|
913
|
+
return `${root}-${obj.name}`;
|
|
914
|
+
case 'enumvalue':
|
|
915
|
+
return `${root}-${obj.enumType.name}-${obj.value}`;
|
|
916
|
+
case 'dict':
|
|
917
|
+
return recursiveKeyName(`${root}-dict`, obj.valueType, substituteDiscriminator);
|
|
918
|
+
case 'plainDate':
|
|
919
|
+
return `${root}-dateType`;
|
|
920
|
+
case 'utcDateTime':
|
|
921
|
+
return `${root}-${getDateTimeEncoding(obj.encode)}`;
|
|
922
|
+
case 'duration':
|
|
923
|
+
return `${root}-${obj.wireType.kind}`;
|
|
924
|
+
case 'model':
|
|
925
|
+
if (substituteDiscriminator) {
|
|
926
|
+
return `${root}-${naming.createPolymorphicInterfaceName(obj.name)}`;
|
|
927
|
+
}
|
|
928
|
+
return `${root}-${obj.name}`;
|
|
929
|
+
case 'nullable':
|
|
930
|
+
return recursiveKeyName(root, obj.type, substituteDiscriminator);
|
|
931
|
+
case 'plainTime':
|
|
932
|
+
if (obj.encode !== 'rfc3339') {
|
|
933
|
+
throw new Error(`unsupported time encoding ${obj.encode}`);
|
|
934
|
+
}
|
|
935
|
+
return `${root}-timeRFC3339`;
|
|
936
|
+
default:
|
|
937
|
+
return `${root}-${obj.kind}`;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
export function isTypePassedByValue(type) {
|
|
941
|
+
if (type.kind === 'nullable') {
|
|
942
|
+
type = type.type;
|
|
943
|
+
}
|
|
944
|
+
return type.kind === 'any' || type.kind === 'array' ||
|
|
945
|
+
type.kind === 'bytes' || type.kind === 'dict' ||
|
|
946
|
+
(type.kind === 'model' && !!type.discriminatedSubtypes);
|
|
947
|
+
}
|
|
948
|
+
// aggregate the properties from the provided type and its parent types.
|
|
949
|
+
// this includes any inherited additional properties.
|
|
950
|
+
function aggregateProperties(model) {
|
|
951
|
+
const allProps = new Array();
|
|
952
|
+
for (const prop of model.properties) {
|
|
953
|
+
allProps.push(prop);
|
|
954
|
+
}
|
|
955
|
+
let addlProps = model.additionalProperties;
|
|
956
|
+
let parent = model.baseModel;
|
|
957
|
+
while (parent) {
|
|
958
|
+
for (const parentProp of parent.properties) {
|
|
959
|
+
const exists = values(allProps).where(p => { return p.name === parentProp.name; }).first();
|
|
960
|
+
if (exists) {
|
|
961
|
+
// don't add the duplicate. the TS compiler has better enforcement than OpenAPI
|
|
962
|
+
// to ensure that duplicate fields with different types aren't added.
|
|
963
|
+
continue;
|
|
964
|
+
}
|
|
965
|
+
allProps.push(parentProp);
|
|
966
|
+
}
|
|
967
|
+
// if we haven't found additional properties yet and the parent has it, use it
|
|
968
|
+
if (!addlProps && parent.additionalProperties) {
|
|
969
|
+
addlProps = parent.additionalProperties;
|
|
970
|
+
}
|
|
971
|
+
parent = parent.baseModel;
|
|
972
|
+
}
|
|
973
|
+
return { props: allProps, addlProps: addlProps };
|
|
974
|
+
}
|
|
975
|
+
//# sourceMappingURL=types.js.map
|