@kubb/ast 5.0.0-beta.19 → 5.0.0-beta.20
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 +191 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +54 -13
- package/dist/index.js +191 -174
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/factory.ts +1 -0
- package/src/nodes/root.ts +51 -13
- package/src/utils.ts +39 -58
- package/src/visitor.ts +119 -138
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/ast",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.20",
|
|
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/factory.ts
CHANGED
package/src/nodes/root.ts
CHANGED
|
@@ -3,32 +3,62 @@ import type { OperationNode } from './operation.ts'
|
|
|
3
3
|
import type { SchemaNode } from './schema.ts'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Metadata for an API document, populated by the adapter and available to every generator.
|
|
7
|
+
*
|
|
8
|
+
* All fields are plain JSON-serializable values — no `Set`, no `Map`, no class instances.
|
|
9
|
+
* Computed fields (`circularNames`, `enumNames`) are pre-calculated once during the adapter
|
|
10
|
+
* pre-scan so generators never need to iterate the full schema list themselves.
|
|
8
11
|
*
|
|
9
12
|
* @example
|
|
10
13
|
* ```ts
|
|
11
|
-
* const meta: InputMeta = { title: 'Pet
|
|
14
|
+
* const meta: InputMeta = { title: 'Pet Store', version: '1.0.0', baseURL: 'https://petstore.swagger.io/v2', circularNames: [], enumNames: [] }
|
|
12
15
|
* ```
|
|
13
16
|
*/
|
|
14
17
|
export type InputMeta = {
|
|
15
18
|
/**
|
|
16
|
-
* API title
|
|
19
|
+
* API title from `info.title` in the source document.
|
|
17
20
|
*/
|
|
18
21
|
title?: string
|
|
19
22
|
/**
|
|
20
|
-
* API description
|
|
23
|
+
* API description from `info.description` in the source document.
|
|
21
24
|
*/
|
|
22
25
|
description?: string
|
|
23
26
|
/**
|
|
24
|
-
* API version string
|
|
27
|
+
* API version string from `info.version` in the source document.
|
|
25
28
|
*/
|
|
26
29
|
version?: string
|
|
27
30
|
/**
|
|
28
|
-
* Resolved
|
|
29
|
-
* For OpenAPI and AsyncAPI, this comes from the selected server URL.
|
|
31
|
+
* Resolved base URL from the first matching server entry in the source document.
|
|
30
32
|
*/
|
|
31
33
|
baseURL?: string
|
|
34
|
+
/**
|
|
35
|
+
* Names of schemas that participate in a circular reference chain.
|
|
36
|
+
* Computed once during the adapter pre-scan — use this instead of calling
|
|
37
|
+
* `findCircularSchemas` per generator call.
|
|
38
|
+
*
|
|
39
|
+
* Convert to a `Set` once at the start of a generator, not per-schema,
|
|
40
|
+
* to keep lookup O(1) without repeated allocations.
|
|
41
|
+
*
|
|
42
|
+
* @example Wrap a circular schema in z.lazy()
|
|
43
|
+
* ```ts
|
|
44
|
+
* const circular = new Set(meta.circularNames)
|
|
45
|
+
* if (circular.has(schema.name)) { ... }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
circularNames: readonly string[]
|
|
49
|
+
/**
|
|
50
|
+
* Names of schemas whose type is `enum`.
|
|
51
|
+
* Computed once during the adapter pre-scan — use this instead of filtering
|
|
52
|
+
* schemas per generator call.
|
|
53
|
+
*
|
|
54
|
+
* Convert to a `Set` once at the start of a generator when you need repeated
|
|
55
|
+
* membership checks, rather than calling `.includes()` per schema.
|
|
56
|
+
*
|
|
57
|
+
* @example Check if a referenced schema is an enum
|
|
58
|
+
* `const enums = new Set(meta.enumNames)`
|
|
59
|
+
* `const isEnum = enums.has(schemaName)`
|
|
60
|
+
*/
|
|
61
|
+
enumNames: readonly string[]
|
|
32
62
|
}
|
|
33
63
|
|
|
34
64
|
/**
|
|
@@ -58,9 +88,9 @@ export type InputNode = BaseNode & {
|
|
|
58
88
|
*/
|
|
59
89
|
operations: Array<OperationNode>
|
|
60
90
|
/**
|
|
61
|
-
*
|
|
91
|
+
* Document metadata populated by the adapter.
|
|
62
92
|
*/
|
|
63
|
-
meta
|
|
93
|
+
meta: InputMeta
|
|
64
94
|
}
|
|
65
95
|
|
|
66
96
|
/**
|
|
@@ -79,10 +109,18 @@ export type InputNode = BaseNode & {
|
|
|
79
109
|
*/
|
|
80
110
|
export type InputStreamNode = {
|
|
81
111
|
kind: 'Input'
|
|
82
|
-
/**
|
|
112
|
+
/**
|
|
113
|
+
* Lazily parsed schema nodes. Each `for await` creates a fresh parse pass, so
|
|
114
|
+
* multiple plugins can iterate independently without sharing state.
|
|
115
|
+
*/
|
|
83
116
|
schemas: AsyncIterable<SchemaNode>
|
|
84
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Lazily parsed operation nodes. Each `for await` creates a fresh parse pass, so
|
|
119
|
+
* multiple plugins can iterate independently without sharing state.
|
|
120
|
+
*/
|
|
85
121
|
operations: AsyncIterable<OperationNode>
|
|
86
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* Document metadata available immediately, before the first yielded node.
|
|
124
|
+
*/
|
|
87
125
|
meta?: InputMeta
|
|
88
126
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { camelCase, isValidVarName } from '@internals/utils'
|
|
1
|
+
import { camelCase, isValidVarName, memoize } from '@internals/utils'
|
|
2
2
|
|
|
3
3
|
import { createFunctionParameter, createFunctionParameters, createParameterGroup, createParamsType, createProperty, createSchema } from './factory.ts'
|
|
4
4
|
import { narrowSchema } from './guards.ts'
|
|
@@ -74,26 +74,18 @@ export function isStringType(node: SchemaNode): boolean {
|
|
|
74
74
|
* the desired casing while preserving `OperationNode.parameters` for other consumers.
|
|
75
75
|
* The input array is not mutated. When `casing` is not set, the original array is returned unchanged.
|
|
76
76
|
*/
|
|
77
|
-
const
|
|
77
|
+
const caseParamsMemo = memoize(new WeakMap<Array<ParameterNode>, (casing: string) => Array<ParameterNode>>(), (params) =>
|
|
78
|
+
memoize(new Map<string, Array<ParameterNode>>(), (casing: string) =>
|
|
79
|
+
params.map((param) => {
|
|
80
|
+
const transformed = casing === 'camelcase' || !isValidVarName(param.name) ? camelCase(param.name) : param.name
|
|
81
|
+
return { ...param, name: transformed }
|
|
82
|
+
}),
|
|
83
|
+
),
|
|
84
|
+
)
|
|
78
85
|
|
|
79
86
|
export function caseParams(params: Array<ParameterNode>, casing: 'camelcase' | undefined): Array<ParameterNode> {
|
|
80
87
|
if (!casing) return params
|
|
81
|
-
|
|
82
|
-
let byParams = caseParamsCache.get(params)
|
|
83
|
-
if (!byParams) {
|
|
84
|
-
byParams = new Map()
|
|
85
|
-
caseParamsCache.set(params, byParams)
|
|
86
|
-
}
|
|
87
|
-
const cached = byParams.get(casing)
|
|
88
|
-
if (cached) return cached
|
|
89
|
-
|
|
90
|
-
const result = params.map((param) => {
|
|
91
|
-
const transformed = casing === 'camelcase' || !isValidVarName(param.name) ? camelCase(param.name) : param.name
|
|
92
|
-
return { ...param, name: transformed }
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
byParams.set(casing, result)
|
|
96
|
-
return result
|
|
88
|
+
return caseParamsMemo(params)(casing)
|
|
97
89
|
}
|
|
98
90
|
|
|
99
91
|
/**
|
|
@@ -790,12 +782,7 @@ export function resolveRefName(node: SchemaNode | undefined): string | undefined
|
|
|
790
782
|
* }
|
|
791
783
|
* ```
|
|
792
784
|
*/
|
|
793
|
-
const
|
|
794
|
-
|
|
795
|
-
function collectSchemaRefs(node: SchemaNode): ReadonlySet<string> {
|
|
796
|
-
const cached = schemaRefCache.get(node)
|
|
797
|
-
if (cached) return cached
|
|
798
|
-
|
|
785
|
+
const collectSchemaRefs = memoize(new WeakMap<SchemaNode, ReadonlySet<string>>(), (node: SchemaNode): ReadonlySet<string> => {
|
|
799
786
|
const refs = new Set<string>()
|
|
800
787
|
collect<void>(node, {
|
|
801
788
|
schema(child) {
|
|
@@ -805,9 +792,8 @@ function collectSchemaRefs(node: SchemaNode): ReadonlySet<string> {
|
|
|
805
792
|
}
|
|
806
793
|
},
|
|
807
794
|
})
|
|
808
|
-
schemaRefCache.set(node, refs)
|
|
809
795
|
return refs
|
|
810
|
-
}
|
|
796
|
+
})
|
|
811
797
|
|
|
812
798
|
export function collectReferencedSchemaNames(node: SchemaNode | undefined, out: Set<string> = new Set()): Set<string> {
|
|
813
799
|
if (!node) return out
|
|
@@ -828,10 +814,10 @@ export function collectReferencedSchemaNames(node: SchemaNode | undefined, out:
|
|
|
828
814
|
*
|
|
829
815
|
* @example Only generate schemas referenced by included operations
|
|
830
816
|
* ```ts
|
|
831
|
-
* const includedOps =
|
|
832
|
-
* const allowed = collectUsedSchemaNames(includedOps,
|
|
817
|
+
* const includedOps = operations.filter(op => resolver.resolveOptions(op, { options, include }) !== null)
|
|
818
|
+
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
833
819
|
*
|
|
834
|
-
* for (const schema of
|
|
820
|
+
* for (const schema of schemas) {
|
|
835
821
|
* if (schema.name && !allowed.has(schema.name)) continue
|
|
836
822
|
* // … generate schema
|
|
837
823
|
* }
|
|
@@ -839,21 +825,15 @@ export function collectReferencedSchemaNames(node: SchemaNode | undefined, out:
|
|
|
839
825
|
*
|
|
840
826
|
* @example Check whether a specific schema is needed
|
|
841
827
|
* ```ts
|
|
842
|
-
* const allowed = collectUsedSchemaNames(includedOps,
|
|
828
|
+
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
843
829
|
* allowed.has('OrderStatus') // false when no included operation references OrderStatus
|
|
844
830
|
* ```
|
|
845
831
|
*/
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
let byOps = usedSchemaNamesCache.get(operations)
|
|
850
|
-
if (!byOps) {
|
|
851
|
-
byOps = new WeakMap()
|
|
852
|
-
usedSchemaNamesCache.set(operations, byOps)
|
|
853
|
-
}
|
|
854
|
-
const cached = byOps.get(schemas)
|
|
855
|
-
if (cached) return cached
|
|
832
|
+
const collectUsedSchemaNamesMemo = memoize(new WeakMap<ReadonlyArray<OperationNode>, (schemas: ReadonlyArray<SchemaNode>) => Set<string>>(), (ops) =>
|
|
833
|
+
memoize(new WeakMap<ReadonlyArray<SchemaNode>, Set<string>>(), (schemas) => computeUsedSchemaNames(ops, schemas)),
|
|
834
|
+
)
|
|
856
835
|
|
|
836
|
+
function computeUsedSchemaNames(operations: ReadonlyArray<OperationNode>, schemas: ReadonlyArray<SchemaNode>): Set<string> {
|
|
857
837
|
const schemaMap = new Map<string, SchemaNode>()
|
|
858
838
|
for (const schema of schemas) {
|
|
859
839
|
if (schema.name) schemaMap.set(schema.name, schema)
|
|
@@ -878,28 +858,16 @@ export function collectUsedSchemaNames(operations: ReadonlyArray<OperationNode>,
|
|
|
878
858
|
}
|
|
879
859
|
}
|
|
880
860
|
|
|
881
|
-
byOps.set(schemas, result)
|
|
882
861
|
return result
|
|
883
862
|
}
|
|
884
863
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
/**
|
|
889
|
-
* Identifies all schemas that participate in circular dependency chains, including direct self-loops.
|
|
890
|
-
*
|
|
891
|
-
* Returns a Set of schema names with circular dependencies. Use this to wrap recursive schema positions
|
|
892
|
-
* in deferred constructs (lazy getter, `z.lazy(() => …)`) to prevent infinite recursion when generated code runs.
|
|
893
|
-
* Refs are followed by name only, keeping the algorithm linear in the schema graph size.
|
|
894
|
-
*
|
|
895
|
-
* @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
|
|
896
|
-
*/
|
|
897
|
-
export function findCircularSchemas(schemas: ReadonlyArray<SchemaNode>): Set<string> {
|
|
898
|
-
if (schemas.length === 0) return EMPTY_CIRCULAR_SET
|
|
864
|
+
export function collectUsedSchemaNames(operations: ReadonlyArray<OperationNode>, schemas: ReadonlyArray<SchemaNode>): Set<string> {
|
|
865
|
+
return collectUsedSchemaNamesMemo(operations)(schemas)
|
|
866
|
+
}
|
|
899
867
|
|
|
900
|
-
|
|
901
|
-
if (cached) return cached
|
|
868
|
+
const EMPTY_CIRCULAR_SET = new Set<string>()
|
|
902
869
|
|
|
870
|
+
const findCircularSchemasMemo = memoize(new WeakMap<ReadonlyArray<SchemaNode>, Set<string>>(), (schemas: ReadonlyArray<SchemaNode>): Set<string> => {
|
|
903
871
|
const graph = new Map<string, Set<string>>()
|
|
904
872
|
|
|
905
873
|
for (const schema of schemas) {
|
|
@@ -925,8 +893,21 @@ export function findCircularSchemas(schemas: ReadonlyArray<SchemaNode>): Set<str
|
|
|
925
893
|
}
|
|
926
894
|
}
|
|
927
895
|
|
|
928
|
-
circularSchemaCache.set(schemas, circular)
|
|
929
896
|
return circular
|
|
897
|
+
})
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Identifies all schemas that participate in circular dependency chains, including direct self-loops.
|
|
901
|
+
*
|
|
902
|
+
* Returns a Set of schema names with circular dependencies. Use this to wrap recursive schema positions
|
|
903
|
+
* in deferred constructs (lazy getter, `z.lazy(() => …)`) to prevent infinite recursion when generated code runs.
|
|
904
|
+
* Refs are followed by name only, keeping the algorithm linear in the schema graph size.
|
|
905
|
+
*
|
|
906
|
+
* @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
|
|
907
|
+
*/
|
|
908
|
+
export function findCircularSchemas(schemas: ReadonlyArray<SchemaNode>): Set<string> {
|
|
909
|
+
if (schemas.length === 0) return EMPTY_CIRCULAR_SET
|
|
910
|
+
return findCircularSchemasMemo(schemas)
|
|
930
911
|
}
|
|
931
912
|
|
|
932
913
|
/**
|
package/src/visitor.ts
CHANGED
|
@@ -266,39 +266,46 @@ export type CollectOptions<T> = CollectVisitor<T> & {
|
|
|
266
266
|
* ```
|
|
267
267
|
*/
|
|
268
268
|
function* getChildren(node: Node, recurse: boolean): Generator<Node, void, undefined> {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
269
|
+
if (node.kind === 'Input') {
|
|
270
|
+
yield* node.schemas
|
|
271
|
+
yield* node.operations
|
|
272
|
+
|
|
273
|
+
return
|
|
274
|
+
}
|
|
275
|
+
if (node.kind === 'Output') return
|
|
276
|
+
if (node.kind === 'Operation') {
|
|
277
|
+
yield* node.parameters
|
|
278
|
+
if (node.requestBody?.content) {
|
|
279
|
+
for (const c of node.requestBody.content) {
|
|
280
|
+
if (c.schema) yield c.schema
|
|
282
281
|
}
|
|
283
|
-
yield* node.responses
|
|
284
|
-
break
|
|
285
|
-
case 'Schema': {
|
|
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
|
|
292
282
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
283
|
+
yield* node.responses
|
|
284
|
+
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
if (node.kind === 'Schema') {
|
|
288
|
+
if (!recurse) return
|
|
289
|
+
if ('properties' in node && node.properties.length > 0) yield* node.properties
|
|
290
|
+
if ('items' in node && node.items) yield* node.items
|
|
291
|
+
if ('members' in node && node.members) yield* node.members
|
|
292
|
+
if ('additionalProperties' in node && node.additionalProperties && node.additionalProperties !== true) yield node.additionalProperties
|
|
293
|
+
|
|
294
|
+
return
|
|
295
|
+
}
|
|
296
|
+
if (node.kind === 'Property') {
|
|
297
|
+
yield node.schema
|
|
298
|
+
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
if (node.kind === 'Parameter') {
|
|
302
|
+
yield node.schema
|
|
303
|
+
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
if (node.kind === 'Response') {
|
|
307
|
+
if (node.schema) yield node.schema
|
|
308
|
+
return
|
|
302
309
|
}
|
|
303
310
|
}
|
|
304
311
|
|
|
@@ -338,11 +345,7 @@ async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit:
|
|
|
338
345
|
await limit(() => visitor.output?.(node, { parent: parent as ParentOf<OutputNode> }))
|
|
339
346
|
break
|
|
340
347
|
case 'Operation':
|
|
341
|
-
await limit(() =>
|
|
342
|
-
visitor.operation?.(node, {
|
|
343
|
-
parent: parent as ParentOf<OperationNode>,
|
|
344
|
-
}),
|
|
345
|
-
)
|
|
348
|
+
await limit(() => visitor.operation?.(node, { parent: parent as ParentOf<OperationNode> }))
|
|
346
349
|
break
|
|
347
350
|
case 'Schema':
|
|
348
351
|
await limit(() => visitor.schema?.(node, { parent: parent as ParentOf<SchemaNode> }))
|
|
@@ -351,19 +354,11 @@ async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit:
|
|
|
351
354
|
await limit(() => visitor.property?.(node, { parent: parent as ParentOf<PropertyNode> }))
|
|
352
355
|
break
|
|
353
356
|
case 'Parameter':
|
|
354
|
-
await limit(() =>
|
|
355
|
-
visitor.parameter?.(node, {
|
|
356
|
-
parent: parent as ParentOf<ParameterNode>,
|
|
357
|
-
}),
|
|
358
|
-
)
|
|
357
|
+
await limit(() => visitor.parameter?.(node, { parent: parent as ParentOf<ParameterNode> }))
|
|
359
358
|
break
|
|
360
359
|
case 'Response':
|
|
361
360
|
await limit(() => visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> }))
|
|
362
361
|
break
|
|
363
|
-
case 'FunctionParameter':
|
|
364
|
-
case 'ParameterGroup':
|
|
365
|
-
case 'FunctionParameters':
|
|
366
|
-
break
|
|
367
362
|
}
|
|
368
363
|
|
|
369
364
|
const children = getChildren(node, recurse)
|
|
@@ -405,91 +400,89 @@ export function transform(node: Node, options: TransformOptions): Node {
|
|
|
405
400
|
const { depth, parent, ...visitor } = options
|
|
406
401
|
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep
|
|
407
402
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
const input = visitor.input?.(node, { parent: parent as ParentOf<InputNode> }) ?? node
|
|
403
|
+
if (node.kind === 'Input') {
|
|
404
|
+
const input = visitor.input?.(node, { parent: parent as ParentOf<InputNode> }) ?? node
|
|
411
405
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
case 'Output': {
|
|
419
|
-
const output = visitor.output?.(node, { parent: parent as ParentOf<OutputNode> }) ?? node
|
|
420
|
-
return output
|
|
421
|
-
}
|
|
422
|
-
case 'Operation': {
|
|
423
|
-
const op = visitor.operation?.(node, { parent: parent as ParentOf<OperationNode> }) ?? node
|
|
424
|
-
|
|
425
|
-
return {
|
|
426
|
-
...op,
|
|
427
|
-
parameters: op.parameters.map((p) => transform(p, { ...options, parent: op })),
|
|
428
|
-
requestBody: op.requestBody
|
|
429
|
-
? {
|
|
430
|
-
...op.requestBody,
|
|
431
|
-
content: op.requestBody.content?.map((c) => ({
|
|
432
|
-
...c,
|
|
433
|
-
schema: c.schema ? transform(c.schema, { ...options, parent: op }) : undefined,
|
|
434
|
-
})),
|
|
435
|
-
}
|
|
436
|
-
: undefined,
|
|
437
|
-
responses: op.responses.map((r) => transform(r, { ...options, parent: op })),
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
case 'Schema': {
|
|
441
|
-
const schema = visitor.schema?.(node, { parent: parent as ParentOf<SchemaNode> }) ?? node
|
|
442
|
-
|
|
443
|
-
const childOptions = { ...options, parent: schema }
|
|
444
|
-
|
|
445
|
-
return {
|
|
446
|
-
...schema,
|
|
447
|
-
...('properties' in schema && recurse
|
|
448
|
-
? {
|
|
449
|
-
properties: schema.properties.map((p) => transform(p, childOptions)),
|
|
450
|
-
}
|
|
451
|
-
: {}),
|
|
452
|
-
...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, childOptions)) } : {}),
|
|
453
|
-
...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, childOptions)) } : {}),
|
|
454
|
-
...('additionalProperties' in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true
|
|
455
|
-
? {
|
|
456
|
-
additionalProperties: transform(schema.additionalProperties, childOptions),
|
|
457
|
-
}
|
|
458
|
-
: {}),
|
|
459
|
-
} as SchemaNode
|
|
406
|
+
return {
|
|
407
|
+
...input,
|
|
408
|
+
schemas: input.schemas.map((s) => transform(s, { ...options, parent: input })),
|
|
409
|
+
operations: input.operations.map((op) => transform(op, { ...options, parent: input })),
|
|
460
410
|
}
|
|
461
|
-
|
|
462
|
-
const prop = visitor.property?.(node, { parent: parent as ParentOf<PropertyNode> }) ?? node
|
|
411
|
+
}
|
|
463
412
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
})
|
|
468
|
-
}
|
|
469
|
-
case 'Parameter': {
|
|
470
|
-
const param = visitor.parameter?.(node, { parent: parent as ParentOf<ParameterNode> }) ?? node
|
|
413
|
+
if (node.kind === 'Output') {
|
|
414
|
+
return visitor.output?.(node, { parent: parent as ParentOf<OutputNode> }) ?? node
|
|
415
|
+
}
|
|
471
416
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
417
|
+
if (node.kind === 'Operation') {
|
|
418
|
+
const op = visitor.operation?.(node, { parent: parent as ParentOf<OperationNode> }) ?? node
|
|
419
|
+
|
|
420
|
+
return {
|
|
421
|
+
...op,
|
|
422
|
+
parameters: op.parameters.map((p) => transform(p, { ...options, parent: op })),
|
|
423
|
+
requestBody: op.requestBody
|
|
424
|
+
? {
|
|
425
|
+
...op.requestBody,
|
|
426
|
+
content: op.requestBody.content?.map((c) => ({
|
|
427
|
+
...c,
|
|
428
|
+
schema: c.schema ? transform(c.schema, { ...options, parent: op }) : undefined,
|
|
429
|
+
})),
|
|
430
|
+
}
|
|
431
|
+
: undefined,
|
|
432
|
+
responses: op.responses.map((r) => transform(r, { ...options, parent: op })),
|
|
476
433
|
}
|
|
477
|
-
|
|
478
|
-
const response = visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> }) ?? node
|
|
434
|
+
}
|
|
479
435
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
436
|
+
if (node.kind === 'Schema') {
|
|
437
|
+
const schema = visitor.schema?.(node, { parent: parent as ParentOf<SchemaNode> }) ?? node
|
|
438
|
+
|
|
439
|
+
const childOptions = { ...options, parent: schema }
|
|
440
|
+
|
|
441
|
+
return {
|
|
442
|
+
...schema,
|
|
443
|
+
...('properties' in schema && recurse
|
|
444
|
+
? {
|
|
445
|
+
properties: schema.properties.map((p) => transform(p, childOptions)),
|
|
446
|
+
}
|
|
447
|
+
: {}),
|
|
448
|
+
...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, childOptions)) } : {}),
|
|
449
|
+
...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, childOptions)) } : {}),
|
|
450
|
+
...('additionalProperties' in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true
|
|
451
|
+
? {
|
|
452
|
+
additionalProperties: transform(schema.additionalProperties, childOptions),
|
|
453
|
+
}
|
|
454
|
+
: {}),
|
|
455
|
+
} as SchemaNode
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (node.kind === 'Property') {
|
|
459
|
+
const prop = visitor.property?.(node, { parent: parent as ParentOf<PropertyNode> }) ?? node
|
|
460
|
+
|
|
461
|
+
return createProperty({
|
|
462
|
+
...prop,
|
|
463
|
+
schema: transform(prop.schema, { ...options, parent: prop }),
|
|
464
|
+
})
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (node.kind === 'Parameter') {
|
|
468
|
+
const param = visitor.parameter?.(node, { parent: parent as ParentOf<ParameterNode> }) ?? node
|
|
469
|
+
|
|
470
|
+
return createParameter({
|
|
471
|
+
...param,
|
|
472
|
+
schema: transform(param.schema, { ...options, parent: param }),
|
|
473
|
+
})
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (node.kind === 'Response') {
|
|
477
|
+
const response = visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> }) ?? node
|
|
478
|
+
|
|
479
|
+
return {
|
|
480
|
+
...response,
|
|
481
|
+
schema: transform(response.schema, { ...options, parent: response }),
|
|
484
482
|
}
|
|
485
|
-
case 'FunctionParameter':
|
|
486
|
-
case 'ParameterGroup':
|
|
487
|
-
case 'FunctionParameters':
|
|
488
|
-
case 'Type':
|
|
489
|
-
return node
|
|
490
|
-
default:
|
|
491
|
-
return node
|
|
492
483
|
}
|
|
484
|
+
|
|
485
|
+
return node
|
|
493
486
|
}
|
|
494
487
|
/**
|
|
495
488
|
* Runs a depth-first synchronous collection pass.
|
|
@@ -524,31 +517,19 @@ export function* collectLazy<T>(node: Node, options: CollectOptions<T>): Generat
|
|
|
524
517
|
v = visitor.output?.(node, { parent: parent as ParentOf<OutputNode> })
|
|
525
518
|
break
|
|
526
519
|
case 'Operation':
|
|
527
|
-
v = visitor.operation?.(node, {
|
|
528
|
-
parent: parent as ParentOf<OperationNode>,
|
|
529
|
-
})
|
|
520
|
+
v = visitor.operation?.(node, { parent: parent as ParentOf<OperationNode> })
|
|
530
521
|
break
|
|
531
522
|
case 'Schema':
|
|
532
523
|
v = visitor.schema?.(node, { parent: parent as ParentOf<SchemaNode> })
|
|
533
524
|
break
|
|
534
525
|
case 'Property':
|
|
535
|
-
v = visitor.property?.(node, {
|
|
536
|
-
parent: parent as ParentOf<PropertyNode>,
|
|
537
|
-
})
|
|
526
|
+
v = visitor.property?.(node, { parent: parent as ParentOf<PropertyNode> })
|
|
538
527
|
break
|
|
539
528
|
case 'Parameter':
|
|
540
|
-
v = visitor.parameter?.(node, {
|
|
541
|
-
parent: parent as ParentOf<ParameterNode>,
|
|
542
|
-
})
|
|
529
|
+
v = visitor.parameter?.(node, { parent: parent as ParentOf<ParameterNode> })
|
|
543
530
|
break
|
|
544
531
|
case 'Response':
|
|
545
|
-
v = visitor.response?.(node, {
|
|
546
|
-
parent: parent as ParentOf<ResponseNode>,
|
|
547
|
-
})
|
|
548
|
-
break
|
|
549
|
-
case 'FunctionParameter':
|
|
550
|
-
case 'ParameterGroup':
|
|
551
|
-
case 'FunctionParameters':
|
|
532
|
+
v = visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> })
|
|
552
533
|
break
|
|
553
534
|
}
|
|
554
535
|
if (v !== undefined) yield v
|