Skip to content

Instantly share code, notes, and snippets.

@haxiomic
Last active August 29, 2015 14:07
Show Gist options
  • Save haxiomic/25ceea09e8aaee11a3d3 to your computer and use it in GitHub Desktop.
Save haxiomic/25ceea09e8aaee11a3d3 to your computer and use it in GitHub Desktop.
Tools for analysing javascript classes (tested on three.js)
function generateClassTree(classObject){//eg: (THREE) => ["Object3D"={"Mesh":{"SkinnedMesh"}, "Camera"}]
var classNameTree = {};
//pull out only class-like properties
var unpushedClasses = {};
for(var className in classObject){
if(classObject[className] instanceof Function)
unpushedClasses[className] = classObject[className];
}
function addBranchToTree(branch){//eg (["Object3D", "Mesh", "Cube"])
var ctx = classNameTree;
for(var i = 0; i < branch.length; i++){
if(!ctx.hasOwnProperty(branch[i]))
ctx[branch[i]] = {};
ctx = ctx[branch[i]];
}
}
//for each class, find subclasses
function findSubclasses(ParentClass, withinObject){
var result = {};
for(var className in withinObject){
var Class = withinObject[className];
if(Class.prototype.__proto__ == ParentClass.prototype){
result[className] = Class;
}
}
return result;
}
function iterate(branch){//['Object3D','Mesh']
var topClassName = branch[branch.length - 1];
var topClass = classObject[topClassName];
addBranchToTree(branch);
delete unpushedClasses[topClassName];
var subclasses = findSubclasses(topClass, unpushedClasses);
for(var subclassName in subclasses){
iterate(branch.concat(subclassName));
}
}
//find root classes
for(var className in unpushedClasses){
var Class = unpushedClasses[className];
if(Class.prototype.constructor === Class){ // || or Object?
iterate([className]);
}
}
return classNameTree;
}
function highestCommonClass(classNames, classTree){//eg: (["SkinnedMesh", "MorphBlendMesh"], classTree) => "Mesh"
var longestBranch = null;
function longestCommonBranchOfPair(a, b){
var commonBranch = [];
var shortLen = a.length < b.length ? a.length : b.length;
for(var i = 0; i < shortLen; i++){
if(a[i] === b[i]) commonBranch[i] = a[i];
else break;
}
return commonBranch;
}
function iterate(obj, parentBranch){
parentBranch = typeof parentBranch !== 'undefined' ? parentBranch : [];
for(var className in obj){
var branch = parentBranch.concat(className);
//is the one of the target branches who's top classes are given in classNames?
var topClass = branch[branch.length - 1];
if(classNames.indexOf(topClass) >= 0){
longestBranch = longestBranch != null ? longestCommonBranchOfPair(branch, longestBranch) : branch;
}
var children = obj[className];
iterate(children, branch);
}
}
iterate(classTree);
return longestBranch != null ? longestBranch[longestBranch.length - 1] : null;
}
function getClassName(obj, classObject){//eg: (new THREE.Scene(), THREE) => "Scene"
var objProto = Object.getPrototypeOf(obj);
//search through the classObject to see if we can find a matching class
for(var className in classObject){
var Class = classObject[className];
if(objProto === Class.prototype) return className;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment