@kubb/ast 5.0.0-beta.13 → 5.0.0-beta.15

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/ast",
3
- "version": "5.0.0-beta.13",
3
+ "version": "5.0.0-beta.15",
4
4
  "description": "Spec-agnostic AST layer for Kubb. Defines the node tree, visitor pattern, factory functions, and type guards used across all code generation plugins.",
5
5
  "keywords": [
6
6
  "ast",
package/src/index.ts CHANGED
@@ -28,7 +28,7 @@ export { isInputNode, isOperationNode, isOutputNode, isSchemaNode, narrowSchema
28
28
  export { createPrinterFactory, definePrinter } from './printer.ts'
29
29
  export { extractRefName } from './refs.ts'
30
30
  export { childName, collectImports, enumPropName, findDiscriminator } from './resolvers.ts'
31
- export { mergeAdjacentObjects, setDiscriminatorEnum, setEnumName, simplifyUnion } from './transformers.ts'
31
+ export { mergeAdjacentObjects, mergeAdjacentObjectsLazy, setDiscriminatorEnum, setEnumName, simplifyUnion } from './transformers.ts'
32
32
  export type * from './types.ts'
33
33
  export {
34
34
  caseParams,
@@ -43,4 +43,4 @@ export {
43
43
  resolveRefName,
44
44
  syncSchemaRef,
45
45
  } from './utils.ts'
46
- export { collect, transform, walk } from './visitor.ts'
46
+ export { collect, collectLazy, transform, walk } from './visitor.ts'
@@ -73,25 +73,30 @@ export function setDiscriminatorEnum({
73
73
  * ])
74
74
  * ```
75
75
  */
76
- export function mergeAdjacentObjects(members: Array<SchemaNode>): Array<SchemaNode> {
77
- return members.reduce<Array<SchemaNode>>((acc, member) => {
76
+ export function* mergeAdjacentObjectsLazy(members: Iterable<SchemaNode>): Generator<SchemaNode, void, undefined> {
77
+ let acc: SchemaNode | undefined
78
+
79
+ for (const member of members) {
78
80
  const objectMember = narrowSchema(member, 'object')
79
- if (objectMember && !objectMember.name) {
80
- const previous = acc.at(-1)
81
- const previousObject = previous ? narrowSchema(previous, 'object') : undefined
82
-
83
- if (previousObject && !previousObject.name) {
84
- acc[acc.length - 1] = createSchema({
85
- ...previousObject,
86
- properties: [...(previousObject.properties ?? []), ...(objectMember.properties ?? [])],
81
+ if (objectMember && !objectMember.name && acc !== undefined) {
82
+ const accObject = narrowSchema(acc, 'object')
83
+ if (accObject && !accObject.name) {
84
+ acc = createSchema({
85
+ ...accObject,
86
+ properties: [...(accObject.properties ?? []), ...(objectMember.properties ?? [])],
87
87
  })
88
- return acc
88
+ continue
89
89
  }
90
90
  }
91
+ if (acc !== undefined) yield acc
92
+ acc = member
93
+ }
91
94
 
92
- acc.push(member)
93
- return acc
94
- }, [])
95
+ if (acc !== undefined) yield acc
96
+ }
97
+
98
+ export function mergeAdjacentObjects(members: Array<SchemaNode>): Array<SchemaNode> {
99
+ return [...mergeAdjacentObjectsLazy(members)]
95
100
  }
96
101
 
97
102
  /**
package/src/utils.ts CHANGED
@@ -17,7 +17,7 @@ import type {
17
17
  } from './nodes/index.ts'
18
18
  import type { SchemaType } from './nodes/schema.ts'
19
19
  import { extractRefName } from './refs.ts'
20
- import { collect } from './visitor.ts'
20
+ import { collect, collectLazy } from './visitor.ts'
21
21
 
22
22
  const plainStringTypes = new Set<SchemaType>(['string', 'uuid', 'email', 'url', 'datetime'] as const)
23
23
 
@@ -775,18 +775,28 @@ export function resolveRefName(node: SchemaNode | undefined): string | undefined
775
775
  * }
776
776
  * ```
777
777
  */
778
- export function collectReferencedSchemaNames(node: SchemaNode | undefined, out: Set<string> = new Set()): Set<string> {
779
- if (!node) return out
778
+ const schemaRefCache = new WeakMap<SchemaNode, ReadonlySet<string>>()
779
+
780
+ function collectSchemaRefs(node: SchemaNode): ReadonlySet<string> {
781
+ const cached = schemaRefCache.get(node)
782
+ if (cached) return cached
783
+
784
+ const refs = new Set<string>()
780
785
  collect<void>(node, {
781
786
  schema(child) {
782
787
  if (child.type === 'ref') {
783
788
  const name = resolveRefName(child)
784
-
785
- if (name) out.add(name)
789
+ if (name) refs.add(name)
786
790
  }
787
- return undefined
788
791
  },
789
792
  })
793
+ schemaRefCache.set(node, refs)
794
+ return refs
795
+ }
796
+
797
+ export function collectReferencedSchemaNames(node: SchemaNode | undefined, out: Set<string> = new Set()): Set<string> {
798
+ if (!node) return out
799
+ for (const name of collectSchemaRefs(node)) out.add(name)
790
800
  return out
791
801
  }
792
802
 
@@ -842,7 +852,7 @@ export function collectUsedSchemaNames(operations: ReadonlyArray<OperationNode>,
842
852
  }
843
853
 
844
854
  for (const op of operations) {
845
- for (const schema of collect<SchemaNode>(op, { depth: 'shallow', schema: (node) => node })) {
855
+ for (const schema of collectLazy<SchemaNode>(op, { depth: 'shallow', schema: (node) => node })) {
846
856
  visitSchema(schema)
847
857
  }
848
858
  }
@@ -902,14 +912,15 @@ export function containsCircularRef(
902
912
  ): boolean {
903
913
  if (!node || circularSchemas.size === 0) return false
904
914
 
905
- const matches = collect<true>(node, {
915
+ for (const _ of collectLazy<true>(node, {
906
916
  schema(child) {
907
917
  if (child.type !== 'ref') return undefined
908
918
  const name = resolveRefName(child)
909
-
910
919
  return name && name !== excludeName && circularSchemas.has(name) ? true : undefined
911
920
  },
912
- })
921
+ })) {
922
+ return true
923
+ }
913
924
 
914
- return matches.length > 0
925
+ return false
915
926
  }
package/src/visitor.ts CHANGED
@@ -265,39 +265,40 @@ export type CollectOptions<T> = CollectVisitor<T> & {
265
265
  * // returns parameters, requestBody schema (if present), and responses
266
266
  * ```
267
267
  */
268
- function getChildren(node: Node, recurse: boolean): Array<Node> {
268
+ function* getChildren(node: Node, recurse: boolean): Generator<Node, void, undefined> {
269
269
  switch (node.kind) {
270
270
  case 'Input':
271
- return [...node.schemas, ...node.operations]
271
+ yield* node.schemas
272
+ yield* node.operations
273
+ break
272
274
  case 'Output':
273
- return []
275
+ break
274
276
  case 'Operation':
275
- return [...node.parameters, ...(node.requestBody?.content?.flatMap((c) => (c.schema ? [c.schema] : [])) ?? []), ...node.responses]
277
+ yield* node.parameters
278
+ if (node.requestBody?.content) {
279
+ for (const c of node.requestBody.content) {
280
+ if (c.schema) yield c.schema
281
+ }
282
+ }
283
+ yield* node.responses
284
+ break
276
285
  case 'Schema': {
277
- const children: Array<Node> = []
278
-
279
- if (!recurse) return []
280
-
281
- if ('properties' in node && node.properties.length > 0) children.push(...node.properties)
282
- if ('items' in node && node.items) children.push(...node.items)
283
- if ('members' in node && node.members) children.push(...node.members)
284
- if ('additionalProperties' in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties)
285
-
286
- return children
286
+ if (!recurse) break
287
+ if ('properties' in node && node.properties.length > 0) yield* node.properties
288
+ if ('items' in node && node.items) yield* node.items
289
+ if ('members' in node && node.members) yield* node.members
290
+ if ('additionalProperties' in node && node.additionalProperties && node.additionalProperties !== true) yield node.additionalProperties
291
+ break
287
292
  }
288
293
  case 'Property':
289
- return [node.schema]
294
+ yield node.schema
295
+ break
290
296
  case 'Parameter':
291
- return [node.schema]
297
+ yield node.schema
298
+ break
292
299
  case 'Response':
293
- return node.schema ? [node.schema] : []
294
- case 'FunctionParameter':
295
- case 'ParameterGroup':
296
- case 'FunctionParameters':
297
- case 'Type':
298
- return []
299
- default:
300
- return []
300
+ if (node.schema) yield node.schema
301
+ break
301
302
  }
302
303
  }
303
304
 
@@ -539,10 +540,9 @@ export function transform(node: Node, options: TransformOptions): Node {
539
540
  * const values = collect(root, { depth: 'shallow', root: () => 'root' })
540
541
  * ```
541
542
  */
542
- export function collect<T>(node: Node, options: CollectOptions<T>): Array<T> {
543
+ export function* collectLazy<T>(node: Node, options: CollectOptions<T>): Generator<T, void, undefined> {
543
544
  const { depth, parent, ...visitor } = options
544
545
  const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep
545
- const results: Array<T> = []
546
546
 
547
547
  let v: T | undefined
548
548
  switch (node.kind) {
@@ -580,13 +580,13 @@ export function collect<T>(node: Node, options: CollectOptions<T>): Array<T> {
580
580
  case 'FunctionParameters':
581
581
  break
582
582
  }
583
- if (v !== undefined) results.push(v)
583
+ if (v !== undefined) yield v
584
584
 
585
585
  for (const child of getChildren(node, recurse)) {
586
- for (const item of collect(child, { ...options, parent: node })) {
587
- results.push(item)
588
- }
586
+ yield* collectLazy(child, { ...options, parent: node })
589
587
  }
588
+ }
590
589
 
591
- return results
590
+ export function collect<T>(node: Node, options: CollectOptions<T>): Array<T> {
591
+ return Array.from(collectLazy(node, options))
592
592
  }