@azure-tools/typespec-rust 0.32.0 → 0.34.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/dist/src/codegen/clients.d.ts.map +1 -1
- package/dist/src/codegen/clients.js +153 -131
- package/dist/src/codegen/clients.js.map +1 -1
- package/dist/src/codegen/codeGenerator.js +16 -16
- package/dist/src/codegen/codeGenerator.js.map +1 -1
- package/dist/src/codegen/context.d.ts +3 -3
- package/dist/src/codegen/context.d.ts.map +1 -1
- package/dist/src/codegen/context.js +5 -5
- package/dist/src/codegen/context.js.map +1 -1
- package/dist/src/codegen/docTests.d.ts.map +1 -1
- package/dist/src/codegen/docTests.js +2 -1
- package/dist/src/codegen/docTests.js.map +1 -1
- package/dist/src/codegen/enums.d.ts +5 -5
- package/dist/src/codegen/enums.d.ts.map +1 -1
- package/dist/src/codegen/enums.js +11 -8
- package/dist/src/codegen/enums.js.map +1 -1
- package/dist/src/codegen/headerTraits.d.ts.map +1 -1
- package/dist/src/codegen/headerTraits.js +7 -4
- package/dist/src/codegen/headerTraits.js.map +1 -1
- package/dist/src/codegen/helpers.d.ts +23 -0
- package/dist/src/codegen/helpers.d.ts.map +1 -1
- package/dist/src/codegen/helpers.js +39 -18
- package/dist/src/codegen/helpers.js.map +1 -1
- package/dist/src/codegen/mod.d.ts.map +1 -1
- package/dist/src/codegen/mod.js +3 -1
- package/dist/src/codegen/mod.js.map +1 -1
- package/dist/src/codegen/models.d.ts +4 -6
- package/dist/src/codegen/models.d.ts.map +1 -1
- package/dist/src/codegen/models.js +132 -68
- package/dist/src/codegen/models.js.map +1 -1
- package/dist/src/codegen/unions.d.ts +8 -6
- package/dist/src/codegen/unions.d.ts.map +1 -1
- package/dist/src/codegen/unions.js +142 -9
- package/dist/src/codegen/unions.js.map +1 -1
- package/dist/src/codegen/use.d.ts +2 -2
- package/dist/src/codegen/use.d.ts.map +1 -1
- package/dist/src/codegen/use.js +3 -5
- package/dist/src/codegen/use.js.map +1 -1
- package/dist/src/codemodel/client.d.ts +9 -1
- package/dist/src/codemodel/client.d.ts.map +1 -1
- package/dist/src/codemodel/client.js +2 -1
- package/dist/src/codemodel/client.js.map +1 -1
- package/dist/src/codemodel/crate.d.ts +1 -1
- package/dist/src/codemodel/crate.d.ts.map +1 -1
- package/dist/src/codemodel/types.d.ts +39 -6
- package/dist/src/codemodel/types.d.ts.map +1 -1
- package/dist/src/codemodel/types.js +25 -1
- package/dist/src/codemodel/types.js.map +1 -1
- package/dist/src/tcgcadapter/adapter.d.ts +5 -2
- package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
- package/dist/src/tcgcadapter/adapter.js +259 -170
- package/dist/src/tcgcadapter/adapter.js.map +1 -1
- package/dist/src/tcgcadapter/naming.d.ts.map +1 -1
- package/dist/src/tcgcadapter/naming.js +2 -2
- package/dist/src/tcgcadapter/naming.js.map +1 -1
- package/dist/src/utils/utils.d.ts +99 -0
- package/dist/src/utils/utils.d.ts.map +1 -0
- package/dist/src/utils/utils.js +288 -0
- package/dist/src/utils/utils.js.map +1 -0
- package/package.json +16 -19
- package/dist/src/shared/shared.d.ts +0 -29
- package/dist/src/shared/shared.d.ts.map +0 -1
- package/dist/src/shared/shared.js +0 -109
- package/dist/src/shared/shared.js.map +0 -1
|
@@ -3,12 +3,10 @@
|
|
|
3
3
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
// cspell: ignore addl responseheader subclients lropaging
|
|
6
|
-
import * as codegen from '@azure-tools/codegen';
|
|
7
|
-
import { values } from '@azure-tools/linq';
|
|
8
6
|
import * as tsp from '@typespec/compiler';
|
|
9
7
|
import * as helpers from './helpers.js';
|
|
10
8
|
import * as naming from './naming.js';
|
|
11
|
-
import * as
|
|
9
|
+
import * as utils from '../utils/utils.js';
|
|
12
10
|
import * as tcgc from '@azure-tools/typespec-client-generator-core';
|
|
13
11
|
import * as rust from '../codemodel/index.js';
|
|
14
12
|
import { FinalStateValue } from "@azure-tools/typespec-azure-core";
|
|
@@ -75,7 +73,7 @@ export class Adapter {
|
|
|
75
73
|
this.adaptTypes();
|
|
76
74
|
this.adaptClients();
|
|
77
75
|
// marker models don't require serde so exclude them from the check
|
|
78
|
-
if (this.crate.enums.length > 0 ||
|
|
76
|
+
if (this.crate.enums.length > 0 || this.crate.models.some(e => e.kind === 'model')) {
|
|
79
77
|
this.crate.addDependency(new rust.CrateDependency('serde'));
|
|
80
78
|
}
|
|
81
79
|
if (this.crate.clients.length > 0 || this.crate.enums.length > 0 || this.crate.models.length > 0 || this.crate.unions.length > 0) {
|
|
@@ -137,6 +135,14 @@ export class Adapter {
|
|
|
137
135
|
processedTypes.add(model.name);
|
|
138
136
|
}
|
|
139
137
|
// END workaround
|
|
138
|
+
if (model.discriminatedSubtypes) {
|
|
139
|
+
const rustUnion = this.getDiscriminatedUnion(model);
|
|
140
|
+
this.crate.unions.push(rustUnion);
|
|
141
|
+
// we don't want to add the base type to the array
|
|
142
|
+
// of models to emit as we hijack its name to be used
|
|
143
|
+
// for the associated tagged enum type.
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
140
146
|
if (model.external) {
|
|
141
147
|
this.getExternalType(model.external);
|
|
142
148
|
}
|
|
@@ -153,8 +159,8 @@ export class Adapter {
|
|
|
153
159
|
* @returns a Rust enum
|
|
154
160
|
*/
|
|
155
161
|
getEnum(sdkEnum) {
|
|
156
|
-
var _a, _b;
|
|
157
|
-
const enumName =
|
|
162
|
+
var _a, _b, _c;
|
|
163
|
+
const enumName = utils.deconstruct(sdkEnum.name).map((each) => utils.capitalize(each)).join('');
|
|
158
164
|
let rustEnum = this.types.get(enumName);
|
|
159
165
|
if (rustEnum) {
|
|
160
166
|
return rustEnum;
|
|
@@ -185,17 +191,43 @@ export class Adapter {
|
|
|
185
191
|
rustEnum = new rust.Enum(enumName, adaptAccessFlags(sdkEnum.access), !sdkEnum.isFixed, enumType);
|
|
186
192
|
rustEnum.docs = this.adaptDocs(sdkEnum.summary, sdkEnum.doc);
|
|
187
193
|
this.types.set(enumName, rustEnum);
|
|
194
|
+
// the first pass is to detect any enum values that coalesce into duplicate entries
|
|
188
195
|
const rustEnumNameToSdkEnumName = new Map();
|
|
189
196
|
for (const value of sdkEnum.values) {
|
|
190
197
|
const enumValueName = naming.fixUpEnumValueName(value);
|
|
191
|
-
|
|
192
|
-
if (existingMapping) {
|
|
193
|
-
|
|
198
|
+
let existingMapping = rustEnumNameToSdkEnumName.get(enumValueName);
|
|
199
|
+
if (!existingMapping) {
|
|
200
|
+
existingMapping = new Array();
|
|
201
|
+
rustEnumNameToSdkEnumName.set(enumValueName, existingMapping);
|
|
202
|
+
}
|
|
203
|
+
existingMapping.push(value);
|
|
204
|
+
}
|
|
205
|
+
// now adapt the values, renaming any collisions as required and reporting diagnostics
|
|
206
|
+
let groupCounter = 1;
|
|
207
|
+
for (const entry of rustEnumNameToSdkEnumName.entries()) {
|
|
208
|
+
const enumValueName = entry[0];
|
|
209
|
+
const enumValues = entry[1];
|
|
210
|
+
if (enumValues.length === 1) {
|
|
211
|
+
const rustEnumValue = new rust.EnumValue(enumValueName, rustEnum, enumValues[0].value);
|
|
212
|
+
rustEnumValue.docs = this.adaptDocs(enumValues[0].summary, enumValues[0].doc);
|
|
213
|
+
rustEnum.values.push(rustEnumValue);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
this.ctx.program.reportDiagnostic({
|
|
217
|
+
code: 'NameCollision',
|
|
218
|
+
severity: 'warning',
|
|
219
|
+
message: `enum values ${enumValues.map((each) => `"${each.value}"`).join(', ')} coalesce into the same name ${enumValueName}`,
|
|
220
|
+
target: (_c = (_b = sdkEnum.__raw) === null || _b === void 0 ? void 0 : _b.node) !== null && _c !== void 0 ? _c : tsp.NoTarget,
|
|
221
|
+
});
|
|
222
|
+
for (let i = 0; i < enumValues.length; ++i) {
|
|
223
|
+
const enumValue = enumValues[i];
|
|
224
|
+
const collidingEnumValueName = `COLLIDES_GRP${groupCounter}_ID${i + 1}_${enumValueName}`;
|
|
225
|
+
const rustEnumValue = new rust.EnumValue(collidingEnumValueName, rustEnum, enumValue.value);
|
|
226
|
+
rustEnumValue.docs = this.adaptDocs(enumValue.summary, enumValue.doc);
|
|
227
|
+
rustEnum.values.push(rustEnumValue);
|
|
228
|
+
}
|
|
229
|
+
++groupCounter;
|
|
194
230
|
}
|
|
195
|
-
rustEnumNameToSdkEnumName.set(enumValueName, value.name);
|
|
196
|
-
const rustEnumValue = new rust.EnumValue(enumValueName, rustEnum, value.value);
|
|
197
|
-
rustEnumValue.docs = this.adaptDocs(value.summary, value.doc);
|
|
198
|
-
rustEnum.values.push(rustEnumValue);
|
|
199
231
|
}
|
|
200
232
|
return rustEnum;
|
|
201
233
|
}
|
|
@@ -251,7 +283,7 @@ export class Adapter {
|
|
|
251
283
|
}
|
|
252
284
|
// remove any non-word characters from the name.
|
|
253
285
|
// the most common case is something like Foo.Bar.Baz
|
|
254
|
-
modelName =
|
|
286
|
+
modelName = utils.capitalize(modelName).replace(/\W/g, '');
|
|
255
287
|
let rustModel = this.types.get(modelName);
|
|
256
288
|
if (rustModel) {
|
|
257
289
|
return rustModel;
|
|
@@ -261,33 +293,43 @@ export class Adapter {
|
|
|
261
293
|
if (!stack) {
|
|
262
294
|
stack = new Array();
|
|
263
295
|
}
|
|
264
|
-
stack.push(modelName);
|
|
265
296
|
let modelFlags = rust.ModelFlags.Unspecified;
|
|
266
297
|
if ((model.usage & tcgc.UsageFlags.Input) === tcgc.UsageFlags.Input) {
|
|
267
298
|
modelFlags |= rust.ModelFlags.Input;
|
|
268
299
|
}
|
|
269
|
-
|
|
300
|
+
// include error and LRO polling types as output types
|
|
301
|
+
if ((model.usage & tcgc.UsageFlags.Output) === tcgc.UsageFlags.Output ||
|
|
302
|
+
(model.usage & tcgc.UsageFlags.Exception) === tcgc.UsageFlags.Exception ||
|
|
303
|
+
(model.usage & tcgc.UsageFlags.LroPolling) === tcgc.UsageFlags.LroPolling) {
|
|
270
304
|
modelFlags |= rust.ModelFlags.Output;
|
|
271
305
|
}
|
|
272
306
|
rustModel = new rust.Model(modelName, model.access === 'internal' ? 'pubCrate' : 'pub', modelFlags);
|
|
273
307
|
rustModel.docs = this.adaptDocs(model.summary, model.doc);
|
|
274
308
|
rustModel.xmlName = getXMLName(model.decorators);
|
|
275
309
|
this.types.set(modelName, rustModel);
|
|
310
|
+
stack.push(rustModel);
|
|
276
311
|
// aggregate the properties from the provided type and its parent types
|
|
277
312
|
const allProps = new Array();
|
|
278
313
|
for (const prop of model.properties) {
|
|
314
|
+
if (prop.discriminator && !model.discriminatedSubtypes) {
|
|
315
|
+
rustModel.flags |= rust.ModelFlags.PolymorphicSubtype;
|
|
316
|
+
}
|
|
279
317
|
allProps.push(prop);
|
|
280
318
|
}
|
|
281
319
|
let addlProps = model.additionalProperties;
|
|
282
320
|
let parent = model.baseModel;
|
|
283
321
|
while (parent) {
|
|
284
322
|
for (const parentProp of parent.properties) {
|
|
285
|
-
|
|
286
|
-
if (exists) {
|
|
323
|
+
if (allProps.find(p => p.name === parentProp.name)) {
|
|
287
324
|
// don't add the duplicate. the TS compiler has better enforcement than OpenAPI
|
|
288
325
|
// to ensure that duplicate fields with different types aren't added.
|
|
289
326
|
continue;
|
|
290
327
|
}
|
|
328
|
+
else if (parentProp.discriminator) {
|
|
329
|
+
// we don't propagate the discriminator to the child
|
|
330
|
+
// types as it's not useful (or necessary)
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
291
333
|
allProps.push(parentProp);
|
|
292
334
|
}
|
|
293
335
|
// propagate parent's additional properties if we don't yet have any.
|
|
@@ -316,13 +358,13 @@ export class Adapter {
|
|
|
316
358
|
throw new AdapterError('UnsupportedTsp', `model property kind ${(_c = property.__raw) === null || _c === void 0 ? void 0 : _c.kind} NYI`, (_d = property.__raw) === null || _d === void 0 ? void 0 : _d.node);
|
|
317
359
|
}
|
|
318
360
|
}
|
|
319
|
-
const structField = this.getModelField(property, rustModel.visibility, stack);
|
|
361
|
+
const structField = this.getModelField(model.usage, property, rustModel.visibility, stack);
|
|
320
362
|
rustModel.fields.push(structField);
|
|
321
363
|
}
|
|
322
364
|
if (addlProps) {
|
|
323
365
|
const addlPropsType = this.getHashMap(this.typeToWireType(this.getType(addlProps)));
|
|
324
366
|
const addlPropsField = new rust.ModelAdditionalProperties('additional_properties', 'pub', this.getOptionType(addlPropsType));
|
|
325
|
-
addlPropsField.docs.summary = '
|
|
367
|
+
addlPropsField.docs.summary = 'Contains unnamed additional properties.';
|
|
326
368
|
rustModel.fields.push(addlPropsField);
|
|
327
369
|
}
|
|
328
370
|
stack.pop();
|
|
@@ -334,55 +376,100 @@ export class Adapter {
|
|
|
334
376
|
* @param union the tcgc union to convert
|
|
335
377
|
* @returns a Rust union
|
|
336
378
|
*/
|
|
337
|
-
getDiscriminatedUnion(
|
|
338
|
-
var _a, _b, _c, _d;
|
|
339
|
-
if (
|
|
340
|
-
throw new AdapterError('InternalError', 'unnamed union', (_a =
|
|
341
|
-
}
|
|
342
|
-
const unionName =
|
|
343
|
-
|
|
379
|
+
getDiscriminatedUnion(src) {
|
|
380
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
381
|
+
if (src.name.length === 0) {
|
|
382
|
+
throw new AdapterError('InternalError', 'unnamed union', (_a = src.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
383
|
+
}
|
|
384
|
+
const unionName = utils.deconstruct(src.name).map((each) => utils.capitalize(each)).join('');
|
|
385
|
+
const keyName = `discriminated-union-${unionName}`;
|
|
386
|
+
let rustUnion = this.types.get(keyName);
|
|
344
387
|
if (rustUnion) {
|
|
345
388
|
return rustUnion;
|
|
346
389
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
if (
|
|
364
|
-
|
|
390
|
+
switch (src.kind) {
|
|
391
|
+
case 'model': {
|
|
392
|
+
if (!src.discriminatedSubtypes) {
|
|
393
|
+
// we should have verified this earlier.
|
|
394
|
+
// having this check means the compiler won't bark
|
|
395
|
+
// at us when accessing src.discriminatedSubtypes
|
|
396
|
+
throw new AdapterError('InternalError', 'getDiscriminatedUnion called for non-polymorphic model', (_b = src.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
397
|
+
}
|
|
398
|
+
// find the discriminator field
|
|
399
|
+
let discriminatorProperty;
|
|
400
|
+
for (const prop of src.properties) {
|
|
401
|
+
if (prop.kind === 'property' && prop.discriminator) {
|
|
402
|
+
discriminatorProperty = prop;
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (!discriminatorProperty) {
|
|
407
|
+
throw new AdapterError('InternalError', `failed to find discriminator field for type ${src.name}`, (_c = src.__raw) === null || _c === void 0 ? void 0 : _c.node);
|
|
408
|
+
}
|
|
409
|
+
rustUnion = new rust.DiscriminatedUnion(unionName, adaptAccessFlags(src.access), discriminatorProperty.name);
|
|
410
|
+
if (discriminatorProperty.type.kind === 'enum' && discriminatorProperty.type.isFixed) {
|
|
411
|
+
// when the DU is a fixed enum, it means we don't fall back to the
|
|
412
|
+
// base type when the discriminator value is unknown or missing.
|
|
413
|
+
rustUnion.unionKind = new rust.DiscriminatedUnionSealed();
|
|
365
414
|
}
|
|
366
415
|
else {
|
|
367
|
-
|
|
416
|
+
rustUnion.unionKind = new rust.DiscriminatedUnionBase(this.getModel(src));
|
|
368
417
|
}
|
|
418
|
+
for (const subType of Object.values(src.discriminatedSubtypes)) {
|
|
419
|
+
if (!subType.discriminatorValue) {
|
|
420
|
+
throw new AdapterError('InternalError', `model ${subType.name} has no discriminator value`, (_d = subType.__raw) === null || _d === void 0 ? void 0 : _d.node);
|
|
421
|
+
}
|
|
422
|
+
const unionMemberType = this.getModel(subType);
|
|
423
|
+
const rustUnionMember = new rust.DiscriminatedUnionMember(unionMemberType, subType.discriminatorValue);
|
|
424
|
+
rustUnion.members.push(rustUnionMember);
|
|
425
|
+
}
|
|
426
|
+
break;
|
|
369
427
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
428
|
+
case 'union': {
|
|
429
|
+
if (!src.discriminatedOptions) {
|
|
430
|
+
// we should have verified this earlier.
|
|
431
|
+
// having this check means the compiler won't bark
|
|
432
|
+
// at us when accessing src.discriminatedOptions
|
|
433
|
+
throw new AdapterError('InternalError', 'getDiscriminatedUnion called for non-discriminated union', (_e = src.__raw) === null || _e === void 0 ? void 0 : _e.node);
|
|
434
|
+
}
|
|
435
|
+
rustUnion = new rust.DiscriminatedUnion(unionName, adaptAccessFlags(src.access), src.discriminatedOptions.discriminatorPropertyName);
|
|
436
|
+
if (src.discriminatedOptions.envelopePropertyName) {
|
|
437
|
+
rustUnion.unionKind = new rust.DiscriminatedUnionEnvelope(src.discriminatedOptions.envelopePropertyName);
|
|
438
|
+
}
|
|
439
|
+
// TODO: remove when https://github.com/microsoft/typespec/issues/8455 is complete
|
|
440
|
+
const discriminatorValues = new Map();
|
|
441
|
+
const rawUnion = src.__raw;
|
|
442
|
+
if (rawUnion) {
|
|
443
|
+
for (const [variantKey, variant] of rawUnion.variants) {
|
|
444
|
+
const discriminatorValue = typeof variantKey === 'string' ? variantKey : variantKey.toString();
|
|
445
|
+
if (variant.type.kind === 'Model') {
|
|
446
|
+
discriminatorValues.set(variant.type.name, discriminatorValue);
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
throw new AdapterError('InternalError', `unexpected kind ${variant.type.kind} for discriminated union member`, rawUnion);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
// END WORKAROUND
|
|
454
|
+
for (const unionMember of src.variantTypes) {
|
|
455
|
+
if (unionMember.kind !== 'model') {
|
|
456
|
+
throw new AdapterError('UnsupportedTsp', `non-model union member kind ${unionMember.kind}`, (_f = unionMember.__raw) === null || _f === void 0 ? void 0 : _f.node);
|
|
457
|
+
}
|
|
458
|
+
// TODO: use unionMember.discriminatorValue
|
|
459
|
+
const discriminatorValue = discriminatorValues.get(unionMember.name);
|
|
460
|
+
if (!discriminatorValue) {
|
|
461
|
+
throw new AdapterError('InternalError', `didn't find discriminant value for type ${unionMember.name}`, (_g = unionMember.__raw) === null || _g === void 0 ? void 0 : _g.node);
|
|
462
|
+
}
|
|
463
|
+
const unionMemberType = this.getModel(unionMember);
|
|
464
|
+
const rustUnionMember = new rust.DiscriminatedUnionMember(unionMemberType, discriminatorValue);
|
|
465
|
+
rustUnionMember.docs = this.adaptDocs(unionMember.summary, unionMember.doc);
|
|
466
|
+
rustUnion.members.push(rustUnionMember);
|
|
467
|
+
}
|
|
468
|
+
break;
|
|
380
469
|
}
|
|
381
|
-
const unionMemberType = this.getModel(unionMember);
|
|
382
|
-
const rustUnionMember = new rust.DiscriminatedUnionMember(unionMemberType, discriminatorValue);
|
|
383
|
-
rustUnionMember.docs = this.adaptDocs(unionMember.summary, unionMember.doc);
|
|
384
|
-
rustUnion.members.push(rustUnionMember);
|
|
385
470
|
}
|
|
471
|
+
rustUnion.docs = this.adaptDocs(src.summary, src.doc);
|
|
472
|
+
this.types.set(keyName, rustUnion);
|
|
386
473
|
return rustUnion;
|
|
387
474
|
}
|
|
388
475
|
getSerializedPropertyName(property) {
|
|
@@ -392,30 +479,58 @@ export class Adapter {
|
|
|
392
479
|
/**
|
|
393
480
|
* converts a tcgc model property to a model field
|
|
394
481
|
*
|
|
482
|
+
* @param modelFlags the flags for the model to which the field belongs
|
|
395
483
|
* @param property the tcgc model property to convert
|
|
396
484
|
* @param modelVisibility the visibility of the model that contains the property
|
|
397
|
-
* @param stack is a stack of
|
|
485
|
+
* @param stack is a stack of types used to detect recursive type definitions
|
|
398
486
|
* @returns a Rust model field
|
|
399
487
|
*/
|
|
400
|
-
getModelField(property, modelVisibility, stack) {
|
|
488
|
+
getModelField(modelFlags, property, modelVisibility, stack) {
|
|
401
489
|
var _a;
|
|
490
|
+
const fieldNeedsBoxing = function (fieldType) {
|
|
491
|
+
if (fieldType.kind === 'model' && stack.includes(fieldType)) {
|
|
492
|
+
// if the field's type is a model and it's in the type stack then
|
|
493
|
+
// box it. this is to avoid infinitely recursive type definitions.
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
else if (fieldType.kind === 'discriminatedUnion') {
|
|
497
|
+
// if the field is a discriminated union whose type
|
|
498
|
+
// is part of the same union then box it.
|
|
499
|
+
for (const member of fieldType.members) {
|
|
500
|
+
if (stack.includes(member.type)) {
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return false;
|
|
506
|
+
};
|
|
402
507
|
let fieldType = this.getType(property.type, stack);
|
|
403
|
-
|
|
404
|
-
// box it. this is to avoid infinitely recursive type definitions.
|
|
405
|
-
if (fieldType.kind === 'model' && stack.includes(fieldType.name)) {
|
|
508
|
+
if (fieldNeedsBoxing(fieldType)) {
|
|
406
509
|
fieldType = this.getBoxType(fieldType);
|
|
407
510
|
}
|
|
408
|
-
// for
|
|
409
|
-
|
|
511
|
+
// for non-spread models each field is always an Option<T>.
|
|
512
|
+
// NOTE: models can be used for both spread and I/O, so when
|
|
513
|
+
// restricting for spread it must be ONLY used for spread.
|
|
514
|
+
const notSpreadOnly = (modelFlags & tcgc.UsageFlags.Spread) === 0 || (modelFlags & tcgc.UsageFlags.Input) || (modelFlags & tcgc.UsageFlags.Output);
|
|
515
|
+
if (notSpreadOnly || property.optional) {
|
|
410
516
|
fieldType = this.getOptionType(fieldType.kind === 'box' ? fieldType : this.typeToWireType(fieldType));
|
|
411
517
|
}
|
|
412
518
|
const serializedName = (_a = this.getSerializedPropertyName(property)) !== null && _a !== void 0 ? _a : property.name;
|
|
413
|
-
const modelField = new rust.ModelField(naming.getEscapedReservedName(snakeCaseName(property.name), 'prop'), serializedName, modelVisibility, fieldType, property.optional);
|
|
519
|
+
const modelField = new rust.ModelField(naming.getEscapedReservedName(utils.snakeCaseName(property.name), 'prop'), serializedName, modelVisibility, fieldType, property.optional);
|
|
414
520
|
modelField.docs = this.adaptDocs(property.summary, property.doc);
|
|
415
521
|
// if this is a literal, add a doc comment explaining its behavior
|
|
416
|
-
const unwrappedType =
|
|
417
|
-
if (unwrappedType.kind === 'literal') {
|
|
418
|
-
|
|
522
|
+
const unwrappedType = utils.unwrapOption(fieldType);
|
|
523
|
+
if (unwrappedType.kind === 'enumValue' || unwrappedType.kind === 'literal') {
|
|
524
|
+
let constValue;
|
|
525
|
+
switch (unwrappedType.kind) {
|
|
526
|
+
case 'enumValue':
|
|
527
|
+
constValue = `${unwrappedType.type.name}::${unwrappedType.name}`;
|
|
528
|
+
break;
|
|
529
|
+
case 'literal':
|
|
530
|
+
constValue = unwrappedType.value;
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
const literalDoc = `${modelField.optional ? 'When Some, field' : 'Field'} has constant value ${constValue}. Any specified value will be ignored.`;
|
|
419
534
|
if (!modelField.docs.description) {
|
|
420
535
|
modelField.docs.description = '';
|
|
421
536
|
}
|
|
@@ -437,17 +552,23 @@ export class Adapter {
|
|
|
437
552
|
if (property.decorators.find((decorator) => decorator.name === 'Azure.ClientGenerator.Core.@deserializeEmptyStringAsNull') !== undefined) {
|
|
438
553
|
modelField.flags |= rust.ModelFieldFlags.DeserializeEmptyStringAsNone;
|
|
439
554
|
}
|
|
555
|
+
else if (property.kind === 'property' && property.discriminator) {
|
|
556
|
+
modelField.flags |= rust.ModelFieldFlags.Discriminator;
|
|
557
|
+
}
|
|
440
558
|
return modelField;
|
|
441
559
|
}
|
|
442
560
|
/**
|
|
443
561
|
* converts a tcgc type to a Rust type
|
|
444
562
|
*
|
|
445
563
|
* @param type the tcgc type to convert
|
|
446
|
-
* @param stack is a stack of
|
|
564
|
+
* @param stack is a stack of types used to detect recursive type definitions
|
|
447
565
|
* @returns the adapted Rust type
|
|
448
566
|
*/
|
|
449
567
|
getType(type, stack) {
|
|
450
568
|
var _a, _b, _c;
|
|
569
|
+
if (type.external) {
|
|
570
|
+
return this.getExternalType(type.external);
|
|
571
|
+
}
|
|
451
572
|
const getDateTimeEncoding = (encoding) => {
|
|
452
573
|
var _a;
|
|
453
574
|
switch (encoding) {
|
|
@@ -523,6 +644,9 @@ export class Adapter {
|
|
|
523
644
|
if (type.external) {
|
|
524
645
|
return this.getExternalType(type.external);
|
|
525
646
|
}
|
|
647
|
+
else if (type.discriminatedSubtypes) {
|
|
648
|
+
return this.getDiscriminatedUnion(type);
|
|
649
|
+
}
|
|
526
650
|
return this.getModel(type, stack);
|
|
527
651
|
case 'endpoint':
|
|
528
652
|
case 'plainDate':
|
|
@@ -569,16 +693,8 @@ export class Adapter {
|
|
|
569
693
|
}
|
|
570
694
|
return safeint;
|
|
571
695
|
}
|
|
572
|
-
case 'unknown':
|
|
573
|
-
|
|
574
|
-
let anyType = this.types.get(keyName);
|
|
575
|
-
if (anyType) {
|
|
576
|
-
return anyType;
|
|
577
|
-
}
|
|
578
|
-
anyType = new rust.JsonValue(this.crate);
|
|
579
|
-
this.types.set(keyName, anyType);
|
|
580
|
-
return anyType;
|
|
581
|
-
}
|
|
696
|
+
case 'unknown':
|
|
697
|
+
return this.getUnknownValue();
|
|
582
698
|
case 'utcDateTime': {
|
|
583
699
|
const encoding = getDateTimeEncoding(type.encode);
|
|
584
700
|
const keyName = `offsetDateTime-${encoding}-utc`;
|
|
@@ -632,6 +748,17 @@ export class Adapter {
|
|
|
632
748
|
this.types.set(keyName, hashmapType);
|
|
633
749
|
return hashmapType;
|
|
634
750
|
}
|
|
751
|
+
/** returns an azure_core::Value */
|
|
752
|
+
getUnknownValue() {
|
|
753
|
+
const keyName = 'jsonValue';
|
|
754
|
+
let anyType = this.types.get(keyName);
|
|
755
|
+
if (anyType) {
|
|
756
|
+
return anyType;
|
|
757
|
+
}
|
|
758
|
+
anyType = new rust.JsonValue(this.crate);
|
|
759
|
+
this.types.set(keyName, anyType);
|
|
760
|
+
return anyType;
|
|
761
|
+
}
|
|
635
762
|
/** returns an Option<T> where T is specified in type */
|
|
636
763
|
getOptionType(type) {
|
|
637
764
|
const typeKey = recursiveKeyName('option', type);
|
|
@@ -827,7 +954,7 @@ export class Adapter {
|
|
|
827
954
|
* @returns a Rust client
|
|
828
955
|
*/
|
|
829
956
|
recursiveAdaptClient(client, parent) {
|
|
830
|
-
var _a, _b, _c, _d;
|
|
957
|
+
var _a, _b, _c, _d, _e;
|
|
831
958
|
let clientName = client.name;
|
|
832
959
|
// NOTE: if the client has the @clientName decorator applied then use that verbatim
|
|
833
960
|
if (parent && !hasClientNameDecorator(client.decorators)) {
|
|
@@ -874,7 +1001,8 @@ export class Adapter {
|
|
|
874
1001
|
(function (AuthTypes) {
|
|
875
1002
|
AuthTypes[AuthTypes["Default"] = 0] = "Default";
|
|
876
1003
|
AuthTypes[AuthTypes["NoAuth"] = 1] = "NoAuth";
|
|
877
|
-
AuthTypes[AuthTypes["
|
|
1004
|
+
AuthTypes[AuthTypes["OAuth2"] = 2] = "OAuth2";
|
|
1005
|
+
AuthTypes[AuthTypes["WithAuth"] = 4] = "WithAuth";
|
|
878
1006
|
})(AuthTypes || (AuthTypes = {}));
|
|
879
1007
|
let authType = AuthTypes.Default;
|
|
880
1008
|
/**
|
|
@@ -892,8 +1020,13 @@ export class Adapter {
|
|
|
892
1020
|
case 'noAuth':
|
|
893
1021
|
return AuthTypes.NoAuth;
|
|
894
1022
|
case 'oauth2': {
|
|
895
|
-
|
|
896
|
-
|
|
1023
|
+
if ((authType & AuthTypes.OAuth2) === 0) {
|
|
1024
|
+
// tsp can describe multiple oauth2 credential flow in a union.
|
|
1025
|
+
// since each flow is implicitly handled via the credential, we
|
|
1026
|
+
// only need to emit one ctor for the oauth2 type.
|
|
1027
|
+
constructable.constructors.push(this.createTokenCredentialCtor(rustClient, cred));
|
|
1028
|
+
}
|
|
1029
|
+
return AuthTypes.OAuth2;
|
|
897
1030
|
}
|
|
898
1031
|
default:
|
|
899
1032
|
this.ctx.program.reportDiagnostic({
|
|
@@ -914,9 +1047,7 @@ export class Adapter {
|
|
|
914
1047
|
authType |= processCredential(rustClient, param, param.type.scheme, rustClient.constructable);
|
|
915
1048
|
break;
|
|
916
1049
|
case 'union': {
|
|
917
|
-
const variantKinds = new Array();
|
|
918
1050
|
for (const variantType of param.type.variantTypes) {
|
|
919
|
-
variantKinds.push(variantType.scheme.type);
|
|
920
1051
|
// if OAuth2 is specified then emit that and skip any unsupported ones.
|
|
921
1052
|
// this prevents emitting the with_no_credential constructor in cases
|
|
922
1053
|
// where it might not actually be supported.
|
|
@@ -947,11 +1078,13 @@ export class Adapter {
|
|
|
947
1078
|
// note that the types of the param and the field are different.
|
|
948
1079
|
// we default to "endpoint" and will use the defined name IFF
|
|
949
1080
|
// it has the @clientName decorator applied
|
|
950
|
-
const endpointName = hasClientNameDecorator(templateArg.decorators) ? snakeCaseName(templateArg.name) : 'endpoint';
|
|
1081
|
+
const endpointName = hasClientNameDecorator(templateArg.decorators) ? utils.snakeCaseName(templateArg.name) : 'endpoint';
|
|
951
1082
|
const adaptedParam = new rust.ClientEndpointParameter(endpointName);
|
|
952
1083
|
adaptedParam.docs = this.adaptDocs(param.summary, param.doc);
|
|
953
1084
|
ctorParams.push(adaptedParam);
|
|
954
|
-
|
|
1085
|
+
const endpointField = new rust.StructField(endpointName, 'pubCrate', new rust.Url(this.crate));
|
|
1086
|
+
rustClient.endpoint = endpointField;
|
|
1087
|
+
rustClient.fields.push(endpointField);
|
|
955
1088
|
// if the server's URL is *only* the endpoint parameter then we're done.
|
|
956
1089
|
// this is the param.type.kind === 'endpoint' case.
|
|
957
1090
|
if (endpointType.serverUrl === `{${templateArg.serializedName}}`) {
|
|
@@ -998,8 +1131,9 @@ export class Adapter {
|
|
|
998
1131
|
// this is a sub-client. it will share some/all the fields of the parent.
|
|
999
1132
|
// NOTE: we must propagate parent params before a potential recursive call
|
|
1000
1133
|
// to create a child client that will need to inherit our client params.
|
|
1134
|
+
rustClient.endpoint = parent.endpoint;
|
|
1001
1135
|
for (const prop of client.clientInitialization.parameters) {
|
|
1002
|
-
const name = snakeCaseName(prop.name);
|
|
1136
|
+
const name = utils.snakeCaseName(prop.name);
|
|
1003
1137
|
const parentField = parent.fields.find((v) => v.name === name);
|
|
1004
1138
|
if (parentField) {
|
|
1005
1139
|
rustClient.fields.push(parentField);
|
|
@@ -1017,7 +1151,7 @@ export class Adapter {
|
|
|
1017
1151
|
else {
|
|
1018
1152
|
throw new AdapterError('InternalError', `uninstantiatable client ${client.name} has no parent`);
|
|
1019
1153
|
}
|
|
1020
|
-
for (const child of
|
|
1154
|
+
for (const child of (_c = client.children) !== null && _c !== void 0 ? _c : []) {
|
|
1021
1155
|
const subClient = this.recursiveAdaptClient(child, rustClient);
|
|
1022
1156
|
this.adaptClientAccessor(client, child, rustClient, subClient);
|
|
1023
1157
|
}
|
|
@@ -1029,7 +1163,7 @@ export class Adapter {
|
|
|
1029
1163
|
code: 'LroPagingNotSupported',
|
|
1030
1164
|
severity: 'warning',
|
|
1031
1165
|
message: `skip emitting Paging LRO ${method.name}`,
|
|
1032
|
-
target: (
|
|
1166
|
+
target: (_e = (_d = method.__raw) === null || _d === void 0 ? void 0 : _d.node) !== null && _e !== void 0 ? _e : tsp.NoTarget,
|
|
1033
1167
|
});
|
|
1034
1168
|
continue;
|
|
1035
1169
|
}
|
|
@@ -1073,22 +1207,8 @@ export class Adapter {
|
|
|
1073
1207
|
* @returns the Rust client parameter
|
|
1074
1208
|
*/
|
|
1075
1209
|
adaptClientParameter(param, constructable) {
|
|
1076
|
-
let paramType;
|
|
1077
|
-
|
|
1078
|
-
if (param.isApiVersionParam || (param.type.kind === 'enum' && (param.type.usage & tcgc.UsageFlags.ApiVersionEnum) === tcgc.UsageFlags.ApiVersionEnum)) {
|
|
1079
|
-
if (param.clientDefaultValue) {
|
|
1080
|
-
// this is optional so it goes into the client options type as a String
|
|
1081
|
-
paramType = this.getStringType();
|
|
1082
|
-
}
|
|
1083
|
-
else {
|
|
1084
|
-
// this is a required param so its type is a &str
|
|
1085
|
-
paramType = this.getRefType(this.getStringSlice());
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
else {
|
|
1089
|
-
paramType = this.getType(param.type);
|
|
1090
|
-
}
|
|
1091
|
-
const paramName = snakeCaseName(param.name);
|
|
1210
|
+
let paramType = param.isApiVersionParam ? this.getStringType() : this.getType(param.type);
|
|
1211
|
+
const paramName = utils.snakeCaseName(param.name);
|
|
1092
1212
|
let optional = false;
|
|
1093
1213
|
// client-side default value makes the param optional
|
|
1094
1214
|
if (param.optional || param.clientDefaultValue) {
|
|
@@ -1124,7 +1244,7 @@ export class Adapter {
|
|
|
1124
1244
|
* @param subClient the sub-client type that the method returns
|
|
1125
1245
|
*/
|
|
1126
1246
|
adaptClientAccessor(parentClient, childClient, rustClient, subClient) {
|
|
1127
|
-
const clientAccessor = new rust.ClientAccessor(`get_${snakeCaseName(subClient.name)}`, rustClient, subClient);
|
|
1247
|
+
const clientAccessor = new rust.ClientAccessor(`get_${utils.snakeCaseName(subClient.name)}`, rustClient, subClient);
|
|
1128
1248
|
clientAccessor.docs.summary = `Returns a new instance of ${subClient.name}.`;
|
|
1129
1249
|
for (const param of childClient.clientInitialization.parameters) {
|
|
1130
1250
|
// check if the client's initializer already has this parameter.
|
|
@@ -1140,7 +1260,7 @@ export class Adapter {
|
|
|
1140
1260
|
if (existsOnParent) {
|
|
1141
1261
|
continue;
|
|
1142
1262
|
}
|
|
1143
|
-
const adaptedParam = new rust.Parameter(snakeCaseName(param.name), this.getType(param.type));
|
|
1263
|
+
const adaptedParam = new rust.Parameter(utils.snakeCaseName(param.name), this.getType(param.type));
|
|
1144
1264
|
adaptedParam.docs = this.adaptDocs(param.summary, param.doc);
|
|
1145
1265
|
clientAccessor.params.push(adaptedParam);
|
|
1146
1266
|
}
|
|
@@ -1156,14 +1276,14 @@ export class Adapter {
|
|
|
1156
1276
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
1157
1277
|
let srcMethodName = method.name;
|
|
1158
1278
|
if (method.kind === 'paging' && !srcMethodName.match(/^list/i)) {
|
|
1159
|
-
const chunks =
|
|
1279
|
+
const chunks = utils.deconstruct(srcMethodName);
|
|
1160
1280
|
if (chunks[0] === 'get') {
|
|
1161
1281
|
chunks[0] = 'list';
|
|
1162
1282
|
}
|
|
1163
1283
|
else {
|
|
1164
1284
|
chunks.unshift('list');
|
|
1165
1285
|
}
|
|
1166
|
-
srcMethodName =
|
|
1286
|
+
srcMethodName = utils.camelCase(chunks);
|
|
1167
1287
|
this.ctx.program.reportDiagnostic({
|
|
1168
1288
|
code: 'PagingMethodRename',
|
|
1169
1289
|
severity: 'warning',
|
|
@@ -1172,7 +1292,8 @@ export class Adapter {
|
|
|
1172
1292
|
});
|
|
1173
1293
|
}
|
|
1174
1294
|
const languageIndependentName = method.crossLanguageDefinitionId;
|
|
1175
|
-
const methodName = naming.getEscapedReservedName(snakeCaseName(srcMethodName), 'fn');
|
|
1295
|
+
const methodName = naming.getEscapedReservedName(utils.snakeCaseName(srcMethodName), 'fn');
|
|
1296
|
+
const pub = adaptAccessFlags(method.access);
|
|
1176
1297
|
if (srcMethodName !== method.name) {
|
|
1177
1298
|
// if the method was renamed then ensure it doesn't collide
|
|
1178
1299
|
for (const existingMethod of rustClient.methods) {
|
|
@@ -1182,7 +1303,7 @@ export class Adapter {
|
|
|
1182
1303
|
}
|
|
1183
1304
|
}
|
|
1184
1305
|
const optionsLifetime = new rust.Lifetime('a');
|
|
1185
|
-
const methodOptionsStruct = new rust.Struct(`${rustClient.name}${
|
|
1306
|
+
const methodOptionsStruct = new rust.Struct(`${rustClient.name}${utils.pascalCase(srcMethodName, false)}Options`, pub);
|
|
1186
1307
|
methodOptionsStruct.lifetime = optionsLifetime;
|
|
1187
1308
|
methodOptionsStruct.docs.summary = `Options to be passed to ${this.asDocLink(`${rustClient.name}::${methodName}()`, `crate::generated::clients::${rustClient.name}::${methodName}()`)}`;
|
|
1188
1309
|
let clientMethodOptions;
|
|
@@ -1197,10 +1318,9 @@ export class Adapter {
|
|
|
1197
1318
|
default:
|
|
1198
1319
|
clientMethodOptions = new rust.ClientMethodOptions(this.crate, optionsLifetime);
|
|
1199
1320
|
}
|
|
1200
|
-
const methodOptionsField = new rust.StructField('method_options',
|
|
1321
|
+
const methodOptionsField = new rust.StructField('method_options', pub, clientMethodOptions);
|
|
1201
1322
|
methodOptionsField.docs.summary = 'Allows customization of the method call.';
|
|
1202
1323
|
methodOptionsStruct.fields.push(methodOptionsField);
|
|
1203
|
-
const pub = adaptAccessFlags(method.access);
|
|
1204
1324
|
const methodOptions = new rust.MethodOptions(methodOptionsStruct);
|
|
1205
1325
|
const httpMethod = method.operation.verb;
|
|
1206
1326
|
let rustMethod;
|
|
@@ -1257,12 +1377,11 @@ export class Adapter {
|
|
|
1257
1377
|
// most params have a one-to-one mapping. however, for spread params, there will
|
|
1258
1378
|
// be a many-to-one mapping. i.e. multiple params will map to the same underlying
|
|
1259
1379
|
// operation param. each param corresponds to a field within the operation param.
|
|
1260
|
-
const opParam =
|
|
1261
|
-
return
|
|
1262
|
-
.where((methodParam) => {
|
|
1380
|
+
const opParam = allOpParams.find((opParam) => {
|
|
1381
|
+
return opParam.methodParameterSegments.map((segment) => segment[segment.length - 1]).some((methodParam) => {
|
|
1263
1382
|
return methodParam.name === param.name;
|
|
1264
|
-
})
|
|
1265
|
-
})
|
|
1383
|
+
});
|
|
1384
|
+
});
|
|
1266
1385
|
if (!opParam) {
|
|
1267
1386
|
throw new AdapterError('InternalError', `didn't find operation parameter for method ${method.name} parameter ${param.name}`, (_f = param.__raw) === null || _f === void 0 ? void 0 : _f.node);
|
|
1268
1387
|
}
|
|
@@ -1311,7 +1430,7 @@ export class Adapter {
|
|
|
1311
1430
|
else {
|
|
1312
1431
|
fieldType = this.getOptionType(adaptedParam.type);
|
|
1313
1432
|
}
|
|
1314
|
-
const optionsField = new rust.StructField(adaptedParam.name,
|
|
1433
|
+
const optionsField = new rust.StructField(adaptedParam.name, pub, fieldType);
|
|
1315
1434
|
optionsField.docs = adaptedParam.docs;
|
|
1316
1435
|
rustMethod.options.type.fields.push(optionsField);
|
|
1317
1436
|
}
|
|
@@ -1462,7 +1581,7 @@ export class Adapter {
|
|
|
1462
1581
|
}
|
|
1463
1582
|
else if (method.kind === 'lro') {
|
|
1464
1583
|
const format = responseFormat === 'NoFormat' ? 'JsonFormat' : responseFormat;
|
|
1465
|
-
const statusType = this.typeToWireType(this.getModel(method.lroMetadata.pollingInfo.responseModel, undefined, `${rustClient.name}${
|
|
1584
|
+
const statusType = this.typeToWireType(this.getModel(method.lroMetadata.pollingInfo.responseModel, undefined, `${rustClient.name}${utils.pascalCase(rustMethod.name, false)}OperationStatus`));
|
|
1466
1585
|
if (statusType.kind !== 'model') {
|
|
1467
1586
|
throw new AdapterError('InternalError', `status type for an LRO method '${method.name}' is not a model`, (_p = method.__raw) === null || _p === void 0 ? void 0 : _p.node);
|
|
1468
1587
|
}
|
|
@@ -1499,7 +1618,7 @@ export class Adapter {
|
|
|
1499
1618
|
else if (responseHeaders.length > 0) {
|
|
1500
1619
|
// for methods that don't return a modeled type but return headers,
|
|
1501
1620
|
// we need to return a marker type
|
|
1502
|
-
const markerType = new rust.MarkerType(`${rustClient.name}${
|
|
1621
|
+
const markerType = new rust.MarkerType(`${rustClient.name}${utils.pascalCase(method.name, false)}Result`, rustMethod.visibility);
|
|
1503
1622
|
markerType.docs.summary = `Contains results for ${this.asDocLink(`${rustClient.name}::${methodName}()`, `crate::generated::clients::${rustClient.name}::${methodName}()`)}`;
|
|
1504
1623
|
this.crate.models.push(markerType);
|
|
1505
1624
|
let resultType;
|
|
@@ -1566,10 +1685,10 @@ export class Adapter {
|
|
|
1566
1685
|
if (header.serializedName !== 'x-ms-meta' && header.serializedName !== 'x-ms-or') {
|
|
1567
1686
|
throw new AdapterError('InternalError', `unexpected response header collection ${header.serializedName}`, header.__raw.node);
|
|
1568
1687
|
}
|
|
1569
|
-
responseHeader = new rust.ResponseHeaderHashMap(snakeCaseName(header.name), lowerCasedHeader);
|
|
1688
|
+
responseHeader = new rust.ResponseHeaderHashMap(utils.snakeCaseName(header.name), lowerCasedHeader);
|
|
1570
1689
|
}
|
|
1571
1690
|
else {
|
|
1572
|
-
responseHeader = new rust.ResponseHeaderScalar(snakeCaseName(header.name), fixETagName(lowerCasedHeader), this.typeToWireType(this.getType(header.type)));
|
|
1691
|
+
responseHeader = new rust.ResponseHeaderScalar(utils.snakeCaseName(header.name), utils.fixETagName(lowerCasedHeader), this.typeToWireType(this.getType(header.type)));
|
|
1573
1692
|
}
|
|
1574
1693
|
responseHeader.docs = this.adaptDocs(header.summary, header.doc);
|
|
1575
1694
|
responseHeadersMap.set(header, responseHeader);
|
|
@@ -1607,13 +1726,13 @@ export class Adapter {
|
|
|
1607
1726
|
case 'ref':
|
|
1608
1727
|
return `Ref${recursiveTypeName(type.type)}`;
|
|
1609
1728
|
case 'scalar':
|
|
1610
|
-
return
|
|
1729
|
+
return utils.capitalize(type.type);
|
|
1611
1730
|
case 'slice':
|
|
1612
1731
|
return `Slice${recursiveTypeName(type.type)}`;
|
|
1613
1732
|
case 'Vec':
|
|
1614
1733
|
return `${type.kind}${recursiveTypeName(type.type)}`;
|
|
1615
1734
|
default:
|
|
1616
|
-
return
|
|
1735
|
+
return utils.capitalize(type.kind);
|
|
1617
1736
|
}
|
|
1618
1737
|
};
|
|
1619
1738
|
const throwOnUnitType = function (type) {
|
|
@@ -1643,7 +1762,7 @@ export class Adapter {
|
|
|
1643
1762
|
const traitName = `${recursiveTypeName(implFor.kind === 'asyncResponse' ? implFor.type : implFor.content)}Headers`;
|
|
1644
1763
|
// NOTE: the complete doc text will be emitted at codegen time
|
|
1645
1764
|
const docs = this.asDocLink(`${client.name}::${method.name}()`, `crate::generated::clients::${client.name}::${method.name}()`);
|
|
1646
|
-
const responseHeadersTrait = new rust.ResponseHeadersTrait(traitName, implFor, docs);
|
|
1765
|
+
const responseHeadersTrait = new rust.ResponseHeadersTrait(traitName, implFor, docs, method.visibility);
|
|
1647
1766
|
responseHeadersTrait.headers.push(...responseHeaders);
|
|
1648
1767
|
return responseHeadersTrait;
|
|
1649
1768
|
}
|
|
@@ -1799,7 +1918,7 @@ export class Adapter {
|
|
|
1799
1918
|
}
|
|
1800
1919
|
return param.name;
|
|
1801
1920
|
};
|
|
1802
|
-
const paramName = naming.getEscapedReservedName(snakeCaseName(getCorrespondingClientParamName(param)), 'param', reservedParams);
|
|
1921
|
+
const paramName = naming.getEscapedReservedName(utils.snakeCaseName(getCorrespondingClientParamName(param)), 'param', reservedParams);
|
|
1803
1922
|
let paramType = this.getType(param.type);
|
|
1804
1923
|
// for required header/path/query method string params, we might emit them as borrowed types
|
|
1805
1924
|
if (!param.optional && !param.onClient && (param.kind === 'header' || param.kind === 'path' || param.kind === 'query')) {
|
|
@@ -2054,9 +2173,9 @@ export class Adapter {
|
|
|
2054
2173
|
if (payloadType.kind !== 'model') {
|
|
2055
2174
|
throw new AdapterError('InternalError', `unexpected kind ${payloadType.kind} for spread body param`, (_b = opParamType.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
2056
2175
|
}
|
|
2057
|
-
const paramName = naming.getEscapedReservedName(snakeCaseName(param.name), 'param');
|
|
2176
|
+
const paramName = naming.getEscapedReservedName(utils.snakeCaseName(param.name), 'param');
|
|
2058
2177
|
const paramLoc = 'method';
|
|
2059
|
-
const formatType =
|
|
2178
|
+
const formatType = utils.getPayloadFormatType(format);
|
|
2060
2179
|
const adaptedParam = new rust.PartialBodyParameter(paramName, paramLoc, param.optional, serializedName, this.getType(param.type), new rust.RequestContent(this.crate, new rust.Payload(payloadType, format), formatType));
|
|
2061
2180
|
return adaptedParam;
|
|
2062
2181
|
}
|
|
@@ -2076,6 +2195,9 @@ export class Adapter {
|
|
|
2076
2195
|
this.crate.addDependency(new rust.CrateDependency('azure_core', ['xml']));
|
|
2077
2196
|
return 'xml';
|
|
2078
2197
|
}
|
|
2198
|
+
else if (contentType.match(/text\/plain/i)) {
|
|
2199
|
+
return 'text';
|
|
2200
|
+
}
|
|
2079
2201
|
else {
|
|
2080
2202
|
throw new AdapterError('InternalError', `unexpected contentType ${contentType}`);
|
|
2081
2203
|
}
|
|
@@ -2104,45 +2226,11 @@ export class Adapter {
|
|
|
2104
2226
|
}
|
|
2105
2227
|
/** type guard to determine if type is a Ref<HashMap> */
|
|
2106
2228
|
function isRefHashMap(type) {
|
|
2107
|
-
return
|
|
2229
|
+
return utils.asTypeOf(type, 'hashmap', 'ref') !== undefined;
|
|
2108
2230
|
}
|
|
2109
2231
|
/** type guard to determine if type is a Ref<Slice> */
|
|
2110
2232
|
function isRefSlice(type) {
|
|
2111
|
-
return
|
|
2112
|
-
}
|
|
2113
|
-
/**
|
|
2114
|
-
* transforms Etag etc to all lower case.
|
|
2115
|
-
* this is to prevent inadvertently snake-casing
|
|
2116
|
-
* Etag to e_tag.
|
|
2117
|
-
*
|
|
2118
|
-
* if name isn't some variant of Etag the
|
|
2119
|
-
* original value is returned.
|
|
2120
|
-
*
|
|
2121
|
-
* @param name the name to transform
|
|
2122
|
-
* @returns etag or the original value
|
|
2123
|
-
*/
|
|
2124
|
-
function fixETagName(name) {
|
|
2125
|
-
return name.match(/^etag$/i) ? 'etag' : name;
|
|
2126
|
-
}
|
|
2127
|
-
/**
|
|
2128
|
-
* removes any illegal characters from the provided name.
|
|
2129
|
-
* note that characters _ and - are preserved so that the
|
|
2130
|
-
* proper snake-casing can be performed.
|
|
2131
|
-
*
|
|
2132
|
-
* @param name the name to transform
|
|
2133
|
-
* @returns the transformed name or the original value
|
|
2134
|
-
*/
|
|
2135
|
-
function removeIllegalChars(name) {
|
|
2136
|
-
return name.replace(/[!@#$%^&*()+=]/g, '');
|
|
2137
|
-
}
|
|
2138
|
-
/**
|
|
2139
|
-
* snake-cases the provided name
|
|
2140
|
-
*
|
|
2141
|
-
* @param name the name to snake-case
|
|
2142
|
-
* @returns name in snake-case format
|
|
2143
|
-
*/
|
|
2144
|
-
function snakeCaseName(name) {
|
|
2145
|
-
return codegen.deconstruct(fixETagName(removeIllegalChars(name))).join('_');
|
|
2233
|
+
return utils.asTypeOf(type, 'slice', 'ref') !== undefined;
|
|
2146
2234
|
}
|
|
2147
2235
|
/**
|
|
2148
2236
|
* recursively creates a map key from the specified type.
|
|
@@ -2172,6 +2260,7 @@ function recursiveKeyName(root, type) {
|
|
|
2172
2260
|
return recursiveKeyName(`${root}-${type.kind}`, type.type);
|
|
2173
2261
|
case 'offsetDateTime':
|
|
2174
2262
|
return `${root}-${type.kind}-${type.encoding}${type.utc ? '-utc' : ''}`;
|
|
2263
|
+
case 'discriminatedUnion':
|
|
2175
2264
|
case 'model':
|
|
2176
2265
|
case 'struct':
|
|
2177
2266
|
return `${root}-${type.kind}-${type.name}`;
|
|
@@ -2233,7 +2322,7 @@ function getXMLKind(decorators, field) {
|
|
|
2233
2322
|
case 'TypeSpec.Xml.@attribute':
|
|
2234
2323
|
return 'attribute';
|
|
2235
2324
|
case 'TypeSpec.Xml.@unwrapped': {
|
|
2236
|
-
const fieldType =
|
|
2325
|
+
const fieldType = utils.unwrapOption(field.type);
|
|
2237
2326
|
switch (fieldType.kind) {
|
|
2238
2327
|
case 'Vec':
|
|
2239
2328
|
return 'unwrappedList';
|