@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/adapter-oas",
3
- "version": "5.0.0-beta.57",
3
+ "version": "5.0.0-beta.59",
4
4
  "description": "OpenAPI and Swagger adapter for Kubb. Parses and validates OAS 2.0/3.x specifications into a @kubb/ast RootNode for downstream code generation plugins.",
5
5
  "keywords": [
6
6
  "adapter",
@@ -46,8 +46,8 @@
46
46
  "api-ref-bundler": "0.5.1",
47
47
  "swagger2openapi": "^7.0.8",
48
48
  "yaml": "^2.9.0",
49
- "@kubb/ast": "5.0.0-beta.57",
50
- "@kubb/core": "5.0.0-beta.57"
49
+ "@kubb/ast": "5.0.0-beta.59",
50
+ "@kubb/core": "5.0.0-beta.59"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/json-schema": "^7.0.15",
package/src/adapter.ts CHANGED
@@ -191,7 +191,7 @@ export const adapterOas = createAdapter<AdapterOas>((options) => {
191
191
  const result = resolve(schemaName)
192
192
  if (!result) return null
193
193
 
194
- return ast.createImport({ name: [result.name], path: result.path })
194
+ return ast.factory.createImport({ name: [result.name], path: result.path })
195
195
  },
196
196
  })
197
197
  },
@@ -200,7 +200,7 @@ export const adapterOas = createAdapter<AdapterOas>((options) => {
200
200
 
201
201
  const [schemas, operations] = await Promise.all([Array.fromAsync(streamNode.schemas), Array.fromAsync(streamNode.operations)])
202
202
 
203
- return ast.createInput({ schemas, operations, meta: streamNode.meta })
203
+ return ast.factory.createInput({ schemas, operations, meta: streamNode.meta })
204
204
  },
205
205
  stream: createStream,
206
206
  }
