@azure-tools/typespec-go 0.8.7 → 0.8.8
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/dist/codegen.go/src/core/clientFactory.js +5 -5
- package/dist/codegen.go/src/core/clientFactory.js.map +1 -1
- package/dist/codegen.go/src/core/cloudConfig.js +1 -1
- package/dist/codegen.go/src/core/cloudConfig.js.map +1 -1
- package/dist/codegen.go/src/core/constants.js +1 -1
- package/dist/codegen.go/src/core/constants.js.map +1 -1
- package/dist/codegen.go/src/core/example.d.ts +1 -1
- package/dist/codegen.go/src/core/example.d.ts.map +1 -1
- package/dist/codegen.go/src/core/example.js +34 -36
- package/dist/codegen.go/src/core/example.js.map +1 -1
- package/dist/codegen.go/src/core/helpers.d.ts +4 -13
- package/dist/codegen.go/src/core/helpers.d.ts.map +1 -1
- package/dist/codegen.go/src/core/helpers.js +16 -37
- package/dist/codegen.go/src/core/helpers.js.map +1 -1
- package/dist/codegen.go/src/core/imports.d.ts +39 -3
- package/dist/codegen.go/src/core/imports.d.ts.map +1 -1
- package/dist/codegen.go/src/core/imports.js +68 -18
- package/dist/codegen.go/src/core/imports.js.map +1 -1
- package/dist/codegen.go/src/core/interfaces.d.ts.map +1 -1
- package/dist/codegen.go/src/core/interfaces.js +1 -2
- package/dist/codegen.go/src/core/interfaces.js.map +1 -1
- package/dist/codegen.go/src/core/models.d.ts +0 -1
- package/dist/codegen.go/src/core/models.d.ts.map +1 -1
- package/dist/codegen.go/src/core/models.js +163 -84
- package/dist/codegen.go/src/core/models.js.map +1 -1
- package/dist/codegen.go/src/core/operations.js +18 -18
- package/dist/codegen.go/src/core/operations.js.map +1 -1
- package/dist/codegen.go/src/core/options.js +14 -6
- package/dist/codegen.go/src/core/options.js.map +1 -1
- package/dist/codegen.go/src/core/polymorphics.d.ts +1 -2
- package/dist/codegen.go/src/core/polymorphics.d.ts.map +1 -1
- package/dist/codegen.go/src/core/polymorphics.js +13 -12
- package/dist/codegen.go/src/core/polymorphics.js.map +1 -1
- package/dist/codegen.go/src/core/responses.js +34 -11
- package/dist/codegen.go/src/core/responses.js.map +1 -1
- package/dist/codegen.go/src/core/time.d.ts +1 -2
- package/dist/codegen.go/src/core/time.d.ts.map +1 -1
- package/dist/codegen.go/src/core/time.js +51 -18
- package/dist/codegen.go/src/core/time.js.map +1 -1
- package/dist/codegen.go/src/core/version.js +1 -1
- package/dist/codegen.go/src/core/version.js.map +1 -1
- package/dist/codegen.go/src/core/xmlAdditionalProps.js +2 -2
- package/dist/codegen.go/src/core/xmlAdditionalProps.js.map +1 -1
- package/dist/codegen.go/src/emitter.js +6 -5
- package/dist/codegen.go/src/emitter.js.map +1 -1
- package/dist/codegen.go/src/fake/factory.d.ts +1 -1
- package/dist/codegen.go/src/fake/factory.d.ts.map +1 -1
- package/dist/codegen.go/src/fake/factory.js +9 -8
- package/dist/codegen.go/src/fake/factory.js.map +1 -1
- package/dist/codegen.go/src/fake/internal.d.ts +1 -1
- package/dist/codegen.go/src/fake/internal.d.ts.map +1 -1
- package/dist/codegen.go/src/fake/internal.js +3 -3
- package/dist/codegen.go/src/fake/internal.js.map +1 -1
- package/dist/codegen.go/src/fake/servers.d.ts +1 -1
- package/dist/codegen.go/src/fake/servers.d.ts.map +1 -1
- package/dist/codegen.go/src/fake/servers.js +127 -77
- package/dist/codegen.go/src/fake/servers.js.map +1 -1
- package/dist/codemodel.go/src/client.d.ts +13 -5
- package/dist/codemodel.go/src/client.d.ts.map +1 -1
- package/dist/codemodel.go/src/client.js +9 -5
- package/dist/codemodel.go/src/client.js.map +1 -1
- package/dist/codemodel.go/src/module.d.ts +29 -0
- package/dist/codemodel.go/src/module.d.ts.map +1 -1
- package/dist/codemodel.go/src/module.js +36 -0
- package/dist/codemodel.go/src/module.js.map +1 -1
- package/dist/codemodel.go/src/param.d.ts +4 -1
- package/dist/codemodel.go/src/param.d.ts.map +1 -1
- package/dist/codemodel.go/src/param.js +2 -1
- package/dist/codemodel.go/src/param.js.map +1 -1
- package/dist/codemodel.go/src/result.d.ts +1 -0
- package/dist/codemodel.go/src/result.d.ts.map +1 -1
- package/dist/codemodel.go/src/result.js +1 -0
- package/dist/codemodel.go/src/result.js.map +1 -1
- package/dist/codemodel.go/src/type.d.ts +23 -13
- package/dist/codemodel.go/src/type.d.ts.map +1 -1
- package/dist/codemodel.go/src/type.js +50 -28
- package/dist/codemodel.go/src/type.js.map +1 -1
- package/dist/typespec-go/src/emitter.d.ts.map +1 -1
- package/dist/typespec-go/src/emitter.js +9 -2
- package/dist/typespec-go/src/emitter.js.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/adapter.d.ts +23 -2
- package/dist/typespec-go/src/tcgcadapter/adapter.d.ts.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/adapter.js +96 -67
- package/dist/typespec-go/src/tcgcadapter/adapter.js.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/clients.d.ts +11 -9
- package/dist/typespec-go/src/tcgcadapter/clients.d.ts.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/clients.js +141 -100
- package/dist/typespec-go/src/tcgcadapter/clients.js.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/errors.d.ts +1 -1
- package/dist/typespec-go/src/tcgcadapter/errors.d.ts.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/errors.js +2 -1
- package/dist/typespec-go/src/tcgcadapter/errors.js.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/types.d.ts +11 -4
- package/dist/typespec-go/src/tcgcadapter/types.d.ts.map +1 -1
- package/dist/typespec-go/src/tcgcadapter/types.js +38 -33
- package/dist/typespec-go/src/tcgcadapter/types.js.map +1 -1
- package/package.json +5 -5
|
@@ -22,9 +22,9 @@ export function generateModels(pkg, options) {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
// this list of packages to import
|
|
25
|
-
const modelImports = new ImportManager();
|
|
26
|
-
const serdeImports = new ImportManager();
|
|
27
|
-
let modelText = helpers.contentPreamble(
|
|
25
|
+
const modelImports = new ImportManager(pkg);
|
|
26
|
+
const serdeImports = new ImportManager(pkg);
|
|
27
|
+
let modelText = helpers.contentPreamble(pkg);
|
|
28
28
|
// we do model generation first as it can add imports to the imports list
|
|
29
29
|
const modelDefs = generateModelDefs(modelImports, serdeImports, pkg, options);
|
|
30
30
|
modelText += modelImports.text();
|
|
@@ -127,7 +127,7 @@ export function generateModels(pkg, options) {
|
|
|
127
127
|
}
|
|
128
128
|
let serdeText = '';
|
|
129
129
|
if (serdeTextBody.length > 0) {
|
|
130
|
-
serdeText = helpers.contentPreamble(
|
|
130
|
+
serdeText = helpers.contentPreamble(pkg);
|
|
131
131
|
serdeText += serdeImports.text();
|
|
132
132
|
serdeText += serdeTextBody;
|
|
133
133
|
}
|
|
@@ -136,6 +136,15 @@ export function generateModels(pkg, options) {
|
|
|
136
136
|
serDe: serdeText
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* converts model types to an array of ModelDef types
|
|
141
|
+
*
|
|
142
|
+
* @param modelImports the import manager for the models file
|
|
143
|
+
* @param serdeImports the import manager for the models_serde file
|
|
144
|
+
* @param pkg contains the package content
|
|
145
|
+
* @param options the Go emitter options
|
|
146
|
+
* @returns an array of ModelDefs
|
|
147
|
+
*/
|
|
139
148
|
function generateModelDefs(modelImports, serdeImports, pkg, options) {
|
|
140
149
|
const models = pkg.models;
|
|
141
150
|
const modelDefs = new Array();
|
|
@@ -174,16 +183,16 @@ function generateModelDefs(modelImports, serdeImports, pkg, options) {
|
|
|
174
183
|
field.docs.description = descriptionMods.join('; ');
|
|
175
184
|
}
|
|
176
185
|
const serDeFormat = helpers.getSerDeFormat(model, pkg);
|
|
177
|
-
const modelDef = new ModelDef(model
|
|
178
|
-
for (const field of
|
|
179
|
-
modelImports.
|
|
186
|
+
const modelDef = new ModelDef(model, serDeFormat);
|
|
187
|
+
for (const field of modelDef.Model.fields) {
|
|
188
|
+
modelImports.addForType(field.type);
|
|
180
189
|
}
|
|
181
190
|
if (model.kind === 'model' && serDeFormat === 'XML' && !model.annotations.omitSerDeMethods) {
|
|
182
191
|
serdeImports.add('encoding/xml');
|
|
183
192
|
let needsDateTimeMarshalling = false;
|
|
184
193
|
let byteArrayFormat = false;
|
|
185
194
|
for (const field of values(model.fields)) {
|
|
186
|
-
serdeImports.
|
|
195
|
+
serdeImports.addForType(field.type);
|
|
187
196
|
if (field.type.kind === 'time') {
|
|
188
197
|
needsDateTimeMarshalling = true;
|
|
189
198
|
}
|
|
@@ -193,14 +202,14 @@ function generateModelDefs(modelImports, serdeImports, pkg, options) {
|
|
|
193
202
|
}
|
|
194
203
|
// due to differences in XML marshallers/unmarshallers, we use different codegen than for JSON
|
|
195
204
|
if (needsDateTimeMarshalling || model.xml?.wrapper || needsXMLArrayMarshalling(model) || byteArrayFormat) {
|
|
196
|
-
generateXMLMarshaller(
|
|
205
|
+
generateXMLMarshaller(modelDef, serdeImports);
|
|
197
206
|
if (needsDateTimeMarshalling || byteArrayFormat) {
|
|
198
|
-
generateXMLUnmarshaller(
|
|
207
|
+
generateXMLUnmarshaller(modelDef, serdeImports);
|
|
199
208
|
}
|
|
200
209
|
}
|
|
201
210
|
else if (needsXMLDictionaryHelper(model)) {
|
|
202
|
-
generateXMLMarshaller(
|
|
203
|
-
generateXMLUnmarshaller(
|
|
211
|
+
generateXMLMarshaller(modelDef, serdeImports);
|
|
212
|
+
generateXMLUnmarshaller(modelDef, serdeImports);
|
|
204
213
|
}
|
|
205
214
|
modelDefs.push(modelDef);
|
|
206
215
|
continue;
|
|
@@ -216,8 +225,8 @@ function generateModelDefs(modelImports, serdeImports, pkg, options) {
|
|
|
216
225
|
modelDef.SerDe.needsJSONPopulateMultipart = true;
|
|
217
226
|
}
|
|
218
227
|
else if (!model.annotations.omitSerDeMethods) {
|
|
219
|
-
generateJSONMarshaller(
|
|
220
|
-
generateJSONUnmarshaller(
|
|
228
|
+
generateJSONMarshaller(modelDef, serdeImports);
|
|
229
|
+
generateJSONUnmarshaller(modelDef, serdeImports, options);
|
|
221
230
|
}
|
|
222
231
|
modelDefs.push(modelDef);
|
|
223
232
|
}
|
|
@@ -245,8 +254,8 @@ function generateDiscriminatorMarkerMethod(type, modelDef) {
|
|
|
245
254
|
const typeName = type.rootType.name;
|
|
246
255
|
const receiver = modelDef.receiverName();
|
|
247
256
|
const interfaceMethod = `Get${typeName}`;
|
|
248
|
-
let method = `func (${receiver} *${modelDef.
|
|
249
|
-
if (type.rootType.name === modelDef.
|
|
257
|
+
let method = `func (${receiver} *${modelDef.Model.name}) ${interfaceMethod}() *${typeName} {`;
|
|
258
|
+
if (type.rootType.name === modelDef.Model.name) {
|
|
250
259
|
// the marker method is on the discriminator itself, so just return the receiver
|
|
251
260
|
method += ` return ${receiver} }\n\n`;
|
|
252
261
|
}
|
|
@@ -259,13 +268,13 @@ function generateDiscriminatorMarkerMethod(type, modelDef) {
|
|
|
259
268
|
}
|
|
260
269
|
method += '\t}\n}\n\n';
|
|
261
270
|
}
|
|
262
|
-
modelDef.Methods.push({ name: interfaceMethod, desc: `${interfaceMethod} implements the ${type.name} interface for type ${modelDef.
|
|
271
|
+
modelDef.Methods.push({ name: interfaceMethod, desc: `${interfaceMethod} implements the ${type.name} interface for type ${modelDef.Model.name}.`, text: method });
|
|
263
272
|
}
|
|
264
273
|
function generateToMultipartForm(modelDef) {
|
|
265
274
|
const receiver = modelDef.receiverName();
|
|
266
|
-
let method = `func (${receiver} ${modelDef.
|
|
275
|
+
let method = `func (${receiver} ${modelDef.Model.name}) toMultipartFormData() (map[string]any, error) {\n`;
|
|
267
276
|
method += '\tobjectMap := make(map[string]any)\n';
|
|
268
|
-
for (const field of modelDef.
|
|
277
|
+
for (const field of modelDef.Model.fields) {
|
|
269
278
|
const fieldType = helpers.recursiveUnwrapMapSlice(field.type);
|
|
270
279
|
let setField;
|
|
271
280
|
let star = '';
|
|
@@ -284,28 +293,43 @@ function generateToMultipartForm(modelDef) {
|
|
|
284
293
|
method += setField;
|
|
285
294
|
}
|
|
286
295
|
method += '\treturn objectMap, nil\n}\n\n';
|
|
287
|
-
modelDef.SerDe.methods.push({ name: 'toMultipartFormData', desc: `toMultipartFormData converts ${modelDef.
|
|
296
|
+
modelDef.SerDe.methods.push({ name: 'toMultipartFormData', desc: `toMultipartFormData converts ${modelDef.Model.name} to multipart/form data.`, text: method });
|
|
288
297
|
}
|
|
289
|
-
|
|
290
|
-
|
|
298
|
+
/**
|
|
299
|
+
* generates the MarshalJSON method for the provided type.
|
|
300
|
+
* the method impl is added to modelDef.SerDe.methods.
|
|
301
|
+
*
|
|
302
|
+
* @param modelDef the type for which to emit the method
|
|
303
|
+
* @param imports the import manager currently in scope
|
|
304
|
+
*/
|
|
305
|
+
function generateJSONMarshaller(modelDef, imports) {
|
|
306
|
+
if (modelDef.Model.kind === 'model' && modelDef.Model.fields.length === 0) {
|
|
291
307
|
// non-discriminated types without content don't need a custom marshaller.
|
|
292
308
|
// there is a case in network where child is allOf base and child has no properties.
|
|
293
309
|
return;
|
|
294
310
|
}
|
|
295
311
|
imports.add('encoding/json');
|
|
296
|
-
const typeName = modelDef.
|
|
312
|
+
const typeName = modelDef.Model.name;
|
|
297
313
|
const receiver = modelDef.receiverName();
|
|
298
314
|
let marshaller = `func (${receiver} ${typeName}) MarshalJSON() ([]byte, error) {\n`;
|
|
299
315
|
marshaller += '\tobjectMap := make(map[string]any)\n';
|
|
300
|
-
marshaller += generateJSONMarshallerBody(
|
|
316
|
+
marshaller += generateJSONMarshallerBody(modelDef, receiver, imports);
|
|
301
317
|
marshaller += '\treturn json.Marshal(objectMap)\n';
|
|
302
318
|
marshaller += '}\n\n';
|
|
303
319
|
modelDef.SerDe.methods.push({ name: 'MarshalJSON', desc: `MarshalJSON implements the json.Marshaller interface for type ${typeName}.`, text: marshaller });
|
|
304
320
|
}
|
|
305
|
-
|
|
321
|
+
/**
|
|
322
|
+
* generates the contents of MarshalJSON that encode the target type
|
|
323
|
+
*
|
|
324
|
+
* @param modelDef the type being encoded
|
|
325
|
+
* @param receiver the name of the receiver in the MarshalJSON method
|
|
326
|
+
* @param imports the import manager currently in scope
|
|
327
|
+
* @returns the text for encoding the target type
|
|
328
|
+
*/
|
|
329
|
+
function generateJSONMarshallerBody(modelDef, receiver, imports) {
|
|
306
330
|
let marshaller = '';
|
|
307
331
|
let addlProps;
|
|
308
|
-
for (const field of
|
|
332
|
+
for (const field of modelDef.Model.fields) {
|
|
309
333
|
if (field.type.kind === 'map' && field.annotations.isAdditionalProperties) {
|
|
310
334
|
addlProps = field.type;
|
|
311
335
|
continue;
|
|
@@ -407,26 +431,43 @@ function generateJSONMarshallerBody(modelType, modelDef, receiver, imports) {
|
|
|
407
431
|
}
|
|
408
432
|
return marshaller;
|
|
409
433
|
}
|
|
410
|
-
|
|
434
|
+
/**
|
|
435
|
+
* generates the UnmarshalJSON method for the provided type.
|
|
436
|
+
* the method impl is added to modelDef.SerDe.methods.
|
|
437
|
+
*
|
|
438
|
+
* @param modelDef the type for which to emit the method
|
|
439
|
+
* @param imports the import manager currently in scope
|
|
440
|
+
* @param options the Go emitter options
|
|
441
|
+
*/
|
|
442
|
+
function generateJSONUnmarshaller(modelDef, imports, options) {
|
|
411
443
|
// there's a corner-case where a derived type might not add any new fields (Cookiecuttershark).
|
|
412
444
|
// in this case skip adding the unmarshaller as it's not necessary and doesn't compile.
|
|
413
|
-
if (modelDef.
|
|
445
|
+
if (modelDef.Model.fields.length === 0) {
|
|
414
446
|
return;
|
|
415
447
|
}
|
|
416
448
|
imports.add('encoding/json');
|
|
417
449
|
imports.add('fmt');
|
|
418
|
-
const typeName = modelDef.
|
|
450
|
+
const typeName = modelDef.Model.name;
|
|
419
451
|
const receiver = modelDef.receiverName();
|
|
420
452
|
let unmarshaller = `func (${receiver} *${typeName}) UnmarshalJSON(data []byte) error {\n`;
|
|
421
453
|
unmarshaller += '\tvar rawMsg map[string]json.RawMessage\n';
|
|
422
454
|
unmarshaller += '\tif err := json.Unmarshal(data, &rawMsg); err != nil {\n';
|
|
423
455
|
unmarshaller += `\t\treturn fmt.Errorf("unmarshalling type %T: %v", ${receiver}, err)\n`;
|
|
424
456
|
unmarshaller += '\t}\n';
|
|
425
|
-
unmarshaller += generateJSONUnmarshallerBody(
|
|
457
|
+
unmarshaller += generateJSONUnmarshallerBody(modelDef, receiver, imports, options);
|
|
426
458
|
unmarshaller += '}\n\n';
|
|
427
459
|
modelDef.SerDe.methods.push({ name: 'UnmarshalJSON', desc: `UnmarshalJSON implements the json.Unmarshaller interface for type ${typeName}.`, text: unmarshaller });
|
|
428
460
|
}
|
|
429
|
-
|
|
461
|
+
/**
|
|
462
|
+
* generates the contents of UnmarshalJSON that decode the target type
|
|
463
|
+
*
|
|
464
|
+
* @param modelDef the type being decoded
|
|
465
|
+
* @param receiver the receiver for the UnmarshalJSON method
|
|
466
|
+
* @param imports the import manager currently in scope
|
|
467
|
+
* @param options the Go emitter options
|
|
468
|
+
* @returns the text for decoding the target type
|
|
469
|
+
*/
|
|
470
|
+
function generateJSONUnmarshallerBody(modelDef, receiver, imports, options) {
|
|
430
471
|
// we almost always need to have an error check when unmarshaling the values.
|
|
431
472
|
// however, fields that are raw JSON don't require any unmarshaling. so, if all
|
|
432
473
|
// of the fields in a type are raw JSON, then the error check isn't necessary
|
|
@@ -438,10 +479,10 @@ function generateJSONUnmarshallerBody(modelType, modelDef, receiver, imports, op
|
|
|
438
479
|
if (!addlProps.valueTypeByValue) {
|
|
439
480
|
ref = '&';
|
|
440
481
|
}
|
|
441
|
-
addlPropsText += `${tab}\t\t\t${receiver}.AdditionalProperties = ${go.getTypeDeclaration(addlProps)}{}\n`;
|
|
482
|
+
addlPropsText += `${tab}\t\t\t${receiver}.AdditionalProperties = ${go.getTypeDeclaration(addlProps, modelDef.Model.pkg)}{}\n`;
|
|
442
483
|
addlPropsText += `${tab}\t\t}\n`;
|
|
443
484
|
addlPropsText += `${tab}\t\tif val != nil {\n`;
|
|
444
|
-
let auxType = go.getTypeDeclaration(addlProps.valueType);
|
|
485
|
+
let auxType = go.getTypeDeclaration(addlProps.valueType, modelDef.Model.pkg);
|
|
445
486
|
let assignment = `${ref}aux`;
|
|
446
487
|
if (addlProps.valueType.kind === 'time') {
|
|
447
488
|
imports.add('time');
|
|
@@ -460,14 +501,14 @@ function generateJSONUnmarshallerBody(modelType, modelDef, receiver, imports, op
|
|
|
460
501
|
let unmarshalBody = '';
|
|
461
502
|
let addlProps;
|
|
462
503
|
unmarshalBody += '\t\tswitch key {\n';
|
|
463
|
-
for (const field of
|
|
504
|
+
for (const field of modelDef.Model.fields) {
|
|
464
505
|
if (field.type.kind === 'map' && field.annotations.isAdditionalProperties) {
|
|
465
506
|
addlProps = field.type;
|
|
466
507
|
continue;
|
|
467
508
|
}
|
|
468
509
|
unmarshalBody += `\t\tcase "${field.serializedName}":\n`;
|
|
469
510
|
if (hasDiscriminatorInterface(field.type)) {
|
|
470
|
-
unmarshalBody += generateDiscriminatorUnmarshaller(field, receiver);
|
|
511
|
+
unmarshalBody += generateDiscriminatorUnmarshaller(modelDef.Model, field, receiver);
|
|
471
512
|
needsErrCheck = true;
|
|
472
513
|
}
|
|
473
514
|
else if (field.type.kind === 'time') {
|
|
@@ -581,7 +622,7 @@ function hasDiscriminatorInterface(item) {
|
|
|
581
622
|
}
|
|
582
623
|
}
|
|
583
624
|
// returns the text for unmarshalling a discriminated type
|
|
584
|
-
function generateDiscriminatorUnmarshaller(field, receiver) {
|
|
625
|
+
function generateDiscriminatorUnmarshaller(modelType, field, receiver) {
|
|
585
626
|
const startingIndentation = '\t\t\t';
|
|
586
627
|
const propertyName = field.name;
|
|
587
628
|
// these are the simple, non-nested cases (e.g. IterfaceType, []InterfaceType, map[string]InterfaceType)
|
|
@@ -597,12 +638,12 @@ function generateDiscriminatorUnmarshaller(field, receiver) {
|
|
|
597
638
|
// nested case (e.g. [][]InterfaceType, map[string]map[string]InterfaceType etc)
|
|
598
639
|
// first, unmarshal the raw data
|
|
599
640
|
const rawTargetVar = `${field.serializedName}Raw`;
|
|
600
|
-
let text = `${startingIndentation}var ${rawTargetVar} ${recursiveGetDiscriminatorTypeName(field.type, true)}\n`;
|
|
641
|
+
let text = `${startingIndentation}var ${rawTargetVar} ${recursiveGetDiscriminatorTypeName(modelType, field.type, true)}\n`;
|
|
601
642
|
text += `${startingIndentation}if err = json.Unmarshal(val, &${rawTargetVar}); err != nil {\n`;
|
|
602
643
|
text += `${startingIndentation}\treturn err\n${startingIndentation}}\n`;
|
|
603
644
|
// create a local instantiation of the final type
|
|
604
645
|
const finalTargetVar = field.serializedName;
|
|
605
|
-
let finalTargetCtor = recursiveGetDiscriminatorTypeName(field.type, false);
|
|
646
|
+
let finalTargetCtor = recursiveGetDiscriminatorTypeName(modelType, field.type, false);
|
|
606
647
|
if (field.type.kind === 'slice') {
|
|
607
648
|
finalTargetCtor = `make(${finalTargetCtor}, len(${rawTargetVar}))`;
|
|
608
649
|
}
|
|
@@ -612,7 +653,7 @@ function generateDiscriminatorUnmarshaller(field, receiver) {
|
|
|
612
653
|
}
|
|
613
654
|
text += `${startingIndentation}${finalTargetVar} := ${finalTargetCtor}\n`;
|
|
614
655
|
// now populate the final type
|
|
615
|
-
text += recursivePopulateDiscriminator(field.type, receiver, rawTargetVar, finalTargetVar, startingIndentation, 1);
|
|
656
|
+
text += recursivePopulateDiscriminator(modelType, field.type, receiver, rawTargetVar, finalTargetVar, startingIndentation, 1);
|
|
616
657
|
// finally, assign the final target to the property
|
|
617
658
|
text += `${startingIndentation}${receiver}.${propertyName} = ${finalTargetVar}\n`;
|
|
618
659
|
return text;
|
|
@@ -620,25 +661,36 @@ function generateDiscriminatorUnmarshaller(field, receiver) {
|
|
|
620
661
|
// constructs the type name for a nested discriminated type
|
|
621
662
|
// raw e.g. map[string]json.RawMessage, []json.RawMessage etc
|
|
622
663
|
// !raw e.g. map[string]map[string]InterfaceType, [][]InterfaceType etc
|
|
623
|
-
function recursiveGetDiscriminatorTypeName(item, raw) {
|
|
664
|
+
function recursiveGetDiscriminatorTypeName(modelType, item, raw) {
|
|
624
665
|
// when raw is true, stop recursing at the level before the leaf schema
|
|
625
666
|
if (item.kind === 'slice') {
|
|
626
667
|
if (!raw || item.elementType.kind !== 'interface') {
|
|
627
|
-
return `[]${recursiveGetDiscriminatorTypeName(item.elementType, raw)}`;
|
|
668
|
+
return `[]${recursiveGetDiscriminatorTypeName(modelType, item.elementType, raw)}`;
|
|
628
669
|
}
|
|
629
670
|
}
|
|
630
671
|
else if (item.kind === 'map') {
|
|
631
672
|
if (!raw || item.valueType.kind !== 'interface') {
|
|
632
|
-
return `map[string]${recursiveGetDiscriminatorTypeName(item.valueType, raw)}`;
|
|
673
|
+
return `map[string]${recursiveGetDiscriminatorTypeName(modelType, item.valueType, raw)}`;
|
|
633
674
|
}
|
|
634
675
|
}
|
|
635
676
|
if (raw) {
|
|
636
677
|
return 'json.RawMessage';
|
|
637
678
|
}
|
|
638
|
-
return go.getTypeDeclaration(item);
|
|
679
|
+
return go.getTypeDeclaration(item, modelType.pkg);
|
|
639
680
|
}
|
|
640
|
-
|
|
641
|
-
|
|
681
|
+
/**
|
|
682
|
+
* recursively constructs the text to populate a nested discriminator
|
|
683
|
+
*
|
|
684
|
+
* @param modelType the type that contains item
|
|
685
|
+
* @param item the type for which to create the population
|
|
686
|
+
* @param receiver the name of the receiver for the method to contain the expression
|
|
687
|
+
* @param rawSrc contains the raw unmarshaled JSON source
|
|
688
|
+
* @param dest the variable that will contain the result of the expression
|
|
689
|
+
* @param indent the current level of indentation (increases with each recursive call)
|
|
690
|
+
* @param nesting the current level of nesting (increments with each recursive call)
|
|
691
|
+
* @returns the text populating the discriminator
|
|
692
|
+
*/
|
|
693
|
+
function recursivePopulateDiscriminator(modelType, item, receiver, rawSrc, dest, indent, nesting) {
|
|
642
694
|
let text = '';
|
|
643
695
|
let interfaceName = '';
|
|
644
696
|
let targetType = '';
|
|
@@ -646,50 +698,57 @@ function recursivePopulateDiscriminator(item, receiver, rawSrc, dest, indent, ne
|
|
|
646
698
|
if (item.elementType.kind !== 'interface') {
|
|
647
699
|
if (nesting > 1) {
|
|
648
700
|
// at nestling level 1, the destination var was already created in generateDiscriminatorUnmarshaller()
|
|
649
|
-
text += `${indent}${dest} = make(${recursiveGetDiscriminatorTypeName(item, false)}, len(${rawSrc}))\n`;
|
|
701
|
+
text += `${indent}${dest} = make(${recursiveGetDiscriminatorTypeName(modelType, item, false)}, len(${rawSrc}))\n`;
|
|
650
702
|
}
|
|
651
703
|
text += `${indent}for i${nesting} := range ${rawSrc} {\n`;
|
|
652
704
|
rawSrc = `${rawSrc}[i${nesting}]`; // source becomes each element in the source slice
|
|
653
705
|
dest = `${dest}[i${nesting}]`; // update destination to each element in the destination slice
|
|
654
|
-
text += recursivePopulateDiscriminator(item.elementType, receiver, rawSrc, dest, indent + '\t', nesting + 1);
|
|
706
|
+
text += recursivePopulateDiscriminator(modelType, item.elementType, receiver, rawSrc, dest, indent + '\t', nesting + 1);
|
|
655
707
|
text += `${indent}}\n`;
|
|
656
708
|
return text;
|
|
657
709
|
}
|
|
658
710
|
// we're at leaf node - 1, so get the interface from the element's type
|
|
659
|
-
interfaceName = go.getTypeDeclaration(item.elementType);
|
|
711
|
+
interfaceName = go.getTypeDeclaration(item.elementType, modelType.pkg);
|
|
660
712
|
targetType = 'Array';
|
|
661
713
|
}
|
|
662
714
|
else if (item.kind === 'map') {
|
|
663
715
|
if (item.valueType.kind !== 'interface') {
|
|
664
716
|
if (nesting > 1) {
|
|
665
717
|
// at nestling level 1, the destination var was already created in generateDiscriminatorUnmarshaller()
|
|
666
|
-
text += `${indent}${dest} = ${recursiveGetDiscriminatorTypeName(item, false)}{}\n`;
|
|
718
|
+
text += `${indent}${dest} = ${recursiveGetDiscriminatorTypeName(modelType, item, false)}{}\n`;
|
|
667
719
|
}
|
|
668
720
|
text += `${indent}for k${nesting}, v${nesting} := range ${rawSrc} {\n`;
|
|
669
721
|
rawSrc = `v${nesting}`; // source becomes the current value in the source map
|
|
670
722
|
dest = `${dest}[k${nesting}]`; // update destination to the destination map's value for the current key
|
|
671
|
-
text += recursivePopulateDiscriminator(item.valueType, receiver, rawSrc, dest, indent + '\t', nesting + 1);
|
|
723
|
+
text += recursivePopulateDiscriminator(modelType, item.valueType, receiver, rawSrc, dest, indent + '\t', nesting + 1);
|
|
672
724
|
text += `${indent}}\n`;
|
|
673
725
|
return text;
|
|
674
726
|
}
|
|
675
727
|
// we're at leaf node - 1, so get the interface from the element's type
|
|
676
|
-
interfaceName = go.getTypeDeclaration(item.valueType);
|
|
728
|
+
interfaceName = go.getTypeDeclaration(item.valueType, modelType.pkg);
|
|
677
729
|
targetType = 'Map';
|
|
678
730
|
}
|
|
679
731
|
text += `${indent}${dest}, err = unmarshal${interfaceName}${targetType}(${rawSrc})\n`;
|
|
680
732
|
text += `${indent}if err != nil {\n${indent}\treturn fmt.Errorf("unmarshalling type %T: %v", ${receiver}, err)\n${indent}}\n`;
|
|
681
733
|
return text;
|
|
682
734
|
}
|
|
683
|
-
|
|
735
|
+
/**
|
|
736
|
+
* generates an implementation of MarshalXML for the provided type.
|
|
737
|
+
* the method impl is added to modelDef.SerDe.methods.
|
|
738
|
+
*
|
|
739
|
+
* @param modelDef the type for which to implement MarshalXML
|
|
740
|
+
* @param imports the import manager currently in scope
|
|
741
|
+
*/
|
|
742
|
+
function generateXMLMarshaller(modelDef, imports) {
|
|
684
743
|
// only needed for types with time.Time, maps, or where the XML name doesn't match the type name
|
|
685
744
|
const receiver = modelDef.receiverName();
|
|
686
|
-
const desc = `MarshalXML implements the xml.Marshaller interface for type ${modelDef.
|
|
687
|
-
let text = `func (${receiver} ${modelDef.
|
|
688
|
-
if (
|
|
689
|
-
text += `\tstart.Name.Local = "${
|
|
745
|
+
const desc = `MarshalXML implements the xml.Marshaller interface for type ${modelDef.Model.name}.`;
|
|
746
|
+
let text = `func (${receiver} ${modelDef.Model.name}) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {\n`;
|
|
747
|
+
if (modelDef.Model.xml?.wrapper) {
|
|
748
|
+
text += `\tstart.Name.Local = "${modelDef.Model.xml.wrapper}"\n`;
|
|
690
749
|
}
|
|
691
|
-
text += generateAliasType(
|
|
692
|
-
for (const field of
|
|
750
|
+
text += generateAliasType(modelDef.Model, receiver, true);
|
|
751
|
+
for (const field of modelDef.Model.fields) {
|
|
693
752
|
if (field.type.kind === 'slice') {
|
|
694
753
|
text += `\tif ${receiver}.${field.name} != nil {\n`;
|
|
695
754
|
text += `\t\taux.${field.name} = &${receiver}.${field.name}\n`;
|
|
@@ -710,16 +769,23 @@ function generateXMLMarshaller(modelType, modelDef, imports) {
|
|
|
710
769
|
text += '}\n\n';
|
|
711
770
|
modelDef.SerDe.methods.push({ name: 'MarshalXML', desc: desc, text: text });
|
|
712
771
|
}
|
|
713
|
-
|
|
772
|
+
/**
|
|
773
|
+
* generates an implementation of UnmarshalXML for the provided type.
|
|
774
|
+
* the method impl is added to modelDef.SerDe.methods.
|
|
775
|
+
*
|
|
776
|
+
* @param modelDef the type for which to implement UnmarshalXML
|
|
777
|
+
* @param imports the import manager currently in scope
|
|
778
|
+
*/
|
|
779
|
+
function generateXMLUnmarshaller(modelDef, imports) {
|
|
714
780
|
// non-polymorphic case, must be something with time.Time
|
|
715
781
|
const receiver = modelDef.receiverName();
|
|
716
|
-
const desc = `UnmarshalXML implements the xml.Unmarshaller interface for type ${modelDef.
|
|
717
|
-
let text = `func (${receiver} *${modelDef.
|
|
718
|
-
text += generateAliasType(
|
|
782
|
+
const desc = `UnmarshalXML implements the xml.Unmarshaller interface for type ${modelDef.Model.name}.`;
|
|
783
|
+
let text = `func (${receiver} *${modelDef.Model.name}) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {\n`;
|
|
784
|
+
text += generateAliasType(modelDef.Model, receiver, false);
|
|
719
785
|
text += '\tif err := dec.DecodeElement(aux, &start); err != nil {\n';
|
|
720
786
|
text += '\t\treturn err\n';
|
|
721
787
|
text += '\t}\n';
|
|
722
|
-
for (const field of
|
|
788
|
+
for (const field of modelDef.Model.fields) {
|
|
723
789
|
if (field.type.kind === 'time') {
|
|
724
790
|
text += `\tif aux.${field.name} != nil && !(*time.Time)(aux.${field.name}).IsZero() {\n`;
|
|
725
791
|
text += `\t\t${receiver}.${field.name} = (*time.Time)(aux.${field.name})\n\t}\n`;
|
|
@@ -740,13 +806,20 @@ function generateXMLUnmarshaller(modelType, modelDef, imports) {
|
|
|
740
806
|
text += '}\n\n';
|
|
741
807
|
modelDef.SerDe.methods.push({ name: 'UnmarshalXML', desc: desc, text: text });
|
|
742
808
|
}
|
|
743
|
-
|
|
809
|
+
/**
|
|
810
|
+
* generates an alias type used by custom XML marshaller/unmarshaller
|
|
811
|
+
*
|
|
812
|
+
* @param modelType the type for which to create the alias
|
|
813
|
+
* @param receiver the name of the receiver for the type's serde method
|
|
814
|
+
* @param forMarshal when true, indicates type is to be used in a marshaller (else an unmarshaller)
|
|
815
|
+
* @returns the text for an initialized type alias
|
|
816
|
+
*/
|
|
744
817
|
function generateAliasType(modelType, receiver, forMarshal) {
|
|
745
818
|
let text = `\ttype alias ${modelType.name}\n`;
|
|
746
819
|
text += '\taux := &struct {\n';
|
|
747
820
|
text += '\t\t*alias\n';
|
|
748
821
|
for (const field of values(modelType.fields)) {
|
|
749
|
-
const sn = getXMLSerialization(
|
|
822
|
+
const sn = getXMLSerialization(modelType, field);
|
|
750
823
|
if (field.type.kind === 'time') {
|
|
751
824
|
text += `\t\t${field.name} *${field.type.format} \`xml:"${sn}"\`\n`;
|
|
752
825
|
}
|
|
@@ -754,7 +827,7 @@ function generateAliasType(modelType, receiver, forMarshal) {
|
|
|
754
827
|
text += `\t\t${field.name} additionalProperties \`xml:"${sn}"\`\n`;
|
|
755
828
|
}
|
|
756
829
|
else if (field.type.kind === 'slice') {
|
|
757
|
-
text += `\t\t${field.name} *${go.getTypeDeclaration(field.type)} \`xml:"${sn}"\`\n`;
|
|
830
|
+
text += `\t\t${field.name} *${go.getTypeDeclaration(field.type, modelType.pkg)} \`xml:"${sn}"\`\n`;
|
|
758
831
|
}
|
|
759
832
|
else if (field.type.kind === 'encodedBytes') {
|
|
760
833
|
text += `\t\t${field.name} *string \`xml:"${sn}"\`\n`;
|
|
@@ -778,6 +851,7 @@ function generateAliasType(modelType, receiver, forMarshal) {
|
|
|
778
851
|
text += '\t}\n';
|
|
779
852
|
return text;
|
|
780
853
|
}
|
|
854
|
+
/** used to track which serde helpers and methods are required for a struct */
|
|
781
855
|
class SerDeInfo {
|
|
782
856
|
methods;
|
|
783
857
|
needsJSONPopulate;
|
|
@@ -794,27 +868,24 @@ class SerDeInfo {
|
|
|
794
868
|
this.needsJSONPopulateMultipart = false;
|
|
795
869
|
}
|
|
796
870
|
}
|
|
797
|
-
|
|
871
|
+
/** represents model definition as a Go struct */
|
|
798
872
|
class ModelDef {
|
|
799
|
-
|
|
873
|
+
Model;
|
|
800
874
|
Format;
|
|
801
|
-
Docs;
|
|
802
|
-
Fields;
|
|
803
875
|
SerDe;
|
|
804
876
|
Methods;
|
|
805
|
-
constructor(
|
|
806
|
-
this.
|
|
877
|
+
constructor(model, format) {
|
|
878
|
+
this.Model = model;
|
|
807
879
|
this.Format = format;
|
|
808
|
-
this.Docs = docs;
|
|
809
|
-
this.Fields = fields;
|
|
810
880
|
this.SerDe = new SerDeInfo();
|
|
811
881
|
this.Methods = new Array();
|
|
812
882
|
}
|
|
883
|
+
/** returns the text for the struct definition */
|
|
813
884
|
text() {
|
|
814
|
-
let text = helpers.formatDocComment(this.
|
|
815
|
-
text += `type ${this.
|
|
885
|
+
let text = helpers.formatDocComment(this.Model.docs);
|
|
886
|
+
text += `type ${this.Model.name} struct {\n`;
|
|
816
887
|
// group fields by required/optional/read-only in that order
|
|
817
|
-
this.
|
|
888
|
+
this.Model.fields.sort((lhs, rhs) => {
|
|
818
889
|
if ((lhs.annotations.required && !rhs.annotations.required) || (!lhs.annotations.readOnly && rhs.annotations.readOnly)) {
|
|
819
890
|
return -1;
|
|
820
891
|
}
|
|
@@ -827,7 +898,7 @@ class ModelDef {
|
|
|
827
898
|
});
|
|
828
899
|
// used to track when to add an extra \n between fields that have comments
|
|
829
900
|
let first = true;
|
|
830
|
-
for (const field of
|
|
901
|
+
for (const field of this.Model.fields) {
|
|
831
902
|
if (field.docs.summary || field.docs.description) {
|
|
832
903
|
if (!first) {
|
|
833
904
|
// add an extra new-line between fields IFF the field
|
|
@@ -836,7 +907,7 @@ class ModelDef {
|
|
|
836
907
|
}
|
|
837
908
|
text += helpers.formatDocComment(field.docs);
|
|
838
909
|
}
|
|
839
|
-
let typeName = go.getTypeDeclaration(field.type);
|
|
910
|
+
let typeName = go.getTypeDeclaration(field.type, this.Model.pkg);
|
|
840
911
|
if (field.type.kind === 'literal') {
|
|
841
912
|
// for constants we use the underlying type name
|
|
842
913
|
typeName = go.getLiteralTypeDeclaration(field.type.type);
|
|
@@ -846,7 +917,7 @@ class ModelDef {
|
|
|
846
917
|
serialization += ',omitempty';
|
|
847
918
|
}
|
|
848
919
|
else if (this.Format === 'XML') {
|
|
849
|
-
serialization = getXMLSerialization(
|
|
920
|
+
serialization = getXMLSerialization(this.Model, field);
|
|
850
921
|
}
|
|
851
922
|
let tag = '';
|
|
852
923
|
// only emit tags for XML; JSON uses custom marshallers/unmarshallers
|
|
@@ -859,12 +930,20 @@ class ModelDef {
|
|
|
859
930
|
text += '}\n\n';
|
|
860
931
|
return text;
|
|
861
932
|
}
|
|
933
|
+
/** returns the name to use for method receivers on this struct */
|
|
862
934
|
receiverName() {
|
|
863
|
-
const typeName = this.
|
|
935
|
+
const typeName = this.Model.name;
|
|
864
936
|
return typeName[0].toLowerCase();
|
|
865
937
|
}
|
|
866
938
|
}
|
|
867
|
-
|
|
939
|
+
/**
|
|
940
|
+
* returns the serialization options to use in the XML tag on a model field
|
|
941
|
+
*
|
|
942
|
+
* @param modelType the type that contains the field
|
|
943
|
+
* @param field the field for which to construct the tag's contents
|
|
944
|
+
* @returns the contents for the XML tag
|
|
945
|
+
*/
|
|
946
|
+
function getXMLSerialization(modelType, field) {
|
|
868
947
|
let serialization = field.serializedName;
|
|
869
948
|
// default to using the serialization name
|
|
870
949
|
if (field.xml?.name) {
|
|
@@ -882,7 +961,7 @@ export function getXMLSerialization(field, isResponseEnvelope) {
|
|
|
882
961
|
}
|
|
883
962
|
else if (field.type.kind === 'slice') {
|
|
884
963
|
// start with the serialized name of the element, preferring xml name if available
|
|
885
|
-
let inner = go.getTypeDeclaration(field.type.elementType);
|
|
964
|
+
let inner = go.getTypeDeclaration(field.type.elementType, modelType.pkg);
|
|
886
965
|
if (field.xml?.name) {
|
|
887
966
|
inner = field.xml.name;
|
|
888
967
|
}
|
|
@@ -906,7 +985,7 @@ export function getXMLSerialization(field, isResponseEnvelope) {
|
|
|
906
985
|
// </slideshow>
|
|
907
986
|
// arrays in the response type are handled slightly different as we
|
|
908
987
|
// unmarshal directly into them so no need to add the unwrapping.
|
|
909
|
-
if (field.xml?.wraps
|
|
988
|
+
if (field.xml?.wraps) {
|
|
910
989
|
serialization += `>${field.xml.wraps}`;
|
|
911
990
|
}
|
|
912
991
|
else {
|