@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.
Files changed (64) hide show
  1. package/dist/src/codegen/clients.d.ts.map +1 -1
  2. package/dist/src/codegen/clients.js +153 -131
  3. package/dist/src/codegen/clients.js.map +1 -1
  4. package/dist/src/codegen/codeGenerator.js +16 -16
  5. package/dist/src/codegen/codeGenerator.js.map +1 -1
  6. package/dist/src/codegen/context.d.ts +3 -3
  7. package/dist/src/codegen/context.d.ts.map +1 -1
  8. package/dist/src/codegen/context.js +5 -5
  9. package/dist/src/codegen/context.js.map +1 -1
  10. package/dist/src/codegen/docTests.d.ts.map +1 -1
  11. package/dist/src/codegen/docTests.js +2 -1
  12. package/dist/src/codegen/docTests.js.map +1 -1
  13. package/dist/src/codegen/enums.d.ts +5 -5
  14. package/dist/src/codegen/enums.d.ts.map +1 -1
  15. package/dist/src/codegen/enums.js +11 -8
  16. package/dist/src/codegen/enums.js.map +1 -1
  17. package/dist/src/codegen/headerTraits.d.ts.map +1 -1
  18. package/dist/src/codegen/headerTraits.js +7 -4
  19. package/dist/src/codegen/headerTraits.js.map +1 -1
  20. package/dist/src/codegen/helpers.d.ts +23 -0
  21. package/dist/src/codegen/helpers.d.ts.map +1 -1
  22. package/dist/src/codegen/helpers.js +39 -18
  23. package/dist/src/codegen/helpers.js.map +1 -1
  24. package/dist/src/codegen/mod.d.ts.map +1 -1
  25. package/dist/src/codegen/mod.js +3 -1
  26. package/dist/src/codegen/mod.js.map +1 -1
  27. package/dist/src/codegen/models.d.ts +4 -6
  28. package/dist/src/codegen/models.d.ts.map +1 -1
  29. package/dist/src/codegen/models.js +132 -68
  30. package/dist/src/codegen/models.js.map +1 -1
  31. package/dist/src/codegen/unions.d.ts +8 -6
  32. package/dist/src/codegen/unions.d.ts.map +1 -1
  33. package/dist/src/codegen/unions.js +142 -9
  34. package/dist/src/codegen/unions.js.map +1 -1
  35. package/dist/src/codegen/use.d.ts +2 -2
  36. package/dist/src/codegen/use.d.ts.map +1 -1
  37. package/dist/src/codegen/use.js +3 -5
  38. package/dist/src/codegen/use.js.map +1 -1
  39. package/dist/src/codemodel/client.d.ts +9 -1
  40. package/dist/src/codemodel/client.d.ts.map +1 -1
  41. package/dist/src/codemodel/client.js +2 -1
  42. package/dist/src/codemodel/client.js.map +1 -1
  43. package/dist/src/codemodel/crate.d.ts +1 -1
  44. package/dist/src/codemodel/crate.d.ts.map +1 -1
  45. package/dist/src/codemodel/types.d.ts +39 -6
  46. package/dist/src/codemodel/types.d.ts.map +1 -1
  47. package/dist/src/codemodel/types.js +25 -1
  48. package/dist/src/codemodel/types.js.map +1 -1
  49. package/dist/src/tcgcadapter/adapter.d.ts +5 -2
  50. package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
  51. package/dist/src/tcgcadapter/adapter.js +259 -170
  52. package/dist/src/tcgcadapter/adapter.js.map +1 -1
  53. package/dist/src/tcgcadapter/naming.d.ts.map +1 -1
  54. package/dist/src/tcgcadapter/naming.js +2 -2
  55. package/dist/src/tcgcadapter/naming.js.map +1 -1
  56. package/dist/src/utils/utils.d.ts +99 -0
  57. package/dist/src/utils/utils.d.ts.map +1 -0
  58. package/dist/src/utils/utils.js +288 -0
  59. package/dist/src/utils/utils.js.map +1 -0
  60. package/package.json +16 -19
  61. package/dist/src/shared/shared.d.ts +0 -29
  62. package/dist/src/shared/shared.d.ts.map +0 -1
  63. package/dist/src/shared/shared.js +0 -109
  64. 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 shared from '../shared/shared.js';
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 || values(this.crate.models).where(e => e.kind === 'model').any()) {
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 = codegen.deconstruct(sdkEnum.name).map((each) => codegen.capitalize(each)).join('');
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
- const existingMapping = rustEnumNameToSdkEnumName.get(enumValueName);
192
- if (existingMapping) {
193
- throw new AdapterError('NameCollision', `enum values ${value.name} and ${existingMapping} coalesce into the same name ${enumValueName}`, (_b = sdkEnum.__raw) === null || _b === void 0 ? void 0 : _b.node);
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 = codegen.capitalize(modelName).replace(/\W/g, '');
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
- if ((model.usage & tcgc.UsageFlags.Output) === tcgc.UsageFlags.Output) {
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
- const exists = values(allProps).where(p => { return p.name === parentProp.name; }).first();
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 = 'contains unnamed additional properties';
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(union) {
338
- var _a, _b, _c, _d;
339
- if (union.name.length === 0) {
340
- throw new AdapterError('InternalError', 'unnamed union', (_a = union.__raw) === null || _a === void 0 ? void 0 : _a.node);
341
- }
342
- const unionName = codegen.capitalize(union.name);
343
- let rustUnion = this.types.get(unionName);
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
- if (!union.discriminatedOptions) {
348
- // we should have verified this earlier.
349
- // having this check means the compiler won't bark
350
- // at us when accessing union.discriminatedOptions
351
- throw new AdapterError('InternalError', 'getDiscriminatedUnion called for non-discriminated union', (_b = union.__raw) === null || _b === void 0 ? void 0 : _b.node);
352
- }
353
- rustUnion = new rust.DiscriminatedUnion(unionName, adaptAccessFlags(union.access), union.discriminatedOptions.discriminatorPropertyName);
354
- rustUnion.envelopeName = union.discriminatedOptions.envelopePropertyName;
355
- rustUnion.docs = this.adaptDocs(union.summary, union.doc);
356
- this.types.set(unionName, rustUnion);
357
- // TODO: remove when https://github.com/microsoft/typespec/issues/8455 is complete
358
- const discriminatorValues = new Map();
359
- const rawUnion = union.__raw;
360
- if (rawUnion) {
361
- for (const [variantKey, variant] of rawUnion.variants) {
362
- const discriminatorValue = typeof variantKey === 'string' ? variantKey : variantKey.toString();
363
- if (variant.type.kind === 'Model') {
364
- discriminatorValues.set(variant.type.name, discriminatorValue);
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
- throw new AdapterError('InternalError', `unexpected kind ${variant.type.kind} for discriminated union member`, rawUnion);
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
- // END WORKAROUND
372
- for (const unionMember of union.variantTypes) {
373
- if (unionMember.kind !== 'model') {
374
- throw new AdapterError('UnsupportedTsp', `non-model union member kind ${unionMember.kind}`, (_c = unionMember.__raw) === null || _c === void 0 ? void 0 : _c.node);
375
- }
376
- // TODO: use unionMember.discriminatorValue
377
- const discriminatorValue = discriminatorValues.get(unionMember.name);
378
- if (!discriminatorValue) {
379
- throw new AdapterError('InternalError', `didn't find discriminant value for type ${unionMember.name}`, (_d = unionMember.__raw) === null || _d === void 0 ? void 0 : _d.node);
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 model type names used to detect recursive type definitions
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
- // if the field's type is a model and it's in the type stack then
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 public models each field is always an Option<T>.
409
- if (modelVisibility === 'pub' || property.optional) {
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 = shared.unwrapOption(fieldType);
417
- if (unwrappedType.kind === 'literal') {
418
- const literalDoc = `${modelField.optional ? 'When Some, field' : 'Field'} has constant value ${unwrappedType.value}. Any specified value will be ignored.`;
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 model type names used to detect recursive type definitions
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
- const keyName = 'jsonValue';
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["WithAuth"] = 2] = "WithAuth";
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
- constructable.constructors.push(this.createTokenCredentialCtor(rustClient, cred));
896
- return AuthTypes.WithAuth;
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
- rustClient.fields.push(new rust.StructField(endpointName, 'pubCrate', new rust.Url(this.crate)));
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 values(client.children)) {
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: (_d = (_c = method.__raw) === null || _c === void 0 ? void 0 : _c.node) !== null && _d !== void 0 ? _d : tsp.NoTarget,
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
- // the second clause is a workaround for https://github.com/Azure/typespec-azure/issues/2745
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 = codegen.deconstruct(srcMethodName);
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 = codegen.camelCase(chunks);
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}${codegen.pascalCase(srcMethodName, false)}Options`, 'pub');
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', 'pub', clientMethodOptions);
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 = values(allOpParams).where((opParam) => {
1261
- return values(opParam.methodParameterSegments.map((segment) => segment[segment.length - 1]))
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
- }).any();
1265
- }).first();
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, 'pub', fieldType);
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}${codegen.pascalCase(rustMethod.name, false)}OperationStatus`));
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}${codegen.pascalCase(method.name, false)}Result`);
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 codegen.capitalize(type.type);
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 codegen.capitalize(type.kind);
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 = shared.getPayloadFormatType(format);
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 shared.asTypeOf(type, 'hashmap', 'ref') !== undefined;
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 shared.asTypeOf(type, 'slice', 'ref') !== undefined;
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 = shared.unwrapOption(field.type);
2325
+ const fieldType = utils.unwrapOption(field.type);
2237
2326
  switch (fieldType.kind) {
2238
2327
  case 'Vec':
2239
2328
  return 'unwrappedList';