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