Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

assembot

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

assembot - npm Package Compare versions

Comparing version
0.1.6
to
0.2.0
bin/assembot-build

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

+44
// Generated by CoffeeScript 1.6.1
(function() {
var Assembler, assembler, defaults, packager, path, _;
_ = require('./util');
path = require('path');
defaults = require('./defaults');
packager = require('./packager');
Assembler = (function() {
function Assembler(target) {
this.target = target;
}
Assembler.prototype["package"] = function(resources, options, callback) {
var _ref;
_ref = _.validateOptionsCallback(options, callback), options = _ref[0], callback = _ref[1];
if (_.type(resources) !== 'array') {
resources = resources.forTarget(this.target);
}
packager.build(this.target, resources, options, callback);
return this;
};
return Assembler;
})();
assembler = function(target, resources, options, callback) {
var asm;
asm = new Assembler(target);
return asm["package"](resources, options, callback);
};
module.exports = {
Assembler: Assembler,
assembler: assembler
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var Bot, assembler, bot, defaults, echo, fs, log, notify, packager, path, processor, resourcelist, _,
_this = this;
_ = require('./util');
fs = require('fs');
path = require('path');
defaults = require('./defaults');
log = require('./log');
packager = require('./packager');
processor = require('./processor');
notify = require('./notify');
echo = require('shelljs').echo;
assembler = require('./assembler').assembler;
resourcelist = require('./resources').resourcelist;
Bot = (function() {
Bot.vent = notify;
Bot.on = function(event, listener) {
return notify.on(event, listener);
};
Bot.before = function(event, listener) {
return notify.on("before:" + event, listener);
};
Bot.after = function(event, listener) {
return notify.on("after:" + event, listener);
};
function Bot(output, options) {
var _this = this;
if (options == null) {
options = {};
}
this.didAssemble = function(err, content) {
_this.content = content;
return Bot.prototype.didAssemble.apply(_this, arguments);
};
this.didRender = function(err) {
return Bot.prototype.didRender.apply(_this, arguments);
};
if (output != null) {
options.output = output;
}
this.options = {};
this.config(options);
this.built = false;
this.returnContent = null;
this.userCallbackForCompletion = null;
notify.createBot(this);
}
Bot.prototype.config = function(options) {
if (options == null) {
options = {};
}
this.options = _.defaults(options, this.options, defaults.options);
this.output = path.resolve(this.options.output);
this.source = path.resolve(this.options.source);
this.target = processor.targetOf(this.output);
return this;
};
Bot.prototype.build = function(callback) {
this.returnContent = callback != null ? callback : null;
notify.beforeBuild(this);
notify.beforeScan(this);
this.resources = resourcelist(this.source).forTarget(this.target);
notify.afterScan(this);
notify.beforeRender(this);
processor.render(this.resources, this.options, this.didRender);
return this;
};
Bot.prototype.then = function(callback) {
this.userCallbackForCompletion = callback;
if (this.built) {
if (typeof this.userCallbackForCompletion === "function") {
this.userCallbackForCompletion();
}
}
return this;
};
Bot.prototype.didRender = function(err) {
if (err != null) {
throw err;
}
notify.afterRender(this);
notify.beforeAssemble(this);
return assembler(this.target, this.resources, this.options, this.didAssemble);
};
Bot.prototype.didAssemble = function(err, content) {
this.content = content;
if (err != null) {
throw err;
}
notify.afterAssemble(this);
return this.writeContent();
};
Bot.prototype.writeContent = function() {
notify.afterBuild(this);
notify.beforeWrite(this);
if (this.returnContent != null) {
log.info("Returning content to callback", this.output);
this.returnContent(this.content);
return typeof this.userCallbackForCompletion === "function" ? this.userCallbackForCompletion() : void 0;
} else {
log.info("Writing", this.output);
this.content.to(this.output);
notify.afterWrite(this);
this.built = true;
return typeof this.userCallbackForCompletion === "function" ? this.userCallbackForCompletion() : void 0;
}
};
Bot.prototype.rebuild = Bot.prototype.build;
return Bot;
})();
bot = function(output, options) {
return new Bot(output, options);
};
module.exports = {
Bot: Bot,
bot: bot
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
module.exports = {
options: {
header: "/* Assembled by AssemBot {%- assembot.version -%} */",
addHeader: true,
minify: 0,
ident: 'require',
autoLoad: null,
replaceTokens: true,
plugins: [],
coffee: {
bare: true
},
http: {
port: 8080,
paths: {
'/': './public',
'/components': './components'
}
}
},
targets: {
"public/app.js": {
source: './source'
},
"public/app.css": {
source: './source'
}
}
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var Bot, assembler, assembot, defaults, loadFirstLocalPackage, loadOptions, loadTargets, loaded_from, log, packager, path, plugins, processor, project_root, resourcelist, _,
__slice = [].slice;
log = require('./log');
defaults = require('./defaults');
_ = require('./util');
path = require('path');
packager = require('./packager');
plugins = require('./plugins');
processor = require('./processor');
project_root = process.cwd();
resourcelist = require('./resources').resourcelist;
assembler = require('./assembler').assembler;
Bot = require('./bot').Bot;
loaded_from = null;
loadFirstLocalPackage = function() {
var data, name, names, _i, _len;
names = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
for (_i = 0, _len = names.length; _i < _len; _i++) {
name = names[_i];
try {
data = require("" + project_root + path.sep + name);
if (data.assembot != null) {
log.debug("Loaded " + name + ".json");
loaded_from = name;
return data.assembot;
} else {
throw new Error("No Assembot block");
}
} catch (ex) {
log.debug("No '" + name + ".json' file found!");
}
}
log.debug("No configuration found, using defaults!");
loaded_from = 'defaults';
return defaults;
};
loadTargets = function() {
var nfo, options, opts, src_targets, targets, tgt, tgt_opts, _ref, _ref1;
nfo = loadFirstLocalPackage('package', 'component', 'build', 'assembot');
options = (_ref = nfo.options) != null ? _ref : defaults.options;
src_targets = (_ref1 = nfo.targets) != null ? _ref1 : defaults.targets;
targets = {};
for (tgt in src_targets) {
opts = src_targets[tgt];
tgt_opts = _.defaults({}, opts, options, defaults.options);
targets[tgt] = tgt_opts;
}
return targets;
};
loadOptions = function(returnDefaults) {
var nfo, _ref;
nfo = loadFirstLocalPackage('package', 'component', 'build', 'assembot');
if (returnDefaults === false) {
if (nfo === defaults) {
return null;
} else {
return loaded_from;
}
} else {
return (_ref = nfo.options) != null ? _ref : defaults.options;
}
};
assembot = function(target, options) {
if (options == null) {
options = {};
}
plugins.init(options, './plugins/header', './plugins/minify', './plugins/settee-templates');
return new Bot(target, options);
};
module.exports = {
assembot: assembot,
defaults: defaults,
assembler: assembler,
resourcelist: resourcelist,
loadTargets: loadTargets,
packager: packager,
processor: processor,
loadOptions: loadOptions,
loadFirstLocalPackage: loadFirstLocalPackage,
_: _
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var debug, error, info, level, log_level, say, trace;
log_level = 1;
level = function(lvl) {
if (lvl != null) {
log_level = lvl;
}
return log_level;
};
say = function() {
return console.log.apply(console, arguments);
};
info = function() {
if (log_level < 1) {
return;
}
return console.log.apply(console, arguments);
};
debug = function() {
if (log_level < 2) {
return;
}
return console.log.apply(console, arguments);
};
trace = function() {
if (log_level < 3) {
return;
}
return console.log.apply(console, arguments);
};
error = function() {
var lines, newError;
newError = new Error;
if (newError.stack != null) {
lines = newError.stack.split("\n");
console.log("Error", lines[2].trim());
}
return console.log.apply(console, arguments);
};
module.exports = {
level: level,
info: info,
debug: debug,
error: error,
trace: trace,
say: say
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var EventEmitter, Notify, log, notifications,
__slice = [].slice;
log = require('./log');
EventEmitter = require('events').EventEmitter;
Notify = (function() {
function Notify() {
this.vent = new EventEmitter;
}
Notify.prototype.on = function(event, listener) {
return this.vent.on(event, listener);
};
Notify.prototype.emit = function() {
var args, _ref;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return (_ref = this.vent).emit.apply(_ref, args);
};
Notify.prototype.createBot = function(bot) {
return this.vent.emit('create:bot', bot);
};
Notify.prototype.beforeBuild = function(bot) {
return this.vent.emit('before:build', bot);
};
Notify.prototype.beforeScan = function(bot) {
return this.vent.emit('before:scan', bot);
};
Notify.prototype.afterScan = function(bot) {
return this.vent.emit('after:scan', bot);
};
Notify.prototype.beforeRender = function(bot) {
return this.vent.emit('before:render', bot);
};
Notify.prototype.beforeRenderItem = function(resource) {
return this.vent.emit('before:renderItem', resource);
};
Notify.prototype.afterRenderItem = function(resource) {
return this.vent.emit('after:renderItem', resource);
};
Notify.prototype.afterRender = function(bot) {
return this.vent.emit('after:render', bot);
};
Notify.prototype.beforeAssemble = function(bot) {
return this.vent.emit('before:assemble', bot);
};
Notify.prototype.afterAssemble = function(bot) {
return this.vent.emit('after:assemble', bot);
};
Notify.prototype.afterBuild = function(bot) {
return this.vent.emit('after:build', bot);
};
Notify.prototype.beforeWrite = function(bot) {
return this.vent.emit('before:write', bot);
};
Notify.prototype.afterWrite = function(bot) {
return this.vent.emit('after:write', bot);
};
Notify.prototype.createServer = function(server, opts) {
return this.vent.emit('create:server', server, opts);
};
Notify.prototype.startServer = function(server, opts) {
return this.vent.emit('start:server', server, opts);
};
return Notify;
})();
notifications = new Notify;
module.exports = notifications;
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var addPackager, build, ecss_wrapper, packagers;
build = function(target, resources, options, done) {
var packager;
packager = packagers[target];
if (packager == null) {
return done(new Error("Unknown package target '" + target + "'"));
}
return packager(resources, options, done);
};
packagers = {};
addPackager = function(target, packager) {
return packagers[target] = packager;
};
module.exports = {
build: build,
addPackager: addPackager
};
addPackager('css', function(resources, options, done) {
var res, results, _i, _len;
results = "";
for (_i = 0, _len = resources.length; _i < _len; _i++) {
res = resources[_i];
results += "/* " + res.path + " */\n";
results += res.content;
results += "\n\n";
}
return done(null, results);
});
ecss_wrapper = function(css) {
return "var node = null, css = " + (JSON.stringify(css)) + ";\nmodule.exports= {\n content: css,\n isActive: function(){ return node != null; },\n activate: function(to){\n if(node != null) return; // Already added to DOM!\n to= to || document.getElementsByTagName('HEAD')[0] || document.body || document; // In the HEAD or BODY tags\n node= document.createElement('style');\n node.innerHTML= css;\n to.appendChild(node);\n return this;\n },\n deactivate: function() {\n if(node != null) {\n node.parentNode.removeChild(node);\n node = null;\n }\n return this;\n }\n};";
};
module.exports.embedded_css = ecss_wrapper;
addPackager('js', function(resources, options, callback) {
var autoStart, i, identifier, res, result, _i, _len, _ref, _ref1;
identifier = (_ref = options.ident) != null ? _ref : 'require';
autoStart = (_ref1 = options.autoStart) != null ? _ref1 : false;
result = "(function(/*! Stitched by Assembot !*/) {\n /* \n The commonjs code below was based on @sstephenson's stitch.\n https://github.com/sstephenson/stitch\n */\n if (!this." + identifier + ") {\n var modules = {}, cache = {}, moduleList= function(startingWith) {\n var names= [], startingWith= startingWith || '';\n for( var name in modules ) {\n if(name.indexOf(startingWith) === 0) names.push(name);\n }\n return names;\n }, require = function(name, root) {\n var path = expand(root, name), module = cache[path], fn;\n if (module) {\n return module.exports;\n } else if (fn = modules[path] || modules[path = expand(path, './index')]) {\n module = {id: path, exports: {}};\n try {\n cache[path] = module;\n var localRequire= function(name) {\n return require(name, dirname(path));\n }\n localRequire.modules= moduleList;\n fn(module.exports, localRequire, module);\n return module.exports;\n } catch (err) {\n delete cache[path];\n throw err;\n }\n } else {\n throw 'module \\'' + name + '\\' not found';\n }\n }, expand = function(root, name) {\n var results = [], parts, part;\n if (/^\\.\\.?(\\/|$)/.test(name)) {\n parts = [root, name].join('/').split('/');\n } else {\n parts = name.split('/');\n }\n for (var i = 0, length = parts.length; i < length; i++) {\n part = parts[i];\n if (part == '..') {\n results.pop();\n } else if (part != '.' && part != '') {\n results.push(part);\n }\n }\n return results.join('/');\n }, dirname = function(path) {\n return path.split('/').slice(0, -1).join('/');\n };\n this." + identifier + " = function(name) {\n return require(name, '');\n }\n this." + identifier + ".define = function(bundle) {\n for (var key in bundle)\n modules[key] = bundle[key];\n };\n this." + identifier + ".modules= moduleList;\n }\n return this." + identifier + ".define;\n}).call(this)({\n";
for (i = _i = 0, _len = resources.length; _i < _len; i = ++_i) {
res = resources[i];
result += i === 0 ? "" : ",\n";
result += JSON.stringify(res.path);
result += ": function(exports, require, module) {\n" + res.content + "\n}";
}
result += "});\n";
if (autoStart) {
result += "" + identifier + "('" + autoStart + "');\n";
}
return callback(null, result);
});
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var Bot, Processor, ProcessorManager, Resource, ResourceList, addPackager, addProcessor, after, before, context, defaults, extend, init, initialized, load, loadPlugin, log, notify, processor, render, replaceTokens, shelljs, targetOf, transpile, tryRequire, tryRequireAll, tryRequireResolve, type, validTarget, _, _ref, _ref1, _ref2,
__slice = [].slice;
log = require('./log');
notify = require('./notify');
shelljs = require('shelljs');
Bot = require('./bot').Bot;
addPackager = require('./packager').addPackager;
_ref = require('./resources'), ResourceList = _ref.ResourceList, Resource = _ref.Resource;
_ref1 = _ = require('./util'), extend = _ref1.extend, defaults = _ref1.defaults, type = _ref1.type, tryRequire = _ref1.tryRequire, tryRequireAll = _ref1.tryRequireAll, tryRequireResolve = _ref1.tryRequireResolve;
_ref2 = processor = require('./processor'), targetOf = _ref2.targetOf, validTarget = _ref2.validTarget, render = _ref2.render, transpile = _ref2.transpile, replaceTokens = _ref2.replaceTokens, addProcessor = _ref2.addProcessor, Processor = _ref2.Processor, ProcessorManager = _ref2.ProcessorManager;
before = Bot.before, after = Bot.after;
loadPlugin = load;
context = {
before: before,
after: after,
log: log,
extend: extend,
defaults: defaults,
processor: processor,
addProcessor: addProcessor,
addPackager: addPackager,
type: type,
tryRequire: tryRequire,
tryRequireAll: tryRequireAll,
tryRequireResolve: tryRequireResolve,
loadPlugin: loadPlugin,
shelljs: shelljs,
Bot: Bot,
Resource: Resource,
ResourceList: ResourceList,
Processor: Processor,
ProcessorManager: ProcessorManager
};
context.on = Bot.on;
initialized = false;
init = function() {
var options, plugin, preload, _i, _len;
options = arguments[0], preload = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
if (initialized) {
return false;
}
if ((options.plugins != null) && type(options.plugins) === 'array') {
preload = preload.concat(options.plugins);
}
for (_i = 0, _len = preload.length; _i < _len; _i++) {
plugin = preload[_i];
load(plugin);
}
initialized = true;
return false;
};
load = function(name) {
return tryRequire(name, function(err, lib) {
if (err != null) {
return log.error("Failure to load plugin " + name, err);
}
lib.call(context, context);
return notify.emit('plugin:loaded', name, lib);
});
};
module.exports = {
init: init,
load: load,
context: context
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
module.exports = function(assembot) {
var log, processor;
processor = assembot.processor, log = assembot.log;
return assembot.before('write', function(bot) {
var header, output;
if (!((bot.options.header != null) && bot.options.addHeader)) {
return;
}
switch (bot.target) {
case 'js':
case 'css':
log.debug("Adding header...");
header = processor.replaceTokens(bot.options.header, {});
log.trace(header);
output = "" + header + "\n" + bot.content;
return bot.content = output;
}
});
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var do_minify, uglify;
uglify = (function() {
try {
return require("uglify-js");
} catch (ex) {
return null;
}
})();
do_minify = function(flag, output_content, log) {
var settings;
if (uglify != null) {
log.debug("Minify...");
try {
settings = {
fromString: true,
mangle: false
};
switch (flag) {
case 1:
case 'minify':
case 'min':
return uglify.minify(output_content, settings);
case 2:
case 'mangle':
case 'munge':
case 'compress':
settings.mangle = true;
return uglify.minify(output_content, settings);
default:
return {
code: output_content,
map: null
};
}
} catch (ex) {
log.info("Error in minify, skipping...");
log.error(ex);
return {
code: output_content,
map: null
};
}
} else {
log.info("Can't minify (install uglify-js)...");
return {
code: output_content,
map: null
};
}
};
module.exports = function(assembot) {
var log;
log = assembot.log;
return assembot.after('build', function(bot) {
if (bot.target !== 'js') {
return;
}
if ((bot.options.minify != null) && bot.options.minify !== false && bot.options.minify > 0) {
return bot.content = do_minify(bot.options.minify, bot.content, log).code;
}
});
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var path, plugin;
path = require('path');
plugin = function(assembot) {
var Resource, cat, log, runtime_path, settee_was_used, shelljs, test, tryRequireResolve;
Resource = assembot.Resource, tryRequireResolve = assembot.tryRequireResolve, log = assembot.log, shelljs = assembot.shelljs;
cat = shelljs.cat, test = shelljs.test;
settee_was_used = false;
runtime_path = null;
tryRequireResolve('settee-templates', function(err, libpath) {
runtime_path = err != null ? (log.debug("Could not detect path of settee-templates."), null) : path.resolve(libpath, '../../../settee.runtime.js');
log.debug("Path of settee-templates is");
return log.debug(runtime_path);
});
assembot.addProcessor('js').ext('.settee').requires('settee-templates').build(function(settee) {
return function(source, opts, converted) {
var output;
settee_was_used = true;
output = "settee= require('runtime/settee');\nmodule.exports=settee(" + (settee.precompile(source)) + ");";
return converted(null, output, opts);
};
});
assembot.before('render', function(bot) {
return settee_was_used = false;
});
return assembot.after('render', function(bot) {
if (settee_was_used) {
if (test('-f', runtime_path)) {
return bot.resources.push(new Resource('runtime/settee.js', cat(runtime_path)));
} else {
throw new Error("Cannot embed Settee runtime! Not found at " + runtime_path);
}
}
});
};
module.exports = plugin;
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var Processor, ProcessorManager, addProcessor, assembot_package, async, build_package, compile_less, compile_stylus, compontent_package, log, manager, notify, packager, path, project_package, project_root, render, replaceTokens, targetOf, tokenParser, transpile, validTarget, _,
__slice = [].slice;
_ = require('./util');
log = require('./log');
path = require('path');
async = require('async');
notify = require('./notify');
project_root = process.cwd();
assembot_package = require('../../package');
project_package = (function() {
try {
return require("" + project_root + path.sep + "package");
} catch (ex) {
return {};
}
})();
compontent_package = (function() {
try {
return require("" + project_root + path.sep + "component");
} catch (ex) {
return {};
}
})();
build_package = (function() {
try {
return require("" + project_root + path.sep + "build");
} catch (ex) {
return {};
}
})();
targetOf = function(filepath) {
var ext;
ext = path.extname(filepath);
return manager.targetForExt(ext);
};
validTarget = function(filepath) {
return targetOf(filepath) !== 'unknown';
};
render = function(resources, options, done) {
var t;
if (resources.length === 0) {
log.debug("Rendering 0 resources");
return done();
} else {
log.debug("Rendering " + resources[0].target + " resources:");
}
t = function(r, cb) {
notify.beforeRenderItem(r);
if (options.replaceTokens) {
r.content = replaceTokens(r.content, options);
}
return transpile(r, options, cb);
};
async.each(resources, t, function(err, rest) {
if (err != null) {
throw err;
}
return done(err);
});
return true;
};
transpile = function(resource, options, done) {
return manager.render(resource, options, done);
};
tokenParser = /(\{%\-([ a-zA-Z0-9\._]*)\-%\})/g;
replaceTokens = function(string, context) {
if (tokenParser.test(string)) {
return string.replace(tokenParser, function(match, token, value, loc, src) {
var data, first_part, key, part, parts, _i, _len;
data = context;
parts = value.split('.');
first_part = parts.shift().trim();
switch (first_part) {
case 'package':
data = project_package;
break;
case 'assembot':
data = assembot_package;
break;
case 'build':
data = build_package;
break;
case 'component':
data = component_package;
break;
case 'NOW':
data = new Date();
break;
default:
data = context[first_part];
}
for (_i = 0, _len = parts.length; _i < _len; _i++) {
part = parts[_i];
key = part.trim();
data = data[key];
}
return String(data);
});
} else {
return string;
}
};
addProcessor = function(type) {
return new Processor(type);
};
module.exports = {
targetOf: targetOf,
validTarget: validTarget,
render: render,
transpile: transpile,
replaceTokens: replaceTokens,
addProcessor: addProcessor,
Processor: Processor,
ProcessorManager: ProcessorManager
};
ProcessorManager = (function() {
function ProcessorManager() {
this.processors = [];
this.processorsByType = {};
this.processorsByExt = {};
this.extByType = [];
}
ProcessorManager.prototype.render = function(resource, options, done) {
var proc;
proc = this.processorFor(resource);
return proc.render(resource, options, done);
};
ProcessorManager.prototype.processorFor = function(res) {
return this.processorsByExt[res.ext];
};
ProcessorManager.prototype.targetForExt = function(ext) {
var _ref, _ref1;
return (_ref = (_ref1 = this.processorsByExt[ext]) != null ? _ref1.type : void 0) != null ? _ref : 'unknown';
};
ProcessorManager.prototype.register = function(processor) {
var ext, _i, _len, _ref;
this.processors.push(processor);
this.processorsByType[processor.type] = processor;
_ref = processor.extensions;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
ext = _ref[_i];
this.processorsByExt[ext] = processor;
}
return this;
};
ProcessorManager.instance = new ProcessorManager;
return ProcessorManager;
})();
manager = ProcessorManager.instance;
Processor = (function() {
function Processor(type) {
this.type = type;
this.extensions = [];
this.requiredLibs = [];
this.renderQueue = [];
this.warning = null;
this.converter = null;
this.builder = null;
}
Processor.prototype.ext = function() {
var ext, exts, _i, _len;
exts = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
for (_i = 0, _len = exts.length; _i < _len; _i++) {
ext = exts[_i];
if (ext[0] === '.') {
this.extensions.push(ext);
} else {
this.extensions.push("." + ext);
}
}
return this;
};
Processor.prototype.requires = function() {
var reqs;
reqs = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
this.requiredLibs = reqs;
return this;
};
Processor.prototype.warn = function(msg) {
this.warning = msg;
return this;
};
Processor.prototype.build = function(builder) {
var warning;
this.builder = this.warning != null ? (warning = this.warning, function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
log.info(" NOTE:", warning);
return builder.apply(null, args);
}) : builder;
manager.register(this);
if (this.requiredLibs.length === 0) {
this.initialize();
}
return this;
};
Processor.prototype.initialize = function() {
var _this = this;
if (this.loading) {
return;
}
this.loading = true;
return _.tryRequireAll(this.requiredLibs, function(err, libs) {
var queued, _i, _len, _ref;
if (err != null) {
throw err;
}
_this.converter = _this.builder.apply(_this.builder, libs);
_ref = _this.renderQueue;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
queued = _ref[_i];
_this.render.apply(_this, queued);
}
_this.renderQueue = [];
return _this.loading = false;
});
};
Processor.prototype.render = function(res, opts, done) {
var file, o;
if (this.converter != null) {
log.debug(" -", res.path);
o = _.defaults({}, {
current_file: res
}, opts);
try {
return this.converter(res.content, o, function(err, content) {
if (err != null) {
return done(err);
}
res.content = content;
notify.afterRenderItem(res);
return done(err, res);
});
} catch (ex) {
file = "" + res.path + res.ext;
ex.name = "Processor Error";
ex.message = "Processor Error for " + file + ": " + ex.message;
log.error(ex.message);
return done(ex, null, opts);
}
} else {
log.trace(" |", res.path, "(queued)");
this.renderQueue.push([res, opts, done]);
return this.initialize();
}
};
return Processor;
})();
/*
Default Processors:
*/
addProcessor('js').ext('.js').build(function() {
return function(source, opts, converted) {
return converted(null, source, opts);
};
});
addProcessor('js').ext('.html').build(function() {
return function(source, opts, converted) {
return converted(null, "module.exports=" + (JSON.stringify(source)) + ";", opts);
};
});
addProcessor('js').ext('.json').build(function() {
return function(source, opts, converted) {
var data;
data = JSON.parse(source);
return converted(null, "module.exports=" + (JSON.stringify(data)) + ";", opts);
};
});
addProcessor('js').ext('.coffee', '.litcoffee').requires('coffee-script').build(function(coffee) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.coffee || {}, {
bare: true
});
options.literate = opts.current_file.ext === '.litcoffee' || false;
output = coffee.compile(source, options);
return converted(null, output, opts);
};
});
addProcessor('js').ext('.eco').requires('eco').build(function(eco) {
return function(source, opts, converted) {
var output;
output = eco.precompile(source);
return converted(null, "module.exports= " + output + ";", opts);
};
});
addProcessor('js').ext('.mustache').requires('coffee-templates').build(function(coffeeTmpl) {
return function(source, opts, converted) {
var output;
output = coffeeTmpl.compile(source);
return converted(null, "module.exports= " + output + ";", opts);
};
});
addProcessor('js').ext('.ejs').requires('ejs').build(function(ejs) {
return function(source, opts, converted) {
var output;
output = ejs.compile(source, {
client: true,
compileDebug: false
});
return converted(null, "module.exports= " + (output.toString()) + ";", opts);
};
});
addProcessor('js').ext('.dot').requires('doT').build(function(dot) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.dot || opts.doT || {}, {});
output = dot.compile(source, options);
return converted(null, "module.exports= " + (output.toString()), opts);
};
});
addProcessor('js').ext('.md', '.markdown').requires('marked').build(function(marked) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.marked || {}, {
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true
});
output = marked(source, options);
return converted(null, "module.exports=" + (JSON.stringify(output)) + ";", opts);
};
});
addProcessor('js').ext('.jade').requires('jade').warn("Jade requires a runtime, be sure it's included in your page.").build(function(jade) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.jade || {}, {
client: true,
compileDebug: false
});
output = jade.compile(source, options);
return converted(null, "module.exports= " + (output.toString()) + ";", opts);
};
});
addProcessor('js').ext('.hogan').requires('hogan.js').warn("Hogan requires a runtime, be sure it's included in your page.").build(function(hogan) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.hogan || {}, {
asString: 1
});
output = hogan.compile(source, options);
return converted(null, "module.exports= new Hogan.Template(" + (output.toString()) + ");", opts);
};
});
addProcessor('js').ext('.handlebars').requires('handlebars').warn("Handlebars requires a runtime, be sure it's included in your page.").build(function(handlebars) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.handlebars || {}, {
simple: false,
commonjs: true
});
output = handlebars.precompile(source, options);
return converted(null, "module.exports= " + (output.toString()) + ";", opts);
};
});
compile_less = function(less, source, callback) {
return less.render(source, callback);
};
compile_stylus = function(stylus, nib, source, opts, callback) {
var options;
options = _.defaults({}, opts.stylus || {}, {
filename: opts.current_file.filename || 'generated.css',
paths: opts.load_paths
});
return stylus(source).set('filename', opts.current_file.filename || 'generated.css').set('paths', opts.load_paths).set(options).use(nib()).render(callback);
};
addProcessor('css').ext('.css').build(function() {
return function(source, opts, converted) {
return converted(null, source, opts);
};
});
addProcessor('css').ext('.less').requires('less').build(function(less) {
return function(source, opts, converted) {
return compile_less(less, source, function(err, css) {
if (err != null) {
converted(err, null, opts);
}
return converted(null, css, opts);
});
};
});
addProcessor('css').ext('.styl').requires('stylus', 'nib').build(function(stylus, nib) {
var load_paths;
load_paths = [process.cwd(), path.dirname(__dirname)];
return function(source, opts, converted) {
opts.load_paths = load_paths;
return compile_stylus(stylus, nib, source, opts, function(err, css) {
if (err != null) {
return converted(err, null, opts);
} else {
return converted(null, css, opts);
}
});
};
});
packager = require('./packager');
addProcessor('js').ext('.ecss').build(function() {
return function(source, opts, converted) {
return converted(null, packager.embedded_css(source), opts);
};
});
addProcessor('js').ext('.eless').requires('less').build(function(less) {
return function(source, opts, converted) {
return compile_less(less, source, function(err, css) {
if (err != null) {
converted(err, null, opts);
}
return converted(null, packager.embedded_css(css), opts);
});
};
});
addProcessor('js').ext('.estyl').requires('stylus', 'nib').build(function(stylus, nib) {
var load_paths;
load_paths = [process.cwd(), path.dirname(__dirname)];
return function(source, opts, converted) {
opts.load_paths = load_paths;
return compile_stylus(stylus, nib, source, opts, function(err, css) {
if (err != null) {
return converted(err, null, opts);
} else {
return converted(null, packager.embedded_css(css), opts);
}
});
};
});
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var EventEmitter, Resource, ResourceList, cat, fs, log, ls, path, processor, resourcelist, test, _, _ref;
path = require('path');
fs = require('fs');
_ = require('./util');
processor = require('./processor');
log = require('./log');
_ref = require('shelljs'), ls = _ref.ls, cat = _ref.cat, test = _ref.test;
EventEmitter = require('events').EventEmitter;
Resource = (function() {
function Resource(filepath, content) {
this.filepath = filepath;
this.content = content;
log.debug(" -", this.filepath);
this.disable = false;
this.ext = path.extname(this.filepath);
this.type = this.ext.slice(1);
this.target = processor.targetOf(this.filepath);
this.path = this.filepath.replace(this.ext, '');
}
return Resource;
})();
ResourceList = (function() {
ResourceList.fromPath = function(sourcePath) {
var contents, filename, filepath, fileset, res, reslist, _i, _len;
log.debug("Resources loaded from", sourcePath);
reslist = new ResourceList;
sourcePath = path.resolve(sourcePath);
fileset = ls('-R', sourcePath);
for (_i = 0, _len = fileset.length; _i < _len; _i++) {
filename = fileset[_i];
filepath = path.join(sourcePath, filename);
if (!test('-f', filepath)) {
continue;
}
contents = cat(filepath);
res = new Resource(filename, contents);
reslist.add(res);
}
return reslist;
};
function ResourceList() {
this.list = [];
this.length = 0;
}
ResourceList.prototype.each = function(callback) {
var i, resource, _i, _len, _ref1;
_ref1 = this.list;
for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) {
resource = _ref1[i];
callback(resource, i);
}
return this;
};
ResourceList.prototype.forTarget = function(target) {
var resource, _i, _len, _ref1, _results;
_ref1 = this.list;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
resource = _ref1[_i];
if (resource.target === target) {
_results.push(resource);
}
}
return _results;
};
ResourceList.prototype.eachForTarget = function(target, callback) {
var i, resource, _i, _len, _ref1;
_ref1 = this.forTarget(target);
for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) {
resource = _ref1[i];
callback(resources, i);
}
return this;
};
ResourceList.prototype.add = function(resource) {
this.list.push(resource);
this.length += 1;
return this;
};
ResourceList.prototype.treeForTarget = function(target) {
var resource, tree, _i, _len, _ref1;
tree = {};
_ref1 = this.forTarget(target);
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
resource = _ref1[_i];
tree[resource.path] = resource;
}
return tree;
};
return ResourceList;
})();
resourcelist = function(filepath) {
return ResourceList.fromPath(filepath);
};
module.exports = {
Resource: Resource,
ResourceList: ResourceList,
resourcelist: resourcelist
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var assembot, build_middleware, express, fs, loadOptions, log, notify, path, project_root, test, _, _ref;
_ = require('./util');
fs = require('fs');
log = require('./log');
path = require('path');
express = require('express');
notify = require('./notify');
test = require('shelljs').test;
_ref = require('./index'), assembot = _ref.assembot, loadOptions = _ref.loadOptions;
project_root = process.cwd();
build_middleware = function(bots, config) {
var bot, bot_by_path, bot_for, paths, _i, _len;
paths = config.paths;
bot_by_path = {};
for (_i = 0, _len = bots.length; _i < _len; _i++) {
bot = bots[_i];
bot_by_path[bot.output] = bot;
}
bot_for = function(url) {
var filepath, localpath, uri;
for (uri in paths) {
filepath = paths[uri];
localpath = path.resolve(path.join(filepath, url));
if (bot = bot_by_path[localpath]) {
return bot;
}
}
return false;
};
return function(req, res, next) {
var url, _ref1;
url = (_ref1 = req.url) != null ? _ref1.slice(1) : void 0;
if (bot = bot_for(url)) {
log.info("Rebuilding:", bot.target);
return bot.build(function(content) {
var contentType;
contentType = (function() {
switch (bot.target) {
case 'js':
return 'application/javascript';
case 'css':
return 'text/css';
default:
return 'text/html';
}
})();
res.set('Content-Type', contentType);
return res.send(200, content);
});
} else {
return next();
}
};
};
exports.start = function(bots, options) {
var app, conf, filepath, uri, _ref1;
log.debug("Configuration");
conf = options.http;
app = express();
log.debug(conf);
log.info("Serving", bots.length, "packages...");
notify.createServer(app, options);
app.use(express.errorHandler({
dumpExceptions: true,
showStack: true
}));
app.use(express.logger());
app.use(build_middleware(bots, conf));
log.info("Mounting paths:");
_ref1 = conf.paths;
for (uri in _ref1) {
filepath = _ref1[uri];
log.info(" " + uri + " -> " + filepath);
app.use(uri, express["static"](filepath));
}
notify.startServer(app, options);
app.listen(conf.port);
return log.info(" Ready! Visit http://127.0.0.1:" + conf.port);
};
}).call(this);
// Generated by CoffeeScript 1.6.1
(function() {
var defaults, exec, extend, fs, isAlreadyLoaded, loaded_libs, loading_now, localRequire, localResolve, path, pp, tryRequire, tryRequireAll, tryRequireResolve, type, util, validateOptionsCallback;
util = require('util');
fs = require('fs');
exec = require('shelljs').exec;
path = require('path');
pp = function(obj) {
return util.puts(util.inspect(obj));
};
extend = function(obj) {
var key, source, value, _i, _len, _ref;
_ref = Array.prototype.slice.call(arguments, 1);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
source = _ref[_i];
if (source) {
for (key in source) {
value = source[key];
obj[key] = value;
}
}
}
return obj;
};
defaults = function(obj) {
var key, source, value, _i, _len, _ref;
_ref = Array.prototype.slice.call(arguments, 1);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
source = _ref[_i];
if (source) {
for (key in source) {
value = source[key];
if (obj[key] == null) {
obj[key] = value;
} else if (type(obj[key]) === 'object') {
obj[key] = defaults({}, obj[key], value);
}
}
}
}
return obj;
};
type = (function() {
var classToType, elemParser, name, toStr, _i, _len, _ref;
toStr = Object.prototype.toString;
elemParser = /\[object HTML(.*)\]/;
classToType = {};
_ref = "Boolean Number String Function Array Date RegExp Undefined Null NodeList".split(" ");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
name = _ref[_i];
classToType["[object " + name + "]"] = name.toLowerCase();
}
return function(obj) {
var found, strType;
strType = toStr.call(obj);
if (found = classToType[strType]) {
return found;
} else if (found = strType.match(elemParser)) {
return found[1].toLowerCase();
} else {
return "object";
}
};
})();
validateOptionsCallback = function(options, callback) {
if (typeof options === 'function') {
return [{}, options];
} else {
return [options, callback];
}
};
tryRequireResolve = function(name, callback) {
try {
path = require.resolve(name);
return callback(null, path);
} catch (ex) {
return localResolve(name, callback);
}
};
tryRequire = function(name, callback) {
var lib;
if (name === null || name === '') {
return callback(null, {});
}
if (loaded_libs[name] != null) {
return callback(null, loaded_libs[name]);
}
try {
lib = require(name);
loaded_libs[name] = lib;
return callback(null, lib);
} catch (ex) {
return localRequire(name, callback);
}
};
tryRequireAll = function(names, callback) {
var libnames, libs, loader, nextLib;
if (names.length === 0) {
return callback(null, []);
}
libs = [];
libnames = names.slice();
nextLib = libnames.shift();
loader = function(err, lib) {
if (err != null) {
return callback(err, null);
}
libs.push(lib);
if (libnames.length === 0) {
return callback(null, libs);
}
nextLib = libnames.shift();
return tryRequire(nextLib, loader);
};
return tryRequire(nextLib, loader);
};
loaded_libs = {};
loading_now = {};
isAlreadyLoaded = function(name, callback) {
if (loaded_libs[name] != null) {
callback(null, loaded_libs[name]);
return true;
}
if (loading_now[name] != null) {
loading_now[name].push(callback);
return true;
} else {
loading_now[name] = [];
loading_now[name].push(callback);
return false;
}
};
localResolve = function(name, callback) {
var cmd, libpath, result;
cmd = "" + process.execPath + " -p -e \"require.resolve('" + name + "')\"";
result = exec(cmd, {
silent: true
});
libpath = result.output.trim();
if (result.code !== 0 || libpath === '') {
return callback(new Error("Could not load '" + name + "' module. (no local path)"));
} else {
return callback(null, libpath);
}
};
localRequire = function(name, callback) {
var cb, lib, libpath, _i, _j, _len, _len1, _ref, _ref1;
if (isAlreadyLoaded(name, callback)) {
return false;
}
if (name.slice(0, 2) === './') {
libpath = path.resolve(name);
try {
lib = require(libpath);
loaded_libs[name] = lib;
_ref = loading_now[name];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
cb = _ref[_i];
cb(null, lib);
}
} catch (ex) {
_ref1 = loading_now[name];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
cb = _ref1[_j];
cb(ex, null);
}
}
delete loading_now[name];
} else {
localResolve(name, function(err, libpath) {
var _k, _l, _len2, _len3, _ref2, _ref3;
if (err != null) {
return (function() {
var _k, _len2, _ref2, _results;
_ref2 = loading_now[name];
_results = [];
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
cb = _ref2[_k];
_results.push(cb(err, null));
}
return _results;
})();
}
try {
lib = require(libpath);
loaded_libs[name] = lib;
_ref2 = loading_now[name];
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
cb = _ref2[_k];
cb(null, lib);
}
} catch (ex) {
_ref3 = loading_now[name];
for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
cb = _ref3[_l];
cb(ex, null);
}
}
return delete loading_now[name];
});
}
return true;
};
module.exports = {
pp: pp,
extend: extend,
defaults: defaults,
type: type,
validateOptionsCallback: validateOptionsCallback,
tryRequire: tryRequire,
tryRequireAll: tryRequireAll,
tryRequireResolve: tryRequireResolve,
localRequire: localRequire
};
extend(module.exports, util);
}).call(this);
_= require './util'
path= require 'path'
defaults= require './defaults'
packager= require './packager'
# {EventEmitter}= require 'events'
#TODO: remove this class!!!
class Assembler #extends EventEmitter
constructor: (@target)->
package: (resources, options, callback)->
[options, callback]= _.validateOptionsCallback options, callback
if _.type(resources) isnt 'array'
resources= resources.forTarget @target
packager.build @target, resources, options, callback
# switch @target
# when 'js' then packager.js resources, options, callback
# when 'css' then packager.css resources, options, callback
# else callback new Error("Unknown package target '#{@target}'")
@
assembler= (target, resources, options, callback)->
asm= new Assembler target
asm.package resources, options, callback
module.exports= {Assembler, assembler}
_= require './util'
fs= require 'fs'
path= require 'path'
defaults= require './defaults'
log= require('./log')
packager= require './packager'
processor= require './processor'
notify= require './notify'
{echo}= require 'shelljs'
{assembler}= require './assembler'
{resourcelist}= require './resources'
class Bot
@vent: notify
@on: (event, listener)-> notify.on event, listener
@before: (event, listener)-> notify.on "before:#{ event }", listener
@after: (event, listener)-> notify.on "after:#{ event }", listener
constructor: (output, options={})->
options.output= output if output?
@options= {}
@config(options)
@built= no
@returnContent= null
@userCallbackForCompletion= null
notify.createBot @
config: (options={})->
@options= _.defaults options, @options, defaults.options # ... overkill?
@output= path.resolve @options.output
@source= path.resolve @options.source
@target= processor.targetOf(@output)
@
# Send a callback to get the generated content instead of saving it to
# the target file
build: (callback)->
@returnContent= callback ? null
notify.beforeBuild @
notify.beforeScan @
@resources= resourcelist(@source).forTarget @target
notify.afterScan @
notify.beforeRender @
processor.render @resources, @options, @didRender
@
# Send a callback to be notified when the build has run to completion.
then: (callback)->
@userCallbackForCompletion= callback
@userCallbackForCompletion?() if @built
@
# Callback handlers for build process...
didRender: (err)=>
throw err if err?
notify.afterRender @
notify.beforeAssemble @
assembler @target, @resources, @options, @didAssemble
didAssemble: (err, @content)=>
throw err if err?
notify.afterAssemble @
@writeContent()
writeContent: ->
notify.afterBuild @
notify.beforeWrite @
if @returnContent?
log.info "Returning content to callback", @output
@returnContent(@content)
@userCallbackForCompletion?()
else
log.info "Writing", @output
@content.to @output
notify.afterWrite @
@built= yes
@userCallbackForCompletion?()
rebuild: @::build
bot= (output, options)->
new Bot output, options
module.exports= {Bot, bot}
module.exports=
options:
header: "/* Assembled by AssemBot {%- assembot.version -%} */"
addHeader: true
# sourceMap: no # NOT SUPPORT YET
minify: 0 # 0=none, 1=minify, 2=mangle
ident: 'require'
autoLoad: null
replaceTokens: yes
plugins: []
coffee:
bare: yes # precedence: 0
http:
port: 8080
paths:
'/': './public'
'/components': './components'
targets:
"public/app.js":
source: './source'
"public/app.css":
source: './source'
log= require('./log')
defaults= require './defaults'
_= require './util'
path= require 'path'
packager= require './packager'
plugins= require './plugins'
processor= require './processor'
project_root= process.cwd()
{resourcelist}= require './resources'
{assembler}= require './assembler'
{Bot}= require './bot'
loaded_from= null
loadFirstLocalPackage= (names...)->
for name in names
try
data= require "#{ project_root }#{ path.sep }#{ name }"
if data.assembot?
log.debug "Loaded #{ name }.json"
loaded_from= name
return data.assembot
else
throw new Error "No Assembot block"
catch ex
log.debug "No '#{ name }.json' file found!"
log.debug "No configuration found, using defaults!"
loaded_from= 'defaults'
defaults
loadTargets= ->
nfo= loadFirstLocalPackage 'package', 'component', 'build', 'assembot'
options= nfo.options ? defaults.options
src_targets= nfo.targets ? defaults.targets
targets= {}
for tgt, opts of src_targets
tgt_opts= _.defaults {}, opts, options, defaults.options
targets[tgt]= tgt_opts
targets
loadOptions= (returnDefaults)->
nfo= loadFirstLocalPackage 'package', 'component', 'build', 'assembot'
if returnDefaults is false
if nfo is defaults
return null
else
loaded_from
else
nfo.options ? defaults.options
assembot= (target, options={})->
plugins.init(
options
'./plugins/header'
'./plugins/minify'
'./plugins/settee-templates'
)
new Bot target, options
module.exports= {
assembot
defaults
assembler
resourcelist
loadTargets
packager
processor
loadOptions
loadFirstLocalPackage
_
}
log_level= 1
level= (lvl)->
log_level= lvl if lvl?
log_level
say= ->
console.log.apply console, arguments
info= ->
return if log_level < 1
console.log.apply console, arguments
debug= ->
return if log_level < 2
console.log.apply console, arguments
trace= ->
return if log_level < 3
console.log.apply console, arguments
error= ->
newError= new Error
if newError.stack?
lines= newError.stack.split "\n"
console.log "Error", lines[2].trim()
console.log.apply console, arguments
module.exports= {level, info, debug, error, trace, say}
log= require './log'
{EventEmitter}= require 'events'
class Notify
constructor: -> @vent= new EventEmitter
on: (event, listener)-> @vent.on event, listener
emit: (args...)-> @vent.emit(args...)
createBot: (bot)-> @vent.emit 'create:bot', bot
beforeBuild: (bot)-> @vent.emit 'before:build', bot
beforeScan: (bot)-> @vent.emit 'before:scan', bot
afterScan: (bot)-> @vent.emit 'after:scan', bot
beforeRender: (bot)-> @vent.emit 'before:render', bot
beforeRenderItem: (resource)-> @vent.emit 'before:renderItem', resource
afterRenderItem: (resource)-> @vent.emit 'after:renderItem', resource
afterRender: (bot)-> @vent.emit 'after:render', bot
beforeAssemble: (bot)-> @vent.emit 'before:assemble', bot
afterAssemble: (bot)-> @vent.emit 'after:assemble', bot
afterBuild: (bot)-> @vent.emit 'after:build', bot
beforeWrite: (bot)-> @vent.emit 'before:write', bot
afterWrite: (bot)-> @vent.emit 'after:write', bot
createServer: (server, opts)-> @vent.emit 'create:server', server, opts
startServer: (server, opts)-> @vent.emit 'start:server', server, opts
notifications= new Notify
module.exports= notifications
# log.debug "NOTIFICATIONS"
# notifications.on 'created', (bot)-> log.debug "> CREATED bot" #, bot
# notifications.on 'before:build', (args...)-> log.debug 'EVENT: before:build'#, args
# notifications.on 'before:scan', (args...)-> log.debug 'EVENT: before:scan'#, args
# notifications.on 'after:scan', (args...)-> log.debug 'EVENT: after:scan'#, args
# notifications.on 'before:render', (args...)-> log.debug 'EVENT: before:render'#, args
# notifications.on 'before:renderItem', (args...)-> log.debug 'EVENT: before:renderItem'#, args
# notifications.on 'after:renderItem', (args...)-> log.debug 'EVENT: after:renderItem'#, args
# notifications.on 'after:render', (args...)-> log.debug 'EVENT: after:render'#, args
# notifications.on 'before:assemble', (args...)-> log.debug 'EVENT: before:assemble'#, args
# notifications.on 'after:assemble', (args...)-> log.debug 'EVENT: after:assemble'#, args
# notifications.on 'after:build', (args...)-> log.debug 'EVENT: after:build'#, args
# notifications.on 'before:write', (args...)-> log.debug 'EVENT: before:write'#, args
# notifications.on 'after:write', (args...)-> log.debug 'EVENT: after:write'#, args
build= (target, resources, options, done)->
packager= packagers[target]
return done new Error("Unknown package target '#{ target }'") unless packager?
packager(resources, options, done)
packagers={}
# Hack for now... Need to have a better manager
addPackager= (target, packager)->
packagers[target]= packager
module.exports= {build, addPackager}
addPackager 'css', (resources, options, done)->
results= ""
for res in resources
results += "/* #{ res.path } */\n"
results += res.content
results += "\n\n"
done null, results
# Need to find a better home for this!
ecss_wrapper= (css)->
"""
var node = null, css = #{ JSON.stringify css };
module.exports= {
content: css,
isActive: function(){ return node != null; },
activate: function(to){
if(node != null) return; // Already added to DOM!
to= to || document.getElementsByTagName('HEAD')[0] || document.body || document; // In the HEAD or BODY tags
node= document.createElement('style');
node.innerHTML= css;
to.appendChild(node);
return this;
},
deactivate: function() {
if(node != null) {
node.parentNode.removeChild(node);
node = null;
}
return this;
}
};
"""
module.exports.embedded_css= ecss_wrapper
addPackager 'js', (resources, options, callback)->
identifier= options.ident ? 'require'
autoStart= options.autoStart ? false
result = """
(function(/*! Stitched by Assembot !*/) {
/*
The commonjs code below was based on @sstephenson's stitch.
https://github.com/sstephenson/stitch
*/
if (!this.#{identifier}) {
var modules = {}, cache = {}, moduleList= function(startingWith) {
var names= [], startingWith= startingWith || '';
for( var name in modules ) {
if(name.indexOf(startingWith) === 0) names.push(name);
}
return names;
}, require = function(name, root) {
var path = expand(root, name), module = cache[path], fn;
if (module) {
return module.exports;
} else if (fn = modules[path] || modules[path = expand(path, './index')]) {
module = {id: path, exports: {}};
try {
cache[path] = module;
var localRequire= function(name) {
return require(name, dirname(path));
}
localRequire.modules= moduleList;
fn(module.exports, localRequire, module);
return module.exports;
} catch (err) {
delete cache[path];
throw err;
}
} else {
throw 'module \\'' + name + '\\' not found';
}
}, expand = function(root, name) {
var results = [], parts, part;
if (/^\\.\\.?(\\/|$)/.test(name)) {
parts = [root, name].join('/').split('/');
} else {
parts = name.split('/');
}
for (var i = 0, length = parts.length; i < length; i++) {
part = parts[i];
if (part == '..') {
results.pop();
} else if (part != '.' && part != '') {
results.push(part);
}
}
return results.join('/');
}, dirname = function(path) {
return path.split('/').slice(0, -1).join('/');
};
this.#{identifier} = function(name) {
return require(name, '');
}
this.#{identifier}.define = function(bundle) {
for (var key in bundle)
modules[key] = bundle[key];
};
this.#{identifier}.modules= moduleList;
}
return this.#{identifier}.define;
}).call(this)({\n
"""
for res,i in resources
result += if i is 0 then "" else ",\n"
result += JSON.stringify res.path
result += ": function(exports, require, module) {\n#{ res.content }\n}"
result += """
});\n
"""
result += "#{identifier}('#{autoStart}');\n" if autoStart
callback null, result
log= require './log'
notify= require './notify'
shelljs= require 'shelljs'
{Bot}= require './bot'
{addPackager}= require './packager'
{ResourceList, Resource}= require './resources'
{extend, defaults, type, tryRequire, tryRequireAll, tryRequireResolve}= _= require './util'
{targetOf, validTarget, render, transpile, replaceTokens, addProcessor, Processor, ProcessorManager}= processor= require './processor'
{before, after}= Bot
loadPlugin= load
# Build plugin_context
context= {
before
after
log
extend
defaults
processor
addProcessor
addPackager
type
tryRequire
tryRequireAll
tryRequireResolve
loadPlugin # ?????
shelljs
Bot
Resource
ResourceList
Processor
ProcessorManager
}
context.on= Bot.on
initialized= no
init= (options, preload...)->
return false if initialized
# Assemble a list of all the plugins to load and load 'em
if options.plugins? and type(options.plugins) is 'array'
preload= preload.concat options.plugins
# These would be from the build config
load plugin for plugin in preload
initialized= yes
false # or true if any loaded
load= (name)->
# Load an individual plugin
tryRequire name, (err, lib)->
# Should they fail quitely?
return log.error "Failure to load plugin #{ name }", err if err?
lib.call(context, context)
notify.emit 'plugin:loaded', name, lib
module.exports= {init, load, context}
module.exports= (assembot)->
# TODO: Add support for adding a header from file...
{processor, log}= assembot
assembot.before 'write', (bot)->
return unless bot.options.header? and bot.options.addHeader
switch bot.target
when 'js', 'css'
log.debug "Adding header..."
header= processor.replaceTokens bot.options.header, {}
log.trace header
output= "#{header}\n#{bot.content}"
bot.content = output
uglify= try
require "uglify-js"
catch ex
null
do_minify= (flag, output_content, log)->
if uglify?
log.debug "Minify..."
try
settings= fromString: true, mangle:false
switch flag
when 1, 'minify', 'min'
uglify.minify( output_content, settings )
when 2, 'mangle', 'munge', 'compress'
settings.mangle= true
uglify.minify( output_content, settings )
else
code:output_content, map:null
catch ex
log.info "Error in minify, skipping..."
log.error ex
code:output_content, map:null
else
log.info "Can't minify (install uglify-js)..."
code:output_content, map:null
module.exports= (assembot)->
{log}= assembot
assembot.after 'build', (bot)->
return if bot.target isnt 'js'
if bot.options.minify? and bot.options.minify isnt false and bot.options.minify > 0
bot.content = do_minify( bot.options.minify, bot.content, log ).code
path= require 'path'
plugin= (assembot)->
{Resource, tryRequireResolve, log, shelljs}= assembot
{cat,test}= shelljs
settee_was_used= no
runtime_path= null
# Get the runtime path
tryRequireResolve 'settee-templates', (err, libpath)->
runtime_path= if err?
log.debug "Could not detect path of settee-templates."
# log.debug err
null
else
path.resolve( libpath, '../../../settee.runtime.js' )
log.debug "Path of settee-templates is"
log.debug runtime_path
# Add transpiler support
assembot
.addProcessor('js').ext('.settee')
.requires('settee-templates')
.build (settee)->
(source, opts, converted)->
settee_was_used= yes
output= """
settee= require('runtime/settee');
module.exports=settee(#{ settee.precompile(source) });
"""
converted null, output, opts
# Reset the tracking when rendering
assembot.before 'render', (bot)->
settee_was_used= no
# Auto embed runtime compontent
assembot.after 'render', (bot)->
if settee_was_used
if test('-f', runtime_path)
bot.resources.push new Resource 'runtime/settee.js', cat(runtime_path)
else
throw new Error "Cannot embed Settee runtime! Not found at #{ runtime_path }"
module.exports= plugin
_= require './util'
log= require './log'
path= require 'path'
async= require 'async'
notify= require './notify'
project_root= process.cwd()
assembot_package= require '../../package'
project_package= try
require "#{project_root}#{path.sep}package"
catch ex
{}
compontent_package= try
require "#{project_root}#{path.sep}component"
catch ex
{}
build_package= try
require "#{project_root}#{path.sep}build"
catch ex
{}
targetOf= (filepath)->
ext= path.extname filepath
manager.targetForExt ext
validTarget= (filepath)->
targetOf(filepath) isnt 'unknown'
render= (resources, options, done)->
if resources.length is 0
log.debug "Rendering 0 resources"
return done()
else
log.debug "Rendering #{ resources[0].target } resources:"
t= (r,cb)->
notify.beforeRenderItem r
r.content= replaceTokens(r.content, options) if options.replaceTokens
transpile r, options, cb
async.each resources, t, (err, rest)->
throw err if err?
done(err)
true
transpile= (resource, options, done)->
manager.render resource, options, done
tokenParser= /(\{%\-([ a-zA-Z0-9\._]*)\-%\})/g
replaceTokens= (string, context)->
if tokenParser.test(string)
string.replace tokenParser, (match, token, value, loc, src)->
data= context
parts= value.split('.')
first_part= parts.shift().trim()
switch first_part
when 'package' then data= project_package
when 'assembot' then data= assembot_package
when 'build' then data= build_package
when 'component' then data= component_package
when 'NOW' then data= new Date()
else
data= context[first_part]
for part in parts
key= part.trim()
data= data[key]
String(data)
else
string
addProcessor= (type)->
new Processor(type)
module.exports= {targetOf, validTarget, render, transpile, replaceTokens, addProcessor, Processor, ProcessorManager}
class ProcessorManager
constructor: ->
@processors= []
@processorsByType= {}
@processorsByExt= {}
@extByType= []
render: (resource, options, done)->
proc= @processorFor resource
proc.render resource, options, done
processorFor: (res)->
@processorsByExt[res.ext]
targetForExt: (ext)->
@processorsByExt[ext]?.type ? 'unknown'
register: (processor)->
@processors.push processor
@processorsByType[processor.type]= processor
for ext in processor.extensions
@processorsByExt[ext]= processor
@
@instance: new @
manager= ProcessorManager.instance
class Processor
constructor: (@type)->
@extensions= []
@requiredLibs= []
@renderQueue=[]
@warning= null
@converter= null
@builder= null
ext: (exts...)->
for ext in exts
if ext[0] is '.'
@extensions.push ext
else
@extensions.push ".#{ ext }"
@
requires: (reqs...)->
@requiredLibs= reqs
@
warn: (msg)->
@warning= msg
@
build: (builder)->
@builder= if @warning?
warning= @warning
(args...)->
log.info " NOTE:", warning
builder(args...)
else
builder
manager.register(@)
if @requiredLibs.length is 0
@initialize()
@
# Rendering logic:
initialize: ->
return if @loading
@loading= true
_.tryRequireAll @requiredLibs, (err, libs)=>
throw err if err?
@converter= @builder.apply @builder, libs
for queued in @renderQueue
@render.apply @, queued
@renderQueue=[]
@loading= false
render: (res, opts, done)->
if @converter?
log.debug " -", res.path
o= _.defaults {}, current_file:res, opts
try
@converter res.content, o, (err, content)->
return done err if err?
res.content= content
notify.afterRenderItem res
done err, res
catch ex
file= "#{ res.path }#{ res.ext }"
ex.name = "Processor Error"
ex.message= "Processor Error for #{ file }: #{ ex.message }"
log.error ex.message
done ex, null, opts
else
log.trace " |", res.path, "(queued)"
@renderQueue.push [res, opts, done]
@initialize()
###
Default Processors:
###
# JS
addProcessor('js').ext('.js')
.build -> (source, opts, converted)->
converted null, source, opts
# HTML
addProcessor('js').ext('.html')
.build -> (source, opts, converted)->
converted null, """module.exports=#{JSON.stringify source};""", opts
# JSON
addProcessor('js').ext('.json')
.build -> (source, opts, converted)->
data= JSON.parse source
converted null, """module.exports=#{JSON.stringify data};""", opts
# COFFEESCRIPT
addProcessor('js').ext('.coffee', '.litcoffee')
.requires('coffee-script')
.build (coffee)-> (source, opts, converted)->
options = _.defaults {}, (opts.coffee || {}),
bare: yes
options.literate= (opts.current_file.ext is '.litcoffee' || no)
output= coffee.compile source, options
converted null, output, opts
# ECO
addProcessor('js').ext('.eco')
.requires('eco')
.build (eco)-> (source, opts, converted)->
output= eco.precompile source
converted null, """module.exports= #{output};""", opts
# MUSTACHE
addProcessor('js').ext('.mustache')
.requires('coffee-templates')
.build (coffeeTmpl)-> (source, opts, converted)->
output= coffeeTmpl.compile source
converted null, """module.exports= #{output};""", opts
# EJS
addProcessor('js').ext('.ejs')
.requires('ejs')
.build (ejs)-> (source, opts, converted)->
output= ejs.compile(source, client:true, compileDebug:false)
converted null, """module.exports= #{output.toString()};""", opts
# DOT
addProcessor('js').ext('.dot')
.requires('doT')
.build (dot)-> (source, opts, converted)->
options= _.defaults {}, (opts.dot || opts.doT || {}), {}
output= dot.compile(source, options)
converted null, """module.exports= #{ output.toString() }""", opts
# MARKDOWN
addProcessor('js').ext('.md', '.markdown')
.requires('marked')
.build (marked)-> (source, opts, converted)->
options= _.defaults {}, (opts.marked || {}),
gfm: true
tables: true
breaks: false
pedantic: false
sanitize: false
smartLists: true
output= marked(source, options)
converted null, """module.exports=#{ JSON.stringify output };""", opts
# Be aware: These require a runtime component...
# # SETTEE MOVED TO PLUGIN!
# addProcessor('js').ext('.settee')
# .requires('settee-templates')
# .warn("Settee requires a runtime, be sure it's included in your page.")
# .build (settee)-> (source, opts, converted)->
# output= """
# if(!this.settee) settee= require('settee');
# module.exports=settee(#{ settee.precompile(source) });
# """
# converted null, output, opts
# JADE
addProcessor('js').ext('.jade')
.requires('jade')
.warn("Jade requires a runtime, be sure it's included in your page.")
.build (jade)-> (source, opts, converted)->
options= _.defaults {}, (opts.jade || {}),
client: true
compileDebug: false
output= jade.compile(source, options)
converted null, """module.exports= #{output.toString()};""", opts
# HOGAN
addProcessor('js').ext('.hogan')
.requires('hogan.js')
.warn("Hogan requires a runtime, be sure it's included in your page.")
.build (hogan)-> (source, opts, converted)->
options= _.defaults {}, (opts.hogan || {}),
asString: 1
output= hogan.compile(source, options)
converted null, """module.exports= new Hogan.Template(#{output.toString()});""", opts
# HANDLEBARS
addProcessor('js').ext('.handlebars')
.requires('handlebars')
.warn("Handlebars requires a runtime, be sure it's included in your page.")
.build (handlebars)-> (source, opts, converted)->
options= _.defaults {}, (opts.handlebars || {}),
simple: false
commonjs: true
output= handlebars.precompile(source, options)
converted null, """module.exports= #{output.toString()};""", opts
# TODO: Add default converters for: yaml(?), others?
compile_less= (less, source, callback)->
less.render source, callback
compile_stylus= (stylus, nib, source, opts, callback)->
options= _.defaults {}, (opts.stylus || {}),
filename: opts.current_file.filename || 'generated.css'
paths: opts.load_paths
stylus(source)
.set('filename', opts.current_file.filename || 'generated.css')
.set('paths', opts.load_paths)
.set(options)
.use(nib())
.render callback
# Default CSS converters
addProcessor('css').ext('.css')
.build -> (source, opts, converted)->
converted null, source, opts
addProcessor('css').ext('.less')
.requires('less')
.build (less)-> (source, opts, converted)->
compile_less less, source, (err, css)->
converted err, null, opts if err?
converted null, css, opts
addProcessor('css').ext('.styl')
.requires('stylus', 'nib')
.build (stylus, nib)->
load_paths= [process.cwd(), path.dirname(__dirname)]
(source, opts, converted)->
opts.load_paths= load_paths
compile_stylus stylus, nib, source, opts, (err, css)->
if err?
converted err, null, opts
else
converted null, css, opts
## Embedded CSS Support
#TODO: Should the processor be responsible for the embedded_css wrapper?
packager= require './packager'
addProcessor('js').ext('.ecss')
.build -> (source, opts, converted)->
converted null, packager.embedded_css(source), opts
addProcessor('js').ext('.eless')
.requires('less')
.build (less)-> (source, opts, converted)->
compile_less less, source, (err, css)->
converted err, null, opts if err?
converted null, packager.embedded_css(css), opts
addProcessor('js').ext('.estyl')
.requires('stylus', 'nib')
.build (stylus, nib)->
load_paths= [process.cwd(), path.dirname(__dirname)]
(source, opts, converted)->
opts.load_paths= load_paths
compile_stylus stylus, nib, source, opts, (err, css)->
if err?
converted err, null, opts
else
converted null, packager.embedded_css(css), opts
# Add other ones too???
path= require 'path'
fs= require 'fs'
_= require './util'
processor= require './processor'
log= require('./log')
{ls, cat, test}= require 'shelljs'
{EventEmitter}= require 'events'
class Resource
# File path should be relative to the source root, not including the source dirname
constructor: (@filepath, @content)->
log.debug " -", @filepath
@disable= no
@ext= path.extname(@filepath)
@type= @ext[1...]
@target= processor.targetOf(@filepath) # returns 'js', 'css', 'unknown'
@path= @filepath.replace @ext, ''
class ResourceList
@fromPath: (sourcePath)->
log.debug "Resources loaded from", sourcePath
reslist= new ResourceList
sourcePath= path.resolve sourcePath
fileset= ls '-R', sourcePath
for filename in fileset
filepath= path.join sourcePath, filename
continue unless test('-f', filepath)
contents= cat(filepath)
res= new Resource filename, contents
reslist.add res
reslist
constructor: ()->
@list= []
@length= 0
each: (callback)->
for resource,i in @list
callback resource, i
@
forTarget: (target)->
resource for resource in @list when resource.target is target
eachForTarget: (target, callback)->
callback resources, i for resource, i in @forTarget(target)
@
add: (resource)->
@list.push resource
@length += 1
@
treeForTarget: (target)->
tree={}
for resource in @forTarget(target)
tree[resource.path]= resource
tree
resourcelist= (filepath)->
ResourceList.fromPath filepath
module.exports= {Resource, ResourceList, resourcelist}
_= require './util'
fs= require 'fs'
log= require './log'
path= require 'path'
express= require 'express'
notify= require './notify'
{test}= require 'shelljs'
{assembot, loadOptions}= require './index'
project_root= process.cwd()
build_middleware= (bots, config)->
{paths}= config
bot_by_path= {}
bot_by_path[bot.output]= bot for bot in bots
# log.info "Paths", paths
# log.info "BotsByPath", bot_by_path
bot_for= (url)->
for uri, filepath of paths
localpath= path.resolve path.join(filepath, url)
if bot= bot_by_path[localpath]
return bot
return false
(req, res, next)->
url= req.url?[1..] # strip the leading /
if bot= bot_for url
log.info "Rebuilding:", bot.target
bot.build (content)->
contentType= switch bot.target
when 'js' then 'application/javascript'
when 'css' then 'text/css'
else 'text/html'
res.set 'Content-Type', contentType
res.send 200, content
else
# log.info "Not a package target:", url, bot
next()
exports.start= (bots, options)->
log.debug "Configuration"
conf= options.http
app= express()
log.debug conf
# log.debug bots
log.info "Serving", bots.length, "packages..."
notify.createServer app, options
app.use express.errorHandler( dumpExceptions:yes, showStack:yes )
app.use express.logger()
app.use build_middleware(bots, conf)
log.info "Mounting paths:"
for uri, filepath of conf.paths
log.info " #{ uri } -> #{ filepath }"
app.use uri, express.static(filepath)
notify.startServer app, options
app.listen(conf.port)
log.info " Ready! Visit http://127.0.0.1:#{ conf.port }"
util= require 'util'
fs= require 'fs'
{exec}= require 'shelljs'
path= require 'path'
# {spawn, exec}= require 'child_process'
pp= (obj)->
util.puts util.inspect obj
extend= (obj)->
for source in Array::slice.call(arguments, 1)
if source
for key,value of source
obj[key]= value
obj
# Merge deeper objects?
defaults= (obj)->
for source in Array::slice.call(arguments, 1)
if source
for key,value of source
unless obj[key]?
obj[key]= value
else if type(obj[key]) is 'object'
obj[key]= defaults {}, obj[key], value
obj
type= do ->
toStr= Object::toString
elemParser= /\[object HTML(.*)\]/
classToType= {}
for name in "Boolean Number String Function Array Date RegExp Undefined Null NodeList".split(" ")
classToType["[object " + name + "]"] = name.toLowerCase()
(obj) ->
strType= toStr.call(obj)
if found= classToType[strType]
found
else if found= strType.match(elemParser)
found[1].toLowerCase()
else
"object"
validateOptionsCallback= (options, callback)->
if typeof options is 'function'
[{}, options]
else
[options, callback]
tryRequireResolve= (name, callback)->
try
path= require.resolve name
callback null, path
catch ex
localResolve name, callback
tryRequire= (name, callback)->
return callback(null, {}) if name is null or name is ''
return callback(null, loaded_libs[name]) if loaded_libs[name]?
try
lib= require name
loaded_libs[name]= lib
callback null, lib
catch ex
localRequire name, callback
tryRequireAll= (names, callback)->
return callback(null, []) if names.length is 0
libs=[]
libnames= names.slice()
nextLib= libnames.shift()
loader= (err, lib)->
return callback err, null if err?
libs.push lib
return callback null, libs if libnames.length is 0
nextLib= libnames.shift()
tryRequire nextLib, loader
tryRequire nextLib, loader
loaded_libs= {}
loading_now= {}
isAlreadyLoaded= (name, callback)->
if loaded_libs[name]?
callback(null, loaded_libs[name])
return true
if loading_now[name]?
loading_now[name].push callback
true
else
loading_now[name]= []
loading_now[name].push callback
false
localResolve= (name, callback)->
cmd= "#{process.execPath} -p -e \"require.resolve('#{ name }')\""
result= exec(cmd, silent:yes)
libpath= result.output.trim()
if result.code != 0 or libpath is ''
callback new Error("Could not load '#{name}' module. (no local path)")
else
callback null, libpath
localRequire= (name, callback)->
return false if isAlreadyLoaded(name, callback)
if name[..1] is './'
libpath= path.resolve(name)
try
lib= require libpath
loaded_libs[name]= lib
cb null, lib for cb in loading_now[name]
catch ex
cb ex, null for cb in loading_now[name]
delete loading_now[name]
else
localResolve name, (err, libpath)->
return (cb err, null for cb in loading_now[name]) if err?
try
lib= require libpath
loaded_libs[name]= lib
cb null, lib for cb in loading_now[name]
catch ex
cb ex, null for cb in loading_now[name]
delete loading_now[name]
true
module.exports= {
pp
extend
defaults
type
validateOptionsCallback
tryRequire
tryRequireAll
tryRequireResolve
localRequire
}
extend module.exports, util
+4
-0
build:
coffee -o lib/assembot -c src/assembot
oldbuild:
coffee -o lib -c src

