@azure-tools/typespec-ts 0.56.1-dev.0 → 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 +31 -31
  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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.56.1-dev.0",
3
+ "version": "0.57.0-dev.10",
4
4
  "description": "A TypeSpec emitter for TypeScript",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -17,55 +17,55 @@
17
17
  "author": "Jose Heredia <joheredi@microsoft.com>",
18
18
  "license": "MIT",
19
19
  "devDependencies": {
20
- "@azure-rest/core-client": "^2.7.0",
21
- "@azure-tools/azure-http-specs": "^0.1.0-alpha.44 || >= 0.1.0-alpha.45-dev.1",
22
- "@azure-tools/typespec-autorest": "^0.71.0 || >= 0.72.0-dev.0",
23
- "@azure-tools/typespec-azure-core": "^0.71.0 || >= 0.72.0-dev.0",
24
- "@azure-tools/typespec-azure-resource-manager": "^0.71.0 || >= 0.72.0-dev.0",
25
- "@azure-tools/typespec-client-generator-core": "^0.71.0 || >= 0.72.0-dev.0",
26
- "@azure/abort-controller": "^2.1.2",
27
- "@azure/core-auth": "^1.6.0",
28
- "@azure/core-lro": "^3.1.0",
29
- "@azure/core-paging": "^1.5.0",
30
- "@azure/core-rest-pipeline": "^1.24.0",
31
- "@azure/core-util": "^1.4.0",
32
- "@azure/logger": "^1.0.4",
33
- "@typespec/ts-http-runtime": "0.3.7",
20
+ "@azure-rest/core-client": "^2.8.0",
21
+ "@azure-tools/azure-http-specs": "^0.1.0-alpha.44 || >= 0.1.0-alpha.45-dev.4",
22
+ "@azure-tools/typespec-autorest": "^0.71.0 || >= 0.72.0-dev.3",
23
+ "@azure-tools/typespec-azure-core": "^0.71.0 || >= 0.72.0-dev.2",
24
+ "@azure-tools/typespec-azure-resource-manager": "^0.71.0 || >= 0.72.0-dev.9",
25
+ "@azure-tools/typespec-client-generator-core": "^0.71.2 || >= 0.72.0-dev.7",
26
+ "@azure/abort-controller": "^2.2.0",
27
+ "@azure/core-auth": "^1.11.0",
28
+ "@azure/core-lro": "^3.4.0",
29
+ "@azure/core-paging": "^1.7.0",
30
+ "@azure/core-rest-pipeline": "^1.25.0",
31
+ "@azure/core-util": "^1.14.0",
32
+ "@azure/logger": "^1.4.0",
33
+ "@typespec/ts-http-runtime": "0.3.8",
34
34
  "cross-env": "^10.1.0",
35
- "concurrently": "^10.0.4",
36
- "vitest": "^4.1.3",
37
- "vite": "^8.1.2",
38
- "@vitest/coverage-v8": "^4.1.3",
39
- "@microsoft/api-extractor": "^7.58.1",
35
+ "concurrently": "^10.0.5",
36
+ "vitest": "^4.1.11",
37
+ "vite": "^8.2.2",
38
+ "@vitest/coverage-v8": "^4.1.11",
39
+ "@microsoft/api-extractor": "~7.58.1",
40
40
  "@types/pluralize": "^0.0.33",
41
- "yaml": "^2.8.3",
41
+ "yaml": "^2.9.0",
42
42
  "@azure-tools/spector-runner": "^0.1.0",
43
43
  "@typespec/http-specs": "^0.1.0-alpha.41",
44
44
  "@typespec/spec-api": "^0.1.0-alpha.16",
45
45
  "@typespec/spector": "^0.1.0-alpha.28",
46
- "@typespec/tspd": "^0.77.0",
47
46
  "@typespec/compiler": "^1.15.0",
47
+ "@typespec/tspd": "^0.77.0",
48
48
  "@typespec/http": "^1.15.0",
49
- "@typespec/openapi": "^1.15.0",
50
49
  "@typespec/rest": "^0.85.0",
50
+ "@typespec/openapi": "^1.15.0",
51
51
  "@typespec/versioning": "^0.85.0",
52
52
  "@typespec/xml": "^0.85.0"
53
53
  },
54
54
  "peerDependencies": {
55
- "@azure-tools/typespec-azure-core": "^0.71.0 || >= 0.72.0-dev.0",
56
- "@azure-tools/typespec-client-generator-core": "^0.71.0 || >= 0.72.0-dev.0",
55
+ "@azure-tools/typespec-azure-core": "^0.71.0 || >= 0.72.0-dev.2",
56
+ "@azure-tools/typespec-client-generator-core": "^0.71.2 || >= 0.72.0-dev.7",
57
57
  "@typespec/compiler": "^1.15.0",
58
58
  "@typespec/rest": "^0.85.0",
59
- "@typespec/http": "^1.15.0",
59
+ "@typespec/xml": "^0.85.0",
60
60
  "@typespec/versioning": "^0.85.0",
61
- "@typespec/xml": "^0.85.0"
61
+ "@typespec/http": "^1.15.0"
62
62
  },
63
63
  "dependencies": {
64
- "fast-xml-parser": "^5.10.1",
64
+ "fast-xml-parser": "^5.11.0",
65
65
  "pluralize": "^8.0.0",
66
- "prettier": "^3.9.5",
67
- "ts-morph": "^23.0.0",
68
- "tslib": "^2.3.1"
66
+ "prettier": "^3.9.6",
67
+ "ts-morph": "^28.0.0",
68
+ "tslib": "^2.8.1"
69
69
  },
70
70
  "files": [
71
71
  "src",
@@ -13,6 +13,7 @@ import { provideContext, useContext } from "../../context-manager.js";
13
13
  import { reportDiagnostic } from "../../lib.js";
14
14
  import { visitPackageTypes } from "../../modular/emit-models.js";
15
15
  import { getAllAncestors, getAllProperties } from "../../modular/helpers/operation-helpers.js";
16
+ import { applyVisibilityModelSplit } from "../../modular/helpers/visibility-helpers.js";
16
17
  import { normalizeModelPropertyName } from "../../modular/type-expressions/get-type-expression.js";
17
18
  import type { SdkContext } from "../../utils/interfaces.js";
18
19
  import { NameType, normalizeName } from "../../utils/name-utils.js";
@@ -92,6 +93,7 @@ export function provideSdkTypes(context: SdkContext) {
92
93
  types: new Map<Type, SdkType>(),
93
94
  flattenProperties: new Map<SdkModelPropertyType, SdkFlattenPropertyContext>(),
94
95
  };
96
+ applyVisibilityModelSplit(context);
95
97
  visitPackageTypes(context);
96
98
  enrichFlattenProperties(context, sdkTypesContext.flattenProperties, flattenPropertyModelMap);
97
99
  for (const sdkModel of emitQueue) {
package/src/interfaces.ts CHANGED
@@ -260,6 +260,10 @@ export interface ClientOptions {
260
260
  * Defaults to false.
261
261
  */
262
262
  generateReactNativeTarget?: boolean;
263
+ /**
264
+ * Generates visibility-specific request models. Experimental and disabled by default.
265
+ */
266
+ experimentalSplitModelsByVisibility?: boolean;
263
267
  }
264
268
 
265
269
  export interface ServiceInfo {
package/src/lib.ts CHANGED
@@ -91,6 +91,7 @@ export interface EmitterOptions {
91
91
  * package.json exports). Defaults to `false`.
92
92
  */
93
93
  "generate-react-native-target"?: boolean;
94
+ "experimental-split-models-by-visibility"?: boolean;
94
95
  }
95
96
 
96
97
  export const EmitterOptionsSchema: JSONSchemaType<EmitterOptions> = {
@@ -312,6 +313,12 @@ export const EmitterOptionsSchema: JSONSchemaType<EmitterOptions> = {
312
313
  description:
313
314
  "When set to true, generates React Native build targets (tsconfig, warp target, package.json exports). Defaults to `false`.",
314
315
  },
316
+ "experimental-split-models-by-visibility": {
317
+ type: "boolean",
318
+ nullable: true,
319
+ description:
320
+ "Whether to project request-body models to their write visibility (e.g. WidgetCreate/WidgetCreateOrUpdate) so read-only properties do not leak into input types. Defaults to false",
321
+ },
315
322
  },
316
323
  required: [],
317
324
  };
@@ -476,6 +483,12 @@ const libDef = {
476
483
  default: paramMessage`Property name ${"propertyName"} is normalized to ${"normalizedName"}.`,
477
484
  },
478
485
  },
486
+ "invalid-exact-name": {
487
+ severity: "warning",
488
+ messages: {
489
+ default: paramMessage`Exact ${"nameKind"} name ${"name"} is not a valid TypeScript identifier. Choose a valid TypeScript identifier or remove exact().`,
490
+ },
491
+ },
479
492
  "un-supported-format-cases": {
480
493
  severity: "warning",
481
494
  messages: {
@@ -61,6 +61,7 @@ export function buildPackageFile(
61
61
  * - Adds LRO dependencies (`@azure/core-lro`, `@azure/abort-controller`) when the package has
62
62
  * polling operations (for non-monorepo Azure packages).
63
63
  * - Updates exports (tshy or warp) when `exports` is provided.
64
+ * - Adds the default `customize` script when the package does not define one.
64
65
  */
65
66
  export function updatePackageFile(
66
67
  model: ClientModel,
@@ -86,6 +87,9 @@ export function updatePackageFile(
86
87
  packageInfo = existingFilePathOrContent;
87
88
  }
88
89
 
90
+ packageInfo.scripts ??= {};
91
+ packageInfo.scripts.customize ??= "echo skipped";
92
+
89
93
  // Migrate AutoRest-specific dependency names and versions to their TypeSpec equivalents.
90
94
  const deps: Record<string, string> = { ...(packageInfo.dependencies ?? {}) };
91
95
  let needsCoreClientUpdate = false;
@@ -136,6 +136,7 @@ function getAzureMonorepoScripts(config: AzureMonorepoInfoConfig) {
136
136
  config.withSamples ? '"samples-dev/*.ts"' : ""
137
137
  }`,
138
138
  clean: "rimraf --glob dist dist-browser dist-esm test-dist temp types *.tgz *.log",
139
+ customize: "echo skipped",
139
140
  "execute:samples": config.withSamples ? "dev-tool samples run samples-dev" : "echo skipped",
140
141
  "extract-api": "rimraf review && dev-tool run extract-api",
141
142
  format: `prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore "src/**/*.{ts,cts,mts}" "test/**/*.{ts,cts,mts}" "*.{js,cjs,mjs,json}" ${
@@ -19,9 +19,9 @@ import { useContext } from "../context-manager.js";
19
19
  import { useDependencies } from "../framework/hooks/use-dependencies.js";
20
20
  import { resolveReference } from "../framework/reference.js";
21
21
  import { refkey } from "../framework/refkey.js";
22
- import { getClientModuleInfo, isMultiEndpointClient } from "../utils/client-utils.js";
22
+ import { getClientModuleInfo } from "../utils/client-utils.js";
23
23
  import type { SdkContext } from "../utils/interfaces.js";
24
- import { NameType, normalizeName } from "../utils/name-utils.js";
24
+ import { NameType, normalizeName, normalizeSdkName } from "../utils/name-utils.js";
25
25
  import { getMethodHierarchiesMap, isTenantLevelOperation } from "../utils/operation-util.js";
26
26
  import { AzurePollingDependencies } from "./external-dependencies.js";
27
27
  import { getPagingLROMethodName } from "./helpers/classical-operation-helpers.js";
@@ -68,19 +68,11 @@ export function buildClassicalClient(
68
68
  });
69
69
 
70
70
  // Add the private client member. This will be the client context from /api
71
- if (isMultiEndpointClient(dpgContext)) {
72
- clientClass.addProperty({
73
- name: "_client",
74
- type: `Client.${clientName}`,
75
- scope: Scope.Private,
76
- });
77
- } else {
78
- clientClass.addProperty({
79
- name: "_client",
80
- type: `${clientName}`,
81
- scope: Scope.Private,
82
- });
83
- }
71
+ clientClass.addProperty({
72
+ name: "_client",
73
+ type: `${clientName}`,
74
+ scope: Scope.Private,
75
+ });
84
76
  // Add the pipeline member. This will be the pipeline from /api
85
77
  clientClass.addProperty({
86
78
  name: "pipeline",
@@ -145,9 +137,14 @@ export function buildClassicalClient(
145
137
  `this._clientParams = {${classicalParams.map((p) => p.name).join(",")}};`,
146
138
  );
147
139
  for (const childClient of client.children) {
148
- const subfolder = normalizeName(childClient.name.replace("Client", ""), NameType.File);
140
+ const subfolder = normalizeSdkName(childClient, NameType.File, {
141
+ nameOverride: childClient.name.replace(/Client$/, ""),
142
+ });
149
143
  clientFile.addImportDeclaration({
150
- moduleSpecifier: `./${subfolder}/${normalizeName(childClient.name, NameType.File)}.js`,
144
+ moduleSpecifier: `./${subfolder}/${normalizeName(
145
+ getClassicalClientName(childClient),
146
+ NameType.File,
147
+ )}.js`,
151
148
  namedImports: [
152
149
  `${getClassicalClientName(childClient)}`,
153
150
  `${getClassicalClientName(childClient)}OptionalParams`,
@@ -190,11 +187,10 @@ function importAllApis(clientFile: SourceFile, srcPath: string, subfolder: strin
190
187
 
191
188
  function generateMethod(
192
189
  context: SdkContext,
193
- clientType: string,
194
190
  method: [string[], SdkServiceMethod<SdkServiceOperation>],
195
191
  ): MethodDeclarationStructure[] {
196
192
  const res: MethodDeclarationStructure[] = [];
197
- const declaration = getOperationFunction(context, method, clientType);
193
+ const declaration = getOperationFunction(context, method, "Client");
198
194
  const methodName = declaration.propertyName ?? declaration.name ?? "FIXME";
199
195
  const methodParams = declaration.parameters?.filter((p) => p.name !== "context") ?? [];
200
196
  const declarationRefKey = resolveReference(refkey(method[1], "api"));
@@ -268,19 +264,14 @@ function buildClientOperationGroups(
268
264
  dpgContext: SdkContext,
269
265
  clientClass: ClassDeclaration,
270
266
  ) {
271
- let clientType = "Client";
272
267
  const [_hierarchy, client] = clientMap;
273
- const { subfolder } = getClientModuleInfo(clientMap);
274
- if (subfolder && subfolder !== "") {
275
- clientType = `Client.${clientClass.getName()}`;
276
- }
277
268
  const methodMap = getMethodHierarchiesMap(dpgContext, client);
278
269
  for (const [prefixKey, operations] of methodMap) {
279
270
  const prefixes = prefixKey.split("/");
280
271
  const layer = 0;
281
272
  if (prefixKey === "") {
282
273
  operations.forEach((op) => {
283
- const methods = generateMethod(dpgContext, clientType, [prefixes, op]);
274
+ const methods = generateMethod(dpgContext, [prefixes, op]);
284
275
  clientClass.addMethods(methods);
285
276
  });
286
277
  } else {
@@ -289,14 +280,12 @@ function buildClientOperationGroups(
289
280
  const operationName = `_get${rawGroupName}Operations`;
290
281
  const propertyType = `${rawGroupName}Operations`;
291
282
  // The `groupName` is used to any places where we don't need normalized name again
292
- const groupName = normalizeName(rawGroupName, NameType.Property);
293
- const existProperty = clientClass.getProperties().filter((p) => {
294
- return p.getName() === normalizeName(groupName, NameType.Property);
295
- });
296
- if (!existProperty || existProperty.length === 0) {
283
+ const groupName = normalizeName(prefixes[0] ?? "", NameType.Property);
284
+ const existingProperty = clientClass.getProperty(groupName);
285
+ if (!existingProperty) {
297
286
  clientClass.addProperty({
298
287
  name: groupName,
299
- type: resolveReference(refkey(propertyType, layer, "classicOperations")),
288
+ type: resolveReference(refkey(client, propertyType, layer, "classicOperations")),
300
289
  scope: Scope.Public,
301
290
  isReadonly: true,
302
291
  docs: ["The operation groups for " + groupName],
@@ -304,7 +293,7 @@ function buildClientOperationGroups(
304
293
  clientClass
305
294
  .getConstructors()[0]
306
295
  ?.addStatements(
307
- `this.${groupName} = ${resolveReference(refkey(operationName, layer, "getClassicOperations"))}(this._client)`,
296
+ `this.${groupName} = ${resolveReference(refkey(client, operationName, layer, "getClassicOperations"))}(this._client)`,
308
297
  );
309
298
  }
310
299
  }
@@ -22,9 +22,9 @@ import { addDeclaration } from "../framework/declaration.js";
22
22
  import { useDependencies } from "../framework/hooks/use-dependencies.js";
23
23
  import { resolveReference } from "../framework/reference.js";
24
24
  import { refkey } from "../framework/refkey.js";
25
- import { getClientModuleInfo, isMultiEndpointClient } from "../utils/client-utils.js";
25
+ import { getClientModuleInfo } from "../utils/client-utils.js";
26
26
  import type { SdkContext } from "../utils/interfaces.js";
27
- import { NameType, normalizeName } from "../utils/name-utils.js";
27
+ import { NameType, normalizeName, normalizeSdkName } from "../utils/name-utils.js";
28
28
  import {
29
29
  getMethodHierarchiesMap,
30
30
  hasDualFormatSupport,
@@ -49,8 +49,7 @@ export function buildOperationFiles(
49
49
  const [_, client] = clientMap;
50
50
  const operationFiles: Set<SourceFile> = new Set();
51
51
  const { subfolder, clientName } = getClientModuleInfo(clientMap);
52
- const isMultiEndpoint = isMultiEndpointClient(dpgContext);
53
- const clientType = isMultiEndpoint ? `Client.${clientName}` : "Client";
52
+ const clientType = "Client";
54
53
  const methodMap = getMethodHierarchiesMap(dpgContext, client);
55
54
  for (const [prefixKey, operations] of methodMap) {
56
55
  const prefixes = prefixKey.split("/");
@@ -187,7 +186,7 @@ export function buildOperationOptions(
187
186
  docs: getDocsFromDescription(p.doc),
188
187
  hasQuestionToken: true,
189
188
  type: getTypeExpression(context, p.type, { isOptional: true }),
190
- name: normalizeName(p.name, NameType.Parameter),
189
+ name: normalizeSdkName(p, NameType.Parameter),
191
190
  };
192
191
  }),
193
192
  ),
@@ -278,7 +278,7 @@ function exportClassicalClient(
278
278
  subfolder: string,
279
279
  isSubClient: boolean = false,
280
280
  ) {
281
- const clientName = client.name;
281
+ const clientName = getClassicalClientName(client);
282
282
  enqueueStatement(indexFile, {
283
283
  kind: StructureKind.ExportDeclaration,
284
284
  namedExports: [clientName],
@@ -51,7 +51,14 @@ import { reportDiagnostic } from "../lib.js";
51
51
  import { getClientHierarchyMap } from "../utils/client-utils.js";
52
52
  import type { SdkContext } from "../utils/interfaces.js";
53
53
  import { isAzureCoreErrorType } from "../utils/model-utils.js";
54
- import { fixLeadingNumber, NameType, normalizeName } from "../utils/name-utils.js";
54
+ import {
55
+ fixLeadingNumber,
56
+ formatPropertyName,
57
+ NameType,
58
+ normalizeName,
59
+ normalizeSdkName,
60
+ reportInvalidExactName,
61
+ } from "../utils/name-utils.js";
55
62
  import { getMethodHierarchiesMap } from "../utils/operation-util.js";
56
63
  import { getHeaderClientOptions } from "./helpers/client-option-helpers.js";
57
64
  import {
@@ -314,6 +321,35 @@ export function getModelsPath(sourceRoot: string, modelNamespace: string[] = [])
314
321
  );
315
322
  }
316
323
 
324
+ /** Finds the namespace prefix shared by every service in the package. */
325
+ function getCommonServiceNamespace(context: SdkContext): string[] {
326
+ if (context.commonServiceNamespace) {
327
+ return context.commonServiceNamespace;
328
+ }
329
+
330
+ const serviceNamespaces = context.allServiceNamespaces ?? listAllServiceNamespaces(context);
331
+ if (serviceNamespaces.length === 0) {
332
+ context.commonServiceNamespace = [];
333
+ return context.commonServiceNamespace;
334
+ }
335
+
336
+ // Start with the first namespace and shorten it at the first segment that
337
+ // differs in each subsequent service namespace.
338
+ const commonNamespace = getNamespaceFullName(serviceNamespaces[0]!).split(".");
339
+ for (const serviceNamespace of serviceNamespaces.slice(1)) {
340
+ const segments = getNamespaceFullName(serviceNamespace).split(".");
341
+ const commonLength = commonNamespace.findIndex((segment, index) => segment !== segments[index]);
342
+ if (commonLength !== -1) {
343
+ commonNamespace.length = commonLength;
344
+ }
345
+ if (commonNamespace.length === 0) {
346
+ break;
347
+ }
348
+ }
349
+ context.commonServiceNamespace = commonNamespace;
350
+ return context.commonServiceNamespace;
351
+ }
352
+
317
353
  export function getModelNamespaces(context: SdkContext, model: SdkType): string[] {
318
354
  if (model.kind === "model" || model.kind === "enum" || model.kind === "union") {
319
355
  if (
@@ -325,22 +361,11 @@ export function getModelNamespaces(context: SdkContext, model: SdkType): string[
325
361
  return [];
326
362
  }
327
363
  const segments = model.namespace.split(".");
328
- // Keep full namespace segments if multiple services are present because there isn't a root namespace to trim
329
- if (context.emitterOptions?.isMultiService) {
330
- return segments;
331
- }
332
-
333
- const allServiceNamespaces = context.allServiceNamespaces ?? listAllServiceNamespaces(context);
334
- const deepestNamespace = getNamespaceFullName(allServiceNamespaces[0]!);
335
- const rootNamespace = deepestNamespace.split(".") ?? [];
336
- if (segments.length > rootNamespace.length) {
337
- while (segments[0] === rootNamespace[0]) {
338
- segments.shift();
339
- rootNamespace.shift();
340
- }
341
- return segments;
342
- }
343
- return [];
364
+ const commonNamespace = getCommonServiceNamespace(context);
365
+ const modelUsesCommonNamespace = commonNamespace.every(
366
+ (segment, index) => segment === segments[index],
367
+ );
368
+ return modelUsesCommonNamespace ? segments.slice(commonNamespace.length) : segments;
344
369
  } else if (model.kind === "array" || model.kind === "dict") {
345
370
  return getModelNamespaces(context, model.valueType);
346
371
  } else if (model.kind === "nullable") {
@@ -602,11 +627,15 @@ function emitEnumMember(
602
627
  member: SdkEnumValueType,
603
628
  reportMemberNameDiagnostic = false, // if reportMemberNameDiagnostic is true, it will report diagnostic for enum member name
604
629
  ): EnumMemberStructure {
605
- const shouldNormalizeName = !member.name.startsWith("$DO_NOT_NORMALIZE$");
606
- const enumTypeName = normalizeName(member.enumType.name, NameType.Interface, true);
607
- let normalizedMemberName = context.emitterOptions?.ignoreEnumMemberNameNormalize
608
- ? fixLeadingNumber(member.name, NameType.EnumMemberName) // need to fix the leading number also for enum member
609
- : normalizeName(member.name, NameType.EnumMemberName, true);
630
+ const shouldNormalizeName = !member.isExactName && !member.name.startsWith("$DO_NOT_NORMALIZE$");
631
+ const enumTypeName = normalizeSdkName(member.enumType, NameType.Interface, {
632
+ shouldGuard: true,
633
+ });
634
+ let normalizedMemberName = member.isExactName
635
+ ? formatPropertyName(member.name)
636
+ : context.emitterOptions?.ignoreEnumMemberNameNormalize
637
+ ? fixLeadingNumber(member.name, NameType.EnumMemberName) // need to fix the leading number also for enum member
638
+ : normalizeSdkName(member, NameType.EnumMemberName, { shouldGuard: true });
610
639
  // If the member name starts with _ due to a leading digit (not because the original has _),
611
640
  // replace the _ prefix with either "V" (for API version enums) or the enum type name.
612
641
  if (
@@ -828,6 +857,8 @@ export function normalizeModelName(
828
857
  return getTypeExpression(context, type);
829
858
  }
830
859
 
860
+ reportInvalidExactName(context.program, type, nameType, type.kind, type.__raw ?? NoTarget);
861
+
831
862
  const segments = getModelNamespaces(context, type);
832
863
  let unionSuffix = "";
833
864
  if (!skipPolymorphicUnionSuffix) {
@@ -835,12 +866,15 @@ export function normalizeModelName(
835
866
  unionSuffix = "Union";
836
867
  }
837
868
  }
838
- const namespacePrefix = context.emitterOptions?.enableModelNamespace ? segments.join("") : "";
869
+ const namespacePrefix = context.emitterOptions?.enableModelNamespace
870
+ ? normalizeName(segments.join(""), nameType)
871
+ : "";
839
872
  const internalModelPrefix =
840
873
  (isPagedResultModel(context, type) && !pagedModelsKeptPublic.has(type)) || type.isGeneratedName
841
874
  ? "_"
842
875
  : "";
843
- return `${internalModelPrefix}${normalizeName(namespacePrefix + type.name, nameType, true)}${unionSuffix}`;
876
+ const modelName = normalizeSdkName(type, nameType, { shouldGuard: true });
877
+ return `${internalModelPrefix}${namespacePrefix}${modelName}${unionSuffix}`;
844
878
  }
845
879
 
846
880
  function buildModelPolymorphicType(context: SdkContext, type: SdkModelType) {
@@ -880,6 +914,7 @@ function buildModelProperty(
880
914
  const normalizedPropName = normalizeModelPropertyName(context, property);
881
915
  if (
882
916
  !context.emitterOptions?.ignorePropertyNameNormalize &&
917
+ !property.isExactName &&
883
918
  normalizedPropName !== `"${property.name}"`
884
919
  ) {
885
920
  reportDiagnostic(context.program, {