@kubb/adapter-oas 5.0.0-beta.84 → 5.0.0-beta.86

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 CHANGED
@@ -165,6 +165,119 @@ const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
165
165
  */
166
166
  const enumDescriptionKeys = ["x-enumDescriptions", "x-enum-descriptions"];
167
167
  //#endregion
168
+ //#region src/discriminator.ts
169
+ /**
170
+ * Maps each child schema name to its discriminator patch data by scanning the given
171
+ * top-level AST schema nodes for union schemas that carry a `discriminatorPropertyName`.
172
+ *
173
+ * Called on a small pre-parsed subset of schemas (only the discriminator parents)
174
+ * rather than on all schemas at once.
175
+ */
176
+ function buildDiscriminatorChildMap(schemas) {
177
+ const childMap = /* @__PURE__ */ new Map();
178
+ for (const schema of schemas) {
179
+ let unionNode = _kubb_ast.ast.narrowSchema(schema, "union");
180
+ if (!unionNode) {
181
+ const intersectionMembers = _kubb_ast.ast.narrowSchema(schema, "intersection")?.members;
182
+ if (intersectionMembers) for (const m of intersectionMembers) {
183
+ const u = _kubb_ast.ast.narrowSchema(m, "union");
184
+ if (u) {
185
+ unionNode = u;
186
+ break;
187
+ }
188
+ }
189
+ }
190
+ if (!unionNode?.discriminatorPropertyName || !unionNode.members) continue;
191
+ const { discriminatorPropertyName, members } = unionNode;
192
+ for (const member of members) {
193
+ const intersectionNode = _kubb_ast.ast.narrowSchema(member, "intersection");
194
+ if (!intersectionNode?.members) continue;
195
+ let refNode = null;
196
+ let objNode = null;
197
+ for (const m of intersectionNode.members) {
198
+ refNode ??= _kubb_ast.ast.narrowSchema(m, "ref");
199
+ objNode ??= _kubb_ast.ast.narrowSchema(m, "object");
200
+ }
201
+ if (!refNode?.name || !objNode) continue;
202
+ const prop = objNode.properties.find((p) => p.name === discriminatorPropertyName);
203
+ const enumNode = prop ? _kubb_ast.ast.narrowSchema(prop.schema, "enum") : null;
204
+ if (!enumNode?.enumValues?.length) continue;
205
+ const enumValues = enumNode.enumValues.filter((v) => v !== null);
206
+ if (!enumValues.length) continue;
207
+ const existing = childMap.get(refNode.name);
208
+ if (!existing) {
209
+ childMap.set(refNode.name, {
210
+ propertyName: discriminatorPropertyName,
211
+ enumValues: [...enumValues]
212
+ });
213
+ continue;
214
+ }
215
+ existing.enumValues.push(...enumValues);
216
+ }
217
+ }
218
+ return childMap;
219
+ }
220
+ /**
221
+ * Patches a single top-level `SchemaNode` with its discriminator entry (adds or replaces
222
+ * the discriminant property).
223
+ */
224
+ function patchDiscriminatorNode(node, entry) {
225
+ const objectNode = _kubb_ast.ast.narrowSchema(node, "object");
226
+ if (!objectNode) return node;
227
+ const { propertyName, enumValues } = entry;
228
+ const enumSchema = _kubb_ast.ast.factory.createSchema({
229
+ type: "enum",
230
+ enumValues
231
+ });
232
+ const newProp = _kubb_ast.ast.factory.createProperty({
233
+ name: propertyName,
234
+ required: true,
235
+ schema: enumSchema
236
+ });
237
+ const existingIdx = objectNode.properties.findIndex((p) => p.name === propertyName);
238
+ const newProperties = existingIdx >= 0 ? objectNode.properties.map((p, i) => i === existingIdx ? newProp : p) : [...objectNode.properties, newProp];
239
+ return {
240
+ ...objectNode,
241
+ properties: newProperties
242
+ };
243
+ }
244
+ /**
245
+ * Creates a single-property object schema used as a discriminator literal.
246
+ *
247
+ * @example
248
+ * ```ts
249
+ * createDiscriminantNode({ propertyName: 'type', value: 'dog' })
250
+ * // -> { type: 'object', properties: [{ name: 'type', required: true, schema: enum('dog') }] }
251
+ * ```
252
+ */
253
+ function createDiscriminantNode({ propertyName, value }) {
254
+ return _kubb_ast.ast.factory.createSchema({
255
+ type: "object",
256
+ primitive: "object",
257
+ properties: [_kubb_ast.ast.factory.createProperty({
258
+ name: propertyName,
259
+ schema: _kubb_ast.ast.factory.createSchema({
260
+ type: "enum",
261
+ primitive: "string",
262
+ enumValues: [value]
263
+ }),
264
+ required: true
265
+ })]
266
+ });
267
+ }
268
+ /**
269
+ * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.
270
+ *
271
+ * @example
272
+ * ```ts
273
+ * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'
274
+ * ```
275
+ */
276
+ function findDiscriminator(mapping, ref) {
277
+ if (!mapping || !ref) return null;
278
+ return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null;
279
+ }
280
+ //#endregion
168
281
  //#region ../../internals/utils/src/casing.ts
169
282
  /**
170
283
  * Shared implementation for camelCase and PascalCase conversion.
@@ -453,6 +566,34 @@ function isDiscriminator(obj) {
453
566
  return !!obj && !!record["discriminator"] && typeof record["discriminator"] !== "string";
454
567
  }
455
568
  //#endregion
569
+ //#region src/mime.ts
570
+ /**
571
+ * MIME type fragments that mark a media type as JSON-like.
572
+ *
573
+ * A content type is JSON when it contains any of these substrings. The `+json` entry catches
574
+ * structured-syntax suffixes such as `application/vnd.api+json`.
575
+ */
576
+ const jsonMimeFragments = [
577
+ "application/json",
578
+ "application/x-json",
579
+ "text/json",
580
+ "text/x-json",
581
+ "+json"
582
+ ];
583
+ /**
584
+ * Returns `true` when a media type string is JSON-like.
585
+ *
586
+ * @example
587
+ * ```ts
588
+ * isJsonMimeType('application/json') // true
589
+ * isJsonMimeType('application/vnd.api+json') // true
590
+ * isJsonMimeType('multipart/form-data') // false
591
+ * ```
592
+ */
593
+ function isJsonMimeType(mimeType) {
594
+ return jsonMimeFragments.some((fragment) => mimeType.includes(fragment));
595
+ }
596
+ //#endregion
456
597
  //#region src/refs.ts
457
598
  const _refCache = /* @__PURE__ */ new WeakMap();
