Socket
Socket
Sign inDemoInstall

buddy

Package Overview
Dependencies
170
Maintainers
1
Versions
180
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.6.11 to 0.7.0

lib/core/dependencies.js

727

lib/builder.js

@@ -1,359 +0,400 @@

// Generated by CoffeeScript 1.4.0
var Builder, CSS, HTML, JS, Source, async, colour, configuration, debug, dependencies, error, exec, existsSync, filelog, fs, notify, object, path, print, processors, readdir, rm, start, strong, targetFactory, warn, _ref, _ref1,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
var fs = require('fs')
, path = require('path')
, exec = require('child_process').exec
, async = require('async')
, targetFactory = require('./core/target')
, configuration = require('./core/configuration')
, processors = require('./processors')
, dependencies = require('./core/dependencies')
, Source = require('./core/source')
, filelog = require('./utils/filelog')
, object = require('./utils/object')
, bind = object.bind
, notify = require('./utils/notify')
, debug = notify.debug
, warn = notify.warn
, error = notify.error
, print = notify.print
, colour = notify.colour
, strong = notify.strong
, _fs = require('./utils/fs')
, readdir = _fs.readdir
, rm = _fs.rm
, existsSync = _fs.existsSync;
fs = require('fs');
var JS = 'js'
, CSS = 'css'
, HTML = 'html'
, start = notify.start = +new Date();
path = require('path');
module.exports = Builder;
exec = require('child_process').exec;
/**
* Constructor
*/
function Builder() {
this._executeScript = bind(this._executeScript, this);
this._buildTargets = bind(this._buildTargets, this);
this._parseTargets = bind(this._parseTargets, this);
this._validBuildType = bind(this._validBuildType, this);
this.config = null;
this.options = {
compress: false,
compile: false,
lint: false,
test: false,
lazy: false,
reload: false,
verbose: false,
watching: false,
deploy: false,
processors: null
};
this.sources = {
js: null,
css: null,
html: null
};
this.targets = {
js: [],
css: [],
html: []
};
}
async = require('async');
/**
* Install dependencies as specified in config file found at 'configpath'
* @param {String} configpath [file name or directory containing default]
* @param {Boolean} verbose
*/
Builder.prototype.install = function(configpath, verbose) {
var self = this;
object.extend(this.options, {verbose: verbose});
this._initialize(configpath, function(err) {
if (err) error(err, 0);
if (self.config.dependencies) {
debug('INSTALL', 1);
print('installing dependencies...', 2);
dependencies.install(self.config.dependencies, function(err, files) {
// Persist file references created on install
if (files) filelog.add(files);
if (err) error(err, 0);
print("completed install in " + (colour((+new Date() - start) / 1000 + 's', notify.CYAN)), 2);
});
} else {
error('no dependencies specified in configuration file', 2);
}
});
};
targetFactory = require('./core/target');
/**
* Build sources based on targets specified in config
* optionally 'compress'ing and 'lint'ing
* @param {String} configpath [file name or directory containing default]
* @param {Boolean} compress
* @param {Boolean} lint
* @param {Boolean} test
* @param {Boolean} lazy
* @param {Boolean} verbose
* @param {Function} fn(err)
*/
Builder.prototype.build = function(configpath, compress, lint, test, lazy, verbose, fn) {
var self = this;
object.extend(this.options, {
compress: compress,
lint: lint,
test: test,
lazy: lazy,
verbose: verbose
});
this._initialize(configpath, function(err) {
if (err) error(err, 2);
async.forEachSeries([JS, CSS], (function(type, cb) {
var build = self.config.build[type]
, opts;
if (build) {
if (self._validBuildType(build)) {
// Generate source cache
debug('SOURCE', 1);
opts = object.clone(self.options);
opts.processors = self.options.processors[type];
self.sources[type] = new Source(type, build.sources, opts);
self.sources[type].parse(function(err) {
if (err) return cb("failed parsing sources " + (strong(build)));
// Generate build targets
debug('TARGET', 1);
self._parseTargets(type, build.targets, function(err, instances) {
// Parse errors shouldn't throw
if (instances) {
self.targets[type] = instances;
// Build targets
self._buildTargets(type, function(err) {
if (err) return cb(err);
cb();
});
} else {
cb();
}
});
});
} else {
return cb('invalid build configuration');
}
} else {
cb();
}
}), function(err) {
var script;
if (err) {
if(fn) fn(err);
error(err, 2);
}
print("completed build in " + (colour((+new Date() - start) / 1000 + 's', notify.CYAN)), 2);
if (fn) fn();
// Run test script
if (self.options.test && (script = self.config.settings.test)) {
self._executeScript(function(script, err) {
if (err) return error(err, 2);
});
}
});
});
};
configuration = require('./core/configuration');
/**
* Build sources and watch for creation, changes, and deletion
* optionally 'compress'ing and 'reload'ing the browser
* @param {String} configpath [file name or directory containing default]
* @param {Boolean} compress
* @param {Boolean} reload
* @param {Boolean} test
* @param {Boolean} lazy
* @param {Boolean} verbose
*/
Builder.prototype.watch = function(configpath, compress, reload, test, lazy, verbose) {
var self = this;
this.build(configpath, compress, false, test, lazy, verbose, function(err) {
if (err) error(err, 2);
debug('WATCH', 1);
print('watching sources:', 2);
[self.sources.js, self.sources.css].forEach(function(source) {
if (source) {
object.extend(source.options, {
watching: true,
reload: reload
});
source.watch(function(err, file) {
// Watch error, don't throw
if (err) {
return error(err, 2, false);
} else {
start = new Date();
// Clear content
file.clearContent();
self._buildTargets(source.type, function(err) {
var script;
// Build error, don't throw
if (err) {
return error(err, 2, false);
} else {
print("completed build in " + (colour((+new Date() - start) / 1000 + 's', notify.CYAN)), 3);
// Run test script
if (self.options.test && (script = self.config.settings.test)) {
self._executeScript(function(script, err) {
if (err) return error(err, 2);
});
}
}
});
}
});
}
});
});
};
processors = require('./processors');
/**
* Build and compress sources based on targets specified in configuration
* @param {String} configpath [file name or directory containing default]
* @param {Boolean} test
* @param {Boolean} lazy
* @param {Boolean} verbose
*/
Builder.prototype.deploy = function(configpath, test, lazy, verbose) {
object.extend(this.options, {deploy: true});
this.build(configpath, true, false, test, lazy, verbose);
};
dependencies = require('./core/dependencies');
/**
* List all file system content created via installing and building
* @param {Boolean} verbose
*/
Builder.prototype.list = function(verbose) {
notify.verbose = verbose;
filelog.load(function(err) {
// List files
debug('LIST', 1);
print('listing generated files...', 2);
filelog.files.forEach(function(file) {
print("" + (strong(file)), 3);
});
});
};
Source = require('./core/source');
/**
* Remove all file system content created via installing and building
* @param {Boolean} verbose
*/
Builder.prototype.clean = function(verbose) {
notify.verbose = verbose;
filelog.load(function(err) {
// Delete files
debug('CLEAN', 1);
print('cleaning generated files...', 2);
filelog.files.forEach(function(file) {
print("" + (colour('deleted', notify.RED)) + " " + (strong(file)), 3);
rm(path.resolve(file), function() {});
});
filelog.clean();
});
};
filelog = require('./utils/filelog');
/**
* Initialize based on configuration located at 'configpath'
* The directory tree will be walked if no 'configpath' specified
* @param {String} configpath [file name or directory containing default]
* @param {Boolean} verbose
* @param {Function} fn()
*/
Builder.prototype._initialize = function(configpath, fn) {
var self = this;
notify.verbose = this.options.verbose;
start = new Date();
if (!this.initialized) {
// Load configuration file
configuration.load(configpath, function(err, data) {
if (err) return fn(err);
self.config = data;
print("loaded config " + (strong(configuration.url)), 2);
// Load filelog
filelog.load(function() {});
// Load and store processors
processors.load(self.config.settings && self.config.settings.processors, function(err, installed) {
if (err) return fn(err);
self.options.processors = installed;
self.initialized = true;
fn();
});
// Register for uncaught errors and clean up
process.on('uncaughtException', function(err) {
dependencies.clean();
[self.sources.js, self.sources.css].forEach(function(source) {
if (source) source.clean();
});
// Ring bell
if (self.options.watching) console.log('\x07');
// throw err;
});
});
} else {
fn();
}
};
notify = require('./utils/notify');
/**
* Check that a given 'build' is properly described in the target configuration
* @param {String} build
*/
Builder.prototype._validBuildType = function(build) {
return !!(build
&& build.sources
&& build.sources.length >= 1
&& build.targets
&& build.targets.length >= 1);
};
object = require('./utils/object');
/**
* Recursively cache all valid target instances specified in configuration
* @param {String} type
* @param {Array} targets
* @param {Function} fn(err, instances)
*/
Builder.prototype._parseTargets = function(type, targets, fn) {
var instances = []
, outstanding = 0
, self = this;
_ref = require('./utils/notify'), debug = _ref.debug, warn = _ref.warn, error = _ref.error, print = _ref.print, colour = _ref.colour, strong = _ref.strong;
// Inner function
var parse = function(tgts, parent) {
tgts.forEach(function(tgt) {
// Create unique options object
var opts = object.extend(object.clone(self.options), tgt);
opts.parent = parent;
opts.hasParent = !!parent;
opts.hasChildren = !!opts.targets;
opts.source = self.sources[type];
opts.processors = opts.processors[type];
// CSS targets are compiled at the target level because of @import inlining
opts.compile = type == CSS;
outstanding++;
targetFactory(type, opts, function(err, instance) {
outstanding--;
// Parse errors shouldn't throw
if (err) warn(err, 2);
if (instance) {
// Insert after parent
if (opts.parent) {
instances.splice(instances.indexOf(opts.parent) + 1, 0, instance);
} else {
instances.push(instance);
}
if (opts.targets) parse(opts.targets, instance);
}
if (!outstanding) return fn(null, instances);
});
});
};
_ref1 = require('./utils/fs'), readdir = _ref1.readdir, rm = _ref1.rm, existsSync = _ref1.existsSync;
parse(targets);
};
JS = 'js';
/**
* Run all targets for a given 'type'
* @param {String} type
* @param {Function} fn(err)
*/
Builder.prototype._buildTargets = function(type, fn) {
debug('BUILD', 1);
async.forEachSeries(this.targets[type], (function(tgt, cb) {
tgt.build(function(err, files) {
// Persist file references created on build
if (files) filelog.add(files);
// Reset unless target has children
if (!tgt.options.hasChildren) tgt.reset();
// Return error
if (err) return cb(err);
// Reload
tgt.options.source.refresh(path.basename(files[0]));
cb();
});
}), function(err) {
if (err) return fn(err);
fn();
});
};
CSS = 'css';
HTML = 'html';
start = notify.start = +(new Date);
module.exports = Builder = (function() {
function Builder() {
this._executeScript = __bind(this._executeScript, this);
this._buildTargets = __bind(this._buildTargets, this);
this._parseTargets = __bind(this._parseTargets, this);
this._validBuildType = __bind(this._validBuildType, this);
this.config = null;
this.options = {
compress: false,
compile: false,
lint: false,
test: false,
lazy: false,
reload: false,
verbose: false,
watching: false,
deploy: false,
processors: null
};
this.sources = {
js: null,
css: null,
html: null
};
this.targets = {
js: [],
css: [],
html: []
};
}
Builder.prototype.install = function(configpath, verbose) {
var _this = this;
object.extend(this.options, {
verbose: verbose
});
return this._initialize(configpath, function(err) {
if (err) {
error(err, 0);
}
if (_this.config.dependencies) {
debug('INSTALL', 1);
print('installing dependencies...', 2);
return dependencies.install(_this.config.dependencies, function(err, files) {
files && filelog.add(files);
err && error(err, 0);
return print("completed install in " + (colour((+(new Date) - start) / 1000 + 's', notify.CYAN)), 2);
});
} else {
return error('no dependencies specified in configuration file', 2);
}
});
};
Builder.prototype.build = function(configpath, compress, lint, test, lazy, verbose, fn) {
var _this = this;
object.extend(this.options, {
compress: compress,
lint: lint,
test: test,
lazy: lazy,
verbose: verbose
});
return this._initialize(configpath, function(err) {
if (err) {
error(err, 2);
}
return async.forEachSeries([JS, CSS], (function(type, cb) {
var build, opts;
if (build = _this.config.build[type]) {
if (_this._validBuildType(build)) {
debug('SOURCE', 1);
opts = object.clone(_this.options);
opts.processors = _this.options.processors[type];
_this.sources[type] = new Source(type, build.sources, opts);
return _this.sources[type].parse(function(err) {
if (err) {
return cb("failed parsing sources " + (strong(build)));
}
debug('TARGET', 1);
return _this._parseTargets(type, build.targets, function(err, instances) {
if (instances) {
_this.targets[type] = instances;
return _this._buildTargets(type, function(err) {
if (err) {
return cb(err);
}
return cb();
});
} else {
return cb();
}
});
});
} else {
return cb('invalid build configuration');
}
} else {
return cb();
}
}), function(err) {
var script;
if (err) {
fn && fn(err);
error(err, 2);
}
print("completed build in " + (colour((+(new Date) - start) / 1000 + 's', notify.CYAN)), 2);
fn && fn();
if (_this.options.test && (script = _this.config.settings.test)) {
return _this._executeScript(function(script, err) {
if (err) {
return error(err, 2);
}
});
}
});
});
};
Builder.prototype.watch = function(configpath, compress, reload, test, lazy, verbose) {
var _this = this;
return this.build(configpath, compress, false, test, lazy, verbose, function(err) {
if (err) {
error(err, 2);
}
debug('WATCH', 1);
print('watching sources:', 2);
return [_this.sources.js, _this.sources.css].forEach(function(source) {
if (source) {
object.extend(source.options, {
watching: true,
reload: reload
});
return source.watch(function(err, file) {
if (err) {
return error(err, 2, false);
} else {
start = new Date();
file.clearContent();
return _this._buildTargets(source.type, function(err) {
var script;
if (err) {
return error(err, 2, false);
} else {
print("completed build in " + (colour((+(new Date) - start) / 1000 + 's', notify.CYAN)), 3);
if (_this.options.test && (script = _this.config.settings.test)) {
return _this._executeScript(function(script, err) {
if (err) {
return error(err, 2);
}
});
}
}
});
}
});
}
});
});
};
Builder.prototype.deploy = function(configpath, test, lazy, verbose) {
object.extend(this.options, {
deploy: true
});
return this.build(configpath, true, false, test, lazy, verbose);
};
Builder.prototype.list = function(verbose) {
var _this = this;
notify.verbose = verbose;
return filelog.load(function(err) {
debug('LIST', 1);
print('listing generated files...', 2);
return filelog.files.forEach(function(file) {
return print("" + (strong(file)), 3);
});
});
};
Builder.prototype.clean = function(verbose) {
var _this = this;
notify.verbose = verbose;
return filelog.load(function(err) {
debug('CLEAN', 1);
print('cleaning generated files...', 2);
filelog.files.forEach(function(file) {
print("" + (colour('deleted', notify.RED)) + " " + (strong(file)), 3);
return rm(path.resolve(file), function() {});
});
return filelog.clean();
});
};
Builder.prototype._initialize = function(configpath, fn) {
var _this = this;
notify.verbose = this.options.verbose;
start = new Date();
if (!this.initialized) {
return configuration.load(configpath, function(err, data) {
if (err) {
return fn(err);
}
_this.config = data;
print("loaded config " + (strong(configuration.url)), 2);
filelog.load(function() {});
processors.load(_this.config.settings && _this.config.settings.processors, function(err, installed) {
if (err) {
return fn(err);
}
_this.options.processors = installed;
_this.initialized = true;
return fn();
});
return process.on('uncaughtException', function(err) {
dependencies.clean();
[_this.sources.js, _this.sources.css].forEach(function(source) {
if (source) {
return source.clean();
}
});
if (_this.options.watching) {
console.log('\x07');
}
throw err;
});
});
} else {
return fn();
}
};
Builder.prototype._validBuildType = function(build) {
return !!(build && build.sources && build.sources.length >= 1 && build.targets && build.targets.length >= 1);
};
Builder.prototype._parseTargets = function(type, targets, fn) {
var instances, outstanding, parse,
_this = this;
instances = [];
outstanding = 0;
parse = function(tgts, parent) {
return tgts.forEach(function(tgt) {
var opts;
opts = object.extend(object.clone(_this.options), tgt);
opts.parent = parent;
opts.hasParent = !!parent;
opts.hasChildren = !!opts.targets;
opts.source = _this.sources[type];
opts.processors = opts.processors[type];
opts.compile = type === CSS;
outstanding++;
return targetFactory(type, opts, function(err, instance) {
outstanding--;
if (err) {
warn(err, 2);
}
if (instance) {
if (opts.parent) {
instances.splice(instances.indexOf(opts.parent) + 1, 0, instance);
} else {
instances.push(instance);
}
if (opts.targets) {
parse(opts.targets, instance);
}
}
if (!outstanding) {
return fn(null, instances);
}
});
});
};
return parse(targets);
};
Builder.prototype._buildTargets = function(type, fn) {
var _this = this;
debug('BUILD', 1);
return async.forEachSeries(this.targets[type], (function(tgt, cb) {
return tgt.build(function(err, files) {
files && filelog.add(files);
if (!tgt.options.hasChildren) {
tgt.reset();
}
if (err) {
return cb(err);
}
tgt.options.source.refresh(path.basename(files[0]));
return cb();
});
}), function(err) {
if (err) {
return fn(err);
}
return fn();
});
};
Builder.prototype._executeScript = function(script, fn) {
print('executing test script...', 2);
debug("execute: " + (strong(this.config.settings.test)), 3);
return exec(script, function(err, stdout, stderr) {
if (err) {
return fn(err);
}
stdout && console.log(stdout);
stderr && console.log(stderr);
return fn();
});
};
return Builder;
})();
/**
* Run the script defined in config 'test'
* @param {String} script
* @param {Function} fn(err)
*/
Builder.prototype._executeScript = function(script, fn) {
print('executing test script...', 2);
debug("execute: " + (strong(this.config.settings.test)), 3);
exec(script, function(err, stdout, stderr) {
if (err) return fn(err);
if (stdout) console.log(stdout);
if (stderr) console.log(stderr);
fn();
});
};

