UNPKG

gulp-cog

Version:

Builds a list of includes in a similar way to snockets or sprockets but searches for available files from upstream pipes. This allows you to include js files from sources other than the disk, such as coffeescript or compiled templates. This plugin also le

162 lines (135 loc) 4.41 kB
var through = require('through2'); var sc = require('stream-combiner'); var _ = require('lodash'); var gutil = require('gulp-util'); var filter = require('gulp-filter'); var minimatch = require('minimatch'); var PluginError = gutil.PluginError; // consts const PLUGIN_NAME = 'gulp-cog'; const DIRECTIVE_REGEX = /^[\/\s#]*?=\s*?((?:require|include)(?:_tree|_directory)?)\s+(.*$)/mg; // plugin level function (dealing with files) function cog(glob) { if (typeof glob === 'undefined') { var glob = '**/*'; } // Collect all files, before we filter stream var allFiles = {}; var collectFilesStream = through.obj(function(file, enc, cb) { allFiles[file.relative] = file; cb(); }, function(cb) { _.each(allFiles, function(file) { collectFilesStream.push(file); }); cb(); }); // Get all includes for a file function getIncludes(file) { var content = String(file.contents); var matches = []; while (regexMatch = DIRECTIVE_REGEX.exec(content)) { matches.push(regexMatch); } // For every require fetch it's matching files var fileLists = _.map(matches, function(match) { return globMatch(match, file).sort(); }); // Merge all matching file lists into one concat list var order = _.reduce(fileLists, function(memo, fileList) { return _.union(memo, fileList); }, []); // And self to include list order.push(file.relative); return order; } function getRelativeDir(file) { var relativeDir = _.initial(file.relative.split('/')).join('/'); if (relativeDir.length > 0) { relativeDir += '/'; } return relativeDir; } // Translate an include match to a glob function globMatch(match, file) { var directiveType = match[1]; var globPattern = match[2]; // relative file // require all files under a directory if (directiveType.indexOf('_tree') !== -1) { globPattern = globPattern.concat('/**/*'); directiveType = directiveType.replace('_tree', ''); } // require only first level files in a directory if (directiveType.indexOf('_directory') !== -1) { globPattern = globPattern.concat('/*'); directiveType = directiveType.replace('_directory', ''); } // Only require and include directives are allowed if (directiveType !== 'require' && directiveType !== 'include') { return []; } // Add file extension to glob pattern if not already set var jsExt = '.js'; if (globPattern.substr(globPattern.length-jsExt.length).indexOf(jsExt) !== 0) { globPattern += jsExt; } // Append the current dir to include so we can match the glob against the file list var relativeDir = getRelativeDir(file); globPattern = relativeDir+globPattern; var possibleIncludes = []; _.each(_.keys(allFiles), function(fileName) { // Only process files in the current directory. ../ will not work. if (fileName.indexOf(relativeDir) !== 0) { return; } possibleIncludes.push(fileName); }); return minimatch.match(possibleIncludes, globPattern); } // creating a stream through which each file will pass var concatFiles = []; var buildIncludesStream = through.obj(function(file, enc, cb) { if (file.isStream()) { this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!')); return cb(); } // Attach includes to masterfile file.includes = _.filter(_.map(getIncludes(file), function(filename) { return allFiles[filename]; }, function(file) { return !!file; })); this.push(file); cb(); }); /* * Construct the stream. * * Steps: * 1. Build a list of all files in the stream for use later * 2. Filter files to only desired master concat files * 3. Build concat manifests data objects for each of the master files */ var stream = sc( collectFilesStream, filter(glob), buildIncludesStream ); return stream; }; /* * Emit include files back into the stream. * * Usually used with gulp-foreach and gulp-concat master files. */ cog.includes = function() { var includesStream = through.obj(function(masterFile, enc, cb) { _.each(masterFile.includes, function(file) { includesStream.push(file); }); cb(); }); return includesStream; }; // exporting the plugin main function module.exports = cog;