458
599
  /**
@@ -519,179 +660,6 @@ function dereferenceWithRef(document, schema) {
519
660
  return schema;
520
661
  }
521
662
  //#endregion
522
- //#region src/dialect.ts
523
- /**
524
- * The OpenAPI / Swagger dialect, the default used by `@kubb/adapter-oas`.
525
- *
526
- * Implements the spec-agnostic {@link ast.SchemaDialect} contract: it isolates the
527
- * decisions that differ between specs (nullability, `$ref`, discriminator, binary,
528
- * ref resolution) so the converter pipeline and dispatch rules stay shared. A
529
- * future adapter (e.g. AsyncAPI) ships its own dialect, `type: ['null', …]`
530
- * nullability, no discriminator object, binary via `contentEncoding` and reuses
531
- * the rest unchanged.
532
- *
533
- * Formats (`uuid`, `email`, dates, …) are intentionally NOT here: they are shared
534
- * JSON Schema vocabulary, so the converters keep that common case.
535
- *
536
- * @example
537
- * ```ts
538
- * const parser = createSchemaParser(context) // uses oasDialect
539
- * const parser = createSchemaParser(context, oasDialect) // explicit
540
- * ```
541
- */
542
- const oasDialect = _kubb_ast.ast.defineDialect({
543
- name: "oas",
544
- schema: {
545
- isNullable,
546
- isReference,
547
- isDiscriminator,
548
- isBinary: (schema) => schema.type === "string" && schema.contentMediaType === "application/octet-stream",
549
- resolveRef
550
- }
551
- });
552
- //#endregion
553
- //#region src/discriminator.ts
554
- /**
555
- * Maps each child schema name to its discriminator patch data by scanning the given
556
- * top-level AST schema nodes for union schemas that carry a `discriminatorPropertyName`.
557
- *
558
- * The streaming path calls this on a small pre-parsed subset of schemas (only the
559
- * discriminator parents) rather than on all schemas at once.
560
- */
561
- function buildDiscriminatorChildMap(schemas) {
562
- const childMap = /* @__PURE__ */ new Map();
563
- for (const schema of schemas) {
564
- let unionNode = _kubb_ast.ast.narrowSchema(schema, "union");
565
- if (!unionNode) {
566
- const intersectionMembers = _kubb_ast.ast.narrowSchema(schema, "intersection")?.members;
567
- if (intersectionMembers) for (const m of intersectionMembers) {
568
- const u = _kubb_ast.ast.narrowSchema(m, "union");
569
- if (u) {
570
- unionNode = u;
571
- break;
572
- }
573
- }
574
- }
575
- if (!unionNode?.discriminatorPropertyName || !unionNode.members) continue;
576
- const { discriminatorPropertyName, members } = unionNode;
577
- for (const member of members) {
578
- const intersectionNode = _kubb_ast.ast.narrowSchema(member, "intersection");
579
- if (!intersectionNode?.members) continue;
580
- let refNode = null;
581
- let objNode = null;
582
- for (const m of intersectionNode.members) {
583
- refNode ??= _kubb_ast.ast.narrowSchema(m, "ref");
584
- objNode ??= _kubb_ast.ast.narrowSchema(m, "object");
585
- }
586
- if (!refNode?.name || !objNode) continue;
587
- const prop = objNode.properties.find((p) => p.name === discriminatorPropertyName);
588
- const enumNode = prop ? _kubb_ast.ast.narrowSchema(prop.schema, "enum") : null;
589
- if (!enumNode?.enumValues?.length) continue;
590
- const enumValues = enumNode.enumValues.filter((v) => v !== null);
591
- if (!enumValues.length) continue;
592
- const existing = childMap.get(refNode.name);
593
- if (!existing) {
594
- childMap.set(refNode.name, {
595
- propertyName: discriminatorPropertyName,
596
- enumValues: [...enumValues]
597
- });
598
- continue;
599
- }
600
- existing.enumValues.push(...enumValues);
601
- }
602
- }
603
- return childMap;
604
- }
605
- /**
606
- * Patches a single top-level `SchemaNode` with its discriminator entry (adds or replaces
607
- * the discriminant property). Used by the streaming path to apply patches inline per yield
608
- * without buffering all schemas.
609
- */
610
- function patchDiscriminatorNode(node, entry) {
611
- const objectNode = _kubb_ast.ast.narrowSchema(node, "object");
612
- if (!objectNode) return node;
613
- const { propertyName, enumValues } = entry;
614
- const enumSchema = _kubb_ast.ast.factory.createSchema({
615
- type: "enum",
616
- enumValues
617
- });
618
- const newProp = _kubb_ast.ast.factory.createProperty({
619
- name: propertyName,
620
- required: true,
621
- schema: enumSchema
622
- });
623
- const existingIdx = objectNode.properties.findIndex((p) => p.name === propertyName);
624
- const newProperties = existingIdx >= 0 ? objectNode.properties.map((p, i) => i === existingIdx ? newProp : p) : [...objectNode.properties, newProp];
625
- return {
626
- ...objectNode,
627
- properties: newProperties
628
- };
629
- }
630
- /**
631
- * Creates a single-property object schema used as a discriminator literal.
632
- *
633
- * @example
634
- * ```ts
635
- * createDiscriminantNode({ propertyName: 'type', value: 'dog' })
636
- * // -> { type: 'object', properties: [{ name: 'type', required: true, schema: enum('dog') }] }
637
- * ```
638
- */
639
- function createDiscriminantNode({ propertyName, value }) {
640
- return _kubb_ast.ast.factory.createSchema({
641
- type: "object",
642
- primitive: "object",
643
- properties: [_kubb_ast.ast.factory.createProperty({
644
- name: propertyName,
645
- schema: _kubb_ast.ast.factory.createSchema({
646
- type: "enum",
647
- primitive: "string",
648
- enumValues: [value]
649
- }),
650
- required: true
651
- })]
652
- });
653
- }
654
- /**
655
- * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.
656
- *
657
- * @example
658
- * ```ts
659
- * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'
660
- * ```
661
- */
662
- function findDiscriminator(mapping, ref) {
663
- if (!mapping || !ref) return null;
664
- return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null;
665
- }
666
- //#endregion
667
- //#region src/mime.ts
668
- /**
669
- * MIME type fragments that mark a media type as JSON-like.
670
- *
671
- * A content type is JSON when it contains any of these substrings. The `+json` entry catches
672
- * structured-syntax suffixes such as `application/vnd.api+json`.
673
- */
674
- const jsonMimeFragments = [
675
- "application/json",
676
- "application/x-json",
677
- "text/json",
678
- "text/x-json",
679
- "+json"
680
- ];
681
- /**
682
- * Returns `true` when a media type string is JSON-like.
683
- *
684
- * @example
685
- * ```ts
686
- * isJsonMimeType('application/json') // true
687
- * isJsonMimeType('application/vnd.api+json') // true
688
- * isJsonMimeType('multipart/form-data') // false
689
- * ```
690
- */
691
- function isJsonMimeType(mimeType) {
692
- return jsonMimeFragments.some((fragment) => mimeType.includes(fragment));
693
- }
694
- //#endregion
695
663
  //#region src/operation.ts
696
664
  /**
697
665
  * Slugifies a path for the `operationId` fallback: non-alphanumerics collapse to single dashes,
@@ -818,8 +786,56 @@ function getOperations(document) {
818
786
  return operations;
819
787
  }
820
788
  //#endregion
789
+ //#region src/dialect.ts
790
+ /**
791
+ * The OpenAPI / Swagger dialect, the default used by `@kubb/adapter-oas`.
792
+ *
793
+ * Implements the spec-agnostic {@link ast.SchemaDialect} contract: it isolates the
794
+ * decisions that differ between specs (nullability, `$ref`, discriminator, binary,
795
+ * ref resolution) so the converter pipeline and dispatch rules stay shared. A
796
+ * future adapter (e.g. AsyncAPI) ships its own dialect, `type: ['null', …]`
797
+ * nullability, no discriminator object, binary via `contentEncoding` and reuses
798
+ * the rest unchanged.
799
+ *
800
+ * Formats (`uuid`, `email`, dates, …) are intentionally NOT here: they are shared
801
+ * JSON Schema vocabulary, so the converters keep that common case.
802
+ *
803
+ * @example
804
+ * ```ts
805
+ * const parser = createSchemaParser(context) // uses oasDialect
806
+ * const parser = createSchemaParser(context, oasDialect) // explicit
807
+ * ```
808
+ */
809
+ const oasDialect = _kubb_ast.ast.defineDialect({
810
+ name: "oas",
811
+ schema: {
812
+ isNullable,
813
+ isReference,
814
+ isDiscriminator,
815
+ isBinary: (schema) => schema.type === "string" && schema.contentMediaType === "application/octet-stream",
816
+ resolveRef
817
+ }
818
+ });
819
+ //#endregion
821
820
  //#region src/resolvers.ts
822
821
  /**
822
+ * Reads the server URL from the document's `servers` array at `server.index`,
823
+ * interpolating any `server.variables` into the URL template.
824
+ *
825
+ * Returns `null` when `server.index` is omitted or out of range.
826
+ *
827
+ * @example Resolve the first server
828
+ * `resolveBaseUrl({ document, server: { index: 0 } })`
829
+ *
830
+ * @example Override a path variable
831
+ * `resolveBaseUrl({ document, server: { index: 0, variables: { version: 'v2' } } })`
832
+ */
833
+ function resolveBaseUrl({ document, server }) {
834
+ const index = server?.index;
835
+ const entry = index !== void 0 ? document.servers?.at(index) : void 0;
836
+ return entry?.url ? resolveServerUrl(entry, server?.variables) : null;
837
+ }
838
+ /**
823
839
  * Replaces `{variable}` placeholders in an OpenAPI server URL with provided values.
824
840
  * Resolution order: `overrides[key]` → `variable.default` → left unreplaced.
825
841
  * Throws if an override value is not in the variable's `enum` list.
@@ -1014,7 +1030,7 @@ function flattenSchema(schema) {
1014
1030
  if (allOfFragments.some(hasStructuralKeywords)) return schema;
1015
1031
  const { allOf: _allOf, ...rest } = schema;
1016
1032
  const merged = rest;
1017
- for (const fragment of allOfFragments) for (const [key, value] of Object.entries(fragment)) if (merged[key] === void 0) merged[key] = value;
1033
+ for (const fragment of allOfFragments) for (const [key, value] of Object.entries(fragment)) merged[key] ??= value;
1018
1034
  return merged;
1019
1035
  }
1020
1036
  /**
@@ -2191,7 +2207,7 @@ function refPromotedEnums(node, promoted) {
2191
2207
  //#region src/schemaDiagnostics.ts
2192
2208
  /**
2193
2209
  * Reports the advisory diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`) for one
2194
- * top-level schema. Walks the node the parser produced during `preScan`, threading the RFC 6901
2210
+ * top-level schema. Walks the node the parser produced, threading the RFC 6901
2195
2211
  * pointer as it descends so a nested field reports against its full path
2196
2212
  * (`#/components/schemas/Pet/properties/owner/properties/name`). Refs are not followed, so the
2197
2213
  * resolved schema is reported under its own walk. Reports land in the active build run, are a
@@ -2243,148 +2259,6 @@ function visit(node, pointer) {
2243
2259
  if (node.type === "union" || node.type === "intersection") for (const [index, member] of (node.members ?? []).entries()) visit(member, `${pointer}/members/${index}`);
2244
2260
  }
2245
2261
  //#endregion
2246
- //#region src/stream.ts
2247
- /**
2248
- * Reads the server URL from the document's `servers` array at `server.index`,
2249
- * interpolating any `server.variables` into the URL template.
2250
- *
2251
- * Returns `null` when `server.index` is omitted or out of range.
2252
- *
2253
- * @example Resolve the first server
2254
- * `resolveBaseUrl({ document, server: { index: 0 } })`
2255
- *
2256
- * @example Override a path variable
2257
- * `resolveBaseUrl({ document, server: { index: 0, variables: { version: 'v2' } } })`
2258
- */
2259
- function resolveBaseUrl({ document, server }) {
2260
- const index = server?.index;
2261
- const entry = index !== void 0 ? document.servers?.at(index) : void 0;
2262
- return entry?.url ? resolveServerUrl(entry, server?.variables) : null;
2263
- }
2264
- /**
2265
- * Parses every schema once to build the lookup structures that streaming needs upfront.
2266
- *
2267
- * Three things happen in this single pass:
2268
- * - `refAliasMap` records schemas that are pure `$ref` aliases so the streaming pass can inline them.
2269
- * - `enumNames` collects the names of every enum schema so plugins skip re-scanning the stream.
2270
- * - `circularNames` runs cycle detection, which requires all nodes in memory simultaneously.
2271
- * The `allNodes` array is local and drops out of scope as soon as this function returns.
2272
- *
2273
- * After this call, only `refAliasMap` and `discriminatorChildMap` stay alive in the adapter closure.
2274
- * Both are proportional to the number of aliases or discriminator parents, not total schema count.
2275
- *
2276
- * Each schema is parsed again during the streaming pass. This is intentional.
2277
- * Holding the parsed nodes in memory here would defeat the streaming memory benefit.
2278
- *
2279
- * @example
2280
- * ```ts
2281
- * const { refAliasMap, enumNames, circularNames } = preScan({
2282
- * schemas,
2283
- * parseSchema,
2284
- * parserOptions,
2285
- * discriminator: 'preserve',
2286
- * })
2287
- * ```
2288
- */
2289
- function preScan({ schemas, parseSchema, parseOperation, document, parserOptions, discriminator, enums = "inline" }) {
2290
- const allNodes = [];
2291
- const refAliasMap = /* @__PURE__ */ new Map();
2292
- const enumNames = [];
2293
- const discriminatorParentNodes = [];
2294
- for (const [name, schema] of Object.entries(schemas)) {
2295
- const node = parseSchema({
2296
- schema,
2297
- name
2298
- }, parserOptions);
2299
- allNodes.push(node);
2300
- reportSchemaDiagnostics({
2301
- node,
2302
- name
2303
- });
2304
- if (node.type === "ref" && node.name && node.name !== name) refAliasMap.set(name, node);
2305
- if (_kubb_ast.ast.narrowSchema(node, _kubb_ast.ast.schemaTypes.enum) && node.name) enumNames.push(node.name);
2306
- if (discriminator === "propagate" && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) discriminatorParentNodes.push(node);
2307
- }
2308
- const circularNames = [...(0, _kubb_ast.findCircularSchemas)(allNodes)];
2309
- const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null;
2310
- let promotedEnums = null;
2311
- if (enums === "root" && document && parseOperation) {
2312
- const operationNodes = [];
2313
- for (const operation of getOperations(document)) {
2314
- const operationNode = parseOperation(parserOptions, operation);
2315
- if (operationNode) operationNodes.push(operationNode);
2316
- }
2317
- promotedEnums = collectInlineEnums([...allNodes, ...operationNodes], new Set(Object.keys(schemas)));
2318
- for (const name of promotedEnums.keys()) enumNames.push(name);
2319
- }
2320
- return {
2321
- refAliasMap,
2322
- enumNames,
2323
- circularNames,
2324
- discriminatorChildMap,
2325
- promotedEnums
2326
- };
2327
- }
2328
- /**
2329
- * Creates a lazy `InputNode<true>` from already-resolved adapter state.
2330
- *
2331
- * The schema and operation iterables each start a fresh parse pass on every
2332
- * `[Symbol.asyncIterator]()` call. This lets multiple plugins consume the same
2333
- * stream object independently without sharing a cursor or holding all nodes in memory.
2334
- *
2335
- * Ref aliases in `refAliasMap` are inlined during iteration: an alias entry is replaced
2336
- * with its target's parsed node (but keeps the alias name) so plugins never receive bare `ref` nodes.
2337
- *
2338
- * @example
2339
- * ```ts
2340
- * const streamNode = createInputStream({ schemas, parseSchema, parseOperation, document, parserOptions, refAliasMap, discriminatorChildMap, meta })
2341
- * for await (const schema of streamNode.schemas) {
2342
- * // each call to for-await restarts from the first schema
2343
- * }
2344
- * ```
2345
- */
2346
- function createInputStream({ schemas, parseSchema, parseOperation, document, parserOptions, refAliasMap, discriminatorChildMap, promotedEnums, meta }) {
2347
- const schemasIterable = { [Symbol.asyncIterator]() {
2348
- return (async function* () {
2349
- if (promotedEnums) for (const definition of promotedEnums.values()) yield definition;
2350
- for (const [name, schema] of Object.entries(schemas)) {
2351
- const alias = refAliasMap.get(name);
2352
- if (alias?.name && schemas[alias.name]) {
2353
- const aliasNode = {
2354
- ...parseSchema({
2355
- schema: schemas[alias.name],
2356
- name: alias.name
2357
- }, parserOptions),
2358
- name
2359
- };
2360
- yield promotedEnums ? refPromotedEnums(aliasNode, promotedEnums) : aliasNode;
2361
- continue;
2362
- }
2363
- const parsed = parseSchema({
2364
- schema,
2365
- name
2366
- }, parserOptions);
2367
- const node = discriminatorChildMap?.get(name) ? patchDiscriminatorNode(parsed, discriminatorChildMap.get(name)) : parsed;
2368
- yield promotedEnums ? refPromotedEnums(node, promotedEnums) : node;
2369
- }
2370
- })();
2371
- } };
2372
- const operationsIterable = { [Symbol.asyncIterator]() {
2373
- return (async function* () {
2374
- for (const operation of getOperations(document)) {
2375
- const node = parseOperation(parserOptions, operation);
2376
- if (node) yield promotedEnums ? refPromotedEnums(node, promotedEnums) : node;
2377
- }
2378
- })();
2379
- } };
2380
- return _kubb_ast.ast.factory.createInput({
2381
- stream: true,
2382
- schemas: schemasIterable,
2383
- operations: operationsIterable,
2384
- meta
2385
- });
2386
- }
2387
- //#endregion
2388
2262
  //#region src/adapter.ts
2389
2263
  /**
2390
2264
  * The `name` of `@kubb/adapter-oas`, used to identify this adapter in a Kubb config.
@@ -2432,7 +2306,6 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
2432
2306
  const documentCache = /* @__PURE__ */ new WeakMap();
2433
2307
  const schemasCache = /* @__PURE__ */ new WeakMap();
2434
2308
  const schemaParserCache = /* @__PURE__ */ new WeakMap();
2435
- const preScanCache = /* @__PURE__ */ new WeakMap();
2436
2309
  function ensureDocument(source) {
2437
2310
  const cached = documentCache.get(source);
2438
2311
  if (cached) return cached;
@@ -2466,35 +2339,57 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
2466
2339
  schemaParserCache.set(document, parser);
2467
2340
  return parser;
2468
2341
  }
2469
- function ensurePreScan(document, schemas, parseSchema, parseOperation) {
2470
- const cached = preScanCache.get(document);
2471
- if (cached) return cached;
2472
- const result = preScan({
2473
- schemas,
2474
- parseSchema,
2475
- parseOperation,
2476
- document,
2477
- parserOptions,
2478
- discriminator,
2479
- enums
2480
- });
2481
- preScanCache.set(document, result);
2482
- return result;
2483
- }
2484
- async function createStream(source) {
2485
- const document = await ensureDocument(source);
2486
- const schemas = await ensureSchemas(document);
2487
- const { parseSchema, parseOperation } = ensureSchemaParser(document);
2488
- const { refAliasMap, enumNames, circularNames, discriminatorChildMap, promotedEnums } = ensurePreScan(document, schemas, parseSchema, parseOperation);
2489
- return createInputStream({
2490
- schemas,
2491
- parseSchema,
2492
- parseOperation,
2493
- document,
2494
- parserOptions,
2495
- refAliasMap,
2496
- discriminatorChildMap,
2497
- promotedEnums,
2342
+ function parseInput({ document, schemas, parser }) {
2343
+ const { parseSchema, parseOperation } = parser;
2344
+ const parsedByName = /* @__PURE__ */ new Map();
2345
+ const refAliasMap = /* @__PURE__ */ new Map();
2346
+ const enumNames = [];
2347
+ const discriminatorParentNodes = [];
2348
+ for (const [name, schema] of Object.entries(schemas)) {
2349
+ const node = parseSchema({
2350
+ schema,
2351
+ name
2352
+ }, parserOptions);
2353
+ parsedByName.set(name, node);
2354
+ reportSchemaDiagnostics({
2355
+ node,
2356
+ name
2357
+ });
2358
+ if (node.type === "ref" && node.name && node.name !== name) refAliasMap.set(name, node);
2359
+ if ((0, _kubb_ast.narrowSchema)(node, "enum") && node.name) enumNames.push(node.name);
2360
+ if (discriminator === "propagate" && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) discriminatorParentNodes.push(node);
2361
+ }
2362
+ const circularNames = [...(0, _kubb_ast.findCircularSchemas)([...parsedByName.values()])];
2363
+ const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null;
2364
+ const operationNodes = [];
2365
+ for (const operation of getOperations(document)) {
2366
+ const operationNode = parseOperation(parserOptions, operation);
2367
+ if (operationNode) operationNodes.push(operationNode);
2368
+ }
2369
+ let promotedEnums = null;
2370
+ if (enums === "root") {
2371
+ promotedEnums = collectInlineEnums([...parsedByName.values(), ...operationNodes], new Set(Object.keys(schemas)));
2372
+ for (const name of promotedEnums.keys()) enumNames.push(name);
2373
+ }
2374
+ const schemaNodes = promotedEnums ? [...promotedEnums.values()] : [];
2375
+ for (const name of Object.keys(schemas)) {
2376
+ const alias = refAliasMap.get(name);
2377
+ let node;
2378
+ if (alias?.name && parsedByName.has(alias.name)) node = {
2379
+ ...parsedByName.get(alias.name),
2380
+ name
2381
+ };
2382
+ else {
2383
+ const parsed = parsedByName.get(name);
2384
+ const child = discriminatorChildMap?.get(name);
2385
+ node = child ? patchDiscriminatorNode(parsed, child) : parsed;
2386
+ }
2387
+ schemaNodes.push(promotedEnums ? refPromotedEnums(node, promotedEnums) : node);
2388
+ }
2389
+ const operations = promotedEnums ? operationNodes.map((node) => refPromotedEnums(node, promotedEnums)) : operationNodes;
2390
+ return _kubb_ast.ast.factory.createInput({
2391
+ schemas: schemaNodes,
2392
+ operations,
2498
2393
  meta: {
2499
2394
  title: document.info?.title,
2500
2395
  description: document.info?.description,
@@ -2545,15 +2440,13 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
2545
2440
  } });
2546
2441
  },
2547
2442
  async parse(source) {
2548
- const streamNode = await createStream(source);
2549
- const [schemas, operations] = await Promise.all([Array.fromAsync(streamNode.schemas), Array.fromAsync(streamNode.operations)]);
2550
- return _kubb_ast.ast.factory.createInput({
2551
- schemas,
2552
- operations,
2553
- meta: streamNode.meta
2443
+ const document = await ensureDocument(source);
2444
+ return parseInput({
2445
+ document,
2446
+ schemas: await ensureSchemas(document),
2447
+ parser: ensureSchemaParser(document)
2554
2448
  });
2555
- },
2556
- stream: createStream
2449
+ }
2557
2450
  };
2558
2451
  });
2559
2452
  //#endregion