@azure-tools/typespec-ts 0.56.1-dev.1 → 0.57.0-dev.10

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 (120) hide show
  1. package/README.md +6 -0
  2. package/dist/src/framework/hooks/sdk-types.d.ts.map +1 -1
  3. package/dist/src/framework/hooks/sdk-types.js +2 -0
  4. package/dist/src/framework/hooks/sdk-types.js.map +1 -1
  5. package/dist/src/interfaces.d.ts +4 -0
  6. package/dist/src/interfaces.d.ts.map +1 -1
  7. package/dist/src/interfaces.js.map +1 -1
  8. package/dist/src/lib.d.ts +11 -1
  9. package/dist/src/lib.d.ts.map +1 -1
  10. package/dist/src/lib.js +11 -0
  11. package/dist/src/lib.js.map +1 -1
  12. package/dist/src/metadata/build-package-file.d.ts +1 -0
  13. package/dist/src/metadata/build-package-file.d.ts.map +1 -1
  14. package/dist/src/metadata/build-package-file.js +3 -0
  15. package/dist/src/metadata/build-package-file.js.map +1 -1
  16. package/dist/src/metadata/package-json/build-azure-monorepo-package.d.ts +2 -0
  17. package/dist/src/metadata/package-json/build-azure-monorepo-package.d.ts.map +1 -1
  18. package/dist/src/metadata/package-json/build-azure-monorepo-package.js +1 -0
  19. package/dist/src/metadata/package-json/build-azure-monorepo-package.js.map +1 -1
  20. package/dist/src/modular/build-classical-client.d.ts.map +1 -1
  21. package/dist/src/modular/build-classical-client.js +19 -33
  22. package/dist/src/modular/build-classical-client.js.map +1 -1
  23. package/dist/src/modular/build-operations.d.ts.map +1 -1
  24. package/dist/src/modular/build-operations.js +4 -5
  25. package/dist/src/modular/build-operations.js.map +1 -1
  26. package/dist/src/modular/build-root-index.js +1 -1
  27. package/dist/src/modular/build-root-index.js.map +1 -1
  28. package/dist/src/modular/emit-models.d.ts.map +1 -1
  29. package/dist/src/modular/emit-models.js +46 -23
  30. package/dist/src/modular/emit-models.js.map +1 -1
  31. package/dist/src/modular/emit-samples.d.ts.map +1 -1
  32. package/dist/src/modular/emit-samples.js +29 -21
  33. package/dist/src/modular/emit-samples.js.map +1 -1
  34. package/dist/src/modular/emit-tests.js +2 -2
  35. package/dist/src/modular/emit-tests.js.map +1 -1
  36. package/dist/src/modular/helpers/classical-operation-helpers.d.ts.map +1 -1
  37. package/dist/src/modular/helpers/classical-operation-helpers.js +17 -15
  38. package/dist/src/modular/helpers/classical-operation-helpers.js.map +1 -1
  39. package/dist/src/modular/helpers/client-helpers.d.ts.map +1 -1
  40. package/dist/src/modular/helpers/client-helpers.js +7 -6
  41. package/dist/src/modular/helpers/client-helpers.js.map +1 -1
  42. package/dist/src/modular/helpers/example-value-helpers.d.ts +2 -1
  43. package/dist/src/modular/helpers/example-value-helpers.d.ts.map +1 -1
  44. package/dist/src/modular/helpers/example-value-helpers.js +34 -24
  45. package/dist/src/modular/helpers/example-value-helpers.js.map +1 -1
  46. package/dist/src/modular/helpers/naming-helpers.d.ts.map +1 -1
  47. package/dist/src/modular/helpers/naming-helpers.js +3 -3
  48. package/dist/src/modular/helpers/naming-helpers.js.map +1 -1
  49. package/dist/src/modular/helpers/operation-helpers.d.ts.map +1 -1
  50. package/dist/src/modular/helpers/operation-helpers.js +23 -18
  51. package/dist/src/modular/helpers/operation-helpers.js.map +1 -1
  52. package/dist/src/modular/helpers/type-helpers.d.ts.map +1 -1
  53. package/dist/src/modular/helpers/type-helpers.js +2 -2
  54. package/dist/src/modular/helpers/type-helpers.js.map +1 -1
  55. package/dist/src/modular/helpers/visibility-helpers.d.ts +7 -0
  56. package/dist/src/modular/helpers/visibility-helpers.d.ts.map +1 -0
  57. package/dist/src/modular/helpers/visibility-helpers.js +353 -0
  58. package/dist/src/modular/helpers/visibility-helpers.js.map +1 -0
  59. package/dist/src/modular/serialization/build-deserializer-function.js +6 -4
  60. package/dist/src/modular/serialization/build-deserializer-function.js.map +1 -1
  61. package/dist/src/modular/serialization/build-serializer-function.d.ts.map +1 -1
  62. package/dist/src/modular/serialization/build-serializer-function.js +9 -7
  63. package/dist/src/modular/serialization/build-serializer-function.js.map +1 -1
  64. package/dist/src/modular/serialization/build-xml-serializer-function.d.ts.map +1 -1
  65. package/dist/src/modular/serialization/build-xml-serializer-function.js +11 -13
  66. package/dist/src/modular/serialization/build-xml-serializer-function.js.map +1 -1
  67. package/dist/src/modular/type-expressions/get-type-expression.d.ts +1 -0
  68. package/dist/src/modular/type-expressions/get-type-expression.d.ts.map +1 -1
  69. package/dist/src/modular/type-expressions/get-type-expression.js +6 -4
  70. package/dist/src/modular/type-expressions/get-type-expression.js.map +1 -1
  71. package/dist/src/transform/transform-client-options.d.ts.map +1 -1
  72. package/dist/src/transform/transform-client-options.js +2 -0
  73. package/dist/src/transform/transform-client-options.js.map +1 -1
  74. package/dist/src/utils/client-utils.d.ts.map +1 -1
  75. package/dist/src/utils/client-utils.js +16 -5
  76. package/dist/src/utils/client-utils.js.map +1 -1
  77. package/dist/src/utils/cross-language-def.d.ts.map +1 -1
  78. package/dist/src/utils/cross-language-def.js +1 -2
  79. package/dist/src/utils/cross-language-def.js.map +1 -1
  80. package/dist/src/utils/interfaces.d.ts +1 -0
  81. package/dist/src/utils/interfaces.d.ts.map +1 -1
  82. package/dist/src/utils/name-utils.d.ts +15 -0
  83. package/dist/src/utils/name-utils.d.ts.map +1 -1
  84. package/dist/src/utils/name-utils.js +60 -0
  85. package/dist/src/utils/name-utils.js.map +1 -1
  86. package/dist/src/utils/operation-util.d.ts.map +1 -1
  87. package/dist/src/utils/operation-util.js +15 -5
  88. package/dist/src/utils/operation-util.js.map +1 -1
  89. package/dist/tsconfig.tsbuildinfo +1 -1
  90. package/package.json +35 -35
  91. package/src/framework/hooks/sdk-types.ts +2 -0
  92. package/src/interfaces.ts +4 -0
  93. package/src/lib.ts +13 -0
  94. package/src/metadata/build-package-file.ts +4 -0
  95. package/src/metadata/package-json/build-azure-monorepo-package.ts +1 -0
  96. package/src/modular/build-classical-client.ts +21 -32
  97. package/src/modular/build-operations.ts +4 -5
  98. package/src/modular/build-root-index.ts +1 -1
  99. package/src/modular/emit-models.ts +59 -24
  100. package/src/modular/emit-samples.ts +42 -34
  101. package/src/modular/emit-tests.ts +2 -2
  102. package/src/modular/helpers/classical-operation-helpers.ts +21 -20
  103. package/src/modular/helpers/client-helpers.ts +6 -5
  104. package/src/modular/helpers/example-value-helpers.ts +52 -41
  105. package/src/modular/helpers/naming-helpers.ts +8 -3
  106. package/src/modular/helpers/operation-helpers.ts +31 -18
  107. package/src/modular/helpers/type-helpers.ts +2 -5
  108. package/src/modular/helpers/visibility-helpers.ts +471 -0
  109. package/src/modular/serialization/build-deserializer-function.ts +6 -9
  110. package/src/modular/serialization/build-serializer-function.ts +14 -11
  111. package/src/modular/serialization/build-xml-serializer-function.ts +11 -17
  112. package/src/modular/type-expressions/get-type-expression.ts +10 -4
  113. package/src/transform/transform-client-options.ts +3 -0
  114. package/src/utils/client-utils.ts +28 -4
  115. package/src/utils/cross-language-def.ts +1 -2
  116. package/src/utils/interfaces.ts +1 -0
  117. package/src/utils/name-utils.ts +94 -0
  118. package/src/utils/operation-util.ts +27 -14
  119. package/static/static-helpers/storageCompatResponse.ts +3 -2
  120. package/static/static-helpers/urlTemplate.ts +4 -2
