@kubb/adapter-oas 5.0.0-beta.35 → 5.0.0-beta.37
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 +159 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +160 -30
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/adapter.ts +2 -1
- package/src/constants.ts +8 -0
- package/src/dialect.ts +3 -3
- package/src/factory.ts +37 -8
- package/src/parser.ts +11 -16
- package/src/refs.ts +12 -1
- package/src/resolvers.ts +27 -10
- package/src/schemaDiagnostics.ts +59 -0
- package/src/stream.ts +5 -3
- package/src/types.ts +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -466,9 +466,9 @@ type AdapterOasOptions = {
|
|
|
466
466
|
serverVariables?: Record<string, string>;
|
|
467
467
|
/**
|
|
468
468
|
* How the `discriminator` field on `oneOf`/`anyOf` schemas is interpreted.
|
|
469
|
-
* - `'strict'`
|
|
469
|
+
* - `'strict'` child schemas stay exactly as written. The discriminator
|
|
470
470
|
* narrows types at the call site but child shapes are not modified.
|
|
471
|
-
* - `'inherit'`
|
|
471
|
+
* - `'inherit'` Kubb propagates the discriminator property as a literal
|
|
472
472
|
* value into each child schema, so each branch's discriminator field is
|
|
473
473
|
* precisely typed.
|
|
474
474
|
*
|
|
@@ -479,9 +479,9 @@ type AdapterOasOptions = {
|
|
|
479
479
|
* Collapse structurally identical schemas and enums into a single shared definition.
|
|
480
480
|
*
|
|
481
481
|
* Duplicated inline shapes (especially enums repeated across many properties) are hoisted
|
|
482
|
-
* into one named schema
|
|
483
|
-
* component
|
|
484
|
-
* `description` and `example` is ignored. Enabled by default
|
|
482
|
+
* into one named schema. Every other occurrence, and any structurally identical top-level
|
|
483
|
+
* component, becomes a `ref` to it. Equality is shape-only: documentation such as
|
|
484
|
+
* `description` and `example` is ignored. Enabled by default. Set to `false` to keep every
|
|
485
485
|
* occurrence inline and produce byte-for-byte identical output to earlier versions.
|
|
486
486
|
*
|
|
487
487
|
* @default true
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "./chunk-C0LytTxp.js";
|
|
2
|
+
import { access } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import { ast, createAdapter } from "@kubb/core";
|
|
4
|
+
import { DiagnosticError, Diagnostics, ast, createAdapter, diagnosticCode } from "@kubb/core";
|
|
4
5
|
import BaseOas from "oas";
|
|
5
6
|
import { bundle, loadConfig } from "@redocly/openapi-core";
|
|
6
7
|
import OASNormalize from "oas-normalize";
|
|
@@ -71,6 +72,23 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
|
|
|
71
72
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
72
73
|
}
|
|
73
74
|
//#endregion
|
|
75
|
+
//#region ../../internals/utils/src/fs.ts
|
|
76
|
+
/**
|
|
77
|
+
* Resolves to `true` when the file or directory at `path` exists.
|
|
78
|
+
* Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* if (await exists('./kubb.config.ts')) {
|
|
83
|
+
* const content = await read('./kubb.config.ts')
|
|
84
|
+
* }
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
async function exists(path) {
|
|
88
|
+
if (typeof Bun !== "undefined") return Bun.file(path).exists();
|
|
89
|
+
return access(path).then(() => true, () => false);
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
74
92
|
//#region ../../internals/utils/src/object.ts
|
|
75
93
|
/**
|
|
76
94
|
* Returns `true` when `value` is a plain (non-null, non-array) object.
|
|
@@ -461,6 +479,18 @@ const structuralKeys = new Set([
|
|
|
461
479
|
* formatMap['float'] // 'number'
|
|
462
480
|
* ```
|
|
463
481
|
*/
|
|
482
|
+
/**
|
|
483
|
+
* Formats `convertFormat` maps to a dedicated type without going through `formatMap`:
|
|
484
|
+
* `int64` and the date/time family. Keep this in sync with the `convertFormat`
|
|
485
|
+
* special-cases in `parser.ts`. `isHandledFormat` reads it so the
|
|
486
|
+
* `KUBB_UNSUPPORTED_FORMAT` diagnostic and the parser agree on what is handled.
|
|
487
|
+
*/
|
|
488
|
+
const specialCasedFormats = new Set([
|
|
489
|
+
"int64",
|
|
490
|
+
"date-time",
|
|
491
|
+
"date",
|
|
492
|
+
"time"
|
|
493
|
+
]);
|
|
464
494
|
const formatMap = {
|
|
465
495
|
uuid: "uuid",
|
|
466
496
|
email: "email",
|
|
@@ -608,7 +638,13 @@ async function mergeDocuments(pathOrApi) {
|
|
|
608
638
|
enablePaths: false,
|
|
609
639
|
canBundle: false
|
|
610
640
|
})));
|
|
611
|
-
if (documents.length === 0) throw new
|
|
641
|
+
if (documents.length === 0) throw new DiagnosticError({
|
|
642
|
+
code: diagnosticCode.inputRequired,
|
|
643
|
+
severity: "error",
|
|
644
|
+
message: "No OAS documents were provided for merging.",
|
|
645
|
+
help: "Pass at least one path or document to `input.path`.",
|
|
646
|
+
location: { kind: "config" }
|
|
647
|
+
});
|
|
612
648
|
const seed = {
|
|
613
649
|
openapi: MERGE_OPENAPI_VERSION,
|
|
614
650
|
info: {
|
|
@@ -624,9 +660,9 @@ async function mergeDocuments(pathOrApi) {
|
|
|
624
660
|
* Creates a `Document` from an `AdapterSource`.
|
|
625
661
|
*
|
|
626
662
|
* Handles all three source types:
|
|
627
|
-
* - `{ type: 'path' }`
|
|
628
|
-
* - `{ type: 'paths' }`
|
|
629
|
-
* - `{ type: 'data' }`
|
|
663
|
+
* - `{ type: 'path' }` resolves and bundles a local file path or remote URL.
|
|
664
|
+
* - `{ type: 'paths' }` merges multiple file paths into a single document.
|
|
665
|
+
* - `{ type: 'data' }` parses an inline string (YAML/JSON) or raw object.
|
|
630
666
|
*
|
|
631
667
|
* @example
|
|
632
668
|
* ```ts
|
|
@@ -634,14 +670,31 @@ async function mergeDocuments(pathOrApi) {
|
|
|
634
670
|
* const document = await parseFromConfig({ type: 'data', data: '{"openapi":"3.0.0",...}' })
|
|
635
671
|
* ```
|
|
636
672
|
*/
|
|
637
|
-
function parseFromConfig(source) {
|
|
673
|
+
async function parseFromConfig(source) {
|
|
638
674
|
if (source.type === "data") {
|
|
639
675
|
if (typeof source.data === "object") return parseDocument(structuredClone(source.data));
|
|
640
676
|
return parseDocument(source.data, { canBundle: false });
|
|
641
677
|
}
|
|
642
678
|
if (source.type === "paths") return mergeDocuments(source.paths);
|
|
643
679
|
if (new URLPath(source.path).isURL) return parseDocument(source.path);
|
|
644
|
-
|
|
680
|
+
const resolved = path.resolve(path.dirname(source.path), source.path);
|
|
681
|
+
await assertInputExists(resolved);
|
|
682
|
+
return parseDocument(resolved);
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Throws a coded `KUBB_INPUT_NOT_FOUND` diagnostic when a local input path does not exist.
|
|
686
|
+
* URLs are skipped, and a malformed but readable file is left for `parseDocument` to surface
|
|
687
|
+
* its parse error instead.
|
|
688
|
+
*/
|
|
689
|
+
async function assertInputExists(input) {
|
|
690
|
+
if (new URLPath(input).isURL) return;
|
|
691
|
+
if (!await exists(input)) throw new DiagnosticError({
|
|
692
|
+
code: diagnosticCode.inputNotFound,
|
|
693
|
+
severity: "error",
|
|
694
|
+
message: `Cannot read the file set in \`input.path\` (or via \`kubb generate PATH\`): ${input}`,
|
|
695
|
+
help: "Check that the path exists and is readable, then set it in `input.path` or pass it as `kubb generate PATH`.",
|
|
696
|
+
location: { kind: "config" }
|
|
697
|
+
});
|
|
645
698
|
}
|
|
646
699
|
/**
|
|
647
700
|
* Validates an OpenAPI document using `oas-normalize` with colorized error output.
|
|
@@ -688,7 +741,21 @@ function resolveRef(document, $ref) {
|
|
|
688
741
|
}
|
|
689
742
|
if (docCache.has($ref)) return docCache.get($ref);
|
|
690
743
|
const current = $ref.split("/").filter(Boolean).reduce((obj, key) => obj?.[key], document);
|
|
691
|
-
if (!current)
|
|
744
|
+
if (!current) {
|
|
745
|
+
const diagnostic = {
|
|
746
|
+
code: diagnosticCode.refNotFound,
|
|
747
|
+
severity: "error",
|
|
748
|
+
message: `Could not find a definition for ${origRef}.`,
|
|
749
|
+
help: "Add the schema under `components.schemas`, or fix the `$ref`. Run `kubb validate` to check the spec.",
|
|
750
|
+
location: {
|
|
751
|
+
kind: "schema",
|
|
752
|
+
pointer: origRef,
|
|
753
|
+
ref: origRef
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
Diagnostics.report(diagnostic);
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
692
759
|
docCache.set($ref, current);
|
|
693
760
|
return current;
|
|
694
761
|
}
|
|
@@ -715,13 +782,13 @@ function dereferenceWithRef(document, schema) {
|
|
|
715
782
|
//#endregion
|
|
716
783
|
//#region src/dialect.ts
|
|
717
784
|
/**
|
|
718
|
-
* The OpenAPI / Swagger dialect
|
|
785
|
+
* The OpenAPI / Swagger dialect, the default used by `@kubb/adapter-oas`.
|
|
719
786
|
*
|
|
720
787
|
* Implements the spec-agnostic {@link ast.SchemaDialect} contract: it isolates the
|
|
721
788
|
* decisions that differ between specs (nullability, `$ref`, discriminator, binary,
|
|
722
789
|
* ref resolution) so the converter pipeline and dispatch rules stay shared. A
|
|
723
|
-
* future adapter (e.g. AsyncAPI) ships its own dialect
|
|
724
|
-
* nullability, no discriminator object, binary via `contentEncoding`
|
|
790
|
+
* future adapter (e.g. AsyncAPI) ships its own dialect, `type: ['null', …]`
|
|
791
|
+
* nullability, no discriminator object, binary via `contentEncoding` and reuses
|
|
725
792
|
* the rest unchanged.
|
|
726
793
|
*
|
|
727
794
|
* Formats (`uuid`, `email`, dates, …) are intentionally NOT here: they are shared
|
|
@@ -763,7 +830,16 @@ function resolveServerUrl(server, overrides) {
|
|
|
763
830
|
for (const [key, variable] of Object.entries(server.variables)) {
|
|
764
831
|
const value = overrides?.[key] ?? (variable.default != null ? String(variable.default) : void 0);
|
|
765
832
|
if (value === void 0) continue;
|
|
766
|
-
if (variable.enum?.length && !variable.enum.some((e) => String(e) === value)) throw new
|
|
833
|
+
if (variable.enum?.length && !variable.enum.some((e) => String(e) === value)) throw new DiagnosticError({
|
|
834
|
+
code: diagnosticCode.invalidServerVariable,
|
|
835
|
+
severity: "error",
|
|
836
|
+
message: `Invalid server variable value '${value}' for '${key}' when resolving ${server.url}. Valid values are: ${variable.enum.join(", ")}.`,
|
|
837
|
+
help: `Use one of the allowed enum values, or drop the enum on the '${key}' server variable.`,
|
|
838
|
+
location: {
|
|
839
|
+
kind: "document",
|
|
840
|
+
pointer: "#/servers"
|
|
841
|
+
}
|
|
842
|
+
});
|
|
767
843
|
url = url.replaceAll(`{${key}}`, value);
|
|
768
844
|
}
|
|
769
845
|
return url;
|
|
@@ -776,6 +852,15 @@ function getSchemaType(format) {
|
|
|
776
852
|
return formatMap[format] ?? null;
|
|
777
853
|
}
|
|
778
854
|
/**
|
|
855
|
+
* Whether the parser maps `format` to a dedicated type. True for any `formatMap` entry and the
|
|
856
|
+
* `specialCasedFormats` `convertFormat` handles directly. False means the format falls back to the
|
|
857
|
+
* base type, which is what `KUBB_UNSUPPORTED_FORMAT` flags. Reading both sources keeps the
|
|
858
|
+
* diagnostic in step with the parser as `formatMap` grows.
|
|
859
|
+
*/
|
|
860
|
+
function isHandledFormat(format) {
|
|
861
|
+
return getSchemaType(format) !== null || specialCasedFormats.has(format);
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
779
864
|
* Converts an OAS primitive type string to its `PrimitiveSchemaType` equivalent.
|
|
780
865
|
* Numeric types (`number`, `integer`, `bigint`) pass through unchanged. `boolean` maps to `'boolean'`. Everything else becomes `'string'`.
|
|
781
866
|
*/
|
|
@@ -872,7 +957,7 @@ function getRequestSchema(document, operation, options = {}) {
|
|
|
872
957
|
/**
|
|
873
958
|
* Flattens a keyword-only `allOf` into its parent schema.
|
|
874
959
|
*
|
|
875
|
-
* Only flattens when every member is a plain fragment
|
|
960
|
+
* Only flattens when every member is a plain fragment, with no `$ref` and no structural keywords
|
|
876
961
|
* (see `structuralKeys`). Outer schema values take precedence over fragment values.
|
|
877
962
|
* Returns `null` for a `null` input, and the original schema unchanged when flattening is unsafe.
|
|
878
963
|
*
|
|
@@ -882,7 +967,7 @@ function getRequestSchema(document, operation, options = {}) {
|
|
|
882
967
|
* // { type: 'object', properties: {}, description: 'A pet' }
|
|
883
968
|
*
|
|
884
969
|
* flattenSchema({ allOf: [{ $ref: '#/components/schemas/Pet' }] })
|
|
885
|
-
* // returned unchanged
|
|
970
|
+
* // returned unchanged, contains a $ref
|
|
886
971
|
* ```
|
|
887
972
|
*/
|
|
888
973
|
/**
|
|
@@ -908,7 +993,7 @@ function flattenSchema(schema) {
|
|
|
908
993
|
/**
|
|
909
994
|
* Extracts the inline schema from a media-type `content` map.
|
|
910
995
|
*
|
|
911
|
-
* Prefers `preferredContentType` when given
|
|
996
|
+
* Prefers `preferredContentType` when given, otherwise uses the first key in the map.
|
|
912
997
|
* Returns `null` when `content` is absent, the schema is missing, or the schema is a `$ref`.
|
|
913
998
|
*
|
|
914
999
|
* @example
|
|
@@ -1100,9 +1185,9 @@ function buildSchemaNode(schema, name, nullable, defaultValue) {
|
|
|
1100
1185
|
/**
|
|
1101
1186
|
* Returns all request body content type keys for an operation.
|
|
1102
1187
|
*
|
|
1103
|
-
* The requestBody is dereferenced
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1188
|
+
* The requestBody is dereferenced in place when it is a `$ref` (the same mutation that
|
|
1189
|
+
* `getRequestSchema` already performs), so the returned list accurately reflects the
|
|
1190
|
+
* available content types even for referenced bodies.
|
|
1106
1191
|
*
|
|
1107
1192
|
* @example
|
|
1108
1193
|
* ```ts
|
|
@@ -1119,7 +1204,7 @@ function getRequestBodyContentTypes(document, operation) {
|
|
|
1119
1204
|
/**
|
|
1120
1205
|
* Returns all response content type keys for an operation at a given status code.
|
|
1121
1206
|
*
|
|
1122
|
-
* Response `$ref`s are resolved in
|
|
1207
|
+
* Response `$ref`s are resolved in place first (the same mutation `getResponseSchema` performs),
|
|
1123
1208
|
* so the returned list reflects the available content types even for referenced responses.
|
|
1124
1209
|
*
|
|
1125
1210
|
* @example
|
|
@@ -1179,16 +1264,12 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1179
1264
|
*/
|
|
1180
1265
|
const resolvingRefs = /* @__PURE__ */ new Set();
|
|
1181
1266
|
/**
|
|
1182
|
-
* Cache of
|
|
1183
|
-
*
|
|
1184
|
-
* Without this, the same referenced schema (e.g. `customer`) is fully re-expanded
|
|
1185
|
-
* every time it appears as a `$ref` in a different parent schema. In heavily
|
|
1186
|
-
* cross-referenced specs like Stripe (~1 400 schemas), this causes exponential
|
|
1187
|
-
* blowup — `customer` alone may be referenced from dozens of top-level schemas,
|
|
1188
|
-
* each triggering a fresh recursive expansion of its entire sub-tree.
|
|
1267
|
+
* Cache of `$ref` schemas already resolved in this parser instance, keyed by ref path.
|
|
1189
1268
|
*
|
|
1190
|
-
*
|
|
1191
|
-
*
|
|
1269
|
+
* Without it, a shared schema (e.g. `customer`) is re-expanded for every `$ref` that points at
|
|
1270
|
+
* it. In cross-referenced specs like Stripe (~1400 schemas) that becomes exponential blowup,
|
|
1271
|
+
* since one schema can be referenced from dozens of parents, each re-walking its whole subtree.
|
|
1272
|
+
* Memoizing by ref path drops the work from O(2^depth) to O(N) unique schema names.
|
|
1192
1273
|
*/
|
|
1193
1274
|
const resolvedRefCache = /* @__PURE__ */ new Map();
|
|
1194
1275
|
/**
|
|
@@ -1726,7 +1807,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1726
1807
|
/**
|
|
1727
1808
|
* Ordered schema-dispatch table. Order is significant: composition keywords (`$ref`, `allOf`,
|
|
1728
1809
|
* `oneOf`/`anyOf`) take precedence over `const`/`format`, which take precedence over the plain
|
|
1729
|
-
* `type`. The first matching rule that produces a node wins
|
|
1810
|
+
* `type`. The first matching rule that produces a node wins. See {@link SchemaRule} for the
|
|
1730
1811
|
* match/convert/fall-through contract.
|
|
1731
1812
|
*/
|
|
1732
1813
|
const schemaRules = [
|
|
@@ -2071,6 +2152,50 @@ function patchDiscriminatorNode(node, entry) {
|
|
|
2071
2152
|
};
|
|
2072
2153
|
}
|
|
2073
2154
|
//#endregion
|
|
2155
|
+
//#region src/schemaDiagnostics.ts
|
|
2156
|
+
/**
|
|
2157
|
+
* Reports the advisory diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`) for one
|
|
2158
|
+
* top-level schema. Walks the node the parser produced during `preScan`, threading the RFC 6901
|
|
2159
|
+
* pointer as it descends so a nested field reports against its full path
|
|
2160
|
+
* (`#/components/schemas/Pet/properties/owner/properties/name`). Refs are not followed, so the
|
|
2161
|
+
* resolved schema is reported under its own walk. Reports land in the active build run, are a
|
|
2162
|
+
* no-op outside one, and repeats are deduped by the build.
|
|
2163
|
+
*/
|
|
2164
|
+
function reportSchemaDiagnostics({ node, name }) {
|
|
2165
|
+
visit(node, `#/components/schemas/${name}`);
|
|
2166
|
+
}
|
|
2167
|
+
function visit(node, pointer) {
|
|
2168
|
+
if (node.deprecated) Diagnostics.report({
|
|
2169
|
+
code: diagnosticCode.deprecated,
|
|
2170
|
+
severity: "info",
|
|
2171
|
+
message: "This schema is marked as deprecated.",
|
|
2172
|
+
location: {
|
|
2173
|
+
kind: "schema",
|
|
2174
|
+
pointer
|
|
2175
|
+
}
|
|
2176
|
+
});
|
|
2177
|
+
if (typeof node.format === "string" && !isHandledFormat(node.format)) Diagnostics.report({
|
|
2178
|
+
code: diagnosticCode.unsupportedFormat,
|
|
2179
|
+
severity: "warning",
|
|
2180
|
+
message: `Kubb does not map the format "${node.format}" to a specific type, so it falls back to the base type.`,
|
|
2181
|
+
help: `Use a format Kubb supports, or handle "${node.format}" with a custom parser or plugin.`,
|
|
2182
|
+
location: {
|
|
2183
|
+
kind: "schema",
|
|
2184
|
+
pointer
|
|
2185
|
+
}
|
|
2186
|
+
});
|
|
2187
|
+
if (node.type === "object") {
|
|
2188
|
+
for (const property of node.properties) visit(property.schema, `${pointer}/properties/${property.name}`);
|
|
2189
|
+
if (node.additionalProperties && typeof node.additionalProperties === "object") visit(node.additionalProperties, `${pointer}/additionalProperties`);
|
|
2190
|
+
return;
|
|
2191
|
+
}
|
|
2192
|
+
if (node.type === "array" || node.type === "tuple") {
|
|
2193
|
+
for (const item of node.items ?? []) visit(item, `${pointer}/items`);
|
|
2194
|
+
return;
|
|
2195
|
+
}
|
|
2196
|
+
if (node.type === "union" || node.type === "intersection") for (const member of node.members ?? []) visit(member, pointer);
|
|
2197
|
+
}
|
|
2198
|
+
//#endregion
|
|
2074
2199
|
//#region src/stream.ts
|
|
2075
2200
|
/**
|
|
2076
2201
|
* Builds the deduplication plan from the already-parsed top-level schema nodes plus a
|
|
@@ -2130,7 +2255,7 @@ function resolveBaseUrl({ document, serverIndex, serverVariables }) {
|
|
|
2130
2255
|
* After this call, only `refAliasMap` and `discriminatorChildMap` stay alive in the adapter closure.
|
|
2131
2256
|
* Both are proportional to the number of aliases or discriminator parents, not total schema count.
|
|
2132
2257
|
*
|
|
2133
|
-
* Each schema is parsed again during the streaming pass
|
|
2258
|
+
* Each schema is parsed again during the streaming pass. This is intentional.
|
|
2134
2259
|
* Holding the parsed nodes in memory here would defeat the streaming memory benefit.
|
|
2135
2260
|
*
|
|
2136
2261
|
* @example
|
|
@@ -2154,6 +2279,10 @@ function preScan({ schemas, parseSchema, parseOperation, baseOas, parserOptions,
|
|
|
2154
2279
|
name
|
|
2155
2280
|
}, parserOptions);
|
|
2156
2281
|
allNodes.push(node);
|
|
2282
|
+
reportSchemaDiagnostics({
|
|
2283
|
+
node,
|
|
2284
|
+
name
|
|
2285
|
+
});
|
|
2157
2286
|
if (node.type === "ref" && node.name && node.name !== name) refAliasMap.set(name, node);
|
|
2158
2287
|
if (ast.narrowSchema(node, ast.schemaTypes.enum) && node.name) enumNames.push(node.name);
|
|
2159
2288
|
if (discriminator === "inherit" && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) discriminatorParentNodes.push(node);
|
|
@@ -2370,6 +2499,7 @@ const adapterOas = createAdapter((options) => {
|
|
|
2370
2499
|
return parsedDocument;
|
|
2371
2500
|
},
|
|
2372
2501
|
async validate(input, options) {
|
|
2502
|
+
await assertInputExists(input);
|
|
2373
2503
|
await validateDocument(await parseDocument(input), options);
|
|
2374
2504
|
},
|
|
2375
2505
|
getImports(node, resolve) {
|