@azure-tools/typespec-autorest-canonical 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -0
  3. package/dist/src/autorest-canonical-openapi-schema.d.ts +3 -0
  4. package/dist/src/autorest-canonical-openapi-schema.d.ts.map +1 -0
  5. package/dist/src/autorest-canonical-openapi-schema.js +12 -0
  6. package/dist/src/autorest-canonical-openapi-schema.js.map +1 -0
  7. package/dist/src/index.d.ts +3 -0
  8. package/dist/src/index.d.ts.map +1 -0
  9. package/dist/src/index.js +3 -0
  10. package/dist/src/index.js.map +1 -0
  11. package/dist/src/json-schema-sorter/sorter.d.ts +30 -0
  12. package/dist/src/json-schema-sorter/sorter.d.ts.map +1 -0
  13. package/dist/src/json-schema-sorter/sorter.js +175 -0
  14. package/dist/src/json-schema-sorter/sorter.js.map +1 -0
  15. package/dist/src/lib.d.ts +188 -0
  16. package/dist/src/lib.d.ts.map +1 -0
  17. package/dist/src/lib.js +150 -0
  18. package/dist/src/lib.js.map +1 -0
  19. package/dist/src/openapi.d.ts +31 -0
  20. package/dist/src/openapi.d.ts.map +1 -0
  21. package/dist/src/openapi.js +1684 -0
  22. package/dist/src/openapi.js.map +1 -0
  23. package/dist/src/testing/index.d.ts +3 -0
  24. package/dist/src/testing/index.d.ts.map +1 -0
  25. package/dist/src/testing/index.js +6 -0
  26. package/dist/src/testing/index.js.map +1 -0
  27. package/dist/src/types.d.ts +475 -0
  28. package/dist/src/types.d.ts.map +1 -0
  29. package/dist/src/types.js +2 -0
  30. package/dist/src/types.js.map +1 -0
  31. package/dist/src/utils.d.ts +42 -0
  32. package/dist/src/utils.d.ts.map +1 -0
  33. package/dist/src/utils.js +79 -0
  34. package/dist/src/utils.js.map +1 -0
  35. package/lib/autorest-canonical.tsp +1 -0
  36. package/package.json +84 -0
  37. package/schema/dist/schema.js +3 -0
@@ -0,0 +1,1684 @@
1
+ import { getAsEmbeddingVector, getLroMetadata, getPagedResult, getUnionAsEnum, isFixed, } from "@azure-tools/typespec-azure-core";
2
+ import { createSdkContext, getClientNameOverride, shouldFlattenProperty, } from "@azure-tools/typespec-client-generator-core";
3
+ import { SyntaxKind, TwoLevelMap, compilerAssert, createProjectedNameProgram, emitFile, getAllTags, getDiscriminator, getDoc, getEncode, getFormat, getKnownValues, getMaxItems, getMaxLength, getMaxValue, getMinItems, getMinLength, getMinValue, getNamespaceFullName, getPattern, getProperty, getPropertyType, getService, getSummary, getVisibility, ignoreDiagnostics, interpolatePath, isArrayModelType, isDeprecated, isErrorModel, isErrorType, isGlobalNamespace, isNeverType, isNullType, isNumericType, isRecordModelType, isSecret, isService, isStringType, isTemplateDeclaration, isTemplateDeclarationOrInstance, isVoidType, listServices, navigateTypesInNamespace, resolveEncodedName, resolvePath, stringTemplateToString, } from "@typespec/compiler";
4
+ import { Visibility, createMetadataInfo, getAllHttpServices, getAuthentication, getHeaderFieldOptions, getQueryParamOptions, getServers, getStatusCodeDescription, getVisibilitySuffix, isContentTypeHeader, isSharedRoute, reportIfNoRoutes, resolveRequestVisibility, } from "@typespec/http";
5
+ import { checkDuplicateTypeName, getExtensions, getExternalDocs, getOpenAPITypeName, getParameterKey, isReadonlyProperty, resolveInfo, shouldInline, } from "@typespec/openapi";
6
+ import { getRenamedFrom, getReturnTypeChangedFrom, getTypeChangedFrom, getVersion, } from "@typespec/versioning";
7
+ import { AutorestCanonicalOpenAPISchema } from "./autorest-canonical-openapi-schema.js";
8
+ import { sortWithJsonSchema } from "./json-schema-sorter/sorter.js";
9
+ import { getTracer, reportDiagnostic } from "./lib.js";
10
+ import { resolveOperationId } from "./utils.js";
11
+ const defaultOptions = {
12
+ "output-file": "{azure-resource-provider-folder}/{service-name}/{version}/openapi.json",
13
+ "new-line": "lf",
14
+ "include-x-typespec-name": "never",
15
+ };
16
+ var UnsupportedVersioningDecorators;
17
+ (function (UnsupportedVersioningDecorators) {
18
+ UnsupportedVersioningDecorators["RenamedFrom"] = "renamedFrom";
19
+ UnsupportedVersioningDecorators["ReturnTypeChangedFrom"] = "returnTypeChangedFrom";
20
+ UnsupportedVersioningDecorators["TypeChangedFrom"] = "typeChangedFrom";
21
+ })(UnsupportedVersioningDecorators || (UnsupportedVersioningDecorators = {}));
22
+ export const namespace = "AutorestCanonical";
23
+ export const canonicalVersion = "canonical";
24
+ export async function $onEmit(context) {
25
+ const resolvedOptions = { ...defaultOptions, ...context.options };
26
+ const tcgcSdkContext = createSdkContext(context, "@azure-tools/typespec-autorest-canonical");
27
+ const armTypesDir = interpolatePath("{project-root}/../../common-types/resource-management", {
28
+ "project-root": context.program.projectRoot,
29
+ "emitter-output-dir": context.emitterOutputDir,
30
+ });
31
+ const options = {
32
+ outputFile: resolvedOptions["output-file"],
33
+ outputDir: context.emitterOutputDir,
34
+ azureResourceProviderFolder: resolvedOptions["azure-resource-provider-folder"],
35
+ newLine: resolvedOptions["new-line"],
36
+ omitUnreachableTypes: resolvedOptions["omit-unreachable-types"],
37
+ includeXTypeSpecName: resolvedOptions["include-x-typespec-name"],
38
+ armTypesDir,
39
+ };
40
+ const emitter = createOAPIEmitter(context.program, tcgcSdkContext, options);
41
+ await emitter.emitOpenAPI();
42
+ }
43
+ function getEmitterDetails(program) {
44
+ return [{ emitter: "@azure-tools/typespec-autorest-canonical" }];
45
+ }
46
+ /**
47
+ * Represents a node that will hold a JSON reference. The value is computed
48
+ * at the end so that we can defer decisions about the name that is
49
+ * referenced.
50
+ */
51
+ class Ref {
52
+ toJSON() {
53
+ compilerAssert(this.value, "Reference value never set.");
54
+ return this.value;
55
+ }
56
+ }
57
+ function createOAPIEmitter(program, tcgcSdkContext, options) {
58
+ const tracer = getTracer(program);
59
+ tracer.trace("options", JSON.stringify(options, null, 2));
60
+ const typeNameOptions = {
61
+ // shorten type names by removing TypeSpec and service namespace
62
+ namespaceFilter(ns) {
63
+ return !isService(program, ns);
64
+ },
65
+ };
66
+ let root;
67
+ let currentService;
68
+ let currentEndpoint;
69
+ let currentConsumes;
70
+ let currentProduces;
71
+ let metadataInfo;
72
+ // Keep a map of all Types+Visibility combinations that were encountered
73
+ // that need schema definitions.
74
+ let pendingSchemas = new TwoLevelMap();
75
+ // Reuse a single ref object per Type+Visibility combination.
76
+ let refs = new TwoLevelMap();
77
+ // Keep track of inline types still in the process of having their schema computed
78
+ // This is used to detect cycles in inline types, which is an
79
+ let inProgressInlineTypes = new Set();
80
+ // Map model properties that represent shared parameters to their parameter
81
+ // definition that will go in #/parameters. Inlined parameters do not go in
82
+ // this map.
83
+ let params;
84
+ // Keep track of models that have had properties spread into parameters. We won't
85
+ // consider these unreferenced when emitting unreferenced types.
86
+ let paramModels;
87
+ // De-dupe the per-endpoint tags that will be added into the #/tags
88
+ let tags;
89
+ // The set of produces/consumes values found in all operations
90
+ const globalProduces = new Set(["application/json"]);
91
+ const globalConsumes = new Set(["application/json"]);
92
+ let outputFile;
93
+ let jsonView;
94
+ let clientView;
95
+ let context;
96
+ async function emitOpenAPI() {
97
+ const services = listServices(program);
98
+ if (services.length === 0) {
99
+ services.push({ type: program.getGlobalNamespaceType() });
100
+ }
101
+ for (const service of services) {
102
+ currentService = service;
103
+ jsonView = createProjectedNameProgram(program, "json");
104
+ clientView = createProjectedNameProgram(program, "client");
105
+ context = {
106
+ program,
107
+ service,
108
+ version: canonicalVersion,
109
+ getClientName,
110
+ };
111
+ const projectedServiceNs = service.type;
112
+ await emitOpenAPIFromVersion(projectedServiceNs === program.getGlobalNamespaceType()
113
+ ? { type: program.getGlobalNamespaceType() }
114
+ : getService(program, projectedServiceNs), services.length > 1, canonicalVersion);
115
+ }
116
+ }
117
+ return { emitOpenAPI };
118
+ function initializeEmitter(service, multipleService, version) {
119
+ var _a, _b, _c, _d, _e;
120
+ const auth = processAuth(service.type);
121
+ const includedVersions = (_b = (_a = getVersion(program, service.type)) === null || _a === void 0 ? void 0 : _a.getVersions()) === null || _b === void 0 ? void 0 : _b.map((item) => item.name);
122
+ const info = resolveInfo(program, service.type);
123
+ root = {
124
+ swagger: "2.0",
125
+ info: {
126
+ title: (_c = service.title) !== null && _c !== void 0 ? _c : "(title)",
127
+ ...info,
128
+ version: (_d = version !== null && version !== void 0 ? version : info === null || info === void 0 ? void 0 : info.version) !== null && _d !== void 0 ? _d : "0000-00-00",
129
+ "x-typespec-generated": getEmitterDetails(program),
130
+ "x-canonical-included-versions": includedVersions,
131
+ },
132
+ schemes: ["https"],
133
+ ...resolveHost(program, service.type),
134
+ externalDocs: getExternalDocs(program, service.type),
135
+ produces: [], // Pre-initialize produces and consumes so that
136
+ consumes: [], // they show up at the top of the document
137
+ security: auth === null || auth === void 0 ? void 0 : auth.security,
138
+ securityDefinitions: (_e = auth === null || auth === void 0 ? void 0 : auth.securitySchemes) !== null && _e !== void 0 ? _e : {},
139
+ tags: [],
140
+ paths: {},
141
+ "x-ms-paths": {},
142
+ definitions: {},
143
+ parameters: {},
144
+ };
145
+ pendingSchemas = new TwoLevelMap();
146
+ refs = new TwoLevelMap();
147
+ metadataInfo = createMetadataInfo(program, {
148
+ canonicalVisibility: Visibility.Read,
149
+ canShareProperty: canSharePropertyUsingReadonlyOrXMSMutability,
150
+ });
151
+ inProgressInlineTypes = new Set();
152
+ params = new Map();
153
+ paramModels = new Set();
154
+ tags = new Set();
155
+ outputFile = resolveOutputFile(program, service, multipleService, options, version);
156
+ }
157
+ function resolveHost(program, namespace) {
158
+ var _a;
159
+ const servers = getServers(program, namespace);
160
+ if (servers === undefined) {
161
+ return {};
162
+ }
163
+ // If there is more than one server we then just make a custom host with a parameter asking for the full url.
164
+ if (servers.length > 1) {
165
+ return {
166
+ "x-ms-parameterized-host": {
167
+ hostTemplate: "{url}",
168
+ useSchemePrefix: false,
169
+ parameters: [
170
+ {
171
+ name: "url",
172
+ in: "path",
173
+ description: "Url",
174
+ type: "string",
175
+ format: "uri",
176
+ "x-ms-skip-url-encoding": true,
177
+ },
178
+ ],
179
+ },
180
+ };
181
+ }
182
+ const server = servers[0];
183
+ if (server.parameters.size === 0) {
184
+ const [scheme, host] = server.url.split("://");
185
+ return {
186
+ host,
187
+ schemes: [scheme],
188
+ };
189
+ }
190
+ const parameters = [];
191
+ for (const prop of server.parameters.values()) {
192
+ const param = getOpenAPI2Parameter(prop, "path", Visibility.Read);
193
+ if (prop.type.kind === "Scalar" &&
194
+ ignoreDiagnostics(program.checker.isTypeAssignableTo((_a = prop.type.projectionBase) !== null && _a !== void 0 ? _a : prop.type, program.checker.getStdType("url"), prop.type))) {
195
+ param["x-ms-skip-url-encoding"] = true;
196
+ }
197
+ parameters.push(param);
198
+ }
199
+ return {
200
+ "x-ms-parameterized-host": {
201
+ hostTemplate: server.url,
202
+ useSchemePrefix: false,
203
+ parameters,
204
+ },
205
+ };
206
+ }
207
+ async function emitOpenAPIFromVersion(service, multipleService, version) {
208
+ initializeEmitter(service, multipleService, version);
209
+ try {
210
+ const services = ignoreDiagnostics(getAllHttpServices(program));
211
+ const routes = services[0].operations;
212
+ reportIfNoRoutes(program, routes);
213
+ routes.forEach(emitOperation);
214
+ emitParameters();
215
+ emitSchemas(service.type);
216
+ emitTags();
217
+ // Finalize global produces/consumes
218
+ if (globalProduces.size > 0) {
219
+ root.produces = [...globalProduces.values()];
220
+ }
221
+ else {
222
+ delete root.produces;
223
+ }
224
+ if (globalConsumes.size > 0) {
225
+ root.consumes = [...globalConsumes.values()];
226
+ }
227
+ else {
228
+ delete root.consumes;
229
+ }
230
+ // Clean up empty entries
231
+ if (root["x-ms-paths"] && Object.keys(root["x-ms-paths"]).length === 0) {
232
+ delete root["x-ms-paths"];
233
+ }
234
+ if (root.security && Object.keys(root.security).length === 0) {
235
+ delete root["security"];
236
+ }
237
+ if (root.securityDefinitions && Object.keys(root.securityDefinitions).length === 0) {
238
+ delete root["securityDefinitions"];
239
+ }
240
+ if (!program.compilerOptions.noEmit && !program.hasError()) {
241
+ // Sort the document
242
+ const sortedRoot = sortOpenAPIDocument(root);
243
+ // Write out the OpenAPI document to the output path
244
+ await emitFile(program, {
245
+ path: outputFile,
246
+ content: prettierOutput(JSON.stringify(sortedRoot, null, 2)),
247
+ newLine: options.newLine,
248
+ });
249
+ }
250
+ }
251
+ catch (err) {
252
+ if (err instanceof ErrorTypeFoundError) {
253
+ // Return early, there must be a parse error if an ErrorType was
254
+ // inserted into the TypeSpec output
255
+ return;
256
+ }
257
+ else {
258
+ throw err;
259
+ }
260
+ }
261
+ }
262
+ function parseNextLinkName(paged) {
263
+ const pathComponents = paged.nextLinkSegments;
264
+ if (pathComponents) {
265
+ return pathComponents[pathComponents.length - 1];
266
+ }
267
+ return undefined;
268
+ }
269
+ function extractPagedMetadataNested(program, type) {
270
+ // This only works for `is Page<T>` not `extends Page<T>`.
271
+ let paged = getPagedResult(program, type);
272
+ if (paged) {
273
+ return paged;
274
+ }
275
+ if (type.baseModel) {
276
+ paged = getPagedResult(program, type.baseModel);
277
+ }
278
+ if (paged) {
279
+ return paged;
280
+ }
281
+ const templateArguments = type.templateMapper;
282
+ if (templateArguments) {
283
+ for (const argument of templateArguments.args) {
284
+ const modelArgument = argument;
285
+ if (modelArgument) {
286
+ paged = extractPagedMetadataNested(program, modelArgument);
287
+ if (paged) {
288
+ return paged;
289
+ }
290
+ }
291
+ }
292
+ }
293
+ return paged;
294
+ }
295
+ function extractPagedMetadata(program, operation) {
296
+ for (const response of operation.responses) {
297
+ const paged = extractPagedMetadataNested(program, response.type);
298
+ if (paged) {
299
+ const nextLinkName = parseNextLinkName(paged);
300
+ if (nextLinkName) {
301
+ currentEndpoint["x-ms-pageable"] = {
302
+ nextLinkName,
303
+ };
304
+ }
305
+ // Once we find paged metadata, we don't need to processes any further.
306
+ return;
307
+ }
308
+ }
309
+ }
310
+ function requiresXMsPaths(path, operation) {
311
+ var _a;
312
+ const isShared = (_a = isSharedRoute(program, operation)) !== null && _a !== void 0 ? _a : false;
313
+ if (path.includes("?")) {
314
+ return true;
315
+ }
316
+ return isShared;
317
+ }
318
+ function getPathWithoutQuery(path) {
319
+ // strip everything from the key including and after the ?
320
+ return path.replace(/\/?\?.*/, "");
321
+ }
322
+ function emitOperation(operation) {
323
+ var _a, _b;
324
+ let { path: fullPath, operation: op, verb, parameters } = operation;
325
+ let pathsObject = root.paths;
326
+ if (getReturnTypeChangedFrom(program, operation.operation)) {
327
+ reportDisallowedDecorator(UnsupportedVersioningDecorators.ReturnTypeChangedFrom, operation.operation);
328
+ }
329
+ const pathWithoutAnyQuery = getPathWithoutQuery(fullPath);
330
+ if (((_a = root.paths[pathWithoutAnyQuery]) === null || _a === void 0 ? void 0 : _a[verb]) === undefined) {
331
+ fullPath = pathWithoutAnyQuery;
332
+ pathsObject = root.paths;
333
+ }
334
+ else if (requiresXMsPaths(fullPath, op)) {
335
+ // if the key already exists in x-ms-paths, append
336
+ // the operation id.
337
+ if (fullPath.includes("?")) {
338
+ if (((_b = root["x-ms-paths"]) === null || _b === void 0 ? void 0 : _b[fullPath]) !== undefined) {
339
+ fullPath += `&_overload=${operation.operation.name}`;
340
+ }
341
+ }
342
+ else {
343
+ fullPath += `?_overload=${operation.operation.name}`;
344
+ }
345
+ pathsObject = root["x-ms-paths"];
346
+ }
347
+ else {
348
+ // This should not happen because http library should have already validated duplicate path or the routes must have been using shared routes and so goes in previous condition.
349
+ compilerAssert(false, `Duplicate route "${fullPath}". This is unexpected.`);
350
+ }
351
+ if (!pathsObject[fullPath]) {
352
+ pathsObject[fullPath] = {};
353
+ }
354
+ const currentPath = pathsObject[fullPath];
355
+ if (!currentPath[verb]) {
356
+ currentPath[verb] = {};
357
+ }
358
+ currentEndpoint = currentPath[verb];
359
+ currentConsumes = new Set();
360
+ currentProduces = new Set();
361
+ const currentTags = getAllTags(program, op);
362
+ if (currentTags) {
363
+ currentEndpoint.tags = currentTags;
364
+ for (const tag of currentTags) {
365
+ // Add to root tags if not already there
366
+ tags.add(tag);
367
+ }
368
+ }
369
+ currentEndpoint.operationId = resolveOperationId(context, op);
370
+ applyExternalDocs(op, currentEndpoint);
371
+ // Set up basic endpoint fields
372
+ currentEndpoint.summary = getSummary(program, op);
373
+ currentEndpoint.description = getDoc(program, op);
374
+ currentEndpoint.parameters = [];
375
+ currentEndpoint.responses = {};
376
+ const lroMetadata = getLroMetadata(program, op);
377
+ // We ignore GET operations because they cannot be LROs per our guidelines and this
378
+ // ensures we don't add the x-ms-long-running-operation extension to the polling operation,
379
+ // which does have LRO metadata.
380
+ if (lroMetadata !== undefined && operation.verb !== "get") {
381
+ currentEndpoint["x-ms-long-running-operation"] = true;
382
+ }
383
+ // Extract paged metadata from Azure.Core.Page
384
+ extractPagedMetadata(program, operation);
385
+ const visibility = resolveRequestVisibility(program, operation.operation, verb);
386
+ emitEndpointParameters(parameters, visibility);
387
+ emitResponses(operation.responses);
388
+ applyEndpointConsumes();
389
+ applyEndpointProduces();
390
+ if (isDeprecated(program, op)) {
391
+ currentEndpoint.deprecated = true;
392
+ }
393
+ // Attach additional extensions after main fields
394
+ attachExtensions(op, currentEndpoint);
395
+ }
396
+ function applyEndpointProduces() {
397
+ if (currentProduces.size > 0 && !checkLocalAndGlobalEqual(globalProduces, currentProduces)) {
398
+ currentEndpoint.produces = [...currentProduces];
399
+ }
400
+ }
401
+ function applyEndpointConsumes() {
402
+ if (currentConsumes.size > 0 && !checkLocalAndGlobalEqual(globalConsumes, currentConsumes)) {
403
+ currentEndpoint.consumes = [...currentConsumes];
404
+ }
405
+ }
406
+ function checkLocalAndGlobalEqual(global, local) {
407
+ if (global.size !== local.size) {
408
+ return false;
409
+ }
410
+ for (const entry of local) {
411
+ if (!global.has(entry)) {
412
+ return false;
413
+ }
414
+ }
415
+ return true;
416
+ }
417
+ function isBytes(type) {
418
+ var _a;
419
+ const baseType = (_a = type.projectionBase) !== null && _a !== void 0 ? _a : type;
420
+ return ignoreDiagnostics(program.checker.isTypeAssignableTo(baseType, program.checker.getStdType("bytes"), type));
421
+ }
422
+ function isBinaryPayload(body, contentType) {
423
+ const types = new Set(typeof contentType === "string" ? [contentType] : contentType);
424
+ return (body.kind === "Scalar" &&
425
+ body.name === "bytes" &&
426
+ !types.has("application/json") &&
427
+ !types.has("text/plain"));
428
+ }
429
+ function emitResponses(responses) {
430
+ for (const response of responses) {
431
+ for (const statusCode of getOpenAPI2StatusCodes(response.statusCodes, response.type)) {
432
+ emitResponseObject(statusCode, response);
433
+ }
434
+ }
435
+ }
436
+ function getOpenAPI2StatusCodes(statusCodes, diagnosticTarget) {
437
+ if (statusCodes === "*") {
438
+ return ["default"];
439
+ }
440
+ else if (typeof statusCodes === "number") {
441
+ return [String(statusCodes)];
442
+ }
443
+ else {
444
+ return rangeToOpenAPI(statusCodes, diagnosticTarget);
445
+ }
446
+ }
447
+ function rangeToOpenAPI(range, diagnosticTarget) {
448
+ const reportInvalid = () => reportDiagnostic(program, {
449
+ code: "unsupported-status-code-range",
450
+ format: { start: String(range.start), end: String(range.end) },
451
+ target: diagnosticTarget,
452
+ });
453
+ const codes = [];
454
+ let start = range.start;
455
+ let end = range.end;
456
+ if (range.start < 100) {
457
+ reportInvalid();
458
+ start = 100;
459
+ codes.push("default");
460
+ }
461
+ else if (range.end > 599) {
462
+ reportInvalid();
463
+ codes.push("default");
464
+ end = 599;
465
+ }
466
+ const groups = [1, 2, 3, 4, 5];
467
+ for (const group of groups) {
468
+ if (start > end) {
469
+ break;
470
+ }
471
+ const groupStart = group * 100;
472
+ const groupEnd = groupStart + 99;
473
+ if (start >= groupStart && start <= groupEnd) {
474
+ codes.push(`${group}XX`);
475
+ if (start !== groupStart || end < groupEnd) {
476
+ reportInvalid();
477
+ }
478
+ start = groupStart + 100;
479
+ }
480
+ }
481
+ return codes;
482
+ }
483
+ function getResponseDescriptionForStatusCode(statusCode) {
484
+ var _a;
485
+ if (statusCode === "default") {
486
+ return "An unexpected error response.";
487
+ }
488
+ return (_a = getStatusCodeDescription(statusCode)) !== null && _a !== void 0 ? _a : "unknown";
489
+ }
490
+ function emitResponseObject(statusCode, response) {
491
+ var _a, _b, _c;
492
+ const openapiResponse = (_a = currentEndpoint.responses[statusCode]) !== null && _a !== void 0 ? _a : {
493
+ description: (_b = response.description) !== null && _b !== void 0 ? _b : getResponseDescriptionForStatusCode(statusCode),
494
+ };
495
+ if (isErrorModel(program, response.type) && statusCode !== "default") {
496
+ openapiResponse["x-ms-error-response"] = true;
497
+ }
498
+ const contentTypes = [];
499
+ let body;
500
+ for (const data of response.responses) {
501
+ if (data.headers && Object.keys(data.headers).length > 0) {
502
+ (_c = openapiResponse.headers) !== null && _c !== void 0 ? _c : (openapiResponse.headers = {});
503
+ for (const [key, value] of Object.entries(data.headers)) {
504
+ openapiResponse.headers[key] = getResponseHeader(value);
505
+ }
506
+ }
507
+ if (data.body) {
508
+ if (body && body !== data.body.type) {
509
+ reportDiagnostic(program, {
510
+ code: "duplicate-body-types",
511
+ target: response.type,
512
+ });
513
+ }
514
+ body = data.body.type;
515
+ contentTypes.push(...data.body.contentTypes);
516
+ }
517
+ }
518
+ if (body) {
519
+ const isBinary = contentTypes.every((t) => isBinaryPayload(body, t));
520
+ openapiResponse.schema = isBinary ? { type: "file" } : getSchemaOrRef(body, Visibility.Read);
521
+ }
522
+ for (const contentType of contentTypes) {
523
+ currentProduces.add(contentType);
524
+ }
525
+ currentEndpoint.responses[statusCode] = openapiResponse;
526
+ }
527
+ function getResponseHeader(prop) {
528
+ const header = {};
529
+ populateParameter(header, prop, "header", Visibility.Read);
530
+ delete header.in;
531
+ delete header.name;
532
+ delete header.required;
533
+ return header;
534
+ }
535
+ function getSchemaOrRef(type, visibility) {
536
+ var _a;
537
+ if (type.kind === "Scalar" && program.checker.isStdType(type)) {
538
+ return getSchemaForScalar(type);
539
+ }
540
+ if (type.kind === "String" || type.kind === "Number" || type.kind === "Boolean") {
541
+ // For literal types, we just want to emit them directly as well.
542
+ return getSchemaForLiterals(type);
543
+ }
544
+ if (type.kind === "StringTemplate") {
545
+ return getSchemaForStringTemplate(type);
546
+ }
547
+ if (type.kind === "Intrinsic" && type.name === "unknown") {
548
+ return getSchemaForIntrinsicType(type);
549
+ }
550
+ if (type.kind === "EnumMember") {
551
+ // Enum members are just the OA representation of their values.
552
+ if (typeof type.value === "number") {
553
+ return { type: "number", enum: [type.value] };
554
+ }
555
+ else {
556
+ return { type: "string", enum: [(_a = type.value) !== null && _a !== void 0 ? _a : type.name] };
557
+ }
558
+ }
559
+ if (type.kind === "ModelProperty") {
560
+ return resolveProperty(type, visibility);
561
+ }
562
+ type = metadataInfo.getEffectivePayloadType(type, visibility);
563
+ const name = getOpenAPITypeName(program, type, typeNameOptions);
564
+ if (shouldInline(program, type)) {
565
+ const schema = getSchemaForInlineType(type, name, visibility);
566
+ if (schema === undefined && isErrorType(type)) {
567
+ // Exit early so that syntax errors are exposed. This error will
568
+ // be caught and handled in emitOpenAPI.
569
+ throw new ErrorTypeFoundError();
570
+ }
571
+ // helps to read output and correlate to TypeSpec
572
+ if (schema && options.includeXTypeSpecName !== "never") {
573
+ schema["x-typespec-name"] = name;
574
+ }
575
+ return schema;
576
+ }
577
+ else {
578
+ // Use shared schema when type is not transformed by visibility from the canonical read visibility.
579
+ if (!metadataInfo.isTransformed(type, visibility)) {
580
+ visibility = Visibility.Read;
581
+ }
582
+ const pending = pendingSchemas.getOrAdd(type, visibility, () => ({
583
+ type,
584
+ visibility,
585
+ ref: refs.getOrAdd(type, visibility, () => new Ref()),
586
+ }));
587
+ return { $ref: pending.ref };
588
+ }
589
+ }
590
+ function getSchemaForInlineType(type, name, visibility) {
591
+ if (inProgressInlineTypes.has(type)) {
592
+ reportDiagnostic(program, {
593
+ code: "inline-cycle",
594
+ format: { type: name },
595
+ target: type,
596
+ });
597
+ return {};
598
+ }
599
+ inProgressInlineTypes.add(type);
600
+ const schema = getSchemaForType(type, visibility);
601
+ inProgressInlineTypes.delete(type);
602
+ return schema;
603
+ }
604
+ function getParamPlaceholder(property) {
605
+ let spreadParam = false;
606
+ if (property.sourceProperty) {
607
+ // chase our sources all the way back to the first place this property
608
+ // was defined.
609
+ spreadParam = true;
610
+ property = property.sourceProperty;
611
+ while (property.sourceProperty) {
612
+ property = property.sourceProperty;
613
+ }
614
+ }
615
+ const parameter = params.get(property);
616
+ if (parameter) {
617
+ return parameter;
618
+ }
619
+ const placeholder = {};
620
+ // only parameters inherited by spreading from non-inlined type are shared in #/parameters
621
+ if (spreadParam && property.model && !shouldInline(program, property.model)) {
622
+ params.set(property, placeholder);
623
+ paramModels.add(property.model);
624
+ }
625
+ return placeholder;
626
+ }
627
+ function getJsonName(type) {
628
+ const viaProjection = jsonView.getProjectedName(type);
629
+ const encodedName = resolveEncodedName(program, type, "application/json");
630
+ // Pick the value set via `encodedName` or default back to the legacy projection otherwise.
631
+ // `resolveEncodedName` will return the original name if no @encodedName so we have to do that check
632
+ return encodedName === type.name ? viaProjection : encodedName;
633
+ }
634
+ function getClientName(type) {
635
+ const viaProjection = clientView.getProjectedName(type);
636
+ const clientName = getClientNameOverride(tcgcSdkContext, type);
637
+ return clientName !== null && clientName !== void 0 ? clientName : viaProjection;
638
+ }
639
+ function emitEndpointParameters(methodParams, visibility) {
640
+ var _a, _b;
641
+ const consumes = (_b = (_a = methodParams.body) === null || _a === void 0 ? void 0 : _a.contentTypes) !== null && _b !== void 0 ? _b : [];
642
+ for (const httpOpParam of methodParams.parameters) {
643
+ const shared = params.get(httpOpParam.param);
644
+ if (shared) {
645
+ currentEndpoint.parameters.push(shared);
646
+ continue;
647
+ }
648
+ if (httpOpParam.type === "header" && isContentTypeHeader(program, httpOpParam.param)) {
649
+ continue;
650
+ }
651
+ emitParameter(httpOpParam.param, httpOpParam.type, visibility, httpOpParam.name);
652
+ }
653
+ if (consumes.length === 0 && methodParams.body) {
654
+ // we didn't find an explicit content type anywhere, so infer from body.
655
+ if (getModelOrScalarTypeIfNullable(methodParams.body.type)) {
656
+ consumes.push("application/json");
657
+ }
658
+ }
659
+ for (const consume of consumes) {
660
+ currentConsumes.add(consume);
661
+ }
662
+ if (methodParams.body && !isVoidType(methodParams.body.type)) {
663
+ const isBinary = isBinaryPayload(methodParams.body.type, consumes);
664
+ const schema = isBinary
665
+ ? { type: "string", format: "binary" }
666
+ : getSchemaOrRef(methodParams.body.type, visibility);
667
+ if (currentConsumes.has("multipart/form-data")) {
668
+ const bodyModelType = methodParams.body.type;
669
+ // Assert, this should never happen. Rest library guard against that.
670
+ compilerAssert(bodyModelType.kind === "Model", "Body should always be a Model.");
671
+ if (bodyModelType) {
672
+ for (const param of bodyModelType.properties.values()) {
673
+ emitParameter(param, "formData", visibility, getJsonName(param));
674
+ }
675
+ }
676
+ }
677
+ else if (methodParams.body.parameter) {
678
+ emitParameter(methodParams.body.parameter, "body", visibility, getJsonName(methodParams.body.parameter), schema);
679
+ }
680
+ else {
681
+ currentEndpoint.parameters.push({
682
+ name: "body",
683
+ in: "body",
684
+ schema,
685
+ required: true,
686
+ });
687
+ }
688
+ }
689
+ }
690
+ function getModelOrScalarTypeIfNullable(type) {
691
+ if (type.kind === "Model" || type.kind === "Scalar") {
692
+ return type;
693
+ }
694
+ else if (type.kind === "Union") {
695
+ // Remove all `null` types and make sure there's a single model type
696
+ const nonNulls = [...type.variants.values()]
697
+ .map((x) => x.type)
698
+ .filter((variant) => !isNullType(variant));
699
+ if (nonNulls.every((t) => t.kind === "Model" || t.kind === "Scalar")) {
700
+ return nonNulls.length === 1 ? nonNulls[0] : undefined;
701
+ }
702
+ }
703
+ return undefined;
704
+ }
705
+ function emitParameter(param, kind, visibility, name, typeOverride) {
706
+ if (isNeverType(param.type)) {
707
+ return;
708
+ }
709
+ const ph = getParamPlaceholder(param);
710
+ currentEndpoint.parameters.push(ph);
711
+ // If the parameter already has a $ref, don't bother populating it
712
+ if (!("$ref" in ph)) {
713
+ populateParameter(ph, param, kind, visibility, name, typeOverride);
714
+ }
715
+ }
716
+ function getSchemaForPrimitiveItems(type, visibility, paramName, multipart) {
717
+ const fullSchema = getSchemaForType(type, visibility);
718
+ if (fullSchema === undefined) {
719
+ return undefined;
720
+ }
721
+ if (fullSchema.type === "object") {
722
+ reportDiagnostic(program, {
723
+ code: multipart ? "unsupported-multipart-type" : "unsupported-param-type",
724
+ format: { part: paramName },
725
+ target: type,
726
+ });
727
+ return { type: "string" };
728
+ }
729
+ return fullSchema;
730
+ }
731
+ function getFormDataSchema(type, visibility, paramName) {
732
+ if (isBytes(type)) {
733
+ return { type: "file" };
734
+ }
735
+ if (type.kind === "Model" && isArrayModelType(program, type)) {
736
+ const schema = getSchemaForPrimitiveItems(type.indexer.value, visibility, paramName, true);
737
+ if (schema === undefined) {
738
+ return undefined;
739
+ }
740
+ delete schema.description;
741
+ return {
742
+ type: "array",
743
+ items: schema,
744
+ };
745
+ }
746
+ else {
747
+ const schema = getSchemaForPrimitiveItems(type, visibility, paramName, true);
748
+ if (schema === undefined) {
749
+ return undefined;
750
+ }
751
+ return schema;
752
+ }
753
+ }
754
+ function getOpenAPI2Parameter(param, kind, visibility, name, bodySchema) {
755
+ var _a;
756
+ const ph = {
757
+ name: name !== null && name !== void 0 ? name : param.name,
758
+ in: kind,
759
+ required: !param.optional,
760
+ description: getDoc(program, param),
761
+ };
762
+ if (param.name !== ph.name) {
763
+ ph["x-ms-client-name"] = param.name;
764
+ }
765
+ if (param.default) {
766
+ ph.default = getDefaultValue(param.default);
767
+ }
768
+ if (ph.in === "body") {
769
+ compilerAssert(bodySchema, "bodySchema argument is required to populate body parameter");
770
+ ph.schema = bodySchema;
771
+ }
772
+ else if (ph.in === "formData") {
773
+ Object.assign(ph, getFormDataSchema(param.type, visibility, ph.name));
774
+ }
775
+ else {
776
+ const collectionFormat = (_a = (kind === "query"
777
+ ? getQueryParamOptions(program, param)
778
+ : kind === "header"
779
+ ? getHeaderFieldOptions(program, param)
780
+ : undefined)) === null || _a === void 0 ? void 0 : _a.format;
781
+ if (collectionFormat === "multi" && !["query", "header", "formData"].includes(ph.in)) {
782
+ reportDiagnostic(program, { code: "invalid-multi-collection-format", target: param });
783
+ }
784
+ if (collectionFormat) {
785
+ ph.collectionFormat = collectionFormat;
786
+ }
787
+ if (param.type.kind === "Model" && isArrayModelType(program, param.type)) {
788
+ ph.type = "array";
789
+ const schema = {
790
+ ...getSchemaForPrimitiveItems(param.type.indexer.value, visibility, ph.name),
791
+ };
792
+ delete schema.description;
793
+ ph.items = schema;
794
+ }
795
+ else {
796
+ Object.assign(ph, getSchemaForPrimitiveItems(param.type, visibility, ph.name));
797
+ }
798
+ }
799
+ attachExtensions(param, ph);
800
+ // Apply decorators to a copy of the parameter definition. We use
801
+ // Object.assign here because applyIntrinsicDecorators returns a new object
802
+ // based on the target object and we need to apply its changes back to the
803
+ // original parameter.
804
+ Object.assign(ph, applyIntrinsicDecorators(param, { type: ph.type, format: ph.format }));
805
+ return ph;
806
+ }
807
+ function populateParameter(ph, param, kind, visibility, name, bodySchema) {
808
+ Object.assign(ph, getOpenAPI2Parameter(param, kind, visibility, name, bodySchema));
809
+ }
810
+ function emitParameters() {
811
+ for (const [property, param] of params) {
812
+ // Add an extension which tells AutorestCanonical that this is a shared operation
813
+ // parameter definition
814
+ if (param["x-ms-parameter-location"] === undefined) {
815
+ param["x-ms-parameter-location"] = "method";
816
+ }
817
+ const key = getParameterKey(program, property, param, root.parameters, typeNameOptions);
818
+ root.parameters[key] = { ...param };
819
+ const refedParam = param;
820
+ for (const key of Object.keys(param)) {
821
+ delete refedParam[key];
822
+ }
823
+ refedParam["$ref"] = "#/parameters/" + encodeURIComponent(key);
824
+ }
825
+ }
826
+ function emitSchemas(serviceNamespace) {
827
+ const processedSchemas = new TwoLevelMap();
828
+ processSchemas();
829
+ if (!options.omitUnreachableTypes) {
830
+ processUnreferencedSchemas();
831
+ }
832
+ // Emit the processed schemas. Only now can we compute the names as it
833
+ // depends on whether we have produced multiple schemas for a single
834
+ // TYPESPEC type.
835
+ for (const group of processedSchemas.values()) {
836
+ for (const [visibility, processed] of group) {
837
+ let name = getOpenAPITypeName(program, processed.type, typeNameOptions);
838
+ if (group.size > 1) {
839
+ name += getVisibilitySuffix(visibility, Visibility.Read);
840
+ }
841
+ checkDuplicateTypeName(program, processed.type, name, root.definitions);
842
+ processed.ref.value = "#/definitions/" + encodeURIComponent(name);
843
+ if (processed.schema) {
844
+ root.definitions[name] = processed.schema;
845
+ }
846
+ }
847
+ }
848
+ function processSchemas() {
849
+ // Process pending schemas. Note that getSchemaForType may pull in new
850
+ // pending schemas so we iterate until there are no pending schemas
851
+ // remaining.
852
+ while (pendingSchemas.size > 0) {
853
+ for (const [type, group] of pendingSchemas) {
854
+ for (const [visibility, pending] of group) {
855
+ processedSchemas.getOrAdd(type, visibility, () => ({
856
+ ...pending,
857
+ schema: getSchemaForType(type, visibility),
858
+ }));
859
+ }
860
+ pendingSchemas.delete(type);
861
+ }
862
+ }
863
+ }
864
+ function processUnreferencedSchemas() {
865
+ const addSchema = (type) => {
866
+ if (!processedSchemas.has(type) && !paramModels.has(type) && !shouldInline(program, type)) {
867
+ getSchemaOrRef(type, Visibility.Read);
868
+ }
869
+ };
870
+ const skipSubNamespaces = isGlobalNamespace(program, serviceNamespace);
871
+ navigateTypesInNamespace(serviceNamespace, {
872
+ model: addSchema,
873
+ scalar: addSchema,
874
+ enum: addSchema,
875
+ union: addSchema,
876
+ }, { skipSubNamespaces });
877
+ processSchemas();
878
+ }
879
+ }
880
+ function emitTags() {
881
+ for (const tag of tags) {
882
+ root.tags.push({ name: tag });
883
+ }
884
+ }
885
+ function getSchemaForType(type, visibility) {
886
+ const builtinType = getSchemaForLiterals(type);
887
+ if (builtinType !== undefined) {
888
+ return builtinType;
889
+ }
890
+ switch (type.kind) {
891
+ case "Intrinsic":
892
+ return getSchemaForIntrinsicType(type);
893
+ case "Model":
894
+ return getSchemaForModel(type, visibility);
895
+ case "ModelProperty":
896
+ return getSchemaForType(type.type, visibility);
897
+ case "Scalar":
898
+ return getSchemaForScalar(type);
899
+ case "Union":
900
+ return getSchemaForUnion(type, visibility);
901
+ case "UnionVariant":
902
+ return getSchemaForUnionVariant(type, visibility);
903
+ case "Enum":
904
+ return getSchemaForEnum(type);
905
+ case "Tuple":
906
+ return { type: "array", items: {} };
907
+ }
908
+ reportDiagnostic(program, {
909
+ code: "invalid-schema",
910
+ format: { type: type.kind },
911
+ target: type,
912
+ });
913
+ return undefined;
914
+ }
915
+ function getSchemaForIntrinsicType(type) {
916
+ switch (type.name) {
917
+ case "unknown":
918
+ return {};
919
+ }
920
+ reportDiagnostic(program, {
921
+ code: "invalid-schema",
922
+ format: { type: type.name },
923
+ target: type,
924
+ });
925
+ return {};
926
+ }
927
+ function getSchemaForEnum(e) {
928
+ var _a;
929
+ const values = [];
930
+ if (e.members.size === 0) {
931
+ reportUnsupportedUnion("empty");
932
+ return {};
933
+ }
934
+ const type = getEnumMemberType(e.members.values().next().value);
935
+ for (const option of e.members.values()) {
936
+ if (type !== getEnumMemberType(option)) {
937
+ reportUnsupportedUnion();
938
+ continue;
939
+ }
940
+ else {
941
+ values.push((_a = option.value) !== null && _a !== void 0 ? _a : option.name);
942
+ }
943
+ }
944
+ const schema = { type, description: getDoc(program, e) };
945
+ if (values.length > 0) {
946
+ schema.enum = values;
947
+ addXMSEnum(e, schema);
948
+ }
949
+ return schema;
950
+ function getEnumMemberType(member) {
951
+ if (typeof member.value === "number") {
952
+ return "number";
953
+ }
954
+ return "string";
955
+ }
956
+ function reportUnsupportedUnion(messageId = "default") {
957
+ reportDiagnostic(program, { code: "union-unsupported", messageId, target: e });
958
+ }
959
+ }
960
+ function getSchemaForUnionEnum(union, e) {
961
+ const values = [];
962
+ let foundCustom = false;
963
+ for (const [name, member] of e.flattenedMembers.entries()) {
964
+ const description = getDoc(program, member.type);
965
+ values.push({
966
+ name: typeof name === "string" ? name : `${member.value}`,
967
+ value: member.value,
968
+ description,
969
+ });
970
+ if (description || typeof name === "string") {
971
+ foundCustom = true;
972
+ }
973
+ }
974
+ const schema = {
975
+ type: e.kind,
976
+ enum: [...e.flattenedMembers.values()].map((x) => x.value),
977
+ "x-ms-enum": {
978
+ name: union.name,
979
+ modelAsString: e.open,
980
+ },
981
+ };
982
+ if (foundCustom) {
983
+ schema["x-ms-enum"].values = values;
984
+ }
985
+ if (e.nullable) {
986
+ schema["x-nullable"] = true;
987
+ }
988
+ return applyIntrinsicDecorators(union, schema);
989
+ }
990
+ function getSchemaForUnion(union, visibility) {
991
+ const nonNullOptions = [...union.variants.values()]
992
+ .map((x) => x.type)
993
+ .filter((t) => !isNullType(t));
994
+ const nullable = union.variants.size !== nonNullOptions.length;
995
+ if (nonNullOptions.length === 0) {
996
+ reportDiagnostic(program, { code: "union-null", target: union });
997
+ return {};
998
+ }
999
+ if (nonNullOptions.length === 1) {
1000
+ const type = nonNullOptions[0];
1001
+ // Get the schema for the model type
1002
+ const schema = getSchemaOrRef(type, visibility);
1003
+ if (schema.$ref) {
1004
+ if (type.kind === "Model") {
1005
+ return { type: "object", allOf: [schema], "x-nullable": nullable };
1006
+ }
1007
+ else {
1008
+ return { ...schema, "x-nullable": nullable };
1009
+ }
1010
+ }
1011
+ else {
1012
+ schema["x-nullable"] = nullable;
1013
+ return schema;
1014
+ }
1015
+ }
1016
+ else {
1017
+ const [asEnum, _] = getUnionAsEnum(union);
1018
+ if (asEnum) {
1019
+ return getSchemaForUnionEnum(union, asEnum);
1020
+ }
1021
+ reportDiagnostic(program, {
1022
+ code: "union-unsupported",
1023
+ target: union,
1024
+ });
1025
+ return {};
1026
+ }
1027
+ }
1028
+ function ifArrayItemContainsIdentifier(program, array) {
1029
+ var _a;
1030
+ if (((_a = array.indexer.value) === null || _a === void 0 ? void 0 : _a.kind) !== "Model") {
1031
+ return true;
1032
+ }
1033
+ return (getExtensions(program, array).has("x-ms-identifiers") ||
1034
+ getProperty(array.indexer.value, "id"));
1035
+ }
1036
+ function getSchemaForUnionVariant(variant, visibility) {
1037
+ return getSchemaForType(variant.type, visibility);
1038
+ }
1039
+ function getDefaultValue(type) {
1040
+ var _a;
1041
+ switch (type.kind) {
1042
+ case "String":
1043
+ return type.value;
1044
+ case "Number":
1045
+ return type.value;
1046
+ case "Boolean":
1047
+ return type.value;
1048
+ case "Tuple":
1049
+ return type.values.map(getDefaultValue);
1050
+ case "EnumMember":
1051
+ return (_a = type.value) !== null && _a !== void 0 ? _a : type.name;
1052
+ case "Intrinsic":
1053
+ return isNullType(type)
1054
+ ? null
1055
+ : reportDiagnostic(program, {
1056
+ code: "invalid-default",
1057
+ format: { type: type.kind },
1058
+ target: type,
1059
+ });
1060
+ case "UnionVariant":
1061
+ return getDefaultValue(type.type);
1062
+ default:
1063
+ reportDiagnostic(program, {
1064
+ code: "invalid-default",
1065
+ format: { type: type.kind },
1066
+ target: type,
1067
+ });
1068
+ }
1069
+ }
1070
+ function includeDerivedModel(model) {
1071
+ var _a, _b;
1072
+ return (!isTemplateDeclaration(model) &&
1073
+ (((_a = model.templateMapper) === null || _a === void 0 ? void 0 : _a.args) === undefined ||
1074
+ ((_b = model.templateMapper) === null || _b === void 0 ? void 0 : _b.args.length) === 0 ||
1075
+ model.derivedModels.length > 0));
1076
+ }
1077
+ function reportDisallowedDecorator(decorator, type) {
1078
+ reportDiagnostic(program, {
1079
+ code: "unsupported-versioning-decorator",
1080
+ format: { decorator },
1081
+ target: type,
1082
+ });
1083
+ }
1084
+ function getSchemaForModel(model, visibility) {
1085
+ const array = getArrayType(model, visibility);
1086
+ if (array) {
1087
+ return array;
1088
+ }
1089
+ const modelSchema = {
1090
+ type: "object",
1091
+ description: getDoc(program, model),
1092
+ };
1093
+ if (model.baseModel) {
1094
+ const discriminator = getDiscriminator(program, model.baseModel);
1095
+ if (discriminator) {
1096
+ const prop = getProperty(model, discriminator.propertyName);
1097
+ if (prop) {
1098
+ const values = getStringValues(prop.type);
1099
+ if (values.length === 1) {
1100
+ const extensions = getExtensions(program, model);
1101
+ if (!extensions.has("x-ms-discriminator-value")) {
1102
+ modelSchema["x-ms-discriminator-value"] = values[0];
1103
+ }
1104
+ }
1105
+ }
1106
+ }
1107
+ }
1108
+ const properties = {};
1109
+ if (isRecordModelType(program, model)) {
1110
+ modelSchema.additionalProperties = getSchemaOrRef(model.indexer.value, visibility);
1111
+ }
1112
+ const derivedModels = model.derivedModels.filter(includeDerivedModel);
1113
+ // getSchemaOrRef on all children to push them into components.schemas
1114
+ for (const child of derivedModels) {
1115
+ getSchemaOrRef(child, visibility);
1116
+ }
1117
+ const discriminator = getDiscriminator(program, model);
1118
+ if (discriminator) {
1119
+ const { propertyName } = discriminator;
1120
+ modelSchema.discriminator = propertyName;
1121
+ // Push discriminator into base type, but only if it is not already there
1122
+ if (!model.properties.get(propertyName)) {
1123
+ properties[propertyName] = {
1124
+ type: "string",
1125
+ description: `Discriminator property for ${model.name}.`,
1126
+ };
1127
+ modelSchema.required = [propertyName];
1128
+ }
1129
+ }
1130
+ applyExternalDocs(model, modelSchema);
1131
+ for (const prop of model.properties.values()) {
1132
+ if (getRenamedFrom(program, prop)) {
1133
+ reportDisallowedDecorator(UnsupportedVersioningDecorators.RenamedFrom, prop.type);
1134
+ }
1135
+ if (getTypeChangedFrom(program, prop)) {
1136
+ reportDisallowedDecorator(UnsupportedVersioningDecorators.TypeChangedFrom, prop.type);
1137
+ }
1138
+ if (!metadataInfo.isPayloadProperty(prop, visibility)) {
1139
+ continue;
1140
+ }
1141
+ if (isNeverType(prop.type)) {
1142
+ // If the property has a type of 'never', don't include it in the schema
1143
+ continue;
1144
+ }
1145
+ const jsonName = jsonView.getProjectedName(prop);
1146
+ const clientName = clientView.getProjectedName(prop);
1147
+ const description = getDoc(program, prop);
1148
+ // if this property is a discriminator property, remove it to keep autorestcanonical validation happy
1149
+ if (model.baseModel) {
1150
+ const { propertyName } = getDiscriminator(program, model.baseModel) || {};
1151
+ if (jsonName === propertyName) {
1152
+ continue;
1153
+ }
1154
+ }
1155
+ if (!metadataInfo.isOptional(prop, visibility) || prop.name === (discriminator === null || discriminator === void 0 ? void 0 : discriminator.propertyName)) {
1156
+ if (!modelSchema.required) {
1157
+ modelSchema.required = [];
1158
+ }
1159
+ modelSchema.required.push(jsonName);
1160
+ }
1161
+ // Apply decorators on the property to the type's schema
1162
+ properties[jsonName] = resolveProperty(prop, visibility);
1163
+ const property = properties[jsonName];
1164
+ if (jsonName !== clientName) {
1165
+ property["x-ms-client-name"] = clientName;
1166
+ }
1167
+ if (description) {
1168
+ property.description = description;
1169
+ }
1170
+ if (prop.default) {
1171
+ property.default = getDefaultValue(prop.default);
1172
+ }
1173
+ if (isReadonlyProperty(program, prop)) {
1174
+ property.readOnly = true;
1175
+ }
1176
+ else {
1177
+ const vis = getVisibility(program, prop);
1178
+ if (vis) {
1179
+ const mutability = [];
1180
+ if (vis.includes("read")) {
1181
+ mutability.push("read");
1182
+ }
1183
+ if (vis.includes("update")) {
1184
+ mutability.push("update");
1185
+ }
1186
+ if (vis.includes("create")) {
1187
+ mutability.push("create");
1188
+ }
1189
+ if (mutability.length > 0) {
1190
+ property["x-ms-mutability"] = mutability;
1191
+ }
1192
+ }
1193
+ }
1194
+ // Attach any additional OpenAPI extensions
1195
+ attachExtensions(prop, property);
1196
+ }
1197
+ // Special case: if a model type extends a single *templated* base type and
1198
+ // has no properties of its own, absorb the definition of the base model
1199
+ // into this schema definition. The assumption here is that any model type
1200
+ // defined like this is just meant to rename the underlying instance of a
1201
+ // templated type.
1202
+ if (model.baseModel &&
1203
+ isTemplateDeclarationOrInstance(model.baseModel) &&
1204
+ Object.keys(properties).length === 0) {
1205
+ // Take the base model schema but carry across the documentation property
1206
+ // that we set before
1207
+ const baseSchema = getSchemaForType(model.baseModel, visibility);
1208
+ Object.assign(modelSchema, baseSchema, { description: modelSchema.description });
1209
+ }
1210
+ else if (model.baseModel) {
1211
+ const baseSchema = getSchemaOrRef(model.baseModel, visibility);
1212
+ modelSchema.allOf = [baseSchema];
1213
+ }
1214
+ if (Object.keys(properties).length > 0) {
1215
+ modelSchema.properties = properties;
1216
+ }
1217
+ // Attach any OpenAPI extensions
1218
+ attachExtensions(model, modelSchema);
1219
+ return modelSchema;
1220
+ }
1221
+ function canSharePropertyUsingReadonlyOrXMSMutability(prop) {
1222
+ const sharedVisibilities = ["read", "create", "update", "write"];
1223
+ const visibilities = getVisibility(program, prop);
1224
+ if (visibilities) {
1225
+ for (const visibility of visibilities) {
1226
+ if (!sharedVisibilities.includes(visibility)) {
1227
+ return false;
1228
+ }
1229
+ }
1230
+ }
1231
+ return true;
1232
+ }
1233
+ function resolveProperty(prop, visibility) {
1234
+ let propSchema;
1235
+ if (prop.type.kind === "Enum" && prop.default) {
1236
+ propSchema = getSchemaForEnum(prop.type);
1237
+ }
1238
+ else if (prop.type.kind === "Union" && prop.default) {
1239
+ const [asEnum, _] = getUnionAsEnum(prop.type);
1240
+ if (asEnum) {
1241
+ propSchema = getSchemaForUnionEnum(prop.type, asEnum);
1242
+ }
1243
+ else {
1244
+ propSchema = getSchemaOrRef(prop.type, visibility);
1245
+ }
1246
+ }
1247
+ else {
1248
+ propSchema = getSchemaOrRef(prop.type, visibility);
1249
+ }
1250
+ return applyIntrinsicDecorators(prop, propSchema);
1251
+ }
1252
+ function attachExtensions(type, emitObject) {
1253
+ // Attach any OpenAPI extensions
1254
+ const extensions = getExtensions(program, type);
1255
+ if (getAsEmbeddingVector(program, type) !== undefined) {
1256
+ emitObject["x-ms-embedding-vector"] = true;
1257
+ }
1258
+ if (extensions) {
1259
+ for (const key of extensions.keys()) {
1260
+ emitObject[key] = extensions.get(key);
1261
+ }
1262
+ }
1263
+ }
1264
+ // Return any string literal values for type
1265
+ function getStringValues(type) {
1266
+ var _a;
1267
+ switch (type.kind) {
1268
+ case "String":
1269
+ return [type.value];
1270
+ case "Union":
1271
+ return [...type.variants.values()].flatMap((x) => getStringValues(x.type)).filter((x) => x);
1272
+ case "EnumMember":
1273
+ return typeof type.value !== "number" ? [(_a = type.value) !== null && _a !== void 0 ? _a : type.name] : [];
1274
+ case "UnionVariant":
1275
+ return getStringValues(type.type);
1276
+ default:
1277
+ return [];
1278
+ }
1279
+ }
1280
+ function applyIntrinsicDecorators(typespecType, target) {
1281
+ const newTarget = { ...target };
1282
+ const docStr = getDoc(program, typespecType);
1283
+ const isString = (typespecType.kind === "Scalar" || typespecType.kind === "ModelProperty") &&
1284
+ isStringType(program, getPropertyType(typespecType));
1285
+ const isNumeric = (typespecType.kind === "Scalar" || typespecType.kind === "ModelProperty") &&
1286
+ isNumericType(program, getPropertyType(typespecType));
1287
+ if (docStr) {
1288
+ newTarget.description = docStr;
1289
+ }
1290
+ const formatStr = getFormat(program, typespecType);
1291
+ if (isString && formatStr) {
1292
+ const allowedStringFormats = [
1293
+ "char",
1294
+ "binary",
1295
+ "byte",
1296
+ "certificate",
1297
+ "date",
1298
+ "time",
1299
+ "date-time",
1300
+ "date-time-rfc1123",
1301
+ "date-time-rfc7231",
1302
+ "duration",
1303
+ "password",
1304
+ "uuid",
1305
+ "base64url",
1306
+ "uri",
1307
+ "url",
1308
+ "arm-id",
1309
+ ];
1310
+ if (!allowedStringFormats.includes(formatStr.toLowerCase())) {
1311
+ reportDiagnostic(program, {
1312
+ code: "invalid-format",
1313
+ format: { schema: "string", format: formatStr },
1314
+ target: typespecType,
1315
+ });
1316
+ }
1317
+ else {
1318
+ newTarget.format = formatStr;
1319
+ }
1320
+ }
1321
+ const pattern = getPattern(program, typespecType);
1322
+ if (isString && pattern) {
1323
+ newTarget.pattern = pattern;
1324
+ }
1325
+ const minLength = getMinLength(program, typespecType);
1326
+ if (isString && minLength !== undefined) {
1327
+ newTarget.minLength = minLength;
1328
+ }
1329
+ const maxLength = getMaxLength(program, typespecType);
1330
+ if (isString && maxLength !== undefined) {
1331
+ newTarget.maxLength = maxLength;
1332
+ }
1333
+ const minValue = getMinValue(program, typespecType);
1334
+ if (isNumeric && minValue !== undefined) {
1335
+ newTarget.minimum = minValue;
1336
+ }
1337
+ const maxValue = getMaxValue(program, typespecType);
1338
+ if (isNumeric && maxValue !== undefined) {
1339
+ newTarget.maximum = maxValue;
1340
+ }
1341
+ const minItems = getMinItems(program, typespecType);
1342
+ if (!target.minItems && minItems !== undefined) {
1343
+ newTarget.minItems = minItems;
1344
+ }
1345
+ const maxItems = getMaxItems(program, typespecType);
1346
+ if (!target.maxItems && maxItems !== undefined) {
1347
+ newTarget.maxItems = maxItems;
1348
+ }
1349
+ if (isSecret(program, typespecType)) {
1350
+ newTarget.format = "password";
1351
+ newTarget["x-ms-secret"] = true;
1352
+ }
1353
+ if (isString) {
1354
+ const values = getKnownValues(program, typespecType);
1355
+ if (values) {
1356
+ const enumSchema = { ...newTarget, ...getSchemaForEnum(values) };
1357
+ enumSchema["x-ms-enum"].modelAsString = true;
1358
+ enumSchema["x-ms-enum"].name = getPropertyType(typespecType).name;
1359
+ return enumSchema;
1360
+ }
1361
+ }
1362
+ if (typespecType.kind === "ModelProperty" &&
1363
+ shouldFlattenProperty(tcgcSdkContext, typespecType)) {
1364
+ newTarget["x-ms-client-flatten"] = true;
1365
+ }
1366
+ attachExtensions(typespecType, newTarget);
1367
+ return typespecType.kind === "Scalar" || typespecType.kind === "ModelProperty"
1368
+ ? applyEncoding(typespecType, newTarget)
1369
+ : newTarget;
1370
+ }
1371
+ function applyEncoding(typespecType, target) {
1372
+ const encodeData = getEncode(program, typespecType);
1373
+ if (encodeData) {
1374
+ const newTarget = { ...target };
1375
+ const newType = getSchemaForScalar(encodeData.type);
1376
+ newTarget.type = newType.type;
1377
+ // If the target already has a format it takes priority. (e.g. int32)
1378
+ newTarget.format = mergeFormatAndEncoding(newTarget.format, encodeData.encoding, newType.format);
1379
+ return newTarget;
1380
+ }
1381
+ return target;
1382
+ }
1383
+ function mergeFormatAndEncoding(format, encoding, encodeAsFormat) {
1384
+ switch (format) {
1385
+ case undefined:
1386
+ return encodeAsFormat !== null && encodeAsFormat !== void 0 ? encodeAsFormat : encoding;
1387
+ case "date-time":
1388
+ switch (encoding) {
1389
+ case "rfc3339":
1390
+ return "date-time";
1391
+ case "unixTimestamp":
1392
+ return "unixtime";
1393
+ case "rfc7231":
1394
+ return "date-time-rfc7231";
1395
+ default:
1396
+ return encoding;
1397
+ }
1398
+ case "duration":
1399
+ switch (encoding) {
1400
+ case "ISO8601":
1401
+ return "duration";
1402
+ default:
1403
+ return encodeAsFormat !== null && encodeAsFormat !== void 0 ? encodeAsFormat : encoding;
1404
+ }
1405
+ default:
1406
+ return encodeAsFormat !== null && encodeAsFormat !== void 0 ? encodeAsFormat : encoding;
1407
+ }
1408
+ }
1409
+ function applyExternalDocs(typespecType, target) {
1410
+ const externalDocs = getExternalDocs(program, typespecType);
1411
+ if (externalDocs) {
1412
+ target.externalDocs = externalDocs;
1413
+ }
1414
+ }
1415
+ function addXMSEnum(type, schema) {
1416
+ var _a;
1417
+ if (type.node && type.node.parent && type.node.parent.kind === SyntaxKind.ModelStatement) {
1418
+ schema["x-ms-enum"] = {
1419
+ name: type.node.parent.id.sv,
1420
+ modelAsString: true,
1421
+ };
1422
+ }
1423
+ else if (type.kind === "String") {
1424
+ schema["x-ms-enum"] = {
1425
+ modelAsString: false,
1426
+ };
1427
+ }
1428
+ else if (type.kind === "Enum") {
1429
+ schema["x-ms-enum"] = {
1430
+ name: type.name,
1431
+ modelAsString: isFixed(program, type) ? false : true,
1432
+ };
1433
+ const values = [];
1434
+ let foundCustom = false;
1435
+ for (const member of type.members.values()) {
1436
+ const description = getDoc(program, member);
1437
+ values.push({
1438
+ name: member.name,
1439
+ value: (_a = member.value) !== null && _a !== void 0 ? _a : member.name,
1440
+ description,
1441
+ });
1442
+ if (description || member.value !== undefined) {
1443
+ foundCustom = true;
1444
+ }
1445
+ }
1446
+ if (foundCustom) {
1447
+ schema["x-ms-enum"].values = values;
1448
+ }
1449
+ }
1450
+ return schema;
1451
+ }
1452
+ function getSchemaForStringTemplate(stringTemplate) {
1453
+ const [value, diagnostics] = stringTemplateToString(stringTemplate);
1454
+ if (diagnostics.length > 0) {
1455
+ program.reportDiagnostics(diagnostics.map((x) => ({ ...x, severity: "warning" })));
1456
+ return { type: "string" };
1457
+ }
1458
+ return { type: "string", enum: [value] };
1459
+ }
1460
+ function getSchemaForLiterals(typespecType) {
1461
+ switch (typespecType.kind) {
1462
+ case "Number":
1463
+ return { type: "number", enum: [typespecType.value] };
1464
+ case "String":
1465
+ return addXMSEnum(typespecType, { type: "string", enum: [typespecType.value] });
1466
+ case "Boolean":
1467
+ return { type: "boolean", enum: [typespecType.value] };
1468
+ default:
1469
+ return undefined;
1470
+ }
1471
+ }
1472
+ /**
1473
+ * If the model is an array model return the OpenAPI2Schema for the array type.
1474
+ */
1475
+ function getArrayType(typespecType, visibility) {
1476
+ if (isArrayModelType(program, typespecType)) {
1477
+ const array = {
1478
+ type: "array",
1479
+ items: getSchemaOrRef(typespecType.indexer.value, visibility | Visibility.Item),
1480
+ };
1481
+ if (!ifArrayItemContainsIdentifier(program, typespecType)) {
1482
+ array["x-ms-identifiers"] = [];
1483
+ }
1484
+ return applyIntrinsicDecorators(typespecType, array);
1485
+ }
1486
+ return undefined;
1487
+ }
1488
+ function getSchemaForScalar(scalar) {
1489
+ let result = {};
1490
+ const isStd = program.checker.isStdType(scalar);
1491
+ if (isStd) {
1492
+ result = getSchemaForStdScalars(scalar);
1493
+ }
1494
+ else if (scalar.baseScalar) {
1495
+ result = getSchemaForScalar(scalar.baseScalar);
1496
+ }
1497
+ const withDecorators = applyIntrinsicDecorators(scalar, result);
1498
+ if (isStd) {
1499
+ // Standard types are going to be inlined in the spec and we don't want the description of the scalar to show up
1500
+ delete withDecorators.description;
1501
+ }
1502
+ return withDecorators;
1503
+ }
1504
+ function getSchemaForStdScalars(scalar) {
1505
+ function reportNonspecificScalar(scalarName, chosenScalarName) {
1506
+ reportDiagnostic(program, {
1507
+ code: "nonspecific-scalar",
1508
+ format: { type: scalarName, chosenType: chosenScalarName },
1509
+ target: scalar,
1510
+ });
1511
+ }
1512
+ switch (scalar.name) {
1513
+ case "bytes":
1514
+ return { type: "string", format: "byte" };
1515
+ case "numeric":
1516
+ reportNonspecificScalar("numeric", "int64");
1517
+ return { type: "integer", format: "int64" };
1518
+ case "integer":
1519
+ reportNonspecificScalar("integer", "int64");
1520
+ return { type: "integer", format: "int64" };
1521
+ case "int8":
1522
+ return { type: "integer", format: "int8" };
1523
+ case "int16":
1524
+ return { type: "integer", format: "int16" };
1525
+ case "int32":
1526
+ return { type: "integer", format: "int32" };
1527
+ case "int64":
1528
+ return { type: "integer", format: "int64" };
1529
+ case "safeint":
1530
+ return { type: "integer", format: "int64" };
1531
+ case "uint8":
1532
+ return { type: "integer", format: "uint8" };
1533
+ case "uint16":
1534
+ return { type: "integer", format: "uint16" };
1535
+ case "uint32":
1536
+ return { type: "integer", format: "uint32" };
1537
+ case "uint64":
1538
+ return { type: "integer", format: "uint64" };
1539
+ case "float":
1540
+ reportNonspecificScalar("float", "float64");
1541
+ return { type: "number" };
1542
+ case "float64":
1543
+ return { type: "number", format: "double" };
1544
+ case "float32":
1545
+ return { type: "number", format: "float" };
1546
+ case "decimal":
1547
+ return { type: "number", format: "decimal" };
1548
+ case "decimal128":
1549
+ return { type: "number", format: "decimal128" };
1550
+ case "string":
1551
+ return { type: "string" };
1552
+ case "boolean":
1553
+ return { type: "boolean" };
1554
+ case "plainDate":
1555
+ return { type: "string", format: "date" };
1556
+ case "utcDateTime":
1557
+ case "offsetDateTime":
1558
+ return { type: "string", format: "date-time" };
1559
+ case "plainTime":
1560
+ return { type: "string", format: "time" };
1561
+ case "duration":
1562
+ return { type: "string", format: "duration" };
1563
+ case "url":
1564
+ return { type: "string", format: "uri" };
1565
+ default:
1566
+ const _assertNever = scalar.name;
1567
+ return {};
1568
+ }
1569
+ }
1570
+ function processAuth(serviceNamespace) {
1571
+ const authentication = getAuthentication(program, serviceNamespace);
1572
+ if (authentication) {
1573
+ return processServiceAuthentication(authentication, serviceNamespace);
1574
+ }
1575
+ return undefined;
1576
+ }
1577
+ function processServiceAuthentication(authentication, serviceNamespace) {
1578
+ const oaiSchemes = {};
1579
+ const security = [];
1580
+ for (const option of authentication.options) {
1581
+ const oai3SecurityOption = {};
1582
+ for (const scheme of option.schemes) {
1583
+ const result = getOpenAPI2Scheme(scheme, serviceNamespace);
1584
+ if (result !== undefined) {
1585
+ const [oaiScheme, scopes] = result;
1586
+ oaiSchemes[scheme.id] = oaiScheme;
1587
+ oai3SecurityOption[scheme.id] = scopes;
1588
+ }
1589
+ }
1590
+ if (Object.keys(oai3SecurityOption).length > 0) {
1591
+ security.push(oai3SecurityOption);
1592
+ }
1593
+ }
1594
+ return { securitySchemes: oaiSchemes, security };
1595
+ }
1596
+ function getOpenAPI2Scheme(auth, serviceNamespace) {
1597
+ switch (auth.type) {
1598
+ case "http":
1599
+ if (auth.scheme !== "basic") {
1600
+ reportDiagnostic(program, {
1601
+ code: "unsupported-http-auth-scheme",
1602
+ target: serviceNamespace,
1603
+ format: { scheme: auth.scheme },
1604
+ });
1605
+ return undefined;
1606
+ }
1607
+ return [{ type: "basic", description: auth.description }, []];
1608
+ case "apiKey":
1609
+ if (auth.in === "cookie") {
1610
+ return undefined;
1611
+ }
1612
+ return [
1613
+ { type: "apiKey", description: auth.description, in: auth.in, name: auth.name },
1614
+ [],
1615
+ ];
1616
+ case "oauth2":
1617
+ const flow = auth.flows[0];
1618
+ if (flow === undefined) {
1619
+ return undefined;
1620
+ }
1621
+ const oaiFlowName = getOpenAPI2Flow(flow.type);
1622
+ return [
1623
+ {
1624
+ type: "oauth2",
1625
+ description: auth.description,
1626
+ flow: oaiFlowName,
1627
+ authorizationUrl: flow.authorizationUrl,
1628
+ tokenUrl: flow.tokenUrl,
1629
+ scopes: Object.fromEntries(flow.scopes.map((x) => { var _a; return [x.value, (_a = x.description) !== null && _a !== void 0 ? _a : ""]; })),
1630
+ },
1631
+ flow.scopes.map((x) => x.value),
1632
+ ];
1633
+ case "openIdConnect":
1634
+ default:
1635
+ reportDiagnostic(program, {
1636
+ code: "unsupported-auth",
1637
+ format: { authType: auth.type },
1638
+ target: currentService.type,
1639
+ });
1640
+ return undefined;
1641
+ }
1642
+ }
1643
+ function getOpenAPI2Flow(flow) {
1644
+ switch (flow) {
1645
+ case "authorizationCode":
1646
+ return "accessCode";
1647
+ case "clientCredentials":
1648
+ return "application";
1649
+ case "implicit":
1650
+ return "implicit";
1651
+ case "password":
1652
+ return "password";
1653
+ default:
1654
+ const _assertNever = flow;
1655
+ compilerAssert(false, "Unreachable");
1656
+ }
1657
+ }
1658
+ }
1659
+ function prettierOutput(output) {
1660
+ return output + "\n";
1661
+ }
1662
+ class ErrorTypeFoundError extends Error {
1663
+ constructor() {
1664
+ super("Error type found in evaluated TypeSpec output");
1665
+ }
1666
+ }
1667
+ export function sortOpenAPIDocument(doc) {
1668
+ // Doing this to make sure the classes with toJSON are resolved.
1669
+ const unsorted = JSON.parse(JSON.stringify(doc));
1670
+ const sorted = sortWithJsonSchema(unsorted, AutorestCanonicalOpenAPISchema, "#/$defs/AutorestCanonicalOpenAPISchema");
1671
+ return sorted;
1672
+ }
1673
+ function resolveOutputFile(program, service, multipleServices, options, version) {
1674
+ const azureResourceProviderFolder = options.azureResourceProviderFolder;
1675
+ const interpolated = interpolatePath(options.outputFile, {
1676
+ "azure-resource-provider-folder": azureResourceProviderFolder,
1677
+ "service-name": multipleServices || azureResourceProviderFolder
1678
+ ? getNamespaceFullName(service.type)
1679
+ : undefined,
1680
+ version,
1681
+ });
1682
+ return resolvePath(options.outputDir, interpolated);
1683
+ }
1684
+ //# sourceMappingURL=openapi.js.map