@kubb/ast 5.0.0-alpha.13 → 5.0.0-alpha.14
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 +126 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +125 -51
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/{visitor-D68E3x_d.d.ts → visitor-UlWOe-In.d.ts} +78 -37
- package/package.json +1 -1
- package/src/factory.ts +23 -2
- package/src/index.ts +2 -1
- package/src/types.ts +1 -1
- package/src/visitor.ts +157 -80
|
@@ -623,12 +623,19 @@ declare function createSchema<T extends DistributiveOmit<Exclude<SchemaNode, Obj
|
|
|
623
623
|
kind: 'Schema';
|
|
624
624
|
};
|
|
625
625
|
declare function createSchema(props: DistributiveOmit<SchemaNode, 'kind'>): SchemaNode;
|
|
626
|
+
/**
|
|
627
|
+
* Derives `schema.optional` and `schema.nullish` from `required` and `schema.nullable`.
|
|
628
|
+
* This keeps `PropertyNode.required` as the single source of truth for optionality.
|
|
629
|
+
*/
|
|
630
|
+
declare function syncPropertySchema(required: boolean, schema: SchemaNode): SchemaNode;
|
|
626
631
|
/**
|
|
627
632
|
* Creates a `PropertyNode`. `required` defaults to `false`.
|
|
633
|
+
* `schema.optional` and `schema.nullish` are auto-derived from `required` and `schema.nullable`.
|
|
628
634
|
*/
|
|
629
635
|
declare function createProperty(props: Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>): PropertyNode;
|
|
630
636
|
/**
|
|
631
637
|
* Creates a `ParameterNode`. `required` defaults to `false`.
|
|
638
|
+
* `schema.optional` is auto-derived from `required` and `schema.nullable`.
|
|
632
639
|
*/
|
|
633
640
|
declare function createParameter(props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>): ParameterNode;
|
|
634
641
|
/**
|
|
@@ -852,69 +859,103 @@ declare function refMapToObject(refMap: RefMap): Record<string, SchemaNode>;
|
|
|
852
859
|
//#endregion
|
|
853
860
|
//#region src/visitor.d.ts
|
|
854
861
|
/**
|
|
855
|
-
*
|
|
862
|
+
* Single source of truth: ordered list of `[NodeType, ParentType]` pairs
|
|
863
|
+
* describing which node types can be the parent of a given node in the AST.
|
|
864
|
+
*
|
|
865
|
+
* `ParentOf` walks this tuple and returns the parent type of the first matching entry.
|
|
856
866
|
*/
|
|
857
|
-
type
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
867
|
+
type ParentNodeMap = [[RootNode, undefined], [OperationNode, RootNode], [SchemaNode, RootNode | OperationNode | SchemaNode | PropertyNode | ParameterNode | ResponseNode], [PropertyNode, SchemaNode], [ParameterNode, OperationNode], [ResponseNode, OperationNode]];
|
|
868
|
+
type ParentOf<T extends Node, TEntries extends ReadonlyArray<[Node, unknown]> = ParentNodeMap> = TEntries extends [infer TEntry extends [Node, unknown], ...infer TRest extends ReadonlyArray<[Node, unknown]>] ? T extends TEntry[0] ? TEntry[1] : ParentOf<T, TRest> : Node;
|
|
869
|
+
/**
|
|
870
|
+
* Traversal context passed as the second argument to every visitor callback.
|
|
871
|
+
* The `parent` field is narrowed based on the node type being visited.
|
|
872
|
+
*/
|
|
873
|
+
type VisitorContext<T extends Node = Node> = {
|
|
874
|
+
parent?: ParentOf<T>;
|
|
864
875
|
};
|
|
865
876
|
/**
|
|
866
877
|
* Synchronous visitor for `transform` and `walk`.
|
|
867
878
|
*/
|
|
868
879
|
type Visitor = {
|
|
869
|
-
root?(node: RootNode): void | RootNode;
|
|
870
|
-
operation?(node: OperationNode): void | OperationNode;
|
|
871
|
-
schema?(node: SchemaNode): void | SchemaNode;
|
|
872
|
-
property?(node: PropertyNode): void | PropertyNode;
|
|
873
|
-
parameter?(node: ParameterNode): void | ParameterNode;
|
|
874
|
-
response?(node: ResponseNode): void | ResponseNode;
|
|
880
|
+
root?(node: RootNode, context: VisitorContext<RootNode>): void | RootNode;
|
|
881
|
+
operation?(node: OperationNode, context: VisitorContext<OperationNode>): void | OperationNode;
|
|
882
|
+
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): void | SchemaNode;
|
|
883
|
+
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): void | PropertyNode;
|
|
884
|
+
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): void | ParameterNode;
|
|
885
|
+
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): void | ResponseNode;
|
|
875
886
|
};
|
|
876
887
|
type MaybePromise<T> = T | Promise<T>;
|
|
877
888
|
/**
|
|
878
889
|
* Async visitor for `walk`. Synchronous `Visitor` objects are compatible.
|
|
879
890
|
*/
|
|
880
891
|
type AsyncVisitor = {
|
|
881
|
-
root?(node: RootNode): MaybePromise<void | RootNode>;
|
|
882
|
-
operation?(node: OperationNode): MaybePromise<void | OperationNode>;
|
|
883
|
-
schema?(node: SchemaNode): MaybePromise<void | SchemaNode>;
|
|
884
|
-
property?(node: PropertyNode): MaybePromise<void | PropertyNode>;
|
|
885
|
-
parameter?(node: ParameterNode): MaybePromise<void | ParameterNode>;
|
|
886
|
-
response?(node: ResponseNode): MaybePromise<void | ResponseNode>;
|
|
892
|
+
root?(node: RootNode, context: VisitorContext<RootNode>): MaybePromise<void | RootNode>;
|
|
893
|
+
operation?(node: OperationNode, context: VisitorContext<OperationNode>): MaybePromise<void | OperationNode>;
|
|
894
|
+
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): MaybePromise<void | SchemaNode>;
|
|
895
|
+
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): MaybePromise<void | PropertyNode>;
|
|
896
|
+
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): MaybePromise<void | ParameterNode>;
|
|
897
|
+
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): MaybePromise<void | ResponseNode>;
|
|
887
898
|
};
|
|
888
899
|
/**
|
|
889
900
|
* Visitor for `collect`.
|
|
890
901
|
*/
|
|
891
902
|
type CollectVisitor<T> = {
|
|
892
|
-
root?(node: RootNode): T | undefined;
|
|
893
|
-
operation?(node: OperationNode): T | undefined;
|
|
894
|
-
schema?(node: SchemaNode): T | undefined;
|
|
895
|
-
property?(node: PropertyNode): T | undefined;
|
|
896
|
-
parameter?(node: ParameterNode): T | undefined;
|
|
897
|
-
response?(node: ResponseNode): T | undefined;
|
|
903
|
+
root?(node: RootNode, context: VisitorContext<RootNode>): T | undefined;
|
|
904
|
+
operation?(node: OperationNode, context: VisitorContext<OperationNode>): T | undefined;
|
|
905
|
+
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): T | undefined;
|
|
906
|
+
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): T | undefined;
|
|
907
|
+
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): T | undefined;
|
|
908
|
+
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): T | undefined;
|
|
909
|
+
};
|
|
910
|
+
/**
|
|
911
|
+
* Options for `transform` and `collect`. Extends `Visitor` with traversal settings.
|
|
912
|
+
*/
|
|
913
|
+
type TransformOptions = Visitor & {
|
|
914
|
+
depth?: VisitorDepth;
|
|
915
|
+
parent?: Node;
|
|
916
|
+
};
|
|
917
|
+
/**
|
|
918
|
+
* Options for `walk`. Extends `AsyncVisitor` with traversal settings.
|
|
919
|
+
*/
|
|
920
|
+
type WalkOptions = AsyncVisitor & {
|
|
921
|
+
depth?: VisitorDepth;
|
|
922
|
+
/**
|
|
923
|
+
* Maximum number of sibling nodes visited concurrently.
|
|
924
|
+
* @default 30
|
|
925
|
+
*/
|
|
926
|
+
concurrency?: number;
|
|
927
|
+
};
|
|
928
|
+
/**
|
|
929
|
+
* Options for `collect`. Extends `CollectVisitor` with traversal settings.
|
|
930
|
+
*/
|
|
931
|
+
type CollectOptions<T> = CollectVisitor<T> & {
|
|
932
|
+
depth?: VisitorDepth;
|
|
933
|
+
parent?: Node;
|
|
898
934
|
};
|
|
899
935
|
/**
|
|
900
936
|
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
901
937
|
* Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
|
|
902
938
|
*/
|
|
903
|
-
declare function walk(node: Node,
|
|
939
|
+
declare function walk(node: Node, options: WalkOptions): Promise<void>;
|
|
904
940
|
/**
|
|
905
941
|
* Depth-first immutable transformation. Visitor return values replace nodes; `undefined` keeps the original.
|
|
906
942
|
*/
|
|
907
|
-
declare function transform(node: RootNode,
|
|
908
|
-
declare function transform(node: OperationNode,
|
|
909
|
-
declare function transform(node: SchemaNode,
|
|
910
|
-
declare function transform(node: PropertyNode,
|
|
911
|
-
declare function transform(node: ParameterNode,
|
|
912
|
-
declare function transform(node: ResponseNode,
|
|
913
|
-
declare function transform(node: Node,
|
|
943
|
+
declare function transform(node: RootNode, options: TransformOptions): RootNode;
|
|
944
|
+
declare function transform(node: OperationNode, options: TransformOptions): OperationNode;
|
|
945
|
+
declare function transform(node: SchemaNode, options: TransformOptions): SchemaNode;
|
|
946
|
+
declare function transform(node: PropertyNode, options: TransformOptions): PropertyNode;
|
|
947
|
+
declare function transform(node: ParameterNode, options: TransformOptions): ParameterNode;
|
|
948
|
+
declare function transform(node: ResponseNode, options: TransformOptions): ResponseNode;
|
|
949
|
+
declare function transform(node: Node, options: TransformOptions): Node;
|
|
950
|
+
/**
|
|
951
|
+
* Combines multiple visitors into a single visitor that applies them sequentially (left to right).
|
|
952
|
+
* For each node kind, the output of one visitor becomes the input of the next.
|
|
953
|
+
*/
|
|
954
|
+
declare function composeTransformers(...visitors: Array<Visitor>): Visitor;
|
|
914
955
|
/**
|
|
915
956
|
* Depth-first synchronous reduction. Collects non-`undefined` visitor return values into an array.
|
|
916
957
|
*/
|
|
917
|
-
declare function collect<T>(node: Node,
|
|
958
|
+
declare function collect<T>(node: Node, options: CollectOptions<T>): Array<T>;
|
|
918
959
|
//#endregion
|
|
919
|
-
export {
|
|
920
|
-
//# sourceMappingURL=visitor-
|
|
960
|
+
export { ScalarSchemaNode as $, syncPropertySchema as A, ParameterLocation as B, createObjectBindingParameter as C, createResponse as D, createProperty as E, OperationNode as F, DatetimeSchemaNode as G, ArraySchemaNode as H, ResponseNode as I, IntersectionSchemaNode as J, EnumSchemaNode as K, HttpStatusCode as L, RootMeta as M, RootNode as N, createRoot as O, HttpMethod as P, RefSchemaNode as Q, MediaType as R, createFunctionParameters as S, createParameter as T, ComplexSchemaType as U, ParameterNode as V, DateSchemaNode as W, ObjectSchemaNode as X, NumberSchemaNode as Y, PrimitiveSchemaType as Z, Printer as _, VisitorDepth as _t, TransformOptions as a, StringSchemaNode as at, DistributiveOmit as b, nodeKinds as bt, WalkOptions as c, UrlSchemaNode as ct, transform as d, FunctionNodeType as dt, ScalarSchemaType as et, walk as f, FunctionParameterNode as ft, resolveRef as g, NodeKind as gt, refMapToObject as h, BaseNode as ht, ParentOf as i, SpecialSchemaType as it, Node as j, createSchema as k, collect as l, PropertyNode as lt, buildRefMap as m, ObjectBindingParameterNode as mt, CollectOptions as n, SchemaNodeByType as nt, Visitor as o, TimeSchemaNode as ot, RefMap as p, FunctionParametersNode as pt, EnumValueNode as q, CollectVisitor as r, SchemaType as rt, VisitorContext as s, UnionSchemaNode as st, AsyncVisitor as t, SchemaNode as tt, composeTransformers as u, FunctionNode as ut, PrinterFactoryOptions as v, httpMethods as vt, createOperation as w, createFunctionParameter as x, schemaTypes as xt, definePrinter as y, mediaTypes as yt, StatusCode as z };
|
|
961
|
+
//# sourceMappingURL=visitor-UlWOe-In.d.ts.map
|
package/package.json
CHANGED
package/src/factory.ts
CHANGED
|
@@ -60,27 +60,48 @@ export function createSchema(props: Record<string, unknown>): Record<string, unk
|
|
|
60
60
|
return { ...props, kind: 'Schema' }
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Derives `schema.optional` and `schema.nullish` from `required` and `schema.nullable`.
|
|
65
|
+
* This keeps `PropertyNode.required` as the single source of truth for optionality.
|
|
66
|
+
*/
|
|
67
|
+
export function syncPropertySchema(required: boolean, schema: SchemaNode): SchemaNode {
|
|
68
|
+
const nullable = schema.nullable ?? false
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
...schema,
|
|
72
|
+
optional: !required && !nullable ? true : undefined,
|
|
73
|
+
nullish: !required && nullable ? true : undefined,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
63
77
|
/**
|
|
64
78
|
* Creates a `PropertyNode`. `required` defaults to `false`.
|
|
79
|
+
* `schema.optional` and `schema.nullish` are auto-derived from `required` and `schema.nullable`.
|
|
65
80
|
*/
|
|
66
81
|
export function createProperty(props: Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>): PropertyNode {
|
|
82
|
+
const required = props.required ?? false
|
|
83
|
+
|
|
67
84
|
return {
|
|
68
|
-
required: false,
|
|
69
85
|
...props,
|
|
70
86
|
kind: 'Property',
|
|
87
|
+
required,
|
|
88
|
+
schema: syncPropertySchema(required, props.schema),
|
|
71
89
|
}
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
/**
|
|
75
93
|
* Creates a `ParameterNode`. `required` defaults to `false`.
|
|
94
|
+
* `schema.optional` is auto-derived from `required` and `schema.nullable`.
|
|
76
95
|
*/
|
|
77
96
|
export function createParameter(
|
|
78
97
|
props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>,
|
|
79
98
|
): ParameterNode {
|
|
99
|
+
const required = props.required ?? false
|
|
80
100
|
return {
|
|
81
|
-
required: false,
|
|
82
101
|
...props,
|
|
83
102
|
kind: 'Parameter',
|
|
103
|
+
required,
|
|
104
|
+
schema: syncPropertySchema(required, props.schema),
|
|
84
105
|
}
|
|
85
106
|
}
|
|
86
107
|
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export {
|
|
|
9
9
|
createResponse,
|
|
10
10
|
createRoot,
|
|
11
11
|
createSchema,
|
|
12
|
+
syncPropertySchema,
|
|
12
13
|
} from './factory.ts'
|
|
13
14
|
export { functionPrinter } from './functionPrinter.ts'
|
|
14
15
|
export {
|
|
@@ -26,4 +27,4 @@ export {
|
|
|
26
27
|
export { definePrinter } from './printer.ts'
|
|
27
28
|
export { buildRefMap, refMapToObject, resolveRef } from './refs.ts'
|
|
28
29
|
export { applyParamsCasing, isPlainStringType } from './utils.ts'
|
|
29
|
-
export { collect, transform, walk } from './visitor.ts'
|
|
30
|
+
export { collect, composeTransformers, transform, walk } from './visitor.ts'
|
package/src/types.ts
CHANGED
|
@@ -44,4 +44,4 @@ export type {
|
|
|
44
44
|
} from './nodes/index.ts'
|
|
45
45
|
export type { Printer, PrinterFactoryOptions } from './printer.ts'
|
|
46
46
|
export type { RefMap } from './refs.ts'
|
|
47
|
-
export type { AsyncVisitor, CollectVisitor, Visitor } from './visitor.ts'
|
|
47
|
+
export type { AsyncVisitor, CollectOptions, CollectVisitor, ParentOf, TransformOptions, Visitor, VisitorContext, WalkOptions } from './visitor.ts'
|
package/src/visitor.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { VisitorDepth } from './constants.ts'
|
|
2
2
|
import { visitorDepths, WALK_CONCURRENCY } from './constants.ts'
|
|
3
|
+
import { createParameter, createProperty } from './factory.ts'
|
|
3
4
|
import type { Node, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -35,27 +36,47 @@ function createLimit(concurrency: number) {
|
|
|
35
36
|
type LimitFn = ReturnType<typeof createLimit>
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
|
-
*
|
|
39
|
+
* Single source of truth: ordered list of `[NodeType, ParentType]` pairs
|
|
40
|
+
* describing which node types can be the parent of a given node in the AST.
|
|
41
|
+
*
|
|
42
|
+
* `ParentOf` walks this tuple and returns the parent type of the first matching entry.
|
|
39
43
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
type ParentNodeMap = [
|
|
45
|
+
[RootNode, undefined],
|
|
46
|
+
[OperationNode, RootNode],
|
|
47
|
+
[SchemaNode, RootNode | OperationNode | SchemaNode | PropertyNode | ParameterNode | ResponseNode],
|
|
48
|
+
[PropertyNode, SchemaNode],
|
|
49
|
+
[ParameterNode, OperationNode],
|
|
50
|
+
[ResponseNode, OperationNode],
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
export type ParentOf<T extends Node, TEntries extends ReadonlyArray<[Node, unknown]> = ParentNodeMap> = TEntries extends [
|
|
54
|
+
infer TEntry extends [Node, unknown],
|
|
55
|
+
...infer TRest extends ReadonlyArray<[Node, unknown]>,
|
|
56
|
+
]
|
|
57
|
+
? T extends TEntry[0]
|
|
58
|
+
? TEntry[1]
|
|
59
|
+
: ParentOf<T, TRest>
|
|
60
|
+
: Node
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Traversal context passed as the second argument to every visitor callback.
|
|
64
|
+
* The `parent` field is narrowed based on the node type being visited.
|
|
65
|
+
*/
|
|
66
|
+
export type VisitorContext<T extends Node = Node> = {
|
|
67
|
+
parent?: ParentOf<T>
|
|
47
68
|
}
|
|
48
69
|
|
|
49
70
|
/**
|
|
50
71
|
* Synchronous visitor for `transform` and `walk`.
|
|
51
72
|
*/
|
|
52
73
|
export type Visitor = {
|
|
53
|
-
root?(node: RootNode): void | RootNode
|
|
54
|
-
operation?(node: OperationNode): void | OperationNode
|
|
55
|
-
schema?(node: SchemaNode): void | SchemaNode
|
|
56
|
-
property?(node: PropertyNode): void | PropertyNode
|
|
57
|
-
parameter?(node: ParameterNode): void | ParameterNode
|
|
58
|
-
response?(node: ResponseNode): void | ResponseNode
|
|
74
|
+
root?(node: RootNode, context: VisitorContext<RootNode>): void | RootNode
|
|
75
|
+
operation?(node: OperationNode, context: VisitorContext<OperationNode>): void | OperationNode
|
|
76
|
+
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): void | SchemaNode
|
|
77
|
+
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): void | PropertyNode
|
|
78
|
+
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): void | ParameterNode
|
|
79
|
+
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): void | ResponseNode
|
|
59
80
|
}
|
|
60
81
|
|
|
61
82
|
type MaybePromise<T> = T | Promise<T>
|
|
@@ -64,24 +85,52 @@ type MaybePromise<T> = T | Promise<T>
|
|
|
64
85
|
* Async visitor for `walk`. Synchronous `Visitor` objects are compatible.
|
|
65
86
|
*/
|
|
66
87
|
export type AsyncVisitor = {
|
|
67
|
-
root?(node: RootNode): MaybePromise<void | RootNode>
|
|
68
|
-
operation?(node: OperationNode): MaybePromise<void | OperationNode>
|
|
69
|
-
schema?(node: SchemaNode): MaybePromise<void | SchemaNode>
|
|
70
|
-
property?(node: PropertyNode): MaybePromise<void | PropertyNode>
|
|
71
|
-
parameter?(node: ParameterNode): MaybePromise<void | ParameterNode>
|
|
72
|
-
response?(node: ResponseNode): MaybePromise<void | ResponseNode>
|
|
88
|
+
root?(node: RootNode, context: VisitorContext<RootNode>): MaybePromise<void | RootNode>
|
|
89
|
+
operation?(node: OperationNode, context: VisitorContext<OperationNode>): MaybePromise<void | OperationNode>
|
|
90
|
+
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): MaybePromise<void | SchemaNode>
|
|
91
|
+
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): MaybePromise<void | PropertyNode>
|
|
92
|
+
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): MaybePromise<void | ParameterNode>
|
|
93
|
+
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): MaybePromise<void | ResponseNode>
|
|
73
94
|
}
|
|
74
95
|
|
|
75
96
|
/**
|
|
76
97
|
* Visitor for `collect`.
|
|
77
98
|
*/
|
|
78
99
|
export type CollectVisitor<T> = {
|
|
79
|
-
root?(node: RootNode): T | undefined
|
|
80
|
-
operation?(node: OperationNode): T | undefined
|
|
81
|
-
schema?(node: SchemaNode): T | undefined
|
|
82
|
-
property?(node: PropertyNode): T | undefined
|
|
83
|
-
parameter?(node: ParameterNode): T | undefined
|
|
84
|
-
response?(node: ResponseNode): T | undefined
|
|
100
|
+
root?(node: RootNode, context: VisitorContext<RootNode>): T | undefined
|
|
101
|
+
operation?(node: OperationNode, context: VisitorContext<OperationNode>): T | undefined
|
|
102
|
+
schema?(node: SchemaNode, context: VisitorContext<SchemaNode>): T | undefined
|
|
103
|
+
property?(node: PropertyNode, context: VisitorContext<PropertyNode>): T | undefined
|
|
104
|
+
parameter?(node: ParameterNode, context: VisitorContext<ParameterNode>): T | undefined
|
|
105
|
+
response?(node: ResponseNode, context: VisitorContext<ResponseNode>): T | undefined
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Options for `transform` and `collect`. Extends `Visitor` with traversal settings.
|
|
110
|
+
*/
|
|
111
|
+
export type TransformOptions = Visitor & {
|
|
112
|
+
depth?: VisitorDepth
|
|
113
|
+
parent?: Node
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Options for `walk`. Extends `AsyncVisitor` with traversal settings.
|
|
118
|
+
*/
|
|
119
|
+
export type WalkOptions = AsyncVisitor & {
|
|
120
|
+
depth?: VisitorDepth
|
|
121
|
+
/**
|
|
122
|
+
* Maximum number of sibling nodes visited concurrently.
|
|
123
|
+
* @default 30
|
|
124
|
+
*/
|
|
125
|
+
concurrency?: number
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Options for `collect`. Extends `CollectVisitor` with traversal settings.
|
|
130
|
+
*/
|
|
131
|
+
export type CollectOptions<T> = CollectVisitor<T> & {
|
|
132
|
+
depth?: VisitorDepth
|
|
133
|
+
parent?: Node
|
|
85
134
|
}
|
|
86
135
|
|
|
87
136
|
/**
|
|
@@ -125,34 +174,31 @@ function getChildren(node: Node, recurse: boolean): Array<Node> {
|
|
|
125
174
|
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
126
175
|
* Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
|
|
127
176
|
*/
|
|
128
|
-
export async function walk(node: Node,
|
|
177
|
+
export async function walk(node: Node, options: WalkOptions): Promise<void> {
|
|
129
178
|
const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep
|
|
130
179
|
const limit = createLimit(options.concurrency ?? WALK_CONCURRENCY)
|
|
131
|
-
return _walk(node,
|
|
180
|
+
return _walk(node, options, recurse, limit, undefined)
|
|
132
181
|
}
|
|
133
182
|
|
|
134
|
-
|
|
135
|
-
* Internal recursive walk implementation — calls visitor then recurses into children.
|
|
136
|
-
*/
|
|
137
|
-
async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit: LimitFn): Promise<void> {
|
|
183
|
+
async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit: LimitFn, parent: Node | undefined): Promise<void> {
|
|
138
184
|
switch (node.kind) {
|
|
139
185
|
case 'Root':
|
|
140
|
-
await limit(() => visitor.root?.(node))
|
|
186
|
+
await limit(() => visitor.root?.(node, { parent: parent as ParentOf<RootNode> }))
|
|
141
187
|
break
|
|
142
188
|
case 'Operation':
|
|
143
|
-
await limit(() => visitor.operation?.(node))
|
|
189
|
+
await limit(() => visitor.operation?.(node, { parent: parent as ParentOf<OperationNode> }))
|
|
144
190
|
break
|
|
145
191
|
case 'Schema':
|
|
146
|
-
await limit(() => visitor.schema?.(node))
|
|
192
|
+
await limit(() => visitor.schema?.(node, { parent: parent as ParentOf<SchemaNode> }))
|
|
147
193
|
break
|
|
148
194
|
case 'Property':
|
|
149
|
-
await limit(() => visitor.property?.(node))
|
|
195
|
+
await limit(() => visitor.property?.(node, { parent: parent as ParentOf<PropertyNode> }))
|
|
150
196
|
break
|
|
151
197
|
case 'Parameter':
|
|
152
|
-
await limit(() => visitor.parameter?.(node))
|
|
198
|
+
await limit(() => visitor.parameter?.(node, { parent: parent as ParentOf<ParameterNode> }))
|
|
153
199
|
break
|
|
154
200
|
case 'Response':
|
|
155
|
-
await limit(() => visitor.response?.(node))
|
|
201
|
+
await limit(() => visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> }))
|
|
156
202
|
break
|
|
157
203
|
case 'FunctionParameter':
|
|
158
204
|
case 'ObjectBindingParameter':
|
|
@@ -161,91 +207,94 @@ async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit:
|
|
|
161
207
|
}
|
|
162
208
|
|
|
163
209
|
const children = getChildren(node, recurse)
|
|
164
|
-
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)))
|
|
210
|
+
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit, node)))
|
|
165
211
|
}
|
|
166
212
|
|
|
167
213
|
/**
|
|
168
214
|
* Depth-first immutable transformation. Visitor return values replace nodes; `undefined` keeps the original.
|
|
169
215
|
*/
|
|
170
|
-
export function transform(node: RootNode,
|
|
171
|
-
export function transform(node: OperationNode,
|
|
172
|
-
export function transform(node: SchemaNode,
|
|
173
|
-
export function transform(node: PropertyNode,
|
|
174
|
-
export function transform(node: ParameterNode,
|
|
175
|
-
export function transform(node: ResponseNode,
|
|
176
|
-
export function transform(node: Node,
|
|
177
|
-
export function transform(node: Node,
|
|
178
|
-
const
|
|
216
|
+
export function transform(node: RootNode, options: TransformOptions): RootNode
|
|
217
|
+
export function transform(node: OperationNode, options: TransformOptions): OperationNode
|
|
218
|
+
export function transform(node: SchemaNode, options: TransformOptions): SchemaNode
|
|
219
|
+
export function transform(node: PropertyNode, options: TransformOptions): PropertyNode
|
|
220
|
+
export function transform(node: ParameterNode, options: TransformOptions): ParameterNode
|
|
221
|
+
export function transform(node: ResponseNode, options: TransformOptions): ResponseNode
|
|
222
|
+
export function transform(node: Node, options: TransformOptions): Node
|
|
223
|
+
export function transform(node: Node, options: TransformOptions): Node {
|
|
224
|
+
const { depth, parent, ...visitor } = options
|
|
225
|
+
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep
|
|
179
226
|
|
|
180
227
|
switch (node.kind) {
|
|
181
228
|
case 'Root': {
|
|
182
229
|
let root = node
|
|
183
|
-
const replaced = visitor.root?.(root)
|
|
230
|
+
const replaced = visitor.root?.(root, { parent: parent as ParentOf<RootNode> })
|
|
184
231
|
if (replaced) root = replaced
|
|
185
232
|
|
|
186
233
|
return {
|
|
187
234
|
...root,
|
|
188
|
-
schemas: root.schemas.map((s) => transform(s,
|
|
189
|
-
operations: root.operations.map((op) => transform(op,
|
|
235
|
+
schemas: root.schemas.map((s) => transform(s, { ...options, parent: root })),
|
|
236
|
+
operations: root.operations.map((op) => transform(op, { ...options, parent: root })),
|
|
190
237
|
}
|
|
191
238
|
}
|
|
192
239
|
case 'Operation': {
|
|
193
240
|
let op = node
|
|
194
|
-
const replaced = visitor.operation?.(op)
|
|
241
|
+
const replaced = visitor.operation?.(op, { parent: parent as ParentOf<OperationNode> })
|
|
195
242
|
if (replaced) op = replaced
|
|
196
243
|
|
|
197
244
|
return {
|
|
198
245
|
...op,
|
|
199
|
-
parameters: op.parameters.map((p) => transform(p,
|
|
246
|
+
parameters: op.parameters.map((p) => transform(p, { ...options, parent: op })),
|
|
200
247
|
requestBody: op.requestBody
|
|
201
|
-
? { ...op.requestBody, schema: op.requestBody.schema ? transform(op.requestBody.schema,
|
|
248
|
+
? { ...op.requestBody, schema: op.requestBody.schema ? transform(op.requestBody.schema, { ...options, parent: op }) : undefined }
|
|
202
249
|
: undefined,
|
|
203
|
-
responses: op.responses.map((r) => transform(r,
|
|
250
|
+
responses: op.responses.map((r) => transform(r, { ...options, parent: op })),
|
|
204
251
|
}
|
|
205
252
|
}
|
|
206
253
|
case 'Schema': {
|
|
207
254
|
let schema = node
|
|
208
|
-
const replaced = visitor.schema?.(schema)
|
|
255
|
+
const replaced = visitor.schema?.(schema, { parent: parent as ParentOf<SchemaNode> })
|
|
209
256
|
if (replaced) schema = replaced
|
|
210
257
|
|
|
258
|
+
const childOptions = { ...options, parent: schema }
|
|
259
|
+
|
|
211
260
|
return {
|
|
212
261
|
...schema,
|
|
213
|
-
...('properties' in schema && recurse ? { properties: schema.properties.map((p) => transform(p,
|
|
214
|
-
...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i,
|
|
215
|
-
...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m,
|
|
262
|
+
...('properties' in schema && recurse ? { properties: schema.properties.map((p) => transform(p, childOptions)) } : {}),
|
|
263
|
+
...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, childOptions)) } : {}),
|
|
264
|
+
...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, childOptions)) } : {}),
|
|
216
265
|
...('additionalProperties' in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true
|
|
217
|
-
? { additionalProperties: transform(schema.additionalProperties,
|
|
266
|
+
? { additionalProperties: transform(schema.additionalProperties, childOptions) }
|
|
218
267
|
: {}),
|
|
219
|
-
}
|
|
268
|
+
} as SchemaNode
|
|
220
269
|
}
|
|
221
270
|
case 'Property': {
|
|
222
271
|
let prop = node
|
|
223
|
-
const replaced = visitor.property?.(prop)
|
|
272
|
+
const replaced = visitor.property?.(prop, { parent: parent as ParentOf<PropertyNode> })
|
|
224
273
|
if (replaced) prop = replaced
|
|
225
274
|
|
|
226
|
-
return {
|
|
275
|
+
return createProperty({
|
|
227
276
|
...prop,
|
|
228
|
-
schema: transform(prop.schema,
|
|
229
|
-
}
|
|
277
|
+
schema: transform(prop.schema, { ...options, parent: prop }),
|
|
278
|
+
})
|
|
230
279
|
}
|
|
231
280
|
case 'Parameter': {
|
|
232
281
|
let param = node
|
|
233
|
-
const replaced = visitor.parameter?.(param)
|
|
282
|
+
const replaced = visitor.parameter?.(param, { parent: parent as ParentOf<ParameterNode> })
|
|
234
283
|
if (replaced) param = replaced
|
|
235
284
|
|
|
236
|
-
return {
|
|
285
|
+
return createParameter({
|
|
237
286
|
...param,
|
|
238
|
-
schema: transform(param.schema,
|
|
239
|
-
}
|
|
287
|
+
schema: transform(param.schema, { ...options, parent: param }),
|
|
288
|
+
})
|
|
240
289
|
}
|
|
241
290
|
case 'Response': {
|
|
242
291
|
let response = node
|
|
243
|
-
const replaced = visitor.response?.(response)
|
|
292
|
+
const replaced = visitor.response?.(response, { parent: parent as ParentOf<ResponseNode> })
|
|
244
293
|
if (replaced) response = replaced
|
|
245
294
|
|
|
246
295
|
return {
|
|
247
296
|
...response,
|
|
248
|
-
schema: transform(response.schema,
|
|
297
|
+
schema: transform(response.schema, { ...options, parent: response }),
|
|
249
298
|
}
|
|
250
299
|
}
|
|
251
300
|
case 'FunctionParameter':
|
|
@@ -255,32 +304,60 @@ export function transform(node: Node, visitor: Visitor, options: VisitorOptions
|
|
|
255
304
|
}
|
|
256
305
|
}
|
|
257
306
|
|
|
307
|
+
/**
|
|
308
|
+
* Combines multiple visitors into a single visitor that applies them sequentially (left to right).
|
|
309
|
+
* For each node kind, the output of one visitor becomes the input of the next.
|
|
310
|
+
*/
|
|
311
|
+
export function composeTransformers(...visitors: Array<Visitor>): Visitor {
|
|
312
|
+
return {
|
|
313
|
+
root(node, context) {
|
|
314
|
+
return visitors.reduce<RootNode>((acc, v) => v.root?.(acc, context) ?? acc, node)
|
|
315
|
+
},
|
|
316
|
+
operation(node, context) {
|
|
317
|
+
return visitors.reduce<OperationNode>((acc, v) => v.operation?.(acc, context) ?? acc, node)
|
|
318
|
+
},
|
|
319
|
+
schema(node, context) {
|
|
320
|
+
return visitors.reduce<SchemaNode>((acc, v) => v.schema?.(acc, context) ?? acc, node)
|
|
321
|
+
},
|
|
322
|
+
property(node, context) {
|
|
323
|
+
return visitors.reduce<PropertyNode>((acc, v) => v.property?.(acc, context) ?? acc, node)
|
|
324
|
+
},
|
|
325
|
+
parameter(node, context) {
|
|
326
|
+
return visitors.reduce<ParameterNode>((acc, v) => v.parameter?.(acc, context) ?? acc, node)
|
|
327
|
+
},
|
|
328
|
+
response(node, context) {
|
|
329
|
+
return visitors.reduce<ResponseNode>((acc, v) => v.response?.(acc, context) ?? acc, node)
|
|
330
|
+
},
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
258
334
|
/**
|
|
259
335
|
* Depth-first synchronous reduction. Collects non-`undefined` visitor return values into an array.
|
|
260
336
|
*/
|
|
261
|
-
export function collect<T>(node: Node,
|
|
262
|
-
const
|
|
337
|
+
export function collect<T>(node: Node, options: CollectOptions<T>): Array<T> {
|
|
338
|
+
const { depth, parent, ...visitor } = options
|
|
339
|
+
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep
|
|
263
340
|
const results: Array<T> = []
|
|
264
341
|
|
|
265
342
|
let v: T | undefined
|
|
266
343
|
switch (node.kind) {
|
|
267
344
|
case 'Root':
|
|
268
|
-
v = visitor.root?.(node)
|
|
345
|
+
v = visitor.root?.(node, { parent: parent as ParentOf<RootNode> })
|
|
269
346
|
break
|
|
270
347
|
case 'Operation':
|
|
271
|
-
v = visitor.operation?.(node)
|
|
348
|
+
v = visitor.operation?.(node, { parent: parent as ParentOf<OperationNode> })
|
|
272
349
|
break
|
|
273
350
|
case 'Schema':
|
|
274
|
-
v = visitor.schema?.(node)
|
|
351
|
+
v = visitor.schema?.(node, { parent: parent as ParentOf<SchemaNode> })
|
|
275
352
|
break
|
|
276
353
|
case 'Property':
|
|
277
|
-
v = visitor.property?.(node)
|
|
354
|
+
v = visitor.property?.(node, { parent: parent as ParentOf<PropertyNode> })
|
|
278
355
|
break
|
|
279
356
|
case 'Parameter':
|
|
280
|
-
v = visitor.parameter?.(node)
|
|
357
|
+
v = visitor.parameter?.(node, { parent: parent as ParentOf<ParameterNode> })
|
|
281
358
|
break
|
|
282
359
|
case 'Response':
|
|
283
|
-
v = visitor.response?.(node)
|
|
360
|
+
v = visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> })
|
|
284
361
|
break
|
|
285
362
|
case 'FunctionParameter':
|
|
286
363
|
case 'ObjectBindingParameter':
|
|
@@ -290,7 +367,7 @@ export function collect<T>(node: Node, visitor: CollectVisitor<T>, options: Visi
|
|
|
290
367
|
if (v !== undefined) results.push(v)
|
|
291
368
|
|
|
292
369
|
for (const child of getChildren(node, recurse)) {
|
|
293
|
-
for (const item of collect(child,
|
|
370
|
+
for (const item of collect(child, { ...options, parent: node })) {
|
|
294
371
|
results.push(item)
|
|
295
372
|
}
|
|
296
373
|
}
|