@@ -19,14 +19,16 @@ type InternalWalkerState = {
19
19
schemaNode : RegularNode | RootNode ;
20
20
} ;
21
21
22
+ type ProcessedFragment = SchemaFragment | SchemaFragment [ ] ;
23
+
22
24
export class Walker extends EventEmitter < WalkerEmitter > {
23
25
public readonly path : string [ ] ;
24
26
public depth : number ;
25
27
26
28
protected fragment : SchemaFragment ;
27
29
protected schemaNode : RegularNode | RootNode ;
28
30
29
- private processedFragments : WeakMap < SchemaFragment , SchemaNode > ;
31
+ private processedFragments : WeakMap < ProcessedFragment , SchemaNode > ;
30
32
private readonly hooks : Partial < Dictionary < WalkerHookHandler , WalkerHookAction > > ;
31
33
32
34
constructor ( protected readonly root : RootNode , protected readonly walkingOptions : WalkingOptions ) {
@@ -103,10 +105,12 @@ export class Walker extends EventEmitter<WalkerEmitter> {
103
105
const state = this . dumpInternalWalkerState ( ) ;
104
106
105
107
super . emit ( 'enterFragment' , fragment ) ;
106
- const schemaNode = this . processFragment ( ) ;
108
+ const [ schemaNode , initialFragment ] = this . processFragment ( ) ;
107
109
super . emit ( 'enterNode' , schemaNode ) ;
108
110
109
- this . processedFragments . set ( schemaNode . fragment , isMirroredNode ( schemaNode ) ? schemaNode . mirroredNode : schemaNode ) ;
111
+ const actualNode = isMirroredNode ( schemaNode ) ? schemaNode . mirroredNode : schemaNode ;
112
+ this . processedFragments . set ( schemaNode . fragment , actualNode ) ;
113
+ this . processedFragments . set ( initialFragment , actualNode ) ;
110
114
111
115
this . fragment = schemaNode . fragment ;
112
116
this . depth = initialDepth + 1 ;
@@ -237,23 +241,23 @@ export class Walker extends EventEmitter<WalkerEmitter> {
237
241
this . schemaNode = schemaNode ;
238
242
}
239
243
240
- protected retrieveFromFragment ( fragment : SchemaFragment ) : MirroredSchemaNode | void {
244
+ protected retrieveFromFragment ( fragment : ProcessedFragment ) : [ MirroredSchemaNode , ProcessedFragment ] | void {
241
245
const processedSchemaNode = this . processedFragments . get ( fragment ) ;
242
246
if ( processedSchemaNode !== void 0 ) {
243
247
if ( isRegularNode ( processedSchemaNode ) ) {
244
- return new MirroredRegularNode ( processedSchemaNode ) ;
248
+ return [ new MirroredRegularNode ( processedSchemaNode ) , fragment ] ;
245
249
}
246
250
247
251
if ( isReferenceNode ( processedSchemaNode ) ) {
248
- return new MirroredReferenceNode ( processedSchemaNode ) ;
252
+ return [ new MirroredReferenceNode ( processedSchemaNode ) , fragment ] ;
249
253
}
250
254
251
255
// whoops, we don't know what to do with it
252
256
throw new TypeError ( 'Cannot mirror the node' ) ;
253
257
}
254
258
}
255
259
256
- protected processFragment ( ) : SchemaNode {
260
+ protected processFragment ( ) : [ SchemaNode , ProcessedFragment ] {
257
261
const { walkingOptions, path } = this ;
258
262
let { fragment } = this ;
259
263
@@ -265,23 +269,29 @@ export class Walker extends EventEmitter<WalkerEmitter> {
265
269
266
270
if ( '$ref' in fragment ) {
267
271
if ( typeof fragment . $ref !== 'string' ) {
268
- return new ReferenceNode ( fragment , '$ref is not a string' ) ;
272
+ return [ new ReferenceNode ( fragment , '$ref is not a string' ) , fragment ] ;
269
273
} else if ( walkingOptions . resolveRef !== null ) {
270
274
try {
271
275
fragment = walkingOptions . resolveRef ( path , fragment . $ref ) ;
272
276
} catch ( ex ) {
273
277
super . emit ( 'error' , createMagicError ( ex ) ) ;
274
- return new ReferenceNode ( fragment , ex ?. message ?? 'Unknown resolving error' ) ;
278
+ return [ new ReferenceNode ( fragment , ex ?. message ?? 'Unknown resolving error' ) , fragment ] ;
275
279
}
276
280
} else {
277
- return new ReferenceNode ( fragment , null ) ;
281
+ return [ new ReferenceNode ( fragment , null ) , fragment ] ;
278
282
}
279
283
}
280
284
285
+ let initialFragment : ProcessedFragment = fragment ;
281
286
if ( walkingOptions . mergeAllOf && SchemaCombinerName . AllOf in fragment ) {
282
287
try {
288
+ if ( Array . isArray ( fragment . allOf ) ) {
289
+ initialFragment = fragment . allOf ;
290
+ }
291
+
283
292
fragment = mergeAllOf ( fragment , path , walkingOptions ) ;
284
293
} catch ( ex ) {
294
+ initialFragment = fragment ;
285
295
super . emit ( 'error' , createMagicError ( new MergingError ( ex ?. message ?? 'Unknown merging error' ) ) ) ;
286
296
// no the end of the world - we will render raw unprocessed fragment
287
297
}
@@ -291,25 +301,28 @@ export class Walker extends EventEmitter<WalkerEmitter> {
291
301
try {
292
302
const merged = mergeOneOrAnyOf ( fragment , path , walkingOptions ) ;
293
303
if ( merged . length === 1 ) {
294
- return new RegularNode ( merged [ 0 ] ) ;
304
+ return [ new RegularNode ( merged [ 0 ] ) , initialFragment ] ;
295
305
} else {
296
306
const combiner = SchemaCombinerName . OneOf in fragment ? SchemaCombinerName . OneOf : SchemaCombinerName . AnyOf ;
297
- return new RegularNode ( {
298
- [ combiner ] : merged ,
299
- } ) ;
307
+ return [
308
+ new RegularNode ( {
309
+ [ combiner ] : merged ,
310
+ } ) ,
311
+ initialFragment ,
312
+ ] ;
300
313
}
301
314
} catch ( ex ) {
302
315
super . emit ( 'error' , createMagicError ( new MergingError ( ex ?. message ?? 'Unknown merging error' ) ) ) ;
303
316
// no the end of the world - we will render raw unprocessed fragment
304
317
}
305
318
}
306
319
307
- retrieved = isNonNullable ( fragment ) ? this . retrieveFromFragment ( fragment ) : null ;
320
+ retrieved = isNonNullable ( fragment ) ? this . retrieveFromFragment ( initialFragment ) : null ;
308
321
309
322
if ( retrieved ) {
310
323
return retrieved ;
311
324
}
312
325
313
- return new RegularNode ( fragment ) ;
326
+ return [ new RegularNode ( fragment ) , initialFragment ] ;
314
327
}
315
328
}
0 commit comments