/** * Copyright (c) 2016-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. */ 'use strict'; /*eslint no-console-disallow: "off"*/ /*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/ function RefVisitor(refs,id){ this.refs=refs; this.id=id; } RefVisitor.prototype={ moveToEdge:function moveToEdge(name){ var ref=this.refs[this.id]; if(ref&&ref.edges){ var edges=ref.edges; for(var edgeId in edges){ if(edges[edgeId]===name){ this.id=edgeId; return this; } } } this.id=undefined; return this; }, moveToFirst:function moveToFirst(callback){ var ref=this.refs[this.id]; if(ref&&ref.edges){ var edges=ref.edges; for(var edgeId in edges){ this.id=edgeId; if(callback(edges[edgeId],this)){ return this; } } } this.id=undefined; return this; }, forEachEdge:function forEachEdge(callback){ var ref=this.refs[this.id]; if(ref&&ref.edges){ var edges=ref.edges; var visitor=new RefVisitor(this.refs,undefined); for(var edgeId in edges){ visitor.id=edgeId; callback(edges[edgeId],visitor); } } }, getType:function getType(){ var ref=this.refs[this.id]; if(ref){ return ref.type; } return undefined; }, getRef:function getRef(){ return this.refs[this.id]; }, clone:function clone(){ return new RefVisitor(this.refs,this.id); }, isDefined:function isDefined(){ return!!this.id; }, getValue:function getValue(){var _this=this; var ref=this.refs[this.id]; if(ref){ if(ref.type==='string'){ if(ref.value){ return ref.value; }else{var _ret=function(){ var rope=[]; _this.forEachEdge(function(name,visitor){ if(name&&name.startsWith('[')&&name.endsWith(']')){ var index=parseInt(name.substring(1,name.length-1),10); rope[index]=visitor.getValue(); } }); return{v:rope.join('')};}();if(typeof _ret==="object")return _ret.v; } }else if(ref.type==='ScriptExecutable'|| ref.type==='EvalExecutable'|| ref.type==='ProgramExecutable'){ return ref.value.url+':'+ref.value.line+':'+ref.value.col; }else if(ref.type==='FunctionExecutable'){ return ref.value.name+'@'+ref.value.url+':'+ref.value.line+':'+ref.value.col; }else if(ref.type==='NativeExecutable'){ return ref.value.function+' '+ref.value.constructor+' '+ref.value.name; }else if(ref.type==='Function'){ var executable=this.clone().moveToEdge('@Executable'); if(executable.id){ return executable.getRef().type+' '+executable.getValue(); } } } return'#none'; }}; function forEachRef(refs,callback){ var visitor=new RefVisitor(refs,undefined); for(var id in refs){ visitor.id=id; callback(visitor); } } function getTypeName(ref){ if(ref.type==='Function'&&!!ref.value){ return'Function '+ref.value.name; } return ref.type; } function idGetProp(refs,id,prop){ var ref=refs[id]; if(ref&&ref.edges){ var edges=ref.edges; for(var edgeId in edges){ if(edges[edgeId]===prop){ return edgeId; } } } return undefined; } function idPropForEach(refs,id,callback){ var ref=refs[id]; if(ref&&ref.edges){ var edges=ref.edges; for(var edgeId in edges){ callback(edges[edgeId],edgeId); } } } function getInternalInstanceName(refs,id){ var elementId=idGetProp(refs,id,'_currentElement'); var typeId=idGetProp(refs,elementId,'type'); var typeRef=refs[typeId]; if(typeRef){ if(typeRef.type==='string'){// element.type is string if(typeRef.value){ return typeRef.value; } }else if(typeRef.type==='Function'){// element.type is function var displayNameId=idGetProp(refs,typeId,'displayName'); if(displayNameId){ var displayNameRef=refs[displayNameId]; if(displayNameRef&&displayNameRef.value){ return displayNameRef.value;// element.type.displayName } } var nameId=idGetProp(refs,typeId,'name'); if(nameId){ var nameRef=refs[nameId]; if(nameRef&&nameRef.value){ return nameRef.value;// element.type.name } } if(typeRef.value&&typeRef.value.name){ return typeRef.value.name;// element.type symbolicated function name } } } return'#unknown'; } function registerReactComponentTreeImpl(refs,registry,parents,inEdgeNames,trees,id){ if(parents[id]===undefined){ // not a component }else if(parents[id]===null){ trees[id]=registry.insert(registry.root,getInternalInstanceName(refs,id)); }else{ var parent=parents[id]; var inEdgeName=inEdgeNames[id]; var parentTree=trees[parent]; if(parentTree===undefined){ parentTree=registerReactComponentTreeImpl( refs, registry, parents, inEdgeNames, trees, parent); } trees[id]=registry.insert(parentTree,inEdgeName); } return trees[id]; } // TODO: make it easier to query the heap graph, it's super annoying to deal with edges directly function registerReactComponentTree(refs,registry){ // build list of parents for react interal instances, so we can connect a tree var parents={}; var inEdgeNames={};var _loop=function _loop( id){ idPropForEach(refs,id,function(name,propId){ if(propId!=='0x0'){ if(name==='_renderedChildren'){ if(parents[id]===undefined){ // mark that we are a react component, even if we don't have a parent parents[id]=null; } idPropForEach(refs,propId,function(childName,childPropId){ if(childName.startsWith('.')){ parents[childPropId]=id; inEdgeNames[childPropId]=childName+': '+ getInternalInstanceName(refs,childPropId); } }); }else if(name==='_renderedComponent'){ if(parents[id]===undefined){ parents[id]=null; } parents[propId]=id; inEdgeNames[propId]=getInternalInstanceName(refs,propId); } } });};for(var id in refs){_loop(id); } // build tree of react internal instances (since that's what has the structure) var trees={}; for(var _id in refs){ registerReactComponentTreeImpl(refs,registry,parents,inEdgeNames,trees,_id); } // hook in components by looking at their _reactInternalInstance fields for(var _id2 in refs){ var internalInstance=idGetProp(refs,_id2,'_reactInternalInstance'); if(internalInstance&&trees[internalInstance]){ trees[_id2]=trees[internalInstance]; } } return trees; } function registerPathToRoot(roots,refs,registry,reactComponentTree){ var visited={}; var breadth=[]; for(var i=0;i0){ var nextBreadth=[];var _loop2=function _loop2( _i){ var id=breadth[_i]; var ref=refs[id]; var node=visited[id]; // TODO: make edges map id -> name, (empty for none) seems that would be better var edges=Object.getOwnPropertyNames(ref.edges); edges.sort(function putUnknownLast(a,b){ var aName=ref.edges[a]; var bName=ref.edges[b]; if(aName===null&&bName!==null){ return 1; }else if(aName!==null&&bName===null){ return-1; }else if(aName===null&&bName===null){ return 0; }else{ return a.localeCompare(b); } }); for(var j=0;j