@@ -1,16 +0,11 @@

// Generated by CoffeeScript 1.4.0
var DEFAULT, DEFAULT_JSON, debug, existsSync, fs, locate, path, strong, _ref;
var fs = require('fs')
, path = require('path')
, existsSync = require('../utils/fs').existsSync
, notify = require('../utils/notify')
, debug = notify.debug
, strong = notify.strong;
fs = require('fs');
var DEFAULT = 'buddy.js'
, DEFAULT_JSON = 'buddy.json';
path = require('path');
existsSync = require('../utils/fs').existsSync;
_ref = require('../utils/notify'), debug = _ref.debug, strong = _ref.strong;
DEFAULT = 'buddy.js';
DEFAULT_JSON = 'buddy.json';
exports.data = null;

@@ -20,74 +15,91 @@

/**
* Load and parse configuration file
* Accepts optional path to file or directory
* @param {String} url
* @param {Function} fn(err, config)
*/
exports.load = function(url, fn) {
debug('CONFIGURATION', 1);
return locate(url, function(err) {
var data;
if (err) {
return fn(err);
}
try {
data = require(exports.url);
} catch (err) {
return fn("parsing " + (strong(exports.url)) + "\n Run " + (strong('buddy -h')) + " for proper formatting");
}
if (data.build || data.dependencies || data.settings) {
exports.data = data;
process.chdir(path.dirname(exports.url));
return fn(null, data);
} else {
return fn("parsing " + (strong(exports.url)) + "\n Run " + (strong('buddy -h')) + " for proper formatting");
}
});
debug('CONFIGURATION', 1);
locate(url, function(err) {
var data;
if (err) return fn(err);
try {
data = require(exports.url);
} catch (e) {
return fn("parsing " + (strong(exports.url)) + "\n Run " + (strong('buddy -h')) + " for proper formatting");
}
if (data.build || data.dependencies || data.settings) {
// Store
exports.data = data;
// Set current directory to location of file
process.chdir(path.dirname(exports.url));
return fn(null, data);
} else {
return fn("parsing " + (strong(exports.url)) + "\n Run " + (strong('buddy -h')) + " for proper formatting");
}
});
};
exports.locate = locate = function(url, fn) {
var dir, parent, urljs, urljson;
if (url) {
url = path.resolve(url);
if (existsSync(url)) {
return fs.stat(url, function(err, stats) {
var urljs, urljson;
if (err) {
return fn(err);
}
if (!path.extname(url).length || stats.isDirectory()) {
urljs = path.join(url, DEFAULT);
urljson = path.join(url, DEFAULT_JSON);
if (existsSync(url = urljs) || existsSync(url = urljson)) {
debug("config file found at: " + (strong(url)), 2);
exports.url = url;
return fn(null, url);
} else {
return fn("" + (strong(path.basename(url))) + " not found in " + (strong(path.dirname(url))));
}
} else {
debug("config file found at: " + (strong(url)), 2);
exports.url = url;
return fn(null, url);
}
});
} else {
return fn("" + (strong(path.basename(url))) + " not found in " + (strong(path.dirname(url))));
}
} else {
while (true) {
if (typeof dir !== "undefined" && dir !== null) {
parent = path.resolve(dir, '../');
if (parent === dir) {
return fn("" + (strong(DEFAULT)) + " not found on this path");
} else {
dir = parent;
}
} else {
dir = process.cwd();
}
urljs = path.join(dir, DEFAULT);
urljson = path.join(dir, DEFAULT_JSON);
if (existsSync(url = urljs) || existsSync(url = urljson)) {
debug("config file found at: " + (strong(url)), 2);
exports.url = url;
return fn(null);
}
}
}
/**
* Locate the configuration file
* Walks the directory tree if no file/directory specified
* @param {Function} fn(err, url)
*/
var locate = exports.locate = function(url, fn) {
var dir, parent, urljs, urljson;
if (url) {
// Check that the supplied path is valid
url = path.resolve(url);
if (existsSync(url)) {
fs.stat(url, function(err, stats) {
if (err) return fn(err);
// Try default file name if passed directory
if (!path.extname(url).length || stats.isDirectory()) {
// Support both js and json file types
urljs = path.join(url, DEFAULT);
urljson = path.join(url, DEFAULT_JSON);
if (existsSync(url = urljs) || existsSync(url = urljson)) {
debug("config file found at: " + (strong(url)), 2);
exports.url = url;
fn(null, url);
} else {
return fn("" + (strong(path.basename(url))) + " not found in " + (strong(path.dirname(url))));
}
} else {
debug("config file found at: " + (strong(url)), 2);
exports.url = url;
fn(null, url);
}
});
} else {
return fn("" + (strong(path.basename(url))) + " not found in " + (strong(path.dirname(url))));
}
// No url specified
// Find the first instance of a DEFAULT file based on the current working directory
} else {
while (true) {
if (typeof dir !== "undefined" && dir !== null) {
parent = path.resolve(dir, '../');
// Exit if we can no longer go up a level
if (parent === dir) {
return fn("" + (strong(DEFAULT)) + " not found on this path");
} else {
// Start at current working directory
dir = parent;
}
} else {
dir = process.cwd();
}
// Support both js and json file types
urljs = path.join(dir, DEFAULT);
urljson = path.join(dir, DEFAULT_JSON);
if (existsSync(url = urljs) || existsSync(url = urljson)) {
debug("config file found at: " + (strong(url)), 2);
exports.url = url;
return fn(null);
}
}
}
};

@@ -1,313 +0,348 @@

// Generated by CoffeeScript 1.4.0
var Dependency, RE_GITHUB_PROJECT, RE_GITHUB_URL, RE_INDEX, RE_PACKAGE_NOT_FOUND, RE_VALID_VERSION, async, bower, cp, debug, existsSync, fs, fsutils, http, mkdir, mv, path, request, rm, semver, strong, unzip, _ref, _ref1,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
var path = require('path')
, fs = require('fs')
, bower = require('bower')
, request = require('superagent')
, http = require('http')
, unzip = require('unzip')
, semver = require('semver')
, async = require('async')
, bind = require('../utils/object').bind
, fsutils = require('../utils/fs')
, notify = require('../utils/notify')
, debug = notify.debug
, strong = notify.strong
, rm = fsutils.rm
, mv = fsutils.mv
, cp = fsutils.cp
, mkdir = fsutils.mkdir
, existsSync = fsutils.existsSync;
path = require('path');
var RE_GITHUB_PROJECT = /\w+\/\w+/
, RE_GITHUB_URL = /git:\/\/(.*)\.git/
, RE_PACKAGE_NOT_FOUND = /was not found/
, RE_INDEX = /^index(?:\.js$)?/
, RE_VALID_VERSION = /^\d+\.\d+\.\d+$|^master$/;
fs = require('fs');
module.exports = Dependency;
bower = require('bower');
/**
* Constructor
* @param {String} source
* @param {String} destination
* @param {String} output
* @param {String} temp
*/
function Dependency(source, destination, output, temp) {
this.move = bind(this.move, this);
this.resolveResources = bind(this.resolveResources, this);
this.fetch = bind(this.fetch, this);
this.validateVersion = bind(this.validateVersion, this);
this.lookupPackage = bind(this.lookupPackage, this);
this.temp = temp;
this.local = false;
this.keep = false;
this.id = source;
this.name = source;
this.url = null;
this.version = 'master';
this.packageFiles = ['component.json', 'package.json'];
this.location = null;
this.resources = null;
this.files = [];
this.dependencies = [];
this.destination = path.resolve(destination);
this.output = output && path.resolve(output);
debug("created Source instance for: " + source, 2);
request = require('superagent');
// Parse specified resources
source = source.split('#');
if (source[1]) this.resources = source[1].split('|');
// Local
if (existsSync(path.resolve(source[0]))) {
this.local = true;
this.location = path.resolve(source[0]);
if (this.resources == null) this.resources = [this.location];
// Don't clean if source is in destination dir
this.keep = this.location.indexOf(path.resolve(this.destination)) != -1;
// Remote
} else {
// Parse version
source = source[0].split('@');
if (source[1]) this.version = source[1];
this.id = this.name = source[0];
// github user/repo
if (RE_GITHUB_PROJECT.test(this.name)) {
this.url = "https://github.com/" + this.name + "/archive/" + this.version + ".zip";
this.id = this.name.split('/')[1];
}
}
}
http = require('http');
/**
* Install the dependency
* @param {Function} fn(err, dependencies)
*/
Dependency.prototype.install = function(fn) {
var self = this;
if (this.local) {
this.move(function(err) {
if (err) return fn(err);
else return fn(null, self.dependencies);
});
} else {
async.series([
this.lookupPackage,
this.validateVersion,
this.fetch,
this.resolveResources,
this.move
], function(err) {
if (err) return fn(err);
else return fn(null, self.dependencies);
});
}
};
unzip = require('unzip');
/*
* Lookup a Bower package's github location
* @param {Function} fn(err)
*/
Dependency.prototype.lookupPackage = function(fn) {
var self = this;
if (!this.url) {
debug("looking up package: " + (strong(this.id)), 3);
bower.commands
.lookup(this.id)
// Error looking up package
.on('error', function() {
fn('no package found for:' + self.id);
})
.on('data', function(data) {
// Error looking up package
if (RE_PACKAGE_NOT_FOUND.test(data)) {
fn('no package found for:' + self.id);
} else {
// Store archive url
var url = RE_GITHUB_URL.exec(data)[1];
self.name = url.replace('github.com/', '');
self.url = "https://" + url + "/archive/" + self.version + ".zip";
fn();
}
});
} else {
// Delay for event chaining
process.nextTick(function() {
fn();
});
}
};
semver = require('semver');
/**
* Retrieve the latest version that satisfies a conditional version number
* @param {Function} fn(err)
*/
Dependency.prototype.validateVersion = function(fn) {
var req
, self = this;
if (!RE_VALID_VERSION.test(this.version)) {
debug("validating version: " + (strong(this.name + '@' + this.version)), 3);
// Get tags
req = request.get("https://api.github.com/repos/" + this.name + "/tags");
req.end(function(err, res) {
var json, version;
// Error downloading
if (err || res.error) {
fn('fetching tags for: ' + self.name + ' failed with error code: ' + http.STATUS_CODES[res.status]);
} else {
// Parse and sort json data
try {
json = JSON.parse(res.text);
} catch (e) {
fn('parsing tag information for: ' + self.name);
}
// Sort by version (name) descending
json.sort(function(a, b) {
return semver.rcompare(a.name, b.name);
});
async = require('async');
// Set latest version
if (self.version === '*' || self.version === 'latest') {
self.version = json[0].name;
self.url = json[0].zipball_url;
// Match version
} else {
for (var i = 0, n = json.length; i < n; ++i) {
version = json[i];
// Find the highest version that passes
if (semver.satisfies(version.name, self.version)) {
self.version = version.name;
self.url = version.zipball_url;
break;
}
}
}
fn();
}
});
} else {
// Delay for event chaining
process.nextTick(function() {
fn();
});
}
};
fsutils = require('../utils/fs');
/**
* Fetch the github archive zipball to 'temp' directory
* @param {Function} fn(err)
*/
Dependency.prototype.fetch = function(fn) {
var self = this
// Create archive filename
, filename = this.temp + path.sep + this.id + '-' + this.version + '.zip'
// Download archive to temp
, req = request.get(this.url).buffer(false);
debug("downloading zipball to temp: " + (strong(this.url)), 3);
req.end(function(err, res) {
// Error downloading
if (err || res.error) {
fn('fetching ' + self.url + ' failed with error code: ' + http.STATUS_CODES[res.status]);
} else {
// Write to disk
res.pipe(fs.createWriteStream(filename));
res.on('end', function() {
// Unzip
var extractor = unzip.Extract({path: self.temp});
fs.createReadStream(filename).pipe(extractor);
// Error unzipping
extractor.on('error', function() {
fn('unzipping archive: ' + filename);
});
// Store path to unzipped package
extractor.on('close', function() {
self.location = filename.replace(path.extname(filename), '');
fn();
});
});
}
});
};
_ref = require('../utils/notify'), debug = _ref.debug, strong = _ref.strong;
/**
* Parse archive component.json or package.json for resources and dependencies
* @param {Function} fn(err)
*/
Dependency.prototype.resolveResources = function(fn) {
var temp, callback,
self = this;
_ref1 = require('../utils/fs'), rm = _ref1.rm, mv = _ref1.mv, cp = _ref1.cp, mkdir = _ref1.mkdir, existsSync = _ref1.existsSync;
// Find 'main' property in json file
var find = function(packageFile, cb) {
var filename;
if (existsSync(filename = path.resolve(self.location, packageFile))) {
fs.readFile(filename, 'utf8', function(err, data) {
var json;
if (err) return cb('reading: ' + self.id + ' ' + packageFile);
try {
json = JSON.parse(data);
} catch (e) {
// Error parsing json
return cb('parsing: ' + self.id + ' ' + packageFile);
}
// Return
cb(null, json);
});
} else {
cb(null);
}
};
RE_GITHUB_PROJECT = /\w+\/\w+/;
// Add file to resources
var add = function(filename) {
var filepath;
// Rename if index
if (RE_INDEX.test(filename)) {
if (!path.extname(filename)) filename += '.js';
var newname = self.id + '.js';
// TODO: async rename
// TODO: parse contents for require redirect
// Rename to package name
fs.renameSync(path.resolve(self.location, filename), path.resolve(self.location, newname));
filename = newname;
}
filepath = path.resolve(self.location, filename);
debug("added resource: " + (strong(path.basename(filepath))), 3);
if (existsSync(filepath)) self.resources.push(filepath);
};
RE_GITHUB_URL = /git:\/\/(.*)\.git/;
// Resources specified
if (this.resources) {
// Store resources with absolute paths
temp = this.resources.concat();
this.resources = [];
temp.forEach(function(filename) {
add(filename);
});
// Delay for event chaining
process.nextTick(function() {
fn();
});
} else {
this.resources = [];
// Find first json file that has a 'main' property
find(this.packageFiles.pop(), callback = function(err, json) {
var version;
if (err) return fn(err);
if (json && json.main) {
add(json.main);
// Find dependencies and store
if (json.dependencies) {
for (var dependency in json.dependencies) {
version = json.dependencies[dependency];
self.dependencies.push("" + dependency + "@" + version);
}
}
// Return
fn();
// Try next
} else if (self.packageFiles.length) {
find(self.packageFiles.pop(), callback);
} else {
return fn('unable to resolve resources for: ' + self.id);
}
});
}
};
RE_PACKAGE_NOT_FOUND = /was not found/;
/**
* Move resources to destination
* @param {Function} fn(err)
*/
Dependency.prototype.move = function(fn) {
var idx,
self = this;
if (!this.keep) {
idx = -1;
async.forEachSeries(this.resources, (function(resource, cb) {
// Copy local files, otherwise move
fsutils[self.local ? 'cp' : 'mv'](resource, self.destination, true, function(err, filepath) {
if (err) return cb(err);
idx++;
self.files.push(path.relative(process.cwd(), filepath));
debug("moved resource " + (strong(path.basename(resource))) + " to destination " + (strong(path.relative(process.cwd(), self.destination))), 3);
self.resources[idx] = filepath;
cb();
});
}), function(err) {
if (err) return fn(err);
else return fn();
});
} else {
// Delay for event chaining
process.nextTick(function() {
fn();
});
}
};
RE_INDEX = /^index(?:\.js$)?/;
RE_VALID_VERSION = /^\d+\.\d+\.\d+$|^master$/;
module.exports = Dependency = (function() {
function Dependency(source, destination, output, temp) {
var _ref2;
this.temp = temp;
this.move = __bind(this.move, this);
this.resolveResources = __bind(this.resolveResources, this);
this.fetch = __bind(this.fetch, this);
this.validateVersion = __bind(this.validateVersion, this);
this.lookupPackage = __bind(this.lookupPackage, this);
debug("created Source instance for: " + source, 2);
this.local = false;
this.keep = false;
this.id = source;
this.name = source;
this.url = null;
this.version = 'master';
this.packageFiles = ['component.json', 'package.json'];
this.location = null;
this.resources = null;
this.files = [];
this.dependencies = [];
this.destination = path.resolve(destination);
this.output = output && path.resolve(output);
source = source.split('#');
if (source[1]) {
this.resources = source[1].split('|');
}
if (existsSync(path.resolve(source[0]))) {
this.local = true;
this.location = path.resolve(source[0]);
if ((_ref2 = this.resources) == null) {
this.resources = [this.location];
}
this.keep = this.location.indexOf(path.resolve(this.destination)) !== -1;
} else {
source = source[0].split('@');
if (source[1]) {
this.version = source[1];
}
this.id = this.name = source[0];
if (RE_GITHUB_PROJECT.test(this.name)) {
this.url = "https://github.com/" + this.name + "/archive/" + this.version + ".zip";
this.id = this.name.split('/')[1];
}
}
}
Dependency.prototype.install = function(fn) {
var _this = this;
if (this.local) {
return this.move(function(err) {
if (err) {
return fn(err);
} else {
return fn(null, _this.dependencies);
}
});
} else {
return async.series([this.lookupPackage, this.validateVersion, this.fetch, this.resolveResources, this.move], function(err) {
if (err) {
return fn(err);
} else {
return fn(null, _this.dependencies);
}
});
}
};
Dependency.prototype.lookupPackage = function(fn) {
var _this = this;
if (!this.url) {
debug("looking up package: " + (strong(this.id)), 3);
return bower.commands.lookup(this.id).on('error', function() {
return fn('no package found for:' + _this.id);
}).on('data', function(data) {
var url;
if (RE_PACKAGE_NOT_FOUND.test(data)) {
return fn('no package found for:' + _this.id);
} else {
url = RE_GITHUB_URL.exec(data)[1];
_this.name = url.replace('github.com/', '');
_this.url = "https://" + url + "/archive/" + _this.version + ".zip";
return fn();
}
});
} else {
return process.nextTick(function() {
return fn();
});
}
};
Dependency.prototype.validateVersion = function(fn) {
var req,
_this = this;
if (!RE_VALID_VERSION.test(this.version)) {
debug("validating version: " + (strong(this.name + '@' + this.version)), 3);
req = request.get("https://api.github.com/repos/" + this.name + "/tags");
return req.end(function(err, res) {
var json, version, _i, _len;
if (err || res.error) {
return fn('fetching tags for: ' + _this.name + ' failed with error code: ' + http.STATUS_CODES[res.status]);
} else {
try {
json = JSON.parse(res.text);
} catch (err) {
fn('parsing tag information for: ' + _this.name);
}
json.sort(function(a, b) {
return semver.rcompare(a.name, b.name);
});
if (_this.version === '*' || _this.version === 'latest') {
_this.version = json[0].name;
_this.url = json[0].zipball_url;
} else {
for (_i = 0, _len = json.length; _i < _len; _i++) {
version = json[_i];
if (semver.satisfies(version.name, _this.version)) {
_this.version = version.name;
_this.url = version.zipball_url;
break;
}
}
}
return fn();
}
});
} else {
return process.nextTick(function() {
return fn();
});
}
};
Dependency.prototype.fetch = function(fn) {
var filename, req,
_this = this;
filename = this.temp + path.sep + this.id + '-' + this.version + '.zip';
debug("downloading zipball to temp: " + (strong(this.url)), 3);
req = request.get(this.url).buffer(false);
return req.end(function(err, res) {
if (err || res.error) {
return fn('fetching ' + _this.url + ' failed with error code: ' + http.STATUS_CODES[res.status]);
} else {
res.pipe(fs.createWriteStream(filename));
return res.on('end', function() {
var extractor;
extractor = unzip.Extract({
path: _this.temp
});
fs.createReadStream(filename).pipe(extractor);
extractor.on('error', function() {
return fn('unzipping archive: ' + filename);
});
return extractor.on('close', function() {
_this.location = filename.replace(path.extname(filename), '');
return fn();
});
});
}
});
};
Dependency.prototype.resolveResources = function(fn) {
var add, callback, find, temp,
_this = this;
find = function(packageFile, cb) {
var filename;
if (existsSync(filename = path.resolve(_this.location, packageFile))) {
return fs.readFile(filename, 'utf8', function(err, data) {
var json;
if (err) {
return cb('reading: ' + _this.id + ' ' + packageFile);
}
try {
json = JSON.parse(data);
} catch (err) {
return cb('parsing: ' + _this.id + ' ' + packageFile);
}
return cb(null, json);
});
} else {
return cb(null);
}
};
add = function(filename) {
var filepath, newname;
if (RE_INDEX.test(filename)) {
if (!path.extname(filename)) {
filename += '.js';
}
newname = _this.id + '.js';
fs.renameSync(path.resolve(_this.location, filename), path.resolve(_this.location, newname));
filename = newname;
}
filepath = path.resolve(_this.location, filename);
debug("added resource: " + (strong(path.basename(filepath))), 3);
if (existsSync(filepath)) {
return _this.resources.push(filepath);
}
};
if (this.resources) {
temp = this.resources.concat();
this.resources = [];
temp.forEach(function(filename) {
return add(filename);
});
return process.nextTick(function() {
return fn();
});
} else {
this.resources = [];
return find(this.packageFiles.pop(), callback = function(err, json) {
var dependency, version, _ref2;
if (err) {
return fn(err);
}
if (json && json.main) {
add(json.main);
if (json.dependencies) {
_ref2 = json.dependencies;
for (dependency in _ref2) {
version = _ref2[dependency];
_this.dependencies.push("" + dependency + "@" + version);
}
}
return fn();
} else if (_this.packageFiles.length) {
return find(_this.packageFiles.pop(), callback);
} else {
return fn('unable to resolve resources for: ' + _this.id);
}
});
}
};
Dependency.prototype.move = function(fn) {
var idx,
_this = this;
if (!this.keep) {
idx = -1;
return async.forEachSeries(this.resources, (function(resource, cb) {
return fsutils[_this.local ? 'cp' : 'mv'](resource, _this.destination, true, function(err, filepath) {
if (err) {
return cb(err);
}
idx++;
_this.files.push(path.relative(process.cwd(), filepath));
debug("moved resource " + (strong(path.basename(resource))) + " to destination " + (strong(path.relative(process.cwd(), _this.destination))), 3);
_this.resources[idx] = filepath;
return cb();
});
}), function(err) {
if (err) {
return fn(err);
} else {
return fn();
}
});
} else {
return process.nextTick(function() {
return fn();
});
}
};
Dependency.prototype.destroy = function() {};
return Dependency;
})();
Dependency.prototype.destroy = function() {};

@@ -1,142 +0,186 @@

// Generated by CoffeeScript 1.4.0
var Source, Watcher, colour, debug, existsSync, fileFactory, ignored, indir, notify, object, path, print, readdir, reloader, strong, _ref, _ref1;
var path = require('path')
, fileFactory = require('./file')
, reloader = require('../utils/reloader')
, Watcher = require('../utils/watcher')
, object = require('../utils/object')
, notify = require('../utils/notify')
, debug = notify.debug
, strong = notify.strong
, print = notify.print
, colour = notify.colour
, fs = require('../utils/fs')
, indir = fs.indir
, readdir = fs.readdir
, existsSync = fs.existsSync
, ignored = fs.ignored;
path = require('path');
module.exports = Source;
fileFactory = require('./file');
/**
* Constructor
* @param {String} type
* @param {Array} sources
* @param {Object} options
*/
function Source(type, sources, options) {
var self = this;
debug("created " + type + " Source instance for: " + (strong(sources)), 2);
this.type = type;
this.options = options;
this._watchers = [];
this.byPath = {};
this.byModule = {};
this.length = 0;
this.locations = [];
sources.forEach(function(source) {
self.locations.push(path.resolve(source));
});
}
reloader = require('../utils/reloader');
/**
* Parse sources, generating File instances for valid files
* @param {Function} fn(err)
*/
Source.prototype.parse = function(fn) {
var outstanding = 0
, self = this;
this.locations.forEach(function(location) {
outstanding++;
readdir(location, ignored, function(err, files) {
outstanding--;
if (err) return fn(err);
files.forEach(function(f) {
self.add(f);
});
if (!outstanding) {
return fn();
}
});
});
};
Watcher = require('../utils/watcher');
/**
* Add a File instance to the cache by 'filepath'
* @param {String} filepath
*/
Source.prototype.add = function(filepath) {
var basepath = this._getBasepath(filepath)
, self = this;
filepath = path.resolve(filepath);
if (!this.byPath[filepath] && basepath) {
// Create File instance
fileFactory(this.type, filepath, basepath, object.clone(this.options), function(err, instance) {
if (err) return;
self.length++;
self.byPath[instance.filepath] = instance;
self.byModule[instance.moduleID] = instance;
});
}
};
notify = require('../utils/notify');
/**
* Remove a File instance from the cache by 'filepath'
* @param {String} filepath
*/
Source.prototype.remove = function(filepath) {
filepath = path.resolve(filepath);
var file = this.byPath[filepath];
if (file) {
this.length--;
delete this.byPath[filepath];
delete this.byModule[file.moduleID];
file.destroy();
}
};
object = require('../utils/object');
/**
* Watch for changes and call 'fn'
* @param {Function} fn(err, file)
*/
Source.prototype.watch = function(fn) {
var self = this;
this.locations.forEach(function(location) {
var watcher;
print("watching "
+ (strong(path.relative(process.cwd(), location)))
+ "...", 3);
self._watchers.push(watcher = new Watcher(ignored));
// Add file on 'create'
watcher.on('create', function(filepath, stats) {
self.add(filepath);
print("["
+ (new Date().toLocaleTimeString())
+ "] "
+ (colour('added', notify.GREEN))
+ " "
+ (strong(path.relative(process.cwd(), filepath))), 3);
});
// Remove file on 'delete'
watcher.on('delete', function(filepath) {
self.remove(filepath);
print("["
+ (new Date().toLocaleTimeString())
+ "] "
+ (colour('removed', notify.RED))
+ " "
+ (strong(path.relative(process.cwd(), filepath))), 3);
});
// Notify when 'change'
// Return File instance
watcher.on('change', function(filepath, stats) {
var file;
print("["
+ (new Date().toLocaleTimeString())
+ "] "
+ (colour('changed', notify.YELLOW))
+ " "
+ (strong(path.relative(process.cwd(), filepath))), 3);
file = self.byPath[filepath];
fn(null, file);
});
// Notify when 'error'
watcher.on('error', function(err) {
fn(err);
});
// Watch
watcher.watch(location);
// Start reloader
if (self.options.reload) {
reloader.start(function(err) {
fn(err);
});
}
});
};
_ref = require('../utils/notify'), debug = _ref.debug, strong = _ref.strong, print = _ref.print, colour = _ref.colour;
/**
* Reload 'file'
* @param {String} file
*/
Source.prototype.refresh = function(file) {
if (this.options.reload) {
reloader.refresh(file);
}
};
_ref1 = require('../utils/fs'), indir = _ref1.indir, readdir = _ref1.readdir, existsSync = _ref1.existsSync, ignored = _ref1.ignored;
/**
* Clean up
*/
Source.prototype.clean = function() {
return reloader.stop();
};
module.exports = Source = (function() {
function Source(type, sources, options) {
var _this = this;
this.type = type;
this.options = options;
debug("created " + type + " Source instance for: " + (strong(sources)), 2);
this._watchers = [];
this.byPath = {};
this.byModule = {};
this.length = 0;
this.locations = [];
sources.forEach(function(source) {
return _this.locations.push(path.resolve(source));
});
}
Source.prototype.parse = function(fn) {
var outstanding,
_this = this;
outstanding = 0;
return this.locations.forEach(function(location) {
outstanding++;
return readdir(location, ignored, function(err, files) {
outstanding--;
if (err) {
return fn(err);
}
files.forEach(function(f) {
return _this.add(f);
});
if (!outstanding) {
return fn();
}
});
});
};
Source.prototype.add = function(filepath) {
var basepath,
_this = this;
filepath = path.resolve(filepath);
basepath = this._getBasepath(filepath);
if (!this.byPath[filepath] && basepath) {
return fileFactory(this.type, filepath, basepath, object.clone(this.options), function(err, instance) {
if (err) {
return;
}
_this.length++;
_this.byPath[instance.filepath] = instance;
return _this.byModule[instance.moduleID] = instance;
});
}
};
Source.prototype.remove = function(filepath) {
var file;
filepath = path.resolve(filepath);
if (file = this.byPath[filepath]) {
this.length--;
delete this.byPath[filepath];
delete this.byModule[file.moduleID];
return file.destroy();
}
};
Source.prototype.watch = function(fn) {
var _this = this;
return this.locations.forEach(function(location) {
var watcher;
print("watching " + (strong(path.relative(process.cwd(), location))) + "...", 3);
_this._watchers.push(watcher = new Watcher(ignored));
watcher.on('create', function(filepath, stats) {
_this.add(filepath);
return print("[" + (new Date().toLocaleTimeString()) + "] " + (colour('added', notify.GREEN)) + " " + (strong(path.relative(process.cwd(), filepath))), 3);
});
watcher.on('delete', function(filepath) {
_this.remove(filepath);
return print("[" + (new Date().toLocaleTimeString()) + "] " + (colour('removed', notify.RED)) + " " + (strong(path.relative(process.cwd(), filepath))), 3);
});
watcher.on('change', function(filepath, stats) {
var file;
print("[" + (new Date().toLocaleTimeString()) + "] " + (colour('changed', notify.YELLOW)) + " " + (strong(path.relative(process.cwd(), filepath))), 3);
file = _this.byPath[filepath];
return fn(null, file);
});
watcher.on('error', function(err) {
return fn(err);
});
watcher.watch(location);
if (_this.options.reload) {
return reloader.start(function(err) {
return fn(err);
});
}
});
};
Source.prototype.refresh = function(file) {
if (this.options.reload) {
return reloader.refresh(file);
}
};
Source.prototype.clean = function() {
return reloader.stop();
};
Source.prototype._getBasepath = function(filepath) {
var location, _i, _len, _ref2;
_ref2 = this.locations;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
location = _ref2[_i];
if (indir(location, filepath)) {
return location;
}
}
return null;
};
return Source;
})();
/**
* Get base path for 'filepath'
* @param {String} filepath
*/
Source.prototype._getBasepath = function(filepath) {
var location;
for (var i = 0, n = this.locations.length; i < n; ++i) {
location = this.locations[i];
if (indir(location, filepath)) {
return location;
}
}
return null;
};

