@kubb/adapter-oas 5.0.0-beta.62 → 5.0.0-beta.63
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 +216 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +216 -94
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/adapter.ts +1 -1
- package/src/constants.ts +13 -14
- package/src/dedupe.ts +237 -0
- package/src/dialect.ts +2 -20
- package/src/discriminator.ts +1 -1
- package/src/factory.ts +1 -1
- package/src/mime.ts +2 -3
- package/src/operation.ts +2 -2
- package/src/parser.ts +16 -22
- package/src/refs.ts +4 -3
- package/src/resolvers.ts +13 -5
- package/src/stream.ts +16 -59
- package/src/types.ts +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1250,7 +1250,7 @@ type AdapterOasResolvedOptions = {
|
|
|
1250
1250
|
enumSuffix: AdapterOasOptions['enumSuffix'];
|
|
1251
1251
|
/**
|
|
1252
1252
|
* Map from original `$ref` paths to their collision-resolved schema names.
|
|
1253
|
-
* Populated
|
|
1253
|
+
* Populated once the adapter resolves a spec's schemas, on the first `stream()` or `parse()`.
|
|
1254
1254
|
*
|
|
1255
1255
|
* @example
|
|
1256
1256
|
* ```ts
|
|
@@ -1267,7 +1267,7 @@ type AdapterOas = AdapterFactoryOptions<'oas', AdapterOasOptions, AdapterOasReso
|
|
|
1267
1267
|
//#endregion
|
|
1268
1268
|
//#region src/adapter.d.ts
|
|
1269
1269
|
/**
|
|
1270
|
-
*
|
|
1270
|
+
* The `name` of `@kubb/adapter-oas`, used to identify this adapter in a Kubb config.
|
|
1271
1271
|
*/
|
|
1272
1272
|
declare const adapterOasName = "oas";
|
|
1273
1273
|
/**
|
package/dist/index.js
CHANGED
|
@@ -14,10 +14,9 @@ import { collect, narrowSchema } from "@kubb/ast";
|
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
16
|
* ```ts
|
|
17
|
-
* import { DEFAULT_PARSER_OPTIONS } from '@kubb/adapter-oas'
|
|
17
|
+
* import { DEFAULT_PARSER_OPTIONS, parseOas } from '@kubb/adapter-oas'
|
|
18
18
|
*
|
|
19
|
-
* const
|
|
20
|
-
* const root = parser.parse({ ...DEFAULT_PARSER_OPTIONS, dateType: 'date' })
|
|
19
|
+
* const { root } = parseOas(document, { ...DEFAULT_PARSER_OPTIONS, dateType: 'date' })
|
|
21
20
|
* ```
|
|
22
21
|
*/
|
|
23
22
|
const DEFAULT_PARSER_OPTIONS = {
|
|
@@ -88,12 +87,24 @@ const structuralKeys = new Set([
|
|
|
88
87
|
"not"
|
|
89
88
|
]);
|
|
90
89
|
/**
|
|
90
|
+
* Formats `convertFormat` maps to a dedicated type without going through `formatMap`:
|
|
91
|
+
* `int64` and the date/time family. Keep this in sync with the `convertFormat`
|
|
92
|
+
* special-cases in `parser.ts`. `isHandledFormat` reads it so the
|
|
93
|
+
* `KUBB_UNSUPPORTED_FORMAT` diagnostic and the parser agree on what is handled.
|
|
94
|
+
*/
|
|
95
|
+
const specialCasedFormats = new Set([
|
|
96
|
+
"int64",
|
|
97
|
+
"date-time",
|
|
98
|
+
"date",
|
|
99
|
+
"time"
|
|
100
|
+
]);
|
|
101
|
+
/**
|
|
91
102
|
* Static map from OAS `format` strings to Kubb `SchemaType` values.
|
|
92
103
|
*
|
|
93
104
|
* Only formats whose AST type differs from the OAS `type` field appear here.
|
|
94
|
-
* Formats that depend on runtime options (`int64`, `date-time`, `date`, `time`) are handled
|
|
95
|
-
* in the parser. `ipv4` and `ipv6` map to their own dedicated schema types. `hostname`
|
|
96
|
-
* `idn-hostname` map to `'url'` as the closest generic string-format type.
|
|
105
|
+
* Formats that depend on runtime options (`int64`, `date-time`, `date`, `time`) are handled
|
|
106
|
+
* separately in the parser. `ipv4` and `ipv6` map to their own dedicated schema types. `hostname`
|
|
107
|
+
* and `idn-hostname` map to `'url'` as the closest generic string-format type.
|
|
97
108
|
*
|
|
98
109
|
* @example
|
|
99
110
|
* ```ts
|
|
@@ -104,18 +115,6 @@ const structuralKeys = new Set([
|
|
|
104
115
|
* formatMap['float'] // 'number'
|
|
105
116
|
* ```
|
|
106
117
|
*/
|
|
107
|
-
/**
|
|
108
|
-
* Formats `convertFormat` maps to a dedicated type without going through `formatMap`:
|
|
109
|
-
* `int64` and the date/time family. Keep this in sync with the `convertFormat`
|
|
110
|
-
* special-cases in `parser.ts`. `isHandledFormat` reads it so the
|
|
111
|
-
* `KUBB_UNSUPPORTED_FORMAT` diagnostic and the parser agree on what is handled.
|
|
112
|
-
*/
|
|
113
|
-
const specialCasedFormats = new Set([
|
|
114
|
-
"int64",
|
|
115
|
-
"date-time",
|
|
116
|
-
"date",
|
|
117
|
-
"time"
|
|
118
|
-
]);
|
|
119
118
|
const formatMap = {
|
|
120
119
|
uuid: "uuid",
|
|
121
120
|
email: "email",
|
|
@@ -636,7 +635,7 @@ function isDiscriminator(obj) {
|
|
|
636
635
|
//#endregion
|
|
637
636
|
//#region src/factory.ts
|
|
638
637
|
/**
|
|
639
|
-
* Loads and
|
|
638
|
+
* Loads and bundles an OpenAPI document, returning the raw `Document`.
|
|
640
639
|
*
|
|
641
640
|
* Accepts a file path string or an already-parsed document object. File paths and URLs are
|
|
642
641
|
* bundled via `api-ref-bundler`, hoisting external file schemas into named `components.schemas`
|
|
@@ -747,17 +746,180 @@ async function validateDocument(document, { throwOnError = false } = {}) {
|
|
|
747
746
|
}
|
|
748
747
|
}
|
|
749
748
|
//#endregion
|
|
749
|
+
//#region src/dedupe.ts
|
|
750
|
+
/**
|
|
751
|
+
* Minimum occurrences before a shape is deduplicated.
|
|
752
|
+
*/
|
|
753
|
+
const MIN_OCCURRENCES = 2;
|
|
754
|
+
/**
|
|
755
|
+
* Builds the shared `ref` replacement for a duplicate occurrence, carrying the
|
|
756
|
+
* usage-slot and documentation fields that are not part of the shared type.
|
|
757
|
+
*/
|
|
758
|
+
function createRefNode(node, target) {
|
|
759
|
+
return ast.factory.createSchema({
|
|
760
|
+
type: "ref",
|
|
761
|
+
name: target.name,
|
|
762
|
+
ref: target.ref,
|
|
763
|
+
optional: node.optional,
|
|
764
|
+
nullish: node.nullish,
|
|
765
|
+
readOnly: node.readOnly,
|
|
766
|
+
writeOnly: node.writeOnly,
|
|
767
|
+
deprecated: node.deprecated,
|
|
768
|
+
description: node.description,
|
|
769
|
+
default: node.default,
|
|
770
|
+
example: node.example
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Strips usage-slot flags from an extracted definition and applies its name.
|
|
775
|
+
* A standalone definition is never optional, so `optional`/`nullish` are cleared.
|
|
776
|
+
*/
|
|
777
|
+
function cleanDefinition(node, name) {
|
|
778
|
+
return {
|
|
779
|
+
...node,
|
|
780
|
+
name,
|
|
781
|
+
optional: void 0,
|
|
782
|
+
nullish: void 0
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Returns `true` when a node is eligible for deduplication. Only enums and objects qualify, and
|
|
787
|
+
* object shapes that take part in a circular chain are rejected so recursive structures are not
|
|
788
|
+
* extracted (which would break the cycle).
|
|
789
|
+
*/
|
|
790
|
+
function isCandidate(node, circularSchemas) {
|
|
791
|
+
if (node.type === "enum") return true;
|
|
792
|
+
if (node.type !== "object") return false;
|
|
793
|
+
if (node.name && circularSchemas.has(node.name)) return false;
|
|
794
|
+
return !containsCircularRef(node, { circularSchemas });
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Produces the name for an inline shape with no existing named component, resolving
|
|
798
|
+
* collisions against `usedNames`. Returns `null` for an unnamed shape, which stays inline.
|
|
799
|
+
*/
|
|
800
|
+
function nameFor(node, usedNames) {
|
|
801
|
+
const base = node.name;
|
|
802
|
+
if (!base) return null;
|
|
803
|
+
let name = base;
|
|
804
|
+
let counter = 2;
|
|
805
|
+
while (usedNames.has(name)) name = `${base}${counter++}`;
|
|
806
|
+
usedNames.add(name);
|
|
807
|
+
return name;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Scans a forest of schema and operation nodes and produces a {@link Plan}.
|
|
811
|
+
*
|
|
812
|
+
* A shape that occurs at least {@link MIN_OCCURRENCES} times is deduplicated: if any occurrence is
|
|
813
|
+
* a named top-level schema, the first one becomes the target (so other top-level duplicates and
|
|
814
|
+
* inline copies turn into references to it). Other top-level names with the same content are
|
|
815
|
+
* recorded as aliases. Otherwise a new definition is extracted using {@link nameFor}. The returned
|
|
816
|
+
* plan rewrites nodes against those decisions.
|
|
817
|
+
*
|
|
818
|
+
* @example
|
|
819
|
+
* ```ts
|
|
820
|
+
* const dedupePlan = plan([...schemaNodes, ...operationNodes], { circularSchemas, usedNames })
|
|
821
|
+
* ```
|
|
822
|
+
*/
|
|
823
|
+
function plan(roots, context) {
|
|
824
|
+
const { circularSchemas, usedNames } = context;
|
|
825
|
+
const topLevelNodes = /* @__PURE__ */ new Set();
|
|
826
|
+
const groups = /* @__PURE__ */ new Map();
|
|
827
|
+
for (const root of roots) {
|
|
828
|
+
if (root.kind === "Schema") topLevelNodes.add(root);
|
|
829
|
+
for (const schemaNode of ast.collect(root, { schema: (node) => node })) {
|
|
830
|
+
if (!isCandidate(schemaNode, circularSchemas)) continue;
|
|
831
|
+
const signature = ast.signatureOf(schemaNode);
|
|
832
|
+
const isTopLevel = topLevelNodes.has(schemaNode) && !!schemaNode.name;
|
|
833
|
+
const group = groups.get(signature);
|
|
834
|
+
if (group) {
|
|
835
|
+
group.count++;
|
|
836
|
+
if (isTopLevel) group.topLevelNames.push(schemaNode.name);
|
|
837
|
+
} else groups.set(signature, {
|
|
838
|
+
count: 1,
|
|
839
|
+
representative: schemaNode,
|
|
840
|
+
topLevelNames: isTopLevel ? [schemaNode.name] : []
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
const bySignature = /* @__PURE__ */ new Map();
|
|
845
|
+
const byName = /* @__PURE__ */ new Map();
|
|
846
|
+
const pendingExtractions = [];
|
|
847
|
+
for (const [signature, group] of groups) {
|
|
848
|
+
if (group.count < MIN_OCCURRENCES) continue;
|
|
849
|
+
const [firstName, ...duplicateNames] = group.topLevelNames;
|
|
850
|
+
if (firstName) {
|
|
851
|
+
const target = {
|
|
852
|
+
name: firstName,
|
|
853
|
+
ref: `${SCHEMA_REF_PREFIX}${firstName}`
|
|
854
|
+
};
|
|
855
|
+
bySignature.set(signature, target);
|
|
856
|
+
for (const duplicate of duplicateNames) byName.set(duplicate, target);
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
const name = nameFor(group.representative, usedNames);
|
|
860
|
+
if (!name) continue;
|
|
861
|
+
bySignature.set(signature, {
|
|
862
|
+
name,
|
|
863
|
+
ref: `${SCHEMA_REF_PREFIX}${name}`
|
|
864
|
+
});
|
|
865
|
+
pendingExtractions.push({
|
|
866
|
+
name,
|
|
867
|
+
representative: group.representative
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
function rewrite(node, skipRootMatch) {
|
|
871
|
+
if (bySignature.size === 0 && byName.size === 0) return node;
|
|
872
|
+
const root = node;
|
|
873
|
+
return ast.transform(node, { schema(schemaNode) {
|
|
874
|
+
if (schemaNode.type === "ref") {
|
|
875
|
+
const refName = schemaNode.ref ? extractRefName(schemaNode.ref) : schemaNode.name;
|
|
876
|
+
const target = refName ? byName.get(refName) : void 0;
|
|
877
|
+
return target ? {
|
|
878
|
+
...schemaNode,
|
|
879
|
+
name: target.name,
|
|
880
|
+
ref: target.ref
|
|
881
|
+
} : void 0;
|
|
882
|
+
}
|
|
883
|
+
if (skipRootMatch && schemaNode === root) return void 0;
|
|
884
|
+
const target = bySignature.get(ast.signatureOf(schemaNode));
|
|
885
|
+
if (!target) return void 0;
|
|
886
|
+
return createRefNode(schemaNode, target);
|
|
887
|
+
} });
|
|
888
|
+
}
|
|
889
|
+
return {
|
|
890
|
+
extracted: pendingExtractions.map(({ name, representative }) => cleanDefinition(rewrite(representative, true), name)),
|
|
891
|
+
apply(node) {
|
|
892
|
+
return rewrite(node, false);
|
|
893
|
+
},
|
|
894
|
+
applyTopLevel(node) {
|
|
895
|
+
const target = bySignature.get(ast.signatureOf(node));
|
|
896
|
+
if (target && target.name !== node.name) return ast.factory.createSchema({
|
|
897
|
+
type: "ref",
|
|
898
|
+
name: node.name ?? null,
|
|
899
|
+
ref: target.ref,
|
|
900
|
+
description: node.description,
|
|
901
|
+
deprecated: node.deprecated
|
|
902
|
+
});
|
|
903
|
+
return rewrite(node, true);
|
|
904
|
+
},
|
|
905
|
+
isAlias(name) {
|
|
906
|
+
return byName.has(name);
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
//#endregion
|
|
750
911
|
//#region src/refs.ts
|
|
751
912
|
const _refCache = /* @__PURE__ */ new WeakMap();
|
|
752
913
|
/**
|
|
753
914
|
* Resolves a local JSON pointer reference from a document.
|
|
754
915
|
*
|
|
755
|
-
* Accepts `#/...` refs. Returns `null` for empty or non-local
|
|
756
|
-
*
|
|
916
|
+
* Accepts `#/...` refs. Returns `null` for an empty or non-local ref. When the pointer cannot be
|
|
917
|
+
* resolved, reports a `refNotFound` diagnostic into the active build and returns `null`. Outside a
|
|
918
|
+
* build there is no sink to collect it, so it throws instead.
|
|
757
919
|
*
|
|
758
920
|
* @example
|
|
759
921
|
* ```ts
|
|
760
|
-
* resolveRef<SchemaObject>(document, '#/components/schemas/Pet')
|
|
922
|
+
* resolveRef<SchemaObject>(document, '#/components/schemas/Pet')
|
|
761
923
|
* ```
|
|
762
924
|
*/
|
|
763
925
|
function resolveRef(document, $ref) {
|
|
@@ -814,23 +976,6 @@ function dereferenceWithRef(document, schema) {
|
|
|
814
976
|
//#endregion
|
|
815
977
|
//#region src/dialect.ts
|
|
816
978
|
/**
|
|
817
|
-
* Derives a schema's `optional`/`nullish` flags from a parent's `required` value and the
|
|
818
|
-
* schema's own `nullable`. How "required" and "nullable" combine is OpenAPI-specific, so it
|
|
819
|
-
* lives in the dialect.
|
|
820
|
-
*
|
|
821
|
-
* - Non-required + non-nullable → `optional: true`.
|
|
822
|
-
* - Non-required + nullable → `nullish: true`.
|
|
823
|
-
* - Required → both flags cleared.
|
|
824
|
-
*/
|
|
825
|
-
function optionality(schema, required) {
|
|
826
|
-
const nullable = schema.nullable ?? false;
|
|
827
|
-
return {
|
|
828
|
-
...schema,
|
|
829
|
-
optional: !required && !nullable ? true : void 0,
|
|
830
|
-
nullish: !required && nullable ? true : void 0
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
979
|
* The OpenAPI / Swagger dialect, the default used by `@kubb/adapter-oas`.
|
|
835
980
|
*
|
|
836
981
|
* Implements the spec-agnostic {@link ast.SchemaDialect} contract: it isolates the
|
|
@@ -856,14 +1001,14 @@ const oasDialect = ast.defineDialect({
|
|
|
856
1001
|
isReference,
|
|
857
1002
|
isDiscriminator,
|
|
858
1003
|
isBinary: (schema) => schema.type === "string" && schema.contentMediaType === "application/octet-stream",
|
|
859
|
-
resolveRef
|
|
860
|
-
|
|
861
|
-
}
|
|
1004
|
+
resolveRef
|
|
1005
|
+
},
|
|
1006
|
+
dedupe: { plan }
|
|
862
1007
|
});
|
|
863
1008
|
//#endregion
|
|
864
1009
|
//#region src/discriminator.ts
|
|
865
1010
|
/**
|
|
866
|
-
*
|
|
1011
|
+
* Maps each child schema name to its discriminator patch data by scanning the given
|
|
867
1012
|
* top-level AST schema nodes for union schemas that carry a `discriminatorPropertyName`.
|
|
868
1013
|
*
|
|
869
1014
|
* The streaming path calls this on a small pre-parsed subset of schemas (only the
|
|
@@ -979,9 +1124,8 @@ function findDiscriminator(mapping, ref) {
|
|
|
979
1124
|
/**
|
|
980
1125
|
* MIME type fragments that mark a media type as JSON-like.
|
|
981
1126
|
*
|
|
982
|
-
*
|
|
983
|
-
*
|
|
984
|
-
* `application/vnd.api+json`.
|
|
1127
|
+
* A content type is JSON when it contains any of these substrings. The `+json` entry catches
|
|
1128
|
+
* structured-syntax suffixes such as `application/vnd.api+json`.
|
|
985
1129
|
*/
|
|
986
1130
|
const jsonMimeFragments = [
|
|
987
1131
|
"application/json",
|
|
@@ -1077,8 +1221,8 @@ function getRequestContent({ document, operation, mediaType }) {
|
|
|
1077
1221
|
return available ? [available, content[available]] : false;
|
|
1078
1222
|
}
|
|
1079
1223
|
/**
|
|
1080
|
-
* Returns the primary request content type. Prefers a JSON-like media type (the last one wins
|
|
1081
|
-
*
|
|
1224
|
+
* Returns the primary request content type. Prefers a JSON-like media type (the last one wins
|
|
1225
|
+
* when several are declared), then the first declared one, defaulting to `'application/json'`.
|
|
1082
1226
|
*/
|
|
1083
1227
|
function getRequestContentType({ document, operation }) {
|
|
1084
1228
|
const content = getRequestBodyContent({
|
|
@@ -1173,9 +1317,9 @@ function getSchemaType(format) {
|
|
|
1173
1317
|
return formatMap[format] ?? null;
|
|
1174
1318
|
}
|
|
1175
1319
|
/**
|
|
1176
|
-
* Whether the parser maps `format` to a dedicated type. True for any `formatMap` entry
|
|
1177
|
-
* `specialCasedFormats` `convertFormat` handles directly. False means the format falls back to
|
|
1178
|
-
* base type, which is what `KUBB_UNSUPPORTED_FORMAT` flags. Reading both sources keeps the
|
|
1320
|
+
* Whether the parser maps `format` to a dedicated type. True for any `formatMap` entry, plus the
|
|
1321
|
+
* `specialCasedFormats` that `convertFormat` handles directly. False means the format falls back to
|
|
1322
|
+
* the base type, which is what `KUBB_UNSUPPORTED_FORMAT` flags. Reading both sources keeps the
|
|
1179
1323
|
* diagnostic in step with the parser as `formatMap` grows.
|
|
1180
1324
|
*/
|
|
1181
1325
|
function isHandledFormat(format) {
|
|
@@ -1193,7 +1337,7 @@ function getPrimitiveType(type) {
|
|
|
1193
1337
|
/**
|
|
1194
1338
|
* Returns all parameters for an operation, merging path-level and operation-level entries.
|
|
1195
1339
|
* Operation-level parameters override path-level ones with the same `in:name` key.
|
|
1196
|
-
* `$ref`
|
|
1340
|
+
* Each `$ref` parameter is dereferenced via `dereferenceWithRef` before merging.
|
|
1197
1341
|
*
|
|
1198
1342
|
* @example
|
|
1199
1343
|
* ```ts
|
|
@@ -1294,7 +1438,10 @@ function getRequestSchema(document, operation, options = {}) {
|
|
|
1294
1438
|
* ```ts
|
|
1295
1439
|
* flattenSchema({ allOf: [{ description: 'A pet' }], type: 'object', properties: {} })
|
|
1296
1440
|
* // { type: 'object', properties: {}, description: 'A pet' }
|
|
1441
|
+
* ```
|
|
1297
1442
|
*
|
|
1443
|
+
* @example
|
|
1444
|
+
* ```ts
|
|
1298
1445
|
* flattenSchema({ allOf: [{ $ref: '#/components/schemas/Pet' }] })
|
|
1299
1446
|
* // returned unchanged, contains a $ref
|
|
1300
1447
|
* ```
|
|
@@ -1988,7 +2135,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1988
2135
|
nullable: schemaNode.type === "null" ? void 0 : propNullable || void 0
|
|
1989
2136
|
},
|
|
1990
2137
|
required
|
|
1991
|
-
}
|
|
2138
|
+
});
|
|
1992
2139
|
}) : [];
|
|
1993
2140
|
const additionalProperties = schema.additionalProperties;
|
|
1994
2141
|
const additionalPropertiesNode = (() => {
|
|
@@ -2302,7 +2449,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2302
2449
|
description: param["description"] ?? schema.description
|
|
2303
2450
|
},
|
|
2304
2451
|
required
|
|
2305
|
-
}
|
|
2452
|
+
});
|
|
2306
2453
|
}
|
|
2307
2454
|
/**
|
|
2308
2455
|
* Reads the inline `requestBody` metadata (description / required) that OAS exposes
|
|
@@ -2355,7 +2502,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2355
2502
|
if (!schema) return [];
|
|
2356
2503
|
return [ast.factory.createContent({
|
|
2357
2504
|
contentType: ct,
|
|
2358
|
-
schema:
|
|
2505
|
+
schema: ast.optionality(parseSchema({
|
|
2359
2506
|
schema,
|
|
2360
2507
|
name: requestBodyName
|
|
2361
2508
|
}, options), requestBodyMeta.required),
|
|
@@ -2558,30 +2705,15 @@ function preScan({ schemas, parseSchema, parseOperation, document, parserOptions
|
|
|
2558
2705
|
}
|
|
2559
2706
|
const circularSchemas = new Set(circularNames);
|
|
2560
2707
|
const usedNames = new Set(Object.keys(schemas));
|
|
2561
|
-
dedupePlan =
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
if (node.type !== "object") return false;
|
|
2565
|
-
if (node.name && circularSchemas.has(node.name)) return false;
|
|
2566
|
-
return !containsCircularRef(node, { circularSchemas });
|
|
2567
|
-
},
|
|
2568
|
-
nameFor: (node) => {
|
|
2569
|
-
const base = node.name;
|
|
2570
|
-
if (!base) return null;
|
|
2571
|
-
let name = base;
|
|
2572
|
-
let counter = 2;
|
|
2573
|
-
while (usedNames.has(name)) name = `${base}${counter++}`;
|
|
2574
|
-
usedNames.add(name);
|
|
2575
|
-
return name;
|
|
2576
|
-
},
|
|
2577
|
-
refFor: (name) => `${SCHEMA_REF_PREFIX}${name}`
|
|
2708
|
+
dedupePlan = oasDialect.dedupe.plan([...allNodes, ...operationNodes], {
|
|
2709
|
+
circularSchemas,
|
|
2710
|
+
usedNames
|
|
2578
2711
|
});
|
|
2579
|
-
for (const definition of dedupePlan.
|
|
2712
|
+
for (const definition of dedupePlan.extracted) if (definition.type === "enum" && definition.name) enumNames.push(definition.name);
|
|
2580
2713
|
}
|
|
2581
|
-
const aliasNames = dedupePlan?.aliasNames;
|
|
2582
2714
|
return {
|
|
2583
2715
|
refAliasMap,
|
|
2584
|
-
enumNames:
|
|
2716
|
+
enumNames: dedupePlan ? enumNames.filter((name) => !dedupePlan.isAlias(name)) : enumNames,
|
|
2585
2717
|
circularNames,
|
|
2586
2718
|
discriminatorChildMap,
|
|
2587
2719
|
dedupePlan
|
|
@@ -2606,39 +2738,29 @@ function preScan({ schemas, parseSchema, parseOperation, document, parserOptions
|
|
|
2606
2738
|
* ```
|
|
2607
2739
|
*/
|
|
2608
2740
|
function createInputStream({ schemas, parseSchema, parseOperation, document, parserOptions, refAliasMap, discriminatorChildMap, dedupePlan, meta }) {
|
|
2609
|
-
const rewriteTopLevelSchema = (node) => {
|
|
2610
|
-
if (!dedupePlan) return node;
|
|
2611
|
-
const canonical = dedupePlan.canonicalBySignature.get(ast.signatureOf(node));
|
|
2612
|
-
if (canonical && canonical.name !== node.name) return ast.factory.createSchema({
|
|
2613
|
-
type: "ref",
|
|
2614
|
-
name: node.name ?? null,
|
|
2615
|
-
ref: canonical.ref,
|
|
2616
|
-
description: node.description,
|
|
2617
|
-
deprecated: node.deprecated
|
|
2618
|
-
});
|
|
2619
|
-
return ast.applyDedupe(node, dedupePlan, true);
|
|
2620
|
-
};
|
|
2621
2741
|
const schemasIterable = { [Symbol.asyncIterator]() {
|
|
2622
2742
|
return (async function* () {
|
|
2623
|
-
if (dedupePlan) for (const definition of dedupePlan.
|
|
2743
|
+
if (dedupePlan) for (const definition of dedupePlan.extracted) yield definition;
|
|
2624
2744
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
2625
|
-
if (dedupePlan?.
|
|
2745
|
+
if (dedupePlan?.isAlias(name)) continue;
|
|
2626
2746
|
const alias = refAliasMap.get(name);
|
|
2627
2747
|
if (alias?.name && schemas[alias.name]) {
|
|
2628
|
-
|
|
2748
|
+
const aliasNode = {
|
|
2629
2749
|
...parseSchema({
|
|
2630
2750
|
schema: schemas[alias.name],
|
|
2631
2751
|
name: alias.name
|
|
2632
2752
|
}, parserOptions),
|
|
2633
2753
|
name
|
|
2634
|
-
}
|
|
2754
|
+
};
|
|
2755
|
+
yield dedupePlan ? dedupePlan.applyTopLevel(aliasNode) : aliasNode;
|
|
2635
2756
|
continue;
|
|
2636
2757
|
}
|
|
2637
2758
|
const parsed = parseSchema({
|
|
2638
2759
|
schema,
|
|
2639
2760
|
name
|
|
2640
2761
|
}, parserOptions);
|
|
2641
|
-
|
|
2762
|
+
const node = discriminatorChildMap?.get(name) ? patchDiscriminatorNode(parsed, discriminatorChildMap.get(name)) : parsed;
|
|
2763
|
+
yield dedupePlan ? dedupePlan.applyTopLevel(node) : node;
|
|
2642
2764
|
}
|
|
2643
2765
|
})();
|
|
2644
2766
|
} };
|
|
@@ -2646,7 +2768,7 @@ function createInputStream({ schemas, parseSchema, parseOperation, document, par
|
|
|
2646
2768
|
return (async function* () {
|
|
2647
2769
|
for (const operation of getOperations(document)) {
|
|
2648
2770
|
const node = parseOperation(parserOptions, operation);
|
|
2649
|
-
if (node) yield dedupePlan ?
|
|
2771
|
+
if (node) yield dedupePlan ? dedupePlan.apply(node) : node;
|
|
2650
2772
|
}
|
|
2651
2773
|
})();
|
|
2652
2774
|
} };
|
|
@@ -2660,7 +2782,7 @@ function createInputStream({ schemas, parseSchema, parseOperation, document, par
|
|
|
2660
2782
|
//#endregion
|
|
2661
2783
|
//#region src/adapter.ts
|
|
2662
2784
|
/**
|
|
2663
|
-
*
|
|
2785
|
+
* The `name` of `@kubb/adapter-oas`, used to identify this adapter in a Kubb config.
|
|
2664
2786
|
*/
|
|
2665
2787
|
const adapterOasName = "oas";
|
|
2666
2788
|
/**
|