Socket
Socket
Sign inDemoInstall

buddy

Package Overview
Dependencies
Maintainers
1
Versions
180
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

buddy - npm Package Compare versions

Comparing version 0.4.0 to 0.5.0

buddy.js

387

lib/builder.js

@@ -1,3 +0,3 @@

// Generated by CoffeeScript 1.3.1
var Builder, CONFIG, file, fs, log, path, target, term, trace;
// Generated by CoffeeScript 1.4.0
var Builder, CSS, CSSFile, CSSTarget, Configuration, Depedencies, HTML, JS, JSFile, JSTarget, RE_IGNORE_FILE, existsSync, fs, notify, path, plugins, readdir, _ref;

@@ -8,34 +8,35 @@ fs = require('fs');

log = console.log, trace = console.trace;
Configuration = require('./configuration');
target = require('./target');
plugins = require('./plugins');
file = require('./file');
Depedencies = require('./dependencies');
term = require('./terminal');
JSFile = require('./jsfile');
CONFIG = 'buddy.json';
CSSFile = require('./cssfile');
module.exports = Builder = (function() {
JSTarget = require('./jstarget');
Builder.name = 'Builder';
CSSTarget = require('./csstarget');
Builder.prototype.JS = 'js';
_ref = require('./utils'), notify = _ref.notify, readdir = _ref.readdir;
Builder.prototype.CSS = 'css';
existsSync = fs.existsSync || path.existsSync;
Builder.prototype.RE_JS_SRC_EXT = /\.coffee$|\.js$/;
RE_IGNORE_FILE = /^[\._~]|[-\.]min[-\.]|svn$/;
Builder.prototype.RE_CSS_SRC_EXT = /\.styl$|\.less$/;
JS = 'js';
Builder.prototype.RE_IGNORE_FILE = /^[\.|_]|[-|\.]min\.|svn|~$/;
CSS = 'css';
Builder.prototype.RE_BUILT_HEADER = /^\/\*BUILT/g;
HTML = 'html';
Builder.prototype.RE_ROOT = /^[a-zA-Z]\:\\\\?$|^\/$/;
module.exports = Builder = (function() {
function Builder(version) {
function Builder() {
this.config = null;
this.base = null;
this.watching = false;
this.plugins = null;
this.dependencies = null;
this.watchers = [];
this.jsSources = {

@@ -52,24 +53,21 @@ locations: [],

};
this.htmlSources = {
locations: [],
byPath: {},
count: 0
};
this.jsTargets = [];
this.cssTargets = [];
this.htmlTargets = [];
}
Builder.prototype.initialize = function(configpath) {
var source, type, _i, _j, _len, _len1, _ref, _ref1;
if (!this.initialized) {
if (this._loadConfig(this._locateConfig(configpath))) {
_ref = [this.JS, this.CSS];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
type = _ref[_i];
if (this._validBuildType(type)) {
_ref1 = this.config[type].sources;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
source = _ref1[_j];
this._parseSourceDirectory(path.resolve(this.base, source), null, this[type + 'Sources']);
}
this._parseTargets(this.config[type].targets, type);
}
}
this.initialized = true;
this.config = new Configuration(configpath);
this.config.locate().load();
this.plugins = plugins.load(this.config.settings && this.config.settings.plugins);
if (this.config.dependencies) {
this.dependencies = new Depedencies(this.config.dependencies, this.plugins.js.compressor);
}
this.initialized = true;
}

@@ -79,154 +77,75 @@ return this;

Builder.prototype.compile = function(compress, types) {
var t, type, _i, _len, _results;
if (types == null) {
types = [this.JS, this.CSS];
Builder.prototype.install = function() {
if (this.dependencies) {
notify.print('installing dependencies...', 2);
return this.dependencies.install(function(err) {
return err && notify.error(err);
});
} else {
return notify.error('no dependencies specified in configuration file');
}
_results = [];
for (_i = 0, _len = types.length; _i < _len; _i++) {
type = types[_i];
if (this[type + 'Targets'].length) {
_results.push((function() {
var _j, _len1, _ref, _results1;
_ref = this[type + 'Targets'];
_results1 = [];
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
t = _ref[_j];
_results1.push(t.run(compress));
}
return _results1;
}).call(this));
} else {
_results.push(void 0);
}
}
return _results;
};
Builder.prototype.watch = function(compress) {
var file, path, type, _i, _len, _ref, _results;
if (!fs.watch) {
return;
}
this.watching = true;
this.compile(compress);
_ref = [this.JS, this.CSS];
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
type = _ref[_i];
if (this[type + 'Sources'].count) {
term.out("watching for changes in " + (term.colour('[' + this.config[type].sources.join(', ') + ']', term.GREY)) + "...", 2);
_results.push((function() {
var _ref1, _results1;
_ref1 = this[type + 'Sources'].byPath;
_results1 = [];
for (path in _ref1) {
file = _ref1[path];
_results1.push(this._watchFile(file, compress));
}
return _results1;
}).call(this));
} else {
_results.push(void 0);
Builder.prototype.build = function(compress, lint) {
var _this = this;
return [JS, CSS].forEach(function(type) {
if (_this._validBuildType(type)) {
_this.config.build[type].sources.forEach(function(source) {
return _this._parseSourceDirectory(path.resolve(process.cwd(), source), null, _this[type + 'Sources']);
});
_this._parseTargets(_this.config.build[type].targets, type);
return _this[type + 'Targets'].forEach(function(target) {
return target.run(compress, lint);
});
}
}
return _results;
});
};
Builder.prototype.deploy = function() {
return this.compile(true);
return this.build(true, false);
};
Builder.prototype._locateConfig = function(configpath) {
var dir, exists;
if (configpath) {
configpath = path.resolve(configpath);
if (exists = path.existsSync(configpath)) {
if (fs.statSync(configpath).isDirectory()) {
configpath = path.join(configpath, CONFIG);
exists = path.existsSync(configpath);
}
}
if (!exists) {
term.out("" + (term.colour('error', term.RED)) + " " + (term.colour(path.basename(configpath), term.GREY)) + " not found in " + (term.colour(path.dirname(configpath), term.GREY)), 2);
return null;
}
} else {
while (true) {
dir = dir != null ? path.resolve(dir, '../') : process.cwd();
configpath = path.join(dir, CONFIG);
if (path.existsSync(configpath)) {
break;
}
if (this.RE_ROOT.test(dir)) {
term.out("" + (term.colour('error', term.RED)) + " " + (term.colour(CONFIG, term.GREY)) + " not found on this path", 2);
return null;
}
}
Builder.prototype._validSource = function(type, filename) {
var compiler, extension, name, _ref1;
extension = path.extname(filename).slice(1);
if (extension === type) {
return true;
}
return configpath;
};
Builder.prototype._loadConfig = function(configpath) {
if (configpath) {
term.out("loading config " + (term.colour(configpath, term.GREY)), 2);
try {
this.config = JSON.parse(fs.readFileSync(configpath, 'utf8'));
} catch (e) {
term.out("" + (term.colour('error', term.RED)) + " error parsing " + (term.colour(configpath, term.GREY)), 2);
return false;
_ref1 = this.plugins[type].compilers;
for (name in _ref1) {
compiler = _ref1[name];
if (extension === compiler.extension) {
return true;
}
this.base = path.dirname(configpath);
return true;
} else {
return false;
}
return false;
};
Builder.prototype._validBuildType = function(type) {
var _ref;
return (((_ref = this.config[type]) != null ? _ref.sources : void 0) != null) && this.config[type].sources.length >= 1 && (this.config[type].targets != null) && this.config[type].targets.length >= 1;
var _ref1;
return (((_ref1 = this.config.build[type]) != null ? _ref1.sources : void 0) != null) && this.config.build[type].sources.length >= 1 && (this.config.build[type].targets != null) && this.config.build[type].targets.length >= 1;
};
Builder.prototype._parseSourceDirectory = function(dir, root, cache) {
var f, item, itempath, _i, _len, _ref, _results;
if (root === null) {
root = dir;
cache.locations.push(dir);
var _this = this;
if (!root) {
cache.locations.push(root = dir);
}
_ref = fs.readdirSync(dir);
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
item = _ref[_i];
if (!item.match(this.RE_IGNORE_FILE)) {
itempath = path.resolve(dir, item);
if (fs.statSync(itempath).isDirectory()) {
this._parseSourceDirectory(itempath, root, cache);
return readdir(dir, RE_IGNORE_FILE).forEach(function(item) {
var f;
if (f = _this._fileFactory(path.resolve(dir, item), root)) {
cache.count++;
if (f.moduleId != null) {
cache.byModule[f.moduleId] = f;
}
if (f = this._fileFactory(itempath, root)) {
cache.byPath[f.filepath] = f;
if (f.module != null) {
cache.byModule[f.module] = f;
}
_results.push(cache.count++);
} else {
_results.push(void 0);
}
} else {
_results.push(void 0);
return cache.byPath[f.filepath] = f;
}
}
return _results;
});
};
Builder.prototype._fileFactory = function(filepath, base) {
var contents;
if (filepath.match(this.RE_JS_SRC_EXT)) {
contents = fs.readFileSync(filepath, 'utf8');
if (contents.match(this.RE_BUILT_HEADER)) {
return null;
}
return new file.JSFile(this.JS, filepath, base, contents);
} else if (filepath.match(this.RE_CSS_SRC_EXT)) {
return new file.CSSFile(this.CSS, filepath, base);
if (this._validSource(JS, filepath)) {
return new JSFile(filepath, base, this.plugins[JS].compilers, this.plugins[JS].module);
} else if (this._validSource(CSS, filepath)) {
return new CSSFile(filepath, base, this.plugins[CSS].compilers);
} else {

@@ -238,36 +157,29 @@ return null;

Builder.prototype._parseTargets = function(targets, type, parentTarget) {
var item, t, _i, _len, _results;
var _this = this;
if (parentTarget == null) {
parentTarget = null;
}
_results = [];
for (_i = 0, _len = targets.length; _i < _len; _i++) {
item = targets[_i];
return targets.forEach(function(item) {
var target;
item.parent = parentTarget;
if (t = this._targetFactory(type, item)) {
t.initialize();
this[type + 'Targets'].push(t);
if (target = _this._targetFactory(type, item)) {
_this[type + 'Targets'].push(target);
if (item.targets) {
_results.push(this._parseTargets(item.targets, type, t));
} else {
_results.push(void 0);
return _this._parseTargets(item.targets, type, target);
}
} else {
_results.push(void 0);
}
}
return _results;
});
};
Builder.prototype._targetFactory = function(type, options) {
var dir, inSources, inputpath, location, outputpath, _i, _len, _ref;
inputpath = path.resolve(this.base, options["in"]);
outputpath = path.resolve(this.base, options.out);
if (!path.existsSync(inputpath)) {
term.out("" + (term.colour('error', term.RED)) + " " + (term.colour(options["in"], term.GREY)) + " not found in project path", 2);
Builder.prototype._targetFactory = function(type, props) {
var dir, inSources, inputpath, location, options, outputpath, _i, _len, _ref1;
inputpath = path.resolve(process.cwd(), props.input);
outputpath = path.resolve(process.cwd(), props.output);
if (!existsSync(inputpath)) {
notify.error("" + (notify.strong(props.input)) + " not found in project path", 2);
return null;
}
_ref = this[type + 'Sources'].locations;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
location = _ref[_i];
_ref1 = this[type + 'Sources'].locations;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
location = _ref1[_i];
dir = fs.statSync(inputpath).isDirectory() ? inputpath : path.dirname(inputpath);

@@ -280,41 +192,86 @@ inSources = dir.indexOf(location) >= 0;

if (!inSources) {
term.out("" + (term.colour('error', term.RED)) + " " + (term.colour(options["in"], term.GREY)) + " not found in source path", 2);
notify.error("" + (notify.strong(props.input)) + " not found in source path", 2);
return null;
}
if (fs.statSync(inputpath).isDirectory() && path.extname(outputpath).length) {
term.out("" + (term.colour('error', term.RED)) + " a file (" + (term.colour(options.out, term.GREY)) + ") is not a valid output target for a directory (" + (term.colour(options["in"], term.GREY)) + ") input target", 2);
notify.error("a file (" + (notify.strong(props.output)) + ") is not a valid output target for a directory (" + (notify.strong(props.input)) + ") input target", 2);
return null;
}
return new target[type.toUpperCase() + 'Target'](inputpath, outputpath, this[type + 'Sources'], options.nodejs, options.parent);
options = {
compressor: this.plugins[type].compressor,
linter: this.plugins[type].linter
};
if (type === JS) {
options.modular = props.modular != null ? props.modular : true;
options.module = this.plugins.js.module;
options.parent = props.parent;
return new JSTarget(inputpath, outputpath, this[type + 'Sources'], options);
} else if (type === CSS) {
return new CSSTarget(inputpath, outputpath, this[type + 'Sources'], options);
}
};
Builder.prototype._watchFile = function(file, compress) {
var callback, stat, watcher,
_this = this;
stat = fs.statSync(file.filepath);
file.lastChange = +stat.mtime;
file.lastSize = stat.size;
return watcher = fs.watch(file.filepath, callback = function(event) {
var last, nstat;
if (event === 'rename') {
watcher.close();
try {
watcher = fs.watch(file.filepath, callback);
} catch (_error) {}
}
if (event === 'change') {
nstat = fs.statSync(file.filepath);
last = +nstat.mtime / 1000;
if (last !== file.lastChange) {
file.lastChange = last;
term.out("[" + (new Date().toLocaleTimeString()) + "] change detected in " + (term.colour(file.filename, term.GREY)), 0);
file.updateContents(fs.readFileSync(file.filepath, 'utf8'));
return _this.compile(compress, [file.type]);
}
}
});
};
return Builder;
})();
/*
watch: (compress, lint) ->
# @build(compress, lint)
# console.log(@jsSources.count, @cssSources.count)
# for type in [@JS, @CSS]
# notify.print("watching for changes in #{notify.strong('['+@config.build[type].sources.join(', ')+']')}...", 2)
# for s in @[type + 'Sources'].locations
# watcher = chokidar.watch(s, {ignored: @RE_IGNORE_FILE, persistent: true})
# watcher.on('add', @_onWatchAdd)
# watcher.on('change', @_onWatchChange)
# watcher.on('unlink', @_onWatchUnlink)
# @watchers.push(watcher)
_onWatchAdd: (filepath) =>
unless (@jsSources.byPath[filepath] or @cssSources.byPath[filepath]) and not path.basename(filepath).match(RE_IGNORE_FILE)
# Find base source directory
for loc in @jsSources.locations.concat(@cssSources.locations)
# Create file instance and store
if filepath.indexOf(loc) is 0 and f = @_fileFactory(filepath, loc)
cache = @[f.type + 'Sources']
cache.count++
cache.byModule[f.moduleId] = f if f.moduleId?
cache.byPath[f.filepath] = f
console.log('add', filepath, cache.count, path.basename(filepath).match(RE_IGNORE_FILE))
return
# notify.print("[#{new Date().toLocaleTimeString()}] change detected in #{notify.strong(path)}", 0)
_onWatchChange: (filepath) =>
# notify.print("[#{new Date().toLocaleTimeString()}] change detected in #{notify.strong(path)}", 0)
_onWatchUnlink: (filepath) =>
# notify.print("[#{new Date().toLocaleTimeString()}] change detected in #{notify.strong(path)}", 0)
_watchFile: (file, compress) ->
# Store initial time and size
stat = fs.statSync(file.filepath)
file.lastChange = +stat.mtime
file.lastSize = stat.size
watcher = fs.watch file.filepath, callback = (event) =>
# Clear old and create new on rename
if event is 'rename'
watcher.close()
try # if source no longer exists, never mind
watcher = fs.watch(file.filepath, callback)
if event is 'change'
# Compare time to the last second
# This should prevent double watch execusion bug
nstat = fs.statSync(file.filepath)
last = +nstat.mtime / 1000
if last isnt file.lastChange
# Store new time
file.lastChange = last
term.out("[#{new Date().toLocaleTimeString()}] change detected in #{term.colour(file.filename, term.GREY)}", 0)
# Update contents
file.updateContents(fs.readFileSync(file.filepath, 'utf8'))
# TODO: re-initialize targets
@compile(compress, [file.type])
*/

@@ -1,5 +0,3 @@

// Generated by CoffeeScript 1.3.1
var CSSFile, File, JSFile, fs, log, path,
__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; };
// Generated by CoffeeScript 1.4.0
var File, RE_BUILT_HEADER, fs, path;

@@ -10,136 +8,63 @@ fs = require('fs');

log = console.log;
RE_BUILT_HEADER = /^\/\*BUILT/g;
exports.File = File = (function() {
module.exports = File = (function() {
File.name = 'File';
function File(type, filepath, base) {
function File(type, filepath, basepath, compilers) {
var compiler, id;
this.type = type;
this.filepath = filepath;
this.base = base;
this.filename = path.basename(this.filepath);
this.name = path.relative(this.base, this.filepath).replace(path.extname(this.filename), '');
this.contents = null;
this.compile = false;
this.extension = path.extname(this.filename).slice(1);
this.dependencies = [];
this.qualifiedFilename = path.relative(basepath, this.filepath).replace(path.extname(this.filename), '');
this.needsCompile = this.extension !== this.type;
this.lastChange = null;
this._contents = '';
if (this.needsCompile) {
for (id in compilers) {
compiler = compilers[id];
if (this.extension === compiler.extension) {
this.compiler = compiler;
break;
}
}
}
}
File.prototype.updateContents = function(contents) {
return this.contents = contents;
File.prototype.parseContents = function() {
var contents;
this._contents = '';
contents = fs.readFileSync(this.filepath, 'utf8');
if (contents.match(RE_BUILT_HEADER)) {
return;
}
return this._contents = contents;
};
return File;
})();
exports.JSFile = JSFile = (function(_super) {
__extends(JSFile, _super);
JSFile.name = 'JSFile';
JSFile.prototype.RE_COFFEE_EXT = /\.coffee$/;
JSFile.prototype.RE_JS_EXT = /\.js$/;
JSFile.prototype.RE_COMMENT_LINES = /^\s*(?:\/\/|#).+$/gm;
JSFile.prototype.RE_REQUIRE = /require[\s|\(]['|"](.*?)['|"]/g;
JSFile.prototype.RE_MODULE = /^require\.module\(.+function *\( *module *, *exports *, *require *\) *{/gm;
JSFile.prototype.RE_WIN_SEPARATOR = /\\\\?/g;
function JSFile(type, filepath, base, contents) {
JSFile.__super__.constructor.call(this, type, filepath, base);
this.compile = this.RE_COFFEE_EXT.test(this.filepath);
this.module = this._getModuleName();
this.dependencies = [];
this.main = false;
this.updateContents(contents || fs.readFileSync(this.filepath, 'utf8'));
}
JSFile.prototype.updateContents = function(contents) {
JSFile.__super__.updateContents.call(this, contents);
return this.dependencies = this._getModuleDependencies();
};
JSFile.prototype.wrap = function(contents) {
if (!this.RE_MODULE.test(contents)) {
contents = "require.module('" + this.module + "', function(module, exports, require) {\n" + contents + "\n});";
File.prototype.getContents = function(options, fn) {
if (this.needsCompile) {
return this._compile(options, fn);
} else {
return fn(null, this._contents);
}
if (this.main) {
contents += "\nrequire('" + this.module + "');";
}
return contents;
};
JSFile.prototype._getModuleName = function() {
var letters, module,
_this = this;
module = this.name;
if (process.platform === 'win32') {
module = module.replace(this.RE_WIN_SEPARATOR, '/');
}
if (/[A-Z]/g.test(module)) {
letters = Array.prototype.map.call(module, function(l, i, arr) {
if (/[A-Z]/g.test(l)) {
return (i > 0 && arr[i - 1] !== '/' ? '_' : '') + l.toLowerCase();
File.prototype._compile = function(options, fn) {
var _this = this;
if (this.compiler != null) {
return this.compiler.compile(this._contents, options.sources, function(err, compiled) {
if (err) {
return fn(err, '');
} else {
return l;
return fn(null, compiled);
}
});
module = letters.join().replace(/,/g, '');
} else {
return fn("no compiler plugin available for " + (nofify.strong(this.filename)), '');
}
return module;
};
JSFile.prototype._getModuleDependencies = function() {
var contents, dep, deps, match, part, parts, _i, _len, _ref;
deps = [];
contents = this.contents.replace(this.RE_COMMENT_LINES, '');
while (match = this.RE_REQUIRE.exec(contents)) {
dep = match[1];
parts = dep.split('/');
if (dep.charAt(0) === '.') {
parts = this.module.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;
};
return File;
return JSFile;
})(File);
exports.CSSFile = CSSFile = (function(_super) {
__extends(CSSFile, _super);
CSSFile.name = 'CSSFile';
CSSFile.prototype.RE_STYLUS_EXT = /\.styl$/;
CSSFile.prototype.RE_LESS_EXT = /\.less$/;
function CSSFile(type, filepath, base) {
CSSFile.__super__.constructor.call(this, type, filepath, base);
this.compile = true;
this.updateContents(fs.readFileSync(this.filepath, 'utf8'));
}
return CSSFile;
})(File);
})();

@@ -1,2 +0,2 @@

// Generated by CoffeeScript 1.3.1
// Generated by CoffeeScript 1.4.0

@@ -3,0 +3,0 @@ (function() {

@@ -1,6 +0,4 @@

// Generated by CoffeeScript 1.3.1
var CSSTarget, JSTarget, Target, coffee, file, fs, growl, less, log, path, stylus, term, uglify,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__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; };
// Generated by CoffeeScript 1.4.0
var Target, existsSync, fs, notify, path,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

@@ -11,54 +9,30 @@ fs = require('fs');

term = require('./terminal');
notify = require('./utils').notify;
coffee = require('coffee-script');
existsSync = fs.existsSync || path.existsSync;
stylus = require('stylus');
module.exports = Target = (function() {
less = require('less');
uglify = require('uglify-js');
growl = require('growl');
file = require('./file');
log = console.log;
exports.Target = Target = (function() {
Target.name = 'Target';
function Target(input, output, cache) {
function Target(type, input, output, fileCache, options) {
this.type = type;
this.input = input;
this.output = output;
this.cache = cache;
this.compress = false;
this.batch = null;
this.fileCache = fileCache;
this.options = options;
this.sources = [];
this.concat = false;
if (!path.extname(this.output).length && fs.statSync(this.input).isFile()) {
this.output = path.join(this.output, path.basename(this.input)).replace(path.extname(this.input), "." + this.type);
}
}
Target.prototype.initialize = function() {
if (this._validInput(this.input)) {
this.sources = [];
if (this.batch === null) {
this.batch = fs.statSync(this.input).isDirectory();
}
if (!path.extname(this.output).length && fs.statSync(this.input).isFile()) {
this.output = path.join(this.output, path.basename(this.input)).replace(path.extname(this.input), this.EXTENSION);
}
this._parseInput(this.input);
} else {
term.out("" + (term.colour('warning', term.YELLOW)) + " input location does not exist " + (term.colour(this.input, term.GREY)), 2);
}
return this;
};
Target.prototype.run = function(compress) {
this.compress = compress;
Target.prototype.run = function(compress, lint, fn) {
this.sources = [];
this._parseSources(this.input);
if (this.sources.length) {
term.out("building " + (term.colour(path.basename(this.input), term.GREY)) + " to " + (term.colour(path.basename(this.output), term.GREY)), 2);
return this._build();
notify.print("building " + (notify.strong(path.basename(this.input))) + " to " + (notify.strong(path.basename(this.output))), 2);
return this._build(compress, lint, fn);
} else {
return term.out("" + (term.colour('warning', term.YELLOW)) + " no sources to build in " + (term.colour(this.input, term.GREY)), 2);
notify.warn("no sources to build in " + (notify.strong(this.input)), 2);
return fn();
}

@@ -71,20 +45,14 @@ };

Target.prototype._validInput = function(input) {
return path.existsSync(input);
};
Target.prototype._parseInput = function(input) {
var f, item, _i, _len, _ref, _results;
Target.prototype._parseSources = function(input) {
var file,
_this = this;
if (fs.statSync(input).isFile()) {
if (f = this.cache.byPath[input]) {
return this._addSource(f);
if (file = this.fileCache.byPath[input]) {
file.parseContents(this.options.modular);
return this._addSource(file);
}
} else {
_ref = fs.readdirSync(input);
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
item = _ref[_i];
_results.push(this._parseInput(path.join(input, item)));
}
return _results;
return fs.readdirSync(input).forEach(function(item) {
return _this._parseSources(path.join(input, item));
});
}

@@ -99,280 +67,34 @@ };

Target.prototype._makeDirectory = function(filepath) {
var dir;
dir = path.dirname(filepath);
if (!path.existsSync(dir)) {
try {
return fs.statSync(dir).isDirectory();
} catch (error) {
if (error.code === 'ENOENT') {
this._makeDirectory(dir);
return fs.mkdirSync(dir);
Target.prototype._lint = function(content, filepath) {
var _this = this;
if (this.options.linter != null) {
return this.options.linter.lint(content, function(err) {
if (err) {
notify.warn('failed linting', 4);
return err.items.forEach(function(item) {
return notify.print("[" + item.line + ":" + item.col + "] " + item.reason, 5);
});
} else {
return notify.print("" + (notify.colour('passed linting', notify.GREEN)) + " " + (notify.strong(path.basename(filepath))), 4);
}
}
}
};
Target.prototype._notifyError = function(filepath, error) {
term.out("" + (term.colour('error', term.RED)) + " building " + (term.colour(path.basename(filepath), term.GREY)) + ": " + error, 4);
try {
return growl.notify("error building " + filepath + ": " + error, {
title: 'BUDDY'
});
} catch (_error) {}
};
return Target;
})();
exports.JSTarget = JSTarget = (function(_super) {
__extends(JSTarget, _super);
JSTarget.name = 'JSTarget';
JSTarget.prototype.BUILT_HEADER = '/*BUILT ';
JSTarget.prototype.REQUIRE = 'require.js';
JSTarget.prototype.EXTENSION = '.js';
JSTarget.prototype.ERROR_LINE_NUMBER = 4;
JSTarget.prototype.RE_COFFEE_HELPERS = /^(\s+)(__\w*)\s=\s(.+)(,|;)$/gm;
JSTarget.prototype.RE_COMPILE_ERROR_LINE = /line\s(\d+)/gi;
function JSTarget(input, output, cache, nodejs, parentTarget) {
this.nodejs = nodejs != null ? nodejs : false;
this.parentTarget = parentTarget != null ? parentTarget : null;
JSTarget.__super__.constructor.call(this, input, output, cache);
}
JSTarget.prototype.initialize = function() {
if (this.nodejs) {
this.batch = true;
}
return JSTarget.__super__.initialize.call(this);
};
JSTarget.prototype._addSource = function(file, dependantFile) {
var dep, dependency, _i, _len, _ref, _ref1;
if ((_ref = this.parentTarget) != null ? _ref.hasSource(file) : void 0) {
return;
}
if (file.dependencies.length) {
_ref1 = file.dependencies;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
dependency = _ref1[_i];
if ((dependantFile != null ? dependantFile.module : void 0) !== dependency) {
if (dep = this.cache.byModule[dependency] || this.cache.byModule["" + dependency + "/index"]) {
this._addSource(dep, file);
} else {
term.out("" + (term.colour('warning', term.YELLOW)) + " dependency " + (term.colour(dependency, term.GREY)) + " for " + (term.colour(file.module, term.GREY)) + " not found", 4);
}
}
}
}
if (file.filepath === this.input && !this.batch) {
file.main = true;
}
return JSTarget.__super__._addSource.call(this, file);
};
JSTarget.prototype._build = function() {
var c, content, contents, f, filepath, _i, _j, _len, _len1, _ref, _ref1;
if (this.batch) {
_ref = this.sources;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
f = _ref[_i];
filepath = path.extname(this.output).length ? this.output : path.join(this.output, f.name) + this.EXTENSION;
content = f.compile ? this._compile(f.contents, filepath) : f.contents;
if (content != null) {
if (!this.nodejs) {
content = f.wrap(content);
}
this._writeFile(content, filepath, false);
}
}
return true;
} else {
contents = [];
_ref1 = this.sources;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
f = _ref1[_j];
c = f.compile ? this._compile(f.contents, f.filepath) : f.contents;
contents.push(f.wrap(c));
}
content = contents.join('\n');
if (content != null) {
if (!(this.nodejs || this.parentTarget)) {
content = "" + (fs.readFileSync(path.join(__dirname, this.REQUIRE), 'utf8')) + "\n" + content;
}
this._writeFile(this._optimizeAndWrap(content), this.output, true);
return true;
} else {
return null;
}
}
};
JSTarget.prototype._compile = function(content, filepath) {
var high, l, line, lineNo, lines, low, match, _i, _len, _ref;
try {
return coffee.compile(content, {
bare: true
});
} catch (error) {
this._notifyError(filepath, error);
if (match = this.RE_COMPILE_ERROR_LINE.exec(error)) {
lineNo = +match[1] - 1;
lines = content.split('\n');
low = Math.max(lineNo - this.ERROR_LINE_NUMBER, 0);
high = Math.min(lineNo + this.ERROR_LINE_NUMBER, lines.length - 1);
l = low;
_ref = lines.slice(low, high + 1 || 9e9);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
if (l++ === lineNo) {
term.out("" + (term.colour('> ' + l + ' ' + line, term.RED)), 4);
} else {
term.out("" + (term.colour(l + ' ' + line, term.GREY)), 5);
}
}
}
return null;
}
};
JSTarget.prototype._writeFile = function(content, filepath, header) {
this._makeDirectory(filepath);
term.out("" + (term.colour('built', term.GREEN)) + " " + (term.colour(path.basename(filepath), term.GREY)), 4);
if (this.compress) {
this._compress(filepath, content, header);
} else {
if (header) {
content = this._addHeader(content);
}
fs.writeFileSync(filepath, content, 'utf8');
}
return true;
};
JSTarget.prototype._compress = function(filepath, contents, header) {
var ast, compressed, jsp, pro;
jsp = uglify.parser;
pro = uglify.uglify;
ast = jsp.parse(contents);
ast = pro.ast_mangle(ast);
ast = pro.ast_squeeze(ast);
compressed = pro.gen_code(ast);
if (header) {
compressed = this._addHeader(compressed);
}
fs.writeFileSync(filepath, compressed);
return term.out("" + (term.colour('compressed', term.GREEN)) + " " + (term.colour(path.basename(filepath), term.GREY)), 4);
};
JSTarget.prototype._optimizeAndWrap = function(contents) {
var expr, replaceSnippet, snippet, snippets;
snippets = {};
replaceSnippet = function(str, p1, p2, p3, p4) {
snippets[p2] = p3.replace('__', '___');
return "" + p1 + p2 + " = _" + p2 + p4;
};
contents = contents.replace(this.RE_COFFEE_HELPERS, replaceSnippet);
return "(function () {\n" + (((function() {
var _results;
_results = [];
for (snippet in snippets) {
expr = snippets[snippet];
_results.push(' var _' + snippet + ' = ' + expr);
}
return _results;
})()).join(';\n')) + ";\n" + contents + "\n}).call(this);";
};
JSTarget.prototype._addHeader = function(content) {
return "" + this.BUILT_HEADER + (new Date().toString()) + "*/\n" + content;
};
return JSTarget;
})(Target);
exports.CSSTarget = CSSTarget = (function(_super) {
__extends(CSSTarget, _super);
CSSTarget.name = 'CSSTarget';
CSSTarget.prototype.EXTENSION = '.css';
function CSSTarget(input, output, cache) {
CSSTarget.__super__.constructor.call(this, input, output, cache);
}
CSSTarget.prototype._build = function() {
var f, filepath, _i, _len, _ref;
if (this.batch) {
_ref = this.sources;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
f = _ref[_i];
filepath = path.join(this.output, f.name) + this.EXTENSION;
if (f.compile) {
this._compile(f.contents, filepath, path.extname(f.filepath));
Target.prototype._compress = function(content, filepath, fn) {
var _this = this;
if (this.options.compressor != null) {
return this.options.compressor.compress(content, function(err, content) {
if (err) {
return fn(err);
} else {
this._writeFile(f.contents, filepath);
notify.print("" + (notify.colour('compressed', notify.GREEN)) + " " + (notify.strong(path.basename(filepath))), 3);
return fn(null, content);
}
}
return true;
} else {
f = this.sources[0];
return this._compile(f.contents, this.output, path.extname(f.filepath));
}
};
CSSTarget.prototype._compile = function(content, filepath, extension) {
var parser, stylc,
_this = this;
if (file.CSSFile.prototype.RE_STYLUS_EXT.test(extension)) {
stylc = stylus(content).set('paths', this.cache.locations.concat());
if (this.compress) {
stylc.set('compress', true);
}
return stylc.render(function(error, css) {
if (error) {
_this._notifyError(filepath, error);
return null;
} else {
return _this._writeFile(css, filepath);
}
});
} else if (file.CSSFile.prototype.RE_LESS_EXT.test(extension)) {
parser = new less.Parser({
paths: this.cache.locations.concat()
});
return parser.parse(content, function(error, tree) {
if (error) {
_this._notifyError(filepath, error);
return null;
} else {
return _this._writeFile(tree.toCSS({
compress: _this.compress
}), filepath);
}
});
}
};
CSSTarget.prototype._writeFile = function(content, filepath) {
this._makeDirectory(filepath);
term.out("" + (term.colour('built', term.GREEN)) + " " + (term.colour(path.basename(filepath), term.GREY)), 4);
fs.writeFileSync(filepath, content, 'utf8');
return true;
};
return Target;
return CSSTarget;
})(Target);
})();

@@ -1,2 +0,2 @@

// Generated by CoffeeScript 1.3.1
// Generated by CoffeeScript 1.4.0

@@ -3,0 +3,0 @@ module.exports = {

{
"name": "buddy",
"description": "A build framework for the compilation of higher order js/css languages (coffeescript/stylus/less).",
"version": "0.4.0",
"author": "popeindustries <alex@pope-industries.com>",
"keywords": ["javascript", "coffeescript", "styus", "less"],
"dependencies": {
"coffee-script": "1.x.x",
"growl": "1.x.x",
"stylus": "0.x.x",
"less": "1.x.x",
"uglify-js": "1.x.x",
"commander": "0.x.x"
},
"devDependencies": {
"rimraf": "*",
"should": "*",
"mocha": "1.x.x"
"name": "buddy",
"description": "A build framework 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.5.0",
"author": "popeindustries <alex@pope-industries.com>",
"keywords": ["build", "modules", "javascript", "coffeescript", "css", "styus", "less"],
"dependencies": {
"coffee-script": "1.4.0",
"stylus": "0.30.1",
"less": "1.3.1",
"uglify-js": "1.3.4",
"clean-css": "0.8.2",
"csslint": "0.9.9",
"jshint": "0.9.1",
"commander": "1.0.5",
"rimraf": "2.0.2",
"mkdirp": "0.3.4",
"bower": "0.4.0"
},
"directories": {
"devDependencies": {
"should": "*",
"mocha": "*"
},
"directories": {
"lib": "./lib"
},
"main": "./index",
"bin": {
"main": "./index.js",
"bin": {
"buddy": "./bin/buddy"
},
"scripts": {
"test": "mocha --compilers coffee:coffee-script --reporter spec --require should"
"scripts": {
"test": "mocha --compilers coffee:coffee-script --reporter spec --require should -t 40000"
},
"engines": {
"node": ">=0.6.0"
},
"repository": {
"engines": {
"node": ">=0.6.0"
},
"repository": {
"type": "git",
"url": "git://github.com/popeindustries/buddy.git"
}
},
"readme": "./README.md",
"_id": "buddy@0.5.0",
"_from": "buddy@~0.5"
}
# Buddy
Buddy is primarily a build framework for the compilation of higher order js/css languages (coffeescript/stylus/less).
Additionally, by using Node.js-style module wrapping and syntax, Buddy helps you write the same style of code for server and client.
This modular approach promotes better js code organization, and allows for automatic concatenation (and optional minification) of code for more efficient delivery to the browser.
**buddy(1)** is a build framework 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.
**Current version:** 0.5.0
*[this version is not backwards compatible with earlier versions. See Change Log below for more details]*
## Installation
Use the *-g* global flag to make the **buddy** command available system-wide:
Use the *-g* global flag to make the **buddy(1)** command available system-wide:

@@ -15,16 +16,51 @@ ```bash

Or, optionally, add **buddy** as a dependency in your project's *package.json* file:
```json
{
"name": "myproject",
"description": "This is my web project",
"version": "0.0.1",
"dependencies": {
"buddy": "0.5.0"
},
"scripts": {
"install": "buddy install",
"build": "buddy build",
"deploy": "buddy deploy"
}
}
```
...then install:
```bash
$ cd path/to/project
$ npm install
```
## Usage
```bash
$ cd path/to/my/project
# compile all source files
$ buddy compile
# compile and minify all source files
$ buddy -c compile
# watch for source changes and compile
$ buddy watch
# compile and minify for production
$ cd path/to/project
# When buddy is installed globally:
# install dependencies
$ buddy install
# build all source files
$ buddy build
# build and compress all source files
$ buddy -c build
# build and lint all source files
$ buddy -l build
# build and compress for production
$ buddy deploy
# view usage, examples, and options
$ buddy --help
# When buddy is installed locally:
# ...if scripts parameter defined in package.json
$ npm run-script install
# ...if called directly
$ ./node_modules/buddy/bin/buddy install
```

@@ -34,16 +70,25 @@

The only requirement for adding Buddy support to a project is the presence of a **buddy.json** file:
The only requirement for adding **buddy(1)** support to a project is the presence of a **buddy.js** file in your project root:
```json
{
"js": {
"sources": ["a/coffeescript/folder", "a/js/folder"],
"targets": [
```js
// Project build configuration.
exports.build = {
js: {
// Directories containing potential js source files for this project.
sources: ['a/coffeescript/source/directory', 'a/js/source/directory'],
// One or more js build targets.
targets: [
{
"in": "a/coffeescript/or/js/file",
"out": "a/js/file/or/folder",
"targets": [
// An entrypoint js (or equivalent) file to be wrapped in a module definition,
// concatenated with all it's resolved dependencies.
input: 'a/coffeescript/or/js/file',
// A destination in which to save the processed input.
// If a directory is specified, the input file name will be used.
output: 'a/js/file/or/directory',
// Targets can have children.
// Any sources included in the parent target will NOT be included in the child.
targets: [
{
"in": "a/coffeescript/or/js/file",
"out": "a/js/file/or/folder"
input: 'a/coffeescript/or/js/file',
output: 'a/js/file/or/directory'
}

@@ -53,18 +98,27 @@ ]

{
"in": "a/coffeescript/folder",
"out": "a/js/folder",
"nodejs": true
// Files are batch processed when a directory is used as input.
input: 'a/coffeescript/or/js/directory',
output: 'a/js/directory',
// Skips module wrapping (ex: for use in server environments).
modular: false
}
]
},
"css": {
"sources": ["a/stylus/folder", "a/less/folder"],
"targets": [
css: {
// Directories containing potential css source files for this project.
sources: ['a/stylus/directory', 'a/less/directory', 'a/css/directory'],
// One or more css build targets
targets: [
{
"in": "a/stylus/or/less/file",
"out": "a/css/file/or/folder"
// An entrypoint css (or equivalent) file to be processed,
// concatenated with all it's resolved dependencies.
input: 'a/stylus/less/or/css/file',
// A destination in which to save the processed input.
// If a directory is specified, the input file name will be used.
output: 'a/css/file/or/directory'
},
{
"in": "a/stylus/or/less/folder",
"out": "a/css/folder"
// Files are batch processed when a directory is used as input.
input: 'a/stylus/less/or/css/directory',
output: 'a/css/directory'
}

@@ -74,2 +128,57 @@ ]

}
// Project dependency configuration.
exports.dependencies = {
// A destination directory in which to place third-party library dependencies.
'a/vendor/directory': {
// An ordered list of dependencies
sources: [
// A git url.
// Install the 'browser-require' source when using Node modules.
'git://github.com/popeindustries/browser-require.git',
// A named library with or without version (ex: jquery#latest, backbone, backbone#1.0.0).
// Version identifiers follow the npm semantic versioning rules.
'library#version'
],
// Dependencies can be packaged and minified to a destination file
output: 'a/js/file'
},
// A destination directory in which to place source library dependencies.
'a/source/directory': {
sources: [
// A git url.
// Will use the 'main' property of package.json to identify the file to install.
'git://github.com/username/project.git',
// A git url with a specific file or directory identifier.
'git://github.com/username/project.git@a/file/or/directory',
// A local file or directory to copy and install.
'a/file/or/directory'
]
}
}
// Project settings configuration.
exports.settings = {
// Override the default plugins, and/or include custom plugins.
plugins: {
js: {
// Append one or more js compilers to the default 'coffeescript'.
compilers: ['a/file', 'another/file'],
// Change the default 'uglifyjs' compressor to a custom specification.
compressor: 'a/file',
// Change the default 'jshint' linter to a custom specification.
linter: 'a/file',
// Change the default 'node' module type to 'amd' or a custom specification.
module: 'amd'
},
css: {
// Append one or more css compilers to the default 'stylus' and 'less'.
compilers: ['a/file', 'another/file'],
// Change the default 'cleancss' compressor to a custom specification.
compressor: 'a/file',
// Change the default 'csslint' linter to a custom specification.
linter: 'a/file'
}
}
}
```

@@ -79,28 +188,24 @@

**Project Root**: The directory from which all paths resolve to. Determined by location of the *buddy.json* config file.
**Project Root**: The directory from which all paths resolve to. Determined by location of the *buddy.js* configuration file.
**Sources**: An array of directories from which all referenced files are retrieved from.
A js module's package name is constructed starting from it's source directory.
**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.
**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.
A js target can also have nested child targets, ensuring that dependencies are not duplicated across related builds.
**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.
**Target parameters**:
- *in*: file or directory to build. If js/coffee file, all dependencies referenced will be concatenated together for output (mixed js/coffee sources are possible).
If directory, all coffee/stylus/less files will be compiled and output to individual js/css files.
- *input*: file or directory to build. If js (or equivalent) file, all dependencies referenced will be concatenated together for output.
If directory, all compileable files will be compiled, wrapped in module definitions (js), and output to individual js/css files.
- *out*: file or directory to output to.
- *output*: file or directory to output to.
- *targets*: a nested target that prevents the duplication of js source code with it's parent target.
- *targets*: a nested target that prevents the duplication of source code with it's parent target.
- *nodejs*: a flag to prevent coffee files from being wrapped with a module declaration.
- *modular*: a flag to prevent js files from being wrapped with a module definition.
**Modules**: Each coffee/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:
**Modules**: Each 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:
```javascript
var lib = require('./my/lib'); // in current package
var SomeClass = require('../some_class'); // in parent package
var SomeClass = require('../someclass'); // in parent package
var util = require('utils/util'); // from root package

@@ -118,3 +223,3 @@

exports.myModuleMethod = function() {
exports.myModuleMethod = function() {
return myModuleVar;

@@ -142,34 +247,78 @@ };

- packages begin at the root folder specified in buddy.json > js > sources:
* packages begin at the root folder specified in *buddy.js > js > sources*:
```
'Users/alex/project/src/package/main.js' > 'package/main'
```
- uppercase filenames are converted to lowercase module ids:
* uppercase filenames are converted to lowercase module ids:
```
'my/package/Class.js' > 'my/package/class'
```
- camelcase filenames are converted to lowercase/underscore module ids:
See [node.js modules](http://nodejs.org/docs/v0.8.0/api/modules.html) for more info on modules.
## Examples
Copy project boilerplate from a local directory:
```js
exports.dependencies = {
'.': {
sources: ['../../boilerplate/project']
}
}
```
'my/package/ClassCamelCase.js' > 'my/package/class_camel_case'
Grab js dependencies to be installed and packaged for inclusion in html:
```js
exports.dependencies = {
// install location
'libs/vendor': {
sources: [
// library for require boilerplate
'git://github.com/popeindustries/browser-require.git',
// jquery at specific version
'jquery#1.8.2'
],
// packaged and compressed
output: 'www/assets/js/libs.js'
}
}
```
See [node.js modules](http://nodejs.org/docs/v0.6.0/api/modules.html) for more info on modules.
Grab sources to be referenced in your builds:
## Examples
```js
exports.dependencies = {
// install location
'libs/src/css': {
sources: [
// reference the lib/nib directory for installation
'git://github.com/visionmedia/nib.git@lib/nib'
]
}
}
```
Compile a library, then reference some library files in your project:
```json
"js": {
"sources": ["lib/src/coffee", "lib/js", "src"],
"targets": [
{
"in": "lib/src/coffee", <--a folder of coffee files (including nested folders)
"out": "lib/js" <--a folder of compiled js files
},
{
"in": "src/main.js", <--the application entry point referencing library dependencies
"out": "js/main.js" <--a concatenation of referenced dependencies
}
]
```js
exports.build = {
js: {
sources: ["libs/src/coffee", "libs/js", "src"],
targets: [
{
// a folder of coffee files (including nested folders)
input: "libs/src/coffee",
// a folder of compiled js files
output: "libs/js"
},
{
// the application entry point referencing library dependencies
input: "src/main.js",
// a concatenation of referenced dependencies
output: "js/main.js"
}
]
}
}

@@ -180,43 +329,43 @@ ```

```json
"js": {
"sources": ["src/coffee"],
"targets": [
{
"in": "src/coffee/main.coffee", <--the application entry point
"out": "js", <--includes all referenced sources
"targets": [
{
"in": "src/coffee/widget.coffee", <--references some of the same sources as main.coffee
"out": "js" <--includes only referenced sources not in main.js
}
]
}
]
```js
exports.build = {
js: {
sources: ["src/coffee"],
targets: [
{
// the application entry point
input: "src/coffee/main.coffee",
// output to main.js (includes all referenced dependencies)
output: "js",
targets: [
{
// references some of the same sources as main.coffee
input: "src/coffee/widget.coffee",
// includes only referenced dependencies not in main.js
output: "js"
}
]
}
]
}
}
```
## License
## Change Log ##
(The MIT License)
**0.5.0** - November 13, 2012
* changed module naming for compatibility with recent versions of Node.js (camel case no longer converted to underscores) **[breaking change]**
* changed configuration file type to 'js' from 'json'; added *dependencies* and *settings* **[breaking change]**
* concatenated js modules no longer self-booting; need to ```require('main');``` manually **[breaking change]**
* removed *watch* command (temporarily) **[breaking change]**
* added *install* command and project dependency management
* added plugin support for compilers, compressors, linters, and modules; added support for custom plugins
* added code linting
* all errors now throw
* complete code base refactor
## License
Copyright (c) 2011 Pope-Industries &lt;alex@pope-industries.com&gt;
Permission 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:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE 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.
Permission is hereby granted to do whatever you want with this software, but I won't be held responsible if something bad happens.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc