Comparing version 0.2.0 to 0.3.0
@@ -0,1 +1,9 @@ | ||
# v0.3.0 | ||
* Better logging, multiple bug fixes. | ||
* Refactored internal Pipeline so that Copier and AssetPackager are treated | ||
the same way. | ||
* Removed placeholders for LESS compiler. (will be separate) | ||
* Added CoffeeScript support | ||
# v0.2.0 | ||
@@ -2,0 +10,0 @@ |
{ | ||
"name": "sample_app", | ||
"main": "./app/main.js", | ||
"convoy": { | ||
"javascript": { | ||
"compilers": { | ||
".js": "convoy/pipeline_plugins/javascript_compiler", | ||
".coffee": "convoy/pipeline_plugins/coffeescript_compiler", | ||
".hbr": "ember/pipeline_plugins/handlebars_compiler" | ||
} | ||
}, | ||
"css": { | ||
"compilers": { | ||
".css": "convoy/pipeline_plugins/css_compiler", | ||
".less": "convoy/pipeline_plugins/less_compiler" | ||
} | ||
} | ||
} | ||
"main": "./app/main.js" | ||
} |
@@ -23,3 +23,2 @@ /** | ||
var MIME = require('mime'); | ||
var watchTree = require("watch").watchTree; | ||
@@ -58,3 +57,3 @@ // var glob = require('glob'); | ||
path = PATH.relative(copier.path, path); | ||
if (path.charAt(0) === '.') return null; // invalid | ||
if (~path.indexOf('..')) return null; | ||
return PATH.resolve(copier.root, path); | ||
@@ -74,16 +73,76 @@ } | ||
function _watch(copier, done) { | ||
if (copier.watch && !copier._watcher) { | ||
FS.stat(copier.root, function(err, stats) { | ||
if (err) return done(err); | ||
function _makeWatcher(root, callback) { | ||
var watcher = null; | ||
var children = null; | ||
var ret = null; | ||
function handleError(err) { | ||
if (err) throw err; | ||
} | ||
function fileChanged() { | ||
teardown(); | ||
setup(function(err) { | ||
if (err) return handleError(err); | ||
callback(root); | ||
}); | ||
} | ||
function childChanged(path) { | ||
callback(path); | ||
} | ||
function setup(next) { | ||
watcher = FS.watch(root, { persistent: true }, fileChanged); | ||
FS.stat(root, function(err, stats) { | ||
if (err) return next(err); | ||
if (stats.isDirectory()) { | ||
copier._watcher = watchTree(copier.root, copier.invalidate); | ||
children = []; | ||
FS.readdir(root, function(err, files) { | ||
if (err) return next(err); | ||
files.forEach(function(path) { | ||
path = PATH.resolve(root, path); | ||
children.push(_makeWatcher(path, childChanged)); | ||
}); | ||
next(); | ||
}); | ||
} else { | ||
copier._watcher = FS.watch(copioer.root, copier.invalidate); | ||
next(); | ||
} | ||
done(); | ||
}); | ||
} else done(); | ||
} | ||
function teardown() { | ||
if (watcher) watcher.close(); | ||
watcher = null; | ||
if (children) { | ||
children.forEach(function(watcher) { | ||
watcher.close(); | ||
}); | ||
} | ||
children = null; | ||
} | ||
ret = { | ||
path: root, | ||
close: teardown | ||
}; | ||
setup(handleError); | ||
return ret; | ||
} | ||
function _watch(copier, done) { | ||
if (copier.watch & !copier._watcher) { | ||
copier._watcher = _makeWatcher(copier.root, function(path) { | ||
copier.info('changed', path); | ||
copier.invalidate(); | ||
}); | ||
} | ||
done(); | ||
} | ||
/** | ||
@@ -97,3 +156,3 @@ * Returns true if the packager can generate the named path. For AssetCopier | ||
AssetCopier.prototype.exists = function(path, done) { | ||
_exists(this, path, true, done); | ||
_exists(this, path, false, done); | ||
}; | ||
@@ -154,3 +213,5 @@ | ||
type: MIME.lookup(realPath, 'application/binary'), | ||
bodyStream: FS.createReadStream(realPath) | ||
mtime: stats.mtime ? stats.mtime.getTime() : 0, | ||
size: stats.size, | ||
bodyPath: realPath | ||
}); | ||
@@ -163,28 +224,2 @@ }); | ||
/** | ||
* Writes the asset to disk. If no outputPath is passed uses the default path | ||
* provided. | ||
* | ||
* @param {String} dstPath Output path to write to. | ||
* @param {String} srcPath The logical path to copy from. | ||
* @param {Function} done Optional. Invoked when complete. | ||
* @return {void} | ||
*/ | ||
AssetCopier.prototype.writeFile = function(dstPath, srcPath, done) { | ||
var self = this; | ||
done = _error(this, done); | ||
_exists(this, srcPath, true, function(exists) { | ||
if (!exists) return done(new Error(srcPath + ' is not a file')); | ||
var realPath = _resolve(self, srcPath); | ||
UTILS.mkdir_p(PATH.dirname(dstPath), function(err) { | ||
if (err) return done(err); | ||
UTILS.cp_r(realPath, dstPath, self, function(err) { | ||
if (err) return done(err); | ||
_watch(self, done); | ||
}); | ||
}); | ||
}); | ||
}; | ||
/** | ||
* Invalidates any caches so that the next call to the packager will rebuild | ||
@@ -191,0 +226,0 @@ * from scratch. |
@@ -43,3 +43,3 @@ /** | ||
var ASYNC = require('async'); | ||
var RESOLVE = require('resolve'); | ||
var RESOLVE = require('./resolver'); | ||
var UTILS = require('./utils'); | ||
@@ -89,2 +89,13 @@ | ||
AssetPackager.prototype.watchPath = function(assetPath) { | ||
var self = this; | ||
if (self.watch && !self._watching[assetPath]) { | ||
self._watching[assetPath] = | ||
FS.watch(assetPath, { persistent: true }, function() { | ||
self.info('changed', assetPath); | ||
self.invalidate(); | ||
}); | ||
} | ||
}; | ||
/** | ||
@@ -100,2 +111,3 @@ * Returns the asset descriptor for a given source asset. `done()` will be | ||
AssetPackager.prototype.getSourceAsset = function(assetPath, done) { | ||
if (!done) done = function() {}; | ||
assetPath = PATH.resolve(this.basedir, assetPath); | ||
@@ -127,2 +139,8 @@ if (!this._sourceAssets[assetPath]) { | ||
function(next) { | ||
FS.stat(assetPath, function(err, stats) { | ||
if (err) return next(err); | ||
asset.mtime = stats.mtime.getTime(); | ||
next(); | ||
}); | ||
}, function(next) { | ||
compiler(asset, self, next); | ||
@@ -139,6 +157,4 @@ | ||
], function(err) { | ||
if (self.watch && !self._watching[assetPath]) { | ||
self._watching[assetPath] = | ||
FS.watch(assetPath, { persistant: false }, self.invalidate); | ||
} | ||
if (err) return done(err); | ||
if (!err) self.watchPath(assetPath); | ||
return done(err, asset); | ||
@@ -207,8 +223,15 @@ }); | ||
*/ | ||
AssetPackager.prototype.resolve = function(moduleId, basedir) { | ||
return RESOLVE.sync(moduleId, { | ||
AssetPackager.prototype.resolve = function(moduleId, basedir, opts) { | ||
if (!opts) opts = {}; | ||
if (this.pipeline && this.pipeline.paths) { | ||
opts.paths = this.pipeline.paths.concat(opts.paths || []); | ||
} | ||
return RESOLVE.sync(moduleId, UTILS.merge({ | ||
extensions: Object.keys(this.compilers), | ||
basedir: basedir || this.basedir, | ||
isFile: _isFile | ||
}); | ||
isFile: _isFile, | ||
mainKey: this.mainKey | ||
}, opts)); | ||
}; | ||
@@ -262,5 +285,12 @@ | ||
ASYNC.mapSeries(asset.dependencies, function(path, next) { | ||
context.getSourceAsset(path, next); | ||
context.getSourceAsset(path, function(err, sourceAsset) { | ||
if (!sourceAsset) { | ||
err = new Error(''+path+' not found (required in '+asset.path+')'); | ||
} | ||
next(err, sourceAsset); | ||
}); | ||
}, function(err, assets) { | ||
if (err) return next(err); | ||
asset.children = assets; | ||
@@ -273,3 +303,3 @@ assets.forEach(function(childAsset) { | ||
expanded.push(asset); | ||
next(); | ||
next(err); | ||
}); | ||
@@ -432,28 +462,2 @@ }); | ||
/** | ||
* Writes the asset to disk. If no outputPath is passed uses the default path | ||
* provided. | ||
* | ||
* @param {String} dstPath Output path to write to. | ||
* @param {String} srcPath Asset path to write. Must equal path. | ||
* @param {Function} done Optional. Invoked when complete. | ||
* @return {void} | ||
*/ | ||
AssetPackager.prototype.writeFile = function(dstPath, srcPath, done) { | ||
var self = this; | ||
done = _error(this, done); | ||
dstPath = PATH.resolve(dstPath); | ||
this.build(srcPath, function(err, asset) { | ||
if (err) return done(err); | ||
UTILS.mkdir_p(PATH.dirname(dstPath), function(err) { | ||
if (err) return done(err); | ||
var encoding = asset.encoding || 'utf8'; | ||
FS.writeFile(dstPath, asset.body, encoding, function(err) { | ||
if (!err) self.info('wrote', dstPath); | ||
done(err); | ||
}); | ||
}); | ||
}); | ||
}; | ||
/** | ||
* Cleans up any watchers. Normally just for testing. | ||
@@ -460,0 +464,0 @@ * @return {void} |
@@ -11,10 +11,17 @@ /** | ||
// generates a new packager subclass with default config | ||
function packager() { | ||
// generates a new packager subclass with default config. Pass an optional | ||
// BaseClass to further extend a packager. | ||
function packager(BaseClass) { | ||
var args = Array.prototype.slice.call(arguments); | ||
if ('function' === typeof BaseClass) { | ||
args.unshift(); | ||
} else { | ||
BaseClass = AssetPackager; | ||
} | ||
function Packager() { | ||
AssetPackager.apply(this, arguments); | ||
BaseClass.apply(this, arguments); | ||
} | ||
Packager.prototype = UTILS.merge(Object.create(AssetPackager.prototype), | ||
Array.prototype.slice.call(arguments)); | ||
Packager.prototype = UTILS.merge(Object.create(BaseClass.prototype), args); | ||
@@ -33,3 +40,4 @@ return Packager; | ||
linker: plugins.CommonJSLinker, | ||
minifier: plugins.UglifyMinifier | ||
minifier: plugins.UglifyMinifier, | ||
mainKey: 'main' | ||
}); | ||
@@ -47,3 +55,4 @@ | ||
linker: plugins.SimpleMergeLinker, | ||
minifier: plugins.UglifyMinifier | ||
minifier: plugins.UglifyMinifier, | ||
mainkey: 'main' | ||
}); | ||
@@ -50,0 +59,0 @@ |
@@ -69,2 +69,3 @@ /** | ||
var packagers = require('./packagers'); | ||
var middleware = require('./middleware').middleware; | ||
@@ -78,3 +79,3 @@ var _extend = UTILS.extend; | ||
this.packagers = {}; | ||
this.invalidate = this.invalidate.bind(); // so we can use as a listener | ||
this.invalidate = this.invalidate.bind(this); // so we can use as a listener | ||
this._config(arguments); | ||
@@ -85,3 +86,3 @@ } | ||
var CONFIG_KEYS = ['watch']; | ||
var CONFIG_KEYS = ['watch', 'paths']; | ||
@@ -105,2 +106,12 @@ Pipeline.prototype._config = function(configs) { | ||
/** | ||
* Returns a new middleware instance for use in a connect stack. You can | ||
* pass the same options to this method as you would pass to the connect | ||
* `static()` middleware. | ||
* | ||
* @param {Hash} options Optional hash of options | ||
* @return {Function} connect handler | ||
*/ | ||
Pipeline.prototype.middleware = middleware; | ||
/** | ||
* If set to true then pipeline will automatically watch all assets and | ||
@@ -146,4 +157,10 @@ * invalidate whenever they change. This will keep it's cache clean when used | ||
this.pipeLogging(ret, path); | ||
ret.on('invalidate', this.invalidate); | ||
var invalidate = this.invalidate, self = this; | ||
ret.on('invalidate', function() { | ||
invalidate.apply(self, arguments); | ||
}); | ||
this.packagers[path] = ret; | ||
this.invalidate(); | ||
return ret; | ||
@@ -163,2 +180,3 @@ }; | ||
delete this.packagers[path]; | ||
this.invalidate(); | ||
} | ||
@@ -201,3 +219,21 @@ }; | ||
if (!packager) return done(new Error('path not found '+path)); | ||
packager.writeFile(PATH.resolve(buildir, path), path, done); | ||
packager.build(path, function(err, asset) { | ||
if (err) return done(err); | ||
var dstPath = PATH.resolve(buildir, path); | ||
UTILS.mkdir_p(PATH.dirname(dstPath), function(err) { | ||
if (err) return done(err); | ||
if (asset.bodyPath) { | ||
UTILS.cp_r(asset.bodyPath, dstPath, self, done); | ||
} else if (asset.body) { | ||
var encoding = asset.encoding || 'utf8'; | ||
FS.writeFile(dstPath, asset.body, encoding, function(err) { | ||
if (!err) self.info('wrote', dstPath); | ||
done(err); | ||
}); | ||
} else { | ||
return done(new Error(path+' asset does not contain body')); | ||
} | ||
}); | ||
}); | ||
}); | ||
@@ -216,6 +252,6 @@ }; | ||
var self = this; | ||
_mapPaths(this, function(err, packagers) { | ||
if (err) return _error(self, err, done); | ||
ASYNC.forEach(Object.keys(packagers), function(path, next) { | ||
packagers[path].writeFile(PATH.resolve(buildir, path), path, next); | ||
self.findPaths(function(err, paths) { | ||
if (err) return done(err); | ||
ASYNC.forEach(paths, function(path, next) { | ||
self.writeFile(path, buildir, next); | ||
}, done); | ||
@@ -235,5 +271,7 @@ }); | ||
Pipeline.prototype.build = function(path, done) { | ||
done = _error(this, done); | ||
this._canInvalidate = true; | ||
_selectPackager(this, path, function(packager) { | ||
if (!packager) { | ||
_error(this, done, new Error('path not found '+path)); | ||
done(new Error('path not found '+path)); | ||
} else { | ||
@@ -268,2 +306,3 @@ packager.build(path, done); | ||
Pipeline.prototype.findPaths = function(done) { | ||
this._canInvalidate = true; | ||
_mapPaths(this, function(err, packagers) { | ||
@@ -275,10 +314,4 @@ done(err, !err && packagers ? Object.keys(packagers) : null); | ||
Pipeline.prototype.invalidate = function() { | ||
var path; | ||
if (!this._invalidating) { | ||
this._invalidating = true; | ||
for(path in packagers) { | ||
if (packagers.hasOwnProperty(path)) packagers[path].invalidate(); | ||
} | ||
this._invalidating = false; | ||
if (this._canInvalidate) { | ||
this._canInvalidate = false; | ||
this.emit('invalidate'); | ||
@@ -288,10 +321,4 @@ } | ||
Pipeline.prototype.middleware = function(root) { | ||
return function(req, res, next) { | ||
// TODO: implement | ||
}; | ||
}; | ||
exports.Pipeline = Pipeline; | ||
@@ -98,3 +98,7 @@ /** | ||
if (err) return done(err); | ||
FS.mkdir(path, done); | ||
FS.mkdir(path, function(err) { | ||
// sometimes another routine gets around to making this first | ||
if (err && err.code === 'EEXIST') err = null; | ||
done(err); | ||
}); | ||
delete making[path]; | ||
@@ -117,3 +121,3 @@ }); | ||
UTIL.pump(is, os, function(err) { | ||
if (!err && logger) logger.info('copied', src, dst); | ||
if (!err && logger) logger.info('copied', src, '->', dst); | ||
done(err); | ||
@@ -120,0 +124,0 @@ }); |
{ | ||
"name": "convoy", | ||
"version": "v0.2.0", | ||
"version": "v0.3.0", | ||
"author": "Charles Jolley <charles@sproutcore.com>", | ||
@@ -22,7 +22,5 @@ "description": "Pluggable, package-aware asset pipeline for node", | ||
"async": "0.1.x", | ||
"resolve": "0.2.x", | ||
"uglify-js": "~1.2", | ||
"glob": "~3.1", | ||
"mime": "~1.2", | ||
"watch": "0.5.x", | ||
"coffee-script": "~1.3" | ||
@@ -35,3 +33,4 @@ }, | ||
"dox": "latest", | ||
"temp": "latest" | ||
"temp": "latest", | ||
"connect": "latest" | ||
}, | ||
@@ -38,0 +37,0 @@ |
@@ -6,4 +6,4 @@ /** | ||
var CoffeeScript = require('coffee-script'); | ||
var FS = require('fs'); | ||
var CoffeeScript = require('coffee-script'); | ||
@@ -10,0 +10,0 @@ function CoffeeScriptCompiler(asset, context, done) { |
@@ -13,3 +13,2 @@ /** | ||
e.CSSCompiler = require('./css_compiler'); | ||
e.LESSCompiler = require('./less_compiler'); | ||
@@ -16,0 +15,0 @@ e.GenericAnalyzer = require('./generic_analyzer'); |
@@ -11,2 +11,7 @@ /** | ||
expanded.map(function(asset) { return asset.body; }).join("\n"); | ||
asset.mtime = expanded.reduce(function (curMtime, asset) { | ||
return Math.max(curMtime || 0, asset.mtime || 0); | ||
}, 0); | ||
done(); | ||
@@ -13,0 +18,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
5
81
137299
5
3824
13
4
- Removedresolve@0.2.x
- Removedwatch@0.5.x
- Removedresolve@0.2.8(transitive)
- Removedwatch@0.5.1(transitive)