@azure-tools/typespec-ts 0.57.0-dev.4 → 0.57.0-dev.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.57.0-dev.4",
3
+ "version": "0.57.0-dev.5",
4
4
  "description": "A TypeSpec emitter for TypeScript",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -40,25 +40,25 @@
40
40
  "@types/pluralize": "^0.0.33",
41
41
  "yaml": "^2.8.3",
42
42
  "@azure-tools/spector-runner": "^0.1.0",
43
- "@typespec/http-specs": "^0.1.0-alpha.41",
43
+ "@typespec/spec-api": "^0.1.0-alpha.16",
44
44
  "@typespec/spector": "^0.1.0-alpha.28",
45
+ "@typespec/http-specs": "^0.1.0-alpha.41",
45
46
  "@typespec/tspd": "^0.77.0",
46
47
  "@typespec/compiler": "^1.15.0",
47
- "@typespec/spec-api": "^0.1.0-alpha.16",
48
48
  "@typespec/http": "^1.15.0",
49
49
  "@typespec/openapi": "^1.15.0",
50
- "@typespec/rest": "^0.85.0",
50
+ "@typespec/versioning": "^0.85.0",
51
51
  "@typespec/xml": "^0.85.0",
52
- "@typespec/versioning": "^0.85.0"
52
+ "@typespec/rest": "^0.85.0"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@azure-tools/typespec-azure-core": "^0.71.0 || >= 0.72.0-dev.0",
56
56
  "@azure-tools/typespec-client-generator-core": "^0.71.2 || >= 0.72.0-dev.4",
57
57
  "@typespec/compiler": "^1.15.0",
58
- "@typespec/http": "^1.15.0",
59
- "@typespec/rest": "^0.85.0",
60
58
  "@typespec/versioning": "^0.85.0",
61
- "@typespec/xml": "^0.85.0"
59
+ "@typespec/rest": "^0.85.0",
60
+ "@typespec/xml": "^0.85.0",
61
+ "@typespec/http": "^1.15.0"
62
62
  },