package/src/constants.ts CHANGED
@@ -73,7 +73,7 @@ export const structuralKeys = new Set(['properties', 'items', 'additionalPropert
73
73
  *
74
74
  * Only formats whose AST type differs from the OAS `type` field appear here.
75
75
  * Formats that depend on runtime options (`int64`, `date-time`, `date`, `time`) are handled separately
76
- * in the parser. `ipv4` and `ipv6` map to their own dedicated schema types; `hostname` and
76
+ * in the parser. `ipv4` and `ipv6` map to their own dedicated schema types. `hostname` and
77
77
  * `idn-hostname` map to `'url'` as the closest generic string-format type.
78
78
  *
79
79
  * @example
@@ -126,8 +126,8 @@ export const formatMap = {
126
126
  export const enumExtensionKeys = ['x-enumNames', 'x-enum-varnames'] as const
127
127
 
128
128
  /**
129
- * Maps `'any' | 'unknown' | 'void'` option strings to their `ScalarSchemaType` constant.
130
- * Replaces a plain object lookup with a `Map` for explicit key membership testing via `.has()`.
129
+ * Maps the `unknownType`/`emptySchemaType` option string to its `ScalarSchemaType` constant.
130
+ * A `Map` (over a plain object) lets callers test key membership with `.has()`.
131
131
  */
132
132
  export const typeOptionMap = new Map<'any' | 'unknown' | 'void', ast.ScalarSchemaType>([
133
133
  ['any', ast.schemaTypes.any],
@@ -82,11 +82,51 @@ export function patchDiscriminatorNode(node: ast.SchemaNode, entry: { propertyNa
82
82
  if (!objectNode) return node
83
83
 
84
84
  const { propertyName, enumValues } = entry
85
- const enumSchema = ast.createSchema({ type: 'enum', enumValues })
86
- const newProp = ast.createProperty({ name: propertyName, required: true, schema: enumSchema })
85
+ const enumSchema = ast.factory.createSchema({ type: 'enum', enumValues })
86
+ const newProp = ast.factory.createProperty({ name: propertyName, required: true, schema: enumSchema })
87
87
 
88
88
  const existingIdx = objectNode.properties.findIndex((p) => p.name === propertyName)
89
89
  const newProperties = existingIdx >= 0 ? objectNode.properties.map((p, i) => (i === existingIdx ? newProp : p)) : [...objectNode.properties, newProp]
90
90
 
91
91
  return { ...objectNode, properties: newProperties }
92
92
  }
93
+
94
+ /**
95
+ * Creates a single-property object schema used as a discriminator literal.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * createDiscriminantNode({ propertyName: 'type', value: 'dog' })
100
+ * // -> { type: 'object', properties: [{ name: 'type', required: true, schema: enum('dog') }] }
101
+ * ```
102
+ */
103
+ export function createDiscriminantNode({ propertyName, value }: { propertyName: string; value: string }): ast.SchemaNode {
104
+ return ast.factory.createSchema({
105
+ type: 'object',
106
+ primitive: 'object',
107
+ properties: [
108
+ ast.factory.createProperty({
109
+ name: propertyName,
110
+ schema: ast.factory.createSchema({
111
+ type: 'enum',
112
+ primitive: 'string',
113
+ enumValues: [value],
114
+ }),
115
+ required: true,
116
+ }),
117
+ ],
118
+ })
119
+ }
120
+
121
+ /**
122
+ * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'
127
+ * ```
128
+ */
129
+ export function findDiscriminator(mapping: Record<string, string> | undefined, ref: string | undefined): string | null {
130
+ if (!mapping || !ref) return null
131
+ return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null
132
+ }
package/src/parser.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { pascalCase } from '@internals/utils'
2
- import { childName, enumPropName, extractRefName, findDiscriminator } from '@kubb/ast/utils'
2
+ import { childName, enumPropName, extractRefName } from '@kubb/ast/utils'
3
3
  import { ast } from '@kubb/core'
4
4
  import { DEFAULT_PARSER_OPTIONS, enumExtensionKeys, SCHEMA_REF_PREFIX, typeOptionMap } from './constants.ts'
5
5
  import { oasDialect, type OasDialect } from './dialect.ts'
6
+ import { createDiscriminantNode, findDiscriminator } from './discriminator.ts'
6
7
  import { getOperationId, getOperations, getRequestContentType, getResponseByStatusCode, getResponseStatusCodes } from './operation.ts'
7
8
  import {
8
9
  buildSchemaNode,
@@ -66,11 +67,17 @@ type SchemaContext = {
66
67
  * that is not convertible falls through to plain `type` handling).
67
68
  */
68
69
  type SchemaRule = {
69
- /** Identifies the rule when reading the table or debugging which branch ran. */
70
+ /**
71
+ * Identifies the rule when reading the table or debugging which branch ran.
72
+ */
70
73
  name: string
71
- /** Returns `true` when this rule is responsible for the given context. */
74
+ /**
75
+ * Returns `true` when this rule is responsible for the given context.
76
+ */
72
77
  match: (context: SchemaContext) => boolean
73
- /** Produces a node for the context, or `null` to fall through to the next rule. */
78
+ /**
79
+ * Produces a node for the context, or `null` to fall through to the next rule.
80
+ */
74
81
  convert: (context: SchemaContext) => ast.SchemaNode | null
75
82
  }
76
83
 
@@ -78,9 +85,9 @@ type SchemaRule = {
78
85
  * Normalizes malformed `{ type: 'array', enum: [...] }` schemas by moving enum values into items.
79
86
  *
80
87
  * This pattern violates the OpenAPI spec but appears in real specs. The fix moves enum values
81
- * from the array to its items sub-schema, making them valid for downstream processing.
88
+ * from the array to its items sub-schema, so they are valid for downstream processing.
82
89
  *
83
- * @note This is a defensive measure for robustness with non-compliant specs.
90
+ * @note A defensive measure for non-compliant specs.
84
91
  */
85
92
  function normalizeArrayEnum(schema: SchemaObject): SchemaObject {
86
93
  const isItemsObject = typeof schema.items === 'object' && !Array.isArray(schema.items)
@@ -98,7 +105,7 @@ function normalizeArrayEnum(schema: SchemaObject): SchemaObject {
98
105
  *
99
106
  * Returns closures that share mutable state (`resolvingRefs` set for cycle detection).
100
107
  * Each converter branch (`convertRef`, `convertAllOf`, etc.) mutually recursively calls `parseSchema`,
101
- * made possible by hoisting of function declarations.
108
+ * which works because function declarations hoist.
102
109
  *
103
110
  * @internal
104
111
  */
@@ -151,7 +158,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
151
158
  resolvedSchema = resolvedRefCache.get(refPath) ?? null
152
159
  }
153
160
 
154
- return ast.createSchema({
161
+ return ast.factory.createSchema({
155
162
  ...buildSchemaNode(schema, name, nullable, defaultValue),
156
163
  type: 'ref',
157
164
  name: extractRefName(schema.$ref!),
@@ -176,7 +183,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
176
183
  const mergedNullable = nullable || memberNode.nullable || undefined
177
184
  const mergedDefault = schema.default === null && mergedNullable ? undefined : (schema.default ?? memberNode.default)
178
185
 
179
- return ast.createSchema({
186
+ return ast.factory.createSchema({
180
187
  ...memberNodeProps,
181
188
  name,
182
189
  title: schema.title ?? memberNode.title,
@@ -264,10 +271,10 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
264
271
  }
265
272
 
266
273
  for (const { propertyName, value } of filteredDiscriminantValues) {
267
- allOfMembers.push(ast.createDiscriminantNode({ propertyName, value }))
274
+ allOfMembers.push(createDiscriminantNode({ propertyName, value }))
268
275
  }
269
276
 
270
- return ast.createSchema({
277
+ return ast.factory.createSchema({
271
278
  type: 'intersection',
272
279
  members: [...ast.mergeAdjacentObjectsLazy(allOfMembers.slice(0, syntheticStart)), ...ast.mergeAdjacentObjectsLazy(allOfMembers.slice(syntheticStart))],
273
280
  ...buildSchemaNode(schema, name, nullable, defaultValue),
@@ -286,7 +293,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
286
293
  return null
287
294
  }
288
295
 
289
- return ast.createSchema({
296
+ return ast.factory.createSchema({
290
297
  type: 'object',
291
298
  primitive: 'object',
292
299
  properties: [discriminatorProperty],
@@ -332,12 +339,12 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
332
339
  )
333
340
  : undefined
334
341
 
335
- return ast.createSchema({
342
+ return ast.factory.createSchema({
336
343
  type: 'intersection',
337
344
  members: [
338
345
  memberNode,
339
346
  narrowedDiscriminatorNode ??
340
- ast.createDiscriminantNode({
347
+ createDiscriminantNode({
341
348
  propertyName: discriminator.propertyName,
342
349
  value: discriminatorValue,
343
350
  }),
@@ -345,7 +352,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
345
352
  })
346
353
  })
347
354
 
348
- const unionNode = ast.createSchema({
355
+ const unionNode = ast.factory.createSchema({
349
356
  type: 'union',
350
357
  ...unionBase,
351
358
  members,
@@ -355,14 +362,14 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
355
362
  return unionNode
356
363
  }
357
364
 
358
- return ast.createSchema({
365
+ return ast.factory.createSchema({
359
366
  type: 'intersection',
360
367
  ...buildSchemaNode(schema, name, nullable, defaultValue),
361
368
  members: [unionNode, sharedPropertiesNode],
362
369
  })
363
370
  }
364
371
 
365
- return ast.createSchema({
372
+ return ast.factory.createSchema({
366
373
  type: 'union',
367
374
  ...unionBase,
368
375
  members: ast.simplifyUnion(unionMembers.map((s) => parseSchema({ schema: s as SchemaObject, name }, rawOptions))),
@@ -376,7 +383,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
376
383
  const constValue = schema.const
377
384
 
378
385
  if (constValue === null) {
379
- return ast.createSchema({
386
+ return ast.factory.createSchema({
380
387
  type: 'null',
381
388
  primitive: 'null',
382
389
  name,
@@ -388,7 +395,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
388
395
  }
389
396
 
390
397
  const constPrimitive = getPrimitiveType(typeof constValue === 'number' ? 'number' : typeof constValue === 'boolean' ? 'boolean' : 'string')
391
- return ast.createSchema({
398
+ return ast.factory.createSchema({
392
399
  type: 'enum',
393
400
  primitive: constPrimitive,
394
401
  enumValues: [constValue as string | number | boolean],
@@ -404,7 +411,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
404
411
  const base = buildSchemaNode(schema, name, nullable, defaultValue)
405
412
 
406
413
  if (schema.format === 'int64') {
407
- return ast.createSchema({
414
+ return ast.factory.createSchema({
408
415
  type: options.integerType === 'bigint' ? 'bigint' : 'integer',
409
416
  primitive: 'integer',
410
417
  ...base,
@@ -420,7 +427,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
420
427
  if (!dateType) return null
421
428
 
422
429
  if (dateType.type === 'datetime') {
423
- return ast.createSchema({
430
+ return ast.factory.createSchema({
424
431
  ...base,
425
432
  primitive: 'string' as const,
426
433
  type: 'datetime',
@@ -428,7 +435,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
428
435
  local: dateType.local,
429
436
  })
430
437
  }
431
- return ast.createSchema({
438
+ return ast.factory.createSchema({
432
439
  ...base,
433
440
  primitive: 'string' as const,
434
441
  type: dateType.type,
@@ -442,14 +449,14 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
442
449
  const specialPrimitive: ast.PrimitiveSchemaType = specialType === 'number' || specialType === 'integer' || specialType === 'bigint' ? specialType : 'string'
443
450
 
444
451
  if (specialType === 'number' || specialType === 'integer' || specialType === 'bigint') {
445
- return ast.createSchema({
452
+ return ast.factory.createSchema({
446
453
  ...base,
447
454
  primitive: specialPrimitive,
448
455
  type: specialType,
449
456
  })
450
457
  }
451
458
  if (specialType === 'url') {
452
- return ast.createSchema({
459
+ return ast.factory.createSchema({
453
460
  ...base,
454
461
  primitive: 'string' as const,
455
462
  type: 'url',
@@ -458,21 +465,21 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
458
465
  })
459
466
  }
460
467
  if (specialType === 'ipv4') {
461
- return ast.createSchema({
468
+ return ast.factory.createSchema({
462
469
  ...base,
463
470
  primitive: 'string' as const,
464
471
  type: 'ipv4',
465
472
  })
466
473
  }
467
474
  if (specialType === 'ipv6') {
468
- return ast.createSchema({
475
+ return ast.factory.createSchema({
469
476
  ...base,
470
477
  primitive: 'string' as const,
471
478
  type: 'ipv6',
472
479
  })
473
480
  }
474
481
  if (specialType === 'uuid' || specialType === 'email') {
475
- return ast.createSchema({
482
+ return ast.factory.createSchema({
476
483
  ...base,
477
484
  primitive: 'string' as const,
478
485
  type: specialType,
@@ -481,7 +488,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
481
488
  })
482
489
  }
483
490
 
484
- return ast.createSchema({
491
+ return ast.factory.createSchema({
485
492
  ...base,
486
493
  primitive: specialPrimitive,
487
494
  type: specialType as ast.ScalarSchemaType,
@@ -503,7 +510,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
503
510
  // render as `never` (plugin-ts) / invalid `z.enum([])` (plugin-zod). Mirror the `const: null`
504
511
  // branch so it renders as a clean `null` (not `z.null().nullable()`).
505
512
  if (nullInEnum && filteredValues.length === 0) {
506
- return ast.createSchema({
513
+ return ast.factory.createSchema({
507
514
  type: 'null',
508
515
  primitive: 'null',
509
516
  name,
@@ -543,7 +550,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
543
550
  const uniqueValues = [...new Set(filteredValues)]
544
551
  const seenNames = new Set<string>()
545
552
 
546
- return ast.createSchema({
553
+ return ast.factory.createSchema({
547
554
  ...enumBase,
548
555
  primitive: enumPrimitiveType,
549
556
  namedEnumValues: uniqueValues
@@ -560,7 +567,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
560
567
  })
561
568
  }
562
569
 
563
- return ast.createSchema({
570
+ return ast.factory.createSchema({
564
571
  ...enumBase,
565
572
  enumValues: [...new Set(filteredValues)],
566
573
  })
@@ -590,7 +597,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
590
597
  return node
591
598
  })()
592
599
 
593
- return ast.createProperty({
600
+ return ast.factory.createProperty({
594
601
  name: propName,
595
602
  schema: {
596
603
  ...schemaNode,
@@ -608,7 +615,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
608
615
  if (additionalProperties && Object.keys(additionalProperties).length > 0) {
609
616
  return parseSchema({ schema: additionalProperties as SchemaObject }, rawOptions)
610
617
  }
611
- if (additionalProperties) return ast.createSchema({ type: typeOptionMap.get(options.unknownType)! })
618
+ if (additionalProperties) return ast.factory.createSchema({ type: typeOptionMap.get(options.unknownType)! })
612
619
  return undefined
613
620
  })()
614
621
 
@@ -619,7 +626,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
619
626
  Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [
620
627
  pattern,
621
628
  patternSchema === true || (typeof patternSchema === 'object' && Object.keys(patternSchema).length === 0)
622
- ? ast.createSchema({
629
+ ? ast.factory.createSchema({
623
630
  type: typeOptionMap.get(options.unknownType)!,
624
631
  })
625
632
  : parseSchema({ schema: patternSchema as SchemaObject }, rawOptions),
@@ -627,7 +634,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
627
634
  )
628
635
  : undefined
629
636
 
630
- const objectNode: ast.SchemaNode = ast.createSchema({
637
+ const objectNode: ast.SchemaNode = ast.factory.createSchema({
631
638
  type: 'object',
632
639
  primitive: 'object',
633
640
  properties,
@@ -658,9 +665,9 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
658
665
  */
659
666
  function convertTuple({ schema, name, nullable, defaultValue, rawOptions }: SchemaContext): ast.SchemaNode {
660
667
  const tupleItems = (schema.prefixItems ?? []).map((item) => parseSchema({ schema: item as SchemaObject }, rawOptions))
661
- const rest = schema.items ? parseSchema({ schema: schema.items as SchemaObject }, rawOptions) : ast.createSchema({ type: 'any' })
668
+ const rest = schema.items ? parseSchema({ schema: schema.items as SchemaObject }, rawOptions) : ast.factory.createSchema({ type: 'any' })
662
669
 
663
- return ast.createSchema({
670
+ return ast.factory.createSchema({
664
671
  type: 'tuple',
665
672
  primitive: 'array',
666
673
  items: tupleItems,
@@ -679,7 +686,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
679
686
  const itemName = rawItems?.enum?.length && name ? enumPropName(null, name, options.enumSuffix) : name
680
687
  const items = rawItems ? [parseSchema({ schema: rawItems, name: itemName }, rawOptions)] : []
681
688
 
682
- return ast.createSchema({
689
+ return ast.factory.createSchema({
683
690
  type: 'array',
684
691
  primitive: 'array',
685
692
  items,
@@ -694,7 +701,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
694
701
  * Converts a `type: 'string'` schema into a `StringSchemaNode`.
695
702
  */
696
703
  function convertString({ schema, name, nullable, defaultValue }: SchemaContext): ast.SchemaNode {
697
- return ast.createSchema({
704
+ return ast.factory.createSchema({
698
705
  type: 'string',
699
706
  primitive: 'string',
700
707
  min: schema.minLength,
@@ -708,7 +715,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
708
715
  * Converts a `type: 'number'` or `type: 'integer'` schema.
709
716
  */
710
717
  function convertNumeric({ schema, name, nullable, defaultValue }: SchemaContext, type: 'number' | 'integer'): ast.SchemaNode {
711
- return ast.createSchema({
718
+ return ast.factory.createSchema({
712
719
  type,
713
720
  primitive: type,
714
721
  min: schema.minimum,
@@ -724,7 +731,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
724
731
  * Converts a `type: 'boolean'` schema.
725
732
  */
726
733
  function convertBoolean({ schema, name, nullable, defaultValue }: SchemaContext): ast.SchemaNode {
727
- return ast.createSchema({
734
+ return ast.factory.createSchema({
728
735
  type: 'boolean',
729
736
  primitive: 'boolean',
730
737
  ...buildSchemaNode(schema, name, nullable, defaultValue),
@@ -735,7 +742,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
735
742
  * Converts an explicit `type: 'null'` schema.
736
743
  */
737
744
  function convertNull({ schema, name, nullable }: SchemaContext): ast.SchemaNode {
738
- return ast.createSchema({
745
+ return ast.factory.createSchema({
739
746
  type: 'null',
740
747
  primitive: 'null',
741
748
  name,
@@ -752,7 +759,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
752
759
  * into a `blob` node.
753
760
  */
754
761
  function convertBlob({ schema, name, nullable, defaultValue }: SchemaContext): ast.SchemaNode {
755
- return ast.createSchema({
762
+ return ast.factory.createSchema({
756
763
  type: 'blob',
757
764
  primitive: 'string',
758
765
  ...buildSchemaNode(schema, name, nullable, defaultValue),
@@ -771,7 +778,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
771
778
  if (nonNullTypes.length <= 1) return null
772
779
 
773
780
  const arrayNullable = types.includes('null') || nullable || undefined
774
- return ast.createSchema({
781
+ return ast.factory.createSchema({
775
782
  type: 'union',
776
783
  members: nonNullTypes.map((t) => parseSchema({ schema: { ...schema, type: t } as SchemaObject, name }, rawOptions)),
777
784
  ...buildSchemaNode(schema, name, arrayNullable, defaultValue),
@@ -859,7 +866,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
859
866
  }
860
867
 
861
868
  const emptyType = typeOptionMap.get(options.emptySchemaType)!
862
- return ast.createSchema({
869
+ return ast.factory.createSchema({
863
870
  type: emptyType as ast.ScalarSchemaType,
864
871
  name,
865
872
  title: schema.title,
@@ -878,9 +885,9 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
878
885
 
879
886
  const schema: ast.SchemaNode = param['schema']
880
887
  ? parseSchema({ schema: param['schema'] as SchemaObject, name: schemaName }, options)
881
- : ast.createSchema({ type: typeOptionMap.get(options.unknownType)! })
888
+ : ast.factory.createSchema({ type: typeOptionMap.get(options.unknownType)! })
882
889
 
883
- return ast.createParameter({
890
+ return ast.factory.createParameter({
884
891
  name: paramName,
885
892
  in: param['in'] as ast.ParameterLocation,
886
893
  schema: {
@@ -996,7 +1003,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
996
1003
  const node =
997
1004
  raw && Object.keys(raw).length > 0
998
1005
  ? parseSchema({ schema: raw, name: responseName }, options)
999
- : ast.createSchema({ type: typeOptionMap.get(options.emptySchemaType)! })
1006
+ : ast.factory.createSchema({ type: typeOptionMap.get(options.emptySchemaType)! })
1000
1007
  return { schema: node, keysToOmit: collectPropertyKeysByFlag(raw, 'writeOnly') }
1001
1008
  }
1002
1009
 
@@ -1011,7 +1018,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
1011
1018
  content.push({ contentType: getRequestContentType({ document, operation }) || 'application/json', ...parseEntrySchema(ctx.contentType) })
1012
1019
  }
1013
1020
 
1014
- return ast.createResponse({
1021
+ return ast.factory.createResponse({
1015
1022
  statusCode: statusCode as ast.StatusCode,
1016
1023
  description,
1017
1024
  content,
@@ -1027,7 +1034,7 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
1027
1034
  return typeof fallback === 'string' ? fallback : undefined
1028
1035
  }
1029
1036
 
1030
- return ast.createOperation({
1037
+ return ast.factory.createOperation({
1031
1038
  operationId,
1032
1039
  protocol: 'http',
1033
1040
  method: operation.method.toUpperCase() as ast.HttpMethod,
@@ -1048,10 +1055,11 @@ export function createSchemaParser(ctx: OasParserContext, dialect: OasDialect =
1048
1055
  /**
1049
1056
  * Parses a single OpenAPI `SchemaObject` into a `SchemaNode`.
1050
1057
  *
1051
- * Use this for targeted schema parsing when you don't need the full spec.
1052
- * For complete spec parsing, use `parseOas()` instead which handles operations and all schemas together.
1058
+ * Reach for this when you only need one schema, not the whole spec. To parse a full spec
1059
+ * with its operations and schemas, call `parseOas()`.
1053
1060
  *
1054
- * @note Circular schema references are tracked via internal state and resolve appropriately.
1061
+ * @note Internal state tracks `$ref` paths under resolution, so circular schemas stop
1062
+ * recursing instead of looping.
1055
1063
  *
1056
1064
  * @example
1057
1065
  * ```ts
@@ -1072,7 +1080,8 @@ export function parseSchema(
1072
1080
  * Parses an OpenAPI specification into Kubb's universal `InputNode` AST.
1073
1081
  *
1074
1082
  * This is the main entry point for `@kubb/adapter-oas`. It converts OpenAPI/Swagger specs into a spec-agnostic tree
1075
- * that downstream plugins (`plugin-ts`, `plugin-zod`, etc.) consume for code generation. No code is generated here, * the tree is a pure data structure representing all schemas and operations.
1083
+ * that downstream plugins (`plugin-ts`, `plugin-zod`, etc.) consume for code generation. No code is generated here.
1084
+ * The tree is a pure data structure of all schemas and operations.
1076
1085
  *
1077
1086
  * Returns the AST root and a `nameMapping` for resolving schema references.
1078
1087
  *
@@ -1105,7 +1114,7 @@ export function parseOas(
1105
1114
  .map((operation) => _parseOperation(mergedOptions, operation))
1106
1115
  .filter((op): op is ast.OperationNode => op !== null)
1107
1116
 
1108
- const root = ast.createInput({ schemas, operations })
1117
+ const root = ast.factory.createInput({ schemas, operations })
1109
1118
 
1110
1119
  return { root, nameMapping }
1111
1120
  }
package/src/resolvers.ts CHANGED
@@ -470,7 +470,7 @@ export function getSchemas(document: Document, { contentType }: GetSchemasOption
470
470
 
471
471
  /**
472
472
  * Resolves the AST type descriptor for a date/time format, honoring the `dateType` option.
473
- * Returns `null` when `dateType: false`, signalling the format should fall through to `string`.
473
+ * Returns `null` when `dateType: false`, so the format falls through to `string`.
474
474
  */
475
475
  export function getDateType(
476
476
  options: ast.ParserOptions,
package/src/stream.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { containsCircularRef, findCircularSchemas } from '@kubb/ast/utils'
1
2
  import { ast } from '@kubb/core'
2
3
  import { SCHEMA_REF_PREFIX } from './constants.ts'
3
4
  import { buildDiscriminatorChildMap, patchDiscriminatorNode } from './discriminator.ts'
@@ -22,7 +23,7 @@ export type PreScanResult = {
22
23
  *
23
24
  * Only enums and objects are candidates, and object shapes that reference a circular schema are
24
25
  * rejected to avoid hoisting recursive structures. Inline shapes reuse their context-derived
25
- * name (collision-resolved against existing component names); shapes without a name stay inline.
26
+ * name (collision-resolved against existing component names). Shapes without a name stay inline.
26
27
  */
27
28
  function createDedupePlan({
28
29
  schemaNodes,
@@ -44,7 +45,7 @@ function createDedupePlan({
44
45
  if (node.type !== 'object') return false
45
46
  // Skip object shapes that are part of a circular chain, hoisting them would break the cycle.
46
47
  if (node.name && circularSchemas.has(node.name)) return false
47
- return !ast.containsCircularRef(node, { circularSchemas })
48
+ return !containsCircularRef(node, { circularSchemas })
48
49
  },
49
50
  nameFor: (node) => {
50
51
  const base = node.name
@@ -149,7 +150,7 @@ export function preScan({
149
150
  }
150
151
  }
151
152
 
152
- const circularNames = [...ast.findCircularSchemas(allNodes)]
153
+ const circularNames = [...findCircularSchemas(allNodes)]
153
154
  const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null
154
155
 
155
156
  let dedupePlan: ast.DedupePlan | null = null
@@ -217,14 +218,14 @@ export function createInputStream({
217
218
  meta: ast.InputMeta
218
219
  }): ast.InputNode<true> {
219
220
  // Rewrites a top-level schema against the dedupe plan: a structurally identical sibling
220
- // becomes a `ref` alias to the canonical one (keeping its own name); otherwise nested
221
+ // becomes a `ref` alias to the canonical one (keeping its own name). Otherwise nested
221
222
  // duplicates are collapsed while the schema's own root is preserved.
222
223
  const rewriteTopLevelSchema = (node: ast.SchemaNode): ast.SchemaNode => {
223
224
  if (!dedupePlan) return node
224
225
 
225
226
  const canonical = dedupePlan.canonicalBySignature.get(ast.signatureOf(node))
226
227
  if (canonical && canonical.name !== node.name) {
227
- return ast.createSchema({
228
+ return ast.factory.createSchema({
228
229
  type: 'ref',
229
230
  name: node.name ?? null,
230
231
  ref: canonical.ref,
@@ -278,5 +279,5 @@ export function createInputStream({
278
279
  },
279
280
  }
280
281
 
281
- return ast.createStreamInput(schemasIterable, operationsIterable, meta)
282
+ return ast.factory.createInput({ stream: true, schemas: schemasIterable, operations: operationsIterable, meta })
282
283
  }