@@ -146,6 +146,7 @@ import {formatOwnerStack} from '../shared/DevToolsOwnerStack';
146146// Kinds
147147const FIBER_INSTANCE = 0 ;
148148const VIRTUAL_INSTANCE = 1 ;
149+ const FILTERED_FIBER_INSTANCE = 2 ;
149150
150151// Flags
151152const FORCE_SUSPENSE_FALLBACK = /* */ 0b001 ;
@@ -157,9 +158,9 @@ const FORCE_ERROR_RESET = /* */ 0b100;
157158type FiberInstance = {
158159 kind : 0 ,
159160 id : number ,
160- parent : null | DevToolsInstance , // filtered parent, including virtual
161- firstChild : null | DevToolsInstance , // filtered first child, including virtual
162- nextSibling : null | DevToolsInstance , // filtered next sibling, including virtual
161+ parent : null | DevToolsInstance ,
162+ firstChild : null | DevToolsInstance ,
163+ nextSibling : null | DevToolsInstance ,
163164 flags : number , // Force Error/Suspense
164165 source : null | string | Error | Source , // source location of this component function, or owned child stack
165166 errors : null | Map < string , number> , // error messages and count
@@ -184,6 +185,39 @@ function createFiberInstance(fiber: Fiber): FiberInstance {
184185 } ;
185186}
186187
188+ type FilteredFiberInstance = {
189+ kind : 2 ,
190+ // We exclude id from the type to get errors if we try to access it.
191+ // However it is still in the object to preserve hidden class.
192+ // id: number,
193+ parent : null | DevToolsInstance ,
194+ firstChild : null | DevToolsInstance ,
195+ nextSibling : null | DevToolsInstance ,
196+ flags : number , // Force Error/Suspense
197+ source : null | string | Error | Source , // always null here.
198+ errors : null , // error messages and count
199+ warnings : null , // warning messages and count
200+ treeBaseDuration : number , // the profiled time of the last render of this subtree
201+ data : Fiber , // one of a Fiber pair
202+ } ;
203+
204+ // This is used to represent a filtered Fiber but still lets us find its host instance.
205+ function createFilteredFiberInstance ( fiber : Fiber ) : FilteredFiberInstance {
206+ return ( {
207+ kind : FILTERED_FIBER_INSTANCE ,
208+ id : 0 ,
209+ parent : null ,
210+ firstChild : null ,
211+ nextSibling : null ,
212+ flags : 0 ,
213+ componentStack : null ,
214+ errors : null ,
215+ warnings : null ,
216+ treeBaseDuration : 0 ,
217+ data : fiber ,
218+ } : any ) ;
219+ }
220+
187221// This type represents a stateful instance of a Server Component or a Component
188222// that gets optimized away - e.g. call-through without creating a Fiber.
189223// It's basically a virtual Fiber. This is not a semantic concept in React.
@@ -192,9 +226,9 @@ function createFiberInstance(fiber: Fiber): FiberInstance {
192226type VirtualInstance = {
193227 kind : 1 ,
194228 id : number ,
195- parent : null | DevToolsInstance , // filtered parent, including virtual
196- firstChild : null | DevToolsInstance , // filtered first child, including virtual
197- nextSibling : null | DevToolsInstance , // filtered next sibling, including virtual
229+ parent : null | DevToolsInstance ,
230+ firstChild : null | DevToolsInstance ,
231+ nextSibling : null | DevToolsInstance ,
198232 flags : number ,
199233 source : null | string | Error | Source , // source location of this server component, or owned child stack
200234 // Errors and Warnings happen per ReactComponentInfo which can appear in
@@ -226,7 +260,7 @@ function createVirtualInstance(
226260 } ;
227261}
228262
229- type DevToolsInstance = FiberInstance | VirtualInstance ;
263+ type DevToolsInstance = FiberInstance | VirtualInstance | FilteredFiberInstance ;
230264
231265type getDisplayNameForFiberType = ( fiber : Fiber ) => string | null ;
232266type getTypeSymbolType = ( type : any ) => symbol | number ;
@@ -736,7 +770,8 @@ const fiberToFiberInstanceMap: Map<Fiber, FiberInstance> = new Map();
736770// Map of id to one (arbitrary) Fiber in a pair.
737771// This Map is used to e.g. get the display name for a Fiber or schedule an update,
738772// operations that should be the same whether the current and work-in-progress Fiber is used.
739- const idToDevToolsInstanceMap : Map < number , DevToolsInstance > = new Map ( ) ;
773+ const idToDevToolsInstanceMap : Map < number , FiberInstance | VirtualInstance > =
774+ new Map ( ) ;
740775
741776// Map of resource DOM nodes to all the Fibers that depend on it.
742777const hostResourceToFiberMap : Map < HostInstance , Set < Fiber >> = new Map ( ) ;
@@ -1083,13 +1118,22 @@ export function attach(
10831118 function debugTree ( instance : DevToolsInstance , indent : number = 0 ) {
10841119 if ( __DEBUG__ ) {
10851120 const name =
1086- ( instance . kind === FIBER_INSTANCE
1121+ ( instance . kind !== VIRTUAL_INSTANCE
10871122 ? getDisplayNameForFiber ( instance . data )
10881123 : instance . data . name ) || '' ;
10891124 console . log (
1090- ' ' . repeat ( indent ) + '- ' + instance . id + ' (' + name + ')' ,
1125+ ' ' . repeat ( indent ) +
1126+ '- ' +
1127+ ( instance . kind === FILTERED_FIBER_INSTANCE ? 0 : instance . id ) +
1128+ ' (' +
1129+ name +
1130+ ')' ,
10911131 'parent' ,
1092- instance . parent === null ? ' ' : instance . parent . id ,
1132+ instance . parent === null
1133+ ? ' '
1134+ : instance . parent . kind === FILTERED_FIBER_INSTANCE
1135+ ? 0
1136+ : instance . parent . id ,
10931137 'next' ,
10941138 instance . nextSibling === null ? ' ' : instance . nextSibling . id ,
10951139 ) ;
@@ -2227,7 +2271,12 @@ export function attach(
22272271 ownerInstance . source = fiber . _debugStack ;
22282272 }
22292273 const ownerID = ownerInstance === null ? 0 : ownerInstance . id ;
2230- const parentID = parentInstance ? parentInstance . id : 0 ;
2274+ const parentID = parentInstance
2275+ ? parentInstance . kind = = = FILTERED_FIBER_INSTANCE
2276+ ? // A Filtered Fiber Instance will always have a Virtual Instance as a parent.
2277+ ( ( parentInstance . parent : any ) : VirtualInstance ) . id
2278+ : parentInstance . id
2279+ : 0 ;
22312280
22322281 const displayNameStringID = getStringID ( displayName ) ;
22332282
@@ -2311,7 +2360,12 @@ export function attach(
23112360 ownerInstance . source = componentInfo . debugStack ;
23122361 }
23132362 const ownerID = ownerInstance === null ? 0 : ownerInstance . id ;
2314- const parentID = parentInstance ? parentInstance . id : 0 ;
2363+ const parentID = parentInstance
2364+ ? parentInstance . kind = = = FILTERED_FIBER_INSTANCE
2365+ ? // A Filtered Fiber Instance will always have a Virtual Instance as a parent.
2366+ ( ( parentInstance . parent : any ) : VirtualInstance ) . id
2367+ : parentInstance . id
2368+ : 0 ;
23152369
23162370 const displayNameStringID = getStringID ( displayName ) ;
23172371
@@ -2636,6 +2690,14 @@ export function attach(
26362690 if ( shouldIncludeInTree ) {
26372691 newInstance = recordMount ( fiber , reconcilingParent ) ;
26382692 insertChild ( newInstance ) ;
2693+ } else if (
2694+ reconcilingParent !== null &&
2695+ reconcilingParent . kind = = = VIRTUAL_INSTANCE
2696+ ) {
2697+ // If the parent is a Virtual Instance and we filtered this Fiber we include a
2698+ // hidden node.
2699+ newInstance = createFilteredFiberInstance ( fiber ) ;
2700+ insertChild ( newInstance ) ;
26392701 }
26402702
26412703 // If we have the tree selection from previous reload, try to match this Fiber.
@@ -2648,7 +2710,7 @@ export function attach(
26482710 const stashedParent = reconcilingParent ;
26492711 const stashedPrevious = previouslyReconciledSibling ;
26502712 const stashedRemaining = remainingReconcilingChildren ;
2651- if ( shouldIncludeInTree ) {
2713+ if ( newInstance !== null ) {
26522714 // Push a new DevTools instance parent while reconciling this subtree.
26532715 reconcilingParent = newInstance ;
26542716 previouslyReconciledSibling = null ;
@@ -2719,7 +2781,7 @@ export function attach(
27192781 }
27202782 }
27212783 } finally {
2722- if ( shouldIncludeInTree ) {
2784+ if ( newInstance !== null ) {
27232785 reconcilingParent = stashedParent ;
27242786 previouslyReconciledSibling = stashedPrevious ;
27252787 remainingReconcilingChildren = stashedRemaining ;
@@ -2759,8 +2821,10 @@ export function attach(
27592821 }
27602822 if ( instance . kind = = = FIBER_INSTANCE ) {
27612823 recordUnmount ( instance ) ;
2762- } else {
2824+ } else if ( instance . kind = = = VIRTUAL_INSTANCE ) {
27632825 recordVirtualUnmount ( instance ) ;
2826+ } else {
2827+ ( instance : FilteredFiberInstance ) ; // assert exhaustive
27642828 }
27652829 removeChild ( instance , null ) ;
27662830 }
@@ -2865,7 +2929,9 @@ export function attach(
28652929 virtualInstance . treeBaseDuration = treeBaseDuration ;
28662930 }
28672931
2868- function recordResetChildren ( parentInstance : DevToolsInstance ) {
2932+ function recordResetChildren (
2933+ parentInstance : FiberInstance | VirtualInstance ,
2934+ ) {
28692935 if ( __DEBUG__ ) {
28702936 if (
28712937 parentInstance . firstChild !== null &&
@@ -2885,7 +2951,17 @@ export function attach(
28852951
28862952 let child: null | DevToolsInstance = parentInstance.firstChild;
28872953 while (child !== null) {
2888- nextChildren . push ( child . id ) ;
2954+ if ( child . kind === FILTERED_FIBER_INSTANCE ) {
2955+ for (
2956+ let innerChild : null | DevToolsInstance = parentInstance . firstChild ;
2957+ innerChild !== null ;
2958+ innerChild = innerChild . nextSibling
2959+ ) {
2960+ nextChildren . push ( ( innerChild : any ) . id ) ;
2961+ }
2962+ } else {
2963+ nextChildren . push ( child . id ) ;
2964+ }
28892965 child = child.nextSibling;
28902966 }
28912967
@@ -3693,7 +3769,7 @@ export function attach(
36933769 devtoolsInstance : DevToolsInstance ,
36943770 hostInstances : Array < HostInstance > ,
36953771 ) {
3696- if ( devtoolsInstance . kind === FIBER_INSTANCE ) {
3772+ if ( devtoolsInstance . kind !== VIRTUAL_INSTANCE ) {
36973773 const fiber = devtoolsInstance . data ;
36983774 appendHostInstancesByFiber ( fiber , hostInstances ) ;
36993775 return ;
@@ -3907,7 +3983,7 @@ export function attach(
39073983 }
39083984
39093985 function instanceToSerializedElement (
3910- instance : DevToolsInstance ,
3986+ instance : FiberInstance | VirtualInstance ,
39113987 ) : SerializedElement {
39123988 if ( instance . kind === FIBER_INSTANCE ) {
39133989 const fiber = instance . data ;
@@ -4002,7 +4078,7 @@ export function attach(
40024078 function findNearestOwnerInstance (
40034079 parentInstance : null | DevToolsInstance ,
40044080 owner : void | null | ReactComponentInfo | Fiber ,
4005- ) : null | DevToolsInstance {
4081+ ) : null | FiberInstance | VirtualInstance {
40064082 if ( owner == null ) {
40074083 return null ;
40084084 }
@@ -4017,6 +4093,9 @@ export function attach(
40174093 // needs a duck type check anyway.
40184094 parentInstance . data === ( owner : any ) . alternate
40194095 ) {
4096+ if ( parentInstance . kind === FILTERED_FIBER_INSTANCE ) {
4097+ return null ;
4098+ }
40204099 return parentInstance;
40214100 }
40224101 parentInstance = parentInstance . parent ;
@@ -4094,7 +4173,11 @@ export function attach(
40944173 if (devtoolsInstance.kind === VIRTUAL_INSTANCE) {
40954174 return inspectVirtualInstanceRaw ( devtoolsInstance ) ;
40964175 }
4097- return inspectFiberInstanceRaw(devtoolsInstance);
4176+ if (devtoolsInstance.kind === FIBER_INSTANCE) {
4177+ return inspectFiberInstanceRaw ( devtoolsInstance ) ;
4178+ }
4179+ (devtoolsInstance: FilteredFiberInstance); // assert exhaustive
4180+ throw new Error('Unsupported instance kind');
40984181 }
40994182
41004183 function inspectFiberInstanceRaw (
@@ -4397,7 +4480,7 @@ export function attach(
43974480 let targetErrorBoundaryID = null ;
43984481 let parent = virtualInstance . parent ;
43994482 while ( parent !== null ) {
4400- if ( parent . kind === FIBER_INSTANCE ) {
4483+ if ( parent . kind !== VIRTUAL_INSTANCE ) {
44014484 targetErrorBoundaryID = getNearestErrorBoundaryID ( parent . data ) ;
44024485 let current = parent . data ;
44034486 while ( current . return !== null ) {
@@ -5188,7 +5271,9 @@ export function attach(
51885271 ) {
51895272 // We don't need to convert milliseconds to microseconds in this case,
51905273 // because the profiling summary is JSON serialized.
5191- target . push ( [ instance . id , instance . treeBaseDuration ] ) ;
5274+ if ( instance . kind !== FILTERED_FIBER_INSTANCE ) {
5275+ target . push ( [ instance . id , instance . treeBaseDuration ] ) ;
5276+ }
51925277 for (
51935278 let child = instance.firstChild;
51945279 child !== null;
@@ -5402,7 +5487,7 @@ export function attach(
54025487 // In that case, we'll do some extra checks for matching mounts.
54035488 let trackedPath : Array < PathFrame > | null = null;
54045489 let trackedPathMatchFiber: Fiber | null = null; // This is the deepest unfiltered match of a Fiber.
5405- let trackedPathMatchInstance: DevToolsInstance | null = null; // This is the deepest matched filtered Instance.
5490+ let trackedPathMatchInstance: FiberInstance | VirtualInstance | null = null; // This is the deepest matched filtered Instance.
54065491 let trackedPathMatchDepth = -1;
54075492 let mightBeOnTrackedPath = false;
54085493
@@ -5421,7 +5506,7 @@ export function attach(
54215506 // The return value signals whether we should keep matching siblings or not.
54225507 function updateTrackedPathStateBeforeMount (
54235508 fiber : Fiber ,
5424- fiberInstance : null | FiberInstance ,
5509+ fiberInstance : null | FiberInstance | FilteredFiberInstance ,
54255510 ) : boolean {
54265511 if ( trackedPath === null || ! mightBeOnTrackedPath ) {
54275512 // Fast path: there's nothing to track so do nothing and ignore siblings.
@@ -5450,7 +5535,7 @@ export function attach(
54505535 ) {
54515536 // We have our next match.
54525537 trackedPathMatchFiber = fiber ;
5453- if ( fiberInstance !== null ) {
5538+ if ( fiberInstance !== null && fiberInstance . kind === FIBER_INSTANCE ) {
54545539 trackedPathMatchInstance = fiberInstance ;
54555540 }
54565541 trackedPathMatchDepth ++ ;
0 commit comments