@@ -16,7 +16,12 @@ import { refkey } from "../../framework/refkey.js";
16
16
  import { reportDiagnostic } from "../../lib.js";
17
17
  import type { SdkContext } from "../../utils/interfaces.js";
18
18
  import { isAzureCoreErrorType } from "../../utils/model-utils.js";
19
- import { NameType, normalizeName } from "../../utils/name-utils.js";
19
+ import {
20
+ formatPropertyAccess,
21
+ NameType,
22
+ normalizeName,
23
+ normalizeSdkPropertyName,
24
+ } from "../../utils/name-utils.js";
20
25
  import { getAdditionalPropertiesName, normalizeModelName } from "../emit-models.js";
21
26
  import {
22
27
  getAllAncestors,
@@ -185,7 +190,6 @@ function buildPolymorphicSerializer(
185
190
  ) {
186
191
  return;
187
192
  }
188
- const union = subType?.discriminatedSubtypes ? "_Union" : "";
189
193
  if (!subType || !subType?.name) {
190
194
  reportDiagnostic(context.program, {
191
195
  code: "anonymous-type-serialization",
@@ -193,13 +197,12 @@ function buildPolymorphicSerializer(
193
197
  });
194
198
  return; // Skip this subtype
195
199
  }
196
- const rawSubTypeName = `${subType.name}${union}`;
197
- const subTypeName = `${normalizeName(rawSubTypeName, NameType.Interface, true)}`;
198
- const subtypeSerializerName = normalizeName(
199
- `${rawSubTypeName}_Serializer`,
200
- NameType.Method,
201
- true,
202
- );
200
+ const union = subType.discriminatedSubtypes ? "Union" : "";
201
+ const subTypeName = normalizeModelName(context, subType, NameType.Interface, !union);
202
+ const subtypeSerializerName = buildModelSerializer(context, subType, {
203
+ nameOnly: true,
204
+ skipDiscriminatedUnionSuffix: false,
205
+ }) as string;
203
206
 
204
207
  cases.push(`
205
208
  case "${discriminatedValue}":
@@ -208,7 +211,7 @@ function buildPolymorphicSerializer(
208
211
  });
209
212
 
210
213
  statements.push(`
211
- switch (item.${normalizeName(type.discriminatorProperty.name, NameType.Property)}) {
214
+ switch (${formatPropertyAccess("item", normalizeSdkPropertyName(type.discriminatorProperty))}) {
212
215
  ${cases.join("\n")}
213
216
  default:
214
217
  return item;
@@ -281,7 +284,7 @@ function buildDiscriminatedUnionSerializer(
281
284
  `);
282
285
  }
283
286
  output.push(`
284
- switch (item.${type.discriminatorProperty ? normalizeName(type.discriminatorProperty.name, NameType.Property) : "unknown"}) {
287
+ switch (${formatPropertyAccess("item", type.discriminatorProperty ? normalizeSdkPropertyName(type.discriminatorProperty) : "unknown")}) {
285
288
  ${cases.join("\n")}
286
289
  default:
287
290
  return ${baseSerializerName}(item);
@@ -23,7 +23,7 @@ import { getAdditionalPropertiesName, normalizeModelName } from "../emit-models.
23
23
  import { getAllAncestors, getAllProperties } from "../helpers/operation-helpers.js";
24
24
  import { getAdditionalPropertiesType } from "../helpers/type-helpers.js";
25
25
  import { XmlHelpers } from "../static-helpers-metadata.js";
26
- import { normalizeModelPropertyName } from "../type-expressions/get-type-expression.js";
26
+ import { getModelPropertyName } from "../type-expressions/get-type-expression.js";
27
27
  import { isSupportedSerializeType, type ModelSerializeOptions } from "./serialize-utils.js";
28
28
 
29
29
  /**
@@ -290,8 +290,8 @@ function buildXmlObjectPropertyAssignments(
290
290
  }
291
291
 
292
292
  const xmlOptions = property.serializationOptions?.xml;
293
- const propertyName = normalizeModelPropertyName(context, property);
294
- const cleanPropertyName = propertyName.replace(/^"|"$/g, "");
293
+ const propertyName = getModelPropertyName(context, property);
294
+ const propertyAccessor = `item[${JSON.stringify(propertyName)}]`;
295
295
 
296
296
  // Use XML name if available, fall back to serializedName, then JSON name, then property name
297
297
  const xmlName = xmlOptions?.name ?? property.name;
@@ -302,14 +302,14 @@ function buildXmlObjectPropertyAssignments(
302
302
  let valueExpr: string;
303
303
  if (nestedSerializer && property.type.kind === "model") {
304
304
  // Nested object - use XML object serializer
305
- valueExpr = `item["${cleanPropertyName}"] !== undefined ? ${nestedSerializer}(item["${cleanPropertyName}"]) : undefined`;
305
+ valueExpr = `${propertyAccessor} !== undefined ? ${nestedSerializer}(${propertyAccessor}) : undefined`;
306
306
  } else if (
307
307
  nestedSerializer &&
308
308
  property.type.kind === "array" &&
309
309
  property.type.valueType.kind === "model"
310
310
  ) {
311
311
  // Array of objects - map each item through XML object serializer
312
- const mappedExpr = `item["${cleanPropertyName}"]?.map((i: any) => ${nestedSerializer}(i))`;
312
+ const mappedExpr = `${propertyAccessor}?.map((i: any) => ${nestedSerializer}(i))`;
313
313
  if (xmlOptions?.unwrapped) {
314
314
  // Unwrapped: items are direct siblings under the item element name
315
315
  const itemKey = xmlOptions?.itemsName ?? xmlName;
@@ -326,7 +326,7 @@ function buildXmlObjectPropertyAssignments(
326
326
  const primitiveExpr = buildXmlValueSerializationExpr(
327
327
  context,
328
328
  property.type,
329
- `item["${cleanPropertyName}"]`,
329
+ propertyAccessor,
330
330
  );
331
331
  if (xmlOptions?.unwrapped) {
332
332
  const itemKey = xmlOptions?.itemsName ?? xmlName;
@@ -339,11 +339,7 @@ function buildXmlObjectPropertyAssignments(
339
339
  }
340
340
  } else {
341
341
  // Handle type-specific serialization
342
- valueExpr = buildXmlValueSerializationExpr(
343
- context,
344
- property.type,
345
- `item["${cleanPropertyName}"]`,
346
- );
342
+ valueExpr = buildXmlValueSerializationExpr(context, property.type, propertyAccessor);
347
343
  }
348
344
 
349
345
  assignments.push(`"${xmlName}": ${valueExpr}`);
@@ -419,14 +415,13 @@ function buildPropertyMetadataArray(
419
415
 
420
416
  const xmlOptions = property.serializationOptions?.xml;
421
417
  const jsonOptions = property.serializationOptions?.json;
422
- const propertyName = normalizeModelPropertyName(context, property);
423
- const cleanPropertyName = propertyName.replace(/^"|"$/g, "");
418
+ const propertyName = getModelPropertyName(context, property);
424
419
 
425
420
  // Use XML name if available, fall back to JSON name, then property name
426
421
  const serializedName = xmlOptions?.name ?? jsonOptions?.name ?? property.name;
427
422
 
428
423
  const metadataObj: string[] = [
429
- `propertyName: "${cleanPropertyName}"`,
424
+ `propertyName: ${JSON.stringify(propertyName)}`,
430
425
  `xmlOptions: { name: "${serializedName}"${buildXmlOptionsString(xmlOptions)} }`,
431
426
  ];
432
427
 
@@ -737,14 +732,13 @@ function buildDeserializePropertyMetadataArray(
737
732
 
738
733
  const xmlOptions = property.serializationOptions?.xml;
739
734
  const jsonOptions = property.serializationOptions?.json;
740
- const propertyName = normalizeModelPropertyName(context, property);
741
- const cleanPropertyName = propertyName.replace(/^"|"$/g, "");
735
+ const propertyName = getModelPropertyName(context, property);
742
736
 
743
737
  // Use XML name if available, fall back to JSON name, then property name
744
738
  const serializedName = xmlOptions?.name ?? jsonOptions?.name ?? property.name;
745
739
 
746
740
  const metadataObj: string[] = [
747
- `propertyName: "${cleanPropertyName}"`,
741
+ `propertyName: ${JSON.stringify(propertyName)}`,
748
742
  `xmlOptions: { name: "${serializedName}"${buildXmlOptionsString(xmlOptions)} }`,
749
743
  ];
750
744
 
@@ -5,7 +5,7 @@ import type {
5
5
  SdkType,
6
6
  } from "@azure-tools/typespec-client-generator-core";
7
7
  import type { SdkContext } from "../../utils/interfaces.js";
8
- import { NameType, normalizeName } from "../../utils/name-utils.js";
8
+ import { normalizeSdkPropertyName } from "../../utils/name-utils.js";
9
9
  import { getCredentialExpression } from "./get-credential-expression.js";
10
10
  import { getEnumExpression } from "./get-enum-expression.js";
11
11
  import { getModelExpression } from "./get-model-expression.js";
@@ -21,10 +21,16 @@ export function normalizeModelPropertyName(
21
21
  context: SdkContext,
22
22
  property: SdkModelPropertyType | SdkHttpParameter | SdkServiceResponseHeader,
23
23
  ): string {
24
- const normalizedPropName = normalizeName(property.name, NameType.Property);
24
+ return JSON.stringify(getModelPropertyName(context, property));
25
+ }
26
+
27
+ export function getModelPropertyName(
28
+ context: SdkContext,
29
+ property: SdkModelPropertyType | SdkHttpParameter | SdkServiceResponseHeader,
30
+ ): string {
25
31
  return context.emitterOptions?.ignorePropertyNameNormalize
26
- ? `"${property.name}"`
27
- : `"${normalizedPropName}"`;
32
+ ? property.name
33
+ : normalizeSdkPropertyName(property);
28
34
  }
29
35
 
30
36
  export function getTypeExpression(
@@ -57,6 +57,8 @@ function extractClientOptions(
57
57
  const ignoreNullableOnOptional = getIgnoreNullableOnOptional(emitterOptions);
58
58
  const wrapNonModelReturn = getWrapNonModelReturn(emitterOptions);
59
59
  const isMultiService = (dpgContext.allServiceNamespaces?.length ?? 0) > 1;
60
+ const experimentalSplitModelsByVisibility =
61
+ emitterOptions["experimental-split-models-by-visibility"] === true;
60
62
 
61
63
  return {
62
64
  ...credentialInfo,
@@ -85,6 +87,7 @@ function extractClientOptions(
85
87
  enableStorageCompat,
86
88
  treatUnknownAsRecord,
87
89
  generateReactNativeTarget,
90
+ experimentalSplitModelsByVisibility,
88
91
  };
89
92
  }
90
93
 
@@ -12,11 +12,12 @@ import {
12
12
  isTemplateDeclaration,
13
13
  isTemplateDeclarationOrInstance,
14
14
  type Namespace,
15
+ NoTarget,
15
16
  type Operation,
16
17
  } from "@typespec/compiler";
17
18
  import type { ClientModuleInfo } from "../modular/interfaces.js";
18
19
  import type { SdkContext } from "./interfaces.js";
19
- import { NameType, normalizeName } from "./name-utils.js";
20
+ import { NameType, normalizeSdkName, reportInvalidExactName } from "./name-utils.js";
20
21
 
21
22
  export function getClients(dpgContext: SdkContext): SdkClient[] {
22
23
  const clients = listClients(dpgContext);
@@ -116,8 +117,9 @@ export function isMultiEndpointClient(dpgContext: SdkContext): boolean {
116
117
 
117
118
  export function getClientModuleInfo(clientMap: [string[], SdkClientType<SdkServiceOperation>]) {
118
119
  const [hierarchy, client] = clientMap;
120
+ const clientName = client.name.replace(/Client$/, "");
119
121
  const clientModuleInfo: ClientModuleInfo = {
120
- clientName: `${client.name.replace(/Client$/, "")}Context`,
122
+ clientName: `${clientName}Context`,
121
123
  };
122
124
  clientModuleInfo.subfolder = hierarchy.join("/");
123
125
  return clientModuleInfo;
@@ -133,13 +135,33 @@ export function getClientHierarchyMap(
133
135
  const clients = individualClients.map((client) => {
134
136
  return [
135
137
  context.sdkPackage.clients.length > 1
136
- ? [normalizeName(client.name.replace("Client", ""), NameType.File)]
138
+ ? [
139
+ normalizeSdkName(client, NameType.File, {
140
+ nameOverride: client.name.replace(/Client$/, ""),
141
+ }),
142
+ ]
137
143
  : [],
138
144
  client,
139
145
  ];
140
146
  }) as [string[], SdkClientType<SdkServiceOperation>][];
141
147
  for (let i = 0; i < clients.length; i++) {
142
148
  const [hierarchy, client] = clients[i]!;
149
+ reportInvalidExactName(
150
+ context.program,
151
+ client,
152
+ NameType.Class,
153
+ "client",
154
+ client.__raw.type ?? NoTarget,
155
+ );
156
+ for (const parameter of client.clientInitialization.parameters) {
157
+ reportInvalidExactName(
158
+ context.program,
159
+ parameter,
160
+ NameType.Parameter,
161
+ "parameter",
162
+ parameter.__raw ?? NoTarget,
163
+ );
164
+ }
143
165
  clientMap.push([hierarchy, client]);
144
166
  const childClientsToGenerate = client.children?.filter((child) => {
145
167
  return (
@@ -151,7 +173,9 @@ export function getClientHierarchyMap(
151
173
  childClientsToGenerate.forEach((child) => {
152
174
  const childHierarchy = [
153
175
  ...hierarchy,
154
- normalizeName(child.name.replace("Client", ""), NameType.File),
176
+ normalizeSdkName(child, NameType.File, {
177
+ nameOverride: child.name.replace(/Client$/, ""),
178
+ }),
155
179
  ];
156
180
  clients.push([childHierarchy, child]);
157
181
  });
@@ -48,8 +48,7 @@ export function generateCrossLanguageDefinitionFile(dpgContext: SdkContext): {
48
48
  }
49
49
  } else {
50
50
  // e,g., @azure/ai-client!ConnectionsOperations#getConnectionWithSecrets:member": "Azure.AI.Projects.Connections.getConnectionWithSecrets"
51
- const rawGroupName = normalizeName(prefixes[0] ?? "", NameType.Interface);
52
- const propertyType = `${normalizeName(rawGroupName, NameType.OperationGroup)}Operations`;
51
+ const propertyType = `${normalizeName(prefixes[0] ?? "", NameType.OperationGroup)}Operations`;
53
52
  for (const operation of operations) {
54
53
  const { name } = operation;
55
54
  const operationName = `${packageName}!${propertyType}#${name}:member`;
@@ -8,6 +8,7 @@ export interface SdkContext extends TCGCSdkContext {
8
8
  generationPathDetail?: GenerationDirDetail;
9
9
  hasApiVersionInClient?: boolean;
10
10
  allServiceNamespaces?: Namespace[];
11
+ commonServiceNamespace?: string[];
11
12
  }
12
13
 
13
14
  export interface GenerationDirDetail {
@@ -1,6 +1,9 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT License.
3
3
 
4
+ import { NoTarget, type DiagnosticTarget, type Program } from "@typespec/compiler";
5
+ import { reportDiagnostic } from "../lib.js";
6
+
4
7
  export interface NormalizeNameOption {
5
8
  shouldGuard?: boolean;
6
9
  customReservedNames?: ReservedName[];
@@ -8,6 +11,15 @@ export interface NormalizeNameOption {
8
11
  numberPrefixOverride?: string;
9
12
  }
10
13
 
14
+ export interface NormalizeSdkNameOption extends NormalizeNameOption {
15
+ nameOverride?: string;
16
+ }
17
+
18
+ export interface SdkName {
19
+ name: string;
20
+ isExactName?: boolean;
21
+ }
22
+
11
23
  export interface ReservedName {
12
24
  name: string;
13
25
  reservedFor: NameType[];
@@ -208,6 +220,88 @@ export function normalizeName(
208
220
  return fixLeadingNumber(result, nameType, numberPrefixOverride);
209
221
  }
210
222
 
223
+ export function normalizeSdkName(
224
+ sdkName: SdkName,
225
+ nameType: NameType,
226
+ options: NormalizeSdkNameOption = {},
227
+ ): string {
228
+ const { nameOverride, ...normalizeOptions } = options;
229
+ const name = nameOverride ?? sdkName.name;
230
+ if (!sdkName.isExactName) {
231
+ return normalizeName(name, nameType, normalizeOptions);
232
+ }
233
+ return normalizeOptions.shouldGuard && nameType === NameType.Method
234
+ ? guardReservedNames(name, nameType, normalizeOptions.customReservedNames)
235
+ : name;
236
+ }
237
+
238
+ export function normalizeSdkPropertyName(sdkName: SdkName): string {
239
+ return normalizeSdkName(sdkName, NameType.Property);
240
+ }
241
+
242
+ export function isValidTypeScriptIdentifierName(name: string): boolean {
243
+ return /^[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*$/u.test(name);
244
+ }
245
+
246
+ const reportedInvalidExactNames = new WeakMap<Program, WeakSet<object>>();
247
+
248
+ export function reportInvalidExactName(
249
+ program: Program,
250
+ item: SdkName & object,
251
+ nameType: NameType,
252
+ nameKind: string,
253
+ target: DiagnosticTarget | typeof NoTarget = NoTarget,
254
+ ): void {
255
+ if (
256
+ !item.isExactName ||
257
+ nameType === NameType.Property ||
258
+ nameType === NameType.EnumMemberName ||
259
+ nameType === NameType.File
260
+ ) {
261
+ return;
262
+ }
263
+
264
+ const requiresMethodGuard = guardReservedNames(item.name, NameType.Method) !== item.name;
265
+ const isValid =
266
+ isValidTypeScriptIdentifierName(item.name) &&
267
+ (nameType === NameType.Method || !requiresMethodGuard);
268
+ if (isValid) {
269
+ return;
270
+ }
271
+
272
+ let reported = reportedInvalidExactNames.get(program);
273
+ if (!reported) {
274
+ reported = new WeakSet<object>();
275
+ reportedInvalidExactNames.set(program, reported);
276
+ }
277
+ if (reported.has(item)) {
278
+ return;
279
+ }
280
+ reported.add(item);
281
+
282
+ reportDiagnostic(program, {
283
+ code: "invalid-exact-name",
284
+ format: { nameKind, name: item.name },
285
+ target,
286
+ });
287
+ }
288
+
289
+ export function formatPropertyName(name: string): string {
290
+ return isValidTypeScriptIdentifierName(name) ? name : JSON.stringify(name);
291
+ }
292
+
293
+ export function formatPropertyAccess(base: string, name: string): string {
294
+ return isValidTypeScriptIdentifierName(name)
295
+ ? `${base}.${name}`
296
+ : `${base}[${JSON.stringify(name)}]`;
297
+ }
298
+
299
+ export function formatOptionalPropertyAccess(base: string, name: string): string {
300
+ return isValidTypeScriptIdentifierName(name)
301
+ ? `${base}?.${name}`
302
+ : `${base}?.[${JSON.stringify(name)}]`;
303
+ }
304
+
211
305
  export function fixLeadingNumber(name: string, nameType: NameType, prefix: string = "_"): string {
212
306
  const casingConvention = getCasingConvention(nameType);
213
307
  if (!name || !name.match(/^[-.]?\d/)) {
@@ -53,7 +53,7 @@ import {
53
53
  } from "./media-types.js";
54
54
  import { isByteOrByteUnion } from "./model-utils.js";
55
55
  import { getLroLogicalResponseName, getResponseTypeName } from "./name-constructors.js";
56
- import { NameType, normalizeName } from "./name-utils.js";
56
+ import { NameType, normalizeName, normalizeSdkName, reportInvalidExactName } from "./name-utils.js";
57
57
  import { getOperationNamespaceInterfaceName } from "./namespace-utils.js";
58
58
 
59
59
  // Sorts the responses by status code
@@ -645,9 +645,10 @@ export function getMethodHierarchiesMap(
645
645
  const operationOrGroup = method[1];
646
646
 
647
647
  if (operationOrGroup.kind === "client") {
648
- operationOrGroup.methods.forEach((m) =>
649
- methodQueue.push([[...prefixes, operationOrGroup.name], m]),
650
- );
648
+ const hierarchyName = operationOrGroup.isExactName
649
+ ? `$DO_NOT_NORMALIZE$${operationOrGroup.name}`
650
+ : operationOrGroup.name;
651
+ operationOrGroup.methods.forEach((m) => methodQueue.push([[...prefixes, hierarchyName], m]));
651
652
  const nonIndependentChildren = operationOrGroup.children?.filter((child) => {
652
653
  return (
653
654
  !(child.clientInitialization.initializedBy & InitializedByFlags.Individually) &&
@@ -656,10 +657,26 @@ export function getMethodHierarchiesMap(
656
657
  });
657
658
  if (nonIndependentChildren && nonIndependentChildren.length > 0) {
658
659
  nonIndependentChildren.forEach((child) =>
659
- methodQueue.push([[...prefixes, operationOrGroup.name], child]),
660
+ methodQueue.push([[...prefixes, hierarchyName], child]),
660
661
  );
661
662
  }
662
663
  } else {
664
+ reportInvalidExactName(
665
+ context.program,
666
+ operationOrGroup,
667
+ NameType.Method,
668
+ "operation",
669
+ operationOrGroup.__raw ?? NoTarget,
670
+ );
671
+ for (const parameter of operationOrGroup.parameters) {
672
+ reportInvalidExactName(
673
+ context.program,
674
+ parameter,
675
+ NameType.Parameter,
676
+ "parameter",
677
+ parameter.__raw ?? NoTarget,
678
+ );
679
+ }
663
680
  const prefixKey =
664
681
  context.emitterOptions?.hierarchyClient || context.emitterOptions?.enableOperationGroup
665
682
  ? prefixes.join("/")
@@ -736,18 +753,14 @@ function resolveParameterNameConflict(
736
753
  // subsequent calls (e.g. emitNonModelResponseTypes then buildApiOptions both call
737
754
  // getMethodHierarchiesMap on the same TCGC object) always normalize from the
738
755
  // original, not from the already-mutated value.
739
- const paramName = normalizeName(
740
- p.name,
741
- NameType.Parameter,
742
- true,
743
- undefined,
744
- undefined,
745
- p.oriName,
746
- );
756
+ const paramName = normalizeSdkName(p, NameType.Parameter, {
757
+ shouldGuard: true,
758
+ nameOverride: p.oriName ?? p.name,
759
+ });
747
760
  if (!p.oriName) {
748
761
  p.oriName = p.name;
749
762
  }
750
- if (paramName === operationOrGroup.name) {
763
+ if (!p.isExactName && paramName === operationOrGroup.name) {
751
764
  p.name = `${paramName}Parameter`;
752
765
  } else {
753
766
  p.name = paramName;
@@ -55,14 +55,15 @@ type StorageCompatResult<TBody, THeaders> = TBody extends undefined | void | nul
55
55
  * @param rawResponse - The raw FullOperationResponse from the HTTP pipeline.
56
56
  * @param parsedBody - The deserialized response body.
57
57
  * @param parsedHeaders - The deserialized response headers.
58
- * @returns The parsedBody augmented with a `_response` property.
58
+ * @returns A flattened copy of the body and headers augmented with a `_response` property.
59
59
  */
60
60
  export function addStorageCompatResponse<TBody, THeaders = Record<string, unknown>>(
61
61
  rawResponse: FullOperationResponse,
62
62
  parsedBody: TBody,
63
63
  parsedHeaders: THeaders,
64
64
  ): StorageCompatResult<TBody, THeaders> {
65
- const base = parsedBody !== undefined && parsedBody !== null ? parsedBody : ({} as TBody);
65
+ const base =
66
+ parsedBody !== undefined && parsedBody !== null ? Object.assign({}, parsedBody) : ({} as TBody);
66
67
  return Object.assign(base as any, parsedHeaders, {
67
68
  _response: {
68
69
  rawResponse,
@@ -69,7 +69,8 @@ function getExpandedValue(option: ValueOptions): string {
69
69
  // prepare the following parts: separator, varName, value
70
70
  vals.push(`${getFirstOrSep(op, isFirst)}`);
71
71
  if (named && varName) {
72
- vals.push(`${encodeURIComponent(varName)}`);
72
+ // No need to encode varName considering it is already encoded
73
+ vals.push(`${varName}`);
73
74
  if (val === "") {
74
75
  vals.push(ifEmpty);
75
76
  } else {
@@ -108,7 +109,8 @@ function getNonExpandedValue(option: ValueOptions): string | undefined {
108
109
  const first = getFirstOrSep(op, isFirst);
109
110
  const [named, ifEmpty] = getNamedAndIfEmpty(op);
110
111
  if (named && varName) {
111
- vals.push(encodeComponent(varName, reserved, op));
112
+ // No need to encode varName considering it is already encoded
113
+ vals.push(varName);
112
114
  if (value === "") {
113
115
  if (!ifEmpty) {
114
116
  vals.push(ifEmpty);