Skip to content

Instantly share code, notes, and snippets.

@rasteiner
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rasteiner/74252a76efde931f7325 to your computer and use it in GitHub Desktop.
Save rasteiner/74252a76efde931f7325 to your computer and use it in GitHub Desktop.
transform Three.js sourcecode tu use relative path require() statements
var glob = require('glob');
var mkdirp = require('mkdirp');
var falafel = require('falafel');
var fs = require('fs');
var colors = require('colors');
var Q = require('q');
var path = require('path');
function searchDefs(src) {
var defs = [];
falafel(src, function(node) {
if(node.type == 'Identifier')
if(node.parent.type == 'MemberExpression')
if(node.parent.object.name == 'THREE' && node.parent.object !== node)
if(node.parent.parent.type == 'AssignmentExpression')
if(node.parent.parent.left.object && node.parent.parent.left.object.name == 'THREE')
if(!defs.contains(node.name)) {
defs.push(node.name);
}
});
return defs;
}
function containsDeclaration(scope, node) {
var i, j, n;
for(i = 0; i < scope.body.body.length; i++) {
n = scope.body.body[i];
if(n.type == 'VariableDeclaration' && n.kind == 'var') {
for(j = 0; j < n.declarations.length; j++) {
if(n.declarations[j].id && n.declarations[j].id.name && n.declarations[j].id.name == node.name) {
return true;
}
}
}
}
return false;
}
function searchStringAssignments(body, node) {
var i, j, n;
var values = [];
for(i = 0; i < body.length; i++) {
n = body[i];
if(n.type == 'VariableDeclaration' && n.kind == 'var') {
for(j = 0; j < n.declarations.length; j++) {
if(n.declarations[j].id && n.declarations[j].id.name) {
if(n.declarations[j].id.name == node.name && n.declarations[j].init && n.declarations[j].init.type == 'Literal'){
values.push(n.declarations[j].init.value);
}
}
}
} else if(n.type == 'IfStatement') {
if(n.consequent.type == 'BlockStatement') {
values = values.concat(searchStringAssignments(n.consequent.body, node));
} else if(n.consequent.type == 'ExpressionStatement' && n.consequent.expression.type == 'AssignmentExpression') {
if(n.consequent.expression.left.name == node.name && n.consequent.expression.right.type == 'Literal') {
values.push(n.consequent.expression.right.value);
}
}
if(n.alternate) {
if(n.alternate.type == 'BlockStatement') {
values = values.concat(searchStringAssignments(n.alternate.body, node));
} else if(n.alternate.type == 'ExpressionStatement' && n.alternate.expression.type == 'AssignmentExpression') {
if(n.alternate.expression.left.name == node.name && n.alternate.expression.right.type == 'Literal') {
values.push(n.alternate.expression.right.value);
}
}
}
}
}
return values;
}
function searchPossibleValues(node) {
var scope = node;
//searchScope
while(scope = scope.parent) {
if(scope.type == 'FunctionExpression' || scope.type == 'Program') {
//is it defined here?
if(containsDeclaration(scope, node)) {
break;
}
}
}
return searchStringAssignments(scope.body.body, node);
}
function searchReqs(src) {
var reqs = [];
falafel(src, function(node) {
if(node.parent && node.parent.object && node.parent.property)
if(node.parent.object.name == 'THREE' && node.parent.object !== node)
if(node.parent.property.name) {
if(node.parent.computed) {
reqs = reqs.concat(searchPossibleValues(node.parent.property));
} else {
if(!reqs.contains(node.parent.property.name)) {
reqs.push(node.parent.property.name);
}
}
}
});
return reqs;
}
function injectReqs(defs, reqs) {
var k, i;
var index = {};
var from, to, rel;
var injects = {}, code;
defs['src/Three.js'].push('REVISION');
for(k in defs) {
for(i = 0; i < defs[k].length; i++) {
index[defs[k][i]] = k;
}
}
for(k in reqs) {
from = k;
to = [];
for(i = 0; i < reqs[k].length; i++) {
if(index[reqs[k][i]]) {
if(!to.contains(index[reqs[k][i]])) {
to.push(index[reqs[k][i]]);
}
} else {
console.error(('Definition of ' + reqs[k][i] + ' not found.').red + ' Referenced in ' + k.green);
}
}
rel = path.relative(path.dirname(from), 'src/Three.js');
if(rel[0] !== '.') {
rel = './' + rel;
}
code = 'var THREE = require(\'' + rel + '\');\n';
for(i = 0; i < to.length; i++) {
if(from == to[i]) continue; //don't need to require itself
if(to[i] == 'src/Three.js')continue; //three.js get's handled separately
rel = path.relative(path.dirname(from), to[i]);
if(rel[0] !== '.') {
rel = './' + rel;
}
code += 'require(\'' + rel + '\');\n';
}
if(from == 'src/Three.js') {
code = '';
} else {
code += '\n\n';
}
injects[from] = code;
}
return injects;
}
glob("src/**/*.js", function(er, files) {
var searches = [];
var defs = {};
var reqs = {};
files.forEach(function(filename) {
searches.push(Q.Promise(function(resolve) {
fs.readFile(filename, {encoding: 'utf8'}, function(er, src) {
defs[filename] = searchDefs(src);
reqs[filename] = searchReqs(src);
resolve();
});
}));
});
Q.all(searches).then(function() {
var injects = injectReqs(defs, reqs);
var k, rel, post;
for(k in injects) {
rel = 'commonjs/' + path.relative('src', k);
mkdirp.sync(path.dirname(rel));
fs.writeFileSync(rel, injects[k] + fs.readFileSync(k, {encoding: 'utf8'}), {encoding: 'utf8'});
}
});
});
// Array.prototype.contains()
// Reference : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/contains#Polyfill
if (![].contains) {
Object.defineProperty(Array.prototype, 'contains', {
enumerable: false,
configurable: true,
writable: true,
value: function (searchElement/*, fromIndex*/) {
if (this === undefined || this === null) {
throw new TypeError('Cannot convert this value to object');
}
var O = Object(this);
var len = parseInt(O.length) || 0;
if (len === 0) { return false; }
var n = parseInt(arguments[1]) || 0;
if (n >= len) { return false; }
var k;
if (n >= 0) {
k = n;
} else {
k = len + n;
if (k < 0) k = 0;
}
while (k < len) {
var currentElement = O[k];
if (searchElement === currentElement ||
searchElement !== searchElement && currentElement !== currentElement
) {
return true;
}
k++;
}
return false;
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment