-
Notifications
You must be signed in to change notification settings - Fork 47.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds a ReactNativeInspector API to ReactNativeRenderer (#9691)
* fixed conflicts with master * splits fiber and stack implementations * prettier run * updated fiber implementation based on feedback * updated fiber implementation for selecting inspector hierarchy * run of prettier * fixed flow issues * updated stack implementation * fixes an implementation difference where before it wasnt properly understoof * addresses comments in PR feedback * updated stack inspector to use emptyObject * Update ReactNativeFiberInspector.js Fixes a flow error * fixes last flow error * prettier * applied changes to how viewConfig works for fibers and extracted measure out * fixed bad paste * fixes flow errors * prettyify * revmoed getComponentName changes * updated logic for getHostProps and addressed other PR feedback * improved throwing to invariant and update stack implemenation based on feedback * prettier
- Loading branch information
Showing
4 changed files
with
224 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule ReactNativeFiberInspector | ||
* @flow | ||
*/ | ||
'use strict'; | ||
|
||
const ReactNativeComponentTree = require('ReactNativeComponentTree'); | ||
const ReactFiberTreeReflection = require('ReactFiberTreeReflection'); | ||
const getComponentName = require('getComponentName'); | ||
const emptyObject = require('fbjs/lib/emptyObject'); | ||
const ReactTypeOfWork = require('ReactTypeOfWork'); | ||
const UIManager = require('UIManager'); | ||
const invariant = require('fbjs/lib/invariant'); | ||
|
||
const {getClosestInstanceFromNode} = ReactNativeComponentTree; | ||
const {findCurrentFiberUsingSlowPath} = ReactFiberTreeReflection; | ||
const {HostComponent} = ReactTypeOfWork; | ||
|
||
import type {Fiber} from 'ReactFiber'; | ||
|
||
let getInspectorDataForViewTag; | ||
|
||
if (__DEV__) { | ||
var traverseOwnerTreeUp = function(hierarchy, instance: any) { | ||
if (instance) { | ||
hierarchy.unshift(instance); | ||
traverseOwnerTreeUp(hierarchy, instance._debugOwner); | ||
} | ||
}; | ||
|
||
var getOwnerHierarchy = function(instance: any) { | ||
var hierarchy = []; | ||
traverseOwnerTreeUp(hierarchy, instance); | ||
return hierarchy; | ||
}; | ||
|
||
var lastNonHostInstance = function(hierarchy) { | ||
for (let i = hierarchy.length - 1; i > 1; i--) { | ||
const instance = hierarchy[i]; | ||
|
||
if (instance.tag !== HostComponent) { | ||
return instance; | ||
} | ||
} | ||
return hierarchy[0]; | ||
}; | ||
|
||
var getHostProps = function(fiber) { | ||
const host = ReactFiberTreeReflection.findCurrentHostFiber(fiber); | ||
if (host) { | ||
return host.memoizedProps || emptyObject; | ||
} | ||
return emptyObject; | ||
}; | ||
|
||
var getHostNode = function(fiber: Fiber | null, findNodeHandle) { | ||
let hostNode; | ||
// look for children first for the hostNode | ||
// as composite fibers do not have a hostNode | ||
while (fiber) { | ||
if (fiber.stateNode !== null && fiber.tag === HostComponent) { | ||
hostNode = findNodeHandle(fiber.stateNode); | ||
} | ||
if (hostNode) { | ||
return hostNode; | ||
} | ||
fiber = fiber.child; | ||
} | ||
return null; | ||
}; | ||
|
||
var stripTopSecret = str => | ||
typeof str === 'string' && str.replace('topsecret-', ''); | ||
|
||
var createHierarchy = function(fiberHierarchy) { | ||
return fiberHierarchy.map(fiber => ({ | ||
name: stripTopSecret(getComponentName(fiber)), | ||
getInspectorData: findNodeHandle => ({ | ||
measure: callback => | ||
UIManager.measure(getHostNode(fiber, findNodeHandle), callback), | ||
props: getHostProps(fiber), | ||
source: fiber._debugSource, | ||
}), | ||
})); | ||
}; | ||
|
||
getInspectorDataForViewTag = function(viewTag: number): Object { | ||
const fiber = findCurrentFiberUsingSlowPath( | ||
getClosestInstanceFromNode(viewTag), | ||
); | ||
const fiberHierarchy = getOwnerHierarchy(fiber); | ||
const instance = lastNonHostInstance(fiberHierarchy); | ||
const hierarchy = createHierarchy(fiberHierarchy); | ||
const props = getHostProps(instance); | ||
const source = instance._debugSource; | ||
const selection = fiberHierarchy.indexOf(instance); | ||
|
||
return { | ||
hierarchy, | ||
instance, | ||
props, | ||
selection, | ||
source, | ||
}; | ||
}; | ||
} else { | ||
getInspectorDataForViewTag = () => { | ||
invariant( | ||
false, | ||
'getInspectorDataForViewTag() is not available in production', | ||
); | ||
}; | ||
} | ||
|
||
module.exports = { | ||
getInspectorDataForViewTag, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule ReactNativeStackInspector | ||
* @flow | ||
*/ | ||
'use strict'; | ||
|
||
const ReactNativeComponentTree = require('ReactNativeComponentTree'); | ||
const getComponentName = require('getComponentName'); | ||
const emptyObject = require('fbjs/lib/emptyObject'); | ||
const UIManager = require('UIManager'); | ||
const invariant = require('fbjs/lib/invariant'); | ||
|
||
let getInspectorDataForViewTag; | ||
|
||
if (__DEV__) { | ||
var traverseOwnerTreeUp = function(hierarchy, instance) { | ||
if (instance) { | ||
hierarchy.unshift(instance); | ||
traverseOwnerTreeUp(hierarchy, instance._currentElement._owner); | ||
} | ||
}; | ||
|
||
var getOwnerHierarchy = function(instance) { | ||
var hierarchy = []; | ||
traverseOwnerTreeUp(hierarchy, instance); | ||
return hierarchy; | ||
}; | ||
|
||
var lastNotNativeInstance = function(hierarchy) { | ||
for (let i = hierarchy.length - 1; i > 1; i--) { | ||
const instance = hierarchy[i]; | ||
if (!instance.viewConfig) { | ||
return instance; | ||
} | ||
} | ||
return hierarchy[0]; | ||
}; | ||
|
||
var getHostProps = function(component) { | ||
const instance = component._instance; | ||
if (instance) { | ||
return instance.props || emptyObject; | ||
} | ||
return emptyObject; | ||
}; | ||
|
||
var createHierarchy = function(componentHierarchy) { | ||
return componentHierarchy.map(component => ({ | ||
name: getComponentName(component), | ||
getInspectorData: () => ({ | ||
measure: callback => | ||
UIManager.measure(component.getHostNode(), callback), | ||
props: getHostProps(component), | ||
source: component._currentElement && component._currentElement._source, | ||
}), | ||
})); | ||
}; | ||
|
||
getInspectorDataForViewTag = function(viewTag: any): Object { | ||
const component = ReactNativeComponentTree.getClosestInstanceFromNode( | ||
viewTag, | ||
); | ||
const componentHierarchy = getOwnerHierarchy(component); | ||
const instance = lastNotNativeInstance(componentHierarchy); | ||
const hierarchy = createHierarchy(componentHierarchy); | ||
const props = getHostProps(instance); | ||
const source = instance._currentElement && instance._currentElement._source; | ||
const selection = componentHierarchy.indexOf(instance); | ||
|
||
return { | ||
hierarchy, | ||
instance, | ||
props, | ||
selection, | ||
source, | ||
}; | ||
}; | ||
} else { | ||
getInspectorDataForViewTag = () => { | ||
invariant( | ||
false, | ||
'getInspectorDataForViewTag() is not available in production', | ||
); | ||
}; | ||
} | ||
|
||
module.exports = { | ||
getInspectorDataForViewTag, | ||
}; |