gulp-dependency-directive
Version:
Resolve dependency directives in assets (e.g. "@requires" or "//= require" in JavaScript)
137 lines (109 loc) • 2.85 kB
JavaScript
;
var fs = require('fs'),
path = require('path'),
Vinyl = require('vinyl'),
Log = require('fancy-log'),
AnsiColors = require('ansi-colors'),
_ = require('lodash'),
Stream = require('stream'),
DAG = require('dag');
var PLUGIN_NAME = 'gulp-dependency-directive';
function resolveDependencies(config) {
var defaults = {
pattern: /\* @requires [\s-]*(.*\.js)/g,
log: false,
ignoreCircularDependencies: false,
resolvePath: function(match, targetFile) {
return path.join(path.dirname(targetFile.path), match);
}
},
stream,
dag = new DAG(),
fileCache = [],
filesReturned = [],
getFiles = function(targetFile) {
var pattern = _.clone(config, true).pattern,
files = [],
content,
match,
relFilePath,
filePath,
file,
dependencies;
// Skip if already added to dependencies
if (_.indexOf(fileCache, targetFile.path) !== -1) {
return false;
} else {
fileCache.push(targetFile.path);
}
content = targetFile.contents.toString('utf8');
while (match = pattern.exec(content)) {
filePath = config.resolvePath(match[1], targetFile);
// Check for circular dependencies
try {
dag.addEdge(targetFile.path, filePath);
} catch (e) {
// Emit error or just continue
if (!config.ignoreCircularDependencies) {
stream.emit('error', new Error(PLUGIN_NAME + ': Circular dependency between "' + targetFile.path + '" and "' + filePath + '"'));
} else {
continue;
}
}
// Check existence
if (!fs.existsSync(filePath)) {
stream.emit('error', new Error(PLUGIN_NAME + ': File not found: ' + filePath));
continue;
}
// Create new file
file = new Vinyl({
base: targetFile.base,
path: filePath,
contents: fs.readFileSync(filePath),
stat: fs.statSync(filePath)
});
// Get new dependencies
while (dependencies = getFiles(file)) {
files = files.concat(dependencies);
}
}
// Add file itself
files.push(targetFile);
return files;
};
// Set default values
config = _.merge(defaults, config);
// Happy streaming
stream = Stream.Transform({
objectMode: true
});
stream._transform = function(file, unused, cb) {
var files;
if (file.isNull()) {
this.push(file);
return cb();
}
files = getFiles(file);
if (!files) {
return cb();
}
// Add dependencies and file itself to stream
files.forEach(_.bind(function(file) {
this.push(file);
}, this));
if (config.log) {
filesReturned = filesReturned.concat(files.map(function(file) {
return file.path;
}));
}
cb();
};
stream._flush = function(cb) {
if (config.log) {
Log('[' + AnsiColors.green(PLUGIN_NAME) + '] Files returned to stream:', filesReturned);
}
cb();
};
return stream;
};
module.exports = resolveDependencies;