@kubb/adapter-oas 5.0.0-beta.61 → 5.0.0-beta.62
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 +88 -85
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +88 -85
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/dialect.ts +28 -6
- package/src/parser.ts +69 -57
- package/src/stream.ts +28 -47
package/dist/index.cjs
CHANGED
|
@@ -837,6 +837,23 @@ function dereferenceWithRef(document, schema) {
|
|
|
837
837
|
//#endregion
|
|
838
838
|
//#region src/dialect.ts
|
|
839
839
|
/**
|
|
840
|
+
* Derives a schema's `optional`/`nullish` flags from a parent's `required` value and the
|
|
841
|
+
* schema's own `nullable`. How "required" and "nullable" combine is OpenAPI-specific, so it
|
|
842
|
+
* lives in the dialect.
|
|
843
|
+
*
|
|
844
|
+
* - Non-required + non-nullable → `optional: true`.
|
|
845
|
+
* - Non-required + nullable → `nullish: true`.
|
|
846
|
+
* - Required → both flags cleared.
|
|
847
|
+
*/
|
|
848
|
+
function optionality(schema, required) {
|
|
849
|
+
const nullable = schema.nullable ?? false;
|
|
850
|
+
return {
|
|
851
|
+
...schema,
|
|
852
|
+
optional: !required && !nullable ? true : void 0,
|
|
853
|
+
nullish: !required && nullable ? true : void 0
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
840
857
|
* The OpenAPI / Swagger dialect, the default used by `@kubb/adapter-oas`.
|
|
841
858
|
*
|
|
842
859
|
* Implements the spec-agnostic {@link ast.SchemaDialect} contract: it isolates the
|
|
@@ -855,13 +872,16 @@ function dereferenceWithRef(document, schema) {
|
|
|
855
872
|
* const parser = createSchemaParser(context, oasDialect) // explicit
|
|
856
873
|
* ```
|
|
857
874
|
*/
|
|
858
|
-
const oasDialect = _kubb_core.ast.
|
|
875
|
+
const oasDialect = _kubb_core.ast.defineDialect({
|
|
859
876
|
name: "oas",
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
877
|
+
schema: {
|
|
878
|
+
isNullable,
|
|
879
|
+
isReference,
|
|
880
|
+
isDiscriminator,
|
|
881
|
+
isBinary: (schema) => schema.type === "string" && schema.contentMediaType === "application/octet-stream",
|
|
882
|
+
resolveRef,
|
|
883
|
+
optionality
|
|
884
|
+
}
|
|
865
885
|
});
|
|
866
886
|
//#endregion
|
|
867
887
|
//#region src/discriminator.ts
|
|
@@ -1584,6 +1604,21 @@ function normalizeArrayEnum(schema) {
|
|
|
1584
1604
|
};
|
|
1585
1605
|
}
|
|
1586
1606
|
/**
|
|
1607
|
+
* Builds a `null` scalar node carrying the schema's documentation. Shared by the `const: null`
|
|
1608
|
+
* and the drf-spectacular `NullEnum` (`{ enum: [null] }`) branches, which render identically.
|
|
1609
|
+
*/
|
|
1610
|
+
function createNullSchema(schema, name) {
|
|
1611
|
+
return _kubb_core.ast.factory.createSchema({
|
|
1612
|
+
type: "null",
|
|
1613
|
+
primitive: "null",
|
|
1614
|
+
name,
|
|
1615
|
+
title: schema.title,
|
|
1616
|
+
description: schema.description,
|
|
1617
|
+
deprecated: schema.deprecated,
|
|
1618
|
+
format: schema.format
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1587
1622
|
* Names the inline enums on a property's schema, and on each item when the property is a tuple, from
|
|
1588
1623
|
* the parent and property name. Wraps `macroEnumName` at the property construction site.
|
|
1589
1624
|
*/
|
|
@@ -1639,7 +1674,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1639
1674
|
if (refPath && !resolvingRefs.has(refPath)) {
|
|
1640
1675
|
if (!resolvedRefCache.has(refPath)) {
|
|
1641
1676
|
try {
|
|
1642
|
-
const referenced = dialect.resolveRef(document, refPath);
|
|
1677
|
+
const referenced = dialect.schema.resolveRef(document, refPath);
|
|
1643
1678
|
if (referenced) {
|
|
1644
1679
|
resolvingRefs.add(refPath);
|
|
1645
1680
|
resolvedSchema = parseSchema({ schema: referenced }, rawOptions);
|
|
@@ -1688,13 +1723,13 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1688
1723
|
}
|
|
1689
1724
|
const filteredDiscriminantValues = [];
|
|
1690
1725
|
const allOfMembers = schema.allOf.filter((item) => {
|
|
1691
|
-
if (!dialect.isReference(item) || !name) return true;
|
|
1692
|
-
const deref = dialect.resolveRef(document, item.$ref);
|
|
1693
|
-
if (!deref || !dialect.isDiscriminator(deref)) return true;
|
|
1726
|
+
if (!dialect.schema.isReference(item) || !name) return true;
|
|
1727
|
+
const deref = dialect.schema.resolveRef(document, item.$ref);
|
|
1728
|
+
if (!deref || !dialect.schema.isDiscriminator(deref)) return true;
|
|
1694
1729
|
const parentUnion = deref.oneOf ?? deref.anyOf;
|
|
1695
1730
|
if (!parentUnion) return true;
|
|
1696
1731
|
const childRef = `${SCHEMA_REF_PREFIX}${name}`;
|
|
1697
|
-
const inOneOf = parentUnion.some((oneOfItem) => dialect.isReference(oneOfItem) && oneOfItem.$ref === childRef);
|
|
1732
|
+
const inOneOf = parentUnion.some((oneOfItem) => dialect.schema.isReference(oneOfItem) && oneOfItem.$ref === childRef);
|
|
1698
1733
|
const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
|
|
1699
1734
|
if (inOneOf || inMapping) {
|
|
1700
1735
|
const discriminatorValue = findDiscriminator(deref.discriminator.mapping, childRef);
|
|
@@ -1715,9 +1750,9 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1715
1750
|
const missingRequired = schema.required.filter((key) => !outerKeys.has(key));
|
|
1716
1751
|
if (missingRequired.length) {
|
|
1717
1752
|
const resolvedMembers = schema.allOf.flatMap((item) => {
|
|
1718
|
-
if (!dialect.isReference(item)) return [item];
|
|
1719
|
-
const deref = dialect.resolveRef(document, item.$ref);
|
|
1720
|
-
return deref && !dialect.isReference(deref) ? [deref] : [];
|
|
1753
|
+
if (!dialect.schema.isReference(item)) return [item];
|
|
1754
|
+
const deref = dialect.schema.resolveRef(document, item.$ref);
|
|
1755
|
+
return deref && !dialect.schema.isReference(deref) ? [deref] : [];
|
|
1721
1756
|
});
|
|
1722
1757
|
for (const key of missingRequired) for (const resolved of resolvedMembers) if (resolved.properties?.[key]) {
|
|
1723
1758
|
allOfMembers.push(parseSchema({
|
|
@@ -1762,10 +1797,10 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1762
1797
|
const strategy = schema.oneOf ? "one" : "any";
|
|
1763
1798
|
const unionBase = {
|
|
1764
1799
|
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1765
|
-
discriminatorPropertyName: dialect.isDiscriminator(schema) ? schema.discriminator.propertyName : void 0,
|
|
1800
|
+
discriminatorPropertyName: dialect.schema.isDiscriminator(schema) ? schema.discriminator.propertyName : void 0,
|
|
1766
1801
|
strategy
|
|
1767
1802
|
};
|
|
1768
|
-
const discriminator = dialect.isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1803
|
+
const discriminator = dialect.schema.isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1769
1804
|
const sharedPropertiesNode = schema.properties ? (() => {
|
|
1770
1805
|
const { oneOf: _oneOf, anyOf: _anyOf, ...schemaWithoutUnion } = schema;
|
|
1771
1806
|
return parseSchema({
|
|
@@ -1775,7 +1810,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1775
1810
|
})() : void 0;
|
|
1776
1811
|
if (sharedPropertiesNode || discriminator?.mapping) {
|
|
1777
1812
|
const members = unionMembers.map((s) => {
|
|
1778
|
-
const ref = dialect.isReference(s) ? s.$ref : void 0;
|
|
1813
|
+
const ref = dialect.schema.isReference(s) ? s.$ref : void 0;
|
|
1779
1814
|
const discriminatorValue = findDiscriminator(discriminator?.mapping, ref);
|
|
1780
1815
|
const memberNode = parseSchema({
|
|
1781
1816
|
schema: s,
|
|
@@ -1821,15 +1856,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1821
1856
|
*/
|
|
1822
1857
|
function convertConst({ schema, name, nullable, defaultValue }) {
|
|
1823
1858
|
const constValue = schema.const;
|
|
1824
|
-
if (constValue === null) return
|
|
1825
|
-
type: "null",
|
|
1826
|
-
primitive: "null",
|
|
1827
|
-
name,
|
|
1828
|
-
title: schema.title,
|
|
1829
|
-
description: schema.description,
|
|
1830
|
-
deprecated: schema.deprecated,
|
|
1831
|
-
format: schema.format
|
|
1832
|
-
});
|
|
1859
|
+
if (constValue === null) return createNullSchema(schema, name);
|
|
1833
1860
|
const constPrimitive = getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string");
|
|
1834
1861
|
return _kubb_core.ast.factory.createSchema({
|
|
1835
1862
|
type: "enum",
|
|
@@ -1918,15 +1945,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1918
1945
|
}, rawOptions);
|
|
1919
1946
|
const nullInEnum = schema.enum.includes(null);
|
|
1920
1947
|
const filteredValues = nullInEnum ? schema.enum.filter((v) => v !== null) : schema.enum;
|
|
1921
|
-
if (nullInEnum && filteredValues.length === 0) return
|
|
1922
|
-
type: "null",
|
|
1923
|
-
primitive: "null",
|
|
1924
|
-
name,
|
|
1925
|
-
title: schema.title,
|
|
1926
|
-
description: schema.description,
|
|
1927
|
-
deprecated: schema.deprecated,
|
|
1928
|
-
format: schema.format
|
|
1929
|
-
});
|
|
1948
|
+
if (nullInEnum && filteredValues.length === 0) return createNullSchema(schema, name);
|
|
1930
1949
|
const enumNullable = nullable || nullInEnum || void 0;
|
|
1931
1950
|
const enumDefault = schema.default === null && enumNullable ? void 0 : schema.default;
|
|
1932
1951
|
const enumPrimitive = getPrimitiveType(type);
|
|
@@ -1976,7 +1995,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1976
1995
|
const properties = schema.properties ? Object.entries(schema.properties).map(([propName, propSchema]) => {
|
|
1977
1996
|
const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
|
|
1978
1997
|
const resolvedPropSchema = propSchema;
|
|
1979
|
-
const propNullable = dialect.isNullable(resolvedPropSchema);
|
|
1998
|
+
const propNullable = dialect.schema.isNullable(resolvedPropSchema);
|
|
1980
1999
|
const schemaNode = nameEnums(parseSchema({
|
|
1981
2000
|
schema: resolvedPropSchema,
|
|
1982
2001
|
name: (0, _kubb_ast_utils.childName)(name, propName)
|
|
@@ -1992,7 +2011,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1992
2011
|
nullable: schemaNode.type === "null" ? void 0 : propNullable || void 0
|
|
1993
2012
|
},
|
|
1994
2013
|
required
|
|
1995
|
-
});
|
|
2014
|
+
}, dialect);
|
|
1996
2015
|
}) : [];
|
|
1997
2016
|
const additionalProperties = schema.additionalProperties;
|
|
1998
2017
|
const additionalPropertiesNode = (() => {
|
|
@@ -2013,7 +2032,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2013
2032
|
maxProperties: schema.maxProperties,
|
|
2014
2033
|
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
2015
2034
|
});
|
|
2016
|
-
if (dialect.isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
2035
|
+
if (dialect.schema.isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
2017
2036
|
const discPropName = schema.discriminator.propertyName;
|
|
2018
2037
|
const values = Object.keys(schema.discriminator.mapping);
|
|
2019
2038
|
const enumName = name ? (0, _kubb_ast_utils.enumPropName)(name, discPropName, options.enumSuffix) : void 0;
|
|
@@ -2157,7 +2176,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2157
2176
|
const schemaRules = [
|
|
2158
2177
|
{
|
|
2159
2178
|
name: "ref",
|
|
2160
|
-
match: ({ schema }) => dialect.isReference(schema),
|
|
2179
|
+
match: ({ schema }) => dialect.schema.isReference(schema),
|
|
2161
2180
|
convert: convertRef
|
|
2162
2181
|
},
|
|
2163
2182
|
{
|
|
@@ -2182,7 +2201,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2182
2201
|
},
|
|
2183
2202
|
{
|
|
2184
2203
|
name: "blob",
|
|
2185
|
-
match: ({ schema }) => dialect.isBinary(schema),
|
|
2204
|
+
match: ({ schema }) => dialect.schema.isBinary(schema),
|
|
2186
2205
|
convert: convertBlob
|
|
2187
2206
|
},
|
|
2188
2207
|
{
|
|
@@ -2263,7 +2282,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2263
2282
|
schema: flattenedSchema,
|
|
2264
2283
|
name
|
|
2265
2284
|
}, rawOptions);
|
|
2266
|
-
const nullable = dialect.isNullable(schema) || void 0;
|
|
2285
|
+
const nullable = dialect.schema.isNullable(schema) || void 0;
|
|
2267
2286
|
const schemaCtx = {
|
|
2268
2287
|
schema,
|
|
2269
2288
|
name,
|
|
@@ -2306,7 +2325,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2306
2325
|
description: param["description"] ?? schema.description
|
|
2307
2326
|
},
|
|
2308
2327
|
required
|
|
2309
|
-
});
|
|
2328
|
+
}, dialect);
|
|
2310
2329
|
}
|
|
2311
2330
|
/**
|
|
2312
2331
|
* Reads the inline `requestBody` metadata (description / required) that OAS exposes
|
|
@@ -2340,7 +2359,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2340
2359
|
const keys = [];
|
|
2341
2360
|
for (const key in schema.properties) {
|
|
2342
2361
|
const prop = schema.properties[key];
|
|
2343
|
-
if (prop && !dialect.isReference(prop) && prop[flag]) keys.push(key);
|
|
2362
|
+
if (prop && !dialect.schema.isReference(prop) && prop[flag]) keys.push(key);
|
|
2344
2363
|
}
|
|
2345
2364
|
return keys.length ? keys : null;
|
|
2346
2365
|
}
|
|
@@ -2357,14 +2376,14 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2357
2376
|
const content = allContentTypes.flatMap((ct) => {
|
|
2358
2377
|
const schema = getRequestSchema(document, operation, { contentType: ct });
|
|
2359
2378
|
if (!schema) return [];
|
|
2360
|
-
return [{
|
|
2379
|
+
return [_kubb_core.ast.factory.createContent({
|
|
2361
2380
|
contentType: ct,
|
|
2362
|
-
schema:
|
|
2381
|
+
schema: dialect.schema.optionality(parseSchema({
|
|
2363
2382
|
schema,
|
|
2364
2383
|
name: requestBodyName
|
|
2365
2384
|
}, options), requestBodyMeta.required),
|
|
2366
2385
|
keysToOmit: collectPropertyKeysByFlag(schema, "readOnly")
|
|
2367
|
-
}];
|
|
2386
|
+
})];
|
|
2368
2387
|
});
|
|
2369
2388
|
const requestBody = content.length > 0 || requestBodyMeta.description ? {
|
|
2370
2389
|
description: requestBodyMeta.description,
|
|
@@ -2389,17 +2408,17 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2389
2408
|
keysToOmit: collectPropertyKeysByFlag(raw, "writeOnly")
|
|
2390
2409
|
};
|
|
2391
2410
|
};
|
|
2392
|
-
const content = (ctx.contentType ? [ctx.contentType] : getResponseBodyContentTypes(document, operation, statusCode)).map((contentType) => ({
|
|
2411
|
+
const content = (ctx.contentType ? [ctx.contentType] : getResponseBodyContentTypes(document, operation, statusCode)).map((contentType) => _kubb_core.ast.factory.createContent({
|
|
2393
2412
|
contentType,
|
|
2394
2413
|
...parseEntrySchema(contentType)
|
|
2395
2414
|
}));
|
|
2396
|
-
if (content.length === 0) content.push({
|
|
2415
|
+
if (content.length === 0) content.push(_kubb_core.ast.factory.createContent({
|
|
2397
2416
|
contentType: getRequestContentType({
|
|
2398
2417
|
document,
|
|
2399
2418
|
operation
|
|
2400
2419
|
}) || "application/json",
|
|
2401
2420
|
...parseEntrySchema(ctx.contentType)
|
|
2402
|
-
});
|
|
2421
|
+
}));
|
|
2403
2422
|
return _kubb_core.ast.factory.createResponse({
|
|
2404
2423
|
statusCode,
|
|
2405
2424
|
description,
|
|
@@ -2407,7 +2426,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2407
2426
|
});
|
|
2408
2427
|
});
|
|
2409
2428
|
const pathItem = document.paths?.[operation.path];
|
|
2410
|
-
const pathItemDoc = pathItem && !dialect.isReference(pathItem) ? pathItem : void 0;
|
|
2429
|
+
const pathItemDoc = pathItem && !dialect.schema.isReference(pathItem) ? pathItem : void 0;
|
|
2411
2430
|
const pickDoc = (key) => {
|
|
2412
2431
|
const own = operation.schema[key];
|
|
2413
2432
|
if (typeof own === "string") return own;
|
|
@@ -2492,36 +2511,6 @@ function visit(node, pointer) {
|
|
|
2492
2511
|
//#endregion
|
|
2493
2512
|
//#region src/stream.ts
|
|
2494
2513
|
/**
|
|
2495
|
-
* Builds the deduplication plan from the already-parsed top-level schema nodes plus a
|
|
2496
|
-
* single extra parse pass over operations (so duplicates in request/response bodies are seen).
|
|
2497
|
-
*
|
|
2498
|
-
* Only enums and objects are candidates, and object shapes that reference a circular schema are
|
|
2499
|
-
* rejected to avoid hoisting recursive structures. Inline shapes reuse their context-derived
|
|
2500
|
-
* name (collision-resolved against existing component names). Shapes without a name stay inline.
|
|
2501
|
-
*/
|
|
2502
|
-
function createDedupePlan({ schemaNodes, operationNodes, schemaNames, circularNames }) {
|
|
2503
|
-
const circularSchemas = new Set(circularNames);
|
|
2504
|
-
const usedNames = new Set(schemaNames);
|
|
2505
|
-
return _kubb_core.ast.buildDedupePlan([...schemaNodes, ...operationNodes], {
|
|
2506
|
-
isCandidate: (node) => {
|
|
2507
|
-
if (node.type === "enum") return true;
|
|
2508
|
-
if (node.type !== "object") return false;
|
|
2509
|
-
if (node.name && circularSchemas.has(node.name)) return false;
|
|
2510
|
-
return !(0, _kubb_ast_utils.containsCircularRef)(node, { circularSchemas });
|
|
2511
|
-
},
|
|
2512
|
-
nameFor: (node) => {
|
|
2513
|
-
const base = node.name;
|
|
2514
|
-
if (!base) return null;
|
|
2515
|
-
let name = base;
|
|
2516
|
-
let counter = 2;
|
|
2517
|
-
while (usedNames.has(name)) name = `${base}${counter++}`;
|
|
2518
|
-
usedNames.add(name);
|
|
2519
|
-
return name;
|
|
2520
|
-
},
|
|
2521
|
-
refFor: (name) => `${SCHEMA_REF_PREFIX}${name}`
|
|
2522
|
-
});
|
|
2523
|
-
}
|
|
2524
|
-
/**
|
|
2525
2514
|
* Reads the server URL from the document's `servers` array at `serverIndex`,
|
|
2526
2515
|
* interpolating any `serverVariables` into the URL template.
|
|
2527
2516
|
*
|
|
@@ -2590,11 +2579,25 @@ function preScan({ schemas, parseSchema, parseOperation, document, parserOptions
|
|
|
2590
2579
|
const operationNode = parseOperation(parserOptions, operation);
|
|
2591
2580
|
if (operationNode) operationNodes.push(operationNode);
|
|
2592
2581
|
}
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2582
|
+
const circularSchemas = new Set(circularNames);
|
|
2583
|
+
const usedNames = new Set(Object.keys(schemas));
|
|
2584
|
+
dedupePlan = _kubb_core.ast.buildDedupePlan([...allNodes, ...operationNodes], {
|
|
2585
|
+
isCandidate: (node) => {
|
|
2586
|
+
if (node.type === "enum") return true;
|
|
2587
|
+
if (node.type !== "object") return false;
|
|
2588
|
+
if (node.name && circularSchemas.has(node.name)) return false;
|
|
2589
|
+
return !(0, _kubb_ast_utils.containsCircularRef)(node, { circularSchemas });
|
|
2590
|
+
},
|
|
2591
|
+
nameFor: (node) => {
|
|
2592
|
+
const base = node.name;
|
|
2593
|
+
if (!base) return null;
|
|
2594
|
+
let name = base;
|
|
2595
|
+
let counter = 2;
|
|
2596
|
+
while (usedNames.has(name)) name = `${base}${counter++}`;
|
|
2597
|
+
usedNames.add(name);
|
|
2598
|
+
return name;
|
|
2599
|
+
},
|
|
2600
|
+
refFor: (name) => `${SCHEMA_REF_PREFIX}${name}`
|
|
2598
2601
|
});
|
|
2599
2602
|
for (const definition of dedupePlan.hoisted) if (definition.type === "enum" && definition.name) enumNames.push(definition.name);
|
|
2600
2603
|
}
|