@kubb/adapter-oas 5.16.1 → 5.17.1
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/index.cjs +102 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +102 -59
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ var compatibility = {
|
|
|
19
19
|
"node": ">=22.22"
|
|
20
20
|
};
|
|
21
21
|
// package.json
|
|
22
|
-
var version = "5.
|
|
22
|
+
var version = "5.17.1";
|
|
23
23
|
// src/constants.ts
|
|
24
24
|
/**
|
|
25
25
|
* Default parser options applied when no explicit options are provided.
|
|
@@ -429,17 +429,32 @@ function isBinary(schema) {
|
|
|
429
429
|
return schema.contentMediaType === "application/octet-stream" && schema.contentEncoding === void 0 && (schema.type === void 0 || schema.type === "string");
|
|
430
430
|
}
|
|
431
431
|
/**
|
|
432
|
+
* Keywords that only annotate a schema. A schema with nothing else does not constrain the value.
|
|
433
|
+
*/
|
|
434
|
+
const annotationKeywords = /* @__PURE__ */ new Set([
|
|
435
|
+
"title",
|
|
436
|
+
"description",
|
|
437
|
+
"default",
|
|
438
|
+
"example",
|
|
439
|
+
"examples",
|
|
440
|
+
"deprecated",
|
|
441
|
+
"readOnly",
|
|
442
|
+
"writeOnly",
|
|
443
|
+
"externalDocs"
|
|
444
|
+
]);
|
|
445
|
+
/**
|
|
432
446
|
* Returns the binary schema for a non-JSON entry the OAS 3.1 upgrade emptied out, or `undefined`
|
|
433
447
|
* when the entry carries a schema of its own. The upgrade rewrites `format: 'binary'` into
|
|
434
448
|
* `contentMediaType` and drops it whenever it only repeats the media type key, for any binary
|
|
435
449
|
* media type (`application/octet-stream`, `application/pdf`, `image/png`, ...), not just
|
|
436
450
|
* `application/octet-stream`. Without the fallback such a body resolves to the empty schema type
|
|
437
|
-
* instead of a blob.
|
|
451
|
+
* instead of a blob. Annotations such as `description` survive the upgrade and are kept.
|
|
438
452
|
*/
|
|
439
453
|
function getBinaryFallbackSchema(mediaType, schema) {
|
|
440
454
|
if (!mediaType || isJsonMimeType(mediaType)) return void 0;
|
|
441
|
-
if (schema && Object.keys(schema).
|
|
455
|
+
if (schema && Object.keys(schema).some((key) => !annotationKeywords.has(key) && !key.startsWith("x-"))) return void 0;
|
|
442
456
|
return {
|
|
457
|
+
...schema,
|
|
443
458
|
type: "string",
|
|
444
459
|
contentMediaType: "application/octet-stream"
|
|
445
460
|
};
|
|
@@ -1204,6 +1219,30 @@ function resolveServerUrl(server, overrides) {
|
|
|
1204
1219
|
}
|
|
1205
1220
|
return url;
|
|
1206
1221
|
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Maps OpenAPI servers to `InputServer` entries: drops entries without a `url` and fills `{variable}` defaults.
|
|
1224
|
+
*/
|
|
1225
|
+
function toInputServers(servers) {
|
|
1226
|
+
return servers.filter((entry) => entry.url).map(({ url, description, variables }) => {
|
|
1227
|
+
const declared = variables && Object.keys(variables).length > 0 ? { variables } : {};
|
|
1228
|
+
try {
|
|
1229
|
+
return {
|
|
1230
|
+
url: resolveServerUrl({
|
|
1231
|
+
url,
|
|
1232
|
+
variables
|
|
1233
|
+
}),
|
|
1234
|
+
description,
|
|
1235
|
+
...declared
|
|
1236
|
+
};
|
|
1237
|
+
} catch {
|
|
1238
|
+
return {
|
|
1239
|
+
url,
|
|
1240
|
+
description,
|
|
1241
|
+
...declared
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1207
1246
|
// src/model/mediaType.ts
|
|
1208
1247
|
/**
|
|
1209
1248
|
* The media type without its parameters, so `text/event-stream; charset=utf-8` matches the bare name.
|
|
@@ -1385,6 +1424,39 @@ function flattenSchema(schema) {
|
|
|
1385
1424
|
function scanSchema(node, pointer = node.pointer) {
|
|
1386
1425
|
if (pointer) visit(node, pointer);
|
|
1387
1426
|
}
|
|
1427
|
+
let formatTally;
|
|
1428
|
+
/**
|
|
1429
|
+
* Runs `fn` and reports `KUBB_UNSUPPORTED_FORMAT` once per format with the number of schemas that use it,
|
|
1430
|
+
* instead of once per schema. `format` is an open value in OpenAPI, so a large spec would otherwise print
|
|
1431
|
+
* thousands of warnings that say the same thing. `fn` must be synchronous.
|
|
1432
|
+
*/
|
|
1433
|
+
function groupUnsupportedFormats(fn) {
|
|
1434
|
+
formatTally = /* @__PURE__ */ new Map();
|
|
1435
|
+
try {
|
|
1436
|
+
return fn();
|
|
1437
|
+
} finally {
|
|
1438
|
+
const tally = formatTally;
|
|
1439
|
+
formatTally = void 0;
|
|
1440
|
+
for (const [format, pointers] of tally) reportUnsupportedFormat(format, [...pointers]);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
function tallyFormat(format, pointer) {
|
|
1444
|
+
if (!formatTally) return reportUnsupportedFormat(format, [pointer]);
|
|
1445
|
+
formatTally.set(format, (formatTally.get(format) ?? /* @__PURE__ */ new Set()).add(pointer));
|
|
1446
|
+
}
|
|
1447
|
+
function reportUnsupportedFormat(format, pointers) {
|
|
1448
|
+
const count = pointers.length;
|
|
1449
|
+
Diagnostics.report({
|
|
1450
|
+
code: Diagnostics.code.unsupportedFormat,
|
|
1451
|
+
severity: "warning",
|
|
1452
|
+
message: count === 1 ? `Kubb does not map the format "${format}" to a specific type, so it falls back to the base type.` : `Kubb does not map the format "${format}" to a specific type, so ${count} schemas fall back to the base type.`,
|
|
1453
|
+
help: `Use a format Kubb supports, or handle "${format}" with a custom parser or plugin.`,
|
|
1454
|
+
location: {
|
|
1455
|
+
kind: "schema",
|
|
1456
|
+
pointer: pointers[0]
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1388
1460
|
function visit(node, pointer) {
|
|
1389
1461
|
node.pointer ??= pointer;
|
|
1390
1462
|
if (node.deprecated) Diagnostics.report({
|
|
@@ -1396,16 +1468,7 @@ function visit(node, pointer) {
|
|
|
1396
1468
|
pointer
|
|
1397
1469
|
}
|
|
1398
1470
|
});
|
|
1399
|
-
if (typeof node.format === "string" && !isHandledFormat(node.format))
|
|
1400
|
-
code: Diagnostics.code.unsupportedFormat,
|
|
1401
|
-
severity: "warning",
|
|
1402
|
-
message: `Kubb does not map the format "${node.format}" to a specific type, so it falls back to the base type.`,
|
|
1403
|
-
help: `Use a format Kubb supports, or handle "${node.format}" with a custom parser or plugin.`,
|
|
1404
|
-
location: {
|
|
1405
|
-
kind: "schema",
|
|
1406
|
-
pointer
|
|
1407
|
-
}
|
|
1408
|
-
});
|
|
1471
|
+
if (typeof node.format === "string" && !isHandledFormat(node.format)) tallyFormat(node.format, pointer);
|
|
1409
1472
|
if (node.type === "object") {
|
|
1410
1473
|
for (const property of node.properties) visit(property.schema, `${pointer}/properties/${escapePointerToken(property.name)}`);
|
|
1411
1474
|
if (node.additionalProperties && typeof node.additionalProperties === "object") visit(node.additionalProperties, `${pointer}/additionalProperties`);
|
|
@@ -1514,18 +1577,6 @@ function getResponseByStatusCode({ operation, refs, statusCode }) {
|
|
|
1514
1577
|
function getRequestBody({ operation, refs }) {
|
|
1515
1578
|
return refs.deref(operation.schema.requestBody);
|
|
1516
1579
|
}
|
|
1517
|
-
/**
|
|
1518
|
-
* Returns the primary request content type. Prefers a JSON-like media type (the last one wins
|
|
1519
|
-
* when several are declared), then the first declared one, defaulting to `'application/json'`.
|
|
1520
|
-
*/
|
|
1521
|
-
function getRequestContentType({ operation, refs }) {
|
|
1522
|
-
const content = getRequestBody({
|
|
1523
|
-
operation,
|
|
1524
|
-
refs
|
|
1525
|
-
})?.content;
|
|
1526
|
-
const mediaTypes = content ? Object.keys(content) : [];
|
|
1527
|
-
return mediaTypes.findLast(isJsonMimeType) ?? mediaTypes[0] ?? "application/json";
|
|
1528
|
-
}
|
|
1529
1580
|
/** Merges path-level and operation-level parameters; operation-level wins per `in:name`. */
|
|
1530
1581
|
function getParameters({ operation, refs }) {
|
|
1531
1582
|
const resolveParams = (params, pointer) => params.flatMap((entry, index) => {
|
|
@@ -1788,15 +1839,13 @@ function parseOperation({ operation, ...ctx }) {
|
|
|
1788
1839
|
}) : {}
|
|
1789
1840
|
};
|
|
1790
1841
|
};
|
|
1791
|
-
const
|
|
1842
|
+
const declaredContentTypes = Object.keys(response?.content ?? {});
|
|
1843
|
+
const responseContent = (contentType && declaredContentTypes.length ? [contentType] : declaredContentTypes).map((ct) => ast.factory.createContent({
|
|
1792
1844
|
contentType: ct,
|
|
1793
1845
|
...parseEntrySchema(ct)
|
|
1794
1846
|
}));
|
|
1795
1847
|
if (responseContent.length === 0) responseContent.push(ast.factory.createContent({
|
|
1796
|
-
contentType:
|
|
1797
|
-
operation,
|
|
1798
|
-
refs
|
|
1799
|
-
}),
|
|
1848
|
+
contentType: "",
|
|
1800
1849
|
...parseEntrySchema(contentType)
|
|
1801
1850
|
}));
|
|
1802
1851
|
return ast.factory.createResponse({
|
|
@@ -1812,6 +1861,7 @@ function parseOperation({ operation, ...ctx }) {
|
|
|
1812
1861
|
const fallback = operation.pathItem[key];
|
|
1813
1862
|
return typeof fallback === "string" ? fallback : void 0;
|
|
1814
1863
|
};
|
|
1864
|
+
const servers = operation.schema.servers ?? operation.pathItem.servers;
|
|
1815
1865
|
return ast.factory.createOperation({
|
|
1816
1866
|
pointer,
|
|
1817
1867
|
operationId,
|
|
@@ -1825,7 +1875,8 @@ function parseOperation({ operation, ...ctx }) {
|
|
|
1825
1875
|
parameters,
|
|
1826
1876
|
requestBody,
|
|
1827
1877
|
responses,
|
|
1828
|
-
extensions: pickExtensions(operation.schema)
|
|
1878
|
+
extensions: pickExtensions(operation.schema),
|
|
1879
|
+
...servers && { servers: toInputServers(servers) }
|
|
1829
1880
|
});
|
|
1830
1881
|
}
|
|
1831
1882
|
// src/emit/createNode.ts
|
|
@@ -1974,6 +2025,15 @@ function removeInheritedDiscriminator({ members, refs }) {
|
|
|
1974
2025
|
});
|
|
1975
2026
|
}
|
|
1976
2027
|
/**
|
|
2028
|
+
* Whether a member can carry the discriminator property. A discriminator is only a hint, so an array
|
|
2029
|
+
* or primitive member keeps its own type instead of an intersection no value can satisfy.
|
|
2030
|
+
*/
|
|
2031
|
+
function isObjectLike(member, refs) {
|
|
2032
|
+
const type = (isReference(member) ? refs.resolve(member.$ref, { report: false }) : member)?.type;
|
|
2033
|
+
if (type === void 0) return true;
|
|
2034
|
+
return Array.isArray(type) ? type.includes("object") : type === "object";
|
|
2035
|
+
}
|
|
2036
|
+
/**
|
|
1977
2037
|
* Narrows each `oneOf`/`anyOf` member with its discriminant value, intersecting the member's own
|
|
1978
2038
|
* node with either the shared-properties slice carrying that value, or a synthetic discriminant
|
|
1979
2039
|
* literal. The referenced child schema's own definition is left untouched — narrowing happens only
|
|
@@ -2036,7 +2096,7 @@ function narrowUnionMembers({ unionMembers, discriminator, sharedPropertiesNode,
|
|
|
2036
2096
|
schema: s,
|
|
2037
2097
|
name
|
|
2038
2098
|
});
|
|
2039
|
-
if (!discriminatorValues.length || !discriminator) return memberNode;
|
|
2099
|
+
if (!discriminatorValues.length || !discriminator || !isObjectLike(s, refs)) return memberNode;
|
|
2040
2100
|
const narrowedDiscriminatorNode = sharedPropertiesNode ? pickDiscriminatorPropertyNode(ast.applyMacros(sharedPropertiesNode, [macroDiscriminatorEnum({
|
|
2041
2101
|
propertyName: discriminator.propertyName,
|
|
2042
2102
|
values: discriminatorValues
|
|
@@ -3384,25 +3444,7 @@ const adapterOas = defineExtension({
|
|
|
3384
3444
|
document,
|
|
3385
3445
|
server
|
|
3386
3446
|
}),
|
|
3387
|
-
servers: (document.servers ?? [])
|
|
3388
|
-
const declared = variables && Object.keys(variables).length > 0 ? { variables } : {};
|
|
3389
|
-
try {
|
|
3390
|
-
return {
|
|
3391
|
-
url: resolveServerUrl({
|
|
3392
|
-
url,
|
|
3393
|
-
variables
|
|
3394
|
-
}),
|
|
3395
|
-
description,
|
|
3396
|
-
...declared
|
|
3397
|
-
};
|
|
3398
|
-
} catch {
|
|
3399
|
-
return {
|
|
3400
|
-
url,
|
|
3401
|
-
description,
|
|
3402
|
-
...declared
|
|
3403
|
-
};
|
|
3404
|
-
}
|
|
3405
|
-
}),
|
|
3447
|
+
servers: toInputServers(document.servers ?? []),
|
|
3406
3448
|
securitySchemes: Object.entries(document.components?.securitySchemes ?? {}).flatMap(([name, value]) => {
|
|
3407
3449
|
const scheme = refs.deref(value);
|
|
3408
3450
|
return scheme?.type ? [{
|
|
@@ -3455,18 +3497,19 @@ const adapterOas = defineExtension({
|
|
|
3455
3497
|
parsedDocument = document;
|
|
3456
3498
|
const refs = createRefs(document);
|
|
3457
3499
|
const { schemas, renames, pointers } = getSchemas(document, { contentType }, refs);
|
|
3458
|
-
|
|
3500
|
+
const parseSchema = createSchemaParser({
|
|
3501
|
+
document,
|
|
3502
|
+
refs,
|
|
3503
|
+
renames,
|
|
3504
|
+
options: parserOptions
|
|
3505
|
+
});
|
|
3506
|
+
return groupUnsupportedFormats(() => parseInput({
|
|
3459
3507
|
document,
|
|
3460
3508
|
refs,
|
|
3461
3509
|
schemas,
|
|
3462
3510
|
pointers,
|
|
3463
|
-
parseSchema
|
|
3464
|
-
|
|
3465
|
-
refs,
|
|
3466
|
-
renames,
|
|
3467
|
-
options: parserOptions
|
|
3468
|
-
})
|
|
3469
|
-
});
|
|
3511
|
+
parseSchema
|
|
3512
|
+
}));
|
|
3470
3513
|
})();
|
|
3471
3514
|
inputCache.set(source, {
|
|
3472
3515
|
promise,
|