@@ -6,6 +6,8 @@ import { ApiDOMStructuredError } from '@swagger-api/apidom-error';
6
6
* SPDX-License-Identifier: MIT
7
7
*/
8
8
9
+ export const customPromisifySymbol : unique symbol = Symbol . for ( 'nodejs.util.promisify.custom' ) ;
10
+
9
11
// getVisitFn :: (Visitor, String, Boolean) -> Function
10
12
export const getVisitFn = ( visitor : any , type : string , isLeaving : boolean ) => {
11
13
const typeVisitor = visitor [ type ] ;
@@ -57,7 +59,31 @@ export const cloneNode = (node: any) =>
57
59
* If a prior visitor edits a node, no following visitors will see that node.
58
60
* `exposeEdits=true` can be used to exoise the edited node from the previous visitors.
59
61
*/
60
- export const mergeAll = (
62
+
63
+ interface MergeAllBase {
64
+ (
65
+ visitors : any [ ] ,
66
+ options ?: {
67
+ visitFnGetter ?: typeof getVisitFn ;
68
+ nodeTypeGetter ?: typeof getNodeType ;
69
+ breakSymbol ?: typeof BREAK ;
70
+ deleteNodeSymbol ?: any ;
71
+ skipVisitingNodeSymbol ?: boolean ;
72
+ exposeEdits ?: boolean ;
73
+ } ,
74
+ ) : {
75
+ enter : ( node : any , ...rest : any [ ] ) => any ;
76
+ leave : ( node : any , ...rest : any [ ] ) => any ;
77
+ } ;
78
+ }
79
+
80
+ interface MergeAllPromisify {
81
+ [ customPromisifySymbol ] : MergeAllBase ;
82
+ }
83
+
84
+ type MergeAll = MergeAllBase & MergeAllPromisify ;
85
+
86
+ export const mergeAll : MergeAll = ( (
61
87
visitors : any [ ] ,
62
88
{
63
89
visitFnGetter = getVisitFn ,
@@ -121,6 +147,77 @@ export const mergeAll = (
121
147
}
122
148
}
123
149
150
+ return undefined ;
151
+ } ,
152
+ } ;
153
+ } ) as MergeAll ;
154
+
155
+ mergeAll [ customPromisifySymbol ] = (
156
+ visitors : any [ ] ,
157
+ {
158
+ visitFnGetter = getVisitFn ,
159
+ nodeTypeGetter = getNodeType ,
160
+ breakSymbol = BREAK ,
161
+ deleteNodeSymbol = null ,
162
+ skipVisitingNodeSymbol = false ,
163
+ exposeEdits = false ,
164
+ } = { } ,
165
+ ) => {
166
+ const skipSymbol = Symbol ( 'skip' ) ;
167
+ const skipping = new Array ( visitors . length ) . fill ( skipSymbol ) ;
168
+
169
+ return {
170
+ async enter ( node : any , ...rest : any [ ] ) {
171
+ let currentNode = node ;
172
+ let hasChanged = false ;
173
+
174
+ for ( let i = 0 ; i < visitors . length ; i += 1 ) {
175
+ if ( skipping [ i ] === skipSymbol ) {
176
+ const visitFn = visitFnGetter ( visitors [ i ] , nodeTypeGetter ( currentNode ) , false ) ;
177
+
178
+ if ( typeof visitFn === 'function' ) {
179
+ // eslint-disable-next-line no-await-in-loop
180
+ const result : any = await visitFn . call ( visitors [ i ] , currentNode , ...rest ) ;
181
+
182
+ if ( result === skipVisitingNodeSymbol ) {
183
+ skipping [ i ] = node ;
184
+ } else if ( result === breakSymbol ) {
185
+ skipping [ i ] = breakSymbol ;
186
+ } else if ( result === deleteNodeSymbol ) {
187
+ return result ;
188
+ } else if ( result !== undefined ) {
189
+ if ( exposeEdits ) {
190
+ currentNode = result ;
191
+ hasChanged = true ;
192
+ } else {
193
+ return result ;
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ return hasChanged ? currentNode : undefined ;
201
+ } ,
202
+ async leave ( node : any , ...rest : any [ ] ) {
203
+ for ( let i = 0 ; i < visitors . length ; i += 1 ) {
204
+ if ( skipping [ i ] === skipSymbol ) {
205
+ const visitFn = visitFnGetter ( visitors [ i ] , nodeTypeGetter ( node ) , true ) ;
206
+
207
+ if ( typeof visitFn === 'function' ) {
208
+ // eslint-disable-next-line no-await-in-loop
209
+ const result = await visitFn . call ( visitors [ i ] , node , ...rest ) ;
210
+ if ( result === breakSymbol ) {
211
+ skipping [ i ] = breakSymbol ;
212
+ } else if ( result !== undefined && result !== skipVisitingNodeSymbol ) {
213
+ return result ;
214
+ }
215
+ }
216
+ } else if ( skipping [ i ] === node ) {
217
+ skipping [ i ] = skipSymbol ;
218
+ }
219
+ }
220
+
124
221
return undefined ;
125
222
} ,
126
223
} ;
0 commit comments