amend-bundle
Version:
Bundle all code from an amend container to one file
157 lines (139 loc) • 4.28 kB
JavaScript
require('node-jsx').install({extension: '.jsx'})
var amend = require('amend');
var babel = require('babel')
var uglify = require('uglify-js')
var fs = require('fs')
var getConfigPaths = amend.getConfigPaths;
var evaluateType = amend.evaluateType;
var readFile = require('./read-file');
var R = require('ramda')
var RF = require('ramda-fantasy')
var Future = RF.Future
var wrap = require('./wrap')
var ject = require('ject')
var dependencyTemplate = "di.{{type}}('{{key}}', require('{{registeredPath}}'))\n"
var moduleTemplate = "di.{{type}}('{{key}}', {{code}})\n"
var codeLens = R.lensProp('code')
var stripExports = R.map(R.replace(/^module.exports = /, ''), codeLens)
var callback
/*
* 1 Get paths
* 2 Filter out config files
* 3 ForEach: require, evaluateType, return Future of object with path, type, code
* 4 Transform code, inject in di, babel, uglify
* 5 commute
* 6 wrap in wrapper
*
* Listen:
* perform step 4 for that specific file
* replace cached future with new one
* step 5 and 6
*
*/
function fetchModule(mod) {
var out;
var future = Future.cache(readFile(mod.path)
.map(function(code) {
return R.assoc('code', code, out);
}).map(processModuleCode))
return out = R.assoc('future', future, mod);
}
function includeDependency (mod) {
var code = ject(dependencyTemplate, mod)
var outModule = R.assoc('code', code, mod)
var future = Future.of(outModule)
.map(function (a) {
return R.assoc('future', future, a)
})
return R.assoc('future', future, outModule)
}
function logError(e) {
console.error(e);
console.error(e.stack);
console.error(e.stack);
}
var rejectConfigs = R.reject(R.prop('isConfig'));
var filterLocals = R.filter(R.prop('isLocal'))
var noLocals = R.reject(R.prop('isLocal'))
var resolvePath = function(mod) {
return R.assoc('path', require.resolve(mod.path), mod);
}
function doEvaluateType (mod) {
var type = evaluateType(mod.module, require(mod.path))
return R.assoc('type', type, mod)
}
var transduceFn = R.compose(rejectConfigs, R.map(doEvaluateType), R.map(resolvePath))
var findIndexByPath = R.useWith(R.findIndex, R.propEq('path'));
var futures;
function listenForFilechange(path) {
var opts = { interval: 200 };
fs.watchFile(path, opts, function() {
var i = findIndexByPath(path, futures);
var incorrect = R.filter(R.compose(R.isNil, R.prop('future')), futures)
futures = R.adjust(fetchModule, i, futures);
callback(createOutputFuture(futures))
})
}
function watchModule(mod) {
listenForFilechange(mod.path);
}
var processModules = R.compose(
//R.map(R.tap(watchModule)),
R.map(R.ifElse(R.prop('isLocal'), fetchModule, includeDependency))
)
function isJSON (fileName) {
return filename.endsWith('.json')
}
function doBabel(mod) {
try {
if (isJSON(mod.path)) {
return mod
}
var transformed = babel.transform(mod.code, { blacklist: [ 'strict' ]}).code
var exportIndex = R.indexOf('module.exports', transformed)
var trimmed = R.drop(exportIndex, transformed)
return R.assoc('code', trimmed, mod)
} catch (e) {
throw new Error('Babel error in module ' + mod.path)
}
}
function doUglify(mod) {
try {
var result = uglify.minify(mod.code, { fromString: true, mangle: false });
return R.assoc('code', result.code, mod);
} catch (e) {
e.filename = mod.path
throw e
}
}
function removeExports (mod) {
var stripped = stripExports(mod)
var result = ject(moduleTemplate, stripped)
return R.assoc('code', result, mod)
}
function removeLastSemi (code) {
return R.replace(/;$/, '', code)
}
var processModuleCode = R.compose(
// doUglify,
removeExports,
R.map(removeLastSemi, codeLens),
doBabel
)
function createOutputFuture(modules) {
return R.commute(Future.of, R.pluck('future', modules))
.map(R.tap(function(list) {
futures = list;
}))
.map(R.pluck('code'))
.map(R.reduce(R.concat, ''))
.map(wrap)
}
module.exports = function bundle(opts, config, cb) {
callback = cb
var modules = getConfigPaths(opts.baseDir, config);
modules = R.transduce(transduceFn, R.flip(R.append), [], modules);
modules = processModules(modules)
var incorrect = R.filter(R.compose(R.isNil, R.prop('future')), modules)
cb(createOutputFuture(modules))
}