@kubb/adapter-oas 5.0.0-beta.57 → 5.0.0-beta.59
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 +178 -137
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +9 -11
- package/dist/index.js +177 -136
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/adapter.ts +2 -2
- package/src/constants.ts +3 -3
- package/src/discriminator.ts +42 -2
- package/src/parser.ts +64 -55
- package/src/resolvers.ts +1 -1
- package/src/stream.ts +7 -6
- package/src/types.ts +9 -11
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { access, readFile } from "node:fs/promises";
|
|
|
5
5
|
import { compileErrors, validate } from "@readme/openapi-parser";
|
|
6
6
|
import { parse } from "yaml";
|
|
7
7
|
import { bundle } from "api-ref-bundler";
|
|
8
|
-
import { childName, enumPropName, extractRefName,
|
|
8
|
+
import { childName, containsCircularRef, enumPropName, extractRefName, findCircularSchemas } from "@kubb/ast/utils";
|
|
9
9
|
import { collect, narrowSchema } from "@kubb/ast";
|
|
10
10
|
//#region src/constants.ts
|
|
11
11
|
/**
|
|
@@ -91,7 +91,7 @@ const structuralKeys = new Set([
|
|
|
91
91
|
*
|
|
92
92
|
* Only formats whose AST type differs from the OAS `type` field appear here.
|
|
93
93
|
* Formats that depend on runtime options (`int64`, `date-time`, `date`, `time`) are handled separately
|
|
94
|
-
* in the parser. `ipv4` and `ipv6` map to their own dedicated schema types
|
|
94
|
+
* in the parser. `ipv4` and `ipv6` map to their own dedicated schema types. `hostname` and
|
|
95
95
|
* `idn-hostname` map to `'url'` as the closest generic string-format type.
|
|
96
96
|
*
|
|
97
97
|
* @example
|
|
@@ -144,8 +144,8 @@ const formatMap = {
|
|
|
144
144
|
*/
|
|
145
145
|
const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
|
|
146
146
|
/**
|
|
147
|
-
* Maps
|
|
148
|
-
*
|
|
147
|
+
* Maps the `unknownType`/`emptySchemaType` option string to its `ScalarSchemaType` constant.
|
|
148
|
+
* A `Map` (over a plain object) lets callers test key membership with `.has()`.
|
|
149
149
|
*/
|
|
150
150
|
const typeOptionMap = new Map([
|
|
151
151
|
["any", ast.schemaTypes.any],
|
|
@@ -840,6 +840,120 @@ const oasDialect = ast.defineSchemaDialect({
|
|
|
840
840
|
resolveRef
|
|
841
841
|
});
|
|
842
842
|
//#endregion
|
|
843
|
+
//#region src/discriminator.ts
|
|
844
|
+
/**
|
|
845
|
+
* Builds a map of child schema names → discriminator patch data by scanning the given
|
|
846
|
+
* top-level AST schema nodes for union schemas that carry a `discriminatorPropertyName`.
|
|
847
|
+
*
|
|
848
|
+
* The streaming path calls this on a small pre-parsed subset of schemas (only the
|
|
849
|
+
* discriminator parents) rather than on all schemas at once.
|
|
850
|
+
*/
|
|
851
|
+
function buildDiscriminatorChildMap(schemas) {
|
|
852
|
+
const childMap = /* @__PURE__ */ new Map();
|
|
853
|
+
for (const schema of schemas) {
|
|
854
|
+
let unionNode = ast.narrowSchema(schema, "union");
|
|
855
|
+
if (!unionNode) {
|
|
856
|
+
const intersectionMembers = ast.narrowSchema(schema, "intersection")?.members;
|
|
857
|
+
if (intersectionMembers) for (const m of intersectionMembers) {
|
|
858
|
+
const u = ast.narrowSchema(m, "union");
|
|
859
|
+
if (u) {
|
|
860
|
+
unionNode = u;
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
if (!unionNode?.discriminatorPropertyName || !unionNode.members) continue;
|
|
866
|
+
const { discriminatorPropertyName, members } = unionNode;
|
|
867
|
+
for (const member of members) {
|
|
868
|
+
const intersectionNode = ast.narrowSchema(member, "intersection");
|
|
869
|
+
if (!intersectionNode?.members) continue;
|
|
870
|
+
let refNode = null;
|
|
871
|
+
let objNode = null;
|
|
872
|
+
for (const m of intersectionNode.members) {
|
|
873
|
+
refNode ??= ast.narrowSchema(m, "ref");
|
|
874
|
+
objNode ??= ast.narrowSchema(m, "object");
|
|
875
|
+
}
|
|
876
|
+
if (!refNode?.name || !objNode) continue;
|
|
877
|
+
const prop = objNode.properties.find((p) => p.name === discriminatorPropertyName);
|
|
878
|
+
const enumNode = prop ? ast.narrowSchema(prop.schema, "enum") : null;
|
|
879
|
+
if (!enumNode?.enumValues?.length) continue;
|
|
880
|
+
const enumValues = enumNode.enumValues.filter((v) => v !== null);
|
|
881
|
+
if (!enumValues.length) continue;
|
|
882
|
+
const existing = childMap.get(refNode.name);
|
|
883
|
+
if (!existing) {
|
|
884
|
+
childMap.set(refNode.name, {
|
|
885
|
+
propertyName: discriminatorPropertyName,
|
|
886
|
+
enumValues: [...enumValues]
|
|
887
|
+
});
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
existing.enumValues.push(...enumValues);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
return childMap;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Patches a single top-level `SchemaNode` with its discriminator entry (adds or replaces
|
|
897
|
+
* the discriminant property). Used by the streaming path to apply patches inline per yield
|
|
898
|
+
* without buffering all schemas.
|
|
899
|
+
*/
|
|
900
|
+
function patchDiscriminatorNode(node, entry) {
|
|
901
|
+
const objectNode = ast.narrowSchema(node, "object");
|
|
902
|
+
if (!objectNode) return node;
|
|
903
|
+
const { propertyName, enumValues } = entry;
|
|
904
|
+
const enumSchema = ast.factory.createSchema({
|
|
905
|
+
type: "enum",
|
|
906
|
+
enumValues
|
|
907
|
+
});
|
|
908
|
+
const newProp = ast.factory.createProperty({
|
|
909
|
+
name: propertyName,
|
|
910
|
+
required: true,
|
|
911
|
+
schema: enumSchema
|
|
912
|
+
});
|
|
913
|
+
const existingIdx = objectNode.properties.findIndex((p) => p.name === propertyName);
|
|
914
|
+
const newProperties = existingIdx >= 0 ? objectNode.properties.map((p, i) => i === existingIdx ? newProp : p) : [...objectNode.properties, newProp];
|
|
915
|
+
return {
|
|
916
|
+
...objectNode,
|
|
917
|
+
properties: newProperties
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Creates a single-property object schema used as a discriminator literal.
|
|
922
|
+
*
|
|
923
|
+
* @example
|
|
924
|
+
* ```ts
|
|
925
|
+
* createDiscriminantNode({ propertyName: 'type', value: 'dog' })
|
|
926
|
+
* // -> { type: 'object', properties: [{ name: 'type', required: true, schema: enum('dog') }] }
|
|
927
|
+
* ```
|
|
928
|
+
*/
|
|
929
|
+
function createDiscriminantNode({ propertyName, value }) {
|
|
930
|
+
return ast.factory.createSchema({
|
|
931
|
+
type: "object",
|
|
932
|
+
primitive: "object",
|
|
933
|
+
properties: [ast.factory.createProperty({
|
|
934
|
+
name: propertyName,
|
|
935
|
+
schema: ast.factory.createSchema({
|
|
936
|
+
type: "enum",
|
|
937
|
+
primitive: "string",
|
|
938
|
+
enumValues: [value]
|
|
939
|
+
}),
|
|
940
|
+
required: true
|
|
941
|
+
})]
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.
|
|
946
|
+
*
|
|
947
|
+
* @example
|
|
948
|
+
* ```ts
|
|
949
|
+
* findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'
|
|
950
|
+
* ```
|
|
951
|
+
*/
|
|
952
|
+
function findDiscriminator(mapping, ref) {
|
|
953
|
+
if (!mapping || !ref) return null;
|
|
954
|
+
return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null;
|
|
955
|
+
}
|
|
956
|
+
//#endregion
|
|
843
957
|
//#region src/mime.ts
|
|
844
958
|
/**
|
|
845
959
|
* MIME type fragments that mark a media type as JSON-like.
|
|
@@ -1328,7 +1442,7 @@ function getSchemas(document, { contentType }) {
|
|
|
1328
1442
|
}
|
|
1329
1443
|
/**
|
|
1330
1444
|
* Resolves the AST type descriptor for a date/time format, honoring the `dateType` option.
|
|
1331
|
-
* Returns `null` when `dateType: false`,
|
|
1445
|
+
* Returns `null` when `dateType: false`, so the format falls through to `string`.
|
|
1332
1446
|
*/
|
|
1333
1447
|
function getDateType(options, format) {
|
|
1334
1448
|
if (!options.dateType) return null;
|
|
@@ -1430,9 +1544,9 @@ function getResponseBodyContentTypes(document, operation, statusCode) {
|
|
|
1430
1544
|
* Normalizes malformed `{ type: 'array', enum: [...] }` schemas by moving enum values into items.
|
|
1431
1545
|
*
|
|
1432
1546
|
* This pattern violates the OpenAPI spec but appears in real specs. The fix moves enum values
|
|
1433
|
-
* from the array to its items sub-schema,
|
|
1547
|
+
* from the array to its items sub-schema, so they are valid for downstream processing.
|
|
1434
1548
|
*
|
|
1435
|
-
* @note
|
|
1549
|
+
* @note A defensive measure for non-compliant specs.
|
|
1436
1550
|
*/
|
|
1437
1551
|
function normalizeArrayEnum(schema) {
|
|
1438
1552
|
const normalizedItems = {
|
|
@@ -1450,7 +1564,7 @@ function normalizeArrayEnum(schema) {
|
|
|
1450
1564
|
*
|
|
1451
1565
|
* Returns closures that share mutable state (`resolvingRefs` set for cycle detection).
|
|
1452
1566
|
* Each converter branch (`convertRef`, `convertAllOf`, etc.) mutually recursively calls `parseSchema`,
|
|
1453
|
-
*
|
|
1567
|
+
* which works because function declarations hoist.
|
|
1454
1568
|
*
|
|
1455
1569
|
* @internal
|
|
1456
1570
|
*/
|
|
@@ -1495,7 +1609,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1495
1609
|
}
|
|
1496
1610
|
resolvedSchema = resolvedRefCache.get(refPath) ?? null;
|
|
1497
1611
|
}
|
|
1498
|
-
return ast.createSchema({
|
|
1612
|
+
return ast.factory.createSchema({
|
|
1499
1613
|
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1500
1614
|
type: "ref",
|
|
1501
1615
|
name: extractRefName(schema.$ref),
|
|
@@ -1516,7 +1630,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1516
1630
|
const { kind: _kind, ...memberNodeProps } = memberNode;
|
|
1517
1631
|
const mergedNullable = nullable || memberNode.nullable || void 0;
|
|
1518
1632
|
const mergedDefault = schema.default === null && mergedNullable ? void 0 : schema.default ?? memberNode.default;
|
|
1519
|
-
return ast.createSchema({
|
|
1633
|
+
return ast.factory.createSchema({
|
|
1520
1634
|
...memberNodeProps,
|
|
1521
1635
|
name,
|
|
1522
1636
|
title: schema.title ?? memberNode.title,
|
|
@@ -1580,11 +1694,11 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1580
1694
|
const { allOf: _allOf, ...schemaWithoutAllOf } = schema;
|
|
1581
1695
|
allOfMembers.push(parseSchema({ schema: schemaWithoutAllOf }, rawOptions));
|
|
1582
1696
|
}
|
|
1583
|
-
for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push(
|
|
1697
|
+
for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push(createDiscriminantNode({
|
|
1584
1698
|
propertyName,
|
|
1585
1699
|
value
|
|
1586
1700
|
}));
|
|
1587
|
-
return ast.createSchema({
|
|
1701
|
+
return ast.factory.createSchema({
|
|
1588
1702
|
type: "intersection",
|
|
1589
1703
|
members: [...ast.mergeAdjacentObjectsLazy(allOfMembers.slice(0, syntheticStart)), ...ast.mergeAdjacentObjectsLazy(allOfMembers.slice(syntheticStart))],
|
|
1590
1704
|
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
@@ -1597,7 +1711,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1597
1711
|
function pickDiscriminatorPropertyNode(node, propertyName) {
|
|
1598
1712
|
const discriminatorProperty = ast.narrowSchema(node, "object")?.properties?.find((property) => property.name === propertyName);
|
|
1599
1713
|
if (!discriminatorProperty) return null;
|
|
1600
|
-
return ast.createSchema({
|
|
1714
|
+
return ast.factory.createSchema({
|
|
1601
1715
|
type: "object",
|
|
1602
1716
|
primitive: "object",
|
|
1603
1717
|
properties: [discriminatorProperty]
|
|
@@ -1632,27 +1746,27 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1632
1746
|
propertyName: discriminator.propertyName,
|
|
1633
1747
|
values: [discriminatorValue]
|
|
1634
1748
|
}), discriminator.propertyName) : void 0;
|
|
1635
|
-
return ast.createSchema({
|
|
1749
|
+
return ast.factory.createSchema({
|
|
1636
1750
|
type: "intersection",
|
|
1637
|
-
members: [memberNode, narrowedDiscriminatorNode ??
|
|
1751
|
+
members: [memberNode, narrowedDiscriminatorNode ?? createDiscriminantNode({
|
|
1638
1752
|
propertyName: discriminator.propertyName,
|
|
1639
1753
|
value: discriminatorValue
|
|
1640
1754
|
})]
|
|
1641
1755
|
});
|
|
1642
1756
|
});
|
|
1643
|
-
const unionNode = ast.createSchema({
|
|
1757
|
+
const unionNode = ast.factory.createSchema({
|
|
1644
1758
|
type: "union",
|
|
1645
1759
|
...unionBase,
|
|
1646
1760
|
members
|
|
1647
1761
|
});
|
|
1648
1762
|
if (!sharedPropertiesNode) return unionNode;
|
|
1649
|
-
return ast.createSchema({
|
|
1763
|
+
return ast.factory.createSchema({
|
|
1650
1764
|
type: "intersection",
|
|
1651
1765
|
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1652
1766
|
members: [unionNode, sharedPropertiesNode]
|
|
1653
1767
|
});
|
|
1654
1768
|
}
|
|
1655
|
-
return ast.createSchema({
|
|
1769
|
+
return ast.factory.createSchema({
|
|
1656
1770
|
type: "union",
|
|
1657
1771
|
...unionBase,
|
|
1658
1772
|
members: ast.simplifyUnion(unionMembers.map((s) => parseSchema({
|
|
@@ -1666,7 +1780,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1666
1780
|
*/
|
|
1667
1781
|
function convertConst({ schema, name, nullable, defaultValue }) {
|
|
1668
1782
|
const constValue = schema.const;
|
|
1669
|
-
if (constValue === null) return ast.createSchema({
|
|
1783
|
+
if (constValue === null) return ast.factory.createSchema({
|
|
1670
1784
|
type: "null",
|
|
1671
1785
|
primitive: "null",
|
|
1672
1786
|
name,
|
|
@@ -1676,7 +1790,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1676
1790
|
format: schema.format
|
|
1677
1791
|
});
|
|
1678
1792
|
const constPrimitive = getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string");
|
|
1679
|
-
return ast.createSchema({
|
|
1793
|
+
return ast.factory.createSchema({
|
|
1680
1794
|
type: "enum",
|
|
1681
1795
|
primitive: constPrimitive,
|
|
1682
1796
|
enumValues: [constValue],
|
|
@@ -1689,7 +1803,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1689
1803
|
*/
|
|
1690
1804
|
function convertFormat({ schema, name, nullable, defaultValue, options }) {
|
|
1691
1805
|
const base = buildSchemaNode(schema, name, nullable, defaultValue);
|
|
1692
|
-
if (schema.format === "int64") return ast.createSchema({
|
|
1806
|
+
if (schema.format === "int64") return ast.factory.createSchema({
|
|
1693
1807
|
type: options.integerType === "bigint" ? "bigint" : "integer",
|
|
1694
1808
|
primitive: "integer",
|
|
1695
1809
|
...base,
|
|
@@ -1701,14 +1815,14 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1701
1815
|
if (schema.format === "date-time" || schema.format === "date" || schema.format === "time") {
|
|
1702
1816
|
const dateType = getDateType(options, schema.format);
|
|
1703
1817
|
if (!dateType) return null;
|
|
1704
|
-
if (dateType.type === "datetime") return ast.createSchema({
|
|
1818
|
+
if (dateType.type === "datetime") return ast.factory.createSchema({
|
|
1705
1819
|
...base,
|
|
1706
1820
|
primitive: "string",
|
|
1707
1821
|
type: "datetime",
|
|
1708
1822
|
offset: dateType.offset,
|
|
1709
1823
|
local: dateType.local
|
|
1710
1824
|
});
|
|
1711
|
-
return ast.createSchema({
|
|
1825
|
+
return ast.factory.createSchema({
|
|
1712
1826
|
...base,
|
|
1713
1827
|
primitive: "string",
|
|
1714
1828
|
type: dateType.type,
|
|
@@ -1718,36 +1832,36 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1718
1832
|
const specialType = getSchemaType(schema.format);
|
|
1719
1833
|
if (!specialType) return null;
|
|
1720
1834
|
const specialPrimitive = specialType === "number" || specialType === "integer" || specialType === "bigint" ? specialType : "string";
|
|
1721
|
-
if (specialType === "number" || specialType === "integer" || specialType === "bigint") return ast.createSchema({
|
|
1835
|
+
if (specialType === "number" || specialType === "integer" || specialType === "bigint") return ast.factory.createSchema({
|
|
1722
1836
|
...base,
|
|
1723
1837
|
primitive: specialPrimitive,
|
|
1724
1838
|
type: specialType
|
|
1725
1839
|
});
|
|
1726
|
-
if (specialType === "url") return ast.createSchema({
|
|
1840
|
+
if (specialType === "url") return ast.factory.createSchema({
|
|
1727
1841
|
...base,
|
|
1728
1842
|
primitive: "string",
|
|
1729
1843
|
type: "url",
|
|
1730
1844
|
min: schema.minLength,
|
|
1731
1845
|
max: schema.maxLength
|
|
1732
1846
|
});
|
|
1733
|
-
if (specialType === "ipv4") return ast.createSchema({
|
|
1847
|
+
if (specialType === "ipv4") return ast.factory.createSchema({
|
|
1734
1848
|
...base,
|
|
1735
1849
|
primitive: "string",
|
|
1736
1850
|
type: "ipv4"
|
|
1737
1851
|
});
|
|
1738
|
-
if (specialType === "ipv6") return ast.createSchema({
|
|
1852
|
+
if (specialType === "ipv6") return ast.factory.createSchema({
|
|
1739
1853
|
...base,
|
|
1740
1854
|
primitive: "string",
|
|
1741
1855
|
type: "ipv6"
|
|
1742
1856
|
});
|
|
1743
|
-
if (specialType === "uuid" || specialType === "email") return ast.createSchema({
|
|
1857
|
+
if (specialType === "uuid" || specialType === "email") return ast.factory.createSchema({
|
|
1744
1858
|
...base,
|
|
1745
1859
|
primitive: "string",
|
|
1746
1860
|
type: specialType,
|
|
1747
1861
|
min: schema.minLength,
|
|
1748
1862
|
max: schema.maxLength
|
|
1749
1863
|
});
|
|
1750
|
-
return ast.createSchema({
|
|
1864
|
+
return ast.factory.createSchema({
|
|
1751
1865
|
...base,
|
|
1752
1866
|
primitive: specialPrimitive,
|
|
1753
1867
|
type: specialType
|
|
@@ -1763,7 +1877,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1763
1877
|
}, rawOptions);
|
|
1764
1878
|
const nullInEnum = schema.enum.includes(null);
|
|
1765
1879
|
const filteredValues = nullInEnum ? schema.enum.filter((v) => v !== null) : schema.enum;
|
|
1766
|
-
if (nullInEnum && filteredValues.length === 0) return ast.createSchema({
|
|
1880
|
+
if (nullInEnum && filteredValues.length === 0) return ast.factory.createSchema({
|
|
1767
1881
|
type: "null",
|
|
1768
1882
|
primitive: "null",
|
|
1769
1883
|
name,
|
|
@@ -1795,7 +1909,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1795
1909
|
const rawEnumNames = extensionKey ? schema[extensionKey] : void 0;
|
|
1796
1910
|
const uniqueValues = [...new Set(filteredValues)];
|
|
1797
1911
|
const seenNames = /* @__PURE__ */ new Set();
|
|
1798
|
-
return ast.createSchema({
|
|
1912
|
+
return ast.factory.createSchema({
|
|
1799
1913
|
...enumBase,
|
|
1800
1914
|
primitive: enumPrimitiveType,
|
|
1801
1915
|
namedEnumValues: uniqueValues.map((value, index) => ({
|
|
@@ -1809,7 +1923,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1809
1923
|
})
|
|
1810
1924
|
});
|
|
1811
1925
|
}
|
|
1812
|
-
return ast.createSchema({
|
|
1926
|
+
return ast.factory.createSchema({
|
|
1813
1927
|
...enumBase,
|
|
1814
1928
|
enumValues: [...new Set(filteredValues)]
|
|
1815
1929
|
});
|
|
@@ -1838,7 +1952,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1838
1952
|
}
|
|
1839
1953
|
return node;
|
|
1840
1954
|
})();
|
|
1841
|
-
return ast.createProperty({
|
|
1955
|
+
return ast.factory.createProperty({
|
|
1842
1956
|
name: propName,
|
|
1843
1957
|
schema: {
|
|
1844
1958
|
...schemaNode,
|
|
@@ -1852,11 +1966,11 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1852
1966
|
if (additionalProperties === true) return true;
|
|
1853
1967
|
if (additionalProperties === false) return false;
|
|
1854
1968
|
if (additionalProperties && Object.keys(additionalProperties).length > 0) return parseSchema({ schema: additionalProperties }, rawOptions);
|
|
1855
|
-
if (additionalProperties) return ast.createSchema({ type: typeOptionMap.get(options.unknownType) });
|
|
1969
|
+
if (additionalProperties) return ast.factory.createSchema({ type: typeOptionMap.get(options.unknownType) });
|
|
1856
1970
|
})();
|
|
1857
1971
|
const rawPatternProperties = "patternProperties" in schema ? schema.patternProperties : void 0;
|
|
1858
|
-
const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || typeof patternSchema === "object" && Object.keys(patternSchema).length === 0 ? ast.createSchema({ type: typeOptionMap.get(options.unknownType) }) : parseSchema({ schema: patternSchema }, rawOptions)])) : void 0;
|
|
1859
|
-
const objectNode = ast.createSchema({
|
|
1972
|
+
const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || typeof patternSchema === "object" && Object.keys(patternSchema).length === 0 ? ast.factory.createSchema({ type: typeOptionMap.get(options.unknownType) }) : parseSchema({ schema: patternSchema }, rawOptions)])) : void 0;
|
|
1973
|
+
const objectNode = ast.factory.createSchema({
|
|
1860
1974
|
type: "object",
|
|
1861
1975
|
primitive: "object",
|
|
1862
1976
|
properties,
|
|
@@ -1884,8 +1998,8 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1884
1998
|
*/
|
|
1885
1999
|
function convertTuple({ schema, name, nullable, defaultValue, rawOptions }) {
|
|
1886
2000
|
const tupleItems = (schema.prefixItems ?? []).map((item) => parseSchema({ schema: item }, rawOptions));
|
|
1887
|
-
const rest = schema.items ? parseSchema({ schema: schema.items }, rawOptions) : ast.createSchema({ type: "any" });
|
|
1888
|
-
return ast.createSchema({
|
|
2001
|
+
const rest = schema.items ? parseSchema({ schema: schema.items }, rawOptions) : ast.factory.createSchema({ type: "any" });
|
|
2002
|
+
return ast.factory.createSchema({
|
|
1889
2003
|
type: "tuple",
|
|
1890
2004
|
primitive: "array",
|
|
1891
2005
|
items: tupleItems,
|
|
@@ -1905,7 +2019,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1905
2019
|
schema: rawItems,
|
|
1906
2020
|
name: itemName
|
|
1907
2021
|
}, rawOptions)] : [];
|
|
1908
|
-
return ast.createSchema({
|
|
2022
|
+
return ast.factory.createSchema({
|
|
1909
2023
|
type: "array",
|
|
1910
2024
|
primitive: "array",
|
|
1911
2025
|
items,
|
|
@@ -1919,7 +2033,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1919
2033
|
* Converts a `type: 'string'` schema into a `StringSchemaNode`.
|
|
1920
2034
|
*/
|
|
1921
2035
|
function convertString({ schema, name, nullable, defaultValue }) {
|
|
1922
|
-
return ast.createSchema({
|
|
2036
|
+
return ast.factory.createSchema({
|
|
1923
2037
|
type: "string",
|
|
1924
2038
|
primitive: "string",
|
|
1925
2039
|
min: schema.minLength,
|
|
@@ -1932,7 +2046,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1932
2046
|
* Converts a `type: 'number'` or `type: 'integer'` schema.
|
|
1933
2047
|
*/
|
|
1934
2048
|
function convertNumeric({ schema, name, nullable, defaultValue }, type) {
|
|
1935
|
-
return ast.createSchema({
|
|
2049
|
+
return ast.factory.createSchema({
|
|
1936
2050
|
type,
|
|
1937
2051
|
primitive: type,
|
|
1938
2052
|
min: schema.minimum,
|
|
@@ -1947,7 +2061,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1947
2061
|
* Converts a `type: 'boolean'` schema.
|
|
1948
2062
|
*/
|
|
1949
2063
|
function convertBoolean({ schema, name, nullable, defaultValue }) {
|
|
1950
|
-
return ast.createSchema({
|
|
2064
|
+
return ast.factory.createSchema({
|
|
1951
2065
|
type: "boolean",
|
|
1952
2066
|
primitive: "boolean",
|
|
1953
2067
|
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
@@ -1957,7 +2071,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1957
2071
|
* Converts an explicit `type: 'null'` schema.
|
|
1958
2072
|
*/
|
|
1959
2073
|
function convertNull({ schema, name, nullable }) {
|
|
1960
|
-
return ast.createSchema({
|
|
2074
|
+
return ast.factory.createSchema({
|
|
1961
2075
|
type: "null",
|
|
1962
2076
|
primitive: "null",
|
|
1963
2077
|
name,
|
|
@@ -1973,7 +2087,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1973
2087
|
* into a `blob` node.
|
|
1974
2088
|
*/
|
|
1975
2089
|
function convertBlob({ schema, name, nullable, defaultValue }) {
|
|
1976
|
-
return ast.createSchema({
|
|
2090
|
+
return ast.factory.createSchema({
|
|
1977
2091
|
type: "blob",
|
|
1978
2092
|
primitive: "string",
|
|
1979
2093
|
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
@@ -1990,7 +2104,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1990
2104
|
const nonNullTypes = types.filter((t) => t !== "null");
|
|
1991
2105
|
if (nonNullTypes.length <= 1) return null;
|
|
1992
2106
|
const arrayNullable = types.includes("null") || nullable || void 0;
|
|
1993
|
-
return ast.createSchema({
|
|
2107
|
+
return ast.factory.createSchema({
|
|
1994
2108
|
type: "union",
|
|
1995
2109
|
members: nonNullTypes.map((t) => parseSchema({
|
|
1996
2110
|
schema: {
|
|
@@ -2133,7 +2247,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2133
2247
|
if (node) return node;
|
|
2134
2248
|
}
|
|
2135
2249
|
const emptyType = typeOptionMap.get(options.emptySchemaType);
|
|
2136
|
-
return ast.createSchema({
|
|
2250
|
+
return ast.factory.createSchema({
|
|
2137
2251
|
type: emptyType,
|
|
2138
2252
|
name,
|
|
2139
2253
|
title: schema.title,
|
|
@@ -2151,8 +2265,8 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2151
2265
|
const schema = param["schema"] ? parseSchema({
|
|
2152
2266
|
schema: param["schema"],
|
|
2153
2267
|
name: schemaName
|
|
2154
|
-
}, options) : ast.createSchema({ type: typeOptionMap.get(options.unknownType) });
|
|
2155
|
-
return ast.createParameter({
|
|
2268
|
+
}, options) : ast.factory.createSchema({ type: typeOptionMap.get(options.unknownType) });
|
|
2269
|
+
return ast.factory.createParameter({
|
|
2156
2270
|
name: paramName,
|
|
2157
2271
|
in: param["in"],
|
|
2158
2272
|
schema: {
|
|
@@ -2239,7 +2353,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2239
2353
|
schema: raw && Object.keys(raw).length > 0 ? parseSchema({
|
|
2240
2354
|
schema: raw,
|
|
2241
2355
|
name: responseName
|
|
2242
|
-
}, options) : ast.createSchema({ type: typeOptionMap.get(options.emptySchemaType) }),
|
|
2356
|
+
}, options) : ast.factory.createSchema({ type: typeOptionMap.get(options.emptySchemaType) }),
|
|
2243
2357
|
keysToOmit: collectPropertyKeysByFlag(raw, "writeOnly")
|
|
2244
2358
|
};
|
|
2245
2359
|
};
|
|
@@ -2254,7 +2368,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2254
2368
|
}) || "application/json",
|
|
2255
2369
|
...parseEntrySchema(ctx.contentType)
|
|
2256
2370
|
});
|
|
2257
|
-
return ast.createResponse({
|
|
2371
|
+
return ast.factory.createResponse({
|
|
2258
2372
|
statusCode,
|
|
2259
2373
|
description,
|
|
2260
2374
|
content
|
|
@@ -2268,7 +2382,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2268
2382
|
const fallback = pathItemDoc?.[key];
|
|
2269
2383
|
return typeof fallback === "string" ? fallback : void 0;
|
|
2270
2384
|
};
|
|
2271
|
-
return ast.createOperation({
|
|
2385
|
+
return ast.factory.createOperation({
|
|
2272
2386
|
operationId,
|
|
2273
2387
|
protocol: "http",
|
|
2274
2388
|
method: operation.method.toUpperCase(),
|
|
@@ -2289,84 +2403,6 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2289
2403
|
};
|
|
2290
2404
|
}
|
|
2291
2405
|
//#endregion
|
|
2292
|
-
//#region src/discriminator.ts
|
|
2293
|
-
/**
|
|
2294
|
-
* Builds a map of child schema names → discriminator patch data by scanning the given
|
|
2295
|
-
* top-level AST schema nodes for union schemas that carry a `discriminatorPropertyName`.
|
|
2296
|
-
*
|
|
2297
|
-
* The streaming path calls this on a small pre-parsed subset of schemas (only the
|
|
2298
|
-
* discriminator parents) rather than on all schemas at once.
|
|
2299
|
-
*/
|
|
2300
|
-
function buildDiscriminatorChildMap(schemas) {
|
|
2301
|
-
const childMap = /* @__PURE__ */ new Map();
|
|
2302
|
-
for (const schema of schemas) {
|
|
2303
|
-
let unionNode = ast.narrowSchema(schema, "union");
|
|
2304
|
-
if (!unionNode) {
|
|
2305
|
-
const intersectionMembers = ast.narrowSchema(schema, "intersection")?.members;
|
|
2306
|
-
if (intersectionMembers) for (const m of intersectionMembers) {
|
|
2307
|
-
const u = ast.narrowSchema(m, "union");
|
|
2308
|
-
if (u) {
|
|
2309
|
-
unionNode = u;
|
|
2310
|
-
break;
|
|
2311
|
-
}
|
|
2312
|
-
}
|
|
2313
|
-
}
|
|
2314
|
-
if (!unionNode?.discriminatorPropertyName || !unionNode.members) continue;
|
|
2315
|
-
const { discriminatorPropertyName, members } = unionNode;
|
|
2316
|
-
for (const member of members) {
|
|
2317
|
-
const intersectionNode = ast.narrowSchema(member, "intersection");
|
|
2318
|
-
if (!intersectionNode?.members) continue;
|
|
2319
|
-
let refNode = null;
|
|
2320
|
-
let objNode = null;
|
|
2321
|
-
for (const m of intersectionNode.members) {
|
|
2322
|
-
refNode ??= ast.narrowSchema(m, "ref");
|
|
2323
|
-
objNode ??= ast.narrowSchema(m, "object");
|
|
2324
|
-
}
|
|
2325
|
-
if (!refNode?.name || !objNode) continue;
|
|
2326
|
-
const prop = objNode.properties.find((p) => p.name === discriminatorPropertyName);
|
|
2327
|
-
const enumNode = prop ? ast.narrowSchema(prop.schema, "enum") : null;
|
|
2328
|
-
if (!enumNode?.enumValues?.length) continue;
|
|
2329
|
-
const enumValues = enumNode.enumValues.filter((v) => v !== null);
|
|
2330
|
-
if (!enumValues.length) continue;
|
|
2331
|
-
const existing = childMap.get(refNode.name);
|
|
2332
|
-
if (!existing) {
|
|
2333
|
-
childMap.set(refNode.name, {
|
|
2334
|
-
propertyName: discriminatorPropertyName,
|
|
2335
|
-
enumValues: [...enumValues]
|
|
2336
|
-
});
|
|
2337
|
-
continue;
|
|
2338
|
-
}
|
|
2339
|
-
existing.enumValues.push(...enumValues);
|
|
2340
|
-
}
|
|
2341
|
-
}
|
|
2342
|
-
return childMap;
|
|
2343
|
-
}
|
|
2344
|
-
/**
|
|
2345
|
-
* Patches a single top-level `SchemaNode` with its discriminator entry (adds or replaces
|
|
2346
|
-
* the discriminant property). Used by the streaming path to apply patches inline per yield
|
|
2347
|
-
* without buffering all schemas.
|
|
2348
|
-
*/
|
|
2349
|
-
function patchDiscriminatorNode(node, entry) {
|
|
2350
|
-
const objectNode = ast.narrowSchema(node, "object");
|
|
2351
|
-
if (!objectNode) return node;
|
|
2352
|
-
const { propertyName, enumValues } = entry;
|
|
2353
|
-
const enumSchema = ast.createSchema({
|
|
2354
|
-
type: "enum",
|
|
2355
|
-
enumValues
|
|
2356
|
-
});
|
|
2357
|
-
const newProp = ast.createProperty({
|
|
2358
|
-
name: propertyName,
|
|
2359
|
-
required: true,
|
|
2360
|
-
schema: enumSchema
|
|
2361
|
-
});
|
|
2362
|
-
const existingIdx = objectNode.properties.findIndex((p) => p.name === propertyName);
|
|
2363
|
-
const newProperties = existingIdx >= 0 ? objectNode.properties.map((p, i) => i === existingIdx ? newProp : p) : [...objectNode.properties, newProp];
|
|
2364
|
-
return {
|
|
2365
|
-
...objectNode,
|
|
2366
|
-
properties: newProperties
|
|
2367
|
-
};
|
|
2368
|
-
}
|
|
2369
|
-
//#endregion
|
|
2370
2406
|
//#region src/schemaDiagnostics.ts
|
|
2371
2407
|
/**
|
|
2372
2408
|
* Reports the advisory diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`) for one
|
|
@@ -2429,7 +2465,7 @@ function visit(node, pointer) {
|
|
|
2429
2465
|
*
|
|
2430
2466
|
* Only enums and objects are candidates, and object shapes that reference a circular schema are
|
|
2431
2467
|
* rejected to avoid hoisting recursive structures. Inline shapes reuse their context-derived
|
|
2432
|
-
* name (collision-resolved against existing component names)
|
|
2468
|
+
* name (collision-resolved against existing component names). Shapes without a name stay inline.
|
|
2433
2469
|
*/
|
|
2434
2470
|
function createDedupePlan({ schemaNodes, operationNodes, schemaNames, circularNames }) {
|
|
2435
2471
|
const circularSchemas = new Set(circularNames);
|
|
@@ -2439,7 +2475,7 @@ function createDedupePlan({ schemaNodes, operationNodes, schemaNames, circularNa
|
|
|
2439
2475
|
if (node.type === "enum") return true;
|
|
2440
2476
|
if (node.type !== "object") return false;
|
|
2441
2477
|
if (node.name && circularSchemas.has(node.name)) return false;
|
|
2442
|
-
return !
|
|
2478
|
+
return !containsCircularRef(node, { circularSchemas });
|
|
2443
2479
|
},
|
|
2444
2480
|
nameFor: (node) => {
|
|
2445
2481
|
const base = node.name;
|
|
@@ -2513,7 +2549,7 @@ function preScan({ schemas, parseSchema, parseOperation, document, parserOptions
|
|
|
2513
2549
|
if (ast.narrowSchema(node, ast.schemaTypes.enum) && node.name) enumNames.push(node.name);
|
|
2514
2550
|
if (discriminator === "inherit" && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) discriminatorParentNodes.push(node);
|
|
2515
2551
|
}
|
|
2516
|
-
const circularNames = [...
|
|
2552
|
+
const circularNames = [...findCircularSchemas(allNodes)];
|
|
2517
2553
|
const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null;
|
|
2518
2554
|
let dedupePlan = null;
|
|
2519
2555
|
if (dedupe) {
|
|
@@ -2561,7 +2597,7 @@ function createInputStream({ schemas, parseSchema, parseOperation, document, par
|
|
|
2561
2597
|
const rewriteTopLevelSchema = (node) => {
|
|
2562
2598
|
if (!dedupePlan) return node;
|
|
2563
2599
|
const canonical = dedupePlan.canonicalBySignature.get(ast.signatureOf(node));
|
|
2564
|
-
if (canonical && canonical.name !== node.name) return ast.createSchema({
|
|
2600
|
+
if (canonical && canonical.name !== node.name) return ast.factory.createSchema({
|
|
2565
2601
|
type: "ref",
|
|
2566
2602
|
name: node.name ?? null,
|
|
2567
2603
|
ref: canonical.ref,
|
|
@@ -2602,7 +2638,12 @@ function createInputStream({ schemas, parseSchema, parseOperation, document, par
|
|
|
2602
2638
|
}
|
|
2603
2639
|
})();
|
|
2604
2640
|
} };
|
|
2605
|
-
return ast.
|
|
2641
|
+
return ast.factory.createInput({
|
|
2642
|
+
stream: true,
|
|
2643
|
+
schemas: schemasIterable,
|
|
2644
|
+
operations: operationsIterable,
|
|
2645
|
+
meta
|
|
2646
|
+
});
|
|
2606
2647
|
}
|
|
2607
2648
|
//#endregion
|
|
2608
2649
|
//#region src/adapter.ts
|
|
@@ -2761,7 +2802,7 @@ const adapterOas = createAdapter((options) => {
|
|
|
2761
2802
|
const rawName = extractRefName(schemaRef.ref);
|
|
2762
2803
|
const result = resolve(nameMapping.get(rawName) ?? rawName);
|
|
2763
2804
|
if (!result) return null;
|
|
2764
|
-
return ast.createImport({
|
|
2805
|
+
return ast.factory.createImport({
|
|
2765
2806
|
name: [result.name],
|
|
2766
2807
|
path: result.path
|
|
2767
2808
|
});
|
|
@@ -2770,7 +2811,7 @@ const adapterOas = createAdapter((options) => {
|
|
|
2770
2811
|
async parse(source) {
|
|
2771
2812
|
const streamNode = await createStream(source);
|
|
2772
2813
|
const [schemas, operations] = await Promise.all([Array.fromAsync(streamNode.schemas), Array.fromAsync(streamNode.operations)]);
|
|
2773
|
-
return ast.createInput({
|
|
2814
|
+
return ast.factory.createInput({
|
|
2774
2815
|
schemas,
|
|
2775
2816
|
operations,
|
|
2776
2817
|
meta: streamNode.meta
|