44using System ;
55using System . Collections . Generic ;
66using System . Linq ;
7+ using System . Linq . Expressions ;
78using System . Net . Http ;
89using System . Text . Json . Nodes ;
910
@@ -15,15 +16,56 @@ namespace Microsoft.OpenApi
1516 public class OpenApiWalker
1617 {
1718 private readonly OpenApiVisitorBase _visitor ;
19+ private readonly Expression < Func < OpenApiDocument , object > > [ ] ? _nodesToVisit ;
1820 private readonly Stack < IOpenApiSchema > _schemaLoop = new ( ) ;
1921 private readonly Stack < IOpenApiPathItem > _pathItemLoop = new ( ) ;
2022
2123 /// <summary>
2224 /// Initializes the <see cref="OpenApiWalker"/> class.
2325 /// </summary>
24- public OpenApiWalker ( OpenApiVisitorBase visitor )
26+ /// <param name="visitor">The visitor to use for walking the OpenAPI document.</param>
27+ /// <param name="nodesToVisit">An expression specifying which nodes to visit.</param>
28+ /// <example>
29+ /// <code>
30+ /// var walker = new OpenApiWalker(visitor, [
31+ /// {
32+ /// doc => doc.Paths,
33+ /// doc => doc.Components.Schemas
34+ /// }]);
35+ /// </code>
36+ /// </example>
37+ public OpenApiWalker ( OpenApiVisitorBase visitor , Expression < Func < OpenApiDocument , object > > [ ] ? nodesToVisit )
2538 {
2639 _visitor = visitor ;
40+ _nodesToVisit = nodesToVisit ;
41+ }
42+
43+ /// <summary>
44+ /// Initializes the <see cref="OpenApiWalker"/> class.
45+ /// </summary>
46+ /// <param name="visitor">The visitor to use for walking the OpenAPI document.</param>
47+ public OpenApiWalker ( OpenApiVisitorBase visitor ) : this ( visitor , null )
48+ {
49+ // TODO: remove this constructor in next major version and make nodesToVisit params
50+ }
51+ private HashSet < string > ? nodesToVisitPaths ;
52+ private bool IsNodeSelected ( Expression < Func < OpenApiDocument , object > > candidate )
53+ {
54+ if ( _nodesToVisit is not { Length : > 0 } )
55+ {
56+ return true ;
57+ }
58+
59+ if ( nodesToVisitPaths == null || nodesToVisitPaths . Count != _nodesToVisit . Length )
60+ {
61+ nodesToVisitPaths = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
62+ foreach ( var node in _nodesToVisit )
63+ {
64+ nodesToVisitPaths . Add ( node . ToString ( ) ) ;
65+ }
66+ }
67+
68+ return nodesToVisitPaths . Contains ( candidate . ToString ( ) ) ;
2769 }
2870
2971 /// <summary>
@@ -42,39 +84,39 @@ public void Walk(OpenApiDocument? doc)
4284
4385 _visitor . Visit ( doc ) ;
4486
45- if ( doc . Info is { } info )
87+ if ( doc . Info is { } info && IsNodeSelected ( static d => d . Info ) )
4688 {
4789 WalkItem ( OpenApiConstants . Info , info , static ( self , item ) => self . Walk ( item ) ) ;
4890 }
4991
50- if ( doc . Servers is { } servers )
92+ if ( doc . Servers is { } servers && IsNodeSelected ( static d => d . Servers ! ) )
5193 {
5294 WalkItem ( OpenApiConstants . Servers , servers , static ( self , item ) => self . Walk ( item ) ) ;
5395 }
5496
55- if ( doc . Paths is { } paths )
97+ if ( doc . Paths is { } paths && IsNodeSelected ( static d => d . Paths ) )
5698 {
5799 WalkItem ( OpenApiConstants . Paths , paths , static ( self , item ) => self . Walk ( item ) ) ;
58100 }
59101
60102 WalkDictionary ( OpenApiConstants . Webhooks , doc . Webhooks , static ( self , item , isComponent ) => self . Walk ( item , isComponent ) ) ;
61103
62- if ( doc . Components is { } components )
104+ if ( doc . Components is { } components && IsNodeSelected ( static d => d . Components ! ) )
63105 {
64106 WalkItem ( OpenApiConstants . Components , components , static ( self , item ) => self . Walk ( item ) ) ;
65107 }
66108
67- if ( doc . Security is { } security )
109+ if ( doc . Security is { } security && IsNodeSelected ( static d => d . Security ! ) )
68110 {
69111 WalkItem ( OpenApiConstants . Security , security , static ( self , item ) => self . Walk ( item ) ) ;
70112 }
71113
72- if ( doc . ExternalDocs is { } externalDocs )
114+ if ( doc . ExternalDocs is { } externalDocs && IsNodeSelected ( static d => d . ExternalDocs ! ) )
73115 {
74116 WalkItem ( OpenApiConstants . ExternalDocs , externalDocs , static ( self , item ) => self . Walk ( item ) ) ;
75117 }
76118
77- if ( doc . Tags is { } tags )
119+ if ( doc . Tags is { } tags && IsNodeSelected ( static d => d . Tags ! ) )
78120 {
79121 WalkItem ( OpenApiConstants . Tags , tags , static ( self , item ) => self . Walk ( item ) ) ;
80122 }
@@ -151,18 +193,30 @@ internal void Walk(OpenApiComponents? components)
151193 _visitor . Visit ( components ) ;
152194
153195 var isComponent = true ;
154- WalkDictionary ( OpenApiConstants . Schemas , components . Schemas , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
155- WalkDictionary ( OpenApiConstants . SecuritySchemes , components . SecuritySchemes , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
156- WalkDictionary ( OpenApiConstants . Callbacks , components . Callbacks , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
157- WalkDictionary ( OpenApiConstants . PathItems , components . PathItems , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
158- WalkDictionary ( OpenApiConstants . Parameters , components . Parameters , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
159- WalkDictionary ( OpenApiConstants . Examples , components . Examples , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
160- WalkDictionary ( OpenApiConstants . Headers , components . Headers , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
161- WalkDictionary ( OpenApiConstants . Links , components . Links , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
162- WalkDictionary ( OpenApiConstants . RequestBodies , components . RequestBodies , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
163- WalkDictionary ( OpenApiConstants . Responses , components . Responses , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
164-
165- Walk ( components as IOpenApiExtensible ) ;
196+ var isComponentsNodeSelected = IsNodeSelected ( static d => d . Components ! ) ;
197+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . Schemas ! ) )
198+ WalkDictionary ( OpenApiConstants . Schemas , components . Schemas , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
199+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . SecuritySchemes ! ) )
200+ WalkDictionary ( OpenApiConstants . SecuritySchemes , components . SecuritySchemes , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
201+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . Callbacks ! ) )
202+ WalkDictionary ( OpenApiConstants . Callbacks , components . Callbacks , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
203+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . PathItems ! ) )
204+ WalkDictionary ( OpenApiConstants . PathItems , components . PathItems , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
205+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . Parameters ! ) )
206+ WalkDictionary ( OpenApiConstants . Parameters , components . Parameters , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
207+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . Examples ! ) )
208+ WalkDictionary ( OpenApiConstants . Examples , components . Examples , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
209+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . Headers ! ) )
210+ WalkDictionary ( OpenApiConstants . Headers , components . Headers , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
211+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . Links ! ) )
212+ WalkDictionary ( OpenApiConstants . Links , components . Links , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
213+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . RequestBodies ! ) )
214+ WalkDictionary ( OpenApiConstants . RequestBodies , components . RequestBodies , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
215+ if ( isComponentsNodeSelected || IsNodeSelected ( static d => d . Components ! . Responses ! ) )
216+ WalkDictionary ( OpenApiConstants . Responses , components . Responses , static ( self , item , isComponent ) => self . Walk ( item ) , isComponent ) ;
217+
218+ if ( isComponentsNodeSelected )
219+ Walk ( components as IOpenApiExtensible ) ;
166220 }
167221
168222 /// <summary>
0 commit comments