denodify
Version:
Use nodejs modules in the browser. Used with bb-server and html-builder
178 lines (150 loc) • 5.63 kB
JavaScript
var Path = require('path');
var required = require('./required');
var fs = require('fs-extra');
require('colors');
var debugMode;
var crypto = require('crypto');
var modules;
var index;
//same id, same file, different requirers
//same id, different file, different requirers
//same id, same file, same requirer //all the time
//different id, different file, different requirers //all the time
//different id, different file, same requirer //all the time
//different id, same file, different requirers //possible but rare
//different id, same file, same requirer //rare but possible
//same id, different file, same requirer //not possible
function pushSet(arr, el) {
arr = arr || [];
if (arr.indexOf(el) === -1) arr.push(el);
return arr;
}
function reset() {
modules = [];
index = 0;
}
function getList(module) {
//TODO!! modules has to be emptied for every build run of demodularify TODO!!!!
//TODO!! node_modules_index has to be zerod for every build run of demodularify TODO!!!!
var path = [];
function walk(module) {
if (module.core) {
//the id does -NOT- start with '.', '..' or '/'
//so doesn't clash with any relative require ids
//these will have to be supplied by the server!!
modules[module.id] = module;
return;
}
if (module.walked) return;
modules[module.filename] = module;
path.push(module.id);
module.walked = true;
module.index = -1;
module.deps.forEach(function(d) {
var dep_id = d.id;
d = modules[d.filename] || d;
d.requirers = pushSet(d.requirers, module.filename);
d.ids = pushSet(d.ids, dep_id);
walk(d);
if (d.index < 0) {
var str = "Module " + module.id + " is dependent on module " + d.id +
'. However, module ' + d.id + ' is also directly or indirectly dependent on module ' +
module.id + ".\nDependency path to this point: \n" + path.join(' relies on \n') +
' relies on ' + d.id;
console.log(str.red);
}
});
module.index = index++;
path.pop();
}
walk(module);
return modules;
}
function endsWith(str, trail) {
return (str.substr(str.length-trail.length, str.length-1) === trail);
};
function trailWith(str, trail) {
return str ? (str + (!endsWith(str, trail) ? trail : '')) : undefined;
};
function resolve(www, parent, id, cb, tags, isDebug) {
// console.log('-------------------', www, parent);
debugMode = isDebug;
try
{ www = Path.resolve(www);
parent = Path.resolve(www, parent);
console.log('Resolving: ' + id + ' in directory ' + parent);
var fileName = Path.resolve(parent, trailWith(id, '.js'));
try {
fs.statSync(fileName);
} catch(e) { cb(e,null);
return;}
required(fileName, {
includeSource: false,
ignoreMissing: function(name, parent) {
var out = name + ' in ' + parent;
console.log('Missing module:'.red.bold, out.yellow);
}
// resolve: ..
}, function(err, deps) {
if (err) {
cb(err, null);
// throw err;
}
else {
var modules = getList(
{ id: id,
filename: fileName,
deps: deps,
index: -1
}
);
var list = Object.keys(modules).map(function(m) {
m = modules[m];
if (m.core) {
m.route = '/_core_modules/' + m.id;
}
else {
var startWithWwwPath = m.filename.indexOf(www) === 0;
if (!startWithWwwPath) {
var hash = crypto.createHash('md5').update(m.filename).digest('hex');
m.route = '/_node_modules/' + hash + '_' + Path.basename(m.filename);
m.lib = true;
// m.route = m.filename;
//TODO set softlinks to filename in www/node_modules dir
//possibly do deduplication?
// console.log( 'Warning: ' + m.id + ' was found outside the www directory (' + www + ')');
}
else m.route = m.filename.slice(www.length);
m.deps = m.deps.map(function(d) { return d.id; });
}
// debug('module:',m);
delete m.id;
return m;
}).sort(function(a, b) {
return a.index > b.index;
}).map(function(m) {
return !tags ?
m :
// { id: m.id, route: m.route, filename: m.filename } :
"<script type=\"text/javascript\" src=\"" + m.route + "\"></script>";
});
// debug('Debug:\n', list);
cb(null, list);
}
});
} catch(e) {
cb(e, null);
}
};
function debug() {
if (debugMode) console.log.apply(console, arguments);
}
module.exports = {
resolve: resolve,
reset: reset
};
// console.log(exports.script.toString());
// list('../', './test', './m3', function(err, tags) {
// console.log();
// console.log(tags);
// }, true);