63
63
  "dependencies": {
64
64
  "fast-xml-parser": "^5.10.1",
@@ -19,7 +19,7 @@ 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
24
  import { NameType, normalizeName } from "../utils/name-utils.js";
25
25
  import { getMethodHierarchiesMap, isTenantLevelOperation } from "../utils/operation-util.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",
@@ -190,11 +182,10 @@ function importAllApis(clientFile: SourceFile, srcPath: string, subfolder: strin
190
182
 
191
183
  function generateMethod(
192
184
  context: SdkContext,
193
- clientType: string,
194
185
  method: [string[], SdkServiceMethod<SdkServiceOperation>],
195
186
  ): MethodDeclarationStructure[] {
196
187
  const res: MethodDeclarationStructure[] = [];
197
- const declaration = getOperationFunction(context, method, clientType);
188
+ const declaration = getOperationFunction(context, method, "Client");
198
189
  const methodName = declaration.propertyName ?? declaration.name ?? "FIXME";
199
190
  const methodParams = declaration.parameters?.filter((p) => p.name !== "context") ?? [];
200
191
  const declarationRefKey = resolveReference(refkey(method[1], "api"));
@@ -268,19 +259,14 @@ function buildClientOperationGroups(
268
259
  dpgContext: SdkContext,
269
260
  clientClass: ClassDeclaration,
270
261
  ) {
271
- let clientType = "Client";
272
262
  const [_hierarchy, client] = clientMap;
273
- const { subfolder } = getClientModuleInfo(clientMap);
274
- if (subfolder && subfolder !== "") {
275
- clientType = `Client.${clientClass.getName()}`;
276
- }
277
263
  const methodMap = getMethodHierarchiesMap(dpgContext, client);
278
264
  for (const [prefixKey, operations] of methodMap) {
279
265
  const prefixes = prefixKey.split("/");
280
266
  const layer = 0;
281
267
  if (prefixKey === "") {
282
268
  operations.forEach((op) => {
283
- const methods = generateMethod(dpgContext, clientType, [prefixes, op]);
269
+ const methods = generateMethod(dpgContext, [prefixes, op]);
284
270
  clientClass.addMethods(methods);
285
271
  });
286
272
  } else {
@@ -296,7 +282,7 @@ function buildClientOperationGroups(
296
282
  if (!existProperty || existProperty.length === 0) {
297
283
  clientClass.addProperty({
298
284
  name: groupName,
299
- type: resolveReference(refkey(propertyType, layer, "classicOperations")),
285
+ type: resolveReference(refkey(client, propertyType, layer, "classicOperations")),
300
286
  scope: Scope.Public,
301
287
  isReadonly: true,
302
288
  docs: ["The operation groups for " + groupName],
@@ -304,7 +290,7 @@ function buildClientOperationGroups(
304
290
  clientClass
305
291
  .getConstructors()[0]
306
292
  ?.addStatements(
307
- `this.${groupName} = ${resolveReference(refkey(operationName, layer, "getClassicOperations"))}(this._client)`,
293
+ `this.${groupName} = ${resolveReference(refkey(client, operationName, layer, "getClassicOperations"))}(this._client)`,
308
294
  );
309
295
  }
310
296
  }
@@ -22,7 +22,7 @@ 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
27
  import { NameType, normalizeName } from "../utils/name-utils.js";
28
28
  import {
@@ -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("/");
@@ -314,6 +314,35 @@ export function getModelsPath(sourceRoot: string, modelNamespace: string[] = [])
314
314
  );
315
315
  }
316
316
 
317
+ /** Finds the namespace prefix shared by every service in the package. */
318
+ function getCommonServiceNamespace(context: SdkContext): string[] {
319
+ if (context.commonServiceNamespace) {
320
+ return context.commonServiceNamespace;
321
+ }
322
+
323
+ const serviceNamespaces = context.allServiceNamespaces ?? listAllServiceNamespaces(context);
324
+ if (serviceNamespaces.length === 0) {
325
+ context.commonServiceNamespace = [];
326
+ return context.commonServiceNamespace;
327
+ }
328
+
329
+ // Start with the first namespace and shorten it at the first segment that
330
+ // differs in each subsequent service namespace.
331
+ const commonNamespace = getNamespaceFullName(serviceNamespaces[0]!).split(".");
332
+ for (const serviceNamespace of serviceNamespaces.slice(1)) {
333
+ const segments = getNamespaceFullName(serviceNamespace).split(".");
334
+ const commonLength = commonNamespace.findIndex((segment, index) => segment !== segments[index]);
335
+ if (commonLength !== -1) {
336
+ commonNamespace.length = commonLength;
337
+ }
338
+ if (commonNamespace.length === 0) {
339
+ break;
340
+ }
341
+ }
342
+ context.commonServiceNamespace = commonNamespace;
343
+ return context.commonServiceNamespace;
344
+ }
345
+
317
346
  export function getModelNamespaces(context: SdkContext, model: SdkType): string[] {
318
347
  if (model.kind === "model" || model.kind === "enum" || model.kind === "union") {
319
348
  if (
@@ -325,22 +354,11 @@ export function getModelNamespaces(context: SdkContext, model: SdkType): string[
325
354
  return [];
326
355
  }
327
356
  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 [];
357
+ const commonNamespace = getCommonServiceNamespace(context);
358
+ const modelUsesCommonNamespace = commonNamespace.every(
359
+ (segment, index) => segment === segments[index],
360
+ );
361
+ return modelUsesCommonNamespace ? segments.slice(commonNamespace.length) : segments;
344
362
  } else if (model.kind === "array" || model.kind === "dict") {
345
363
  return getModelNamespaces(context, model.valueType);
346
364
  } else if (model.kind === "nullable") {
@@ -58,6 +58,7 @@ export function getClassicalOperation(
58
58
  ) {
59
59
  const prefixes = operationGroup[0];
60
60
  const operations = operationGroup[1];
61
+ const client = clientMap[1];
61
62
  const { clientName } = getClientModuleInfo(clientMap);
62
63
  const hasClientContextImport = classicFile.getImportDeclarations().filter((i) => {
63
64
  return (
@@ -119,7 +120,9 @@ export function getClassicalOperation(
119
120
  properties.push({
120
121
  kind: StructureKind.PropertySignature,
121
122
  name,
122
- type: resolveReference(refkey(nextLayerInterfaceName, layer + 1, "classicOperations")),
123
+ type: resolveReference(
124
+ refkey(client, nextLayerInterfaceName, layer + 1, "classicOperations"),
125
+ ),
123
126
  });
124
127
  }
125
128
  } else {
@@ -197,7 +200,7 @@ export function getClassicalOperation(
197
200
  addDeclaration(
198
201
  classicFile,
199
202
  interfaceDeclaration,
200
- refkey(interfaceName, layer, "classicOperations"),
203
+ refkey(client, interfaceName, layer, "classicOperations"),
201
204
  );
202
205
  }
203
206
 
@@ -286,7 +289,7 @@ export function getClassicalOperation(
286
289
  addDeclaration(
287
290
  classicFile,
288
291
  functionDeclaration,
289
- refkey(functionName, layer, "getClassicOperation"),
292
+ refkey(client, functionName, layer, "getClassicOperation"),
290
293
  );
291
294
  }
292
295
 
@@ -319,11 +322,11 @@ export function getClassicalOperation(
319
322
  ${normalizeName(
320
323
  prefixes[layer + 1] ?? "FIXME",
321
324
  NameType.Property,
322
- )}: ${resolveReference(refkey(nextLayerOperationFunctionName, layer + 1, "getClassicOperations"))}(context)}`;
325
+ )}: ${resolveReference(refkey(client, nextLayerOperationFunctionName, layer + 1, "getClassicOperations"))}(context)}`;
323
326
  }
324
327
  } else {
325
328
  statement = `,
326
- ...${resolveReference(refkey(nextLayerOperationFunctionName, layer + 1, "getClassicOperations"))}(context)}`;
329
+ ...${resolveReference(refkey(client, nextLayerOperationFunctionName, layer + 1, "getClassicOperations"))}(context)}`;
327
330
  }
328
331
 
329
332
  if (statement) {
@@ -342,23 +345,23 @@ export function getClassicalOperation(
342
345
  type: clientName,
343
346
  },
344
347
  ],
345
- returnType: resolveReference(refkey(interfaceName, layer, "classicOperations")),
348
+ returnType: resolveReference(refkey(client, interfaceName, layer, "classicOperations")),
346
349
  statements:
347
350
  layer !== prefixes.length - 1
348
351
  ? `return {
349
352
  ${normalizeName(
350
353
  prefixes[layer + 1] ?? "FIXME",
351
354
  NameType.Property,
352
- )}: ${resolveReference(refkey(nextLayerOperationFunctionName, layer + 1, "getClassicOperations"))}(context)
355
+ )}: ${resolveReference(refkey(client, nextLayerOperationFunctionName, layer + 1, "getClassicOperations"))}(context)
353
356
  }`
354
357
  : `return {
355
- ...${resolveReference(refkey(functionName, layer, "getClassicOperation"))}(context)
358
+ ...${resolveReference(refkey(client, functionName, layer, "getClassicOperation"))}(context)
356
359
  }`,
357
360
  };
358
361
  addDeclaration(
359
362
  classicFile,
360
363
  functions,
361
- refkey(operationFunctionName, layer, "getClassicOperations"),
364
+ refkey(client, operationFunctionName, layer, "getClassicOperations"),
362
365
  );
363
366
  }
364
367
 
@@ -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 {