@@ -8,2 +11,3 @@

push:

@@ -10,0 +14,0 @@ git push dropbox

+148
-28

@@ -1,38 +0,158 @@

# AssemBot Notes
# AssemBot Notes/Todos
## Version 0.2 - The Clean Up
- Add support for loading plugins from `assembot` block.
- Add support for excluding files from build (relative to source root).
- Add support for lifecyle events (good for plugin integration). All lifecycle
events would send the current `bot` instance as the first parameter. It should
emit a before/after event for each of these:
- scan
- renderItem
- render
- assemble
- write (or callback)
Move to a class based approach? So you can have something like:
Add listeners to `Assembot` class itself:
var package= AssemBot.createPackage('package.js', {
source: './source'
});
AssemBot.on 'before:renderItem', (bot, resource)->
# Do something with resource here...
Example:
```json
{
"assembot": {
"options": {
"plugins": ["./my-local-plugin", "plugin-from-npm"]
},
"targets": {
"public/app.js": {
"source": "./source",
"exclude": "test/*"
}
}
}
}
```
## Ideas
- Move from processors overwriting `resource.content` to having a
second property: `resource.rendered`. Default processors would
just take the content and assign it to rendered.
- Add support for including `./components` -- component.io style. More condusive
to AssemBot's build system style (already supports/expects common-js
modules).
Loads `component.json`, and includes the files referenced.
Converts `component-tip` to module path `component/tip`?
Or `elucidata-type` to `components/type` (all components under the `components/`
path, remove vendor prefix)?
List which components to load in the config block, or just include all locally
installed components automatically? If latter, would need to include an
exclusion filter.
{
"assembot": {
"options": {
"plugins": ["./my-local-plugin", "plugin-from-npm"],
"components": {
"path": "./components",
"exclude": "component-tip"
}
},
"targets": {
"public/app.js": {
"source": "./source",
"exclude": "test/*"
}
}
}
}
- Add hooks for plugins and processors to add to the resource list.
For example, if a template engine had a runtime, it could automatically add it
to the resource list for compilation to it's available without the need for an
external script tag.
Maybe add method to the `Processor` class like: `.runtime(modulePath, contentsOrPath)`?
addProcessor('js').ext('.settee')
.requires('settee-templates')
.runtime('engines/settee', CONTENT_OR_FILEPATH)
.build ->
# the rest...
package.build(function(err, content, sourcemap){
// Do want you want with it here.
});
Or, use lifecycle events:
settee_was_used= no
addProcessor('js').ext('.settee')
.requires('settee-templates')
.build ->
settee_was_used= yes
# the rest...
package.fileList(function(filelist){
// Array of file paths
});
// Override any settings you'd like
package.set({
minify: 1
});
AssemBot.on 'after:render', (bot)->
if settee_was_used
bot.resources.push new Resource 'runtime/settee.js', cat('settee.runtime.js')
Would it be better to base it on the source folder instead of the output file(s)?
var assembot= AssemBot.createFromSource('./source');
## Exploratory
### Packages
What would it take to make a custom package type?
For example a 'assembot-php' plugin:
```coffeescript
module.exports= (assembot, done)-> # (Not sure if done is really needed yet)
assembot.assembleCss(function(err, css){
// do with as you please, write to file, whatever.
});
assembot.assembleJs(function(err, js, srcMap){
// Same here
});
assemby.assembleAll(function(err, css, js, sourcemap){
// Whole shebang
});
assembot.addProcessor('php').ext('php')
.build -> (content, opts, done)->
done(null, content, opts) # just pass on through, no rendering required
assembot.addPackager('php') # new code needed for this...
.build (resources, options)->
result= ""
result += res.content for res in resources
result
```
Your build.json:
{
"assembot": {
"targets": {
"app-in-a-page.php": {
"source": "./source"
}
}
}
}
### Minifier
Make the minifier use the plugin system?
```coffeescript
assembot.on 'before:write', (bot)->
bot.content= results
```
- What if the plugin uses async code?
### Processors
Move the default processors into plugins?
Especially the ones that require a runtime?!
+15
-5
{
"name": "assembot",
"version": "0.1.6",
"version": "0.2.0",
"license": "MIT",
"description": "Simple asset assembly bot for compiling/combining client-side js and css files.",
"author": "Matt McCray <matt@elucidata.net>",
"main": "./lib/builder.js",
"main": "./lib/assembot/index.js",
"bin": {
"assembot": "./bin/assembot"
"assembot": "./bin/assembot",
"assembot-build": "./bin/assembot-build",
"assembot-debug": "./bin/assembot-debug",
"assembot-info": "./bin/assembot-info",
"assembot-init": "./bin/assembot-init",
"assembot-new": "./bin/assembot-new",
"assembot-serve": "./bin/assembot-serve"
},

@@ -28,5 +34,9 @@ "scripts": {

"express": "~3.1.0",
"optparse": "~1.0.4",
"marked": "~0.2.8"
"marked": "~0.2.8",
"commander": "~1.1.1",
"coffee-templates": "0.0.6",
"shelljs": "~0.1.2",
"minimatch": "~0.2.11",
"async": "~0.2.6"
}
}

