@azure-tools/typespec-ts 0.46.1-alpha.20251201.1 → 0.47.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 (66) hide show
  1. package/CHANGELOG.md +15 -3
  2. package/LICENSE +21 -0
  3. package/dist/src/framework/hooks/sdkTypes.d.ts +7 -1
  4. package/dist/src/framework/hooks/sdkTypes.d.ts.map +1 -1
  5. package/dist/src/framework/hooks/sdkTypes.js +59 -1
  6. package/dist/src/framework/hooks/sdkTypes.js.map +1 -1
  7. package/dist/src/lib.d.ts +19 -1
  8. package/dist/src/lib.d.ts.map +1 -1
  9. package/dist/src/lib.js +12 -0
  10. package/dist/src/lib.js.map +1 -1
  11. package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
  12. package/dist/src/modular/buildClassicalClient.js +84 -6
  13. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  14. package/dist/src/modular/emitModels.d.ts.map +1 -1
  15. package/dist/src/modular/emitModels.js +57 -14
  16. package/dist/src/modular/emitModels.js.map +1 -1
  17. package/dist/src/modular/emitSamples.d.ts.map +1 -1
  18. package/dist/src/modular/emitSamples.js +52 -25
  19. package/dist/src/modular/emitSamples.js.map +1 -1
  20. package/dist/src/modular/helpers/operationHelpers.d.ts +5 -4
  21. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  22. package/dist/src/modular/helpers/operationHelpers.js +113 -23
  23. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  24. package/dist/src/modular/helpers/typeHelpers.d.ts +3 -1
  25. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  26. package/dist/src/modular/helpers/typeHelpers.js +7 -3
  27. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  28. package/dist/src/modular/serialization/buildDeserializerFunction.d.ts +4 -2
  29. package/dist/src/modular/serialization/buildDeserializerFunction.d.ts.map +1 -1
  30. package/dist/src/modular/serialization/buildDeserializerFunction.js +60 -17
  31. package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
  32. package/dist/src/modular/serialization/buildSerializerFunction.d.ts +4 -2
  33. package/dist/src/modular/serialization/buildSerializerFunction.d.ts.map +1 -1
  34. package/dist/src/modular/serialization/buildSerializerFunction.js +61 -19
  35. package/dist/src/modular/serialization/buildSerializerFunction.js.map +1 -1
  36. package/dist/src/modular/serialization/serializeUtils.d.ts +11 -0
  37. package/dist/src/modular/serialization/serializeUtils.d.ts.map +1 -1
  38. package/dist/src/modular/serialization/serializeUtils.js +15 -0
  39. package/dist/src/modular/serialization/serializeUtils.js.map +1 -1
  40. package/dist/src/modular/static-helpers-metadata.d.ts +5 -0
  41. package/dist/src/modular/static-helpers-metadata.d.ts.map +1 -1
  42. package/dist/src/modular/static-helpers-metadata.js +5 -0
  43. package/dist/src/modular/static-helpers-metadata.js.map +1 -1
  44. package/dist/src/utils/namespaceUtils.d.ts.map +1 -1
  45. package/dist/src/utils/namespaceUtils.js +19 -4
  46. package/dist/src/utils/namespaceUtils.js.map +1 -1
  47. package/dist/src/utils/operationUtil.d.ts +1 -0
  48. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  49. package/dist/src/utils/operationUtil.js +26 -0
  50. package/dist/src/utils/operationUtil.js.map +1 -1
  51. package/dist/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +7 -11
  53. package/src/framework/hooks/sdkTypes.ts +102 -2
  54. package/src/lib.ts +12 -0
  55. package/src/modular/buildClassicalClient.ts +116 -6
  56. package/src/modular/emitModels.ts +72 -19
  57. package/src/modular/emitSamples.ts +85 -20
  58. package/src/modular/helpers/operationHelpers.ts +151 -41
  59. package/src/modular/helpers/typeHelpers.ts +19 -3
  60. package/src/modular/serialization/buildDeserializerFunction.ts +87 -35
  61. package/src/modular/serialization/buildSerializerFunction.ts +86 -36
  62. package/src/modular/serialization/serializeUtils.ts +37 -0
  63. package/src/modular/static-helpers-metadata.ts +5 -0
  64. package/src/utils/namespaceUtils.ts +19 -3
  65. package/src/utils/operationUtil.ts +35 -0
  66. package/static/static-helpers/serialization/check-prop-undefined.ts +17 -0
