@@ -19,6 +19,7 @@ import {
19
19
FunctionalComponent ,
20
20
ClassComponent ,
21
21
HostComponent ,
22
+ HostPortal ,
22
23
HostText ,
23
24
HostRoot ,
24
25
} from 'shared/ReactTypeOfWork' ;
@@ -286,60 +287,86 @@ function toJSON(inst: Instance | TextInstance): ReactTestRendererNode {
286
287
}
287
288
}
288
289
289
- function nodeAndSiblingsTrees ( nodeWithSibling : ?Fiber ) {
290
+ function childrenToTree ( node ) {
291
+ if ( ! node ) {
292
+ return null ;
293
+ }
294
+ const children = nodeAndSiblingsArray ( node ) ;
295
+ if ( children . length === 0 ) {
296
+ return null ;
297
+ } else if ( children . length === 1 ) {
298
+ return toTree ( children [ 0 ] ) ;
299
+ }
300
+ return flatten ( children . map ( toTree ) ) ;
301
+ }
302
+
303
+ function nodeAndSiblingsArray ( nodeWithSibling ) {
290
304
const array = [ ] ;
291
305
let node = nodeWithSibling ;
292
306
while ( node != null ) {
293
307
array . push ( node ) ;
294
308
node = node . sibling ;
295
309
}
296
- const trees = array . map ( toTree ) ;
297
- return trees . length ? trees : null ;
310
+ return array ;
298
311
}
299
312
300
- function hasSiblings ( node : ?Fiber ) {
301
- return node && node . sibling ;
313
+ function flatten ( arr ) {
314
+ const result = [ ] ;
315
+ const stack = [ { i : 0 , array : arr } ] ;
316
+ while ( stack . length ) {
317
+ const n = stack . pop ( ) ;
318
+ while ( n . i < n . array . length ) {
319
+ const el = n . array [ n . i ] ;
320
+ n . i += 1 ;
321
+ if ( Array . isArray ( el ) ) {
322
+ stack . push ( n ) ;
323
+ stack . push ( { i : 0 , array : el } ) ;
324
+ break ;
325
+ }
326
+ result . push ( el ) ;
327
+ }
328
+ }
329
+ return result ;
302
330
}
303
331
304
332
function toTree ( node : ?Fiber ) {
305
333
if ( node == null ) {
306
334
return null ;
307
335
}
308
336
switch ( node . tag ) {
309
- case HostRoot : // 3
310
- return toTree ( node . child ) ;
337
+ case HostRoot :
338
+ return childrenToTree ( node . child ) ;
339
+ case HostPortal :
340
+ return childrenToTree ( node . child ) ;
311
341
case ClassComponent :
312
342
return {
313
343
nodeType : 'component' ,
314
344
type : node . type ,
315
345
props : { ...node . memoizedProps } ,
316
346
instance : node . stateNode ,
317
- rendered : hasSiblings ( node . child )
318
- ? nodeAndSiblingsTrees ( node . child )
319
- : toTree ( node . child ) ,
347
+ rendered : childrenToTree ( node . child ) ,
320
348
} ;
321
- case FunctionalComponent : // 1
349
+ case FunctionalComponent :
322
350
return {
323
351
nodeType : 'component' ,
324
352
type : node . type ,
325
353
props : { ...node . memoizedProps } ,
326
354
instance : null ,
327
- rendered : hasSiblings ( node . child )
328
- ? nodeAndSiblingsTrees ( node . child )
329
- : toTree ( node . child ) ,
355
+ rendered : childrenToTree ( node . child ) ,
330
356
} ;
331
- case HostComponent : // 5
357
+ case HostComponent : {
332
358
return {
333
359
nodeType : 'host' ,
334
360
type : node . type ,
335
361
props : { ...node . memoizedProps } ,
336
362
instance : null , // TODO: use createNodeMock here somehow?
337
- rendered : nodeAndSiblingsTrees ( node . child ) ,
363
+ rendered : flatten ( nodeAndSiblingsArray ( node . child ) . map ( toTree ) ) ,
338
364
} ;
339
- case HostText : // 6
365
+ }
366
+ case HostText :
340
367
return node . stateNode . text ;
341
- case Fragment : // 10
342
- return toTree ( node . child ) ;
368
+ case Fragment :
369
+ return childrenToTree ( node . child ) ;
343
370
default :
344
371
invariant (
345
372
false ,
0 commit comments