@azure-tools/typespec-rust 0.33.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 (55) hide show
  1. package/dist/src/codegen/clients.d.ts.map +1 -1
  2. package/dist/src/codegen/clients.js +118 -91
  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.js +1 -1
  7. package/dist/src/codegen/context.js.map +1 -1
  8. package/dist/src/codegen/enums.d.ts +5 -5
  9. package/dist/src/codegen/enums.d.ts.map +1 -1
  10. package/dist/src/codegen/enums.js +10 -6
  11. package/dist/src/codegen/enums.js.map +1 -1
  12. package/dist/src/codegen/headerTraits.d.ts.map +1 -1
  13. package/dist/src/codegen/headerTraits.js +4 -3
  14. package/dist/src/codegen/headerTraits.js.map +1 -1
  15. package/dist/src/codegen/helpers.d.ts +23 -0
  16. package/dist/src/codegen/helpers.d.ts.map +1 -1
  17. package/dist/src/codegen/helpers.js +37 -17
  18. package/dist/src/codegen/helpers.js.map +1 -1
  19. package/dist/src/codegen/mod.d.ts.map +1 -1
  20. package/dist/src/codegen/mod.js +3 -1
  21. package/dist/src/codegen/mod.js.map +1 -1
  22. package/dist/src/codegen/models.d.ts +4 -6
  23. package/dist/src/codegen/models.d.ts.map +1 -1
  24. package/dist/src/codegen/models.js +129 -61
  25. package/dist/src/codegen/models.js.map +1 -1
  26. package/dist/src/codegen/unions.d.ts +8 -6
  27. package/dist/src/codegen/unions.d.ts.map +1 -1
  28. package/dist/src/codegen/unions.js +142 -9
  29. package/dist/src/codegen/unions.js.map +1 -1
  30. package/dist/src/codegen/use.d.ts +1 -19
  31. package/dist/src/codegen/use.d.ts.map +1 -1
  32. package/dist/src/codegen/use.js +7 -41
  33. package/dist/src/codegen/use.js.map +1 -1
  34. package/dist/src/codemodel/crate.d.ts +1 -1
  35. package/dist/src/codemodel/crate.d.ts.map +1 -1
  36. package/dist/src/codemodel/types.d.ts +35 -4
  37. package/dist/src/codemodel/types.d.ts.map +1 -1
  38. package/dist/src/codemodel/types.js +23 -0
  39. package/dist/src/codemodel/types.js.map +1 -1
  40. package/dist/src/tcgcadapter/adapter.d.ts +5 -2
  41. package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
  42. package/dist/src/tcgcadapter/adapter.js +208 -155
  43. package/dist/src/tcgcadapter/adapter.js.map +1 -1
  44. package/dist/src/tcgcadapter/naming.d.ts.map +1 -1
  45. package/dist/src/tcgcadapter/naming.js +2 -2
  46. package/dist/src/tcgcadapter/naming.js.map +1 -1
  47. package/dist/src/utils/utils.d.ts +99 -0
  48. package/dist/src/utils/utils.d.ts.map +1 -0
  49. package/dist/src/utils/utils.js +288 -0
  50. package/dist/src/utils/utils.js.map +1 -0
  51. package/package.json +5 -8
  52. package/dist/src/shared/shared.d.ts +0 -29
  53. package/dist/src/shared/shared.d.ts.map +0 -1
  54. package/dist/src/shared/shared.js +0 -109
  55. 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
  }