@@ -2,6 +2,7 @@ import { FunctionDeclarationStructure, StructureKind } from "ts-morph";
2
2
  import {
3
3
  SdkArrayType,
4
4
  SdkDictionaryType,
5
+ SdkModelPropertyType,
5
6
  SdkModelType,
6
7
  SdkType,
7
8
  SdkUnionType,
@@ -34,17 +35,55 @@ import {
34
35
  } from "../helpers/typeHelpers.js";
35
36
  import { reportDiagnostic } from "../../lib.js";
36
37
  import { NoTarget } from "@typespec/compiler";
38
+ import { useContext } from "../../contextManager.js";
39
+
40
+ export function buildPropertyDeserializer(
41
+ context: SdkContext,
42
+ property: SdkModelPropertyType,
43
+ options: ModelSerializeOptions = {
44
+ nameOnly: false,
45
+ skipDiscriminatedUnionSuffix: false
46
+ }
47
+ ) {
48
+ const propertyContext =
49
+ useContext("sdkTypes").flattenProperties.get(property);
50
+ // only build de-serializer for flatten property
51
+ if (property.flatten !== true || !propertyContext) {
52
+ return undefined;
53
+ }
54
+
55
+ const predefinedName = `_${normalizeName(
56
+ `${propertyContext.baseModel.name}_${property.name}`,
57
+ NameType.Method,
58
+ true
59
+ )}Deserializer`;
60
+ return buildModelDeserializer(context, property.type, {
61
+ ...options,
62
+ flatten: {
63
+ baseModel: propertyContext.baseModel,
64
+ property
65
+ },
66
+ overrides: {
67
+ allOptional: property.optional,
68
+ propertyRenames: propertyContext.conflictMap
69
+ },
70
+ predefinedName
71
+ });
72
+ }
37
73
 
38
74
  export function buildModelDeserializer(
39
75
  context: SdkContext,
40
76
  type: SdkType,
41
- skipDiscriminatedUnion = false,
42
- nameOnly: boolean = false
77
+ options: ModelSerializeOptions = {
78
+ nameOnly: false,
79
+ skipDiscriminatedUnionSuffix: false
80
+ }
43
81
  ): FunctionDeclarationStructure | undefined | string {
44
82
  // const modelTcgcType = getTcgcType(type) as SdkModelType;
45
83
  if (!isSupportedSerializeType(type)) {
46
84
  return undefined;
47
85
  }
86
+ const { nameOnly, skipDiscriminatedUnionSuffix } = options;
48
87
  if (type.kind === "model" || type.kind === "union" || type.kind === "enum") {
49
88
  if (
50
89
  !type.usage ||
@@ -72,16 +111,13 @@ export function buildModelDeserializer(
72
111
  return buildPolymorphicDeserializer(context, type, nameOnly);
73
112
  }
74
113
 
75
- if (isDiscriminatedUnion(type) && !skipDiscriminatedUnion) {
114
+ if (isDiscriminatedUnion(type) && !skipDiscriminatedUnionSuffix) {
76
115
  return buildDiscriminatedUnionDeserializer(context, type, nameOnly);
77
116
  }
78
117
 
79
118
  switch (type.kind) {
80
119
  case "model":
81
- return buildModelTypeDeserializer(context, type, {
82
- nameOnly,
83
- skipDiscriminatedUnionSuffix: skipDiscriminatedUnion
84
- });
120
+ return buildModelTypeDeserializer(context, type, options);
85
121
  case "union": // for non-discriminated union, we just return whatever we get
86
122
  return buildUnionDeserializer(context, type, nameOnly);
87
123
  case "dict":
@@ -220,6 +256,7 @@ function buildDiscriminatedUnionDeserializer(
220
256
  if (nameOnly) {
221
257
  return resolveReference(refkey(type, "deserializer"));
222
258
  }
259
+ // Get the base deserializer name and ensure reference tracking
223
260
  const baseDeserializerName = `${normalizeModelName(
224
261
  context,
225
262
  type,
@@ -241,12 +278,17 @@ function buildDiscriminatedUnionDeserializer(
241
278
  type.discriminatorProperty
242
279
  );
243
280
  const union = subType.discriminatedSubtypes ? "Union" : "";
244
- const subTypeName = `${normalizeName(subType.name, NameType.Interface, true)}${union}`;
245
- const subtypeDeserializerName = normalizeName(
246
- `${subTypeName}Deserializer`,
247
- NameType.Operation,
248
- true
281
+ const subTypeName = normalizeModelName(
282
+ context,
283
+ subType,
284
+ NameType.Interface,
285
+ !union
249
286
  );
287
+ // Get the deserializer name and ensure reference tracking
288
+ const subtypeDeserializerName = buildModelDeserializer(context, subType, {
289
+ nameOnly: true,
290
+ skipDiscriminatedUnionSuffix: false
291
+ }) as string;
250
292
 
251
293
  const caseLabels = discriminatedValues.map((value) => `case "${value}":`);
252
294
  cases.push(`
@@ -338,14 +380,18 @@ function buildModelTypeDeserializer(
338
380
  });
339
381
  return ""; // Return empty string to continue processing
340
382
  }
341
- const deserializerFunctionName = `${normalizeModelName(
342
- context,
343
- type,
344
- NameType.Operation,
345
- options.skipDiscriminatedUnionSuffix
346
- )}Deserializer`;
383
+ const deserializerFunctionName =
384
+ options.predefinedName ??
385
+ `${normalizeModelName(
386
+ context,
387
+ type,
388
+ NameType.Operation,
389
+ options.skipDiscriminatedUnionSuffix
390
+ )}Deserializer`;
347
391
  if (options.nameOnly) {
348
- return resolveReference(refkey(type, "deserializer"));
392
+ return options.flatten
393
+ ? resolveReference(refkey(options.flatten.property, "deserializer"))
394
+ : resolveReference(refkey(type, "deserializer"));
349
395
  }
350
396
  const deserializerFunction: FunctionDeclarationStructure = {
351
397
  kind: StructureKind.Function,
@@ -357,7 +403,9 @@ function buildModelTypeDeserializer(
357
403
  type: "any"
358
404
  }
359
405
  ],
360
- returnType: resolveReference(refkey(type)),
406
+ returnType: options.flatten
407
+ ? undefined // not set return type for flattened property deserializer and type system will infer correct one
408
+ : resolveReference(refkey(type)),
361
409
  statements: ["return item;"]
362
410
  };
363
411
  const nullabilityPrefix = "";
@@ -365,7 +413,13 @@ function buildModelTypeDeserializer(
365
413
  const additionalPropertiesSpread =
366
414
  getAdditionalPropertiesStatement(context, type) ?? "";
367
415
 
368
- const propertiesStr = getResponseMapping(context, type, "item");
416
+ const propertiesStr = getResponseMapping(
417
+ context,
418
+ type,
419
+ "item",
420
+ options.overrides,
421
+ !options.flatten
422
+ );
369
423
  const propertiesDeserialization = propertiesStr.filter((p) => p.trim());
370
424
 
371
425
  const output = [];
@@ -406,8 +460,10 @@ function getAdditionalPropertiesStatement(
406
460
  const deserializerFunction = buildModelDeserializer(
407
461
  context,
408
462
  additionalPropertyType,
409
- false,
410
- true
463
+ {
464
+ nameOnly: true,
465
+ skipDiscriminatedUnionSuffix: false
466
+ }
411
467
  );
412
468
  if (typeof deserializerFunction === "string") {
413
469
  params.push(deserializerFunction);
@@ -431,12 +487,10 @@ function buildDictTypeDeserializer(
431
487
  type: SdkDictionaryType,
432
488
  nameOnly = false
433
489
  ): FunctionDeclarationStructure | undefined | string {
434
- const valueDeserializer = buildModelDeserializer(
435
- context,
436
- type.valueType,
437
- false,
438
- true
439
- );
490
+ const valueDeserializer = buildModelDeserializer(context, type.valueType, {
491
+ nameOnly: true,
492
+ skipDiscriminatedUnionSuffix: false
493
+ });
440
494
  if (!valueDeserializer) {
441
495
  return undefined;
442
496
  }
@@ -490,12 +544,10 @@ function buildArrayTypeDeserializer(
490
544
  type: SdkArrayType,
491
545
  nameOnly = false
492
546
  ): FunctionDeclarationStructure | undefined | string {
493
- const valueDeserializer = buildModelDeserializer(
494
- context,
495
- type.valueType,
496
- false,
497
- true
498
- );
547
+ const valueDeserializer = buildModelDeserializer(context, type.valueType, {
548
+ nameOnly: true,
549
+ skipDiscriminatedUnionSuffix: false
550
+ });
499
551
  if (!valueDeserializer) {
500
552
  return undefined;
501
553
  }
@@ -2,6 +2,7 @@ import { FunctionDeclarationStructure, StructureKind } from "ts-morph";
2
2
  import {
3
3
  SdkArrayType,
4
4
  SdkDictionaryType,
5
+ SdkModelPropertyType,
5
6
  SdkModelType,
6
7
  SdkType,
7
8
  SdkUnionType,
@@ -40,17 +41,53 @@ import {
40
41
  } from "../helpers/typeHelpers.js";
41
42
  import { reportDiagnostic } from "../../lib.js";
42
43
  import { NoTarget } from "@typespec/compiler";
44
+ import { useContext } from "../../contextManager.js";
45
+
46
+ export function buildPropertySerializer(
47
+ context: SdkContext,
48
+ property: SdkModelPropertyType,
49
+ options: ModelSerializeOptions = {
50
+ nameOnly: false,
51
+ skipDiscriminatedUnionSuffix: false
52
+ }
53
+ ) {
54
+ const propertyContext =
55
+ useContext("sdkTypes").flattenProperties.get(property);
56
+ // only build de-serializer for flatten property
57
+ if (property.flatten !== true || !propertyContext) {
58
+ return undefined;
59
+ }
60
+ const predefinedName = `_${normalizeName(
61
+ `${propertyContext.baseModel.name}_${property.name}`,
62
+ NameType.Method,
63
+ true
64
+ )}Serializer`;
65
+ return buildModelSerializer(context, property.type, {
66
+ ...options,
67
+ flatten: {
68
+ baseModel: propertyContext.baseModel,
69
+ property
70
+ },
71
+ overrides: {
72
+ allOptional: property.optional,
73
+ propertyRenames: propertyContext.conflictMap
74
+ },
75
+ predefinedName
76
+ });
77
+ }
43
78
 
44
79
  export function buildModelSerializer(
45
80
  context: SdkContext,
46
81
  type: SdkType,
47
- skipDiscriminatedUnion = false,
48
- nameOnly: boolean = false
82
+ options: ModelSerializeOptions = {
83
+ nameOnly: false,
84
+ skipDiscriminatedUnionSuffix: false
85
+ }
49
86
  ): FunctionDeclarationStructure | undefined | string {
50
- // const modelTcgcType = getTcgcType(type) as SdkModelType;
51
87
  if (!isSupportedSerializeType(type)) {
52
88
  return undefined;
53
89
  }
90
+ const { nameOnly } = options;
54
91
  if (type.kind === "model" || type.kind === "union" || type.kind === "enum") {
55
92
  if (
56
93
  !type.usage ||
@@ -80,16 +117,13 @@ export function buildModelSerializer(
80
117
  return buildPolymorphicSerializer(context, type, nameOnly);
81
118
  }
82
119
 
83
- if (isDiscriminatedUnion(type) && !skipDiscriminatedUnion) {
120
+ if (isDiscriminatedUnion(type) && !options.skipDiscriminatedUnionSuffix) {
84
121
  return buildDiscriminatedUnionSerializer(context, type, nameOnly);
85
122
  }
86
123
 
87
124
  switch (type.kind) {
88
125
  case "model":
89
- return buildModelTypeSerializer(context, type, {
90
- nameOnly,
91
- skipDiscriminatedUnionSuffix: skipDiscriminatedUnion
92
- });
126
+ return buildModelTypeSerializer(context, type, options);
93
127
  case "union": // for non-discriminated union, we just return whatever we get
94
128
  return buildUnionSerializer(context, type, nameOnly);
95
129
  case "dict":
@@ -227,6 +261,7 @@ function buildDiscriminatedUnionSerializer(
227
261
  if (nameOnly) {
228
262
  return resolveReference(refkey(type, "serializer"));
229
263
  }
264
+ // Get the base serializer name and ensure reference tracking
230
265
  const baseSerializerName = `${normalizeModelName(
231
266
  context,
232
267
  type,
@@ -248,12 +283,17 @@ function buildDiscriminatedUnionSerializer(
248
283
  type.discriminatorProperty
249
284
  );
250
285
  const union = subType.discriminatedSubtypes ? "Union" : "";
251
- const subTypeName = `${normalizeName(subType.name, NameType.Interface, true)}${union}`;
252
- const subtypeSerializerName = normalizeName(
253
- `${subTypeName}Serializer`,
254
- NameType.Method,
255
- true
286
+ const subTypeName = normalizeModelName(
287
+ context,
288
+ subType,
289
+ NameType.Interface,
290
+ !union
256
291
  );
292
+ // Get the serializer name and ensure reference tracking
293
+ const subtypeSerializerName = buildModelSerializer(context, subType, {
294
+ nameOnly: true,
295
+ skipDiscriminatedUnionSuffix: false
296
+ }) as string;
257
297
 
258
298
  const caseLabels = discriminatedValues.map((value) => `case "${value}":`);
259
299
  cases.push(`
@@ -345,14 +385,18 @@ function buildModelTypeSerializer(
345
385
  });
346
386
  return ""; // Return empty string to continue processing
347
387
  }
348
- const serializerFunctionName = `${normalizeModelName(
349
- context,
350
- type,
351
- NameType.Operation,
352
- options.skipDiscriminatedUnionSuffix
353
- )}Serializer`;
388
+ const serializerFunctionName =
389
+ options.predefinedName ??
390
+ `${normalizeModelName(
391
+ context,
392
+ type,
393
+ NameType.Operation,
394
+ options.skipDiscriminatedUnionSuffix
395
+ )}Serializer`;
354
396
  if (options.nameOnly) {
355
- return resolveReference(refkey(type, "serializer"));
397
+ return options.flatten
398
+ ? resolveReference(refkey(options.flatten.property, "serializer"))
399
+ : resolveReference(refkey(type, "serializer"));
356
400
  }
357
401
  const serializerFunction: FunctionDeclarationStructure = {
358
402
  kind: StructureKind.Function,
@@ -361,7 +405,9 @@ function buildModelTypeSerializer(
361
405
  parameters: [
362
406
  {
363
407
  name: "item",
364
- type: resolveReference(refkey(type))
408
+ type: options.flatten
409
+ ? resolveReference(refkey(options.flatten.baseModel))
410
+ : resolveReference(refkey(type))
365
411
  }
366
412
  ],
367
413
  returnType: "any",
@@ -435,7 +481,13 @@ function buildModelTypeSerializer(
435
481
  type
436
482
  );
437
483
 
438
- const propertiesStr = getRequestModelMapping(context, type, "item");
484
+ const propertiesStr = getRequestModelMapping(
485
+ context,
486
+ type,
487
+ "item",
488
+ options.overrides,
489
+ !options.flatten
490
+ );
439
491
 
440
492
  if (additionalPropertiesSpread) {
441
493
  propertiesStr.unshift(additionalPropertiesSpread);
@@ -470,8 +522,10 @@ function getAdditionalPropertiesStatement(
470
522
  const deserializerFunction = buildModelSerializer(
471
523
  context,
472
524
  additionalPropertyType,
473
- false,
474
- true
525
+ {
526
+ nameOnly: true,
527
+ skipDiscriminatedUnionSuffix: false
528
+ }
475
529
  );
476
530
  const params = [`item.${getAdditionalPropertiesName(context, type)} ?? {}`];
477
531
  if (typeof deserializerFunction === "string") {
@@ -497,12 +551,10 @@ function buildDictTypeSerializer(
497
551
  type: SdkDictionaryType,
498
552
  nameOnly = false
499
553
  ): FunctionDeclarationStructure | undefined | string {
500
- const valueSerializer = buildModelSerializer(
501
- context,
502
- type.valueType,
503
- false,
504
- true
505
- );
554
+ const valueSerializer = buildModelSerializer(context, type.valueType, {
555
+ nameOnly: true,
556
+ skipDiscriminatedUnionSuffix: false
557
+ });
506
558
  if (!valueSerializer) {
507
559
  return undefined;
508
560
  }
@@ -555,12 +607,10 @@ function buildArrayTypeSerializer(
555
607
  type: SdkArrayType,
556
608
  nameOnly = false
557
609
  ): FunctionDeclarationStructure | undefined | string {
558
- const valueSerializer = buildModelSerializer(
559
- context,
560
- type.valueType,
561
- false,
562
- true
563
- );
610
+ const valueSerializer = buildModelSerializer(context, type.valueType, {
611
+ nameOnly: true,
612
+ skipDiscriminatedUnionSuffix: false
613
+ });
564
614
  if (!valueSerializer) {
565
615
  return undefined;
566
616
  }
@@ -182,4 +182,41 @@ export function isPolymorphicUnion(t: SdkType): boolean {
182
182
  export interface ModelSerializeOptions {
183
183
  nameOnly: boolean;
184
184
  skipDiscriminatedUnionSuffix: boolean;
185
+ // Indicates if the serializer is being built for a property that is flattened.
186
+ flatten?: {
187
+ baseModel: SdkModelType;
188
+ property: SdkModelPropertyType;
189
+ };
190
+ // Indicates if any overrides should be applied when building the serializer/deserializer.
191
+ overrides?: ModelOverrideOptions;
192
+ // Predefined name to use for the serializer/deserializer instead of generating one.
193
+ predefinedName?: string;
194
+ }
195
+
196
+ // Options for overriding model information during serialization/deserialization.
197
+ export interface ModelOverrideOptions {
198
+ // If true, all properties will be treated as optional during serialization/deserialization.
199
+ allOptional?: boolean;
200
+
201
+ // The <Property, Client_Name> map for any renamed properties.
202
+ // Mainly because the original client name has collision with other property names during flattening.
203
+ propertyRenames?: Map<SdkModelPropertyType, string>;
204
+ }
205
+
206
+ export function getPropertyWithOverrides(
207
+ property: SdkModelPropertyType,
208
+ overrides?: ModelOverrideOptions
209
+ ): SdkModelPropertyType {
210
+ if (!overrides) {
211
+ return property;
212
+ }
213
+ let updatedProperty = property;
214
+ if (overrides.allOptional) {
215
+ updatedProperty = { ...updatedProperty, optional: true };
216
+ }
217
+ const renamedClientName = overrides.propertyRenames?.get(property);
218
+ if (renamedClientName) {
219
+ updatedProperty = { ...updatedProperty, name: renamedClientName };
220
+ }
221
+ return updatedProperty;
185
222
  }
@@ -33,6 +33,11 @@ export const SerializationHelpers = {
33
33
  kind: "function",
34
34
  name: "getBinaryResponse",
35
35
  location: "serialization/get-binary-response.ts"
36
+ },
37
+ areAllPropsUndefined: {
38
+ kind: "function",
39
+ name: "areAllPropsUndefined",
40
+ location: "serialization/check-prop-undefined.ts"
36
41
  }
37
42
  } as const;
38
43
 
@@ -3,8 +3,10 @@ import {
3
3
  isGlobalNamespace,
4
4
  isService,
5
5
  Namespace,
6
+ NoTarget,
6
7
  Operation
7
8
  } from "@typespec/compiler";
9
+ import { reportDiagnostic } from "../lib.js";
8
10
  import { SdkContext } from "./interfaces.js";
9
11
 
10
12
  export function getModelNamespaceName(
@@ -68,14 +70,28 @@ export function getOperationNamespaceInterfaceName(
68
70
  export function detectModelConflicts(dpgContext: SdkContext) {
69
71
  const allModels = getAllModels(dpgContext);
70
72
  const nameSet = new Set<string>();
73
+ const reported = new Set<string>();
74
+ let hasConflict = false;
71
75
  for (const model of allModels) {
72
76
  if (model.name === "") {
73
77
  continue;
74
78
  }
75
- if (nameSet.has(model.name)) {
76
- return true;
79
+ if (nameSet.has(model.name) && !reported.has(model.name)) {
80
+ reportDiagnostic(dpgContext.program, {
81
+ code: "detected-model-name-conflict",
82
+ format: {
83
+ modelName: model.name,
84
+ namespaces: allModels
85
+ .filter((m) => m.name === model.name)
86
+ .map((m) => m.namespace)
87
+ .join(" and ")
88
+ },
89
+ target: NoTarget
90
+ });
91
+ reported.add(model.name);
92
+ hasConflict = true;
77
93
  }
78
94
  nameSet.add(model.name);
79
95
  }
80
- return false;
96
+ return hasConflict;
81
97
  }
@@ -679,6 +679,41 @@ export function getMethodHierarchiesMap(
679
679
  return operationHierarchiesMap;
680
680
  }
681
681
 
682
+ export function isTenantLevelOperation(
683
+ operation: ServiceOperation,
684
+ client: SdkClientType<SdkServiceOperation>
685
+ ): boolean {
686
+ // Check if this operation has a subscriptionId path parameter
687
+ const subscriptionIdParam = operation.operation.parameters?.find(
688
+ (param) =>
689
+ param.name.toLowerCase() === "subscriptionid" && param.kind === "path"
690
+ );
691
+
692
+ if (subscriptionIdParam) {
693
+ // The operation has a client-level subscriptionId parameter, then it's not tenant-level
694
+ if (subscriptionIdParam.onClient) {
695
+ return false;
696
+ }
697
+ } else {
698
+ // Skip tenant-level internal ARM APIs
699
+ // Ref: https://armwiki.azurewebsites.net/rpaas/operations_auto_gen.html#special-cases
700
+ const pathLC = operation.operation.path.toLowerCase();
701
+ // Get the provider namespace from the client
702
+ const clientNamespaceLC = client.namespace.toLowerCase();
703
+ if (
704
+ operation.crossLanguageDefinitionId?.toLowerCase() ===
705
+ "azure.resourcemanager.operations.list" ||
706
+ pathLC.includes(`${clientNamespaceLC}/checknameavailability`)
707
+ ) {
708
+ return false;
709
+ }
710
+ }
711
+
712
+ // The operation has no subscriptionId parameter or has method-level subscriptionId parameter
713
+ // Considered as tenant-level
714
+ return true;
715
+ }
716
+
682
717
  function resolveParameterNameConflict(
683
718
  operationOrGroup: SdkServiceMethod<SdkHttpOperation>,
684
719
  p: SdkMethodParameter | SdkHttpParameter | SdkBodyParameter
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Returns true if all specified properties of the item are undefined.
3
+ * @param item The object to check.
4
+ * @param properties The list of property names to check on the item.
5
+ * @returns True if all specified properties are undefined, otherwise false.
6
+ */
7
+ export function areAllPropsUndefined(
8
+ item: Record<string, any>,
9
+ properties: string[]
10
+ ): boolean {
11
+ for (const property of properties) {
12
+ if (item[property] !== undefined) {
13
+ return false;
14
+ }
15
+ }
16
+ return true;
17
+ }