@typespec/openapi3 0.59.0-dev.1 → 0.59.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/actions/convert/transforms/transform-operation-responses.d.ts.map +1 -1
- package/dist/src/cli/actions/convert/transforms/transform-operation-responses.js +6 -4
- package/dist/src/cli/actions/convert/transforms/transform-operation-responses.js.map +1 -1
- package/dist/src/encoding.d.ts +5 -0
- package/dist/src/encoding.d.ts.map +1 -0
- package/dist/src/encoding.js +42 -0
- package/dist/src/encoding.js.map +1 -0
- package/dist/src/examples.d.ts +14 -0
- package/dist/src/examples.d.ts.map +1 -0
- package/dist/src/examples.js +180 -0
- package/dist/src/examples.js.map +1 -0
- package/dist/src/openapi.d.ts.map +1 -1
- package/dist/src/openapi.js +240 -438
- package/dist/src/openapi.js.map +1 -1
- package/dist/src/schema-emitter.d.ts.map +1 -1
- package/dist/src/schema-emitter.js +28 -90
- package/dist/src/schema-emitter.js.map +1 -1
- package/dist/src/status-codes.d.ts +5 -0
- package/dist/src/status-codes.d.ts.map +1 -0
- package/dist/src/status-codes.js +51 -0
- package/dist/src/status-codes.js.map +1 -0
- package/dist/src/std-scalar-schemas.d.ts +7 -0
- package/dist/src/std-scalar-schemas.d.ts.map +1 -0
- package/dist/src/std-scalar-schemas.js +63 -0
- package/dist/src/std-scalar-schemas.js.map +1 -0
- package/dist/src/types.d.ts +4 -4
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/util.d.ts +6 -0
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +3 -0
- package/dist/src/util.js.map +1 -1
- package/package.json +6 -6
package/dist/src/openapi.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { compilerAssert, createDiagnosticCollector, emitFile, getAllTags, getAnyExtensionFromPath, getDoc,
|
|
1
|
+
import { compilerAssert, createDiagnosticCollector, emitFile, getAllTags, getAnyExtensionFromPath, getDoc, getFormat, getKnownValues, getMaxItems, getMaxLength, getMaxValue, getMaxValueExclusive, getMinItems, getMinLength, getMinValue, getMinValueExclusive, getNamespaceFullName, getPattern, getService, getSummary, ignoreDiagnostics, interpolatePath, isDeprecated, isGlobalNamespace, isNeverType, isSecret, isVoidType, listServices, navigateTypesInNamespace, projectProgram, resolvePath, } from "@typespec/compiler";
|
|
2
2
|
import { createAssetEmitter } from "@typespec/compiler/emitter-framework";
|
|
3
3
|
import { createMetadataInfo, getHttpService, getServers, getStatusCodeDescription, isContentTypeHeader, isOrExtendsHttpFile, isOverloadSameEndpoint, reportIfNoRoutes, resolveAuthentication, resolveRequestVisibility, Visibility, } from "@typespec/http";
|
|
4
|
-
import { getExtensions, getExternalDocs, getOpenAPITypeName, getParameterKey,
|
|
4
|
+
import { getExtensions, getExternalDocs, getOpenAPITypeName, getParameterKey, isReadonlyProperty, resolveInfo, resolveOperationId, shouldInline, } from "@typespec/openapi";
|
|
5
5
|
import { buildVersionProjections } from "@typespec/versioning";
|
|
6
6
|
import { stringify } from "yaml";
|
|
7
7
|
import { getRef } from "./decorators.js";
|
|
8
|
+
import { applyEncoding } from "./encoding.js";
|
|
9
|
+
import { getExampleOrExamples, resolveOperationExamples } from "./examples.js";
|
|
8
10
|
import { createDiagnostic } from "./lib.js";
|
|
9
11
|
import { getDefaultValue, isBytesKeptRaw, OpenAPI3SchemaEmitter } from "./schema-emitter.js";
|
|
10
|
-
import {
|
|
12
|
+
import { getOpenAPI3StatusCodes } from "./status-codes.js";
|
|
13
|
+
import { deepEquals, isSharedHttpOperation } from "./util.js";
|
|
11
14
|
import { resolveVisibilityUsage } from "./visibility-usage.js";
|
|
12
15
|
const defaultFileType = "yaml";
|
|
13
16
|
const defaultOptions = {
|
|
@@ -76,10 +79,10 @@ function createOAPIEmitter(context, options) {
|
|
|
76
79
|
let root;
|
|
77
80
|
let diagnostics;
|
|
78
81
|
let currentService;
|
|
82
|
+
let serviceAuth;
|
|
79
83
|
// Get the service namespace string for use in name shortening
|
|
80
84
|
let serviceNamespaceName;
|
|
81
85
|
let currentPath;
|
|
82
|
-
let currentEndpoint;
|
|
83
86
|
let metadataInfo;
|
|
84
87
|
let visibilityUsage;
|
|
85
88
|
// Map model properties that represent shared parameters to their parameter
|
|
@@ -316,15 +319,7 @@ function createOAPIEmitter(context, options) {
|
|
|
316
319
|
/**
|
|
317
320
|
* Validates that common responses are consistent and returns the minimal set that describes the differences.
|
|
318
321
|
*/
|
|
319
|
-
function
|
|
320
|
-
const statusCodeResponses = [];
|
|
321
|
-
for (const op of ops) {
|
|
322
|
-
for (const response of op.responses) {
|
|
323
|
-
if (getOpenAPI3StatusCodes(response.statusCodes, response.type).includes(statusCode)) {
|
|
324
|
-
statusCodeResponses.push(response);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
322
|
+
function deduplicateCommonResponses(statusCodeResponses) {
|
|
328
323
|
const ref = statusCodeResponses[0];
|
|
329
324
|
const sameTypeKind = statusCodeResponses.every((r) => r.type.kind === ref.type.kind);
|
|
330
325
|
const sameTypeValue = statusCodeResponses.every((r) => r.type === ref.type);
|
|
@@ -336,156 +331,61 @@ function createOAPIEmitter(context, options) {
|
|
|
336
331
|
return statusCodeResponses;
|
|
337
332
|
}
|
|
338
333
|
}
|
|
339
|
-
/**
|
|
340
|
-
* Validates that common bodies are consistent and returns the minimal set that describes the differences.
|
|
341
|
-
*/
|
|
342
|
-
function validateCommonBodies(ops) {
|
|
343
|
-
const allBodies = ops.map((op) => op.parameters.body);
|
|
344
|
-
return [...new Set(allBodies)];
|
|
345
|
-
}
|
|
346
334
|
/**
|
|
347
335
|
* Validates that common parameters are consistent and returns the minimal set that describes the differences.
|
|
348
336
|
*/
|
|
349
|
-
function
|
|
337
|
+
function resolveSharedRouteParameters(ops) {
|
|
350
338
|
const finalParams = [];
|
|
351
|
-
const
|
|
339
|
+
const parameters = new Map();
|
|
352
340
|
for (const op of ops) {
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
|
|
341
|
+
for (const parameter of op.parameters.parameters) {
|
|
342
|
+
const existing = parameters.get(parameter.name);
|
|
343
|
+
if (existing) {
|
|
344
|
+
existing.push(parameter);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
parameters.set(parameter.name, [parameter]);
|
|
348
|
+
}
|
|
356
349
|
}
|
|
357
350
|
}
|
|
358
|
-
|
|
359
|
-
if (!reference) {
|
|
351
|
+
if (parameters.size === 0) {
|
|
360
352
|
return [];
|
|
361
353
|
}
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
// param is consistent when used, but does not appear in all shared operations. Only need one copy, but it must be optional.
|
|
373
|
-
reference.param.optional = true;
|
|
374
|
-
finalParams.push(reference);
|
|
375
|
-
}
|
|
376
|
-
else if (inAllOps && !(sameLocations && sameOptionality && sameTypeKind)) {
|
|
377
|
-
// param is in all shared operations, but is not consistent. Need multiple copies, which must be optional.
|
|
378
|
-
// exception allowed when the params only differ by their value (e.g. string enum values)
|
|
379
|
-
commonParams.forEach((p) => {
|
|
380
|
-
p.param.optional = true;
|
|
381
|
-
});
|
|
382
|
-
finalParams.push(...commonParams);
|
|
383
|
-
}
|
|
384
|
-
else {
|
|
385
|
-
finalParams.push(...commonParams);
|
|
386
|
-
}
|
|
387
|
-
return finalParams;
|
|
388
|
-
}
|
|
389
|
-
function getOpenAPI3StatusCodes(statusCodes, response) {
|
|
390
|
-
if (isDefaultResponse(program, response) || statusCodes === "*") {
|
|
391
|
-
return ["default"];
|
|
392
|
-
}
|
|
393
|
-
else if (typeof statusCodes === "number") {
|
|
394
|
-
return [String(statusCodes)];
|
|
395
|
-
}
|
|
396
|
-
else {
|
|
397
|
-
return rangeToOpenAPI(statusCodes, response);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
function rangeToOpenAPI(range, diagnosticTarget) {
|
|
401
|
-
const reportInvalid = () => diagnostics.add(createDiagnostic({
|
|
402
|
-
code: "unsupported-status-code-range",
|
|
403
|
-
format: { start: String(range.start), end: String(range.end) },
|
|
404
|
-
target: diagnosticTarget,
|
|
405
|
-
}));
|
|
406
|
-
const codes = [];
|
|
407
|
-
let start = range.start;
|
|
408
|
-
let end = range.end;
|
|
409
|
-
if (range.start < 100) {
|
|
410
|
-
reportInvalid();
|
|
411
|
-
start = 100;
|
|
412
|
-
codes.push("default");
|
|
413
|
-
}
|
|
414
|
-
else if (range.end > 599) {
|
|
415
|
-
reportInvalid();
|
|
416
|
-
codes.push("default");
|
|
417
|
-
end = 599;
|
|
418
|
-
}
|
|
419
|
-
const groups = [1, 2, 3, 4, 5];
|
|
420
|
-
for (const group of groups) {
|
|
421
|
-
if (start > end) {
|
|
422
|
-
break;
|
|
354
|
+
for (const sharedParams of parameters.values()) {
|
|
355
|
+
const reference = sharedParams[0];
|
|
356
|
+
const inAllOps = ops.length === sharedParams.length;
|
|
357
|
+
const sameLocations = sharedParams.every((p) => p.type === reference.type);
|
|
358
|
+
const sameOptionality = sharedParams.every((p) => p.param.optional === reference.param.optional);
|
|
359
|
+
const sameTypeKind = sharedParams.every((p) => p.param.type.kind === reference.param.type.kind);
|
|
360
|
+
const sameTypeValue = sharedParams.every((p) => p.param.type === reference.param.type);
|
|
361
|
+
if (inAllOps && sameLocations && sameOptionality && sameTypeKind && sameTypeValue) {
|
|
362
|
+
// param is consistent and in all shared operations. Only need one copy.
|
|
363
|
+
finalParams.push(reference);
|
|
423
364
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
if (start !== groupStart || end < groupEnd) {
|
|
429
|
-
reportInvalid();
|
|
430
|
-
}
|
|
431
|
-
start = groupStart + 100;
|
|
365
|
+
else if (!inAllOps && sameLocations && sameOptionality && sameTypeKind && sameTypeValue) {
|
|
366
|
+
// param is consistent when used, but does not appear in all shared operations. Only need one copy, but it must be optional.
|
|
367
|
+
reference.param.optional = true;
|
|
368
|
+
finalParams.push(reference);
|
|
432
369
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
for (const op of operations) {
|
|
441
|
-
// determine which parameters are shared by shared route operations
|
|
442
|
-
for (const param of op.parameters.parameters) {
|
|
443
|
-
if (paramMap.has(param.name)) {
|
|
444
|
-
paramMap.get(param.name).push(op);
|
|
445
|
-
}
|
|
446
|
-
else {
|
|
447
|
-
paramMap.set(param.name, [op]);
|
|
448
|
-
}
|
|
370
|
+
else if (inAllOps && !(sameLocations && sameOptionality && sameTypeKind)) {
|
|
371
|
+
// param is in all shared operations, but is not consistent. Need multiple copies, which must be optional.
|
|
372
|
+
// exception allowed when the params only differ by their value (e.g. string enum values)
|
|
373
|
+
sharedParams.forEach((p) => {
|
|
374
|
+
p.param.optional = true;
|
|
375
|
+
});
|
|
376
|
+
finalParams.push(...sharedParams);
|
|
449
377
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
const statusCodes = getOpenAPI3StatusCodes(response.statusCodes, op.operation);
|
|
453
|
-
for (const statusCode of statusCodes) {
|
|
454
|
-
if (responseMap.has(statusCode)) {
|
|
455
|
-
responseMap.get(statusCode).push(op);
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
responseMap.set(statusCode, [op]);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
378
|
+
else {
|
|
379
|
+
finalParams.push(...sharedParams);
|
|
461
380
|
}
|
|
462
381
|
}
|
|
463
|
-
|
|
464
|
-
|
|
382
|
+
return finalParams;
|
|
383
|
+
}
|
|
384
|
+
function buildSharedOperation(operations) {
|
|
385
|
+
return {
|
|
465
386
|
kind: "shared",
|
|
466
|
-
|
|
467
|
-
description: joinOps(operations, getDoc, " "),
|
|
468
|
-
summary: joinOps(operations, getSummary, " "),
|
|
469
|
-
path: operations[0].path,
|
|
470
|
-
verb: operations[0].verb,
|
|
471
|
-
operations: operations.map((op) => op.operation),
|
|
472
|
-
parameters: {
|
|
473
|
-
parameters: [],
|
|
474
|
-
},
|
|
475
|
-
bodies: undefined,
|
|
476
|
-
authentication: operations[0].authentication,
|
|
477
|
-
responses: new Map(),
|
|
387
|
+
operations: operations,
|
|
478
388
|
};
|
|
479
|
-
for (const [paramName, ops] of paramMap) {
|
|
480
|
-
const commonParams = validateCommonParameters(ops, paramName, totalOps);
|
|
481
|
-
shared.parameters.parameters.push(...commonParams);
|
|
482
|
-
}
|
|
483
|
-
shared.bodies = validateCommonBodies(operations);
|
|
484
|
-
for (const [statusCode, ops] of responseMap) {
|
|
485
|
-
shared.responses.set(statusCode, validateCommonResponses(statusCode, ops));
|
|
486
|
-
}
|
|
487
|
-
results.push(shared);
|
|
488
|
-
return results;
|
|
489
389
|
}
|
|
490
390
|
/**
|
|
491
391
|
* Groups HttpOperations together if they share the same route.
|
|
@@ -507,10 +407,7 @@ function createOAPIEmitter(context, options) {
|
|
|
507
407
|
result.push(ops[0]);
|
|
508
408
|
}
|
|
509
409
|
else {
|
|
510
|
-
|
|
511
|
-
for (const op of sharedOps) {
|
|
512
|
-
result.push(op);
|
|
513
|
-
}
|
|
410
|
+
result.push(buildSharedOperation(ops));
|
|
514
411
|
}
|
|
515
412
|
}
|
|
516
413
|
return result;
|
|
@@ -518,17 +415,15 @@ function createOAPIEmitter(context, options) {
|
|
|
518
415
|
async function getOpenApiFromVersion(service, version) {
|
|
519
416
|
try {
|
|
520
417
|
const httpService = ignoreDiagnostics(getHttpService(program, service.type));
|
|
521
|
-
const auth = resolveAuthentication(httpService);
|
|
418
|
+
const auth = (serviceAuth = resolveAuthentication(httpService));
|
|
522
419
|
initializeEmitter(service, auth.schemes, auth.defaultAuth, version);
|
|
523
420
|
reportIfNoRoutes(program, httpService.operations);
|
|
524
421
|
for (const op of resolveOperations(httpService.operations)) {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
const opAuth = auth.operationsAuth.get(op.operation);
|
|
531
|
-
emitOperation(op, opAuth);
|
|
422
|
+
const result = getOperationOrSharedOperation(op);
|
|
423
|
+
if (result) {
|
|
424
|
+
const { operation, path, verb } = result;
|
|
425
|
+
currentPath[path] ??= {};
|
|
426
|
+
currentPath[path][verb] = operation;
|
|
532
427
|
}
|
|
533
428
|
}
|
|
534
429
|
emitParameters();
|
|
@@ -566,26 +461,46 @@ function createOAPIEmitter(context, options) {
|
|
|
566
461
|
return undefined;
|
|
567
462
|
}
|
|
568
463
|
}
|
|
569
|
-
function
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
464
|
+
function computeSharedOperationId(shared) {
|
|
465
|
+
return shared.operations.map((op) => resolveOperationId(program, op.operation)).join("_");
|
|
466
|
+
}
|
|
467
|
+
function getOperationOrSharedOperation(operation) {
|
|
468
|
+
if (isSharedHttpOperation(operation)) {
|
|
469
|
+
return getSharedOperation(operation);
|
|
573
470
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
currentPath[verb] = {};
|
|
471
|
+
else {
|
|
472
|
+
return getOperation(operation);
|
|
577
473
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
474
|
+
}
|
|
475
|
+
function getSharedOperation(shared) {
|
|
476
|
+
const operations = shared.operations;
|
|
477
|
+
const verb = operations[0].verb;
|
|
478
|
+
const path = operations[0].path;
|
|
479
|
+
const examples = resolveOperationExamples(program, shared);
|
|
480
|
+
const oai3Operation = {
|
|
481
|
+
operationId: computeSharedOperationId(shared),
|
|
482
|
+
parameters: [],
|
|
483
|
+
description: joinOps(operations, getDoc, " "),
|
|
484
|
+
summary: joinOps(operations, getSummary, " "),
|
|
485
|
+
responses: getSharedResponses(shared, examples),
|
|
486
|
+
};
|
|
487
|
+
for (const op of operations) {
|
|
488
|
+
applyExternalDocs(op.operation, oai3Operation);
|
|
489
|
+
attachExtensions(program, op.operation, oai3Operation);
|
|
490
|
+
if (isDeprecated(program, op.operation)) {
|
|
491
|
+
oai3Operation.deprecated = true;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
for (const op of operations) {
|
|
495
|
+
const opTags = getAllTags(program, op.operation);
|
|
581
496
|
if (opTags) {
|
|
582
|
-
const currentTags =
|
|
497
|
+
const currentTags = oai3Operation.tags;
|
|
583
498
|
if (currentTags) {
|
|
584
499
|
// combine tags but eliminate duplicates
|
|
585
|
-
|
|
500
|
+
oai3Operation.tags = [...new Set([...currentTags, ...opTags])];
|
|
586
501
|
}
|
|
587
502
|
else {
|
|
588
|
-
|
|
503
|
+
oai3Operation.tags = opTags;
|
|
589
504
|
}
|
|
590
505
|
for (const tag of opTags) {
|
|
591
506
|
// Add to root tags if not already there
|
|
@@ -593,105 +508,98 @@ function createOAPIEmitter(context, options) {
|
|
|
593
508
|
}
|
|
594
509
|
}
|
|
595
510
|
}
|
|
596
|
-
// Set up basic endpoint fields
|
|
597
|
-
currentEndpoint.operationId = shared.operationId;
|
|
598
|
-
for (const op of ops) {
|
|
599
|
-
applyExternalDocs(op, currentEndpoint);
|
|
600
|
-
}
|
|
601
|
-
currentEndpoint.summary = shared.summary;
|
|
602
|
-
currentEndpoint.description = shared.description;
|
|
603
|
-
currentEndpoint.parameters = [];
|
|
604
|
-
currentEndpoint.responses = {};
|
|
605
511
|
// Error out if shared routes do not have consistent `@parameterVisibility`. We can
|
|
606
512
|
// lift this restriction in the future if a use case develops.
|
|
607
|
-
const visibilities =
|
|
608
|
-
return resolveRequestVisibility(program, op, verb);
|
|
609
|
-
});
|
|
513
|
+
const visibilities = operations.map((op) => resolveRequestVisibility(program, op.operation, verb));
|
|
610
514
|
if (visibilities.some((v) => v !== visibilities[0])) {
|
|
611
515
|
diagnostics.add(createDiagnostic({
|
|
612
516
|
code: "inconsistent-shared-route-request-visibility",
|
|
613
|
-
target:
|
|
517
|
+
target: operations[0].operation,
|
|
614
518
|
}));
|
|
615
519
|
}
|
|
616
|
-
const visibility =
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
emitMergedRequestBody(shared, shared.bodies, visibility);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
emitSharedResponses(shared, shared.responses);
|
|
627
|
-
for (const op of ops) {
|
|
628
|
-
if (isDeprecated(program, op)) {
|
|
629
|
-
currentEndpoint.deprecated = true;
|
|
630
|
-
}
|
|
631
|
-
attachExtensions(program, op, currentEndpoint);
|
|
520
|
+
const visibility = visibilities[0];
|
|
521
|
+
oai3Operation.parameters = getEndpointParameters(resolveSharedRouteParameters(operations), visibility);
|
|
522
|
+
const bodies = [
|
|
523
|
+
...new Set(operations.map((op) => op.parameters.body).filter((x) => x !== undefined)),
|
|
524
|
+
];
|
|
525
|
+
if (bodies) {
|
|
526
|
+
oai3Operation.requestBody = getRequestBody(bodies, visibility, examples);
|
|
632
527
|
}
|
|
528
|
+
const authReference = serviceAuth.operationsAuth.get(shared.operations[0].operation);
|
|
633
529
|
if (authReference) {
|
|
634
|
-
|
|
530
|
+
oai3Operation.security = getEndpointSecurity(authReference);
|
|
635
531
|
}
|
|
532
|
+
return { operation: oai3Operation, verb, path };
|
|
636
533
|
}
|
|
637
|
-
function
|
|
534
|
+
function getOperation(operation) {
|
|
638
535
|
const { path: fullPath, operation: op, verb, parameters } = operation;
|
|
639
536
|
// If path contains a query string, issue msg and don't emit this endpoint
|
|
640
537
|
if (fullPath.indexOf("?") > 0) {
|
|
641
538
|
diagnostics.add(createDiagnostic({ code: "path-query", target: op }));
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
if (!root.paths[fullPath]) {
|
|
645
|
-
root.paths[fullPath] = {};
|
|
646
|
-
}
|
|
647
|
-
currentPath = root.paths[fullPath];
|
|
648
|
-
if (!currentPath[verb]) {
|
|
649
|
-
currentPath[verb] = {};
|
|
539
|
+
return undefined;
|
|
650
540
|
}
|
|
651
|
-
|
|
541
|
+
const visibility = resolveRequestVisibility(program, operation.operation, verb);
|
|
542
|
+
const examples = resolveOperationExamples(program, operation);
|
|
543
|
+
const oai3Operation = {
|
|
544
|
+
operationId: resolveOperationId(program, operation.operation),
|
|
545
|
+
summary: getSummary(program, operation.operation),
|
|
546
|
+
description: getDoc(program, operation.operation),
|
|
547
|
+
parameters: getEndpointParameters(parameters.parameters, visibility),
|
|
548
|
+
responses: getResponses(operation, operation.responses, examples),
|
|
549
|
+
};
|
|
652
550
|
const currentTags = getAllTags(program, op);
|
|
653
551
|
if (currentTags) {
|
|
654
|
-
|
|
552
|
+
oai3Operation.tags = currentTags;
|
|
655
553
|
for (const tag of currentTags) {
|
|
656
554
|
// Add to root tags if not already there
|
|
657
555
|
tags.add(tag);
|
|
658
556
|
}
|
|
659
557
|
}
|
|
660
|
-
|
|
661
|
-
applyExternalDocs(op, currentEndpoint);
|
|
558
|
+
applyExternalDocs(op, oai3Operation);
|
|
662
559
|
// Set up basic endpoint fields
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
const visibility = resolveRequestVisibility(program, operation.operation, verb);
|
|
668
|
-
emitEndpointParameters(parameters.parameters, visibility);
|
|
669
|
-
emitRequestBody(operation, parameters.body, visibility);
|
|
670
|
-
emitResponses(operation, operation.responses);
|
|
560
|
+
if (parameters.body) {
|
|
561
|
+
oai3Operation.requestBody = getRequestBody(parameters.body && [parameters.body], visibility, examples);
|
|
562
|
+
}
|
|
563
|
+
const authReference = serviceAuth.operationsAuth.get(operation.operation);
|
|
671
564
|
if (authReference) {
|
|
672
|
-
|
|
565
|
+
oai3Operation.security = getEndpointSecurity(authReference);
|
|
673
566
|
}
|
|
674
567
|
if (isDeprecated(program, op)) {
|
|
675
|
-
|
|
568
|
+
oai3Operation.deprecated = true;
|
|
676
569
|
}
|
|
677
|
-
attachExtensions(program, op,
|
|
570
|
+
attachExtensions(program, op, oai3Operation);
|
|
571
|
+
return { operation: oai3Operation, path: fullPath, verb };
|
|
678
572
|
}
|
|
679
|
-
function
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
573
|
+
function getSharedResponses(operation, examples) {
|
|
574
|
+
const responseMap = new Map();
|
|
575
|
+
for (const op of operation.operations) {
|
|
576
|
+
for (const response of op.responses) {
|
|
577
|
+
const statusCodes = diagnostics.pipe(getOpenAPI3StatusCodes(program, response.statusCodes, op.operation));
|
|
578
|
+
for (const statusCode of statusCodes) {
|
|
579
|
+
if (responseMap.has(statusCode)) {
|
|
580
|
+
responseMap.get(statusCode).push(response);
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
responseMap.set(statusCode, [response]);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
686
586
|
}
|
|
687
587
|
}
|
|
588
|
+
const result = {};
|
|
589
|
+
for (const [statusCode, statusCodeResponses] of responseMap) {
|
|
590
|
+
const dedupeResponses = deduplicateCommonResponses(statusCodeResponses);
|
|
591
|
+
result[statusCode] = getResponseForStatusCode(operation, statusCode, dedupeResponses, examples);
|
|
592
|
+
}
|
|
593
|
+
return result;
|
|
688
594
|
}
|
|
689
|
-
function
|
|
595
|
+
function getResponses(operation, responses, examples) {
|
|
596
|
+
const result = {};
|
|
690
597
|
for (const response of responses) {
|
|
691
|
-
for (const statusCode of getOpenAPI3StatusCodes(response.statusCodes, response.type)) {
|
|
692
|
-
|
|
598
|
+
for (const statusCode of diagnostics.pipe(getOpenAPI3StatusCodes(program, response.statusCodes, response.type))) {
|
|
599
|
+
result[statusCode] = getResponseForStatusCode(operation, statusCode, [response], examples);
|
|
693
600
|
}
|
|
694
601
|
}
|
|
602
|
+
return result;
|
|
695
603
|
}
|
|
696
604
|
function isBinaryPayload(body, contentType) {
|
|
697
605
|
return (body.kind === "Scalar" &&
|
|
@@ -699,33 +607,28 @@ function createOAPIEmitter(context, options) {
|
|
|
699
607
|
contentType !== "application/json" &&
|
|
700
608
|
contentType !== "text/plain");
|
|
701
609
|
}
|
|
702
|
-
function
|
|
610
|
+
function getResponseForStatusCode(operation, statusCode, responses, examples) {
|
|
703
611
|
const openApiResponse = {
|
|
704
|
-
description:
|
|
705
|
-
content: {},
|
|
612
|
+
description: "",
|
|
706
613
|
};
|
|
707
614
|
const schemaMap = new Map();
|
|
708
615
|
for (const response of responses) {
|
|
616
|
+
const refUrl = getRef(program, response.type);
|
|
617
|
+
if (refUrl) {
|
|
618
|
+
return { $ref: refUrl };
|
|
619
|
+
}
|
|
709
620
|
if (response.description && response.description !== openApiResponse.description) {
|
|
710
621
|
openApiResponse.description = openApiResponse.description
|
|
711
622
|
? `${openApiResponse.description} ${response.description}`
|
|
712
623
|
: response.description;
|
|
713
624
|
}
|
|
714
625
|
emitResponseHeaders(openApiResponse, response.responses, response.type);
|
|
715
|
-
emitResponseContent(operation, openApiResponse, response.responses, schemaMap);
|
|
626
|
+
emitResponseContent(operation, openApiResponse, response.responses, statusCode, examples, schemaMap);
|
|
716
627
|
if (!openApiResponse.description) {
|
|
717
628
|
openApiResponse.description = getResponseDescriptionForStatusCode(statusCode);
|
|
718
629
|
}
|
|
719
|
-
currentEndpoint.responses[statusCode] = openApiResponse;
|
|
720
630
|
}
|
|
721
|
-
|
|
722
|
-
function emitResponseObject(operation, statusCode, response) {
|
|
723
|
-
const openApiResponse = currentEndpoint.responses[statusCode] ?? {
|
|
724
|
-
description: response.description ?? getResponseDescriptionForStatusCode(statusCode),
|
|
725
|
-
};
|
|
726
|
-
emitResponseHeaders(openApiResponse, response.responses, response.type);
|
|
727
|
-
emitResponseContent(operation, openApiResponse, response.responses);
|
|
728
|
-
currentEndpoint.responses[statusCode] = openApiResponse;
|
|
631
|
+
return openApiResponse;
|
|
729
632
|
}
|
|
730
633
|
function emitResponseHeaders(obj, responses, target) {
|
|
731
634
|
for (const data of responses) {
|
|
@@ -751,7 +654,7 @@ function createOAPIEmitter(context, options) {
|
|
|
751
654
|
}
|
|
752
655
|
}
|
|
753
656
|
}
|
|
754
|
-
function emitResponseContent(operation, obj, responses, schemaMap = undefined) {
|
|
657
|
+
function emitResponseContent(operation, obj, responses, statusCode, examples, schemaMap = undefined) {
|
|
755
658
|
schemaMap ??= new Map();
|
|
756
659
|
for (const data of responses) {
|
|
757
660
|
if (data.body === undefined) {
|
|
@@ -759,7 +662,7 @@ function createOAPIEmitter(context, options) {
|
|
|
759
662
|
}
|
|
760
663
|
obj.content ??= {};
|
|
761
664
|
for (const contentType of data.body.contentTypes) {
|
|
762
|
-
const contents = getBodyContentEntry(
|
|
665
|
+
const contents = getBodyContentEntry(data.body, Visibility.Read, contentType, examples.responses[statusCode]?.[contentType]);
|
|
763
666
|
if (schemaMap.has(contentType)) {
|
|
764
667
|
schemaMap.get(contentType).push(contents);
|
|
765
668
|
}
|
|
@@ -837,70 +740,22 @@ function createOAPIEmitter(context, options) {
|
|
|
837
740
|
},
|
|
838
741
|
});
|
|
839
742
|
}
|
|
840
|
-
function
|
|
841
|
-
return operation.kind === "shared";
|
|
842
|
-
}
|
|
843
|
-
function findOperationExamples(operation) {
|
|
844
|
-
if (isSharedHttpOperation(operation)) {
|
|
845
|
-
return operation.operations.flatMap((op) => getOpExamples(program, op).map((x) => [op, x]));
|
|
846
|
-
}
|
|
847
|
-
else {
|
|
848
|
-
return getOpExamples(program, operation.operation).map((x) => [operation.operation, x]);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
function getExamplesForBodyContentEntry(operation, target) {
|
|
852
|
-
const examples = findOperationExamples(operation);
|
|
853
|
-
if (examples.length === 0) {
|
|
854
|
-
return {};
|
|
855
|
-
}
|
|
856
|
-
const flattenedExamples = examples
|
|
857
|
-
.map(([op, example]) => {
|
|
858
|
-
const value = target === "request" ? example.parameters : example.returnType;
|
|
859
|
-
const type = target === "request" ? op.parameters : op.returnType;
|
|
860
|
-
return value
|
|
861
|
-
? [{ value, title: example.title, description: example.description }, type]
|
|
862
|
-
: undefined;
|
|
863
|
-
})
|
|
864
|
-
.filter(isDefined);
|
|
865
|
-
return getExampleOrExamples(flattenedExamples);
|
|
866
|
-
}
|
|
867
|
-
function getExampleOrExamples(examples) {
|
|
868
|
-
if (examples.length === 0) {
|
|
869
|
-
return {};
|
|
870
|
-
}
|
|
871
|
-
if (examples.length === 1 &&
|
|
872
|
-
examples[0][0].title === undefined &&
|
|
873
|
-
examples[0][0].description === undefined) {
|
|
874
|
-
const [example, type] = examples[0];
|
|
875
|
-
return { example: serializeValueAsJson(program, example.value, type) };
|
|
876
|
-
}
|
|
877
|
-
else {
|
|
878
|
-
const exampleObj = {};
|
|
879
|
-
for (const [index, [example, type]] of examples.entries()) {
|
|
880
|
-
exampleObj[example.title ?? `example${index}`] = {
|
|
881
|
-
summary: example.title,
|
|
882
|
-
description: example.description,
|
|
883
|
-
value: serializeValueAsJson(program, example.value, type),
|
|
884
|
-
};
|
|
885
|
-
}
|
|
886
|
-
return { examples: exampleObj };
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
function getBodyContentEntry(operation, target, body, visibility, contentType) {
|
|
743
|
+
function getBodyContentEntry(body, visibility, contentType, examples) {
|
|
890
744
|
const isBinary = isBinaryPayload(body.type, contentType);
|
|
891
745
|
if (isBinary) {
|
|
892
746
|
return { schema: { type: "string", format: "binary" } };
|
|
893
747
|
}
|
|
748
|
+
const oai3Examples = examples && getExampleOrExamples(program, examples);
|
|
894
749
|
switch (body.bodyKind) {
|
|
895
750
|
case "single":
|
|
896
751
|
return {
|
|
897
752
|
schema: getSchemaForSingleBody(body.type, visibility, body.isExplicit && body.containsMetadataAnnotations, contentType.startsWith("multipart/") ? contentType : undefined),
|
|
898
|
-
...
|
|
753
|
+
...oai3Examples,
|
|
899
754
|
};
|
|
900
755
|
case "multipart":
|
|
901
756
|
return {
|
|
902
757
|
...getBodyContentForMultipartBody(body, visibility, contentType),
|
|
903
|
-
...
|
|
758
|
+
...oai3Examples,
|
|
904
759
|
};
|
|
905
760
|
}
|
|
906
761
|
}
|
|
@@ -992,56 +847,57 @@ function createOAPIEmitter(context, options) {
|
|
|
992
847
|
}
|
|
993
848
|
return false;
|
|
994
849
|
}
|
|
995
|
-
function
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
}
|
|
1006
|
-
const refUrl = getRef(program, property);
|
|
1007
|
-
if (refUrl) {
|
|
1008
|
-
return {
|
|
1009
|
-
$ref: refUrl,
|
|
850
|
+
function getParameter(parameter, visibility) {
|
|
851
|
+
const param = {
|
|
852
|
+
name: parameter.name,
|
|
853
|
+
in: parameter.type,
|
|
854
|
+
...getOpenAPIParameterBase(parameter.param, visibility),
|
|
855
|
+
};
|
|
856
|
+
const format = mapParameterFormat(parameter);
|
|
857
|
+
if (format === undefined) {
|
|
858
|
+
param.schema = {
|
|
859
|
+
type: "string",
|
|
1010
860
|
};
|
|
1011
861
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
}
|
|
1015
|
-
const placeholder = {};
|
|
1016
|
-
// only parameters inherited by spreading from non-inlined type are shared in #/components/parameters
|
|
1017
|
-
if (spreadParam && property.model && !shouldInline(program, property.model)) {
|
|
1018
|
-
params.set(property, placeholder);
|
|
1019
|
-
paramModels.add(property.model);
|
|
862
|
+
else {
|
|
863
|
+
Object.assign(param, format);
|
|
1020
864
|
}
|
|
1021
|
-
return
|
|
865
|
+
return param;
|
|
1022
866
|
}
|
|
1023
|
-
function
|
|
867
|
+
function getEndpointParameters(parameters, visibility) {
|
|
868
|
+
const result = [];
|
|
1024
869
|
for (const httpOpParam of parameters) {
|
|
1025
870
|
if (params.has(httpOpParam.param)) {
|
|
1026
|
-
|
|
871
|
+
result.push(params.get(httpOpParam.param));
|
|
1027
872
|
continue;
|
|
1028
873
|
}
|
|
874
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
1029
875
|
if (httpOpParam.type === "header" && isContentTypeHeader(program, httpOpParam.param)) {
|
|
1030
876
|
continue;
|
|
1031
877
|
}
|
|
1032
|
-
|
|
878
|
+
const param = getParameterOrRef(httpOpParam, visibility);
|
|
879
|
+
if (param) {
|
|
880
|
+
const existing = result.find((x) => !("$ref" in param) && !("$ref" in x) && x.name === param.name && x.in === param.in);
|
|
881
|
+
if (existing && !("$ref" in param) && !("$ref" in existing)) {
|
|
882
|
+
mergeOpenApiParameters(existing, param);
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
result.push(param);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
1033
888
|
}
|
|
889
|
+
return result;
|
|
1034
890
|
}
|
|
1035
|
-
function
|
|
1036
|
-
if (bodies === undefined) {
|
|
1037
|
-
return;
|
|
891
|
+
function getRequestBody(bodies, visibility, examples) {
|
|
892
|
+
if (bodies === undefined || bodies.every((x) => isVoidType(x.type))) {
|
|
893
|
+
return undefined;
|
|
1038
894
|
}
|
|
1039
895
|
const requestBody = {
|
|
1040
|
-
|
|
896
|
+
required: bodies.every((body) => (body.property ? !body.property.optional : true)),
|
|
1041
897
|
content: {},
|
|
1042
898
|
};
|
|
1043
899
|
const schemaMap = new Map();
|
|
1044
|
-
for (const body of bodies) {
|
|
900
|
+
for (const body of bodies.filter((x) => !isVoidType(x.type))) {
|
|
1045
901
|
const desc = body.property ? getDoc(program, body.property) : undefined;
|
|
1046
902
|
if (desc) {
|
|
1047
903
|
requestBody.description = requestBody.description
|
|
@@ -1050,67 +906,67 @@ function createOAPIEmitter(context, options) {
|
|
|
1050
906
|
}
|
|
1051
907
|
const contentTypes = body.contentTypes.length > 0 ? body.contentTypes : ["application/json"];
|
|
1052
908
|
for (const contentType of contentTypes) {
|
|
1053
|
-
const
|
|
1054
|
-
|
|
1055
|
-
|
|
909
|
+
const existing = schemaMap.get(contentType);
|
|
910
|
+
const entry = getBodyContentEntry(body, visibility, contentType, examples.requestBody[contentType]);
|
|
911
|
+
if (existing) {
|
|
912
|
+
existing.push(entry);
|
|
1056
913
|
}
|
|
1057
914
|
else {
|
|
1058
|
-
schemaMap.set(contentType, [
|
|
915
|
+
schemaMap.set(contentType, [entry]);
|
|
1059
916
|
}
|
|
1060
917
|
}
|
|
1061
918
|
}
|
|
1062
|
-
const content = {};
|
|
1063
919
|
for (const [contentType, schemaArray] of schemaMap) {
|
|
1064
920
|
if (schemaArray.length === 1) {
|
|
1065
|
-
content[contentType] =
|
|
921
|
+
requestBody.content[contentType] = schemaArray[0];
|
|
1066
922
|
}
|
|
1067
923
|
else {
|
|
1068
|
-
content[contentType] = {
|
|
1069
|
-
schema: { anyOf: schemaArray },
|
|
924
|
+
requestBody.content[contentType] = {
|
|
925
|
+
schema: { anyOf: schemaArray.map((x) => x.schema).filter((x) => x !== undefined) },
|
|
926
|
+
encoding: schemaArray.find((x) => x.encoding)?.encoding,
|
|
1070
927
|
};
|
|
1071
928
|
}
|
|
1072
929
|
}
|
|
1073
|
-
requestBody
|
|
1074
|
-
currentEndpoint.requestBody = requestBody;
|
|
930
|
+
return requestBody;
|
|
1075
931
|
}
|
|
1076
|
-
function
|
|
1077
|
-
if (
|
|
1078
|
-
return;
|
|
932
|
+
function getParameterOrRef(parameter, visibility) {
|
|
933
|
+
if (isNeverType(parameter.param.type)) {
|
|
934
|
+
return undefined;
|
|
1079
935
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
936
|
+
let spreadParam = false;
|
|
937
|
+
let property = parameter.param;
|
|
938
|
+
if (property.sourceProperty) {
|
|
939
|
+
// chase our sources all the way back to the first place this property
|
|
940
|
+
// was defined.
|
|
941
|
+
spreadParam = true;
|
|
942
|
+
property = property.sourceProperty;
|
|
943
|
+
while (property.sourceProperty) {
|
|
944
|
+
property = property.sourceProperty;
|
|
945
|
+
}
|
|
1088
946
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
947
|
+
const refUrl = getRef(program, property);
|
|
948
|
+
if (refUrl) {
|
|
949
|
+
return {
|
|
950
|
+
$ref: refUrl,
|
|
951
|
+
};
|
|
1094
952
|
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
populateParameter(existing, parameter, visibility);
|
|
953
|
+
if (params.has(property)) {
|
|
954
|
+
return params.get(property);
|
|
1098
955
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
populateParameter(ph, parameter, visibility);
|
|
1105
|
-
}
|
|
956
|
+
const param = getParameter(parameter, visibility);
|
|
957
|
+
// only parameters inherited by spreading from non-inlined type are shared in #/components/parameters
|
|
958
|
+
if (spreadParam && property.model && !shouldInline(program, property.model)) {
|
|
959
|
+
params.set(property, param);
|
|
960
|
+
paramModels.add(property.model);
|
|
1106
961
|
}
|
|
962
|
+
return param;
|
|
1107
963
|
}
|
|
1108
964
|
function getOpenAPIParameterBase(param, visibility) {
|
|
1109
965
|
const typeSchema = getSchemaForType(param.type, visibility);
|
|
1110
966
|
if (!typeSchema) {
|
|
1111
967
|
return undefined;
|
|
1112
968
|
}
|
|
1113
|
-
const schema = applyEncoding(param, applyIntrinsicDecorators(param, typeSchema));
|
|
969
|
+
const schema = applyEncoding(program, param, applyIntrinsicDecorators(param, typeSchema), options);
|
|
1114
970
|
if (param.defaultValue) {
|
|
1115
971
|
schema.default = getDefaultValue(program, param.defaultValue);
|
|
1116
972
|
}
|
|
@@ -1124,35 +980,18 @@ function createOAPIEmitter(context, options) {
|
|
|
1124
980
|
attachExtensions(program, param, oaiParam);
|
|
1125
981
|
return oaiParam;
|
|
1126
982
|
}
|
|
1127
|
-
function mergeOpenApiParameters(
|
|
1128
|
-
if (
|
|
1129
|
-
const schema =
|
|
1130
|
-
if (schema.enum &&
|
|
1131
|
-
schema.enum = [...new Set([...schema.enum, ...
|
|
983
|
+
function mergeOpenApiParameters(target, apply) {
|
|
984
|
+
if (target.schema) {
|
|
985
|
+
const schema = target.schema;
|
|
986
|
+
if (schema.enum && apply.schema.enum) {
|
|
987
|
+
schema.enum = [...new Set([...schema.enum, ...apply.schema.enum])];
|
|
1132
988
|
}
|
|
1133
|
-
|
|
989
|
+
target.schema = schema;
|
|
1134
990
|
}
|
|
1135
991
|
else {
|
|
1136
|
-
Object.assign(
|
|
1137
|
-
}
|
|
1138
|
-
return param;
|
|
1139
|
-
}
|
|
1140
|
-
function populateParameter(ph, parameter, visibility) {
|
|
1141
|
-
ph.name = parameter.name;
|
|
1142
|
-
ph.in = parameter.type;
|
|
1143
|
-
const paramBase = getOpenAPIParameterBase(parameter.param, visibility);
|
|
1144
|
-
if (paramBase) {
|
|
1145
|
-
ph = mergeOpenApiParameters(ph, paramBase);
|
|
1146
|
-
}
|
|
1147
|
-
const format = mapParameterFormat(parameter);
|
|
1148
|
-
if (format === undefined) {
|
|
1149
|
-
ph.schema = {
|
|
1150
|
-
type: "string",
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
|
-
else {
|
|
1154
|
-
Object.assign(ph, format);
|
|
992
|
+
Object.assign(target, apply);
|
|
1155
993
|
}
|
|
994
|
+
return target;
|
|
1156
995
|
}
|
|
1157
996
|
function mapParameterFormat(parameter) {
|
|
1158
997
|
switch (parameter.type) {
|
|
@@ -1333,44 +1172,6 @@ function createOAPIEmitter(context, options) {
|
|
|
1333
1172
|
attachExtensions(program, typespecType, newTarget);
|
|
1334
1173
|
return newTarget;
|
|
1335
1174
|
}
|
|
1336
|
-
function applyEncoding(typespecType, target) {
|
|
1337
|
-
const encodeData = getEncode(program, typespecType);
|
|
1338
|
-
if (encodeData) {
|
|
1339
|
-
const newTarget = { ...target };
|
|
1340
|
-
const newType = callSchemaEmitter(encodeData.type, Visibility.Read, false, "application/json");
|
|
1341
|
-
newTarget.type = newType.type;
|
|
1342
|
-
// If the target already has a format it takes priority. (e.g. int32)
|
|
1343
|
-
newTarget.format = mergeFormatAndEncoding(newTarget.format, encodeData.encoding, newType.format);
|
|
1344
|
-
return newTarget;
|
|
1345
|
-
}
|
|
1346
|
-
return target;
|
|
1347
|
-
}
|
|
1348
|
-
function mergeFormatAndEncoding(format, encoding, encodeAsFormat) {
|
|
1349
|
-
switch (format) {
|
|
1350
|
-
case undefined:
|
|
1351
|
-
return encodeAsFormat ?? encoding;
|
|
1352
|
-
case "date-time":
|
|
1353
|
-
switch (encoding) {
|
|
1354
|
-
case "rfc3339":
|
|
1355
|
-
return "date-time";
|
|
1356
|
-
case "unixTimestamp":
|
|
1357
|
-
return "unixtime";
|
|
1358
|
-
case "rfc7231":
|
|
1359
|
-
return "http-date";
|
|
1360
|
-
default:
|
|
1361
|
-
return encoding;
|
|
1362
|
-
}
|
|
1363
|
-
case "duration":
|
|
1364
|
-
switch (encoding) {
|
|
1365
|
-
case "ISO8601":
|
|
1366
|
-
return "duration";
|
|
1367
|
-
default:
|
|
1368
|
-
return encodeAsFormat ?? encoding;
|
|
1369
|
-
}
|
|
1370
|
-
default:
|
|
1371
|
-
return encodeAsFormat ?? encoding;
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
1175
|
function applyExternalDocs(typespecType, target) {
|
|
1375
1176
|
const externalDocs = getExternalDocs(program, typespecType);
|
|
1376
1177
|
if (externalDocs) {
|
|
@@ -1406,14 +1207,15 @@ function createOAPIEmitter(context, options) {
|
|
|
1406
1207
|
});
|
|
1407
1208
|
return security;
|
|
1408
1209
|
}
|
|
1409
|
-
function
|
|
1210
|
+
function getEndpointSecurity(authReference) {
|
|
1410
1211
|
const security = getOpenAPISecurity(authReference);
|
|
1411
1212
|
if (deepEquals(security, root.security)) {
|
|
1412
|
-
return;
|
|
1213
|
+
return undefined;
|
|
1413
1214
|
}
|
|
1414
1215
|
if (security.length > 0) {
|
|
1415
|
-
|
|
1216
|
+
return security;
|
|
1416
1217
|
}
|
|
1218
|
+
return undefined;
|
|
1417
1219
|
}
|
|
1418
1220
|
function getOpenAPI3Scheme(auth) {
|
|
1419
1221
|
const scheme = getOpenAPI3SchemeInternal(auth);
|