@@ -154,7 +160,7 @@ export class Adapter {
154
160
  */
155
161
  getEnum(sdkEnum) {
156
162
  var _a, _b, _c;
157
- const enumName = codegen.deconstruct(sdkEnum.name).map((each) => codegen.capitalize(each)).join('');
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;
@@ -277,7 +283,7 @@ export class Adapter {
277
283
  }
278
284
  // remove any non-word characters from the name.
279
285
  // the most common case is something like Foo.Bar.Baz
280
- modelName = codegen.capitalize(modelName).replace(/\W/g, '');
286
+ modelName = utils.capitalize(modelName).replace(/\W/g, '');
281
287
  let rustModel = this.types.get(modelName);
282
288
  if (rustModel) {
283
289
  return rustModel;
@@ -287,33 +293,43 @@ export class Adapter {
287
293
  if (!stack) {
288
294
  stack = new Array();
289
295
  }
290
- stack.push(modelName);
291
296
  let modelFlags = rust.ModelFlags.Unspecified;
292
297
  if ((model.usage & tcgc.UsageFlags.Input) === tcgc.UsageFlags.Input) {
293
298
  modelFlags |= rust.ModelFlags.Input;
294
299
  }
295
- 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) {
296
304
  modelFlags |= rust.ModelFlags.Output;
297
305
  }
298
306
  rustModel = new rust.Model(modelName, model.access === 'internal' ? 'pubCrate' : 'pub', modelFlags);
299
307
  rustModel.docs = this.adaptDocs(model.summary, model.doc);
300
308
  rustModel.xmlName = getXMLName(model.decorators);
301
309
  this.types.set(modelName, rustModel);
310
+ stack.push(rustModel);
302
311
  // aggregate the properties from the provided type and its parent types
303
312
  const allProps = new Array();
304
313
  for (const prop of model.properties) {
314
+ if (prop.discriminator && !model.discriminatedSubtypes) {
315
+ rustModel.flags |= rust.ModelFlags.PolymorphicSubtype;
316
+ }
305
317
  allProps.push(prop);
306
318
  }
307
319
  let addlProps = model.additionalProperties;
308
320
  let parent = model.baseModel;
309
321
  while (parent) {
310
322
  for (const parentProp of parent.properties) {
311
- const exists = values(allProps).where(p => { return p.name === parentProp.name; }).first();
312
- if (exists) {
323
+ if (allProps.find(p => p.name === parentProp.name)) {
313
324
  // don't add the duplicate. the TS compiler has better enforcement than OpenAPI
314
325
  // to ensure that duplicate fields with different types aren't added.
315
326
  continue;
316
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
+ }
317
333
  allProps.push(parentProp);
318
334
  }
319
335
  // propagate parent's additional properties if we don't yet have any.
@@ -342,13 +358,13 @@ export class Adapter {
342
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);
343
359
  }
344
360
  }
345
- const structField = this.getModelField(property, rustModel.visibility, stack);
361
+ const structField = this.getModelField(model.usage, property, rustModel.visibility, stack);
346
362
  rustModel.fields.push(structField);
347
363
  }
348
364
  if (addlProps) {
349
365
  const addlPropsType = this.getHashMap(this.typeToWireType(this.getType(addlProps)));
350
366
  const addlPropsField = new rust.ModelAdditionalProperties('additional_properties', 'pub', this.getOptionType(addlPropsType));
351
- addlPropsField.docs.summary = 'contains unnamed additional properties';
367
+ addlPropsField.docs.summary = 'Contains unnamed additional properties.';
352
368
  rustModel.fields.push(addlPropsField);
353
369
  }
354
370
  stack.pop();
@@ -360,55 +376,100 @@ export class Adapter {
360
376
  * @param union the tcgc union to convert
361
377
  * @returns a Rust union
362
378
  */
363
- getDiscriminatedUnion(union) {
364
- var _a, _b, _c, _d;
365
- if (union.name.length === 0) {
366
- throw new AdapterError('InternalError', 'unnamed union', (_a = union.__raw) === null || _a === void 0 ? void 0 : _a.node);
367
- }
368
- const unionName = codegen.capitalize(union.name);
369
- 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);
370
387
  if (rustUnion) {
371
388
  return rustUnion;
372
389
  }
373
- if (!union.discriminatedOptions) {
374
- // we should have verified this earlier.
375
- // having this check means the compiler won't bark
376
- // at us when accessing union.discriminatedOptions
377
- throw new AdapterError('InternalError', 'getDiscriminatedUnion called for non-discriminated union', (_b = union.__raw) === null || _b === void 0 ? void 0 : _b.node);
378
- }
379
- rustUnion = new rust.DiscriminatedUnion(unionName, adaptAccessFlags(union.access), union.discriminatedOptions.discriminatorPropertyName);
380
- rustUnion.envelopeName = union.discriminatedOptions.envelopePropertyName;
381
- rustUnion.docs = this.adaptDocs(union.summary, union.doc);
382
- this.types.set(unionName, rustUnion);
383
- // TODO: remove when https://github.com/microsoft/typespec/issues/8455 is complete
384
- const discriminatorValues = new Map();
385
- const rawUnion = union.__raw;
386
- if (rawUnion) {
387
- for (const [variantKey, variant] of rawUnion.variants) {
388
- const discriminatorValue = typeof variantKey === 'string' ? variantKey : variantKey.toString();
389
- if (variant.type.kind === 'Model') {
390
- 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();
391
414
  }
392
415
  else {
393
- throw new AdapterError('InternalError', `unexpected kind ${variant.type.kind} for discriminated union member`, rawUnion);
416
+ rustUnion.unionKind = new rust.DiscriminatedUnionBase(this.getModel(src));
394
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;
395
427
  }
396
- }
397
- // END WORKAROUND
398
- for (const unionMember of union.variantTypes) {
399
- if (unionMember.kind !== 'model') {
400
- throw new AdapterError('UnsupportedTsp', `non-model union member kind ${unionMember.kind}`, (_c = unionMember.__raw) === null || _c === void 0 ? void 0 : _c.node);
401
- }
402
- // TODO: use unionMember.discriminatorValue
403
- const discriminatorValue = discriminatorValues.get(unionMember.name);
404
- if (!discriminatorValue) {
405
- 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;
406
469
  }
407
- const unionMemberType = this.getModel(unionMember);
408
- const rustUnionMember = new rust.DiscriminatedUnionMember(unionMemberType, discriminatorValue);
409
- rustUnionMember.docs = this.adaptDocs(unionMember.summary, unionMember.doc);
410
- rustUnion.members.push(rustUnionMember);
411
470
  }
471
+ rustUnion.docs = this.adaptDocs(src.summary, src.doc);
472
+ this.types.set(keyName, rustUnion);
412
473
  return rustUnion;
413
474
  }
414
475
  getSerializedPropertyName(property) {
@@ -418,30 +479,58 @@ export class Adapter {
418
479
  /**
419
480
  * converts a tcgc model property to a model field
420
481
  *
482
+ * @param modelFlags the flags for the model to which the field belongs
421
483
  * @param property the tcgc model property to convert
422
484
  * @param modelVisibility the visibility of the model that contains the property
423
- * @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
424
486
  * @returns a Rust model field
425
487
  */
426
- getModelField(property, modelVisibility, stack) {
488
+ getModelField(modelFlags, property, modelVisibility, stack) {
427
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
+ };
428
507
  let fieldType = this.getType(property.type, stack);
429
- // if the field's type is a model and it's in the type stack then
430
- // box it. this is to avoid infinitely recursive type definitions.
431
- if (fieldType.kind === 'model' && stack.includes(fieldType.name)) {
508
+ if (fieldNeedsBoxing(fieldType)) {
432
509
  fieldType = this.getBoxType(fieldType);
433
510
  }
434
- // for public models each field is always an Option<T>.
435
- 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) {
436
516
  fieldType = this.getOptionType(fieldType.kind === 'box' ? fieldType : this.typeToWireType(fieldType));
437
517
  }
438
518
  const serializedName = (_a = this.getSerializedPropertyName(property)) !== null && _a !== void 0 ? _a : property.name;
439
- 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);
440
520
  modelField.docs = this.adaptDocs(property.summary, property.doc);
441
521
  // if this is a literal, add a doc comment explaining its behavior
442
- const unwrappedType = shared.unwrapOption(fieldType);
443
- if (unwrappedType.kind === 'literal') {
444
- 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.`;
445
534
  if (!modelField.docs.description) {
446
535
  modelField.docs.description = '';
447
536
  }
@@ -463,17 +552,23 @@ export class Adapter {
463
552
  if (property.decorators.find((decorator) => decorator.name === 'Azure.ClientGenerator.Core.@deserializeEmptyStringAsNull') !== undefined) {
464
553
  modelField.flags |= rust.ModelFieldFlags.DeserializeEmptyStringAsNone;
465
554
  }
555
+ else if (property.kind === 'property' && property.discriminator) {
556
+ modelField.flags |= rust.ModelFieldFlags.Discriminator;
557
+ }
466
558
  return modelField;
467
559
  }
468
560
  /**
469
561
  * converts a tcgc type to a Rust type
470
562
  *
471
563
  * @param type the tcgc type to convert
472
- * @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
473
565
  * @returns the adapted Rust type
474
566
  */
475
567
  getType(type, stack) {
476
568
  var _a, _b, _c;
569
+ if (type.external) {
570
+ return this.getExternalType(type.external);
571
+ }
477
572
  const getDateTimeEncoding = (encoding) => {
478
573
  var _a;
479
574
  switch (encoding) {
@@ -549,6 +644,9 @@ export class Adapter {
549
644
  if (type.external) {
550
645
  return this.getExternalType(type.external);
551
646
  }
647
+ else if (type.discriminatedSubtypes) {
648
+ return this.getDiscriminatedUnion(type);
649
+ }
552
650
  return this.getModel(type, stack);
553
651
  case 'endpoint':
554
652
  case 'plainDate':
@@ -595,16 +693,8 @@ export class Adapter {
595
693
  }
596
694
  return safeint;
597
695
  }
598
- case 'unknown': {
599
- const keyName = 'jsonValue';
600
- let anyType = this.types.get(keyName);
601
- if (anyType) {
602
- return anyType;
603
- }
604
- anyType = new rust.JsonValue(this.crate);
605
- this.types.set(keyName, anyType);
606
- return anyType;
607
- }
696
+ case 'unknown':
697
+ return this.getUnknownValue();
608
698
  case 'utcDateTime': {
609
699
  const encoding = getDateTimeEncoding(type.encode);
610
700
  const keyName = `offsetDateTime-${encoding}-utc`;
@@ -658,6 +748,17 @@ export class Adapter {
658
748
  this.types.set(keyName, hashmapType);
659
749
  return hashmapType;
660
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
+ }
661
762
  /** returns an Option<T> where T is specified in type */
662
763
  getOptionType(type) {
663
764
  const typeKey = recursiveKeyName('option', type);
@@ -853,7 +954,7 @@ export class Adapter {
853
954
  * @returns a Rust client
854
955
  */
855
956
  recursiveAdaptClient(client, parent) {
856
- var _a, _b, _c, _d;
957
+ var _a, _b, _c, _d, _e;
857
958
  let clientName = client.name;
858
959
  // NOTE: if the client has the @clientName decorator applied then use that verbatim
859
960
  if (parent && !hasClientNameDecorator(client.decorators)) {
@@ -977,7 +1078,7 @@ export class Adapter {
977
1078
  // note that the types of the param and the field are different.
978
1079
  // we default to "endpoint" and will use the defined name IFF
979
1080
  // it has the @clientName decorator applied
980
- const endpointName = hasClientNameDecorator(templateArg.decorators) ? snakeCaseName(templateArg.name) : 'endpoint';
1081
+ const endpointName = hasClientNameDecorator(templateArg.decorators) ? utils.snakeCaseName(templateArg.name) : 'endpoint';
981
1082
  const adaptedParam = new rust.ClientEndpointParameter(endpointName);
982
1083
  adaptedParam.docs = this.adaptDocs(param.summary, param.doc);
983
1084
  ctorParams.push(adaptedParam);
@@ -1032,7 +1133,7 @@ export class Adapter {
1032
1133
  // to create a child client that will need to inherit our client params.
1033
1134
  rustClient.endpoint = parent.endpoint;
1034
1135
  for (const prop of client.clientInitialization.parameters) {
1035
- const name = snakeCaseName(prop.name);
1136
+ const name = utils.snakeCaseName(prop.name);
1036
1137
  const parentField = parent.fields.find((v) => v.name === name);
1037
1138
  if (parentField) {
1038
1139
  rustClient.fields.push(parentField);
@@ -1050,7 +1151,7 @@ export class Adapter {
1050
1151
  else {
1051
1152
  throw new AdapterError('InternalError', `uninstantiatable client ${client.name} has no parent`);
1052
1153
  }
1053
- for (const child of values(client.children)) {
1154
+ for (const child of (_c = client.children) !== null && _c !== void 0 ? _c : []) {
1054
1155
  const subClient = this.recursiveAdaptClient(child, rustClient);
1055
1156
  this.adaptClientAccessor(client, child, rustClient, subClient);
1056
1157
  }
@@ -1062,7 +1163,7 @@ export class Adapter {
1062
1163
  code: 'LroPagingNotSupported',
1063
1164
  severity: 'warning',
1064
1165
  message: `skip emitting Paging LRO ${method.name}`,
1065
- 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,
1066
1167
  });
1067
1168
  continue;
1068
1169
  }
@@ -1106,22 +1207,8 @@ export class Adapter {
1106
1207
  * @returns the Rust client parameter
1107
1208
  */
1108
1209
  adaptClientParameter(param, constructable) {
1109
- let paramType;
1110
- // the second clause is a workaround for https://github.com/Azure/typespec-azure/issues/2745
1111
- if (param.isApiVersionParam || (param.type.kind === 'enum' && (param.type.usage & tcgc.UsageFlags.ApiVersionEnum) === tcgc.UsageFlags.ApiVersionEnum)) {
1112
- if (param.clientDefaultValue) {
1113
- // this is optional so it goes into the client options type as a String
1114
- paramType = this.getStringType();
1115
- }
1116
- else {
1117
- // this is a required param so its type is a &str
1118
- paramType = this.getRefType(this.getStringSlice());
1119
- }
1120
- }
1121
- else {
1122
- paramType = this.getType(param.type);
1123
- }
1124
- const paramName = snakeCaseName(param.name);
1210
+ let paramType = param.isApiVersionParam ? this.getStringType() : this.getType(param.type);
1211
+ const paramName = utils.snakeCaseName(param.name);
1125
1212
  let optional = false;
1126
1213
  // client-side default value makes the param optional
1127
1214
  if (param.optional || param.clientDefaultValue) {
@@ -1157,7 +1244,7 @@ export class Adapter {
1157
1244
  * @param subClient the sub-client type that the method returns
1158
1245
  */
1159
1246
  adaptClientAccessor(parentClient, childClient, rustClient, subClient) {
1160
- const clientAccessor = new rust.ClientAccessor(`get_${snakeCaseName(subClient.name)}`, rustClient, subClient);
1247
+ const clientAccessor = new rust.ClientAccessor(`get_${utils.snakeCaseName(subClient.name)}`, rustClient, subClient);
1161
1248
  clientAccessor.docs.summary = `Returns a new instance of ${subClient.name}.`;
1162
1249
  for (const param of childClient.clientInitialization.parameters) {
1163
1250
  // check if the client's initializer already has this parameter.
@@ -1173,7 +1260,7 @@ export class Adapter {
1173
1260
  if (existsOnParent) {
1174
1261
  continue;
1175
1262
  }
1176
- 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));
1177
1264
  adaptedParam.docs = this.adaptDocs(param.summary, param.doc);
1178
1265
  clientAccessor.params.push(adaptedParam);
1179
1266
  }
@@ -1189,14 +1276,14 @@ export class Adapter {
1189
1276
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
1190
1277
  let srcMethodName = method.name;
1191
1278
  if (method.kind === 'paging' && !srcMethodName.match(/^list/i)) {
1192
- const chunks = codegen.deconstruct(srcMethodName);
1279
+ const chunks = utils.deconstruct(srcMethodName);
1193
1280
  if (chunks[0] === 'get') {
1194
1281
  chunks[0] = 'list';
1195
1282
  }
1196
1283
  else {
1197
1284
  chunks.unshift('list');
1198
1285
  }
1199
- srcMethodName = codegen.camelCase(chunks);
1286
+ srcMethodName = utils.camelCase(chunks);
1200
1287
  this.ctx.program.reportDiagnostic({
1201
1288
  code: 'PagingMethodRename',
1202
1289
  severity: 'warning',
@@ -1205,7 +1292,8 @@ export class Adapter {
1205
1292
  });
1206
1293
  }
1207
1294
  const languageIndependentName = method.crossLanguageDefinitionId;
1208
- const methodName = naming.getEscapedReservedName(snakeCaseName(srcMethodName), 'fn');
1295
+ const methodName = naming.getEscapedReservedName(utils.snakeCaseName(srcMethodName), 'fn');
1296
+ const pub = adaptAccessFlags(method.access);
1209
1297
  if (srcMethodName !== method.name) {
1210
1298
  // if the method was renamed then ensure it doesn't collide
1211
1299
  for (const existingMethod of rustClient.methods) {
@@ -1215,7 +1303,7 @@ export class Adapter {
1215
1303
  }
1216
1304
  }
1217
1305
  const optionsLifetime = new rust.Lifetime('a');
1218
- 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);
1219
1307
  methodOptionsStruct.lifetime = optionsLifetime;
1220
1308
  methodOptionsStruct.docs.summary = `Options to be passed to ${this.asDocLink(`${rustClient.name}::${methodName}()`, `crate::generated::clients::${rustClient.name}::${methodName}()`)}`;
1221
1309
  let clientMethodOptions;
@@ -1230,10 +1318,9 @@ export class Adapter {
1230
1318
  default:
1231
1319
  clientMethodOptions = new rust.ClientMethodOptions(this.crate, optionsLifetime);
1232
1320
  }
1233
- const methodOptionsField = new rust.StructField('method_options', 'pub', clientMethodOptions);
1321
+ const methodOptionsField = new rust.StructField('method_options', pub, clientMethodOptions);
1234
1322
  methodOptionsField.docs.summary = 'Allows customization of the method call.';
1235
1323
  methodOptionsStruct.fields.push(methodOptionsField);
1236
- const pub = adaptAccessFlags(method.access);
1237
1324
  const methodOptions = new rust.MethodOptions(methodOptionsStruct);
1238
1325
  const httpMethod = method.operation.verb;
1239
1326
  let rustMethod;
@@ -1290,12 +1377,11 @@ export class Adapter {
1290
1377
  // most params have a one-to-one mapping. however, for spread params, there will
1291
1378
  // be a many-to-one mapping. i.e. multiple params will map to the same underlying
1292
1379
  // operation param. each param corresponds to a field within the operation param.
1293
- const opParam = values(allOpParams).where((opParam) => {
1294
- return values(opParam.methodParameterSegments.map((segment) => segment[segment.length - 1]))
1295
- .where((methodParam) => {
1380
+ const opParam = allOpParams.find((opParam) => {
1381
+ return opParam.methodParameterSegments.map((segment) => segment[segment.length - 1]).some((methodParam) => {
1296
1382
  return methodParam.name === param.name;
1297
- }).any();
1298
- }).first();
1383
+ });
1384
+ });
1299
1385
  if (!opParam) {
1300
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);
1301
1387
  }
@@ -1344,7 +1430,7 @@ export class Adapter {
1344
1430
  else {
1345
1431
  fieldType = this.getOptionType(adaptedParam.type);
1346
1432
  }
1347
- const optionsField = new rust.StructField(adaptedParam.name, 'pub', fieldType);
1433
+ const optionsField = new rust.StructField(adaptedParam.name, pub, fieldType);
1348
1434
  optionsField.docs = adaptedParam.docs;
1349
1435
  rustMethod.options.type.fields.push(optionsField);
1350
1436
  }
@@ -1495,7 +1581,7 @@ export class Adapter {
1495
1581
  }
1496
1582
  else if (method.kind === 'lro') {
1497
1583
  const format = responseFormat === 'NoFormat' ? 'JsonFormat' : responseFormat;
1498
- 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`));
1499
1585
  if (statusType.kind !== 'model') {
1500
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);
1501
1587
  }
@@ -1532,7 +1618,7 @@ export class Adapter {
1532
1618
  else if (responseHeaders.length > 0) {
1533
1619
  // for methods that don't return a modeled type but return headers,
1534
1620
  // we need to return a marker type
1535
- const markerType = new rust.MarkerType(`${rustClient.name}${codegen.pascalCase(method.name, false)}Result`, rustMethod.visibility);
1621
+ const markerType = new rust.MarkerType(`${rustClient.name}${utils.pascalCase(method.name, false)}Result`, rustMethod.visibility);
1536
1622
  markerType.docs.summary = `Contains results for ${this.asDocLink(`${rustClient.name}::${methodName}()`, `crate::generated::clients::${rustClient.name}::${methodName}()`)}`;
1537
1623
  this.crate.models.push(markerType);
1538
1624
  let resultType;
@@ -1599,10 +1685,10 @@ export class Adapter {
1599
1685
  if (header.serializedName !== 'x-ms-meta' && header.serializedName !== 'x-ms-or') {
1600
1686
  throw new AdapterError('InternalError', `unexpected response header collection ${header.serializedName}`, header.__raw.node);
1601
1687
  }
1602
- responseHeader = new rust.ResponseHeaderHashMap(snakeCaseName(header.name), lowerCasedHeader);
1688
+ responseHeader = new rust.ResponseHeaderHashMap(utils.snakeCaseName(header.name), lowerCasedHeader);
1603
1689
  }
1604
1690
  else {
1605
- 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)));
1606
1692
  }
1607
1693
  responseHeader.docs = this.adaptDocs(header.summary, header.doc);
1608
1694
  responseHeadersMap.set(header, responseHeader);
@@ -1640,13 +1726,13 @@ export class Adapter {
1640
1726
  case 'ref':
1641
1727
  return `Ref${recursiveTypeName(type.type)}`;
1642
1728
  case 'scalar':
1643
- return codegen.capitalize(type.type);
1729
+ return utils.capitalize(type.type);
1644
1730
  case 'slice':
1645
1731
  return `Slice${recursiveTypeName(type.type)}`;
1646
1732
  case 'Vec':
1647
1733
  return `${type.kind}${recursiveTypeName(type.type)}`;
1648
1734
  default:
1649
- return codegen.capitalize(type.kind);
1735
+ return utils.capitalize(type.kind);
1650
1736
  }
1651
1737
  };
1652
1738
  const throwOnUnitType = function (type) {
@@ -1832,7 +1918,7 @@ export class Adapter {
1832
1918
  }
1833
1919
  return param.name;
1834
1920
  };
1835
- const paramName = naming.getEscapedReservedName(snakeCaseName(getCorrespondingClientParamName(param)), 'param', reservedParams);
1921
+ const paramName = naming.getEscapedReservedName(utils.snakeCaseName(getCorrespondingClientParamName(param)), 'param', reservedParams);
1836
1922
  let paramType = this.getType(param.type);
1837
1923
  // for required header/path/query method string params, we might emit them as borrowed types
1838
1924
  if (!param.optional && !param.onClient && (param.kind === 'header' || param.kind === 'path' || param.kind === 'query')) {
@@ -2087,9 +2173,9 @@ export class Adapter {
2087
2173
  if (payloadType.kind !== 'model') {
2088
2174
  throw new AdapterError('InternalError', `unexpected kind ${payloadType.kind} for spread body param`, (_b = opParamType.__raw) === null || _b === void 0 ? void 0 : _b.node);
2089
2175
  }
2090
- const paramName = naming.getEscapedReservedName(snakeCaseName(param.name), 'param');
2176
+ const paramName = naming.getEscapedReservedName(utils.snakeCaseName(param.name), 'param');
2091
2177
  const paramLoc = 'method';
2092
- const formatType = shared.getPayloadFormatType(format);
2178
+ const formatType = utils.getPayloadFormatType(format);
2093
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));
2094
2180
  return adaptedParam;
2095
2181
  }
@@ -2140,45 +2226,11 @@ export class Adapter {
2140
2226
  }
2141
2227
  /** type guard to determine if type is a Ref<HashMap> */
2142
2228
  function isRefHashMap(type) {
2143
- return shared.asTypeOf(type, 'hashmap', 'ref') !== undefined;
2229
+ return utils.asTypeOf(type, 'hashmap', 'ref') !== undefined;
2144
2230
  }
2145
2231
  /** type guard to determine if type is a Ref<Slice> */
2146
2232
  function isRefSlice(type) {
2147
- return shared.asTypeOf(type, 'slice', 'ref') !== undefined;
2148
- }
2149
- /**
2150
- * transforms Etag etc to all lower case.
2151
- * this is to prevent inadvertently snake-casing
2152
- * Etag to e_tag.
2153
- *
2154
- * if name isn't some variant of Etag the
2155
- * original value is returned.
2156
- *
2157
- * @param name the name to transform
2158
- * @returns etag or the original value
2159
- */
2160
- function fixETagName(name) {
2161
- return name.match(/^etag$/i) ? 'etag' : name;
2162
- }
2163
- /**
2164
- * removes any illegal characters from the provided name.
2165
- * note that characters _ and - are preserved so that the
2166
- * proper snake-casing can be performed.
2167
- *
2168
- * @param name the name to transform
2169
- * @returns the transformed name or the original value
2170
- */
2171
- function removeIllegalChars(name) {
2172
- return name.replace(/[!@#$%^&*()+=]/g, '');
2173
- }
2174
- /**
2175
- * snake-cases the provided name
2176
- *
2177
- * @param name the name to snake-case
2178
- * @returns name in snake-case format
2179
- */
2180
- function snakeCaseName(name) {
2181
- return codegen.deconstruct(fixETagName(removeIllegalChars(name))).join('_');
2233
+ return utils.asTypeOf(type, 'slice', 'ref') !== undefined;
2182
2234
  }
2183
2235
  /**
2184
2236
  * recursively creates a map key from the specified type.
@@ -2208,6 +2260,7 @@ function recursiveKeyName(root, type) {
2208
2260
  return recursiveKeyName(`${root}-${type.kind}`, type.type);
2209
2261
  case 'offsetDateTime':
2210
2262
  return `${root}-${type.kind}-${type.encoding}${type.utc ? '-utc' : ''}`;
2263
+ case 'discriminatedUnion':
2211
2264
  case 'model':
2212
2265
  case 'struct':
2213
2266
  return `${root}-${type.kind}-${type.name}`;
@@ -2269,7 +2322,7 @@ function getXMLKind(decorators, field) {
2269
2322
  case 'TypeSpec.Xml.@attribute':
2270
2323
  return 'attribute';
2271
2324
  case 'TypeSpec.Xml.@unwrapped': {
2272
- const fieldType = shared.unwrapOption(field.type);
2325
+ const fieldType = utils.unwrapOption(field.type);
2273
2326
  switch (fieldType.kind) {
2274
2327
  case 'Vec':
2275
2328
  return 'unwrappedList';