@@ -1,22 +0,23 @@

// Generated by CoffeeScript 1.4.0
var coffee;
var coffee = require('coffee-script');
coffee = require('coffee-script');
module.exports = {
name: 'coffeescript',
extension: 'coffee',
category: 'js',
type: 'compiler',
module.exports = {
name: 'coffeescript',
extension: 'coffee',
category: 'js',
type: 'compiler',
compile: function(data, fn) {
var compiled;
try {
compiled = coffee.compile(data, {
bare: true
});
return fn(null, compiled);
} catch (err) {
return fn(err, '');
}
}
/**
* Compile 'data'
* @param {String} data
* @param {Function} fn(err, compiled)
*/
compile: function(data, fn) {
try {
// Compile without function wrapper
var compiled = coffee.compile(data, {bare: true});
fn(null, compiled);
} catch (err) {
fn(err, '');
}
}
};

@@ -1,23 +0,21 @@

// Generated by CoffeeScript 1.4.0
var less;
var less = require('less');
less = require('less');
module.exports = {
name: 'less',
extension: 'less',
category: 'css',
type: 'compiler',
module.exports = {
name: 'less',
extension: 'less',
category: 'css',
type: 'compiler',
compile: function(data, fn) {
var parser,
_this = this;
parser = new less.Parser();
return parser.parse(data, function(err, tree) {
if (err) {
return fn(err, '');
} else {
return fn(null, tree.toCSS());
}
});
}
/**
* Compile 'data' and pass 'sources' for dependency reference
* @param {String} data
* @param {Function} fn(err, compiled)
*/
compile: function(data, fn) {
var parser = new less.Parser();
parser.parse(data, function(err, tree) {
if (err) fn(err, '');
else fn(null, tree.toCSS());
});
}
};

@@ -1,23 +0,21 @@

// Generated by CoffeeScript 1.4.0
var stylus;
var stylus = require('stylus');
stylus = require('stylus');
module.exports = {
name: 'stylus',
extension: 'styl',
category: 'css',
type: 'compiler',
module.exports = {
name: 'stylus',
extension: 'styl',
category: 'css',
type: 'compiler',
compile: function(content, fn) {
var stylc,
_this = this;
stylc = stylus(content).set('paths');
return stylc.render(function(err, css) {
if (err) {
return fn(err, '');
} else {
return fn(null, css);
}
});
}
/**
* Compile 'data' and pass 'sources' for dependency reference
* @param {String} data
* @param {Function} fn(err, compiled)
*/
compile: function(content, fn) {
var stylc = stylus(content).set('paths');
stylc.render(function(err, css) {
if (err) fn(err, '');
else fn(null, css);
});
}
};

@@ -1,9 +0,13 @@

// Generated by CoffeeScript 1.4.0
module.exports = {
name: 'typescript',
extension: 'ts',
category: 'js',
type: 'compiler',
module.exports = {
name: 'typescript',
extension: 'ts',
category: 'js',
type: 'compiler',
compile: function(data, fn) {}
/**
* Compile 'data'
* @param {String} data
* @param {Function} fn(err, compiled)
*/
compile: function(data, fn) {}
};

@@ -1,19 +0,21 @@

// Generated by CoffeeScript 1.4.0
var cleanCSS;
var cleanCSS = require('clean-css');
cleanCSS = require('clean-css');
module.exports = {
name: 'cleancss',
category: 'css',
type: 'compressor',
module.exports = {
name: 'cleancss',
category: 'css',
type: 'compressor',
compress: function(data, fn) {
var compressed;
try {
compressed = cleanCSS.process(data);
return fn(null, compressed);
} catch (err) {
return fn(err);
}
}
/**
* Compress 'data'
* @param {String} data
* @param {Function} fn(err, compressed)
*/
compress: function(data, fn) {
try {
var compressed = cleanCSS.process(data);
fn(null, compressed);
} catch (err) {
fn(err);
}
}
};

@@ -1,21 +0,21 @@

// Generated by CoffeeScript 1.4.0
var uglify;
var uglify = require('uglify-js');
uglify = require('uglify-js');
module.exports = {
name: 'uglifyjs',
category: 'js',
type: 'compressor',
module.exports = {
name: 'uglifyjs',
category: 'js',
type: 'compressor',
compress: function(data, fn) {
var result;
try {
result = uglify.minify(data, {
fromString: true
});
return fn(null, result.code);
} catch (err) {
return fn(err);
}
}
/**
* Compress 'data'
* @param {String} data
* @param {Function} fn(err, compressed)
*/
compress: function(data, fn) {
try {
var result = uglify.minify(data, {fromString: true});
fn(null, result.code);
} catch (err) {
fn(err);
}
}
};

@@ -1,120 +0,119 @@

// Generated by CoffeeScript 1.4.0
var DEFAULTS, debug, defaults, existsSync, loadModules, overrideDefaults, path, resolvePath, strong, _ref;
var path = require('path')
, existsSync = require('../utils/fs').existsSync
, notify = require('../utils/notify')
, debug = notify.debug
, strong = notify.strong;
path = require('path');
var DEFAULTS = {
js: {
compilers: ['./compilers/coffeescript', './compilers/typescript'],
compressor: './compressor/uglifyjs',
linter: './linter/jshint',
module: './module/node'
},
css: {
compilers: ['./compilers/less', './compilers/stylus'],
compressor: './compressor/cleancss',
linter: './linter/csslint',
module: './module/css'
},
html: {}
}
, defaults = null;
existsSync = require('../utils/fs').existsSync;
_ref = require('../utils/notify'), debug = _ref.debug, strong = _ref.strong;
DEFAULTS = {
js: {
compilers: ['./compilers/coffeescript', './compilers/typescript'],
compressor: './compressor/uglifyjs',
linter: './linter/jshint',
module: './module/node'
},
css: {
compilers: ['./compilers/less', './compilers/stylus'],
compressor: './compressor/cleancss',
linter: './linter/csslint',
module: './module/css'
},
html: {}
};
defaults = null;
exports.installed = null;
/**
* Load all processor modules, overriding defaults if specified in 'options'
* @param {Object} options
* @param {Function} fn(err)
*/
exports.load = function(options, fn) {
debug('PROCESSORS', 1);
defaults = JSON.parse(JSON.stringify(DEFAULTS));
options && overrideDefaults(options);
return loadModules(function(err, processors) {
if (err) {
return fn(err);
}
return fn(null, exports.installed);
});
debug('PROCESSORS', 1);
// Create a copy of DEFAULTS
defaults = JSON.parse(JSON.stringify(DEFAULTS));
// Override if we have options
options && overrideDefaults(options);
loadModules(function(err, processors) {
if (err) return fn(err);
fn(null, exports.installed);
});
};
resolvePath = function(processor, type) {
var processorPath;
processorPath = path.resolve(processor);
if (!existsSync(processorPath + '.js')) {
processorPath = path.resolve(__dirname, type, processor);
}
return processorPath;
};
/**
* Resolve processor path
* Handles overrides of defaults specified in configuration
* @param {String} processor
* @param {String} type
*/
function resolvePath(processor, type) {
// Try version specified in configuration
var processorPath = path.resolve(processor);
// Fallback to default version
if (!existsSync(processorPath + '.js')) {
processorPath = path.resolve(__dirname, type, processor);
}
return processorPath;
}
overrideDefaults = function(options) {
var category, processor, type, _results;
debug('overriding defaults', 2);
_results = [];
for (category in options) {
_results.push((function() {
var _ref1, _results1,
_this = this;
_ref1 = options[category];
_results1 = [];
for (type in _ref1) {
processor = _ref1[type];
if (Array.isArray(defaults[category][type])) {
if (!Array.isArray(processor)) {
processor = [processor];
}
_results1.push(processor.forEach(function(plug) {
debug("override " + category + "/" + type + " with: " + (strong(plug)), 3);
return defaults[category][type].push(resolvePath(plug, type));
}));
} else {
debug("override " + category + "/" + type + " with: " + (strong(processor)), 3);
_results1.push(defaults[category][type] = resolvePath(processor, type));
}
}
return _results1;
}).call(this));
}
return _results;
};
/**
* Override processor defaults with those specified in 'options'
* @param {Object} options
*/
function overrideDefaults(options) {
debug('overriding defaults', 2);
for (var category in options) {
for (var type in options[category]) {
var processor = options[category][type];
if (Array.isArray(defaults[category][type])) {
// Handle arrays of plugins for 'compilers'
if (!Array.isArray(processor)) processor = [processor];
processor.forEach(function(plug) {
debug("override " + category + "/" + type + " with: " + (strong(plug)), 3);
defaults[category][type].push(resolvePath(plug, type));
});
} else {
debug("override " + category + "/" + type + " with: " + (strong(processor)), 3);
defaults[category][type] = resolvePath(processor, type);
}
}
}
}
loadModules = function(fn) {
var category, idx, installed, proc, processor, type, _base, _base1, _i, _len, _ref1, _ref2, _ref3, _ref4;
installed = {};
for (category in defaults) {
if ((_ref1 = installed[category]) == null) {
installed[category] = {};
}
_ref2 = defaults[category];
for (type in _ref2) {
processor = _ref2[type];
if (Array.isArray(processor)) {
if ((_ref3 = (_base = installed[category])[type]) == null) {
_base[type] = [];
}
for (idx = _i = 0, _len = processor.length; _i < _len; idx = ++_i) {
proc = processor[idx];
try {
debug("load " + category + "/" + type + ":" + idx + " => " + (strong(proc)), 2);
installed[category][type][idx] = require(proc);
} catch (err) {
return fn("failed loading processor " + (strong(proc)));
}
}
} else {
if ((_ref4 = (_base1 = installed[category])[type]) == null) {
_base1[type] = {};
}
try {
debug("load " + category + "/" + type + " => " + (strong(processor)), 2);
installed[category][type] = require(processor);
} catch (err) {
return fn("failed loading processor " + (strong(processor)));
}
}
}
}
exports.installed = installed;
return fn();
};
/**
* Load processor modules
* @param {Function} fn(err)
*/
function loadModules(fn) {
var installed = {};
for (var category in defaults) {
// Create category hash
if (installed[category] == null) installed[category] = {};
for (var type in defaults[category]) {
var processor = defaults[category][type];
// Handle arrays of plugins for 'compilers'
if (Array.isArray(processor)) {
if (installed[category][type] == null) installed[category][type] = [];
for (var i = 0, n = processor.length; i < n; ++i) {
var proc = processor[i];
try {
debug("load " + category + "/" + type + ":" + i + " => " + (strong(proc)), 2);
installed[category][type][i] = require(proc);
} catch (err) {
return fn("failed loading processor " + (strong(proc)));
}
}
} else {
if (installed[category][type] == null) installed[category][type] = {};
try {
debug("load " + category + "/" + type + " => " + (strong(processor)), 2);
installed[category][type] = require(processor);
} catch (err) {
return fn("failed loading processor " + (strong(processor)));
}
}
}
}
exports.installed = installed;
return fn();
}

@@ -9,23 +9,27 @@ // Generated by CoffeeScript 1.4.0

module.exports = {
name: 'csslint',
category: 'css',
type: 'linter',
lint: function(data, fn) {
var items, result;
result = csslint.verify(data);
if (result.messages.length) {
items = result.messages.map(function(error) {
var _ref;
return {
line: error.line,
col: error.col,
reason: error.message,
evidence: (_ref = error.evidence) != null ? _ref.replace(RE_TRIM, '') : void 0
};
});
return fn({
items: items
});
}
}
name: 'csslint',
category: 'css',
type: 'linter',
/**
* Lint 'data'
* @param {String} data
* @param {Function} fn(err)
*/
lint: function(data, fn) {
var result = csslint.verify(data);
if (result.messages.length) {
var items = result.messages.map(function(error) {
return {
line: error.line,
col: error.col,
reason: error.message,
evidence: (error.evidence != null)
? error.evidence.replace(RE_TRIM, '')
: null
};
});
fn({items: items});
}
}
};

@@ -1,53 +0,53 @@

// Generated by CoffeeScript 1.4.0
var RE_TRIM, jshint;
var jshint = require('jshint').JSHINT
, RE_TRIM = /^\s+|\s+$/;
jshint = require('jshint').JSHINT;
module.exports = {
name: 'jshint',
category: 'js',
type: 'linter',
options: {
curly: true,
eqeqeq: false,
immed: true,
latedef: true,
newcap: true,
noarg: true,
undef: true,
unused: true,
eqnull: true,
es5: false,
esnext: false,
bitwise: true,
strict: false,
trailing: false,
smarttabs: true,
node: true,
boss: true
},
RE_TRIM = /^\s+|\s+$/;
module.exports = {
name: 'jshint',
category: 'js',
type: 'linter',
options: {
curly: true,
eqeqeq: false,
immed: true,
latedef: true,
newcap: true,
noarg: true,
undef: true,
unused: true,
eqnull: true,
es5: false,
esnext: false,
bitwise: true,
strict: false,
trailing: false,
smarttabs: true,
node: true,
boss: true
},
lint: function(data, fn) {
var items, result;
result = jshint(data, exports.options, {});
if (!result) {
items = jshint.errors.map(function(error) {
var _ref;
if (error) {
return {
line: error.line,
col: error.character,
reason: error.reason,
evidence: (_ref = error.evidence) != null ? _ref.replace(RE_TRIM, '') : void 0
};
} else {
return null;
}
});
return fn({
items: items
});
}
}
/**
* Lint 'data'
* @param {String} data
* @param {Function} fn(err)
*/
lint: function(data, fn) {
var result = jshint(data, exports.options, {});
if (!result) {
var items = jshint.errors.map(function(error) {
if (error) {
return {
line: error.line,
col: error.character,
reason: error.reason,
evidence: (error.evidence != null)
? error.evidence.replace(RE_TRIM, '')
: null
};
} else {
return null;
}
});
fn({items: items});
}
}
};

@@ -1,29 +0,50 @@

// Generated by CoffeeScript 1.4.0
var fs, path;
var path = require('path')
, fs = require('fs');
path = require('path');
module.exports = {
name: 'amd',
category: 'js',
type: 'module',
fs = require('fs');
/**
* Retrieve a module's id based on it's 'qualifiedFilename'
* @param {String} qualifiedFilename
* @return {String}
*/
getModuleID: function(qualifiedFilename) {
return '';
},
module.exports = {
name: 'amd',
category: 'js',
type: 'module',
getModuleID: function(qualifiedFilename) {
return '';
},
getModuleDependencies: function(contents, id) {
var deps;
deps = [];
return deps;
},
wrapModuleContents: function(contents, id, isMain) {
if (isMain == null) {
isMain = false;
}
return contents;
},
getModuleFrameworkSource: function() {
return '';
}
/**
* Retrieve all module references in file 'content'
* Convert all references relative to 'id'
* @param {String} content
* @param {String} id
* @return {Array}
*/
getModuleDependencies: function(contents, id) {
var deps;
deps = [];
return deps;
},
/**
* Wrap 'content' in module definition if not already wrapped
* @param {String} content
* @param {String} id
* @param {Boolean} lazy
* @return {String}
*/
wrapModuleContents: function(contents, id, lazy) {
return contents;
},
/**
* Concatenate file and dependency content
* @param {File} file
* @return String
*/
concat: function(file) {
return '';
}
};

@@ -1,73 +0,103 @@

// Generated by CoffeeScript 1.4.0
var RE_COMMENT_LINES, RE_IMPORT, RE_WIN_SEPARATOR, path;
var path = require('path');
path = require('path');
var RE_WIN_SEPARATOR = /\\\\?/g
, RE_IMPORT = /@import\s['|"](.*?)['|"];?/g
, RE_COMMENT_LINES = /((?:\/\*(?:[^*]|(?:\*+[^*\/]))*\*+\/))$/gm;
RE_WIN_SEPARATOR = /\\\\?/g;
module.exports = {
name: 'css',
category: 'css',
type: 'module',
RE_IMPORT = /@import\s['|"](.*?)['|"];?/g;
/**
* Retrieve a module's id based on it's 'qualifiedFilename'
* @param {String} qualifiedFilename
* @return {String}
*/
getModuleID: function(qualifiedFilename) {
// Convert to lowercase
var module = qualifiedFilename.toLowerCase();
// Fix path separator for windows
if (process.platform === 'win32') module = module.replace(RE_WIN_SEPARATOR, '/');
return module;
},
RE_COMMENT_LINES = /((?:\/\*(?:[^*]|(?:\*+[^*\/]))*\*+\/))$/gm;
/**
* Retrieve all module references in file 'content'
* Convert all references relative to 'id'
* @param {String} content
* @param {String} id
* @return {Array}
*/
getModuleDependencies: function(content, id) {
var deps = []
, dep, d, match, part, parts;
// Remove commented lines
content = content.replace(RE_COMMENT_LINES, '');
// Match all uses of '@import'
while (match = RE_IMPORT.exec(content)) {
dep = match[1].replace('.css', '');
// Force relative path
if (dep.indexOf('/') == -1) dep = './' + dep;
parts = dep.split('/');
if (dep.charAt(0) == '.') {
parts = id.split('/');
parts.pop();
d = dep.split('/');
for (var i = 0, n = d.length; i < n; ++i) {
part = d[i];
if (part == '..') {
parts.pop();
} else if (part != '.') {
parts.push(part);
}
}
}
deps.push(parts.join('/'));
}
return deps;
},
module.exports = {
name: 'css',
category: 'css',
type: 'module',
getModuleID: function(qualifiedFilename) {
var module;
module = qualifiedFilename.toLowerCase();
if (process.platform === 'win32') {
module = module.replace(RE_WIN_SEPARATOR, '/');
}
return module;
},
getModuleDependencies: function(content, id) {
var dep, deps, match, part, parts, _i, _len, _ref;
deps = [];
content = content.replace(RE_COMMENT_LINES, '');
while (match = RE_IMPORT.exec(content)) {
dep = match[1].replace('.css', '');
if (dep.indexOf('/') === -1) {
dep = './' + dep;
}
parts = dep.split('/');
if (dep.charAt(0) === '.') {
parts = id.split('/');
parts.pop();
_ref = dep.split('/');
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
part = _ref[_i];
if (part === '..') {
parts.pop();
} else if (part !== '.') {
parts.push(part);
}
}
}
deps.push(parts.join('/'));
}
return deps;
},
wrapModuleContents: function(content, id) {
return content;
},
concat: function(file) {
var inline;
inline = function(file, content) {
file.dependencies.forEach(function(dependency) {
var id, inlineContent, re;
if ('string' !== typeof dependency) {
inlineContent = dependency.dependencies.length ? inline(dependency, dependency.getContent(false)) : dependency.getContent(false);
id = dependency.moduleID.split('/').reverse()[0];
} else {
inlineContent = '';
id = dependency.split('/').reverse()[0];
}
re = new RegExp("^@import\\s['|\"](?:\\.\\/)?(?:\\w*\/)?" + id + "(?:\\.css)?['|\"];?\\s*$", 'im');
return content = content.replace(re, inlineContent + '\n');
});
return content;
};
return inline(file, file.getContent(false)).replace(RE_COMMENT_LINES, '');
}
/**
* Wrap 'content' in module definition if not already wrapped
* @param {String} content
* @param {String} id
* @return {String}
*/
wrapModuleContents: function(content, id) {
// No op
return content;
},
/**
* Concatenate file and dependency content
* @param {File} file
* @return String
*/
concat: function(file) {
var inline = function(file, content) {
file.dependencies.forEach(function(dependency) {
var id, inlineContent, re;
if ('string' !== typeof dependency) {
// First inline dependencies if necessary
inlineContent = dependency.dependencies.length
? inline(dependency, dependency.getContent(false))
: dependency.getContent(false);
// Replace @import with inline content
// Use fuzzy match to get around absolute and relative pathing differences
id = dependency.moduleID.split('/').reverse()[0];
} else {
// Dependency already inlined
inlineContent = '';
id = dependency.split('/').reverse()[0];
}
re = new RegExp("^@import\\s['|\"](?:\\.\\/)?(?:\\w*\/)?" + id + "(?:\\.css)?['|\"];?\\s*$", 'im');
content = content.replace(re, inlineContent + '\n');
});
return content;
};
// Remove comments and return
return inline(file, file.getContent(false)).replace(RE_COMMENT_LINES, '');
}
};

@@ -1,99 +0,127 @@

// Generated by CoffeeScript 1.4.0
var ESCAPE_MAP, RE_COMMENT_LINES, RE_ESCAPE, RE_MODULE, RE_MODULE_LAZY, RE_REQUIRE, RE_SPACES, RE_WIN_SEPARATOR, debug, indent, path, _ref;
var path = require('path')
, notify = require('../../utils/notify')
, indent = notify.indent
, debug = notify.debug;
path = require('path');
var RE_WIN_SEPARATOR = /\\\\?/g
, RE_MODULE = /require\.register[\s|\(].+(?:function)? *\( *module *, *exports *, *require *\)/gm
, RE_MODULE_LAZY = /require\.register[\s|\(].+\)?/gm
, RE_COMMENT_LINES = /^\s*(?:\/\/|#).+$/gm
, RE_REQUIRE = /require[\s|\(]['|"](.*?)['|"]/g
, RE_SPACES = /\s/
, RE_ESCAPE = /\\|\r?\n|"/g
, ESCAPE_MAP = {
'\\': '\\\\',
'\n': '\\n',
'\r\n': '\\n',
'"': '\\"'
};
_ref = require('../../utils/notify'), indent = _ref.indent, debug = _ref.debug;
module.exports = {
name: 'node',
category: 'js',
type: 'module',
RE_WIN_SEPARATOR = /\\\\?/g;
/**
* Retrieve a module's id based on it's 'qualifiedFilename'
* @param {String} qualifiedFilename
* @return {String}
*/
getModuleID: function(qualifiedFilename) {
// Convert to lowercase and remove spaces
var module = qualifiedFilename.toLowerCase().replace(RE_SPACES, '');
// Fix path separator for windows
if (process.platform == 'win32') module = module.replace(RE_WIN_SEPARATOR, '/');
return module;
},
RE_MODULE = /require\.register[\s|\(].+(?:function)? *\( *module *, *exports *, *require *\)/gm;
/**
* Retrieve all module references in file 'content'
* Convert all references relative to 'id'
* @param {String} content
* @param {String} id
* @return {Array}
*/
getModuleDependencies: function(content, id) {
var deps = []
, dep, d, match, part, parts;
// Remove commented lines
content = content.replace(RE_COMMENT_LINES, '');
while (match = RE_REQUIRE.exec(content)) {
dep = match[1];
parts = dep.split('/');
// Resolve relative path
if (dep.charAt(0) == '.') {
parts = id.split('/');
parts.pop();
d = dep.split('/');
for (var i = 0, n = d.length; i < n; ++i) {
part = d[i];
if (part == '..') {
parts.pop();
} else if (part != '.') {
parts.push(part);
}
}
}
deps.push(parts.join('/'));
}
return deps;
},
RE_MODULE_LAZY = /require\.register[\s|\(].+\)?/gm;
/**
* Wrap 'content' in module definition if not already wrapped
* @param {String} content
* @param {String} id
* @param {Boolean} lazy
* @return {String}
*/
wrapModuleContents: function(content, id, lazy) {
if (lazy == null) lazy = false;
var re = lazy
? RE_MODULE_LAZY
: RE_MODULE;
// Reset
re.lastIndex = 0;
if (!re.test(content)) {
if (lazy) {
content = "require.register('"
+ id
+ "', "
+ content
+ ");";
} else {
content = "require.register('"
+ id
+ "', function(module, exports, require) {\n"
+ (indent(content, 2))
+ "\n});";
}
}
return content;
},
RE_COMMENT_LINES = /^\s*(?:\/\/|#).+$/gm;
/**
* Concatenate file and dependency content
* @param {File} file
* @return String
*/
concat: function(file) {
var contents = []
, add;
// Inner function
add = function(file) {
var content;
// First add dependencies
file.dependencies.forEach(function(dependency) {
if ('string' !== typeof dependency) add(dependency);
});
// Store if not already stored
content = file.getContent(true);
if (contents.indexOf(content) == -1) contents.push(content);
};
RE_REQUIRE = /require[\s|\(]['|"](.*?)['|"]/g;
RE_SPACES = /\s/;
RE_ESCAPE = /\\|\r?\n|"/g;
ESCAPE_MAP = {
'\\': '\\\\',
'\n': '\\n',
'\r\n': '\\n',
'"': '\\"'
add(file);
return contents.join('\n');
}
};
module.exports = {
name: 'node',
category: 'js',
type: 'module',
getModuleID: function(qualifiedFilename) {
var module;
module = qualifiedFilename.toLowerCase().replace(RE_SPACES, '');
if (process.platform === 'win32') {
module = module.replace(RE_WIN_SEPARATOR, '/');
}
return module;
},
getModuleDependencies: function(content, id) {
var dep, deps, match, part, parts, _i, _len, _ref1;
deps = [];
content = content.replace(RE_COMMENT_LINES, '');
while (match = RE_REQUIRE.exec(content)) {
dep = match[1];
parts = dep.split('/');
if (dep.charAt(0) === '.') {
parts = id.split('/');
parts.pop();
_ref1 = dep.split('/');
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
part = _ref1[_i];
if (part === '..') {
parts.pop();
} else if (part !== '.') {
parts.push(part);
}
}
}
deps.push(parts.join('/'));
}
return deps;
},
wrapModuleContents: function(content, id, lazy) {
var re;
if (lazy == null) {
lazy = false;
}
re = lazy ? RE_MODULE_LAZY : RE_MODULE;
re.lastIndex = 0;
if (!re.test(content)) {
if (lazy) {
content = "require.register('" + id + "', " + content + ");";
} else {
content = "require.register('" + id + "', function(module, exports, require) {\n" + (indent(content, 2)) + "\n});";
}
}
return content;
},
concat: function(file) {
var add, contents;
contents = [];
add = function(file) {
var content;
file.dependencies.forEach(function(dependency) {
if ('string' !== typeof dependency) {
return add(dependency);
}
});
content = file.getContent(true);
if (contents.indexOf(content) === -1) {
return contents.push(content);
}
};
add(file);
return contents.join('\n');
}
};

@@ -1,76 +0,81 @@

// Generated by CoffeeScript 1.4.0
var NAME, RE_ABSOLUTE, clean, debug, existsSync, fs, path, strong, _ref;
var fs = require('fs')
, path = require('path')
, existsSync = require('./fs').existsSync
, debug = require('./notify').debug
, strong = require('./notify').strong
, NAME = '.buddy-filelog'
, RE_ABSOLUTE = /^([a-z]:\\)|^\//i;
fs = require('fs');
path = require('path');
existsSync = require('./fs').existsSync;
_ref = require('./notify'), debug = _ref.debug, strong = _ref.strong;
NAME = '.buddy-filelog';
RE_ABSOLUTE = /^([a-z]:\\)|^\//i;
exports.filename = null;
exports.files = [];
/**
* Load existing log file
* @param {Function} fn(err)
*/
exports.load = function(fn) {
exports.filename = path.resolve(NAME);
if (existsSync(exports.filename)) {
return fs.readFile(exports.filename, 'utf8', function(err, data) {
if (err) {
return fn(err);
}
try {
exports.files = JSON.parse(data);
if (exports.files.length) {
if ((path.sep === '/' && data.indexOf('\\') !== -1) || (path.sep === '\\' && data.indexOf('/') !== -1) || RE_ABSOLUTE.test(exports.files[0])) {
clean(function(err) {
return fn();
});
}
}
} catch (err) {
return fn(err);
}
return fn();
});
} else {
return fn();
}
exports.filename = path.resolve(NAME);
if (existsSync(exports.filename)) {
fs.readFile(exports.filename, 'utf8', function(err, data) {
if (err) return fn(err);
try {
exports.files = JSON.parse(data);
if (exports.files.length) {
// Clean if file is old or from another system
if ((path.sep == '/' && data.indexOf('\\') != -1)
|| (path.sep == '\\' && data.indexOf('/') != -1)
|| RE_ABSOLUTE.test(exports.files[0])) {
exports.clean(function(err) {
return fn();
});
}
}
} catch (err) {
return fn(err);
}
return fn();
});
} else {
return fn();
}
};
/**
* Add 'files' to the file log
* @param {Array} newFiles
* @param {Function} [fn(err, files)]
*/
exports.add = function(newFiles, fn) {
var _this = this;
newFiles.forEach(function(file) {
file = path.relative(process.cwd(), file);
if (exports.files.indexOf(file) === -1) {
exports.files.push(file);
return debug("adding to filelog: " + (strong(file)), 2);
}
});
return fs.writeFile(exports.filename, JSON.stringify(exports.files), 'utf8', function(err) {
if (fn) {
if (err) {
return fn(err);
}
return fn(null, exports.files);
}
});
newFiles.forEach(function(file) {
file = path.relative(process.cwd(), file);
if (exports.files.indexOf(file) == -1) {
exports.files.push(file);
debug("adding to filelog: " + (strong(file)), 2);
}
});
// Save
fs.writeFile(exports.filename, JSON.stringify(exports.files), 'utf8', function(err) {
// Callback
if (fn) {
if (err) return fn(err);
fn(null, exports.files);
}
});
};
exports.clean = clean = function(fn) {
exports.files = [];
return fs.writeFile(exports.filename, JSON.stringify(exports.files), 'utf8', function(err) {
debug('cleaned filelog', 2);
if (fn) {
if (err) {
return fn(err);
}
return fn();
}
});
/**
* Clean the file log of file references
* @param {Function} [fn(err)]
*/
exports.clean = function(fn) {
exports.files = [];
// Save
fs.writeFile(exports.filename, JSON.stringify(exports.files), 'utf8', function(err) {
debug('cleaned filelog', 2);
// Callback
if (fn) {
if (err) return fn(err);
fn();
}
});
};

@@ -1,244 +0,267 @@

// Generated by CoffeeScript 1.4.0
var RE_IGNORE, cp, exists, existsSync, fs, mkdir, mkdirp, mv, path, readdir, rimraf, rm;
var fs = require('fs')
, path = require('path')
, mkdirp = require('mkdirp')
, rimraf = require('rimraf')
, RE_IGNORE = /^[\.~]|~$/;
fs = require('fs');
// Node 0.8.0 api change
var existsSync = exports.existsSync = fs.existsSync || path.existsSync;
var exists = exports.exists = fs.exists || path.exists;
path = require('path');
mkdirp = require('mkdirp');
rimraf = require('rimraf');
exports.existsSync = existsSync = fs.existsSync || path.existsSync;
exports.exists = exists = fs.exists || path.exists;
RE_IGNORE = /^[\.~]|~$/;
// starts with '.', or '~', ends with '~'
exports.ignoredHidden = /^[\.~]|~$/;
// starts with '.', or '~' contains '-min.', '.min.' or 'svn', ends with '~'
exports.ignored = /^[\.~]|[-\.]min[-\.]|svn|~$/;
/**
* Check that a 'filepath' is likely a child of a given directory
* Applies to nested directories
* Only makes String comparison. Does not check for existance
* @param {String} dir
* @param {String} filepath
* @returns {Boolean}
*/
exports.indir = function(dir, filepath) {
dir = path.resolve(dir);
filepath = path.resolve(filepath);
if (filepath.indexOf(dir) !== -1) {
if (path.relative(dir, filepath).indexOf('..') !== -1) {
return false;
} else {
return true;
}
} else {
return false;
}
dir = path.resolve(dir);
filepath = path.resolve(filepath);
if (filepath.indexOf(dir) != -1) {
if (path.relative(dir, filepath).indexOf('..') != -1) {
return false;
} else {
return true;
}
} else {
return false;
}
};
exports.readdir = readdir = function(dir, ignore, fn) {
var _files, _outstanding, _readdir;
ignore = ignore ? new RegExp(exports.ignoredHidden.source + '|' + ignore.source) : exports.ignoredHidden;
_outstanding = 0;
_files = [];
_readdir = function(dir) {
if (existsSync(dir)) {
_outstanding++;
return fs.readdir(dir, function(err, files) {
_outstanding--;
if (err) {
return fn(err);
}
files.forEach(function(file) {
var filepath;
if (!ignore.test(path.basename(file))) {
filepath = path.resolve(dir, file);
_outstanding++;
return fs.stat(filepath, function(err, stats) {
_outstanding--;
if (err) {
if (err.code === 'ENOENT') {
} else {
return fn(err);
}
} else {
if (stats.isDirectory()) {
return _readdir(filepath);
} else {
_files.push(filepath);
if (!_outstanding) {
return fn(null, _files);
}
}
}
});
}
});
if (!_outstanding) {
return fn(null, _files);
}
});
} else {
if (!_outstanding) {
return fn(null, _files);
}
}
};
return _readdir(dir);
/**
* Read and store the contents of a directory, ignoring files of type specified
* @param {String} dir
* @param {Regex} ignore
* @param {Function} fn(err, files)
*/
var readdir = exports.readdir = function(dir, ignore, fn) {
var _files = []
, _outstanding = 0
, _readdir;
// Merge ignores
ignore = ignore
? new RegExp(exports.ignoredHidden.source + '|' + ignore.source)
: exports.ignoredHidden;
// Inner function
_readdir = function(dir) {
if (existsSync(dir)) {
_outstanding++;
return fs.readdir(dir, function(err, files) {
_outstanding--;
if (err) return fn(err);
files.forEach(function(file) {
// Skip ignored files
if (!ignore.test(path.basename(file))) {
var filepath = path.resolve(dir, file);
_outstanding++;
return fs.stat(filepath, function(err, stats) {
_outstanding--;
if (err) {
// Exit if proper error, otherwise skip
if (err.code === 'ENOENT') return;
else return fn(err);
} else {
// Recurse child directory
if (stats.isDirectory()) {
return _readdir(filepath);
} else {
// Store
_files.push(filepath);
// Return if no outstanding
if (!_outstanding) return fn(null, _files);
}
}
});
}
});
// Return if no outstanding
if (!_outstanding) return fn(null, _files);
});
// Return if no outstanding
} else if (!_outstanding) return fn(null, _files);
};
return _readdir(dir);
};
exports.mkdir = mkdir = function(filepath, fn) {
var dir;
dir = path.extname(filepath) ? path.dirname(filepath) : filepath;
if (!existsSync(dir)) {
return mkdirp(dir, function(err) {
if (err) {
return fn(err);
} else {
return fn();
}
});
} else {
return fn();
}
/**
* Recursively create directory path specified by 'filepath'
* @param {String} filepath
* @param {Function} fn(err)
*/
var mkdir = exports.mkdir = function(filepath, fn) {
// Resolve directory name if passed a file
var dir = path.extname(filepath)
? path.dirname(filepath)
: filepath;
if (!existsSync(dir)) {
mkdirp(dir, function(err) {
if (err) return fn(err);
else return fn();
});
} else {
return fn();
}
};
exports.mv = mv = function(source, destination, force, fn) {
if (force == null) {
force = false;
}
return mkdir(destination, function(err) {
var filepath;
if (err) {
return fn(err);
} else {
filepath = path.resolve(destination, path.basename(source));
if (!force && existsSync(filepath)) {
return fn(null, filepath);
} else {
return rm(filepath, function(err) {
return fs.rename(source, filepath, function(err) {
if (err) {
return fn(err);
} else {
return fn(null, filepath);
}
});
});
}
}
});
/**
* Move file or directory 'source' to 'destination'
* @param {String} source
* @param {String} destination
* @param {Boolean} force
* @param {Function} fn(err, filepath)
*/
var mv = exports.mv = function(source, destination, force, fn) {
if (force == null) force = false;
mkdir(destination, function(err) {
if (err) {
return fn(err);
} else {
var filepath = path.resolve(destination, path.basename(source));
if (!force && existsSync(filepath)) {
return fn(null, filepath);
} else {
rm(filepath, function(err) {
// Ignore rm errors
fs.rename(source, filepath, function(err) {
if (err) return fn(err);
else return fn(null, filepath);
});
});
}
}
});
};
exports.cp = cp = function(source, destination, force, fn) {
var _base, _cp, _filepath, _first, _outstanding;
if (force == null) {
force = false;
}
_outstanding = 0;
_base = '';
_filepath = '';
_first = true;
_cp = function(source, destination) {
_outstanding++;
fs.stat(source, function(err, stats) {
var contentsOnly, dest, destDir, destName, filepath, isDestFile;
_outstanding--;
if (err) {
if (err.code === 'ENOENT') {
} else {
return fn(err);
}
} else {
isDestFile = path.extname(destination).length;
if (stats.isFile()) {
destDir = isDestFile ? path.dirname(destination) : destination;
destName = isDestFile ? path.basename(destination) : path.basename(source);
filepath = path.resolve(destDir, destName);
if (!force && existsSync(filepath)) {
if (!_outstanding) {
return fn(null, _filepath);
}
} else {
return rm(filepath, function(err) {
var file;
_outstanding++;
if (_first) {
_filepath = filepath;
_first = false;
}
fs.createReadStream(source).pipe(file = fs.createWriteStream(filepath));
file.on('error', function(err) {
return fn(err);
});
return file.on('close', function() {
_outstanding--;
if (!_outstanding) {
return fn(null, _filepath);
}
});
});
}
} else {
if (isDestFile) {
return fn(new Error('invalid destination for copy: ' + destination));
} else {
contentsOnly = _first && /\\$|\/$/.test(source);
dest = contentsOnly ? destination : path.resolve(destination, path.basename(source));
_outstanding++;
return mkdir(dest, function(err) {
_outstanding--;
if (err) {
return fn(err);
} else {
_outstanding++;
return fs.readdir(source, function(err, files) {
_outstanding--;
if (err) {
if (err.code === 'ENOENT') {
} else {
return fn(err);
}
} else {
if (_first) {
_filepath = dest;
_first = false;
}
files.forEach(function(file) {
return _cp(path.resolve(source, file), dest);
});
if (!_outstanding) {
return fn(null, _filepath);
}
}
});
}
});
}
}
}
});
if (!_outstanding) {
return fn(null, _filepath);
}
};
return _cp(source, destination);
/**
* Copy file or directory 'source' to 'destination'
* Copies contents of 'source' if directory and ends in trailing '/'
* @param {String} source
* @param {String} destination
* @param {Boolean} force
* @param {Function} fn(err, filepath)
*/
var cp = exports.cp = function(source, destination, force, fn) {
var _base = ''
, _filepath = ''
, _first = true
, _outstanding = 0
, _cp;
if (force == null) force = false;
// Inner function
_cp = function(source, destination) {
_outstanding++;
fs.stat(source, function(err, stats) {
var isDestFile;
_outstanding--;
// Exit if proper error, otherwise skip
if (err) {
if (err.code === 'ENOENT') return;
else return fn(err);
} else {
isDestFile = path.extname(destination).length;
// File
if (stats.isFile()) {
// Handle file or directory as destination
var destDir = isDestFile ? path.dirname(destination) : destination
, destName = isDestFile ? path.basename(destination) : path.basename(source)
, filepath = path.resolve(destDir, destName);
// Write file if it doesn't already exist
if (!force && existsSync(filepath)) {
if (!_outstanding) return fn(null, _filepath);
} else {
rm(filepath, function(err) {
// Ignore rm errors
var file;
_outstanding++;
// Return the new path for the first source
if (_first) {
_filepath = filepath;
_first = false;
}
// Pipe stream
fs.createReadStream(source).pipe(file = fs.createWriteStream(filepath));
file.on('error', function(err) { return fn(err); });
file.on('close', function() {
_outstanding--;
// Return if no outstanding
if (!_outstanding) return fn(null, _filepath);
});
});
}
// Directory
} else {
// Guard against invalid directory to file copy
if (isDestFile) {
fn(new Error('invalid destination for copy: ' + destination));
} else {
// Copy contents only if source ends in '/'
var contentsOnly = _first && /\\$|\/$/.test(source)
, dest = contentsOnly ? destination : path.resolve(destination, path.basename(source));
// Create in destination
_outstanding++;
mkdir(dest, function(err) {
_outstanding--;
if (err) {
return fn(err);
} else {
// Loop through contents
_outstanding++;
fs.readdir(source, function(err, files) {
_outstanding--;
// Exit if proper error, otherwise skip
if (err) {
if (err.code === 'ENOENT') return;
else return fn(err);
} else {
// Return the new path for the first source
if (_first) {
_filepath = dest;
_first = false;
}
// Loop through files and cp
files.forEach(function(file) {
_cp(path.resolve(source, file), dest);
});
// Return if no outstanding
if (!_outstanding) return fn(null, _filepath);
}
});
}
});
}
}
}
});
// Return if no outstanding
if (!_outstanding) return fn(null, _filepath);
};
return _cp(source, destination);
};
exports.rm = rm = function(source, fn) {
if (existsSync(source)) {
if (source.indexOf(process.cwd()) !== -1) {
return rimraf(source, function(err) {
if (err) {
return fn(err);
} else {
return fn();
}
});
} else {
return fn(new Error('cannot rm source outside of project path: ' + source));
}
} else {
return fn(new Error('cannot rm non-existant source: ' + source));
}
/**
* Recursive remove file or directory
* Makes sure only project sources are removed
* @param {String} source
* @param {Function} fn(err)
*/
var rm = exports.rm = function(source, fn) {
if (existsSync(source)) {
if (source.indexOf(process.cwd()) != -1) {
rimraf(source, function(err) {
if (err) return fn(err);
else return fn();
});
} else {
fn(new Error('cannot rm source outside of project path: ' + source));
}
} else {
fn(new Error('cannot rm non-existant source: ' + source));
}
};

@@ -1,90 +0,97 @@

// Generated by CoffeeScript 1.4.0
// Console output formatting
exports.RED = '0;31';
exports.YELLOW = '0;33';
exports.CYAN = '0;36';
exports.GREEN = '0;32';
exports.GREY = '0;90';
exports.silent = false;
exports.verbose = false;
exports.nocolor = !process.stdout.isTTY;
exports.start = exports.last = 0;
/**
* Add TTY colours to given 'string'
* @param {String} string
* @param {String} colourCode
*/
exports.colour = function(string, colourCode) {
if (exports.nocolor) {
return string;
} else {
return '\033[' + colourCode + 'm' + string + '\033[0m';
}
if (exports.nocolor) return string;
else return '\033[' + colourCode + 'm' + string + '\033[0m';
};
/**
* Print 'msg' to console, with indentation level
* @param {String} msg
* @param {Int} column
*/
exports.print = function(msg, column) {
if (column == null) {
column = 0;
}
if (!exports.silent) {
return console.log(exports.indent(msg, column));
}
if (column == null) column = 0;
if (!exports.silent) console.log(exports.indent(msg, column));
};
/**
* Print 'err' to console, with error colour and indentation level
* @param {Object or String} err
* @param {Int} column
*/
exports.error = function(err, column, throws) {
if (column == null) {
column = 0;
}
if (throws == null) {
throws = true;
}
if ('string' === typeof err) {
err = new Error(err);
}
if (!throws) {
err.message += '\x07';
}
exports.print("" + (exports.colour('error', exports.RED)) + ": " + err.message, column);
if (throws) {
throw err;
}
if (column == null) column = 0;
if (throws == null) throws = true;
if ('string' == typeof err) err = new Error(err);
// Add beep when not throwing
if (!throws) err.message += '\x07';
exports.print("" + (exports.colour('error', exports.RED)) + ": " + err.message, column);
if (throws) throw err;
};
/**
* Print 'msg' to console, with warning colour and indentation level
* @param {String} msg
* @param {Int} column
*/
exports.warn = function(msg, column) {
if (column == null) {
column = 0;
}
if ('string' instanceof Error) {
msg = msg.message;
}
return exports.print("" + (exports.colour('warning', exports.YELLOW)) + " " + msg, column);
if (column == null) column = 0;
if ('string' instanceof Error) msg = msg.message;
exports.print("" + (exports.colour('warning', exports.YELLOW)) + " " + msg, column);
};
/**
* Print 'msg' to console, with debug colour and indentation level
* @param {String} msg
* @param {Int} column
*/
exports.debug = function(msg, column) {
var now;
if (column == null) {
column = 0;
}
now = +(new Date);
if (!exports.last) {
exports.last = exports.start;
}
if (exports.verbose) {
exports.print("" + (exports.colour('+', exports.CYAN)) + (exports.strong(now - exports.last + 'ms')) + (exports.colour('::', exports.CYAN)) + (exports.strong(now - exports.start + 'ms')) + (exports.colour('=', exports.CYAN)) + msg, column);
}
return exports.last = now;
var now = +new Date;
if (column == null) column = 0;
if (!exports.last) exports.last = exports.start;
if (exports.verbose) {
msg = ""
+ exports.colour('+', exports.CYAN)
+ exports.strong(now - exports.last + 'ms')
+ exports.colour('::', exports.CYAN)
+ exports.strong(now - exports.start + 'ms')
+ exports.colour('=', exports.CYAN)
+ msg;
exports.print(msg, column);
}
exports.last = now;
};
/**
* Colourize 'string' for emphasis
* @param {String} string
*/
exports.strong = function(string) {
return exports.colour(string, exports.GREY);
return exports.colour(string, exports.GREY);
};
/**
* Indent the given 'string' a specific number of spaces
* @param {String} string
* @param {Int} column
*/
exports.indent = function(string, column) {
var spaces;
spaces = (new Array(column)).join(' ');
return string.replace(/^/gm, spaces);
var spaces = (new Array(column)).join(' ');
return string.replace(/^/gm, spaces);
};

@@ -1,20 +0,35 @@

// Generated by CoffeeScript 1.4.0
/**
* Extend 'obj' with properties from 'options'
* @param {Object} obj
* @param {Object} options
*/
exports.extend = function(obj, options) {
var option, value;
for (option in options) {
value = options[option];
obj[option] = value;
}
return obj;
for (var option in options) {
obj[option] = options[option];
}
return obj;
};
/**
* Shallow copy of 'obj'
* @param {Object} obj
* @return {Object}
*/
exports.clone = function(obj) {
var o, prop, value;
o = {};
for (prop in obj) {
value = obj[prop];
o[prop] = value;
}
return o;
var o = {};
for (var prop in obj) {
o[prop] = obj[prop];
}
return o;
};
/**
* Bind 'fn' to 'ctx'
* @param {Function} fn
* @param {Object} ctx
*/
exports.bind = function(fn, ctx) {
return function(){
return fn.apply(ctx, arguments);
};
};

@@ -1,79 +0,88 @@

// Generated by CoffeeScript 1.4.0
var EventEmitter, Parser, ReloadConnection, TIMEOUT,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
var EventEmitter = require('events').EventEmitter
, util = require("util")
, Parser = require('livereload-protocol')
, TIMEOUT = 1000;
EventEmitter = require('events').EventEmitter;
module.exports = ReloadConnection;
Parser = require('livereload-protocol');
/**
* Constructor
* @param {Object} socket
* @param {String} id
* @param {Object} options
*/
function ReloadConnection(socket, id, options) {
EventEmitter.call(this);
var self = this
, timeoutID = null
, protocols = {
monitoring: [Parser.protocols.MONITORING_7],
conncheck: [Parser.protocols.CONN_CHECK_1],
saving: [Parser.protocols.SAVING_1]
};
this.socket = socket;
this.id = id;
this.parser = new Parser('server', protocols);
TIMEOUT = 1000;
// Register for socket events
this.socket.on('message', function(data) {
self.parser.received(data);
});
this.socket.on('close', function() {
if (timeoutID) clearTimeout(timeoutID);
self.emit('disconnected');
});
this.socket.on('error', function(err) {
self.socket.close();
self.emit('error', err);
});
module.exports = ReloadConnection = (function(_super) {
// Register for parser events
this.parser.on('command', function(command) {
if (command.command === 'ping') {
self.send({command: 'pong', token: command.token});
} else {
self.emit('command', command);
}
});
this.parser.on('connected', function() {
if (timeoutID) clearTimeout(timeoutID);
self.send(self.parser.hello(options));
self.emit('connected');
});
__extends(ReloadConnection, _super);
// Start handshake timeout
timeoutID = setTimeout(function() {
timeoutID = null;
self.close();
}, TIMEOUT);
}
function ReloadConnection(socket, id, options) {
var protocols, timeoutID,
_this = this;
this.socket = socket;
this.id = id;
protocols = {
monitoring: [Parser.protocols.MONITORING_7],
conncheck: [Parser.protocols.CONN_CHECK_1],
saving: [Parser.protocols.SAVING_1]
};
this.parser = new Parser('server', protocols);
this.socket.on('message', function(data) {
return _this.parser.received(data);
});
this.socket.on('close', function() {
if (timeoutID) {
clearTimeout(timeoutID);
}
return _this.emit('disconnected');
});
this.socket.on('error', function(err) {
_this.socket.close();
return _this.emit('error', err);
});
this.parser.on('command', function(command) {
if (command.command === 'ping') {
return _this.send({
command: 'pong',
token: command.token
});
} else {
return _this.emit('command', command);
}
});
this.parser.on('connected', function() {
if (timeoutID) {
clearTimeout(timeoutID);
}
_this.send(_this.parser.hello(options));
return _this.emit('connected');
});
timeoutID = setTimeout(function() {
timeoutID = null;
return _this.close();
}, TIMEOUT);
}
// Inherit
util.inherits(ReloadConnection, EventEmitter);
ReloadConnection.prototype.isActive = function() {
var _ref;
return ((_ref = this.parser.negotiatedProtocols) != null ? _ref.monitoring : void 0) >= 7;
};
/**
* Get active state
* @return {Boolean}
*/
ReloadConnection.prototype.isActive = function() {
if (this.parser.negotiatedProtocols != null) {
return this.parser.negotiatedProtocols.monitoring >= 7;
}
};
ReloadConnection.prototype.send = function(msg) {
this.parser.sending(msg);
return this.socket.send(JSON.stringify(msg));
};
/**
* Send 'msg' to client
* @param {Object} msg
*/
ReloadConnection.prototype.send = function(msg) {
this.parser.sending(msg);
this.socket.send(JSON.stringify(msg));
};
ReloadConnection.prototype.close = function() {
return this.socket.close();
};
return ReloadConnection;
})(EventEmitter);
/**
* Close connection
*/
ReloadConnection.prototype.close = function() {
this.socket.close();
};

@@ -1,61 +0,68 @@

// Generated by CoffeeScript 1.4.0
var ReloadServer, debug, fs, path, print, ready, server, strong, _ref;
var path = require('path')
, fs = require('fs')
, ReloadServer = require('./reloadserver')
, notify = require('./notify')
, debug = notify.debug
, strong = notify.strong
, print = notify.print
, ready = false
, server;
path = require('path');
/**
* Start the reload server
* @param {Function} fn(err)
*/
exports.start = function(fn) {
if (!server) {
server = new ReloadServer();
server.on('connected', function(connection) {
print("live-reload client connected: " + connection.id, 3);
});
server.on('disconnected', function(connection) {
print("live-reload client disconnected: " + connection.id, 3);
});
server.on('command', function(message) {
debug("received live-reload command '" + message.command + "': " + message.url, 4);
});
server.on('error', function(err) {
fn(err);
});
fs = require('fs');
ReloadServer = require('./reloadserver');
_ref = require('./notify'), debug = _ref.debug, strong = _ref.strong, print = _ref.print;
server = null;
ready = false;
exports.start = function(fn) {
if (!server) {
server = new ReloadServer();
server.on('connected', function(connection) {
return print("live-reload client connected: " + connection.id, 3);
});
server.on('disconnected', function(connection) {
return print("live-reload client disconnected: " + connection.id, 3);
});
server.on('command', function(message) {
return debug("received live-reload command '" + message.command + "': " + message.url, 4);
});
server.on('error', function(err) {
return fn(err);
});
return server.listen(function(err) {
if (!err) {
print("started live-reload server on port: " + server.port, 2);
return ready = true;
}
});
}
server.listen(function(err) {
if (!err) {
print("started live-reload server on port: " + server.port, 2);
ready = true;
}
});
}
};
/**
* Stop server
*/
exports.stop = function() {
if (server) {
server.close();
server = null;
return ready = false;
}
if (server) {
server.close();
server = null;
ready = false;
}
};
/**
* Refresh the 'file' in browser
* @param {String} file
*/
exports.refresh = function(file) {
var msg;
if (ready) {
msg = {
command: 'reload',
path: file,
liveCSS: true
};
debug("sending " + (strong('reload')) + " command to live-reload clients", 4);
return server.activeConnections().forEach(function(connection) {
return connection.send(msg);
});
}
var msg;
if (ready) {
msg = {
command: 'reload',
path: file,
liveCSS: true
};
debug("sending " + (strong('reload')) + " command to live-reload clients", 4);
server.activeConnections().forEach(function(connection) {
connection.send(msg);
});
}
};

@@ -1,124 +0,120 @@

// Generated by CoffeeScript 1.4.0
var Connection, EventEmitter, PORT, ReloadServer, Url, fs, http, path, ws,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
var http = require('http')
, util = require("util")
, Url = require('url')
, fs = require('fs')
, path = require('path')
, EventEmitter = require('events').EventEmitter
, ws = require('websocket.io')
, Connection = require('./reloadconnection')
, PORT = 35729;
http = require('http');
module.exports = ReloadServer;
Url = require('url');
function ReloadServer() {
EventEmitter.call(this);
fs = require('fs');
this.options = {
id: 'com.popeindustries.buddy',
name: 'buddy-livereload',
version: '1.0',
port: PORT
};
this.port = this.options.port;
this.connections = {};
this.connectionId = 0;
this.server = null;
this.wsServer = null;
}
path = require('path');
// Inherit
util.inherits(ReloadServer, EventEmitter);
EventEmitter = require('events').EventEmitter;
/**
* Begin listening
* @param {Function} fn(err)
*/
ReloadServer.prototype.listen = function(fn) {
var self = this;
this.server = http.createServer();
this.server.on('error', function(err) {
fn(err);
});
this.server.listen(this.options.port, function(err) {
if (err) return fn(err);
self.server.on('request', function(request, response) {
request.on('end', function() {
var url = Url.parse(request.url, true);
// Serve livereload.js file
if (url.pathname == '/livereload.js') {
fs.readFile(path.join(__dirname, 'livereload.js'), 'utf8', function(err, data) {
if (err) return fn(err);
response.writeHead(200, {
'Content-Length': data.length,
'Content-Type': 'text/javascript'
});
response.end(data);
});
// All other requests 404
} else {
response.writeHead(404);
response.end();
}
});
});
// Create socket server
self.wsServer = ws.attach(self.server);
self.wsServer.on('connection', function(socket) {
self._createConnection(socket);
});
fn();
});
};
ws = require('websocket.io');
/**
* Get all active connections
* @return {Arrray}
*/
ReloadServer.prototype.activeConnections = function() {
var connections = []
, connection;
for (var id in this.connections) {
connection = this.connections[id];
if (connection.isActive()) connections.push(connection);
}
return connections;
};
Connection = require('./reloadconnection');
/**
* Close server
*/
ReloadServer.prototype.close = function() {
this.server.close();
for (var connection in this.connections) {
connection.close();
}
this.connections = {};
};
PORT = 35729;
module.exports = ReloadServer = (function(_super) {
__extends(ReloadServer, _super);
function ReloadServer() {
this.options = {
id: 'com.popeindustries.buddy',
name: 'buddy-livereload',
version: '1.0',
port: PORT
};
this.port = this.options.port;
this.connections = {};
this.connectionId = 0;
this.server = null;
this.wsServer = null;
}
ReloadServer.prototype.listen = function(fn) {
var _this = this;
this.server = http.createServer();
this.server.on('error', function(err) {
return fn(err);
});
return this.server.listen(this.options.port, function(err) {
if (err) {
return fn(err);
}
_this.server.on('request', function(request, response) {
return request.on('end', function() {
var url;
url = Url.parse(request.url, true);
if (url.pathname === '/livereload.js') {
return fs.readFile(path.join(__dirname, 'livereload.js'), 'utf8', function(err, data) {
if (err) {
return fn(err);
}
response.writeHead(200, {
'Content-Length': data.length,
'Content-Type': 'text/javascript'
});
return response.end(data);
});
} else {
response.writeHead(404);
return response.end();
}
});
});
_this.wsServer = ws.attach(_this.server);
_this.wsServer.on('connection', function(socket) {
return _this._createConnection(socket);
});
return fn();
});
};
ReloadServer.prototype.activeConnections = function() {
var connection, connections, id, _ref;
connections = [];
_ref = this.connections;
for (id in _ref) {
connection = _ref[id];
if (connection.isActive()) {
connections.push(connection);
}
}
return connections;
};
ReloadServer.prototype.close = function() {
var connection;
this.server.close();
for (connection in this.connections) {
connection.close();
}
return this.connections = {};
};
ReloadServer.prototype._createConnection = function(socket) {
var connection,
_this = this;
connection = new Connection(socket, "buddy" + (++this.connectionId), this.options);
connection.on('connected', function() {
_this.connections[connection.id] = connection;
return _this.emit('connected', connection);
});
connection.on('disconnected', function() {
delete _this.connections[connection.id];
return _this.emit('disconnected', connection);
});
connection.on('command', function(command) {
return _this.emit('command', command);
});
connection.on('error', function(err) {
return _this.emit('error', err);
});
return connection;
};
return ReloadServer;
})(EventEmitter);
/**
* Create connection instance
* @param {Object} socket
*/
ReloadServer.prototype._createConnection = function(socket) {
var connection = new Connection(socket, "buddy" + (++this.connectionId), this.options);
self = this;
connection.on('connected', function() {
self.connections[connection.id] = connection;
self.emit('connected', connection);
});
connection.on('disconnected', function() {
delete self.connections[connection.id];
self.emit('disconnected', connection);
});
connection.on('command', function(command) {
self.emit('command', command);
});
connection.on('error', function(err) {
self.emit('error', err);
});
return connection;
};

@@ -1,131 +0,148 @@

// Generated by CoffeeScript 1.4.0
var THROTTLE_TIMEOUT, Watcher, events, existsSync, fs, path, readdir, wait, _ref,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__slice = [].slice;
var fs = require('fs')
, path = require('path')
, util = require("util")
, EventEmitter = require('events').EventEmitter
, _fs = require('./fs')
, readdir = _fs.readdir
, existsSync = _fs.existsSync
, THROTTLE_TIMEOUT = 100;
fs = require('fs');
module.exports = Watcher;
path = require('path');
/**
* Constructor
* @param {RegExp} ignore
*/
function Watcher(ignore) {
EventEmitter.call(this);
events = require('events');
this.ignore = (ignore != null)
? ignore
: /^\./;
this.watchers = {};
this._throttling = {
create: false,
'delete': false,
change: false
};
}
_ref = require('./fs'), readdir = _ref.readdir, wait = _ref.wait, existsSync = _ref.existsSync;
// Inherit
util.inherits(Watcher, EventEmitter);
THROTTLE_TIMEOUT = 100;
/**
* Watch a 'source' file or directory for changes
* @param {String} source
*/
Watcher.prototype.watch = function(source) {
var self = this;
if (!this.ignore.test(path.basename(source))) {
fs.stat(source, function(err, stats) {
var lastChange;
if (err) {
self.emit('error', err);
} else {
lastChange = stats.mtime.getTime();
// Recursively parse items in directory
if (stats.isDirectory()) {
fs.readdir(source, function(err, files) {
if (err) {
self.emit('error', err);
} else {
files.forEach(function(file) {
self.watch(path.resolve(source, file));
});
}
});
}
module.exports = Watcher = (function(_super) {
// Store watcher objects
self.watchers[source] = fs.watch(source, function(evt, filename) {
if (existsSync(source)) {
fs.stat(source, function(err, stats) {
if (err) {
self._throttleEvent('error', err);
} else {
if (stats.isFile()) {
// Notify if changed
if (stats.mtime.getTime() !== lastChange) {
self._throttleEvent('change', source, stats);
}
lastChange = stats.mtime.getTime();
} else if (stats.isDirectory()) {
// Notify if new
if (!self.watchers[source]) {
self._throttleEvent('create', source, stats);
}
// Check for new file
fs.readdir(source, function(err, files) {
if (err) {
self._throttleEvent('error', err);
} else {
files.forEach(function(file) {
var item = path.resolve(source, file);
// New file
if (!self.ignore.test(path.basename(item)) && !self.watchers[item]) {
fs.stat(item, function(err, stats) {
self._throttleEvent('create', item, stats);
self.watch(item);
});
}
});
}
});
}
}
});
// Deleted
} else {
self.unwatch(source);
self._throttleEvent('delete', source);
}
});
}
});
}
};
__extends(Watcher, _super);
/**
* Stop watching a 'source' file or directory for changes
* @param {String} source
*/
Watcher.prototype.unwatch = function(source) {
var watcher = this.watchers[source];
if (watcher) {
delete this.watchers[source];
try {
watcher.close();
} catch (err) { }
}
};
function Watcher(ignore) {
this.ignore = ignore != null ? ignore : /^\./;
this.watchers = {};
this._throttling = {
create: false,
'delete': false,
change: false
};
}
/**
* Stop watching all sources for changes
*/
Watcher.prototype.clean = function() {
for (var source in this.watchers) {
this.unwatch(source);
}
};
Watcher.prototype.watch = function(source) {
var _this = this;
if (!this.ignore.test(path.basename(source))) {
return fs.stat(source, function(err, stats) {
var lastChange;
if (err) {
return _this.emit('error', err);
} else {
lastChange = stats.mtime.getTime();
if (stats.isDirectory()) {
fs.readdir(source, function(err, files) {
if (err) {
return _this.emit('error', err);
} else {
return files.forEach(function(file) {
return _this.watch(path.resolve(source, file));
});
}
});
}
return _this.watchers[source] = fs.watch(source, function(evt, filename) {
if (existsSync(source)) {
return fs.stat(source, function(err, stats) {
if (err) {
return _this._throttleEvent('error', err);
} else {
if (stats.isFile()) {
if (stats.mtime.getTime() !== lastChange) {
_this._throttleEvent('change', source, stats);
}
return lastChange = stats.mtime.getTime();
} else if (stats.isDirectory()) {
if (!_this.watchers[source]) {
_this._throttleEvent('create', source, stats);
}
return fs.readdir(source, function(err, files) {
if (err) {
return _this._throttleEvent('error', err);
} else {
return files.forEach(function(file) {
var item;
item = path.resolve(source, file);
if (!_this.ignore.test(path.basename(item)) && !_this.watchers[item]) {
return fs.stat(item, function(err, stats) {
_this._throttleEvent('create', item, stats);
return _this.watch(item);
});
}
});
}
});
}
}
});
} else {
_this.unwatch(source);
return _this._throttleEvent('delete', source);
}
});
}
});
}
};
Watcher.prototype.unwatch = function(source) {
var watcher;
if (watcher = this.watchers[source]) {
delete this.watchers[source];
try {
return watcher.close();
} catch (err) {
}
}
};
Watcher.prototype.clean = function() {
var source, _results;
_results = [];
for (source in this.watchers) {
_results.push(this.unwatch(source));
}
return _results;
};
Watcher.prototype._throttleEvent = function() {
var props, type,
_this = this;
type = arguments[0], props = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
if (!this._throttling[type]) {
this._throttling[type] = true;
this.emit.apply(this, [type].concat(props));
return setTimeout((function() {
return _this._throttling[type] = false;
}), THROTTLE_TIMEOUT);
}
};
return Watcher;
})(events.EventEmitter);
/**
* Protect against mutiple event emits
* @param {String} type
* @param [props]
*/
Watcher.prototype._throttleEvent = function(type) {
var self = this
, props = (2 <= arguments.length)
? Array.prototype.slice.call(arguments, 1)
: [];
if (!this._throttling[type]) {
this._throttling[type] = true;
this.emit.apply(this, [type].concat(props));
setTimeout((function() {
self._throttling[type] = false;
}), THROTTLE_TIMEOUT);
}
};
{
"name": "buddy",
"description": "A build tool for js/css projects. Manages third-party dependencies, compiles source code, automatically modularizes js sources, statically resolves module dependencies, and lints/concatenates/compresses output.",
"version": "0.6.11",
"version": "0.7.0",
"author": "popeindustries <alex@pope-industries.com>",

@@ -9,15 +9,15 @@ "keywords": ["build", "buildtool", "modules", "javascript", "coffeescript", "css", "styus", "less"],

"coffee-script": "1.4.0",
"stylus": "0.31.0",
"less": "1.3.1",
"uglify-js": "2.2.2",
"clean-css": "0.8.2",
"stylus": "0.32.0",
"less": "1.3.3",
"uglify-js": "2.2.3",
"clean-css": "0.9.1",
"csslint": "0.9.9",
"jshint": "0.9.1",
"commander": "1.1.1",
"rimraf": "2.0.2",
"rimraf": "2.1.1",
"mkdirp": "0.3.4",
"bower": "0.6.3",
"superagent": "0.10.0",
"bower": "0.6.8",
"superagent": "0.12.0",
"unzip": "0.1.0",
"semver": "1.1.1",
"semver": "1.1.2",
"async": "0.1.22",

@@ -49,3 +49,3 @@ "livereload-protocol": "0.2.2",

"readmeFilename": "README.md",
"readme": "# buddy(1)\n\n**buddy(1)** is a build tool for js/css projects. It helps you manage third-party dependencies, compiles source code from higher order js/css languages (CoffeeScript/Stylus/Less), automatically wraps js files in module definitions, statically resolves module dependencies, and concatenates (and optionally compresses) all souces into a single file for more efficient delivery to the browser.\n\n**Current version:** 0.6.10\n*[the 0.5.x+ branch is not backwards compatible with earlier versions. See [Change Log](#a1) below for more details]*\n\n## Features\n\n- Allows you to write js __modules__ without the module boilerplate (similar to Node.js)\n- Resolves js module __dependencies__ automatically\n- Supports ___lazy___ runtime evaluation by storing js modules as strings\n- __Compiles__ _CoffeeScript_, _Stylus_, and _Less_ source files\n- __Concatenates__ js modules into a single file\n- Runs js and css code through __linters__ to check for syntax errors\n- __Watches__ for source changes and builds automatically\n- __Refreshes__ connected browsers after each change\n- __Inlines__ css `@imports` automatically\n- Supports execution of a ___test___ script after each build\n- Copies __libraries__ from GitHub to your project\n- Copies __assets__ from a local destination to your project\n\n## Installation\n\nUse the *-g* global flag to make the **buddy(1)** command available system-wide:\n\n```bash\n$ npm -g install buddy\n```\n\nOr, optionally, add **buddy** as a dependency in your project's *package.json* file:\n\n```json\n{\n \"name\": \"myproject\",\n \"description\": \"This is my web project\",\n \"version\": \"0.0.1\",\n \"dependencies\": {\n \"buddy\": \"0.5.0\"\n },\n \"scripts\": {\n \"install\": \"./node_modules/buddy/bin/buddy install\",\n \"build\": \"./node_modules/buddy/bin/buddy build\",\n \"deploy\": \"./node_modules/buddy/bin/buddy deploy\"\n }\n}\n```\n\n...then install:\n\n```bash\n$ cd path/to/project\n$ npm install\n```\n\n## Usage\n\n```text\nUsage: buddy [options] <command> [path/to/buddy.json]>\n\nCommands:\n\n install [config] install dependencies\n build [config] build js and css sources\n watch [config] watch js and css source files and build changes\n deploy [config] build compressed js and css sources\n ls list all previously created files and directories\n clean remove all previously created files and directories\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -c, --compress compress output for production deployment\n -l, --lint check output for syntax and logic errors\n -r, --reload reload all connected live-reload clients on file change during watch\n -t, --test run test command on build completion\n -L, --lazy convert js modules for lazy evaluation\n -v, --verbose print all messages for debugging\n```\n\n### Configuration\n\nThe only requirement for adding **buddy** support to a project is the presence of a **buddy.js** file in your project root:\n\n```js\n// Project build configuration.\nexports.build = {\n js: {\n // Directories containing potential js source files for this project.\n sources: ['a/coffeescript/source/directory', 'a/js/source/directory'],\n // One or more js build targets.\n targets: [\n {\n // An entrypoint js (or equivalent) file to be wrapped in a module definition,\n // concatenated with all it's resolved dependencies.\n input: 'a/coffeescript/or/js/file',\n // A destination in which to save the processed input.\n // If a directory is specified, the input file name will be used.\n output: 'a/js/file/or/directory',\n // Targets can have children.\n // Any sources included in the parent target will NOT be included in the child.\n targets: [\n {\n input: 'a/coffeescript/or/js/file',\n output: 'a/js/file/or/directory'\n }\n ]\n },\n {\n // Files are batch processed when a directory is used as input.\n input: 'a/coffeescript/or/js/directory',\n output: 'a/js/directory',\n // Skips module wrapping (ex: for use in server environments).\n modular: false\n }\n ]\n },\n css: {\n // Directories containing potential css source files for this project.\n sources: ['a/stylus/directory', 'a/less/directory', 'a/css/directory'],\n // One or more css build targets\n targets: [\n {\n // An entrypoint css (or equivalent) file to be processed,\n // concatenated with all it's resolved dependencies.\n input: 'a/stylus/less/or/css/file',\n // A destination in which to save the processed input.\n // If a directory is specified, the input file name will be used.\n output: 'a/css/file/or/directory'\n },\n {\n // Files are batch processed when a directory is used as input.\n input: 'a/stylus/less/or/css/directory',\n output: 'a/css/directory'\n }\n ]\n }\n}\n\n// Project dependency configuration.\nexports.dependencies = {\n // A destination directory in which to place third-party library dependencies.\n 'a/vendor/directory': {\n // An ordered list of dependencies\n sources: [\n // A github user/repo.\n // Install the 'browser-require' source when using Node-style modules.\n 'popeindustries/browser-require',\n // A named library with or without version (ex: jquery@latest, backbone, backbone@1.0.0).\n // Version identifiers follow the npm semantic versioning rules.\n 'library@version'\n ],\n // Dependencies can be packaged and minified to a destination file\n output: 'a/js/file'\n },\n // A destination directory in which to place source library dependencies.\n 'a/source/directory': {\n sources: [\n // A github user/repo.\n // Will use the 'main' or 'scripts' properties of\n // components.json or package.json to identify the file to install.\n 'username/repo',\n // A github user/repo with specific file or directory locations.\n 'username/repo#a/file/or/directory|another/file/or/directory',\n // A local file or directory to copy and install.\n 'a/file/or/directory'\n ]\n }\n}\n\n// Project settings configuration.\nexports.settings = {\n // Run a command after build\n test: 'command --flags',\n // Override the default plugins, and/or include custom plugins.\n plugins: {\n js: {\n // Append one or more js compilers to the default 'coffeescript'.\n compilers: ['a/file', 'another/file'],\n // Change the default 'uglifyjs' compressor to a custom specification.\n compressor: 'a/file',\n // Change the default 'jshint' linter to a custom specification.\n linter: 'a/file',\n // Change the default 'node' module type to 'amd' or a custom specification.\n module: 'amd'\n },\n css: {\n // Append one or more css compilers to the default 'stylus' and 'less'.\n compilers: ['a/file', 'another/file'],\n // Change the default 'cleancss' compressor to a custom specification.\n compressor: 'a/file',\n // Change the default 'csslint' linter to a custom specification.\n linter: 'a/file'\n }\n }\n}\n```\n\n## Concepts\n\n### BUILD\n\n**Project Root**: The directory from which all paths resolve to. Determined by location of the *buddy.js* configuration file.\n\n**Sources**: An array of directories from which all referenced files are retrieved from. ***Note:*** A *js* module's id is derived from it's relative path to it's source directory.\n\n**Targets**: Objects that specify the *input* and *output* files or directories for each build. Targets are built in sequence, allowing builds to be chained together. ***Note:*** A *js* target can also have nested child targets, ensuring that dependencies are not duplicated across related builds.\n\n**Target parameters**:\n\n- *input*: file or directory to build. If js (or equivalent) file, all dependencies referenced will be concatenated together for output.\nIf directory, all compileable files will be compiled, wrapped in module definitions (js), and output to individual js/css files.\n\n- *output*: file or directory to output to.\n\n- *targets*: a nested target that prevents the duplication of source code with it's parent target.\n\n- *modular*: a flag to prevent js files from being wrapped with a module definition.\n\n### MODULES\n\nEach js file is wrapped in a module declaration based on the file's location. Dependencies (and concatenation order) are determined by the use of ```require()``` statements:\n\n```javascript\nvar lib = require('./my/lib'); // in current package\nvar SomeClass = require('../someclass'); // in parent package\nvar util = require('utils/util'); // from root package\n\nlib.doSomething();\nvar something = new SomeClass();\nutil.log('hey');\n```\n\nSpecifying a module's public behaviour is achieved by decorating an ```exports``` object:\n\n```javascript\nvar myModuleVar = 'my module';\n\nexports.myModuleMethod = function() {\n return myModuleVar;\n};\n```\n\n...or overwriting the ```exports``` object completely:\n\n```javascript\nfunction MyModule() {\n this.myVar = 'my instance var';\n};\n\nMyModule.prototype.myMethod = function() {\n return this.myVar;\n};\n\nmodule.exports = MyModule;\n```\n\nEach module is provided with a ```module```, ```exports```, and ```require``` reference.\n\nWhen ```require()```-ing a module, keep in mind that the module id is resolved based on the following rules:\n\n * packages begin at the root folder specified in *buddy.js > js > sources*:\n```\n'Users/alex/project/src/package/main.js' > 'package/main'\n```\n * uppercase filenames are converted to lowercase module ids:\n```\n'my/package/Class.js' > 'my/package/class'\n```\n\nSee [node.js modules](http://nodejs.org/docs/v0.8.0/api/modules.html) for more info on modules.\n\n***NOTE***: ```require``` boilerplate needs to be included on the page to enable module loading. It's recommended to ```install``` a library like *popeindustries/browser-require*.\n\n### DEPENDENCIES\n\nDependency resources are installed from local locations or remotely from Github.\n\n**Sources**: An array of local or remote resource locations.\n\n- **destination**: each group of sources will be installed to the project relative location specified.\n\n- **identifier**: github ```username/repo``` identifiers are preferred, but it is also possible to use identifiers from the [bower](https://github.com/twitter/bower) package manager: ```'jquery', 'backbone', 'underscore'```\n\n- **versioning**: github sources can specify a version by appending ```@``` and a npm-style symantic version: ```'*', '1.2.3', '1.x', '~1.2.0', '>=1.2.3'```\n\n- **resources**: specific resources can be specified by appending ```#``` and a list of ```|``` separated relative file or directory locations: ```'username/repo#a/file/or/directory|another/file/or/directory'```\n\n**Output**: A file destination to concatenate and compress the source contents. The order of *sources* determines the content order.\n\n## Examples\n\nCopy project boilerplate from a local directory:\n\n```js\nexports.dependencies = {\n '.': {\n sources: ['../../boilerplate/project']\n }\n}\n```\n\nGrab js dependencies to be installed and packaged for inclusion in html:\n\n```js\nexports.dependencies = {\n // install location\n 'libs/vendor': {\n sources: [\n // library for require boilerplate\n 'popeindustries/browser-require',\n // jquery at specific version\n 'jquery@1.8.2'\n ],\n // packaged and compressed\n output: 'www/assets/js/libs.js'\n }\n}\n```\n\nGrab sources to be referenced in your builds:\n\n```js\nexports.dependencies = {\n // install location\n 'libs/src/css': {\n sources: [\n // reference the lib/nib directory for installation\n 'visionmedia/nib#lib/nib'\n ]\n }\n}\n```\n\nCompile a library, then reference some library files in your project:\n\n```js\nexports.build = {\n js: {\n sources: ['libs/src/coffee', 'libs/js', 'src'],\n targets: [\n {\n // a folder of coffee files (including nested folders)\n input: 'libs/src/coffee',\n // a folder of compiled js files\n output: 'libs/js'\n },\n {\n // the application entry point referencing library dependencies\n input: 'src/main.js',\n // a concatenation of referenced dependencies\n output: 'js/main.js'\n }\n ]\n }\n}\n```\n\nCompile a site with an additional widget using shared sources:\n\n```js\nexports.build = {\n js: {\n sources: ['src/coffee'],\n targets: [\n {\n // the application entry point\n input: 'src/coffee/main.coffee',\n // output to main.js (includes all referenced dependencies)\n output: 'js',\n targets: [\n {\n // references some of the same sources as main.coffee\n input: 'src/coffee/widget.coffee',\n // includes only referenced dependencies not in main.js\n output: 'js'\n }\n ]\n }\n ]\n }\n}\n```\n\n<a name=\"a1\"/>\n## Changelog\n\n**0.6.11** - December 21, 2012\n* fix css comment removal deleting base64 content\n\n**0.6.10** - December 21, 2012\n* updated _Uglify-js_ compressor to 2.0\n\n**0.6.9** - December 14, 2012\n* fixed _watch_ not adding new file during renames\n\n**0.6.8** - December 13, 2012\n* fixed _install_ crash\n* _install_ now overwrites previously downloaded resources\n* properly handle duplicate `@import` rules while inlining\n\n**0.6.7** - December 11, 2012\n* added _--lazy_ option for generating js modules for lazy evaluation; module contents are encoded as strings to be passed to a Function constructor on first require()\n\n**0.6.6** - December 6, 2012\n* added live-reload support for _watch_ command with _--reload_\n* re-enabled linting support\n\n**0.6.5** - December 5, 2012\n* fix for *watch* command firing repeated change events\n* fix for *watch* command not properly building targets on change\n* fix for child target building shared resources\n\n**0.6.4** - December 4, 2012\n* fix for _--test_ not displaying both stdout and stderr\n* added wrapping of batch files in module definitions if _options.modular_ is not false\n* fix for building targets that contain no source\n\n**0.6.3** - December 4, 2012\n* fix for _watch_ command attempting to watch a source that doesn't exist\n* added support for default json config file type\n\n**0.6.2** - December 4, 2012\n* fix for css _@import_ inlining\n\n**0.6.1** - December 3, 2012\n* added _--test_ to watch command\n\n**0.6.0** - December 3, 2012\n* complete rewrite for async file operations\n* added _--test_ flag for executing a command after build\n* added _--verbose_ flag for outputting detailed notifications during build\n* added _ls_ command to list all generated files\n* added inlining of '@import' rules for all css source types\n* simplified dependency resource parsing on install; only parse 'main' field in component.json/package.json\n\n**0.5.4** - November 23, 2012\n* regression fix for _clean_ command\n* improved _.buddy-filelog_ force clean\n* improved notifications for _install_ and *clean* commands\n\n**0.5.3** - November 23, 2012\n* refactored _install_ command behaviour; no longer uses git operations, changed syntax for specifying version ('@') and resources ('#'), added ability to list several resources __[breaking change]__\n* _.buddy-filelog_ now stores relative paths for compatibility on different systems\n* file deletions limited to resources under the project root\n\n**0.5.2** - Novemver 20, 2012\n* added _watch_ command; handle add, remove, and change of source files\n\n**0.5.1** - Novemver 14, 2012\n* added _clean_ command to remove all generated files\n* added hidden _.buddy-filelog_ file for tracking files changes between sessions\n* fix for false-negative module wrapping test\n\n**0.5.0** - November 13, 2012\n* _compile_ command renamed to *build* __[breaking change]__\n* changed module naming for compatibility with recent versions of Node.js (camel case no longer converted to underscores) __[breaking change]__\n* changed configuration file type to 'js' from 'json'; added _dependencies_ and _settings_ __[breaking change]__\n* changed configuration _target_ parameters to _input/output_ from _in/out_ __[breaking change]__\n* changed configuration _target_ parameter to _modular_ from _nodejs_ __[breaking change]__\n* concatenated js modules no longer self-booting; need to ```require('main');``` manually __[breaking change]__\n* _require_ boilerplate no longer included in generated source; install _popeindustries/browser-require_ or equivalent __[breaking change]__\n* removed _watch_ command (temporarily) __[breaking change]__\n* added _install_ command and project dependency management\n* added plugin support for compilers, compressors, linters, and modules; added support for custom plugins\n* added code linting\n* all errors now throw\n* complete code base refactor\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2011 Pope-Industries &lt;alex@pope-industries.com&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
"readme": "# buddy(1)\n\n**buddy(1)** is a build tool for js/css projects. It helps you manage third-party dependencies, compiles source code from higher order js/css languages (CoffeeScript/Stylus/Less), automatically wraps js files in module definitions, statically resolves module dependencies, and concatenates (and optionally compresses) all souces into a single file for more efficient delivery to the browser.\n\n**Current version:** 0.7.0\n*[the 0.5.x+ branch is not backwards compatible with earlier versions. See [Change Log](#a1) below for more details]*\n\n## Features\n\n- Allows you to write js __modules__ without the module boilerplate (similar to Node.js)\n- Resolves js module __dependencies__ automatically\n- Supports ___lazy___ runtime evaluation by storing js modules as strings\n- __Compiles__ _CoffeeScript_, _Stylus_, and _Less_ source files\n- __Concatenates__ js modules into a single file\n- Runs js and css code through __linters__ to check for syntax errors\n- __Watches__ for source changes and builds automatically\n- __Refreshes__ connected browsers after each change\n- __Inlines__ css `@imports` automatically\n- Supports execution of a ___test___ script after each build\n- Copies __libraries__ from GitHub to your project\n- Copies __assets__ from a local destination to your project\n\n## Installation\n\nUse the *-g* global flag to make the **buddy(1)** command available system-wide:\n\n```bash\n$ npm -g install buddy\n```\n\nOr, optionally, add **buddy** as a dependency in your project's *package.json* file:\n\n```json\n{\n \"name\": \"myproject\",\n \"description\": \"This is my web project\",\n \"version\": \"0.0.1\",\n \"dependencies\": {\n \"buddy\": \"0.5.0\"\n },\n \"scripts\": {\n \"install\": \"./node_modules/buddy/bin/buddy install\",\n \"build\": \"./node_modules/buddy/bin/buddy build\",\n \"deploy\": \"./node_modules/buddy/bin/buddy deploy\"\n }\n}\n```\n\n...then install:\n\n```bash\n$ cd path/to/project\n$ npm install\n```\n\n## Usage\n\n```text\nUsage: buddy [options] <command> [path/to/buddy.json]>\n\nCommands:\n\n install [config] install dependencies\n build [config] build js and css sources\n watch [config] watch js and css source files and build changes\n deploy [config] build compressed js and css sources\n ls list all previously created files and directories\n clean remove all previously created files and directories\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -c, --compress compress output for production deployment\n -l, --lint check output for syntax and logic errors\n -r, --reload reload all connected live-reload clients on file change during watch\n -t, --test run test command on build completion\n -L, --lazy convert js modules for lazy evaluation\n -v, --verbose print all messages for debugging\n```\n\n### Configuration\n\nThe only requirement for adding **buddy** support to a project is the presence of a **buddy.js** file in your project root:\n\n```js\n// Project build configuration.\nexports.build = {\n js: {\n // Directories containing potential js source files for this project.\n sources: ['a/coffeescript/source/directory', 'a/js/source/directory'],\n // One or more js build targets.\n targets: [\n {\n // An entrypoint js (or equivalent) file to be wrapped in a module definition,\n // concatenated with all it's resolved dependencies.\n input: 'a/coffeescript/or/js/file',\n // A destination in which to save the processed input.\n // If a directory is specified, the input file name will be used.\n output: 'a/js/file/or/directory',\n // Targets can have children.\n // Any sources included in the parent target will NOT be included in the child.\n targets: [\n {\n input: 'a/coffeescript/or/js/file',\n output: 'a/js/file/or/directory'\n }\n ]\n },\n {\n // Files are batch processed when a directory is used as input.\n input: 'a/coffeescript/or/js/directory',\n output: 'a/js/directory',\n // Skips module wrapping (ex: for use in server environments).\n modular: false\n }\n ]\n },\n css: {\n // Directories containing potential css source files for this project.\n sources: ['a/stylus/directory', 'a/less/directory', 'a/css/directory'],\n // One or more css build targets\n targets: [\n {\n // An entrypoint css (or equivalent) file to be processed,\n // concatenated with all it's resolved dependencies.\n input: 'a/stylus/less/or/css/file',\n // A destination in which to save the processed input.\n // If a directory is specified, the input file name will be used.\n output: 'a/css/file/or/directory'\n },\n {\n // Files are batch processed when a directory is used as input.\n input: 'a/stylus/less/or/css/directory',\n output: 'a/css/directory'\n }\n ]\n }\n}\n\n// Project dependency configuration.\nexports.dependencies = {\n // A destination directory in which to place third-party library dependencies.\n 'a/vendor/directory': {\n // An ordered list of dependencies\n sources: [\n // A github user/repo.\n // Install the 'browser-require' source when using Node-style modules.\n 'popeindustries/browser-require',\n // A named library with or without version (ex: jquery@latest, backbone, backbone@1.0.0).\n // Version identifiers follow the npm semantic versioning rules.\n 'library@version'\n ],\n // Dependencies can be packaged and minified to a destination file\n output: 'a/js/file'\n },\n // A destination directory in which to place source library dependencies.\n 'a/source/directory': {\n sources: [\n // A github user/repo.\n // Will use the 'main' or 'scripts' properties of\n // components.json or package.json to identify the file to install.\n 'username/repo',\n // A github user/repo with specific file or directory locations.\n 'username/repo#a/file/or/directory|another/file/or/directory',\n // A local file or directory to copy and install.\n 'a/file/or/directory'\n ]\n }\n}\n\n// Project settings configuration.\nexports.settings = {\n // Run a command after build\n test: 'command --flags',\n // Override the default plugins, and/or include custom plugins.\n plugins: {\n js: {\n // Append one or more js compilers to the default 'coffeescript'.\n compilers: ['a/file', 'another/file'],\n // Change the default 'uglifyjs' compressor to a custom specification.\n compressor: 'a/file',\n // Change the default 'jshint' linter to a custom specification.\n linter: 'a/file',\n // Change the default 'node' module type to 'amd' or a custom specification.\n module: 'amd'\n },\n css: {\n // Append one or more css compilers to the default 'stylus' and 'less'.\n compilers: ['a/file', 'another/file'],\n // Change the default 'cleancss' compressor to a custom specification.\n compressor: 'a/file',\n // Change the default 'csslint' linter to a custom specification.\n linter: 'a/file'\n }\n }\n}\n```\n\n## Concepts\n\n### BUILD\n\n**Project Root**: The directory from which all paths resolve to. Determined by location of the *buddy.js* configuration file.\n\n**Sources**: An array of directories from which all referenced files are retrieved from. ***Note:*** A *js* module's id is derived from it's relative path to it's source directory.\n\n**Targets**: Objects that specify the *input* and *output* files or directories for each build. Targets are built in sequence, allowing builds to be chained together. ***Note:*** A *js* target can also have nested child targets, ensuring that dependencies are not duplicated across related builds.\n\n**Target parameters**:\n\n- *input*: file or directory to build. If js (or equivalent) file, all dependencies referenced will be concatenated together for output.\nIf directory, all compileable files will be compiled, wrapped in module definitions (js), and output to individual js/css files.\n\n- *output*: file or directory to output to.\n\n- *targets*: a nested target that prevents the duplication of source code with it's parent target.\n\n- *modular*: a flag to prevent js files from being wrapped with a module definition.\n\n### MODULES\n\nEach js file is wrapped in a module declaration based on the file's location. Dependencies (and concatenation order) are determined by the use of ```require()``` statements:\n\n```javascript\nvar lib = require('./my/lib'); // in current package\nvar SomeClass = require('../someclass'); // in parent package\nvar util = require('utils/util'); // from root package\n\nlib.doSomething();\nvar something = new SomeClass();\nutil.log('hey');\n```\n\nSpecifying a module's public behaviour is achieved by decorating an ```exports``` object:\n\n```javascript\nvar myModuleVar = 'my module';\n\nexports.myModuleMethod = function() {\n return myModuleVar;\n};\n```\n\n...or overwriting the ```exports``` object completely:\n\n```javascript\nfunction MyModule() {\n this.myVar = 'my instance var';\n};\n\nMyModule.prototype.myMethod = function() {\n return this.myVar;\n};\n\nmodule.exports = MyModule;\n```\n\nEach module is provided with a ```module```, ```exports```, and ```require``` reference.\n\nWhen ```require()```-ing a module, keep in mind that the module id is resolved based on the following rules:\n\n * packages begin at the root folder specified in *buddy.js > js > sources*:\n```\n'Users/alex/project/src/package/main.js' > 'package/main'\n```\n * uppercase filenames are converted to lowercase module ids:\n```\n'my/package/Class.js' > 'my/package/class'\n```\n\nSee [node.js modules](http://nodejs.org/docs/v0.8.0/api/modules.html) for more info on modules.\n\n***NOTE***: ```require``` boilerplate needs to be included on the page to enable module loading. It's recommended to ```install``` a library like *popeindustries/browser-require*.\n\n### DEPENDENCIES\n\nDependency resources are installed from local locations or remotely from Github.\n\n**Sources**: An array of local or remote resource locations.\n\n- **destination**: each group of sources will be installed to the project relative location specified.\n\n- **identifier**: github ```username/repo``` identifiers are preferred, but it is also possible to use identifiers from the [bower](https://github.com/twitter/bower) package manager: ```'jquery', 'backbone', 'underscore'```\n\n- **versioning**: github sources can specify a version by appending ```@``` and a npm-style symantic version: ```'*', '1.2.3', '1.x', '~1.2.0', '>=1.2.3'```\n\n- **resources**: specific resources can be specified by appending ```#``` and a list of ```|``` separated relative file or directory locations: ```'username/repo#a/file/or/directory|another/file/or/directory'```\n\n**Output**: A file destination to concatenate and compress the source contents. The order of *sources* determines the content order.\n\n## Examples\n\nCopy project boilerplate from a local directory:\n\n```js\nexports.dependencies = {\n '.': {\n sources: ['../../boilerplate/project']\n }\n}\n```\n\nGrab js dependencies to be installed and packaged for inclusion in html:\n\n```js\nexports.dependencies = {\n // install location\n 'libs/vendor': {\n sources: [\n // library for require boilerplate\n 'popeindustries/browser-require',\n // jquery at specific version\n 'jquery@1.8.2'\n ],\n // packaged and compressed\n output: 'www/assets/js/libs.js'\n }\n}\n```\n\nGrab sources to be referenced in your builds:\n\n```js\nexports.dependencies = {\n // install location\n 'libs/src/css': {\n sources: [\n // reference the lib/nib directory for installation\n 'visionmedia/nib#lib/nib'\n ]\n }\n}\n```\n\nCompile a library, then reference some library files in your project:\n\n```js\nexports.build = {\n js: {\n sources: ['libs/src/coffee', 'libs/js', 'src'],\n targets: [\n {\n // a folder of coffee files (including nested folders)\n input: 'libs/src/coffee',\n // a folder of compiled js files\n output: 'libs/js'\n },\n {\n // the application entry point referencing library dependencies\n input: 'src/main.js',\n // a concatenation of referenced dependencies\n output: 'js/main.js'\n }\n ]\n }\n}\n```\n\nCompile a site with an additional widget using shared sources:\n\n```js\nexports.build = {\n js: {\n sources: ['src/coffee'],\n targets: [\n {\n // the application entry point\n input: 'src/coffee/main.coffee',\n // output to main.js (includes all referenced dependencies)\n output: 'js',\n targets: [\n {\n // references some of the same sources as main.coffee\n input: 'src/coffee/widget.coffee',\n // includes only referenced dependencies not in main.js\n output: 'js'\n }\n ]\n }\n ]\n }\n}\n```\n\n<a name=\"a1\"/>\n## Changelog\n\n**0.7.0** - January 7, 2013\n* bye bye CoffeeScript - migrated to js only source\n* upgraded dependencies\n\n**0.6.11** - December 21, 2012\n* fix css comment removal deleting base64 content\n\n**0.6.10** - December 21, 2012\n* updated _Uglify-js_ compressor to 2.0\n\n**0.6.9** - December 14, 2012\n* fixed _watch_ not adding new file during renames\n\n**0.6.8** - December 13, 2012\n* fixed _install_ crash\n* _install_ now overwrites previously downloaded resources\n* properly handle duplicate `@import` rules while inlining\n\n**0.6.7** - December 11, 2012\n* added _--lazy_ option for generating js modules for lazy evaluation; module contents are encoded as strings to be passed to a Function constructor on first require()\n\n**0.6.6** - December 6, 2012\n* added live-reload support for _watch_ command with _--reload_\n* re-enabled linting support\n\n**0.6.5** - December 5, 2012\n* fix for *watch* command firing repeated change events\n* fix for *watch* command not properly building targets on change\n* fix for child target building shared resources\n\n**0.6.4** - December 4, 2012\n* fix for _--test_ not displaying both stdout and stderr\n* added wrapping of batch files in module definitions if _options.modular_ is not false\n* fix for building targets that contain no source\n\n**0.6.3** - December 4, 2012\n* fix for _watch_ command attempting to watch a source that doesn't exist\n* added support for default json config file type\n\n**0.6.2** - December 4, 2012\n* fix for css _@import_ inlining\n\n**0.6.1** - December 3, 2012\n* added _--test_ to watch command\n\n**0.6.0** - December 3, 2012\n* complete rewrite for async file operations\n* added _--test_ flag for executing a command after build\n* added _--verbose_ flag for outputting detailed notifications during build\n* added _ls_ command to list all generated files\n* added inlining of '@import' rules for all css source types\n* simplified dependency resource parsing on install; only parse 'main' field in component.json/package.json\n\n**0.5.4** - November 23, 2012\n* regression fix for _clean_ command\n* improved _.buddy-filelog_ force clean\n* improved notifications for _install_ and *clean* commands\n\n**0.5.3** - November 23, 2012\n* refactored _install_ command behaviour; no longer uses git operations, changed syntax for specifying version ('@') and resources ('#'), added ability to list several resources __[breaking change]__\n* _.buddy-filelog_ now stores relative paths for compatibility on different systems\n* file deletions limited to resources under the project root\n\n**0.5.2** - Novemver 20, 2012\n* added _watch_ command; handle add, remove, and change of source files\n\n**0.5.1** - Novemver 14, 2012\n* added _clean_ command to remove all generated files\n* added hidden _.buddy-filelog_ file for tracking files changes between sessions\n* fix for false-negative module wrapping test\n\n**0.5.0** - November 13, 2012\n* _compile_ command renamed to *build* __[breaking change]__\n* changed module naming for compatibility with recent versions of Node.js (camel case no longer converted to underscores) __[breaking change]__\n* changed configuration file type to 'js' from 'json'; added _dependencies_ and _settings_ __[breaking change]__\n* changed configuration _target_ parameters to _input/output_ from _in/out_ __[breaking change]__\n* changed configuration _target_ parameter to _modular_ from _nodejs_ __[breaking change]__\n* concatenated js modules no longer self-booting; need to ```require('main');``` manually __[breaking change]__\n* _require_ boilerplate no longer included in generated source; install _popeindustries/browser-require_ or equivalent __[breaking change]__\n* removed _watch_ command (temporarily) __[breaking change]__\n* added _install_ command and project dependency management\n* added plugin support for compilers, compressors, linters, and modules; added support for custom plugins\n* added code linting\n* all errors now throw\n* complete code base refactor\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2011 Pope-Industries &lt;alex@pope-industries.com&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
}

@@ -5,3 +5,3 @@ # buddy(1)

**Current version:** 0.6.11
**Current version:** 0.7.0
*[the 0.5.x+ branch is not backwards compatible with earlier versions. See [Change Log](#a1) below for more details]*

@@ -390,2 +390,6 @@

**0.7.0** - January 7, 2013
* bye bye CoffeeScript - migrated to js only source
* upgraded dependencies
**0.6.11** - December 21, 2012

@@ -392,0 +396,0 @@ * fix css comment removal deleting base64 content

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc