@kubb/adapter-oas 5.0.0-beta.17 → 5.0.0-beta.19

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.17",
3
+ "version": "5.0.0-beta.19",
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",
@@ -47,7 +47,7 @@
47
47
  "oas": "^32.1.18",
48
48
  "oas-normalize": "^16.0.4",
49
49
  "swagger2openapi": "^7.0.8",
50
- "@kubb/core": "5.0.0-beta.17"
50
+ "@kubb/core": "5.0.0-beta.19"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/swagger2openapi": "^7.0.4",
package/src/adapter.ts CHANGED
@@ -58,6 +58,8 @@ export const adapterOas = createAdapter<AdapterOas>((options) => {
58
58
  let nameMapping = new Map<string, string>()
59
59
  let parsedDocument: Document | null = null
60
60
  let schemaObjects: ReturnType<typeof getSchemas>['schemas'] | null = null
61
+ let baseOasInstance: BaseOas | null = null
62
+ let schemaParserInstance: ReturnType<typeof createSchemaParser> | null = null
61
63
 
62
64
  function resolveBaseURL(document: Document): string | undefined {
63
65
  const server = serverIndex !== undefined ? document.servers?.at(serverIndex) : undefined
@@ -81,6 +83,16 @@ export const adapterOas = createAdapter<AdapterOas>((options) => {
81
83
  return schemaObjects
82
84
  }
83
85
 
86
+ function ensureBaseOas(document: Document): BaseOas {
87
+ if (!baseOasInstance) baseOasInstance = new BaseOas(document)
88
+ return baseOasInstance
89
+ }
90
+
91
+ function ensureSchemaParser(document: Document): ReturnType<typeof createSchemaParser> {
92
+ if (!schemaParserInstance) schemaParserInstance = createSchemaParser({ document, contentType })
93
+ return schemaParserInstance
94
+ }
95
+
84
96
  return {
85
97
  name: adapterOasName,
86
98
  get options() {
@@ -148,7 +160,7 @@ export const adapterOas = createAdapter<AdapterOas>((options) => {
148
160
  const document = await ensureDocument(source)
149
161
  const schemas = await ensureSchemas(document)
150
162
 
151
- const baseOas = new BaseOas(document)
163
+ const baseOas = ensureBaseOas(document)
152
164
  const operationCount = Object.values(baseOas.getPaths()).flatMap(Object.values).filter(Boolean).length
153
165
 
154
166
  return { schemas: Object.keys(schemas).length, operations: operationCount }
@@ -157,30 +169,29 @@ export const adapterOas = createAdapter<AdapterOas>((options) => {
157
169
  const document = await ensureDocument(source)
158
170
  const schemas = await ensureSchemas(document)
159
171
 
160
- let discriminatorChildMap: Awaited<ReturnType<typeof buildDiscriminatorChildMap>> | null = null
161
- if (discriminator === 'inherit') {
162
- const { parseSchema: _preParser } = createSchemaParser({ document, contentType })
172
+ const discriminatorChildMap: Awaited<ReturnType<typeof buildDiscriminatorChildMap>> | null = (() => {
173
+ if (discriminator !== 'inherit') return null
174
+ const { parseSchema: _preParser } = ensureSchemaParser(document)
163
175
  const parentNodes: ast.SchemaNode[] = []
164
176
  for (const [name, schema] of Object.entries(schemas)) {
165
177
  if ((schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) {
166
178
  parentNodes.push(_preParser({ schema, name }, parserOptions))
167
179
  }
168
180
  }
169
- if (parentNodes.length > 0) {
170
- discriminatorChildMap = buildDiscriminatorChildMap(parentNodes)
171
- }
172
- }
181
+ return parentNodes.length > 0 ? buildDiscriminatorChildMap(parentNodes) : null
182
+ })()
173
183
 
174
184
  // Each [Symbol.asyncIterator]() call returns a fresh generator so multiple
175
185
  // plugins can do independent `for await` passes without shared state.
186
+ // The underlying parser and BaseOas instance are cached at adapter scope.
176
187
  const schemasIterable: AsyncIterable<ast.SchemaNode> = {
177
188
  [Symbol.asyncIterator]() {
178
189
  return (async function* () {
179
- const { parseSchema: _parseSchema } = createSchemaParser({ document, contentType })
190
+ const { parseSchema: _parseSchema } = ensureSchemaParser(document)
180
191
  for (const [name, schema] of Object.entries(schemas)) {
181
- let node = _parseSchema({ schema, name }, parserOptions)
192
+ const parsedNode = _parseSchema({ schema, name }, parserOptions)
182
193
  const entry = discriminatorChildMap?.get(name)
183
- if (entry) node = patchDiscriminatorNode(node, entry)
194
+ const node = entry ? patchDiscriminatorNode(parsedNode, entry) : parsedNode
184
195
  yield node
185
196
  }
186
197
  })()
@@ -190,8 +201,8 @@ export const adapterOas = createAdapter<AdapterOas>((options) => {
190
201
  const operationsIterable: AsyncIterable<ast.OperationNode> = {
191
202
  [Symbol.asyncIterator]() {
192
203
  return (async function* () {
193
- const { parseOperation: _parseOperation } = createSchemaParser({ document, contentType })
194
- const baseOas = new BaseOas(document)
204
+ const { parseOperation: _parseOperation } = ensureSchemaParser(document)
205
+ const baseOas = ensureBaseOas(document)
195
206
  const paths = baseOas.getPaths()
196
207
 
197
208
  for (const methods of Object.values(paths)) {
@@ -61,14 +61,11 @@ export function buildDiscriminatorChildMap(schemas: ast.SchemaNode[]): Map<strin
61
61
  if (!enumValues.length) continue
62
62
 
63
63
  const existing = childMap.get(refNode.name)
64
- if (existing) {
65
- existing.enumValues.push(...enumValues)
66
- } else {
67
- childMap.set(refNode.name, {
68
- propertyName: discriminatorPropertyName,
69
- enumValues: [...enumValues],
70
- })
64
+ if (!existing) {
65
+ childMap.set(refNode.name, { propertyName: discriminatorPropertyName, enumValues: [...enumValues] })
66
+ continue
71
67
  }
68
+ existing.enumValues.push(...enumValues)
72
69
  }
73
70
  }
74
71
 
package/src/parser.ts CHANGED
@@ -115,9 +115,7 @@ export function createSchemaParser(ctx: OasParserContext) {
115
115
  let resolvedSchema: ast.SchemaNode | undefined
116
116
  const refPath = schema.$ref
117
117
  if (refPath && !resolvingRefs.has(refPath)) {
118
- if (resolvedRefCache.has(refPath)) {
119
- resolvedSchema = resolvedRefCache.get(refPath)
120
- } else {
118
+ if (!resolvedRefCache.has(refPath)) {
121
119
  try {
122
120
  const referenced = resolveRef<SchemaObject>(document, refPath)
123
121
  if (referenced) {
@@ -130,6 +128,7 @@ export function createSchemaParser(ctx: OasParserContext) {
130
128
  }
131
129
  resolvedRefCache.set(refPath, resolvedSchema)
132
130
  }
131
+ resolvedSchema = resolvedRefCache.get(refPath)
133
132
  }
134
133
 
135
134
  return ast.createSchema({
@@ -169,6 +168,7 @@ export function createSchemaParser(ctx: OasParserContext) {
169
168
  default: mergedDefault,
170
169
  example: schema.example ?? memberNode.example,
171
170
  pattern: schema.pattern ?? ('pattern' in memberNode ? memberNode.pattern : undefined),
171
+ format: schema.format ?? memberNode.format,
172
172
  } as ast.DistributiveOmit<ast.SchemaNode, 'kind'>)
173
173
  }
174
174
 
@@ -359,6 +359,7 @@ export function createSchemaParser(ctx: OasParserContext) {
359
359
  title: schema.title,
360
360
  description: schema.description,
361
361
  deprecated: schema.deprecated,
362
+ format: schema.format,
362
363
  })
363
364
  }
364
365
 
@@ -489,6 +490,7 @@ export function createSchemaParser(ctx: OasParserContext) {
489
490
  writeOnly: schema.writeOnly,
490
491
  default: enumDefault,
491
492
  example: schema.example,
493
+ format: schema.format,
492
494
  }
493
495
 
494
496
  const extensionKey = enumExtensionKeys.find((key) => key in schema)
@@ -536,15 +538,17 @@ export function createSchemaParser(ctx: OasParserContext) {
536
538
 
537
539
  const resolvedChildName = ast.childName(name, propName)
538
540
  const propNode = parseSchema({ schema: resolvedPropSchema, name: resolvedChildName }, rawOptions)
539
- let schemaNode = ast.setEnumName(propNode, name, propName, options.enumSuffix)
540
-
541
- const tupleNode = ast.narrowSchema(schemaNode, 'tuple')
542
- if (tupleNode?.items) {
543
- const namedItems = tupleNode.items.map((item) => ast.setEnumName(item, name, propName, options.enumSuffix))
544
- if (namedItems.some((item, i) => item !== tupleNode.items![i])) {
545
- schemaNode = { ...tupleNode, items: namedItems }
541
+ const schemaNode = (() => {
542
+ const node = ast.setEnumName(propNode, name, propName, options.enumSuffix)
543
+ const tupleNode = ast.narrowSchema(node, 'tuple')
544
+ if (tupleNode?.items) {
545
+ const namedItems = tupleNode.items.map((item) => ast.setEnumName(item, name, propName, options.enumSuffix))
546
+ if (namedItems.some((item, i) => item !== tupleNode.items![i])) {
547
+ return { ...tupleNode, items: namedItems }
548
+ }
546
549
  }
547
- }
550
+ return node
551
+ })()
548
552
 
549
553
  return ast.createProperty({
550
554
  name: propName,
@@ -558,18 +562,15 @@ export function createSchemaParser(ctx: OasParserContext) {
558
562
  : []
559
563
 
560
564
  const additionalProperties = schema.additionalProperties
561
- let additionalPropertiesNode: ast.SchemaNode | boolean | undefined
562
- if (additionalProperties === true) {
563
- additionalPropertiesNode = true
564
- } else if (additionalProperties && Object.keys(additionalProperties).length > 0) {
565
- additionalPropertiesNode = parseSchema({ schema: additionalProperties as SchemaObject }, rawOptions)
566
- } else if (additionalProperties === false) {
567
- additionalPropertiesNode = false
568
- } else if (additionalProperties) {
569
- additionalPropertiesNode = ast.createSchema({
570
- type: typeOptionMap.get(options.unknownType)!,
571
- })
572
- }
565
+ const additionalPropertiesNode: ast.SchemaNode | boolean | undefined = (() => {
566
+ if (additionalProperties === true) return true
567
+ if (additionalProperties === false) return false
568
+ if (additionalProperties && Object.keys(additionalProperties).length > 0) {
569
+ return parseSchema({ schema: additionalProperties as SchemaObject }, rawOptions)
570
+ }
571
+ if (additionalProperties) return ast.createSchema({ type: typeOptionMap.get(options.unknownType)! })
572
+ return undefined
573
+ })()
573
574
 
574
575
  const rawPatternProperties = 'patternProperties' in schema ? schema.patternProperties : undefined
575
576
 
@@ -702,6 +703,7 @@ export function createSchemaParser(ctx: OasParserContext) {
702
703
  description: schema.description,
703
704
  deprecated: schema.deprecated,
704
705
  nullable,
706
+ format: schema.format,
705
707
  })
706
708
  }
707
709
 
@@ -795,6 +797,7 @@ export function createSchemaParser(ctx: OasParserContext) {
795
797
  name,
796
798
  title: schema.title,
797
799
  description: schema.description,
800
+ format: schema.format,
798
801
  })
799
802
  }
800
803
 
package/src/refs.ts CHANGED
@@ -20,11 +20,8 @@ export function resolveRef<T = unknown>(document: Document, $ref: string): T | n
20
20
  if ($ref === '') {
21
21
  return null
22
22
  }
23
- if ($ref.startsWith('#')) {
24
- $ref = globalThis.decodeURIComponent($ref.substring(1))
25
- } else {
26
- return null
27
- }
23
+ if (!$ref.startsWith('#')) return null
24
+ $ref = globalThis.decodeURIComponent($ref.substring(1))
28
25
 
29
26
  let docCache = _refCache.get(document)
30
27
  if (!docCache) {
package/src/resolvers.ts CHANGED
@@ -314,13 +314,13 @@ function* collectRefs(schema: unknown): Generator<string, void, undefined> {
314
314
  if (schema && typeof schema === 'object') {
315
315
  for (const key in schema) {
316
316
  const value = (schema as Record<string, unknown>)[key]
317
- if (key === '$ref' && typeof value === 'string') {
318
- if (value.startsWith(SCHEMA_REF_PREFIX)) {
319
- const name = value.slice(SCHEMA_REF_PREFIX.length)
320
- if (name) yield name
321
- }
322
- } else {
317
+ if (!(key === '$ref' && typeof value === 'string')) {
323
318
  yield* collectRefs(value)
319
+ continue
320
+ }
321
+ if (value.startsWith(SCHEMA_REF_PREFIX)) {
322
+ const name = value.slice(SCHEMA_REF_PREFIX.length)
323
+ if (name) yield name
324
324
  }
325
325
  }
326
326
  }
@@ -512,6 +512,7 @@ export function buildSchemaNode(schema: SchemaObject, name: string | null | unde
512
512
  writeOnly: schema.writeOnly,
513
513
  default: defaultValue,
514
514
  example: schema.example,
515
+ format: schema.format,
515
516
  } as const
516
517
  }
517
518