Skip to content

Instantly share code, notes, and snippets.

@Nnubes256
Created June 8, 2016 18:46
Show Gist options
  • Save Nnubes256/edc27814c0777926aa31e22b4f491cef to your computer and use it in GitHub Desktop.
Save Nnubes256/edc27814c0777926aa31e22b4f491cef to your computer and use it in GitHub Desktop.
classfinder
var fs = require('fs');
var cytoscape = require('cytoscape');
var acorn = require('acorn');
var ONLY_PARSE = true;
var ONLY_AST = false;
var MODULE_MODULE = "C";
var MODULE_REQUIRE = "F";
var MODULE_DEFINE = "v";
var MODULE_EMPTY = "G";
var cy;
var file;
var matches = [];
var matchesAcc = 0;
var regex = new RegExp(
'(ig\\.' +
MODULE_MODULE +
'\\("([a-z0-9-.]+)"\\)(\\.' +
MODULE_REQUIRE +
'\\(([a-z0-9.," -]+)\\))?)',
"g"
);
/*
var ImpactImpostor = function() {
this.className = "";
this.extensions = [];
this.self = this;
};
ImpactImpostor.prototype.C = function(className) {
if(typeof className !== 'string')
throw new Error("Class is not defined as an string");
this.className = className;
return this.self; // HACK
};
ImpactImpostor.prototype.D = function() {
for (var i = 0; i < arguments.length; i++) {
if(typeof arguments[i] !== 'string')
throw new Error("Extension is not defined as an string!");
this.extensions.push(arguments[i]);
}
};
function evalInContext(js, context) {
return function() { return eval(js); }.call(context);
}
function evaluateClassDef(line) {
'use strict';
var impact = new ImpactImpostor();
var context = {
ig: impact
};
var result = evalInContext(line, context);
return {className: impact.class, extensions: impact.extensions};
}
*/
Object.size = function(obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
if (!Array.prototype.first)
{
Array.prototype.first = function(predicate)
{
"use strict";
if (this === null)
throw new TypeError();
if (typeof predicate != "function")
throw new TypeError();
for (var i = 0; i < this.length; i++) {
if (predicate(this[i])) {
return match;
}
}
return null;
};
}
function escapeRegExp(string) {
return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
String.prototype.replaceAll = function(find, replace) {
return this.replace(new RegExp(escapeRegExp(find), 'g'), replace);
};
process.stderr.write('Reading javascript...');
// Read compiled game
fs.readFile('game.compiled.js', 'utf8', function (err, rawData) {
if (err) {
throw err;
}
process.stderr.write('processing');
var data = rawData.replaceAll('\n',' ');
var i = 0;
//var truths = 0;
//var empty = 0;
//var non_empty = 0;
var bad = false;
var fZoneChar;
var fZone;
var fBody = '';
var EMPTY_FUNC = '(' + MODULE_EMPTY + '())';
var FUNC = '(function(){';
var time = process.hrtime();
var ext;
while ((match = regex.exec(data)) !== null) {
fBody = '';
fZoneChar = match.index + match[0].length + 2;
fZone = data.charAt(fZoneChar);
if(data.substring(fZoneChar, fZoneChar+5) == EMPTY_FUNC) {
//empty++;
} else if(data.substring(fZoneChar, fZoneChar+12) == FUNC) {
//non_empty++;
var pos = fZoneChar+12;
var done = false;
var braceAcc = 0;
var char;
i = 0;
while(!done) {
char = data.charAt(pos+i);
if(char == '}') {
if(braceAcc === 0) {
done = true;
}
else braceAcc--;
}
if(char == '{') braceAcc++;
if(!done) fBody += char;
//process.stderr.cursorTo(0);
//process.stderr.write(i.toString());
i++;
}
//process.stderr.write('\n');
} else {
console.error(
"Unknown function found: " +
data.substring(
fZoneChar - match[0].length - 2, fZoneChar+100
)
);
bad = true;
}
if(match[4])
ext = match[4].replaceAll('"','').replaceAll(" ", "").split(',');
else ext = [];
matches[matchesAcc] = {
moduleName: match[2],
extensions: ext,
body: (fBody === '' ? null : fBody)
};
if(bad) {
console.error(matches[matchesAcc]);
}
bad = false;
matchesAcc++;
process.stderr.write('.');
//fZone == '(' ? truths++ : console.error(fZone);
}
//console.error(empty + non_empty);
var diff = process.hrtime(time);
console.error('done!');
console.error(
'Found and parsed ' + matchesAcc + ' modules in ' +
(diff[1] / 1000000) + ' ms'
);
if(ONLY_PARSE) {
console.log(JSON.stringify(matches));
process.exit(0);
}
process.stderr.write("Processing function bodies (SEMI-STUB)");
var body;
var ast;
var html = "<!DOCTYPE html><html><body>";
for (i = 0; i < matches.length; i++) {
body = matches[i].body;
if(!body) continue;
try {
ast = acorn.parse(body);
} catch(e) {
console.error("\n");
console.error(body);
console.error("");
console.error("");
throw e;
}
process.stdout.write(JSON.stringify(ast));
process.stdout.write("\n\n");
process.stderr.write(".");
}
html += "</body></html>";
console.error("done!");
if (ONLY_AST) process.exit(0);
console.error("Computing graph...");
var posAcc = 0;
var extAcc = 0;
var edgAcc = 0;
var idAcc = 0;
var elements = {
nodes: [],
edges: []
};
/*
var sortedMatches = matches.sort(function(a,b) {
if(a.extensions.length === 0 && b.extensions.length === 0) {
return 0; // Both have no extensions
}
if(a.extensions.length === 0) {
return -1; // A has no extensions
}
if(b.extensions.length === 0) {
return 1; // B has no extensions
}
return 0; // Both have extensions
});
*/
// Add fake DOM ready node
elements.nodes[0] = {
group: "nodes",
data: {
id: "dom.ready",
name: "dom.ready",
moduleName: "dom.ready",
extensions: []
},
position: { x: posAcc, y: 0 },
};
posAcc++;
for (i = 0; i < matches.length; i++) {
process.stderr.cursorTo(0);
process.stderr.write("Adding nodes: " + (i+1));
elements.nodes[i+1] = {
group: "nodes",
data: {
id: matches[i].moduleName,
name: matches[i].moduleName,
moduleName: matches[i].moduleName,
extensions: matches[i].extensions,
},
position: { x: posAcc, y: 0 },
};
posAcc++;
}
process.stderr.write(" done!\n");
var matchesProcessed = [];
var matchExts;
var extsMatch;
var extsInitialized = true;
var matchIndex = 0;
for (i = 0; i < matches.length; i++) {
process.stderr.cursorTo(0);
process.stderr.write("Adding edges: " + (i+1));
matchExts = matches[i].extensions;
if (matchExts.length === 0) {
matchesProcessed.push(matches[i]);
continue;
} else {
for (var j = 0; j < matchExts.length; j++) {
elements.edges.push({
data: {
id: ('e'+edgAcc),
source: matches[i].moduleName,
target: matchExts[j]
}
});
edgAcc++;
}
matchesProcessed.push(matches[i]);
continue;
}
}
process.stderr.write(" done!\n");
process.stderr.write("Loading cytoscape...");
cytoscape({
elements: elements,
ready: function(){
cy = this;
process.stderr.write('loaded...');
graph(cy);
}
});
function end() {
for (i = 0; i < matches.length; i++) {
var exts = matches[i].extensions;
console.log(
'Class ' +
matches[i].moduleName +
' Extends ' +
(exts.length === 0 ? 'None' : exts.join(' '))
);
}
}
});
function graph(cy) {
process.stderr.write("doing layout...");
cy.layout({ name: 'circle' });
var json = cy.json().elements;
console.error("done!");
console.log(JSON.stringify(json)+"\n\n");
//end();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment