@azure-tools/typespec-java 0.19.3 → 0.20.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.
@@ -1,11 +1,10 @@
1
1
  import { AnySchema, ApiVersion, ArraySchema, BinaryResponse, BinarySchema, BooleanSchema, ByteArraySchema, ChoiceValue, DateSchema, DateTimeSchema, DictionarySchema, Discriminator, GroupProperty, GroupSchema, HttpHeader, HttpParameter, ImplementationLocation, KeySecurityScheme, Language, Metadata, NumberSchema, OAuth2SecurityScheme, ObjectSchema, OperationGroup, Parameter, ParameterLocation, Property, Relations, Response, SchemaResponse, SchemaType, Security, SerializationStyle, StringSchema, TimeSchema, UnixTimeSchema, UriSchema, VirtualParameter, } from "@autorest/codemodel";
2
2
  import { KnownMediaType } from "@azure-tools/codegen";
3
- import { getLroMetadata, getPagedResult, isPollingLocation } from "@azure-tools/typespec-azure-core";
4
- import { createSdkContext, getAllModels, getClientNameOverride, getClientType, getCrossLanguageDefinitionId, getDefaultApiVersion, getHttpOperationWithCache, getWireName, isApiVersion, isSdkBuiltInKind, isSdkIntKind, listClients, listOperationGroups, listOperationsInOperationGroup, shouldGenerateConvenient, shouldGenerateProtocol, getHttpOperationExamples, } from "@azure-tools/typespec-client-generator-core";
5
- import { getDoc, getEffectiveModelType, getEncode, getFriendlyName, getNamespaceFullName, getOverloadedOperation, getProjectedName, getSummary, getVisibility, isArrayModelType, isErrorModel, isRecordModelType, isVoidType, listServices, } from "@typespec/compiler";
6
- import { Visibility, getAuthentication, getHeaderFieldName, getPathParamName, getQueryParamName, getServers, getStatusCodeDescription, isBody, isBodyRoot, isHeader, isMultipartBodyProperty, isPathParam, isQueryParam, } from "@typespec/http";
7
- import { getResourceOperation, getSegment } from "@typespec/rest";
8
- import { getAddedOnVersions, getVersion } from "@typespec/versioning";
3
+ import { UsageFlags, createSdkContext, getAllModels, getClientType, getWireName, isApiVersion, isSdkBuiltInKind, isSdkIntKind, } from "@azure-tools/typespec-client-generator-core";
4
+ import { getDoc, getEffectiveModelType, getNamespaceFullName, getOverloadedOperation, getSummary, getVisibility, isArrayModelType, isRecordModelType, listServices, } from "@typespec/compiler";
5
+ import { Visibility, getAuthentication, getHeaderFieldName, getPathParamName, getQueryParamName, isBody, isBodyRoot, isHeader, isMultipartBodyProperty, isPathParam, isQueryParam, } from "@typespec/http";
6
+ import { getSegment } from "@typespec/rest";
7
+ import { getAddedOnVersions } from "@typespec/versioning";
9
8
  import { fail } from "assert";
10
9
  import pkg from "lodash";
11
10
  import { Client as CodeModelClient } from "./common/client.js";
@@ -19,10 +18,10 @@ import { DurationSchema } from "./common/schemas/time.js";
19
18
  import { SchemaContext } from "./common/schemas/usage.js";
20
19
  import { createPollOperationDetailsSchema, getFileDetailsSchema } from "./external-schemas.js";
21
20
  import { ClientContext } from "./models.js";
22
- import { ORIGIN_API_VERSION, SPECIAL_HEADER_NAMES, cloneOperationParameter, getServiceVersion, isKnownContentType, isLroNewPollingStrategy, isPayloadProperty, operationIsJsonMergePatch, operationIsMultipart, operationIsMultipleContentTypes, } from "./operation-utils.js";
21
+ import { CONTENT_TYPE_KEY, ORIGIN_API_VERSION, SPECIAL_HEADER_NAMES, cloneOperationParameter, getServiceVersion, isKnownContentType, isLroNewPollingStrategy, isPayloadProperty, operationIsJsonMergePatch, operationIsMultipart, operationIsMultipleContentTypes, } from "./operation-utils.js";
23
22
  import { PreNamer } from "./prenamer/prenamer.js";
24
- import { ProcessingCache, getAccess, getDurationFormatFromSdkType, getNonNullSdkType, getUnionDescription, getUsage, hasScalarAsBase, isArmCommonType, isModelReferredInTemplate, isNullableType, isStable, modelIs, pushDistinct, } from "./type-utils.js";
25
- import { getNamespace, logWarning, pascalCase, stringArrayContainsIgnoreCase, trace } from "./utils.js";
23
+ import { ProcessingCache, getAccess, getDurationFormatFromSdkType, getNonNullSdkType, getUnionDescription, getUsage, isStable, modelIs, pushDistinct, } from "./type-utils.js";
24
+ import { getNamespace, logWarning, pascalCase, removeClientSuffix, stringArrayContainsIgnoreCase, trace, } from "./utils.js";
26
25
  const { isEqual } = pkg;
27
26
  export class CodeModelBuilder {
28
27
  constructor(program1, context) {
@@ -77,7 +76,9 @@ export class CodeModelBuilder {
77
76
  });
78
77
  }
79
78
  async build() {
80
- this.sdkContext = await createSdkContext(this.emitterContext, "@azure-tools/typespec-java");
79
+ this.sdkContext = await createSdkContext(this.emitterContext, "@azure-tools/typespec-java", {
80
+ versioning: { previewStringRegex: /$/ },
81
+ }); // include all versions and do the filter by ourselves
81
82
  // auth
82
83
  // TODO: it is not very likely, but different client could have different auth
83
84
  const auth = getAuthentication(this.program, this.serviceNamespace);
@@ -89,8 +90,8 @@ export class CodeModelBuilder {
89
90
  this.codeModel.arm = true;
90
91
  this.options["group-etag-headers"] = false;
91
92
  }
92
- const clients = this.processClients();
93
- this.processModels(clients);
93
+ this.processClients();
94
+ this.processModels();
94
95
  this.processSchemaUsage();
95
96
  if (this.options.namer) {
96
97
  this.codeModel = new PreNamer(this.codeModel).init().process();
@@ -98,64 +99,41 @@ export class CodeModelBuilder {
98
99
  this.deduplicateSchemaName();
99
100
  return this.codeModel;
100
101
  }
101
- processHost(server) {
102
+ processHostParameters(sdkPathParameters) {
102
103
  const hostParameters = [];
103
- if (server && !this.isArmSynthesizedServer(server)) {
104
- server.parameters.forEach((it) => {
105
- let parameter;
106
- if (isApiVersion(this.sdkContext, it)) {
107
- parameter = this.createApiVersionParameter(it.name, ParameterLocation.Uri);
108
- }
109
- else {
110
- const sdkType = getClientType(this.sdkContext, it.type);
111
- const schema = this.processSchemaFromSdkType(sdkType, it.name);
112
- this.trackSchemaUsage(schema, {
113
- usage: [SchemaContext.Input, SchemaContext.Output /*SchemaContext.Public*/],
114
- });
115
- parameter = new Parameter(this.getName(it), this.getDoc(it), schema, {
116
- implementation: ImplementationLocation.Client,
117
- origin: "modelerfour:synthesized/host",
118
- required: !it.optional,
119
- protocol: {
120
- http: new HttpParameter(ParameterLocation.Uri),
121
- },
122
- language: {
123
- default: {
124
- serializedName: it.name,
125
- },
126
- },
127
- extensions: {
128
- // TODO: deprecate this logic of string/url for x-ms-skip-url-encoding
129
- "x-ms-skip-url-encoding": schema instanceof UriSchema,
104
+ let parameter;
105
+ sdkPathParameters.forEach((arg) => {
106
+ var _a;
107
+ if (arg.isApiVersionParam) {
108
+ parameter = this.createApiVersionParameter(arg.name, ParameterLocation.Uri);
109
+ }
110
+ else {
111
+ const schema = this.processSchemaFromSdkType(arg.type, arg.name);
112
+ this.trackSchemaUsage(schema, {
113
+ usage: [SchemaContext.Input, SchemaContext.Output /*SchemaContext.Public*/],
114
+ });
115
+ parameter = new Parameter(arg.name, (_a = arg.description) !== null && _a !== void 0 ? _a : "", schema, {
116
+ implementation: ImplementationLocation.Client,
117
+ origin: "modelerfour:synthesized/host",
118
+ required: true,
119
+ protocol: {
120
+ http: new HttpParameter(ParameterLocation.Uri),
121
+ },
122
+ language: {
123
+ default: {
124
+ serializedName: arg.name,
130
125
  },
131
- // // make the logic same as TCGC, which takes the server-side default of host as client-side default
132
- // clientDefaultValue: getDefaultValue(it.defaultValue),
133
- });
134
- }
135
- hostParameters.push(this.codeModel.addGlobalParameter(parameter));
136
- });
137
- return hostParameters;
138
- }
139
- else {
140
- // use "endpoint"
141
- hostParameters.push(this.codeModel.addGlobalParameter(new Parameter("endpoint", "Server parameter", this.stringSchema, {
142
- implementation: ImplementationLocation.Client,
143
- origin: "modelerfour:synthesized/host",
144
- required: true,
145
- protocol: {
146
- http: new HttpParameter(ParameterLocation.Uri),
147
- },
148
- language: {
149
- default: {
150
- serializedName: "endpoint",
151
126
  },
152
- },
153
- extensions: {
154
- "x-ms-skip-url-encoding": true,
155
- },
156
- })));
157
- return hostParameters;
158
- }
127
+ // TODO: deprecate this logic of string/url for x-ms-skip-url-encoding
128
+ extensions: {
129
+ "x-ms-skip-url-encoding": schema instanceof UriSchema,
130
+ },
131
+ clientDefaultValue: arg.clientDefaultValue,
132
+ });
133
+ }
134
+ hostParameters.push(this.codeModel.addGlobalParameter(parameter));
135
+ });
136
+ return hostParameters;
159
137
  }
160
138
  processAuth(auth) {
161
139
  const securitySchemes = [];
@@ -210,16 +188,7 @@ export class CodeModelBuilder {
210
188
  isBranded() {
211
189
  return !this.options["flavor"] || this.options["flavor"].toLocaleLowerCase() === "azure";
212
190
  }
213
- isInternal(operation) {
214
- const access = getAccess(operation);
215
- if (access) {
216
- return access === "internal";
217
- }
218
- else {
219
- return false;
220
- }
221
- }
222
- processModels(clients) {
191
+ processModels() {
223
192
  const processedSdkModels = new Set();
224
193
  // lambda to mark model as public
225
194
  const modelAsPublic = (model) => {
@@ -315,23 +284,22 @@ export class CodeModelBuilder {
315
284
  }
316
285
  }
317
286
  processClients() {
318
- var _a, _b;
319
- const clients = listClients(this.sdkContext);
287
+ var _a, _b, _c;
320
288
  // preprocess group-etag-headers
321
289
  this.options["group-etag-headers"] = (_a = this.options["group-etag-headers"]) !== null && _a !== void 0 ? _a : true;
322
- for (const client of clients) {
290
+ const sdkPackage = this.sdkContext.sdkPackage;
291
+ for (const client of sdkPackage.clients) {
323
292
  let clientName = client.name;
324
- let clientSubNamespace = undefined;
325
293
  let javaNamespace = this.getJavaNamespace(this.namespace);
326
294
  const clientFullName = client.name;
327
295
  const clientNameSegments = clientFullName.split(".");
328
296
  if (clientNameSegments.length > 1) {
329
297
  clientName = clientNameSegments.at(-1);
330
- clientSubNamespace = clientNameSegments.slice(0, -1).join(".");
298
+ const clientSubNamespace = clientNameSegments.slice(0, -1).join(".");
331
299
  javaNamespace = this.getJavaNamespace(this.namespace + "." + clientSubNamespace);
332
300
  }
333
- const codeModelClient = new CodeModelClient(clientName, this.getDoc(client.type), {
334
- summary: this.getSummary(client.type),
301
+ const codeModelClient = new CodeModelClient(clientName, (_b = client.details) !== null && _b !== void 0 ? _b : "", {
302
+ summary: client.description,
335
303
  language: {
336
304
  default: {
337
305
  namespace: this.namespace,
@@ -345,111 +313,144 @@ export class CodeModelBuilder {
345
313
  });
346
314
  codeModelClient.crossLanguageDefinitionId = client.crossLanguageDefinitionId;
347
315
  // versioning
348
- const versioning = getVersion(this.program, client.service);
349
- if (versioning && versioning.getVersions()) {
350
- // @versioned in versioning
316
+ const versions = client.apiVersions;
317
+ if (versions && versions.length > 0) {
351
318
  if (!this.sdkContext.apiVersion || ["all", "latest"].includes(this.sdkContext.apiVersion)) {
352
- this.apiVersion = getDefaultApiVersion(this.sdkContext, client.service);
319
+ this.apiVersion = versions[versions.length - 1];
353
320
  }
354
321
  else {
355
- this.apiVersion = versioning.getVersions().find((it) => it.value === this.sdkContext.apiVersion);
322
+ this.apiVersion = versions.find((it) => it === this.sdkContext.apiVersion);
356
323
  if (!this.apiVersion) {
357
324
  throw new Error("Unrecognized api-version: " + this.sdkContext.apiVersion);
358
325
  }
359
326
  }
360
327
  codeModelClient.apiVersions = [];
361
- for (const version of this.getFilteredApiVersions(this.apiVersion, versioning.getVersions(), this.options["service-version-exclude-preview"])) {
328
+ for (const version of this.getFilteredApiVersions(this.apiVersion, versions, this.options["service-version-exclude-preview"])) {
362
329
  const apiVersion = new ApiVersion();
363
- apiVersion.version = version.value;
330
+ apiVersion.version = version;
364
331
  codeModelClient.apiVersions.push(apiVersion);
365
332
  }
366
333
  }
367
- // server
334
+ // client initialization
368
335
  let baseUri = "{endpoint}";
369
- const servers = getServers(this.program, client.service);
370
- if (servers && servers.length === 1 && !this.isArmSynthesizedServer(servers[0])) {
371
- baseUri = servers[0].url;
372
- }
373
- const hostParameters = this.processHost((servers === null || servers === void 0 ? void 0 : servers.length) === 1 ? servers[0] : undefined);
374
- codeModelClient.addGlobalParameters(hostParameters);
336
+ let hostParameters = [];
337
+ client.initialization.properties.forEach((initializationProperty) => {
338
+ if (initializationProperty.kind === "endpoint") {
339
+ let sdkPathParameters = [];
340
+ if (initializationProperty.type.kind === "union") {
341
+ if (initializationProperty.type.values.length === 2) {
342
+ // only get the sdkPathParameters from the endpoint whose serverUrl is not {"endpoint"}
343
+ for (const endpointType of initializationProperty.type.values) {
344
+ if (endpointType.kind === "endpoint" && endpointType.serverUrl !== "{endpoint}") {
345
+ sdkPathParameters = endpointType.templateArguments;
346
+ baseUri = endpointType.serverUrl;
347
+ }
348
+ }
349
+ }
350
+ else if (initializationProperty.type.values.length > 2) {
351
+ throw new Error("Multiple server url defined for one client is not supported yet.");
352
+ }
353
+ }
354
+ else if (initializationProperty.type.kind === "endpoint") {
355
+ sdkPathParameters = initializationProperty.type.templateArguments;
356
+ baseUri = initializationProperty.type.serverUrl;
357
+ }
358
+ hostParameters = this.processHostParameters(sdkPathParameters);
359
+ codeModelClient.addGlobalParameters(hostParameters);
360
+ }
361
+ });
375
362
  const clientContext = new ClientContext(baseUri, hostParameters, codeModelClient.globalParameters, codeModelClient.apiVersions);
376
- clientContext.preProcessOperations(this.sdkContext, client);
377
- const operationGroups = listOperationGroups(this.sdkContext, client, true);
378
- const operationWithoutGroup = listOperationsInOperationGroup(this.sdkContext, client);
363
+ // preprocess operation groups and operations
364
+ // operations without operation group
365
+ const serviceMethodsWithoutSubClient = this.listServiceMethodsUnderClient(client);
379
366
  let codeModelGroup = new OperationGroup("");
380
- for (const operation of operationWithoutGroup) {
381
- if (!this.needToSkipProcessingOperation(operation, clientContext)) {
382
- codeModelGroup.addOperation(this.processOperation("", operation, clientContext));
367
+ for (const serviceMethod of serviceMethodsWithoutSubClient) {
368
+ if (!this.needToSkipProcessingOperation(serviceMethod.__raw, clientContext)) {
369
+ codeModelGroup.addOperation(this.processOperation(serviceMethod, clientContext, ""));
383
370
  }
384
371
  }
385
- if (((_b = codeModelGroup.operations) === null || _b === void 0 ? void 0 : _b.length) > 0) {
372
+ if (((_c = codeModelGroup.operations) === null || _c === void 0 ? void 0 : _c.length) > 0) {
386
373
  codeModelClient.operationGroups.push(codeModelGroup);
387
374
  }
388
- for (const operationGroup of operationGroups) {
389
- const operations = listOperationsInOperationGroup(this.sdkContext, operationGroup);
375
+ // operations under operation groups
376
+ const subClients = this.listSubClientsUnderClient(client, true, true);
377
+ for (const subClient of subClients) {
378
+ const serviceMethods = this.listServiceMethodsUnderClient(subClient);
390
379
  // operation group with no operation is skipped
391
- if (operations.length > 0) {
392
- // groupPath would be in format of "[<SubNamespace>.]<ClientName>.Chat.Completions"
393
- let operationGroupPath = operationGroup.groupPath;
394
- if (clientSubNamespace && operationGroup.groupPath.startsWith(clientSubNamespace + ".")) {
395
- // remove SubNamespace
396
- operationGroupPath = operationGroupPath.slice((clientSubNamespace + ".").length);
397
- }
398
- const groupPath = operationGroupPath.split(".");
399
- let operationGroupName;
400
- if (groupPath.length > 1) {
401
- // remove ClientName
402
- operationGroupName = groupPath.slice(1).join("");
403
- }
404
- else {
405
- operationGroupName = groupPath[0];
406
- }
407
- codeModelGroup = new OperationGroup(operationGroupName);
408
- for (const operation of operations) {
409
- if (!this.needToSkipProcessingOperation(operation, clientContext)) {
410
- codeModelGroup.addOperation(this.processOperation(operationGroupName, operation, clientContext));
380
+ if (serviceMethods.length > 0) {
381
+ codeModelGroup = new OperationGroup(subClient.name);
382
+ for (const serviceMethod of serviceMethods) {
383
+ if (!this.needToSkipProcessingOperation(serviceMethod.__raw, clientContext)) {
384
+ codeModelGroup.addOperation(this.processOperation(serviceMethod, clientContext, subClient.name));
411
385
  }
412
386
  }
413
387
  codeModelClient.operationGroups.push(codeModelGroup);
414
388
  }
415
389
  }
416
390
  this.codeModel.clients.push(codeModelClient);
417
- }
418
- // postprocess for ServiceVersion
419
- let apiVersionSameForAllClients = true;
420
- let sharedApiVersions = undefined;
421
- for (const client of this.codeModel.clients) {
422
- const apiVersions = client.apiVersions;
423
- if (!apiVersions) {
424
- // client does not have apiVersions
425
- apiVersionSameForAllClients = false;
391
+ // postprocess for ServiceVersion
392
+ let apiVersionSameForAllClients = true;
393
+ let sharedApiVersions = undefined;
394
+ for (const client of this.codeModel.clients) {
395
+ const apiVersions = client.apiVersions;
396
+ if (!apiVersions) {
397
+ // client does not have apiVersions
398
+ apiVersionSameForAllClients = false;
399
+ }
400
+ else if (!sharedApiVersions) {
401
+ // first client, set it to sharedApiVersions
402
+ sharedApiVersions = apiVersions;
403
+ }
404
+ else {
405
+ apiVersionSameForAllClients = isEqual(sharedApiVersions, apiVersions);
406
+ }
407
+ if (!apiVersionSameForAllClients) {
408
+ break;
409
+ }
426
410
  }
427
- else if (!sharedApiVersions) {
428
- // first client, set it to sharedApiVersions
429
- sharedApiVersions = apiVersions;
411
+ if (apiVersionSameForAllClients) {
412
+ const serviceVersion = getServiceVersion(this.codeModel);
413
+ for (const client of this.codeModel.clients) {
414
+ client.serviceVersion = serviceVersion;
415
+ }
430
416
  }
431
417
  else {
432
- apiVersionSameForAllClients = isEqual(sharedApiVersions, apiVersions);
433
- }
434
- if (!apiVersionSameForAllClients) {
435
- break;
418
+ for (const client of this.codeModel.clients) {
419
+ const apiVersions = client.apiVersions;
420
+ if (apiVersions) {
421
+ client.serviceVersion = getServiceVersion(client);
422
+ }
423
+ }
436
424
  }
437
425
  }
438
- if (apiVersionSameForAllClients) {
439
- const serviceVersion = getServiceVersion(this.codeModel);
440
- for (const client of this.codeModel.clients) {
441
- client.serviceVersion = serviceVersion;
426
+ }
427
+ listSubClientsUnderClient(client, includeNestedOperationGroups, isRootClient) {
428
+ const operationGroups = [];
429
+ for (const method of client.methods) {
430
+ if (method.kind === "clientaccessor") {
431
+ const subClient = method.response;
432
+ if (!isRootClient) {
433
+ // if it is not root client, append the parent client's name
434
+ subClient.name = removeClientSuffix(client.name) + removeClientSuffix(pascalCase(subClient.name));
435
+ }
436
+ operationGroups.push(subClient);
437
+ if (includeNestedOperationGroups) {
438
+ for (const operationGroup of this.listSubClientsUnderClient(subClient, includeNestedOperationGroups, false)) {
439
+ operationGroups.push(operationGroup);
440
+ }
441
+ }
442
442
  }
443
443
  }
444
- else {
445
- for (const client of this.codeModel.clients) {
446
- const apiVersions = client.apiVersions;
447
- if (apiVersions) {
448
- client.serviceVersion = getServiceVersion(client);
449
- }
444
+ return operationGroups;
445
+ }
446
+ listServiceMethodsUnderClient(client) {
447
+ const methods = [];
448
+ for (const method of client.methods) {
449
+ if (method.kind !== "clientaccessor") {
450
+ methods.push(method);
450
451
  }
451
452
  }
452
- return clients;
453
+ return methods;
453
454
  }
454
455
  /**
455
456
  * Filter api-versions for "ServiceVersion".
@@ -467,20 +468,12 @@ export class CodeModelBuilder {
467
468
  .slice(0, versions.indexOf(pinnedApiVersion) + 1)
468
469
  .filter((version) => !excludePreview || !isStable(pinnedApiVersion) || isStable(version));
469
470
  }
470
- /**
471
- * `@armProviderNamespace` currently will add a default server if not defined globally:
472
- * https://github.com/Azure/typespec-azure/blob/8b8d7c05f168d9305a09691c4fedcb88f4a57652/packages/typespec-azure-resource-manager/src/namespace.ts#L121-L128
473
- * TODO: if the synthesized server has the right hostParameter, we can use that instead
474
- *
475
- * @param server returned by getServers
476
- * @returns whether it's synthesized by `@armProviderNamespace`
477
- */
478
- isArmSynthesizedServer(server) {
479
- return this.isArm() && (!server.parameters || server.parameters.size == 0);
480
- }
481
471
  needToSkipProcessingOperation(operation, clientContext) {
482
472
  // don't generate protocol and convenience method for overloaded operations
483
473
  // issue link: https://github.com/Azure/autorest.java/issues/1958#issuecomment-1562558219 we will support generate overload methods for non-union type in future (TODO issue: https://github.com/Azure/autorest.java/issues/2160)
474
+ if (operation === undefined) {
475
+ return true;
476
+ }
484
477
  if (getOverloadedOperation(this.program, operation)) {
485
478
  this.trace(`Operation '${operation.name}' is temporary skipped, as it is an overloaded operation`);
486
479
  return true;
@@ -493,9 +486,9 @@ export class CodeModelBuilder {
493
486
  supportsAdvancedVersioning() {
494
487
  return Boolean(this.options["advanced-versioning"]);
495
488
  }
496
- getOperationExample(operation) {
489
+ getOperationExample(sdkMethod) {
497
490
  var _a, _b;
498
- const httpOperationExamples = getHttpOperationExamples(this.sdkContext, operation);
491
+ const httpOperationExamples = sdkMethod.operation.examples;
499
492
  if (httpOperationExamples && httpOperationExamples.length > 0) {
500
493
  const operationExamples = {};
501
494
  for (const example of httpOperationExamples) {
@@ -503,8 +496,7 @@ export class CodeModelBuilder {
503
496
  // example.filePath is relative path from sdkContext.examplesDir
504
497
  // this is not a URL format (file:// or https://)
505
498
  operationExample["x-ms-original-file"] = example.filePath;
506
- operationExamples[(_b = (_a = operationExample.title) !== null && _a !== void 0 ? _a : operationExample.operationId) !== null && _b !== void 0 ? _b : operation.operation.name] =
507
- operationExample;
499
+ operationExamples[(_b = (_a = operationExample.title) !== null && _a !== void 0 ? _a : operationExample.operationId) !== null && _b !== void 0 ? _b : sdkMethod.name] = operationExample;
508
500
  }
509
501
  return operationExamples;
510
502
  }
@@ -512,58 +504,47 @@ export class CodeModelBuilder {
512
504
  return undefined;
513
505
  }
514
506
  }
515
- processOperation(groupName, operation, clientContext) {
507
+ processOperation(sdkMethod, clientContext, groupName) {
516
508
  var _a;
517
- const op = getHttpOperationWithCache(this.sdkContext, operation);
509
+ const operationName = sdkMethod.name;
510
+ const httpOperation = sdkMethod.operation;
511
+ const operationId = groupName ? `${groupName}_${operationName}` : `${operationName}`;
518
512
  const operationGroup = this.codeModel.getOperationGroup(groupName);
519
- const operationName = this.getName(operation);
520
- const opId = groupName ? `${groupName}_${operationName}` : `${operationName}`;
521
- const operationExamples = this.getOperationExample(op);
522
- const codeModelOperation = new CodeModelOperation(operationName, this.getDoc(operation), {
523
- operationId: opId,
524
- summary: this.getSummary(operation),
513
+ const operationExamples = this.getOperationExample(sdkMethod);
514
+ const codeModelOperation = new CodeModelOperation(operationName, (_a = sdkMethod.details) !== null && _a !== void 0 ? _a : "", {
515
+ operationId: operationId,
516
+ summary: sdkMethod.description,
525
517
  extensions: {
526
518
  "x-ms-examples": operationExamples,
527
519
  },
528
520
  });
529
- codeModelOperation.crossLanguageDefinitionId = getCrossLanguageDefinitionId(this.sdkContext, operation);
530
- codeModelOperation.internalApi = this.isInternal(operation);
531
- const convenienceApiName = this.getConvenienceApiName(operation);
532
- let generateConvenienceApi = Boolean(convenienceApiName);
533
- let generateProtocolApi = shouldGenerateProtocol(this.sdkContext, operation);
521
+ codeModelOperation.crossLanguageDefinitionId = sdkMethod.crossLanguageDefintionId;
522
+ codeModelOperation.internalApi = sdkMethod.access === "internal";
523
+ const convenienceApiName = this.getConvenienceApiName(sdkMethod);
524
+ let generateConvenienceApi = sdkMethod.generateConvenient;
525
+ let generateProtocolApi = sdkMethod.generateProtocol;
534
526
  let apiComment = undefined;
535
527
  if (generateConvenienceApi) {
536
528
  // check if the convenience API need to be disabled for some special cases
537
- if (operationIsMultipart(op)) {
529
+ if (operationIsMultipart(httpOperation)) {
538
530
  // do not generate protocol method for multipart/form-data, as it be very hard for user to prepare the request body as BinaryData
539
531
  generateProtocolApi = false;
540
- apiComment = `Protocol API requires serialization of parts with content-disposition and data, as operation '${op.operation.name}' is 'multipart/form-data'`;
532
+ apiComment = `Protocol API requires serialization of parts with content-disposition and data, as operation '${operationName}' is 'multipart/form-data'`;
541
533
  this.logWarning(apiComment);
542
534
  }
543
- else if (operationIsMultipleContentTypes(op)) {
535
+ else if (operationIsMultipleContentTypes(httpOperation)) {
544
536
  // and multiple content types
545
537
  // issue link: https://github.com/Azure/autorest.java/issues/1958#issuecomment-1562558219
546
538
  generateConvenienceApi = false;
547
- apiComment = `Convenience API is not generated, as operation '${op.operation.name}' is multiple content-type`;
539
+ apiComment = `Convenience API is not generated, as operation '${operationName}' is multiple content-type`;
548
540
  this.logWarning(apiComment);
549
541
  }
550
- else if (operationIsJsonMergePatch(op) && this.options["stream-style-serialization"] === false) {
542
+ else if (operationIsJsonMergePatch(httpOperation) && this.options["stream-style-serialization"] === false) {
551
543
  // do not generate convenient method for json merge patch operation if stream-style-serialization is not enabled
552
544
  generateConvenienceApi = false;
553
- apiComment = `Convenience API is not generated, as operation '${op.operation.name}' is 'application/merge-patch+json' and stream-style-serialization is not enabled`;
545
+ apiComment = `Convenience API is not generated, as operation '${operationName}' is 'application/merge-patch+json' and stream-style-serialization is not enabled`;
554
546
  this.logWarning(apiComment);
555
547
  }
556
- // else {
557
- // const union = operationRefersUnion(this.program, op, this.typeUnionRefCache);
558
- // if (union) {
559
- // // and Union
560
- // generateConvenienceApi = false;
561
- // apiComment = `Convenience API is not generated, as operation '${
562
- // op.operation.name
563
- // }' refers Union '${getUnionDescription(union, this.typeNameOptions)}'`;
564
- // this.logWarning(apiComment);
565
- // }
566
- // }
567
548
  }
568
549
  if (generateConvenienceApi && convenienceApiName) {
569
550
  codeModelOperation.convenienceApi = new ConvenienceApi(convenienceApiName);
@@ -577,75 +558,76 @@ export class CodeModelBuilder {
577
558
  codeModelOperation.addRequest(new Request({
578
559
  protocol: {
579
560
  http: {
580
- path: op.path,
581
- method: op.verb,
561
+ path: httpOperation.path,
562
+ method: httpOperation.verb,
582
563
  uri: clientContext.baseUri,
583
564
  },
584
565
  },
585
566
  }));
586
567
  // host
587
568
  clientContext.hostParameters.forEach((it) => codeModelOperation.addParameter(it));
588
- // parameters
589
- op.parameters.parameters.map((it) => this.processParameter(codeModelOperation, it, clientContext));
590
- // "accept" header
591
- this.addAcceptHeaderParameter(codeModelOperation, op.responses);
592
- // body
593
- if (op.parameters.body) {
594
- if (op.parameters.body.property) {
595
- if (!isVoidType(op.parameters.body.property.type)) {
596
- this.processParameterBody(codeModelOperation, op, op.parameters.body.property);
569
+ // path/query/header parameters
570
+ for (const param of httpOperation.parameters) {
571
+ // if it's paged operation with request body, skip content-type header added by TCGC, as next link call should not have content type header
572
+ if ((sdkMethod.kind === "paging" || sdkMethod.kind === "lropaging") &&
573
+ httpOperation.bodyParam &&
574
+ param.kind === "header") {
575
+ if (param.serializedName.toLocaleLowerCase() === CONTENT_TYPE_KEY) {
576
+ continue;
597
577
  }
598
578
  }
599
- else if (op.parameters.body.type) {
600
- let bodyType = op.parameters.body.type;
601
- if (bodyType.kind === "Model") {
602
- // try use resource type as round-trip model
603
- const resourceType = (_a = getResourceOperation(this.program, operation)) === null || _a === void 0 ? void 0 : _a.resourceType;
604
- if (resourceType && op.responses && op.responses.length > 0) {
605
- const resp = op.responses[0];
606
- if (resp.responses && resp.responses.length > 0 && resp.responses[0].body) {
607
- const responseBody = resp.responses[0].body;
608
- const bodyTypeInResponse = this.findResponseBody(responseBody.type);
609
- // response body type is resource type, and request body type (if templated) contains resource type
610
- if (bodyTypeInResponse === resourceType && isModelReferredInTemplate(bodyType, resourceType)) {
611
- bodyType = resourceType;
612
- }
613
- }
614
- }
615
- this.processParameterBody(codeModelOperation, op, bodyType);
579
+ // if the request body is optional, skip content-type header added by TCGC
580
+ // TODO: add optional content type to code-model, and support optional content-type from codegen, https://github.com/Azure/autorest.java/issues/2930
581
+ if (httpOperation.bodyParam && httpOperation.bodyParam.optional) {
582
+ if (param.serializedName.toLocaleLowerCase() === CONTENT_TYPE_KEY) {
583
+ continue;
616
584
  }
617
585
  }
586
+ this.processParameter(codeModelOperation, param, clientContext);
587
+ }
588
+ // body
589
+ if (httpOperation.bodyParam && httpOperation.__raw && httpOperation.bodyParam.type.__raw) {
590
+ this.processParameterBody(codeModelOperation, httpOperation.__raw, httpOperation, httpOperation.bodyParam);
618
591
  }
619
592
  // group ETag header parameters, if exists
620
593
  if (this.options["group-etag-headers"]) {
621
- this.processEtagHeaderParameters(codeModelOperation, op);
594
+ this.processEtagHeaderParameters(codeModelOperation, sdkMethod.operation);
622
595
  }
623
596
  // lro metadata
624
- const lroMetadata = this.processLroMetadata(codeModelOperation, op);
597
+ let lroMetadata = new LongRunningMetadata(false);
598
+ if (sdkMethod.kind === "lro" || sdkMethod.kind === "lropaging") {
599
+ lroMetadata = this.processLroMetadata(codeModelOperation, sdkMethod);
600
+ }
625
601
  // responses
626
- op.responses.map((it) => this.processResponse(codeModelOperation, it, lroMetadata.longRunning));
602
+ for (const [code, response] of sdkMethod.operation.responses) {
603
+ this.processResponse(codeModelOperation, code, response, lroMetadata.longRunning, false);
604
+ }
605
+ // exception
606
+ for (const [code, response] of sdkMethod.operation.exceptions) {
607
+ this.processResponse(codeModelOperation, code, response, lroMetadata.longRunning, true);
608
+ }
627
609
  // check for paged
628
- this.processRouteForPaged(codeModelOperation, op.responses);
610
+ this.processRouteForPaged(codeModelOperation, sdkMethod.operation.responses, sdkMethod);
629
611
  // check for long-running operation
630
- this.processRouteForLongRunning(codeModelOperation, operation, op.responses, lroMetadata);
612
+ this.processRouteForLongRunning(codeModelOperation, sdkMethod.operation.responses, lroMetadata);
631
613
  operationGroup.addOperation(codeModelOperation);
632
614
  return codeModelOperation;
633
615
  }
634
- processRouteForPaged(op, responses) {
635
- var _a, _b, _c, _d;
636
- for (const response of responses) {
637
- if (response.responses && response.responses.length > 0 && response.responses[0].body) {
638
- const responseBody = response.responses[0].body;
639
- const bodyType = this.findResponseBody(responseBody.type);
640
- if (bodyType.kind === "Model") {
641
- const pagedResult = getPagedResult(this.program, bodyType);
642
- if (pagedResult) {
616
+ processRouteForPaged(op, responses, sdkMethod) {
617
+ var _a, _b;
618
+ if (sdkMethod.kind === "paging" || sdkMethod.kind === "lropaging") {
619
+ for (const [_, response] of responses) {
620
+ const bodyType = response.type;
621
+ if (bodyType && bodyType.kind === "model") {
622
+ const itemName = sdkMethod.response.resultPath;
623
+ const nextLinkName = sdkMethod.nextLinkPath;
624
+ if (itemName && nextLinkName) {
643
625
  op.extensions = (_a = op.extensions) !== null && _a !== void 0 ? _a : {};
644
626
  op.extensions["x-ms-pageable"] = {
645
- itemName: (_b = pagedResult.itemsProperty) === null || _b === void 0 ? void 0 : _b.name,
646
- nextLinkName: (_c = pagedResult.nextLinkProperty) === null || _c === void 0 ? void 0 : _c.name,
627
+ itemName: itemName,
628
+ nextLinkName: nextLinkName,
647
629
  };
648
- (_d = op.responses) === null || _d === void 0 ? void 0 : _d.forEach((r) => {
630
+ (_b = op.responses) === null || _b === void 0 ? void 0 : _b.forEach((r) => {
649
631
  if (r instanceof SchemaResponse) {
650
632
  this.trackSchemaUsage(r.schema, { usage: [SchemaContext.Paged] });
651
633
  }
@@ -656,18 +638,17 @@ export class CodeModelBuilder {
656
638
  }
657
639
  }
658
640
  }
659
- processLroMetadata(op, httpOperation) {
660
- const operation = httpOperation.operation;
641
+ processLroMetadata(op, sdkMethod) {
661
642
  const trackConvenienceApi = Boolean(op.convenienceApi);
662
- const lroMetadata = getLroMetadata(this.program, operation);
643
+ const lroMetadata = sdkMethod.__raw_lro_metadata;
663
644
  // needs lroMetadata.statusMonitorStep, as getLroMetadata would return for @pollingOperation operation
664
645
  if (lroMetadata && lroMetadata.pollingInfo && lroMetadata.statusMonitorStep) {
665
646
  let pollingSchema = undefined;
666
647
  let finalSchema = undefined;
667
648
  let pollingStrategy = undefined;
668
649
  let finalResultPropertySerializedName = undefined;
669
- const verb = httpOperation.verb;
670
- const useNewPollStrategy = isLroNewPollingStrategy(httpOperation, lroMetadata);
650
+ const verb = sdkMethod.operation.verb;
651
+ const useNewPollStrategy = isLroNewPollingStrategy(sdkMethod.operation.__raw, lroMetadata);
671
652
  if (useNewPollStrategy) {
672
653
  // use OperationLocationPollingStrategy
673
654
  pollingStrategy = new Metadata({
@@ -728,24 +709,13 @@ export class CodeModelBuilder {
728
709
  }
729
710
  return new LongRunningMetadata(false);
730
711
  }
731
- processRouteForLongRunning(op, operation, responses, lroMetadata) {
732
- var _a, _b;
712
+ processRouteForLongRunning(op, responses, lroMetadata) {
713
+ var _a;
733
714
  if (lroMetadata.longRunning) {
734
715
  op.extensions = (_a = op.extensions) !== null && _a !== void 0 ? _a : {};
735
716
  op.extensions["x-ms-long-running-operation"] = true;
736
717
  return;
737
718
  }
738
- for (const resp of responses) {
739
- if (resp.responses && resp.responses.length > 0 && resp.responses[0].headers) {
740
- for (const [_, header] of Object.entries(resp.responses[0].headers)) {
741
- if (isPollingLocation(this.program, header)) {
742
- op.extensions = (_b = op.extensions) !== null && _b !== void 0 ? _b : {};
743
- op.extensions["x-ms-long-running-operation"] = true;
744
- break;
745
- }
746
- }
747
- }
748
- }
749
719
  }
750
720
  processParameter(op, param, clientContext) {
751
721
  var _a, _b;
@@ -754,65 +724,52 @@ export class CodeModelBuilder {
754
724
  if (this.isArm()) {
755
725
  // Currently we assume ARM tsp only have one client and one api-version.
756
726
  // TODO: How will service define mixed api-versions(like those in Compute RP)?
757
- const apiVersion = (_a = this.apiVersion) === null || _a === void 0 ? void 0 : _a.value;
727
+ const apiVersion = this.apiVersion;
758
728
  if (!this._armApiVersionParameter) {
759
- this._armApiVersionParameter = this.createApiVersionParameter("api-version", param.type === "query" ? ParameterLocation.Query : ParameterLocation.Path, apiVersion);
729
+ this._armApiVersionParameter = this.createApiVersionParameter("api-version", param.kind === "query" ? ParameterLocation.Query : ParameterLocation.Path, apiVersion);
760
730
  clientContext.addGlobalParameter(this._armApiVersionParameter);
761
731
  }
762
732
  op.addParameter(this._armApiVersionParameter);
763
733
  }
764
734
  else {
765
- const parameter = param.type === "query" ? this.apiVersionParameter : this.apiVersionParameterInPath;
735
+ const parameter = param.kind === "query" ? this.apiVersionParameter : this.apiVersionParameterInPath;
766
736
  op.addParameter(parameter);
767
737
  clientContext.addGlobalParameter(parameter);
768
738
  }
769
739
  }
770
- else if (this.isSubscriptionId(param)) {
740
+ else if (param.kind === "path" && param.onClient && this.isSubscriptionId(param)) {
771
741
  const parameter = this.subscriptionIdParameter(param);
772
742
  op.addParameter(parameter);
773
743
  clientContext.addGlobalParameter(parameter);
774
744
  }
775
- else if (SPECIAL_HEADER_NAMES.has(param.name.toLowerCase())) {
745
+ else if (param.kind === "header" && SPECIAL_HEADER_NAMES.has(param.serializedName.toLowerCase())) {
776
746
  // special headers
777
- op.specialHeaders = (_b = op.specialHeaders) !== null && _b !== void 0 ? _b : [];
778
- if (!stringArrayContainsIgnoreCase(op.specialHeaders, param.name)) {
779
- op.specialHeaders.push(param.name);
747
+ op.specialHeaders = (_a = op.specialHeaders) !== null && _a !== void 0 ? _a : [];
748
+ if (!stringArrayContainsIgnoreCase(op.specialHeaders, param.serializedName)) {
749
+ op.specialHeaders.push(param.serializedName);
780
750
  }
781
751
  }
782
752
  else {
783
753
  // schema
784
- let schema;
785
- const sdkType = getNonNullSdkType(getClientType(this.sdkContext, param.param));
786
- if (param.type === "header" &&
787
- param.param.type.kind === "Scalar" &&
788
- getEncode(this.program, param.param) === undefined &&
789
- getEncode(this.program, param.param.type) === undefined &&
790
- (hasScalarAsBase(param.param.type, "utcDateTime") || hasScalarAsBase(param.param.type, "offsetDateTime")) &&
791
- (sdkType.kind === "utcDateTime" || sdkType.kind === "offsetDateTime")) {
792
- // utcDateTime in header maps to rfc7231
793
- schema = this.processDateTimeSchemaFromSdkType(sdkType, param.param.name, true);
794
- }
795
- else {
796
- schema = this.processSchemaFromSdkType(sdkType, param.param.name);
797
- }
754
+ const sdkType = getNonNullSdkType(param.type);
755
+ const schema = this.processSchemaFromSdkType(sdkType, param.name);
798
756
  let extensions = undefined;
799
- // skip-url-encoding
800
- if (param.type === "path") {
757
+ if (param.kind === "path") {
801
758
  if (param.allowReserved) {
802
759
  extensions = extensions !== null && extensions !== void 0 ? extensions : {};
803
760
  extensions["x-ms-skip-url-encoding"] = true;
804
761
  }
805
762
  }
806
763
  // TODO: deprecate this logic of string/url for x-ms-skip-url-encoding
807
- if ((param.type === "query" || param.type === "path") &&
808
- param.param.type.kind === "Scalar" &&
764
+ if ((param.kind === "query" || param.kind === "path") &&
765
+ isSdkBuiltInKind(sdkType.kind) &&
809
766
  schema instanceof UriSchema) {
810
767
  extensions = extensions !== null && extensions !== void 0 ? extensions : {};
811
768
  extensions["x-ms-skip-url-encoding"] = true;
812
769
  }
813
- if (this.supportsAdvancedVersioning()) {
770
+ if (this.supportsAdvancedVersioning() && param.__raw) {
814
771
  // versioning
815
- const addedOn = getAddedOnVersions(this.program, param.param);
772
+ const addedOn = getAddedOnVersions(this.program, param.__raw);
816
773
  if (addedOn) {
817
774
  extensions = extensions !== null && extensions !== void 0 ? extensions : {};
818
775
  extensions["x-ms-versioning-added"] = clientContext.getAddedVersions(addedOn);
@@ -821,62 +778,59 @@ export class CodeModelBuilder {
821
778
  // format if array
822
779
  let style = undefined;
823
780
  let explode = undefined;
824
- if (param.param.type.kind === "Model" && isArrayModelType(this.program, param.param.type)) {
825
- if (param.type === "query") {
826
- // eslint-disable-next-line deprecation/deprecation
827
- const queryParamFormat = param === null || param === void 0 ? void 0 : param.format;
828
- if (queryParamFormat) {
829
- switch (queryParamFormat) {
830
- case "csv":
831
- style = SerializationStyle.Simple;
832
- break;
833
- case "ssv":
834
- style = SerializationStyle.SpaceDelimited;
835
- break;
836
- case "tsv":
837
- style = SerializationStyle.TabDelimited;
838
- break;
839
- case "pipes":
840
- style = SerializationStyle.PipeDelimited;
841
- break;
842
- case "multi":
843
- style = SerializationStyle.Form;
844
- explode = true;
845
- break;
846
- default:
847
- this.logWarning(`Unrecognized query parameter format: '${queryParamFormat}'.`);
848
- break;
849
- }
781
+ if (sdkType.kind === "array") {
782
+ if (param.kind === "query") {
783
+ const format = param.collectionFormat;
784
+ switch (format) {
785
+ case "csv":
786
+ case "simple":
787
+ style = SerializationStyle.Simple;
788
+ break;
789
+ case "ssv":
790
+ style = SerializationStyle.SpaceDelimited;
791
+ break;
792
+ case "tsv":
793
+ style = SerializationStyle.TabDelimited;
794
+ break;
795
+ case "pipes":
796
+ style = SerializationStyle.PipeDelimited;
797
+ break;
798
+ case "multi":
799
+ case "form":
800
+ style = SerializationStyle.Form;
801
+ explode = true;
802
+ break;
850
803
  }
851
804
  }
852
- else if (param.type === "header") {
853
- if (param.format) {
854
- switch (param.format) {
855
- case "csv":
856
- style = SerializationStyle.Simple;
857
- break;
858
- default:
859
- this.logWarning(`Unrecognized header parameter format: '${param.format}'.`);
860
- break;
861
- }
805
+ else if (param.kind === "header") {
806
+ const format = param.collectionFormat;
807
+ switch (format) {
808
+ case "csv":
809
+ style = SerializationStyle.Simple;
810
+ break;
811
+ default:
812
+ if (format) {
813
+ this.logWarning(`Unrecognized header parameter format: '${format}'.`);
814
+ }
815
+ break;
862
816
  }
863
817
  }
864
818
  }
865
- const nullable = isNullableType(param.param.type);
866
- const parameter = new Parameter(this.getName(param.param), this.getDoc(param.param), schema, {
867
- summary: this.getSummary(param.param),
819
+ const nullable = param.type.kind === "nullable";
820
+ const parameter = new Parameter(param.name, (_b = param.details) !== null && _b !== void 0 ? _b : "", schema, {
821
+ summary: param.description,
868
822
  implementation: ImplementationLocation.Method,
869
- required: !param.param.optional,
823
+ required: !param.optional,
870
824
  nullable: nullable,
871
825
  protocol: {
872
- http: new HttpParameter(param.type, {
826
+ http: new HttpParameter(param.kind, {
873
827
  style: style,
874
828
  explode: explode,
875
829
  }),
876
830
  },
877
831
  language: {
878
832
  default: {
879
- serializedName: this.getSerializedName(param.param),
833
+ serializedName: param.serializedName, // it uses param.name previously, but better to use param.serializedName directly
880
834
  },
881
835
  },
882
836
  extensions: extensions,
@@ -888,43 +842,6 @@ export class CodeModelBuilder {
888
842
  }
889
843
  }
890
844
  }
891
- addAcceptHeaderParameter(op, responses) {
892
- var _a, _b, _c;
893
- if ((_a = op.parameters) === null || _a === void 0 ? void 0 : _a.some((it) => { var _a; return ((_a = it.language.default.serializedName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === "accept"; })) {
894
- // parameters already include "accept" header
895
- return;
896
- }
897
- const produces = new Set();
898
- for (const resp of responses) {
899
- if (resp.responses && resp.responses.length > 0) {
900
- for (const response of resp.responses) {
901
- (_b = response.body) === null || _b === void 0 ? void 0 : _b.contentTypes.forEach((it) => produces.add(it));
902
- }
903
- }
904
- }
905
- if (produces.size === 0) {
906
- produces.add("application/json");
907
- }
908
- const acceptTypes = Array.from(produces.values()).join(", ");
909
- const acceptSchema = ((_c = this.codeModel.schemas.constants) === null || _c === void 0 ? void 0 : _c.find((it) => it.language.default.name === "accept" && it.value.value === acceptTypes)) ||
910
- this.codeModel.schemas.add(new ConstantSchema("accept", `Accept: ${acceptTypes}`, {
911
- valueType: this.stringSchema,
912
- value: new ConstantValue(acceptTypes),
913
- }));
914
- op.addParameter(new Parameter("accept", "Accept header", acceptSchema, {
915
- implementation: ImplementationLocation.Method,
916
- origin: "modelerfour:synthesized/accept",
917
- required: true,
918
- protocol: {
919
- http: new HttpParameter(ParameterLocation.Header),
920
- },
921
- language: {
922
- default: {
923
- serializedName: "accept",
924
- },
925
- },
926
- }));
927
- }
928
845
  processEtagHeaderParameters(op, httpOperation) {
929
846
  if (op.convenienceApi && op.parameters && op.signatureParameters) {
930
847
  const etagHeadersNames = new Set([
@@ -975,7 +892,7 @@ export class CodeModelBuilder {
975
892
  request.signatureParameters.push(clonedParameter);
976
893
  }
977
894
  }
978
- const namespace = getNamespace(httpOperation.operation);
895
+ const namespace = getNamespace(httpOperation.__raw.operation); // TODO: SdkHttpOperation does not have namespace
979
896
  const schemaName = groupToRequestConditions ? "RequestConditions" : "MatchConditions";
980
897
  const schemaDescription = groupToRequestConditions
981
898
  ? "Specifies HTTP options for conditional requests based on modification time."
@@ -1026,35 +943,27 @@ export class CodeModelBuilder {
1026
943
  }
1027
944
  }
1028
945
  }
1029
- processParameterBody(op, httpOperation, body) {
1030
- var _a, _b, _c;
946
+ processParameterBody(op, rawHttpOperation, sdkHttpOperation, sdkBody) {
947
+ var _a;
1031
948
  // set contentTypes to mediaTypes
1032
- op.requests[0].protocol.http.mediaTypes = httpOperation.parameters.body.contentTypes;
1033
- const parameters = httpOperation.operation.parameters;
949
+ op.requests[0].protocol.http.mediaTypes = sdkBody.contentTypes;
1034
950
  const unknownRequestBody = op.requests[0].protocol.http.mediaTypes &&
1035
951
  op.requests[0].protocol.http.mediaTypes.length > 0 &&
1036
952
  !isKnownContentType(op.requests[0].protocol.http.mediaTypes);
1037
- const sdkType = getClientType(this.sdkContext, body, httpOperation.operation);
953
+ const sdkType = sdkBody.type;
1038
954
  let schema;
1039
- if (unknownRequestBody &&
1040
- body.kind === "ModelProperty" &&
1041
- body.type.kind === "Scalar" &&
1042
- body.type.name === "bytes") {
1043
- // handle binary request body
1044
- schema = this.processBinarySchema(body.type);
955
+ if (unknownRequestBody && sdkType.kind === "bytes") {
956
+ // if it's unknown request body, handle binary request body
957
+ schema = this.processBinarySchemaFromSdkType(sdkType);
1045
958
  }
1046
959
  else {
1047
- schema = this.processSchemaFromSdkType(sdkType, body.name);
1048
- }
1049
- // Explicit body parameter @body or @bodyRoot would result to body.kind === "ModelProperty"
1050
- // Implicit body parameter would result to body.kind === "Model"
1051
- // see https://typespec.io/docs/libraries/http/cheat-sheet#data-types
1052
- const bodyParameterFlatten = sdkType.kind === "model" && body.kind === "Model" && !this.isArm();
1053
- const parameterName = body.kind === "Model" ? (sdkType.kind === "model" ? sdkType.name : "") : this.getName(body);
1054
- const parameter = new Parameter(parameterName, this.getDoc(body), schema, {
1055
- summary: this.getSummary(body),
960
+ schema = this.processSchemaFromSdkType(getNonNullSdkType(sdkType), sdkBody.name);
961
+ }
962
+ const parameterName = sdkBody.name;
963
+ const parameter = new Parameter(parameterName, (_a = sdkBody.description) !== null && _a !== void 0 ? _a : "", schema, {
964
+ summary: sdkBody.details,
1056
965
  implementation: ImplementationLocation.Method,
1057
- required: body.kind === "Model" || !body.optional,
966
+ required: !sdkBody.optional,
1058
967
  protocol: {
1059
968
  http: new HttpParameter(ParameterLocation.Body),
1060
969
  },
@@ -1065,21 +974,25 @@ export class CodeModelBuilder {
1065
974
  // model/schema does not need to be Public or Internal, if it is not to be used in convenience API
1066
975
  this.trackSchemaUsage(schema, { usage: [op.internalApi ? SchemaContext.Internal : SchemaContext.Public] });
1067
976
  }
1068
- if (operationIsJsonMergePatch(httpOperation)) {
977
+ if (operationIsJsonMergePatch(sdkHttpOperation)) {
1069
978
  this.trackSchemaUsage(schema, { usage: [SchemaContext.JsonMergePatch] });
1070
979
  }
1071
- if (op.convenienceApi && operationIsMultipart(httpOperation)) {
980
+ if (op.convenienceApi && operationIsMultipart(sdkHttpOperation)) {
1072
981
  this.trackSchemaUsage(schema, { serializationFormats: [KnownMediaType.Multipart] });
1073
982
  }
983
+ // Implicit body parameter would have usage flag: UsageFlags.Spread, for this case we need to do body parameter flatten
984
+ const bodyParameterFlatten = sdkType.kind === "model" && sdkType.usage & UsageFlags.Spread && !this.isArm();
1074
985
  if (schema instanceof ObjectSchema && bodyParameterFlatten) {
1075
986
  // flatten body parameter
987
+ const parameters = sdkHttpOperation.parameters;
988
+ const bodyParameter = sdkHttpOperation.bodyParam;
1076
989
  // name the schema for documentation
1077
990
  schema.language.default.name = pascalCase(op.language.default.name) + "Request";
1078
991
  if (!parameter.language.default.name) {
1079
992
  // name the parameter for documentation
1080
993
  parameter.language.default.name = "request";
1081
994
  }
1082
- if (operationIsJsonMergePatch(httpOperation)) {
995
+ if (operationIsJsonMergePatch(sdkHttpOperation)) {
1083
996
  // skip model flatten, if "application/merge-patch+json"
1084
997
  schema.language.default.name = pascalCase(op.language.default.name) + "PatchRequest";
1085
998
  return;
@@ -1092,56 +1005,17 @@ export class CodeModelBuilder {
1092
1005
  });
1093
1006
  request.parameters = [];
1094
1007
  op.convenienceApi.requests.push(request);
1095
- for (const [_, opParameter] of parameters.properties) {
1096
- const serializedName = this.getSerializedName(opParameter);
1097
- const paramLocation = this.getParameterLocation(opParameter);
1098
- let existParameter;
1099
- if (paramLocation === "BodyProperty") {
1100
- // property of body, it won't match existing parameter (whose paramLocation be body, path, query, header)
1101
- existParameter = undefined;
1102
- }
1103
- else {
1104
- existParameter = op.parameters.find((it) => {
1105
- var _a;
1106
- const sameParamLocation = paramLocation === ((_a = it.protocol.http) === null || _a === void 0 ? void 0 : _a.in);
1107
- const sameSerializedName = it.language.default.serializedName === serializedName;
1108
- if (paramLocation === ParameterLocation.Body) {
1109
- // body, same paramLocation, as there could only be 1 body in operation
1110
- return sameParamLocation;
1111
- }
1112
- else {
1113
- // path, query, header, require same serializedName and same paramLocation
1114
- return sameParamLocation && sameSerializedName;
1008
+ // header/query/path params
1009
+ for (const opParameter of parameters) {
1010
+ this.addParameterOrBodyPropertyToCodeModelRequest(opParameter, op, request, schema, parameter);
1011
+ }
1012
+ // body param
1013
+ if (bodyParameter) {
1014
+ if (bodyParameter.type.kind === "model") {
1015
+ for (const bodyProperty of bodyParameter.type.properties) {
1016
+ if (bodyProperty.kind === "property") {
1017
+ this.addParameterOrBodyPropertyToCodeModelRequest(bodyProperty, op, request, schema, parameter);
1115
1018
  }
1116
- });
1117
- }
1118
- if (existParameter) {
1119
- // parameter
1120
- if (existParameter.implementation === ImplementationLocation.Method &&
1121
- ((_b = (_a = existParameter.origin) === null || _a === void 0 ? void 0 : _a.startsWith("modelerfour:synthesized/")) !== null && _b !== void 0 ? _b : true) &&
1122
- !(existParameter.schema instanceof ConstantSchema)) {
1123
- request.parameters.push(cloneOperationParameter(existParameter));
1124
- }
1125
- }
1126
- else {
1127
- // property from anonymous model
1128
- const existBodyProperty = (_c = schema.properties) === null || _c === void 0 ? void 0 : _c.find((it) => it.serializedName === serializedName);
1129
- if (existBodyProperty &&
1130
- !existBodyProperty.readOnly &&
1131
- !(existBodyProperty.schema instanceof ConstantSchema)) {
1132
- request.parameters.push(new VirtualParameter(existBodyProperty.language.default.name, existBodyProperty.language.default.description, existBodyProperty.schema, {
1133
- originalParameter: parameter,
1134
- targetProperty: existBodyProperty,
1135
- language: {
1136
- default: {
1137
- serializedName: existBodyProperty.serializedName,
1138
- },
1139
- },
1140
- summary: existBodyProperty.summary,
1141
- implementation: ImplementationLocation.Method,
1142
- required: existBodyProperty.required,
1143
- nullable: existBodyProperty.nullable,
1144
- }));
1145
1019
  }
1146
1020
  }
1147
1021
  }
@@ -1149,7 +1023,7 @@ export class CodeModelBuilder {
1149
1023
  if (request.signatureParameters.length > 6) {
1150
1024
  // create an option bag
1151
1025
  const name = op.language.default.name + "Options";
1152
- const namespace = getNamespace(httpOperation.operation);
1026
+ const namespace = getNamespace(rawHttpOperation.operation);
1153
1027
  // option bag schema
1154
1028
  const optionBagSchema = this.codeModel.schemas.add(new GroupSchema(name, `Options for ${op.language.default.name} API`, {
1155
1029
  language: {
@@ -1190,110 +1064,136 @@ export class CodeModelBuilder {
1190
1064
  }
1191
1065
  }
1192
1066
  }
1067
+ addParameterOrBodyPropertyToCodeModelRequest(opParameter, op, request, schema, originalParameter) {
1068
+ var _a, _b, _c, _d, _e;
1069
+ const serializedName = opParameter.serializedName;
1070
+ let existParameter;
1071
+ if (opParameter.kind !== "property") {
1072
+ // not body property
1073
+ // header/query/path, same location and same serializedName
1074
+ existParameter = (_a = op.parameters) === null || _a === void 0 ? void 0 : _a.find((it) => { var _a; return ((_a = it.protocol.http) === null || _a === void 0 ? void 0 : _a.in) === opParameter.kind && it.language.default.serializedName === serializedName; });
1075
+ }
1076
+ request.parameters = (_b = request.parameters) !== null && _b !== void 0 ? _b : [];
1077
+ if (existParameter) {
1078
+ // parameter
1079
+ if (existParameter.implementation === ImplementationLocation.Method &&
1080
+ ((_d = (_c = existParameter.origin) === null || _c === void 0 ? void 0 : _c.startsWith("modelerfour:synthesized/")) !== null && _d !== void 0 ? _d : true) &&
1081
+ !(existParameter.schema instanceof ConstantSchema)) {
1082
+ request.parameters.push(cloneOperationParameter(existParameter));
1083
+ }
1084
+ }
1085
+ else {
1086
+ // property from anonymous model
1087
+ const existBodyProperty = (_e = schema.properties) === null || _e === void 0 ? void 0 : _e.find((it) => it.serializedName === serializedName);
1088
+ if (existBodyProperty && !existBodyProperty.readOnly && !(existBodyProperty.schema instanceof ConstantSchema)) {
1089
+ request.parameters.push(new VirtualParameter(existBodyProperty.language.default.name, existBodyProperty.language.default.description, existBodyProperty.schema, {
1090
+ originalParameter: originalParameter,
1091
+ targetProperty: existBodyProperty,
1092
+ language: {
1093
+ default: {
1094
+ serializedName: existBodyProperty.serializedName,
1095
+ },
1096
+ },
1097
+ summary: existBodyProperty.summary,
1098
+ implementation: ImplementationLocation.Method,
1099
+ required: existBodyProperty.required,
1100
+ nullable: existBodyProperty.nullable,
1101
+ }));
1102
+ }
1103
+ }
1104
+ }
1193
1105
  findResponseBody(bodyType) {
1194
1106
  // find a type that possibly without http metadata like @statusCode
1195
1107
  return this.getEffectiveSchemaType(bodyType);
1196
1108
  }
1197
- processResponse(op, resp, longRunning) {
1109
+ processResponse(op, statusCode, sdkResponse, longRunning, isErrorResponse) {
1110
+ var _a;
1198
1111
  // TODO: what to do if more than 1 response?
1199
1112
  // It happens when the response type is Union, on one status code.
1200
- let response;
1113
+ // let response: Response;
1201
1114
  let headers = undefined;
1202
- if (resp.responses && resp.responses.length > 0) {
1203
- // headers
1204
- headers = [];
1205
- for (const response of resp.responses.values()) {
1206
- if (response.headers) {
1207
- for (const [key, header] of Object.entries(response.headers)) {
1208
- const sdkType = getClientType(this.sdkContext, header);
1209
- const schema = this.processSchemaFromSdkType(sdkType, key);
1210
- headers.push(new HttpHeader(key, schema, {
1211
- language: {
1212
- default: {
1213
- name: key,
1214
- description: this.getDoc(header),
1215
- },
1216
- },
1217
- }));
1218
- }
1219
- }
1220
- }
1221
- }
1222
- let responseBody = undefined;
1223
- let bodyType = undefined;
1224
- let trackConvenienceApi = Boolean(op.convenienceApi);
1225
- if (resp.responses && resp.responses.length > 0 && resp.responses[0].body) {
1226
- responseBody = resp.responses[0].body;
1227
- }
1228
- if (responseBody) {
1229
- const unknownResponseBody = responseBody.contentTypes.length > 0 && !isKnownContentType(responseBody.contentTypes);
1230
- bodyType = this.findResponseBody(responseBody.type);
1231
- if (unknownResponseBody && bodyType.kind === "Scalar" && bodyType.name === "bytes") {
1232
- // binary
1233
- response = new BinaryResponse({
1234
- protocol: {
1235
- http: {
1236
- statusCodes: this.getStatusCodes(resp.statusCodes),
1237
- headers: headers,
1238
- mediaTypes: responseBody.contentTypes,
1239
- knownMediaType: KnownMediaType.Binary,
1240
- },
1241
- },
1115
+ // headers
1116
+ headers = [];
1117
+ if (sdkResponse.headers) {
1118
+ for (const header of sdkResponse.headers) {
1119
+ const schema = this.processSchemaFromSdkType(header.type, header.serializedName);
1120
+ headers.push(new HttpHeader(header.serializedName, schema, {
1242
1121
  language: {
1243
1122
  default: {
1244
- name: op.language.default.name + "Response",
1245
- description: this.getResponseDescription(resp),
1123
+ name: header.serializedName,
1124
+ description: (_a = header.description) !== null && _a !== void 0 ? _a : header.details,
1246
1125
  },
1247
1126
  },
1248
- });
1127
+ }));
1249
1128
  }
1250
- else {
1251
- // schema (usually JSON)
1252
- let schema = undefined;
1253
- if (longRunning) {
1254
- // LRO uses the LroMetadata for poll/final result, not the response of activation request
1255
- trackConvenienceApi = false;
1256
- }
1257
- if (!schema) {
1258
- const sdkType = getClientType(this.sdkContext, bodyType);
1259
- schema = this.processSchemaFromSdkType(sdkType, op.language.default.name + "Response");
1260
- }
1261
- response = new SchemaResponse(schema, {
1262
- protocol: {
1263
- http: {
1264
- statusCodes: this.getStatusCodes(resp.statusCodes),
1265
- headers: headers,
1266
- mediaTypes: responseBody.contentTypes,
1267
- },
1129
+ }
1130
+ const bodyType = sdkResponse.type;
1131
+ let trackConvenienceApi = Boolean(op.convenienceApi);
1132
+ const unknownResponseBody = sdkResponse.contentTypes && sdkResponse.contentTypes.length > 0 && !isKnownContentType(sdkResponse.contentTypes);
1133
+ let response;
1134
+ if (unknownResponseBody && bodyType && bodyType.kind === "bytes") {
1135
+ // binary
1136
+ response = new BinaryResponse({
1137
+ protocol: {
1138
+ http: {
1139
+ statusCodes: this.getStatusCodes(statusCode),
1140
+ headers: headers,
1141
+ mediaTypes: sdkResponse.contentTypes,
1142
+ knownMediaType: KnownMediaType.Binary,
1268
1143
  },
1269
- language: {
1270
- default: {
1271
- name: op.language.default.name + "Response",
1272
- description: this.getResponseDescription(resp),
1273
- },
1144
+ },
1145
+ language: {
1146
+ default: {
1147
+ name: op.language.default.name + "Response",
1148
+ description: sdkResponse.description,
1274
1149
  },
1275
- });
1150
+ },
1151
+ });
1152
+ }
1153
+ else if (bodyType) {
1154
+ // schema (usually JSON)
1155
+ let schema = undefined;
1156
+ if (longRunning) {
1157
+ // LRO uses the LroMetadata for poll/final result, not the response of activation request
1158
+ trackConvenienceApi = false;
1276
1159
  }
1160
+ if (!schema) {
1161
+ schema = this.processSchemaFromSdkType(bodyType, op.language.default.name + "Response");
1162
+ }
1163
+ response = new SchemaResponse(schema, {
1164
+ protocol: {
1165
+ http: {
1166
+ statusCodes: this.getStatusCodes(statusCode),
1167
+ headers: headers,
1168
+ mediaTypes: sdkResponse.contentTypes,
1169
+ },
1170
+ },
1171
+ language: {
1172
+ default: {
1173
+ name: op.language.default.name + "Response",
1174
+ description: sdkResponse.description,
1175
+ },
1176
+ },
1177
+ });
1277
1178
  }
1278
1179
  else {
1279
1180
  // not binary nor schema, usually NoContent
1280
1181
  response = new Response({
1281
1182
  protocol: {
1282
1183
  http: {
1283
- statusCodes: this.getStatusCodes(resp.statusCodes),
1184
+ statusCodes: this.getStatusCodes(statusCode),
1284
1185
  headers: headers,
1285
1186
  },
1286
1187
  },
1287
1188
  language: {
1288
1189
  default: {
1289
1190
  name: op.language.default.name + "Response",
1290
- description: this.getResponseDescription(resp),
1191
+ description: sdkResponse.description,
1291
1192
  },
1292
1193
  },
1293
1194
  });
1294
1195
  }
1295
- if (resp.statusCodes === "*" || (bodyType && isErrorModel(this.program, bodyType))) {
1296
- // "*", or the model is @error
1196
+ if (isErrorResponse) {
1297
1197
  op.addException(response);
1298
1198
  if (response instanceof SchemaResponse) {
1299
1199
  this.trackSchemaUsage(response.schema, { usage: [SchemaContext.Exception] });
@@ -1327,11 +1227,6 @@ export class CodeModelBuilder {
1327
1227
  .map((it) => it.toString());
1328
1228
  }
1329
1229
  }
1330
- getResponseDescription(resp) {
1331
- return (resp.description ||
1332
- (resp.statusCodes === "*" ? "An unexpected error response" : getStatusCodeDescription(resp.statusCodes)) ||
1333
- "");
1334
- }
1335
1230
  processSchemaFromSdkType(type, nameHint) {
1336
1231
  return this.schemaCache.process(type, nameHint) || fail("Unable to process schema.");
1337
1232
  }
@@ -1744,9 +1639,10 @@ export class CodeModelBuilder {
1744
1639
  });
1745
1640
  return this.codeModel.schemas.add(unionSchema);
1746
1641
  }
1747
- processBinarySchema(type) {
1748
- return this.codeModel.schemas.add(new BinarySchema(this.getDoc(type), {
1749
- summary: this.getSummary(type),
1642
+ processBinarySchemaFromSdkType(type) {
1643
+ var _a;
1644
+ return this.codeModel.schemas.add(new BinarySchema((_a = type.description) !== null && _a !== void 0 ? _a : "", {
1645
+ summary: type.details,
1750
1646
  }));
1751
1647
  }
1752
1648
  getUnionVariantName(type, option) {
@@ -1834,30 +1730,6 @@ export class CodeModelBuilder {
1834
1730
  getSummary(target) {
1835
1731
  return target ? getSummary(this.program, target) : undefined;
1836
1732
  }
1837
- getName(target, nameHint = undefined) {
1838
- // TODO: once getLibraryName API in typespec-client-generator-core can get projected name from language and client, as well as can handle template case, use getLibraryName API
1839
- const emitterClientName = getClientNameOverride(this.sdkContext, target);
1840
- if (emitterClientName && typeof emitterClientName === "string") {
1841
- return emitterClientName;
1842
- }
1843
- // TODO: deprecate getProjectedName
1844
- const languageProjectedName = getProjectedName(this.program, target, "java");
1845
- if (languageProjectedName) {
1846
- return languageProjectedName;
1847
- }
1848
- const clientProjectedName = getProjectedName(this.program, target, "client");
1849
- if (clientProjectedName) {
1850
- return clientProjectedName;
1851
- }
1852
- const friendlyName = getFriendlyName(this.program, target);
1853
- if (friendlyName) {
1854
- return friendlyName;
1855
- }
1856
- if (typeof target.name === "symbol") {
1857
- return "";
1858
- }
1859
- return target.name || "";
1860
- }
1861
1733
  getSerializedName(target) {
1862
1734
  if (isHeader(this.program, target)) {
1863
1735
  return getHeaderFieldName(this.program, target);
@@ -1943,10 +1815,10 @@ export class CodeModelBuilder {
1943
1815
  return undefined;
1944
1816
  }
1945
1817
  }
1946
- getConvenienceApiName(op) {
1947
- // check @convenienceMethod
1948
- if (shouldGenerateConvenient(this.sdkContext, op)) {
1949
- return this.getName(op);
1818
+ getConvenienceApiName(sdkMethod) {
1819
+ // check @convenienceAPI
1820
+ if (sdkMethod.generateConvenient) {
1821
+ return sdkMethod.name;
1950
1822
  }
1951
1823
  else {
1952
1824
  return undefined;
@@ -2028,16 +1900,11 @@ export class CodeModelBuilder {
2028
1900
  (this._apiVersionParameterInPath = this.createApiVersionParameter("apiVersion", ParameterLocation.Path)));
2029
1901
  }
2030
1902
  isSubscriptionId(param) {
2031
- var _a;
2032
- return ("subscriptionId".toLocaleLowerCase() === ((_a = param === null || param === void 0 ? void 0 : param.name) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase()) &&
2033
- param.param &&
2034
- isArmCommonType(param.param) &&
2035
- isPathParam(this.program, param.param));
1903
+ return "subscriptionId".toLocaleLowerCase() === param.serializedName.toLocaleLowerCase();
2036
1904
  }
2037
1905
  subscriptionIdParameter(parameter) {
2038
1906
  if (!this._subscriptionParameter) {
2039
- const param = parameter.param;
2040
- const description = getDoc(this.program, param);
1907
+ const description = parameter.description;
2041
1908
  this._subscriptionParameter = new Parameter("subscriptionId", description ? description : "The ID of the target subscription.", this.stringSchema, {
2042
1909
  implementation: ImplementationLocation.Client,
2043
1910
  required: true,