@samitouri / QOS-React-2 / commits / 0ea4674d08

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

Dominic Gannaway committed May 23, 2017 at 22:22 UTC 0ea4674d08b2e8ff9abc4d901f6a21e7660a2e5a
4 files changed +224
src/renderers/native/ReactNativeFiber.js
+2
@@ -23,6 +23,7 @@ const ReactNativeInjection = require('ReactNativeInjection');
23 const ReactNativeTagHandles = require('ReactNativeTagHandles');
24 const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');
25 const ReactPortal = require('ReactPortal');
26 +const ReactNativeFiberInspector = require('ReactNativeFiberInspector');
27 const ReactVersion = require('ReactVersion');
28 const UIManager = require('UIManager');
29
@@ -465,6 +466,7 @@ if (typeof injectInternals === 'function') {
466 injectInternals({
467 findFiberByHostInstance: ReactNativeComponentTree.getClosestInstanceFromNode,
468 findHostInstanceByFiber: NativeRenderer.findHostInstance,
469 + getInspectorDataForViewTag: ReactNativeFiberInspector.getInspectorDataForViewTag,
470 // This is an enum because we may add more (e.g. profiler build)
471 bundleType: __DEV__ ? 1 : 0,
472 version: ReactVersion,
src/renderers/native/ReactNativeFiberInspector.js new
+124
@@ -0,0 +1,124 @@
1 +/**
2 + * Copyright (c) 2015-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactNativeFiberInspector
10 + * @flow
11 + */
12 +'use strict';
13 +
14 +const ReactNativeComponentTree = require('ReactNativeComponentTree');
15 +const ReactFiberTreeReflection = require('ReactFiberTreeReflection');
16 +const getComponentName = require('getComponentName');
17 +const emptyObject = require('fbjs/lib/emptyObject');
18 +const ReactTypeOfWork = require('ReactTypeOfWork');
19 +const UIManager = require('UIManager');
20 +const invariant = require('fbjs/lib/invariant');
21 +
22 +const {getClosestInstanceFromNode} = ReactNativeComponentTree;
23 +const {findCurrentFiberUsingSlowPath} = ReactFiberTreeReflection;
24 +const {HostComponent} = ReactTypeOfWork;
25 +
26 +import type {Fiber} from 'ReactFiber';
27 +
28 +let getInspectorDataForViewTag;
29 +
30 +if (__DEV__) {
31 + var traverseOwnerTreeUp = function(hierarchy, instance: any) {
32 + if (instance) {
33 + hierarchy.unshift(instance);
34 + traverseOwnerTreeUp(hierarchy, instance._debugOwner);
35 + }
36 + };
37 +
38 + var getOwnerHierarchy = function(instance: any) {
39 + var hierarchy = [];
40 + traverseOwnerTreeUp(hierarchy, instance);
41 + return hierarchy;
42 + };
43 +
44 + var lastNonHostInstance = function(hierarchy) {
45 + for (let i = hierarchy.length - 1; i > 1; i--) {
46 + const instance = hierarchy[i];
47 +
48 + if (instance.tag !== HostComponent) {
49 + return instance;
50 + }
51 + }
52 + return hierarchy[0];
53 + };
54 +
55 + var getHostProps = function(fiber) {
56 + const host = ReactFiberTreeReflection.findCurrentHostFiber(fiber);
57 + if (host) {
58 + return host.memoizedProps || emptyObject;
59 + }
60 + return emptyObject;
61 + };
62 +
63 + var getHostNode = function(fiber: Fiber | null, findNodeHandle) {
64 + let hostNode;
65 + // look for children first for the hostNode
66 + // as composite fibers do not have a hostNode
67 + while (fiber) {
68 + if (fiber.stateNode !== null && fiber.tag === HostComponent) {
69 + hostNode = findNodeHandle(fiber.stateNode);
70 + }
71 + if (hostNode) {
72 + return hostNode;
73 + }
74 + fiber = fiber.child;
75 + }
76 + return null;
77 + };
78 +
79 + var stripTopSecret = str =>
80 + typeof str === 'string' && str.replace('topsecret-', '');
81 +
82 + var createHierarchy = function(fiberHierarchy) {
83 + return fiberHierarchy.map(fiber => ({
84 + name: stripTopSecret(getComponentName(fiber)),
85 + getInspectorData: findNodeHandle => ({
86 + measure: callback =>
87 + UIManager.measure(getHostNode(fiber, findNodeHandle), callback),
88 + props: getHostProps(fiber),
89 + source: fiber._debugSource,
90 + }),
91 + }));
92 + };
93 +
94 + getInspectorDataForViewTag = function(viewTag: number): Object {
95 + const fiber = findCurrentFiberUsingSlowPath(
96 + getClosestInstanceFromNode(viewTag),
97 + );
98 + const fiberHierarchy = getOwnerHierarchy(fiber);
99 + const instance = lastNonHostInstance(fiberHierarchy);
100 + const hierarchy = createHierarchy(fiberHierarchy);
101 + const props = getHostProps(instance);
102 + const source = instance._debugSource;
103 + const selection = fiberHierarchy.indexOf(instance);
104 +
105 + return {
106 + hierarchy,
107 + instance,
108 + props,
109 + selection,
110 + source,
111 + };
112 + };
113 +} else {
114 + getInspectorDataForViewTag = () => {
115 + invariant(
116 + false,
117 + 'getInspectorDataForViewTag() is not available in production',
118 + );
119 + };
120 +}
121 +
122 +module.exports = {
123 + getInspectorDataForViewTag,
124 +};
src/renderers/native/ReactNativeStack.js
+2
@@ -16,6 +16,7 @@ var ReactNativeInjection = require('ReactNativeInjection');
16 var ReactNativeMount = require('ReactNativeMount');
17 var ReactNativeStackInjection = require('ReactNativeStackInjection');
18 var ReactUpdates = require('ReactUpdates');
19 +var ReactNativeStackInspector = require('ReactNativeStackInspector');
20
21 var findNodeHandle = require('findNodeHandle');
22
@@ -81,6 +82,7 @@ if (
82 },
83 Mount: ReactNativeMount,
84 Reconciler: require('ReactReconciler'),
85 + getInspectorDataForViewTag: ReactNativeStackInspector.getInspectorDataForViewTag,
86 });
87 }
88
src/renderers/native/ReactNativeStackInspector.js new
+96
@@ -0,0 +1,96 @@
1 +/**
2 + * Copyright (c) 2015-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactNativeStackInspector
10 + * @flow
11 + */
12 +'use strict';
13 +
14 +const ReactNativeComponentTree = require('ReactNativeComponentTree');
15 +const getComponentName = require('getComponentName');
16 +const emptyObject = require('fbjs/lib/emptyObject');
17 +const UIManager = require('UIManager');
18 +const invariant = require('fbjs/lib/invariant');
19 +
20 +let getInspectorDataForViewTag;
21 +
22 +if (__DEV__) {
23 + var traverseOwnerTreeUp = function(hierarchy, instance) {
24 + if (instance) {
25 + hierarchy.unshift(instance);
26 + traverseOwnerTreeUp(hierarchy, instance._currentElement._owner);
27 + }
28 + };
29 +
30 + var getOwnerHierarchy = function(instance) {
31 + var hierarchy = [];
32 + traverseOwnerTreeUp(hierarchy, instance);
33 + return hierarchy;
34 + };
35 +
36 + var lastNotNativeInstance = function(hierarchy) {
37 + for (let i = hierarchy.length - 1; i > 1; i--) {
38 + const instance = hierarchy[i];
39 + if (!instance.viewConfig) {
40 + return instance;
41 + }
42 + }
43 + return hierarchy[0];
44 + };
45 +
46 + var getHostProps = function(component) {
47 + const instance = component._instance;
48 + if (instance) {
49 + return instance.props || emptyObject;
50 + }
51 + return emptyObject;
52 + };
53 +
54 + var createHierarchy = function(componentHierarchy) {
55 + return componentHierarchy.map(component => ({
56 + name: getComponentName(component),
57 + getInspectorData: () => ({
58 + measure: callback =>
59 + UIManager.measure(component.getHostNode(), callback),
60 + props: getHostProps(component),
61 + source: component._currentElement && component._currentElement._source,
62 + }),
63 + }));
64 + };
65 +
66 + getInspectorDataForViewTag = function(viewTag: any): Object {
67 + const component = ReactNativeComponentTree.getClosestInstanceFromNode(
68 + viewTag,
69 + );
70 + const componentHierarchy = getOwnerHierarchy(component);
71 + const instance = lastNotNativeInstance(componentHierarchy);
72 + const hierarchy = createHierarchy(componentHierarchy);
73 + const props = getHostProps(instance);
74 + const source = instance._currentElement && instance._currentElement._source;
75 + const selection = componentHierarchy.indexOf(instance);
76 +
77 + return {
78 + hierarchy,
79 + instance,
80 + props,
81 + selection,
82 + source,
83 + };
84 + };
85 +} else {
86 + getInspectorDataForViewTag = () => {
87 + invariant(
88 + false,
89 + 'getInspectorDataForViewTag() is not available in production',
90 + );
91 + };
92 +}
93 +
94 +module.exports = {
95 + getInspectorDataForViewTag,
96 +};