diff --git a/examples/components/tobi-ferret/component.json b/examples/components/tobi-ferret/component.json index 1d6250a..be89eb9 100644 --- a/examples/components/tobi-ferret/component.json +++ b/examples/components/tobi-ferret/component.json @@ -1,7 +1,8 @@ { "name": "ferret", "dependencies": { - "tobi/bar": "*" + "tobi/bar": "*", + "loki/foo": "*" }, "scripts": ["index.js"], "styles": ["ferret.css"] diff --git a/examples/components/tobi-ferret/components/loki-foo/component.json b/examples/components/tobi-ferret/components/loki-foo/component.json new file mode 100644 index 0000000..fe1aaff --- /dev/null +++ b/examples/components/tobi-ferret/components/loki-foo/component.json @@ -0,0 +1,4 @@ +{ + "name": "loki-foo", + "scripts": ["index.js"] +} \ No newline at end of file diff --git a/examples/components/tobi-ferret/components/loki-foo/index.js b/examples/components/tobi-ferret/components/loki-foo/index.js new file mode 100644 index 0000000..bf9640c --- /dev/null +++ b/examples/components/tobi-ferret/components/loki-foo/index.js @@ -0,0 +1 @@ +module.exports = 'loki'; \ No newline at end of file diff --git a/lib/builder.js b/lib/builder.js index 20e84c5..b60310d 100644 --- a/lib/builder.js +++ b/lib/builder.js @@ -5,6 +5,7 @@ var fs = require('fs') , path = require('path') + , join = path.join , Batch = require('batch') , debug = require('debug')('component:builder') , Emitter = require('events').EventEmitter @@ -26,6 +27,9 @@ module.exports = Builder; function Builder(dir) { this.dir = dir; this.name = basename(dir); + this.paths = []; + this.paths.push(join(dir, 'components')); + this.paths.push(join(dir, '..')); this.ignored = { scripts: [], styles: [] @@ -38,6 +42,35 @@ function Builder(dir) { Builder.prototype.__proto__ = Emitter.prototype; +/** + * Lookup component `name` using `.paths` + * and invoke `fn(err, dir)`. + * + * @param {String} name + * @param {String} fn + * @api public + */ + +Builder.prototype.lookup = function(name, fn){ + var paths = this.paths; + var i = 0; + + debug('lookup %s', name); + function next() { + var path = paths[i++]; + if (!path) return fn(); + var dir = join(path, name); + debug('lookup check %s', dir); + fs.exists(dir, function(yes){ + if (!yes) return next(); + debug('lookup found %s', dir); + fn(null, dir); + }); + } + + next(); +}; + /** * Ignore the given component name(s) of `type`. * @@ -141,15 +174,17 @@ Builder.prototype.build = function(fn){ }; /** - * Build scripts and invoke `fn(err, js)`. + * Build `type` and invoke `fn`. * - * @param {Function} fn + * @param {String} type + * @param {String} fn + * @param {String} process * @api private */ -Builder.prototype.buildScripts = function(fn){ +Builder.prototype.buildType = function(type, fn, process){ var self = this; - debug('building %s js', this.name); + debug('building %s %s', this.name, type); this.json(function(err, conf){ if (err) return fn(err); @@ -160,28 +195,32 @@ Builder.prototype.buildScripts = function(fn){ dep = dep.replace('/', '-'); // ignored - if (self.ignoring(dep, 'scripts')) return debug('ignoring %s', dep); + if (self.ignoring(dep, type)) return debug('ignoring %s', dep); // ignore it so we dont have dups - self.ignore(dep, 'scripts'); - - // build dep - var dir = self.path(path.join('..', dep)); - debug('building dependency %s', dep); - var builder = new Builder(dir); - builder.ignored = self.ignored; - self.emit('dependency', builder); - batch.push(builder.buildScripts.bind(builder)); + self.ignore(dep, type); + + // lookup dep + batch.push(function(done){ + self.lookup(dep, function(err, dir){ + if (err) return done(err); + debug('building dependency %s in %s', dep, dir); + var builder = new Builder(dir); + builder.ignored = self.ignored; + self.emit('dependency', builder); + builder.buildType(type, done, process); + }); + }); }); } - if (conf.scripts) { - conf.scripts.forEach(function(script){ - var path = self.path(script); + if (conf[type]) { + conf[type].forEach(function(file){ + var path = self.path(file); batch.push(function(done){ fs.readFile(path, 'utf8', function(err, str){ if (err) return fn(err); - done(null, register(conf.name + '/' + script, str)); + done(null, process(conf.name + '/' + file, str)); }); }); }); @@ -195,53 +234,26 @@ Builder.prototype.buildScripts = function(fn){ }; /** - * Build styles and invoke `fn(err, css)`. + * Build scripts and invoke `fn(err, js)`. * * @param {Function} fn * @api private */ -Builder.prototype.buildStyles = function(fn){ - var self = this; - debug('building %s css', this.name); - - this.json(function(err, conf){ - if (err) return fn(err); - var batch = new Batch; - - if (conf.dependencies) { - Object.keys(conf.dependencies).forEach(function(dep){ - dep = dep.replace('/', '-'); - - // ignored - if (self.ignoring(dep, 'styles')) return debug('ignoring %s', dep); - - // ignore it so we dont have dups - self.ignore(dep, 'styles'); - - // build dep - var dir = self.path(path.join('..', dep)); - debug('building dependency %s', dep); - var builder = new Builder(dir); - builder.ignored = self.ignored; - self.emit('dependency', builder); - batch.push(builder.buildStyles.bind(builder)); - }); - } +Builder.prototype.buildScripts = function(fn){ + this.buildType('scripts', fn, register); +}; - if (conf.styles) { - conf.styles.forEach(function(script){ - var path = self.path(script); - batch.push(function(done){ - fs.readFile(path, 'utf8', done); - }); - }); - } +/** + * Build styles and invoke `fn(err, css)`. + * + * @param {Function} fn + * @api private + */ - batch.end(function(err, res){ - if (err) return fn(err); - fn(null, res.join('\n')); - }); +Builder.prototype.buildStyles = function(fn){ + this.buildType('styles', fn, function(file, str){ + return str; }); };