@@ -40,3 +40,3 @@ # AssemBot

npm install
npm install assembot --save
./node_modules/.bin/assembot --build

@@ -47,3 +47,3 @@

AssemBot will try to enable support for transpiling `.coffee`, `.litcoffee`, `.eco`, `.dot`, `.ejs`, `.less`, `.styl` files and more. It will also assemble `.css`, `.js`, and `.html` files. Any `.html` files become a module that exports the contents of the file as a string. Stylus support will attempt to enable Nib by default as well.
AssemBot initially enables support for transpiling `.coffee`, `.litcoffee`, `.eco`, `.dot`, `.ejs`, `.less`, and `.styl` files. When using stylus, it will attempt to enable Nib by default as well.

@@ -54,4 +54,16 @@ ## Token Replacement

If you have `replaceTokens` set to `true`, AssemBot will attempt to replace all tokens in your sources files. It is enabled by default.
AssemBot will attempt to replace all tokens in your sources files. To disable this behavior, set `replaceTokens` to `false`.
## Embedded CSS
Supports compiling CSS into the JS package. Use `.ecss` (or `.estyl` or `.eless`) file extension. Generates a module you can use like this:
```coffeescript
require('my/view/styles').activate()
# EmbeddCSS API:
# .activate() - Appends a generated <style> tag to HEAD, BODY, or document
# .deactivate() - Removes the generated <style> tag
# .isActive() - Boolean
```
## Dev Server

@@ -58,0 +70,0 @@

// Generated by CoffeeScript 1.5.0
(function() {
var api, assemble_files, build_css_package, build_js_package, converter, defaults, do_header, do_minify, filelistForType, fs, outputTargets, path, project_root, uglify, _;
path = require('path');
fs = require('fs');
defaults = require('./defaults');
_ = require('./util');
converter = require('./converter');
project_root = process.cwd();
uglify = require("uglify-js");
do_minify = function(output_content, config) {
var settings;
if (config.minify) {
if (uglify != null) {
_.log("Minify... (" + config.output.target + ")");
try {
settings = {
fromString: true,
mangle: false
};
if (config.sourceMap) {
settings.outSourceMap = config.output.sourceMapName;
}
switch (config.minify) {
case 1:
case 'minify':
case 'min':
return uglify.minify(output_content, settings);
case 2:
case 'mangle':
case 'munge':
case 'compress':
settings.mangle = true;
return uglify.minify(output_content, settings);
default:
return {
code: output_content,
map: null
};
}
} catch (ex) {
_.log("Error in minify, skipping... (" + config.output.target + ")");
return {
code: output_content,
map: null
};
}
} else {
_.log("Can't minify (install uglify-js) (" + config.output.target + ")");
return {
code: output_content,
map: null
};
}
} else {
return {
code: output_content,
map: null
};
}
};
do_header = function(output_content, config) {
if (config.header) {
return "" + (converter.replaceTokens(config.header, config)) + "\n" + output_content;
} else {
return output_content;
}
};
outputTargets = function(info) {
var config, ext, output, targets;
targets = [];
for (output in info) {
config = info[output];
ext = path.extname(output);
if (ext === '.js' || ext === '.css') {
targets.push(output);
}
}
return targets;
};
module.exports = api = {
buildTargets: function(config, resolvePaths) {
var target, targets, targetsFP, _i, _len;
if (resolvePaths == null) {
resolvePaths = false;
}
this.prepConfig(config);
targets = outputTargets(config);
if (resolvePaths) {
targetsFP = [];
for (_i = 0, _len = targets.length; _i < _len; _i++) {
target = targets[_i];
targetsFP.push(path.resolve(target));
}
return targetsFP;
} else {
return targets;
}
},
buildPackage: function(config, callback) {
var target;
_.log("Assembling... (" + config.output.target + ")");
target = config.type;
try {
return assemble_files(target, config, function(err, src_tree) {
var minified, output_content;
output_content = target === '.js' ? build_js_package(src_tree, config) : build_css_package(src_tree, config);
minified = do_minify(output_content, config);
output_content = minified.code;
output_content = do_header(output_content, config);
return callback(null, output_content, minified.map);
});
} catch (ex) {
return callback(ex, null, null);
}
},
prepConfig: function(info, opts) {
var config, output, src;
if (opts == null) {
opts = {};
}
for (output in info) {
config = info[output];
_.extend(config, opts);
_.defaults(config, defaults.config);
config.type = 'meta';
config.projectRoot = project_root;
src = config.source;
if ((src != null) && typeof src === 'string') {
config.source = {
target: src,
path: path.resolve(src),
dir: "" + (path.resolve(src)) + path.sep
};
config.output = {
target: output,
name: path.basename(output),
path: path.resolve(output),
ext: path.extname(output),
dir: path.dirname(path.resolve(output)),
sourceMapName: "" + (path.basename(output)) + ".map",
sourceMapPath: "" + (path.resolve(output)) + ".map"
};
config.type = config.output.ext;
}
}
return info;
},
buildTarget: function(config, callback) {
if (config.type === '.js') {
return this.buildPackage(config, function(err, output, source_map) {
if (err != null) {
throw err;
}
if (callback != null) {
callback(err, output, source_map);
return;
}
if (!fs.existsSync(config.output.dir)) {
fs.mkdirSync(config.output.dir);
}
if ((source_map != null) && config.sourceMap) {
fs.writeFileSync(config.output.sourceMapPath, source_map, 'utf8');
_.log("SourceMap... (" + config.output.target + ")");
output += "\n//@ sourceMappingURL=" + config.output.sourceMapName;
}
fs.writeFileSync(config.output.path, output, 'utf8');
return _.log("Wrote: " + config.output.target);
});
} else if (config.type === '.css') {
return this.buildPackage(config, function(err, output) {
if (err != null) {
throw err;
}
if (callback != null) {
callback(err, output);
return;
}
if (!fs.existsSync(config.output.dir)) {
fs.mkdirSync(config.output.dir);
}
fs.writeFileSync(config.output.path, output, 'utf8');
return _.log("Wrote: " + config.output.target);
});
}
},
build: function(info, opts) {
var config, output, _results;
if (opts == null) {
opts = {};
}
_.puts("ASSEMBOT ACTIVATE!");
this.prepConfig(info, opts);
_results = [];
for (output in info) {
config = info[output];
_results.push(this.buildTarget(config));
}
return _results;
},
displayTargetTree: function(info, opts) {
var config, output, src_dir;
if (opts == null) {
opts = {};
}
_.puts("ASSEMBOT ACTIVATE!");
this.prepConfig(info, opts);
for (output in info) {
config = info[output];
_.puts("");
_.puts(output);
src_dir = path.dirname(config.source.path);
_.walkTree(config.source.path, function(file, fullpath) {
var ext;
ext = path.extname(file);
if (converter.validTypeFor(config.type, ext)) {
return _.puts(" " + (path.relative(src_dir, fullpath)));
}
});
}
return _.puts("");
},
displayModuleTree: function(info, opts) {
var config, output, src_dir;
if (opts == null) {
opts = {};
}
_.puts("ASSEMBOT ACTIVATE!");
this.prepConfig(info, opts);
for (output in info) {
config = info[output];
if (config.type === '.js') {
_.puts("");
_.puts("" + config.ident + " (in " + output + ")");
src_dir = path.dirname(config.source.path);
_.walkTree(config.source.path, function(file, fullpath) {
var ext;
ext = path.extname(file);
if (converter.validTypeFor(config.type, ext)) {
return _.puts(" " + (path.relative(config.source.path, fullpath).replace(ext, '')));
}
});
}
}
return _.puts("");
}
};
filelistForType = function(type, path, callback) {
var filelist;
filelist = [];
_.walkTree(path, function(file, fullpath) {
var ext;
ext = path.extname(file);
if (converter.validTypeFor(type, ext)) {
return filelist.push(fullpath);
}
});
return filelist;
};
assemble_files = function(type, info, callback) {
var build_count, ext, file, fullpath, libpath, local_info, output, pkg_list, src_dir, src_path, _i, _len;
src_path = info.source.path;
src_dir = "" + src_path + path.sep;
pkg_list = [];
output = {};
_.walkTree(src_path, function(file, fullpath) {
var ext;
ext = path.extname(file);
if (converter.validTypeFor(type, ext)) {
return pkg_list.push(fullpath);
}
});
build_count = 0;
for (_i = 0, _len = pkg_list.length; _i < _len; _i++) {
fullpath = pkg_list[_i];
file = path.basename(fullpath);
ext = path.extname(fullpath);
libpath = fullpath.replace(src_dir, '').replace(ext, '');
local_info = _.extend({}, info);
local_info.current_file = {
fullpath: fullpath,
filename: file,
loadpath: src_path,
ext: ext,
path: libpath
};
converter.buildSourceFor(type, fullpath, local_info, function(err, converted_source, opts) {
if (err != null) {
throw err;
}
build_count += 1;
output[opts.current_file.path] = converted_source;
if (build_count === pkg_list.length) {
return callback(null, output);
}
});
}
return pkg_list;
};
build_js_package = function(sources, opts) {
var autoStart, identifier, index, name, result, source, _ref, _ref1;
if (opts == null) {
opts = {};
}
identifier = (_ref = opts.ident) != null ? _ref : 'require';
autoStart = (_ref1 = opts.autoStart) != null ? _ref1 : false;
result = "(function(/*! Stitched by Assembot !*/) {\n if (!this." + identifier + ") {\n var modules = {}, cache = {}, moduleList= function() {\n var names= [];\n for( var name in modules ) {\n names.push(name);\n }\n return names;\n }, require = function(name, root) {\n var path = expand(root, name), module = cache[path], fn;\n if (module) {\n return module.exports;\n } else if (fn = modules[path] || modules[path = expand(path, './index')]) {\n module = {id: path, exports: {}};\n try {\n cache[path] = module;\n var localRequire= function(name) {\n return require(name, dirname(path));\n }\n localRequire.modules= moduleList;\n fn(module.exports, localRequire, module);\n return module.exports;\n } catch (err) {\n delete cache[path];\n throw err;\n }\n } else {\n throw 'module \\'' + name + '\\' not found';\n }\n }, expand = function(root, name) {\n var results = [], parts, part;\n if (/^\\.\\.?(\\/|$)/.test(name)) {\n parts = [root, name].join('/').split('/');\n } else {\n parts = name.split('/');\n }\n for (var i = 0, length = parts.length; i < length; i++) {\n part = parts[i];\n if (part == '..') {\n results.pop();\n } else if (part != '.' && part != '') {\n results.push(part);\n }\n }\n return results.join('/');\n }, dirname = function(path) {\n return path.split('/').slice(0, -1).join('/');\n };\n this." + identifier + " = function(name) {\n return require(name, '');\n }\n this." + identifier + ".define = function(bundle) {\n for (var key in bundle)\n modules[key] = bundle[key];\n };\n this." + identifier + ".modules= moduleList;\n }\n return this." + identifier + ".define;\n}).call(this)({\n";
index = 0;
for (name in sources) {
source = sources[name];
result += index++ === 0 ? "" : ",\n";
result += JSON.stringify(name);
result += ": function(exports, require, module) {" + source + "}";
}
result += "});\n";
if (autoStart) {
result += "this." + identifier + "('" + autoStart + "');\n";
}
return result;
};
build_css_package = function(sources, opts) {
var content, key, results;
if (opts == null) {
opts = {};
}
results = "";
for (key in sources) {
content = sources[key];
results += "/* " + key + " */\n";
results += content;
results += "\n\n";
}
return results;
};
}).call(this);
// Generated by CoffeeScript 1.5.0
/*
AssemBot CLI!
*/
(function() {
var builder, defaults, fs, optparse, path, server, _;
path = require('path');
fs = require('fs');
_ = require('./util');
builder = require('./builder');
server = require('./server');
defaults = require('./defaults');
optparse = require('optparse');
module.exports = {
run: function() {
var assbot_conf, assembot_info, buildTo, command, config, empty, nfo, options, parser, project_root, template;
command = 'help';
buildTo = {
source: null,
js: null,
css: null
};
project_root = process.cwd();
assembot_info = require('../package');
nfo = (function() {
try {
return require("" + project_root + path.sep + "package");
} catch (ex) {
_.puts("No 'package.json' file found, using defaults!");
return empty = {
assembot: _.extend({}, defaults.assembot)
};
}
})();
assbot_conf = nfo.assembot == null ? (_.puts("No 'assembot' block in your package.json file found, using defaults!"), _.extend({}, defaults.assembot)) : nfo.assembot;
options = _.defaults({}, assbot_conf.options || {}, defaults.options);
delete assbot_conf.options;
parser = new optparse.OptionParser([['-b', '--build', 'Run build'], ['-s', '--serve', 'Run dev server'], ['-f', '--files', 'Shows the build targets and associated files'], ['-d', '--debug', 'Shows internal build config data'], ['-p', '--port [PORT]', "Set dev server port"], ['-r', '--root [PATH]', 'Set dev server root path'], ['-m', '--minify [LEVEL]', 'Force minification 0=none 1=minify 2=mangle'], ['-c', '--modules', 'Shows the commonjs modules for .js build targets'], ['-v', '--version', 'Shows version number'], ['-h', '--help', 'Shows help'], ['--init', 'Creates a package.json, if missing'], ['--source [PATH]', 'Set source folder'], ['--js [PATH]', 'Export js package from source'], ['--css [PATH]', 'Export css package from source']]);
parser.banner = 'Usage: assembot [options]';
parser.on('build', function(name, value) {
return command = name;
});
parser.on('help', function(name, value) {
return command = name;
});
parser.on('debug', function(name, value) {
return command = name;
});
parser.on('files', function(name, value) {
return command = name;
});
parser.on('init', function(name, value) {
return command = name;
});
parser.on('minify', function(name, value) {
return options.minify = parseInt(value || "1");
});
parser.on('modules', function(name, value) {
return command = name;
});
parser.on('port', function(name, value) {
return options.port = value;
});
parser.on('serve', function(name, value) {
return command = name;
});
parser.on('version', function(name, value) {
return command = name;
});
parser.on('js', function(name, value) {
return buildTo[name] = value;
});
parser.on('css', function(name, value) {
return buildTo[name] = value;
});
parser.on('*', function(name, value) {
return _.puts("Unknown option: " + name);
});
parser.on('root', function(name, value) {
var newRoot;
newRoot = path.resolve(value);
if (fs.existsSync(newRoot)) {
return options.wwwRoot = newRoot;
} else {
return _.log("Not a valid path: " + newRoot);
}
});
parser.on('source', function(name, value) {
command = name;
return buildTo.source = value;
});
parser.parse(process.argv);
if (command === 'serve') {
return server.serve(assbot_conf, options);
} else if (command === 'build') {
return builder.build(assbot_conf, options);
} else if (command === 'files') {
return builder.displayTargetTree(assbot_conf, options);
} else if (command === 'modules') {
return builder.displayModuleTree(assbot_conf, options);
} else if (command === 'debug') {
builder.prepConfig(assbot_conf, options);
return _.pp(assbot_conf);
} else if (command === 'version') {
return _.puts(assembot_info.version);
} else if (command === 'init') {
_.puts("ASSEMBOT! Bleep, bloop!\nv" + assembot_info.version + "\n");
if (fs.existsSync('./package.json')) {
return _.puts("package.json already exists.");
} else {
_.puts("Creating a default package.json for you...");
assembot_conf.options = defaults.options;
template = {
name: path.basename(process.cwd()),
version: "1.0.0",
license: "",
description: "",
author: "",
assembot: assbot_conf
};
fs.writeFileSync(path.resolve('./package.json'), JSON.stringify(template, null, 2));
return _.puts('Done.');
}
} else if (command === 'source') {
config = {};
if (buildTo.js != null) {
config[buildTo.js] = _.extend({}, defaults.config, {
source: buildTo.source
});
}
if (buildTo.css != null) {
config[buildTo.css] = _.extend({}, defaults.config, {
source: buildTo.source
});
return builder.build(config, options);
}
} else {
_.puts("ASSEMBOT! Bleep, bloop!\nv" + assembot_info.version + "\n");
return _.puts(parser.toString());
}
}
};
}).call(this);
// Generated by CoffeeScript 1.5.0
(function() {
var addConvertor, addConvertorOLD, addCssConvertor, addJsConvertor, api, assembot_package, fs, path, project_package, project_root, type_db, validType, _;
path = require('path');
fs = require('fs');
_ = require('./util');
project_root = process.cwd();
assembot_package = require('../package');
project_package = (function() {
try {
return require("" + project_root + path.sep + "package");
} catch (ex) {
return {};
}
})();
type_db = {
".js": {
types: [],
handlers: {}
},
".css": {
types: [],
handlers: {}
}
};
validType = function(target) {
if (target[0] === '.') {
return target;
} else {
return "." + target;
}
};
module.exports = api = {
debug: function() {
return _.pp(type_db);
},
addFor: function(target, type, converter) {
target = validType(target);
type = validType(type);
type_db[target].types.push(type);
type_db[target].handlers[type] = converter;
return this;
},
validTypeFor: function(target, ext) {
var type;
target = validType(target);
type = validType(ext);
if (type_db[target] != null) {
return type_db[target].types.indexOf(type) >= 0;
} else {
return false;
}
},
buildSourceFor: function(target, fullpath, info, callback) {
var converter, ext, source;
target = validType(target);
ext = path.extname(fullpath);
source = fs.readFileSync(fullpath, 'utf8');
converter = type_db[target].handlers[ext];
converter(this.replaceTokens(String(source), info), info, callback);
return this;
},
tokenParser: /(\{%\-([ a-zA-Z0-9\._]*)\-%\})/g,
replaceTokens: function(string, info) {
if (info.replaceTokens && this.tokenParser.test(string)) {
return string.replace(this.tokenParser, function(match, token, value, loc, src) {
var data, first_part, key, part, parts, _i, _len;
data = info;
parts = value.split('.');
first_part = parts.shift().trim();
switch (first_part) {
case 'package':
data = project_package;
break;
case 'assembot':
data = assembot_package;
break;
case 'NOW':
data = new Date();
break;
default:
data = info[first_part];
}
for (_i = 0, _len = parts.length; _i < _len; _i++) {
part = parts[_i];
key = part.trim();
data = data[key];
}
return String(data);
});
} else {
return string;
}
}
};
addConvertorOLD = function(target, type, modules, handler) {
var args, converter;
if (!_.isArray(modules)) {
modules = [modules];
}
args = [];
if (modules.length > 0) {
api.addFor(target, type, function(source, opts, callback) {
var module, _i, _len, _results;
_results = [];
for (_i = 0, _len = modules.length; _i < _len; _i++) {
module = modules[_i];
_results.push(_.tryRequire(module, function(err, lib) {
var converter, file, subHandler;
if (err != null) {
file = "" + opts.current_file.path + opts.current_file.ext;
_.pp(err);
throw "Cannot transpile " + file + ": Module(s) '" + (modules.join("'")) + "' cannot be loaded! " + err;
}
args.push(lib);
if (args.length >= modules.length) {
converter = handler.apply(handler, args);
subHandler = function(s, o, c) {
try {
return converter(s, o, c);
} catch (ex) {
file = "" + o.current_file.path + o.current_file.ext;
return c(new Error("Transpiler error for " + file + ": " + ex.message), null, o);
}
};
api.addFor(target, type, subHandler);
return subHandler(source, opts, callback);
}
}));
}
return _results;
});
} else {
converter = handler.apply(handler, args);
api.addFor(target, type, function(s, o, c) {
var file;
try {
return converter(s, o, c);
} catch (ex) {
file = "" + o.current_file.path + o.current_file.ext;
return c(new Error("Transpiler error for " + file + ": " + ex.message), null, o);
}
});
}
return true;
};
addConvertor = function(target, type, modules, handler) {
var loading, queue;
if (!_.isArray(modules)) {
modules = [modules];
}
loading = false;
queue = [];
return api.addFor(target, type, function(origSrc, origOpts, origCallback) {
queue.push([origSrc, origOpts, origCallback]);
if (!loading) {
loading = true;
return _.tryRequireAll(modules, function(err, libs) {
var arglist, converter, safeHandler, _i, _len, _results;
if (err != null) {
throw "Module(s) '" + (modules.join("'")) + "' cannot be loaded! " + err;
}
converter = handler.apply(handler, libs);
safeHandler = function(src, opts, callback) {
var file;
try {
return converter(src, opts, callback);
} catch (ex) {
file = "" + opts.current_file.path + opts.current_file.ext;
return c(new Error("Transpiler error for " + file + ": " + ex.message), null, opts);
}
};
api.addFor(target, type, safeHandler);
_results = [];
for (_i = 0, _len = queue.length; _i < _len; _i++) {
arglist = queue[_i];
_results.push(safeHandler.apply(safeHandler, arglist));
}
return _results;
});
}
});
};
addJsConvertor = function(type, modules, handler) {
var thisType, _i, _len;
if (_.isArray(type)) {
for (_i = 0, _len = type.length; _i < _len; _i++) {
thisType = type[_i];
addConvertor('js', thisType, modules, handler);
}
} else {
addConvertor('js', type, modules, handler);
}
return true;
};
addCssConvertor = function(type, modules, handler) {
return addConvertor('css', type, modules, handler);
};
addJsConvertor('.js', [], function() {
return function(source, opts, converted) {
return converted(null, source, opts);
};
});
addJsConvertor('.html', [], function() {
return function(source, opts, converted) {
return converted(null, "module.exports=" + (JSON.stringify(source)) + ";", opts);
};
});
addJsConvertor('.json', [], function() {
return function(source, opts, converted) {
var data;
data = JSON.parse(source);
return converted(null, "module.exports=" + (JSON.stringify(data)) + ";", opts);
};
});
addJsConvertor(['.coffee', '.litcoffee'], 'coffee-script', function(coffee) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.coffee || {}, {
bare: true
});
options.literate = opts.current_file.ext === '.litcoffee' || false;
output = coffee.compile(source, options);
return converted(null, output, opts);
};
});
addJsConvertor('.eco', 'eco', function(eco) {
return function(source, opts, converted) {
var output;
output = eco.precompile(source);
return converted(null, "module.exports= " + output + ";", opts);
};
});
addJsConvertor('.ejs', 'ejs', function(ejs) {
return function(source, opts, converted) {
var output;
output = ejs.compile(source, {
client: true,
compileDebug: false
});
return converted(null, "module.exports= " + (output.toString()) + ";", opts);
};
});
addJsConvertor('.handlebars', 'handlebars', function(handlebars) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.handlebars || {}, {
simple: false,
commonjs: true
});
output = handlebars.precompile(source, options);
return converted(null, "module.exports= " + (output.toString()) + ";", opts);
};
});
addJsConvertor('.jade', 'jade', function(jade) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.jade || {}, {
client: true,
compileDebug: false
});
output = jade.compile(source, options);
return converted(null, "module.exports= " + (output.toString()) + ";", opts);
};
});
addJsConvertor('.hogan', 'hogan.js', function(hogan) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.hogan || {}, {
asString: 1
});
output = hogan.compile(source, options);
return converted(null, "module.exports= new Hogan.Template(" + (output.toString()) + ");", opts);
};
});
addJsConvertor('.dot', 'doT', function(dot) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.dot || opts.doT || {}, {});
output = dot.compile(source, options);
return converted(null, "module.exports= " + (output.toString()), opts);
};
});
addJsConvertor(['.md', 'markdown'], 'marked', function(marked) {
return function(source, opts, converted) {
var options, output;
options = _.defaults({}, opts.marked || {}, {
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true
});
output = marked(source, options);
return converted(null, "module.exports=" + (JSON.stringify(output)) + ";", opts);
};
});
addCssConvertor('.css', [], function() {
return function(source, opts, converted) {
return converted(null, source, opts);
};
});
addCssConvertor('.less', 'less', function(less) {
return function(source, opts, converted) {
return less.render(source, function(err, css) {
if (err != null) {
converted(err, null, opts);
}
return converted(null, css, opts);
});
};
});
addCssConvertor('.styl', ['stylus', 'nib'], function(stylus, nib) {
var load_paths;
load_paths = [process.cwd(), path.dirname(__dirname)];
return function(source, opts, converted) {
var options;
options = _.defaults({}, opts.marked || {}, {
filename: opts.current_file.filename || 'generated.css',
paths: load_paths
});
return stylus(source).set('filename', opts.current_file.filename || 'generated.css').set('paths', load_paths).set(options).use(nib()).render(function(err, css) {
if (err != null) {
return converted(err, null, opts);
} else {
return converted(null, css, opts);
}
});
};
});
}).call(this);
// Generated by CoffeeScript 1.5.0
(function() {
var _;
_ = require('./util');
exports.config = {
source: './source',
ident: 'require',
autoStart: false,
minify: 0,
sourceMap: false,
header: "/* Assembled by AssemBot {%- assembot.version -%} */",
replaceTokens: true,
coffee: {
bare: true,
literate: false
}
};
exports.options = {
port: 8080,
wwwRoot: './public'
};
exports.assembot = {
"public/app.js": _.extend({}, exports.config),
"public/theme.css": _.extend({}, exports.config)
};
}).call(this);
// Generated by CoffeeScript 1.5.0
(function() {
var builder, express, fs, getConfigFor, inspect, path, print, puts, _, _ref;
express = require('express');
fs = require('fs');
path = require('path');
builder = require('./builder');
_ = require('./util');
_ref = require('./util'), puts = _ref.puts, print = _ref.print, inspect = _ref.inspect;
getConfigFor = function(path, info) {
var config, output;
for (output in info) {
config = info[output];
if (config.text !== 'meta') {
if (config.output.path === path) {
return config;
}
}
}
};
exports.serve = function(config, opts) {
var app, port, project_root, root, targets;
if (opts == null) {
opts = {};
}
puts("Setting up dev server...");
targets = builder.buildTargets(config, true);
app = express();
port = config.port || opts.port || 8080;
project_root = process.cwd();
root = path.resolve(opts.wwwRoot || config.wwwRoot || ("" + project_root + "/public"));
puts(" root: " + root);
puts(" port: " + port);
app.get('/*', function(req, res) {
var conf, localpath, uri;
uri = req.params[0] || 'index.html';
localpath = path.join(root, uri);
if (targets.indexOf(localpath) >= 0) {
conf = getConfigFor(localpath, config);
return builder.buildTarget(conf, function(err, content) {
if (err != null) {
return res.send(500, String(err));
} else {
return res.send(200, content);
}
});
} else {
if (fs.existsSync(localpath)) {
return res.sendfile(localpath);
} else {
return res.send(404, "Not Found");
}
}
});
app.use(express.errorHandler({
dumpExceptions: true,
showStack: true
}));
app.listen(port);
return puts(" Ready! Visit http://127.0.0.1:" + port);
};
}).call(this);
// Generated by CoffeeScript 1.5.0
(function() {
var exec, fs, loaded_libs, loading_now, localRequire, path, spawn, util, walk, _;
util = require('util');
fs = require('fs');
path = require('path');
spawn = require('child_process').spawn;
exec = require('child_process').exec;
exports.pp = function(obj) {
return util.puts(util.inspect(obj));
};
exports.extend = function(obj) {
var key, source, value, _i, _len, _ref;
_ref = Array.prototype.slice.call(arguments, 1);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
source = _ref[_i];
if (source) {
for (key in source) {
value = source[key];
obj[key] = value;
}
}
}
return obj;
};
exports.defaults = function(obj) {
var key, source, value, _i, _len, _ref;
_ref = Array.prototype.slice.call(arguments, 1);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
source = _ref[_i];
if (source) {
for (key in source) {
value = source[key];
if (obj[key] == null) {
obj[key] = value;
}
}
}
}
return obj;
};
exports.walkTree = walk = function(dir, callback, files_only) {
var file_list, filename, fullpath, stat, _i, _len;
if (files_only == null) {
files_only = true;
}
file_list = fs.readdirSync(dir);
for (_i = 0, _len = file_list.length; _i < _len; _i++) {
filename = file_list[_i];
fullpath = [dir, filename].join(path.sep);
stat = fs.statSync(fullpath);
if (stat.isDirectory()) {
if (!files_only) {
callback(filename, fullpath, true);
}
walk(fullpath, callback);
} else {
callback(filename, fullpath, false);
}
}
return file_list;
};
exports.tryRequire = function(name, callback) {
var lib;
if (name === null || name === '') {
callback(null, {});
return;
}
if (loaded_libs[name] != null) {
callback(null, loaded_libs[name]);
return;
}
try {
lib = require(name);
loaded_libs[name] = lib;
return callback(null, lib);
} catch (ex) {
return localRequire(name, callback);
}
};
exports.tryRequireAll = function(names, callback) {
var libnames, libs, loader, nextLib;
if (names.length === 0) {
callback(null, []);
return;
}
libs = [];
libnames = names.slice();
nextLib = libnames.shift();
loader = function(err, lib) {
if (err != null) {
return callback(err, null);
} else {
libs.push(lib);
if (libnames.length === 0) {
return callback(null, libs);
} else {
nextLib = libnames.shift();
return exports.tryRequire(nextLib, loader);
}
}
};
return exports.tryRequire(nextLib, loader);
};
_ = exports;
loaded_libs = {};
loading_now = {};
localRequire = function(name, callback) {
var child, cmd;
if (loaded_libs[name] != null) {
callback(null, loaded_libs[name]);
return;
}
if (loading_now[name] != null) {
loading_now[name].push(callback);
return;
} else {
loading_now[name] = [];
loading_now[name].push(callback);
}
cmd = "" + process.execPath + " -p -e \"require.resolve('" + name + "')\"";
child = exec(cmd, function(stdin, stdout, stderr) {
var cb, err, lib, libpath, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
libpath = stdout.trim();
if (libpath === '') {
err = new Error("Could not load '" + name + "' module. (no local path)");
_ref = loading_now[name];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
cb = _ref[_i];
cb(err, null);
}
delete loading_now[name];
}
try {
lib = require(libpath);
loaded_libs[name] = lib;
_ref1 = loading_now[name];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
cb = _ref1[_j];
cb(null, lib);
}
return delete loading_now[name];
} catch (ex) {
_ref2 = loading_now[name];
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
cb = _ref2[_k];
cb(ex, null);
}
return delete loading_now[name];
}
});
return true;
};
exports.extend(exports, util);
}).call(this);
path= require 'path'
fs= require 'fs'
defaults= require './defaults'
_= require './util'
converter= require './converter'
project_root= process.cwd()
uglify= require "uglify-js"
do_minify= (output_content, config)->
if config.minify
if uglify?
_.log "Minify... (#{ config.output.target })"
try
settings= fromString: true, mangle:false
settings.outSourceMap= config.output.sourceMapName if config.sourceMap
switch config.minify
when 1, 'minify', 'min'
uglify.minify( output_content, settings )
when 2, 'mangle', 'munge', 'compress'
settings.mangle= true
uglify.minify( output_content, settings )
else
code:output_content, map:null
catch ex
_.log "Error in minify, skipping... (#{ config.output.target })"
code:output_content, map:null
else
_.log "Can't minify (install uglify-js) (#{ config.output.target })"
code:output_content, map:null
else
code:output_content, map:null
do_header= (output_content, config)->
if config.header
"#{converter.replaceTokens(config.header, config)}\n#{output_content}"
else
output_content
outputTargets= (info)->
targets=[]
for output, config of info
ext= path.extname(output)
targets.push( output ) if ext is '.js' or ext is '.css'
targets
module.exports= api=
buildTargets: (config, resolvePaths=no)->
@prepConfig(config)
targets= outputTargets(config)
if resolvePaths
targetsFP= []
for target in targets
targetsFP.push path.resolve(target)
targetsFP
else
targets
buildPackage: (config, callback)->
_.log "Assembling... (#{ config.output.target })"
target= config.type
try
assemble_files target, config, (err, src_tree)->
output_content= if target is '.js'
build_js_package src_tree, config
else
build_css_package src_tree, config
minified= do_minify(output_content, config)
output_content= minified.code
output_content= do_header(output_content, config)
callback null, output_content, minified.map
catch ex
callback ex, null, null
prepConfig: (info, opts={})->
for output, config of info
_.extend config, opts
_.defaults config, defaults.config
config.type= 'meta'
config.projectRoot= project_root
src= config.source
if src? and typeof src is 'string'
config.source=
target: src
path: path.resolve(src)
dir: "#{path.resolve(src)}#{path.sep}"
config.output=
target: output
name: path.basename(output)
path: path.resolve(output)
ext: path.extname(output)
dir: path.dirname(path.resolve(output))
sourceMapName: "#{ path.basename(output) }.map"
sourceMapPath: "#{ path.resolve(output) }.map"
config.type= config.output.ext
# _.pp info
info
buildTarget: (config, callback)->
if config.type is '.js'
@buildPackage config, (err, output, source_map)->
throw err if err?
if callback?
callback(err, output, source_map)
return
fs.mkdirSync config.output.dir unless fs.existsSync config.output.dir
if source_map? and config.sourceMap
fs.writeFileSync config.output.sourceMapPath, source_map, 'utf8'
_.log "SourceMap... (#{ config.output.target })"
output += "\n//@ sourceMappingURL=#{config.output.sourceMapName}"
#console.log source_map
fs.writeFileSync config.output.path, output, 'utf8'
_.log "Wrote: #{ config.output.target }"
else if config.type is '.css'
@buildPackage config, (err, output)->
throw err if err?
if callback?
callback(err, output)
return
fs.mkdirSync config.output.dir unless fs.existsSync config.output.dir
fs.writeFileSync config.output.path, output, 'utf8'
_.log "Wrote: #{ config.output.target }"
build: (info, opts={})->
_.puts "ASSEMBOT ACTIVATE!"
@prepConfig info, opts
for output, config of info
@buildTarget config
displayTargetTree: (info, opts={})->
_.puts "ASSEMBOT ACTIVATE!"
@prepConfig info, opts
for output, config of info
# unless config.type is 'meta'
_.puts ""
_.puts output
src_dir= path.dirname config.source.path
_.walkTree config.source.path, (file, fullpath)->
ext= path.extname file
if converter.validTypeFor config.type, ext
_.puts " #{path.relative(src_dir, fullpath)}"
_.puts ""
displayModuleTree: (info, opts={})->
_.puts "ASSEMBOT ACTIVATE!"
@prepConfig info, opts
for output, config of info
# unless config.type is 'meta'
if config.type is '.js'
_.puts ""
_.puts "#{ config.ident } (in #{output})"
src_dir= path.dirname config.source.path
_.walkTree config.source.path, (file, fullpath)->
ext= path.extname file
if converter.validTypeFor config.type, ext
_.puts " #{path.relative(config.source.path, fullpath).replace(ext, '')}"
_.puts ""
filelistForType= (type, path, callback)->
filelist= []
_.walkTree path, (file, fullpath)->
ext= path.extname file
if converter.validTypeFor type, ext
filelist.push fullpath
filelist
assemble_files= (type, info, callback)->
src_path= info.source.path
src_dir= "#{ src_path }#{ path.sep }"
pkg_list= []
output={}
_.walkTree src_path, (file, fullpath)->
ext= path.extname file
if converter.validTypeFor type, ext
pkg_list.push fullpath
build_count= 0
# _.pp pkg_list
for fullpath in pkg_list
file= path.basename(fullpath)
ext= path.extname(fullpath)
libpath= fullpath.replace(src_dir, '').replace(ext, '')
local_info= _.extend {}, info
local_info.current_file= fullpath:fullpath, filename:file, loadpath:src_path, ext:ext, path:libpath
converter.buildSourceFor type, fullpath, local_info, (err, converted_source, opts)->
throw err if err?
build_count += 1
output[opts.current_file.path]= converted_source
# _.puts " - #{opts.current_file.filename} (#{build_count}/#{pkg_list.length})" # if verbose
if build_count == pkg_list.length
callback null, output
# converter.debug()
pkg_list
build_js_package= (sources, opts={})->
identifier= opts.ident ? 'require'
autoStart= opts.autoStart ? false
result = """
(function(/*! Stitched by Assembot !*/) {
if (!this.#{identifier}) {
var modules = {}, cache = {}, moduleList= function() {
var names= [];
for( var name in modules ) {
names.push(name);
}
return names;
}, require = function(name, root) {
var path = expand(root, name), module = cache[path], fn;
if (module) {
return module.exports;
} else if (fn = modules[path] || modules[path = expand(path, './index')]) {
module = {id: path, exports: {}};
try {
cache[path] = module;
var localRequire= function(name) {
return require(name, dirname(path));
}
localRequire.modules= moduleList;
fn(module.exports, localRequire, module);
return module.exports;
} catch (err) {
delete cache[path];
throw err;
}
} else {
throw 'module \\'' + name + '\\' not found';
}
}, expand = function(root, name) {
var results = [], parts, part;
if (/^\\.\\.?(\\/|$)/.test(name)) {
parts = [root, name].join('/').split('/');
} else {
parts = name.split('/');
}
for (var i = 0, length = parts.length; i < length; i++) {
part = parts[i];
if (part == '..') {
results.pop();
} else if (part != '.' && part != '') {
results.push(part);
}
}
return results.join('/');
}, dirname = function(path) {
return path.split('/').slice(0, -1).join('/');
};
this.#{identifier} = function(name) {
return require(name, '');
}
this.#{identifier}.define = function(bundle) {
for (var key in bundle)
modules[key] = bundle[key];
};
this.#{identifier}.modules= moduleList;
}
return this.#{identifier}.define;
}).call(this)({\n
"""
index = 0
for name, source of sources
result += if index++ is 0 then "" else ",\n"
result += JSON.stringify name
result += ": function(exports, require, module) {#{source}}"
result += """
});\n
"""
result += "this.#{identifier}('#{autoStart}');\n" if autoStart
result
build_css_package= (sources, opts={})->
results= ""
for key, content of sources
results += "/* #{key} */\n"
results += content
results += "\n\n"
results
###
AssemBot CLI!
###
path= require 'path'
fs= require 'fs'
_= require './util'
builder= require './builder'
server= require './server'
defaults= require './defaults'
optparse = require 'optparse'
# process.on 'uncaughtException', (ex)->
# _.log "DANGER!"
# _.pp ex
module.exports=
run: ->
command= 'help'
buildTo= source:null, js:null, css:null
project_root= process.cwd()
assembot_info= require '../package'
nfo= try
require "#{project_root}#{path.sep}package"
catch ex
_.puts "No 'package.json' file found, using defaults!"
empty=
assembot: _.extend {}, defaults.assembot
assbot_conf= unless nfo.assembot?
_.puts "No 'assembot' block in your package.json file found, using defaults!"
_.extend {}, defaults.assembot
else
nfo.assembot
options= _.defaults {}, (assbot_conf.options || {}), defaults.options
delete assbot_conf.options
parser = new optparse.OptionParser [
['-b', '--build', 'Run build']
['-s', '--serve', 'Run dev server']
['-f', '--files', 'Shows the build targets and associated files']
['-d', '--debug', 'Shows internal build config data']
['-p', '--port [PORT]', "Set dev server port"]
['-r', '--root [PATH]', 'Set dev server root path']
['-m', '--minify [LEVEL]', 'Force minification 0=none 1=minify 2=mangle']
['-c', '--modules', 'Shows the commonjs modules for .js build targets']
['-v', '--version', 'Shows version number']
['-h', '--help', 'Shows help']
[ '--init', 'Creates a package.json, if missing']
[ '--source [PATH]', 'Set source folder']
[ '--js [PATH]', 'Export js package from source']
[ '--css [PATH]', 'Export css package from source']
# [ '--out', 'Build to STDOUT']
]
parser.banner = 'Usage: assembot [options]';
parser.on 'build', (name, value)-> command= name
parser.on 'help', (name, value)-> command= name
parser.on 'debug', (name, value)-> command= name
parser.on 'files', (name, value)-> command= name
parser.on 'init', (name, value)-> command= name
parser.on 'minify', (name, value)-> options.minify= parseInt value || "1"
parser.on 'modules', (name, value)-> command= name
parser.on 'port', (name, value)-> options.port= value
parser.on 'serve', (name, value)-> command= name
parser.on 'version', (name, value)-> command= name
parser.on 'js', (name, value)-> buildTo[name]= value
parser.on 'css', (name, value)-> buildTo[name]= value
parser.on '*', (name, value)-> _.puts "Unknown option: #{name}"
parser.on 'root', (name, value)->
newRoot= path.resolve(value)
if fs.existsSync newRoot
options.wwwRoot= newRoot
else
_.log "Not a valid path: #{ newRoot }"
parser.on 'source', (name, value)->
command= name
buildTo.source= value
parser.parse process.argv
if command is 'serve'
server.serve assbot_conf, options
else if command is 'build'
builder.build assbot_conf, options
else if command is 'files'
builder.displayTargetTree assbot_conf, options
else if command is 'modules'
builder.displayModuleTree assbot_conf, options
else if command is 'debug'
builder.prepConfig assbot_conf, options
_.pp assbot_conf
else if command is 'version'
_.puts assembot_info.version
else if command is 'init'
_.puts """
ASSEMBOT! Bleep, bloop!
v#{ assembot_info.version }
"""
if fs.existsSync './package.json'
_.puts "package.json already exists."
else
_.puts "Creating a default package.json for you..."
assembot_conf.options= defaults.options
template=
name: path.basename(process.cwd())
version: "1.0.0"
license: ""
description: ""
author: ""
assembot: assbot_conf
# _.puts JSON.stringify(template, null, 2)
fs.writeFileSync path.resolve('./package.json'), JSON.stringify(template, null, 2)
_.puts 'Done.'
else if command is 'source'
config={}
if buildTo.js?
config[buildTo.js]= _.extend {}, defaults.config, source:buildTo.source
if buildTo.css?
config[buildTo.css]= _.extend {}, defaults.config, source:buildTo.source
builder.build config, options
else
_.puts """
ASSEMBOT! Bleep, bloop!
v#{ assembot_info.version }
"""
_.puts parser.toString()
path= require 'path'
fs= require 'fs'
_= require './util'
project_root= process.cwd()
assembot_package= require '../package'
project_package= try
require "#{project_root}#{path.sep}package"
catch ex
{}
type_db=
".js":
types: []
handlers: {}
".css":
types: []
handlers: {}
# Must be a file extension
validType= (target)->
if target[0] is '.'
target
else
".#{ target }"
# The public API
module.exports= api=
debug: ->
_.pp type_db
addFor: (target, type, converter)->
target= validType(target)
type= validType(type)
type_db[target].types.push type
type_db[target].handlers[type]= converter
@
validTypeFor: (target, ext)->
target= validType(target)
type= validType(ext)
if type_db[target]? then type_db[target].types.indexOf(type) >= 0 else false
# Example:
# convertor.buildSourceFor 'js', '/X.coffee', {}, (err, src, info)-> log src
buildSourceFor: (target, fullpath, info, callback)->
target= validType(target)
ext= path.extname(fullpath)
source= fs.readFileSync fullpath, 'utf8'
converter= type_db[target].handlers[ext]
converter @replaceTokens(String(source), info), info, callback
@
tokenParser: /(\{%\-([ a-zA-Z0-9\._]*)\-%\})/g
replaceTokens: (string, info)->
if info.replaceTokens and @tokenParser.test(string)
string.replace @tokenParser, (match, token, value, loc, src)->
data= info
parts= value.split('.')
first_part= parts.shift().trim()
switch first_part
when 'package' then data= project_package
when 'assembot' then data= assembot_package
when 'NOW' then data= new Date()
else
data= info[first_part]
for part in parts
key= part.trim()
data= data[key]
String(data)
else
string
#
# Default Converters:
#
addConvertorOLD= (target, type, modules, handler)->
modules= [modules] unless _.isArray modules
args= []
if modules.length > 0
api.addFor target, type, (source,opts,callback)->
for module in modules
_.tryRequire module, (err, lib)->
if err?
# Could not load requirement
file= "#{ opts.current_file.path }#{ opts.current_file.ext }"
_.pp err
throw "Cannot transpile #{file}: Module(s) '#{ modules.join "'"}' cannot be loaded! #{err}"
args.push lib
if args.length >= modules.length
converter= handler.apply handler, args
subHandler= (s,o,c)->
try
converter(s,o,c)
catch ex
file= "#{ o.current_file.path }#{ o.current_file.ext }"
c new Error("Transpiler error for #{ file }: #{ ex.message }"), null, o
api.addFor target, type, subHandler
subHandler source, opts, callback
else
converter= handler.apply handler, args
api.addFor target, type, (s,o,c)->
try
converter(s,o,c)
catch ex
file= "#{ o.current_file.path }#{ o.current_file.ext }"
c new Error("Transpiler error for #{ file }: #{ ex.message }"), null, o
true
addConvertor= (target, type, modules, handler)->
modules= [modules] unless _.isArray modules
loading= no
queue= []
api.addFor target, type, (origSrc, origOpts, origCallback)->
queue.push [origSrc, origOpts, origCallback]
unless loading
loading= yes
_.tryRequireAll modules, (err, libs)->
if err?
throw "Module(s) '#{ modules.join "'"}' cannot be loaded! #{err}"
converter= handler.apply handler, libs
safeHandler= (src,opts,callback)->
try
converter(src,opts,callback)
catch ex
file= "#{ opts.current_file.path }#{ opts.current_file.ext }"
c new Error("Transpiler error for #{ file }: #{ ex.message }"), null, opts
api.addFor target, type, safeHandler
for arglist in queue
safeHandler.apply safeHandler, arglist
addJsConvertor= (type, modules, handler)->
if _.isArray type
for thisType in type
addConvertor 'js', thisType, modules, handler
else
addConvertor 'js', type, modules, handler
true
addCssConvertor= (type, modules, handler)->
addConvertor 'css', type, modules, handler
# Default JS converters
addJsConvertor '.js', [], ->
(source, opts, converted)->
converted null, source, opts
addJsConvertor '.html', [], ->
(source, opts, converted)->
converted null, """module.exports=#{JSON.stringify source};""", opts
addJsConvertor '.json', [], ->
(source, opts, converted)->
data= JSON.parse source
converted null, """module.exports=#{JSON.stringify data};""", opts
addJsConvertor ['.coffee', '.litcoffee'], 'coffee-script', (coffee)->
(source, opts, converted)->
options = _.defaults {}, (opts.coffee || {}),
bare: yes
options.literate= (opts.current_file.ext is '.litcoffee' || no)
output= coffee.compile source, options
converted null, output, opts
addJsConvertor '.eco', 'eco', (eco)->
(source, opts, converted)->
output= eco.precompile source
converted null, """module.exports= #{output};""", opts
addJsConvertor '.ejs', 'ejs', (ejs)->
(source, opts, converted)->
output= ejs.compile(source, client:true, compileDebug:false)
converted null, """module.exports= #{output.toString()};""", opts
addJsConvertor '.handlebars', 'handlebars', (handlebars)->
(source, opts, converted)->
options= _.defaults {}, (opts.handlebars || {}),
simple: false
commonjs: true
output= handlebars.precompile(source, options)
converted null, """module.exports= #{output.toString()};""", opts
addJsConvertor '.jade', 'jade', (jade)->
(source, opts, converted)->
options= _.defaults {}, (opts.jade || {}),
client: true
compileDebug: false
output= jade.compile(source, options)
converted null, """module.exports= #{output.toString()};""", opts
addJsConvertor '.hogan', 'hogan.js', (hogan)->
(source, opts, converted)->
options= _.defaults {}, (opts.hogan || {}),
asString: 1
output= hogan.compile(source, options)
converted null, """module.exports= new Hogan.Template(#{output.toString()});""", opts
addJsConvertor '.dot', 'doT', (dot)->
(source, opts, converted)->
options= _.defaults {}, (opts.dot || opts.doT || {}), {}
output= dot.compile(source, options)
# _.pp """module.exports= #{ output.toString() }"""
converted null, """module.exports= #{ output.toString() }""", opts
addJsConvertor ['.md', 'markdown'], 'marked', (marked)->
(source, opts, converted)->
options= _.defaults {}, (opts.marked || {}),
gfm: true
tables: true
breaks: false
pedantic: false
sanitize: false
smartLists: true
output= marked(source, options)
# _.pp """module.exports= #{ output.toString() }"""
converted null, """module.exports=#{ JSON.stringify output };""", opts
# TODO: Add default converters for: yaml(?), others?
# Default CSS converters
addCssConvertor '.css', [], ->
(source, opts, converted)->
converted null, source, opts
addCssConvertor '.less', 'less', (less)->
(source, opts, converted)->
less.render source, (err, css)->
converted err, null, opts if err?
converted null, css, opts
addCssConvertor '.styl', ['stylus', 'nib'], (stylus, nib)->
load_paths= [process.cwd(), path.dirname(__dirname)]
(source, opts, converted)->
options= _.defaults {}, (opts.marked || {}),
filename: opts.current_file.filename || 'generated.css'
paths: load_paths
stylus(source)
.set('filename', opts.current_file.filename || 'generated.css')
.set('paths', load_paths)
.set(options)
.use(nib())
.render (err, css)->
if err?
converted err, null, opts
else
converted null, css, opts
# Add other ones too???
_= require './util'
exports.config=
source: './source'
ident: 'require'
autoStart: no
minify: 0 # 0=none, 1=minify, 2=mangle
sourceMap: no # still a work in progress
header: "/* Assembled by AssemBot {%- assembot.version -%} */"
replaceTokens: yes
coffee:
bare: yes
literate: no
exports.options=
port: 8080
wwwRoot: './public'
exports.assembot=
"public/app.js": _.extend {}, exports.config
"public/theme.css": _.extend {}, exports.config
express= require 'express'
fs= require 'fs'
path= require 'path'
builder= require './builder'
_= require './util'
{puts, print, inspect}= require './util'
getConfigFor= (path, info)->
for output, config of info
unless config.text is 'meta'
return config if config.output.path is path
exports.serve= (config, opts={})->
puts "Setting up dev server..."
targets= builder.buildTargets(config, yes)
app= express()
port= config.port || opts.port || 8080
project_root= process.cwd()
root= path.resolve (opts.wwwRoot || config.wwwRoot || "#{ project_root }/public")
puts " root: #{root}"
puts " port: #{port}"
app.get '/*', (req, res)->
uri= req.params[0] || 'index.html'
localpath= path.join(root, uri)
if targets.indexOf(localpath) >= 0
conf = getConfigFor localpath, config
builder.buildTarget conf, (err, content)->
if err?
res.send 500, String(err)
else
res.send 200, content
else
if fs.existsSync localpath
res.sendfile localpath
else
res.send 404, "Not Found"
# app.use express.static(root)
app.use express.errorHandler(
dumpExceptions: true
showStack: true
)
app.listen(port)
puts " Ready! Visit http://127.0.0.1:#{ port }"
util= require 'util'
fs= require 'fs'
path= require 'path'
spawn= require('child_process').spawn
exec= require('child_process').exec
exports.pp= (obj)-> util.puts util.inspect obj
exports.extend= (obj)->
for source in Array::slice.call(arguments, 1)
if source
for key,value of source
obj[key]= value
obj
exports.defaults= (obj)->
for source in Array::slice.call(arguments, 1)
if source
for key,value of source
unless obj[key]?
obj[key]= value
obj
exports.walkTree= walk=(dir, callback, files_only=yes)->
file_list= fs.readdirSync dir
for filename in file_list
fullpath= [dir, filename].join path.sep
stat= fs.statSync fullpath
if stat.isDirectory()
# Keep on walkin...
callback filename, fullpath, true unless files_only
walk fullpath, callback
else
# Call back...
callback filename, fullpath, false
file_list
exports.tryRequire= (name, callback)->
if name is null or name is ''
callback null, {}
return
if loaded_libs[name]?
callback null, loaded_libs[name]
return
try
lib= require name
loaded_libs[name]= lib
callback null, lib
catch ex
localRequire name, callback
exports.tryRequireAll= (names, callback)->
if names.length is 0
callback(null, [])
return
libs=[]
libnames= names.slice()
nextLib= libnames.shift()
loader= (err, lib)->
if err?
callback err, null
else
libs.push lib
if libnames.length is 0
callback null, libs
else
nextLib= libnames.shift()
exports.tryRequire nextLib, loader
exports.tryRequire nextLib, loader
_= exports
loaded_libs= {}
loading_now= {}
localRequire= (name, callback)->
if loaded_libs[name]?
callback(null, loaded_libs[name])
return
if loading_now[name]?
loading_now[name].push callback
return
else
loading_now[name]= []
loading_now[name].push callback
cmd= "#{process.execPath} -p -e \"require.resolve('#{ name }')\""
child= exec cmd, (stdin, stdout, stderr)->
libpath= stdout.trim()
if libpath is ''
err= new Error("Could not load '#{name}' module. (no local path)")
for cb in loading_now[name]
cb err, null
delete loading_now[name]
try
lib= require libpath
loaded_libs[name]= lib
for cb in loading_now[name]
cb null, lib
delete loading_now[name]
catch ex
for cb in loading_now[name]
cb ex, null
delete loading_now[name]
true
exports.extend exports, util

Sorry, the diff of this file is not supported yet