grunt-depconcat
Version:
Concat depended files
161 lines (130 loc) • 4.87 kB
JavaScript
/*
* grunt-depconcat
* https://github.com/terrykingcha/grunt-depconcat
*
* Copyright (c) 2013 tERry.K
* Licensed under the MIT license.
*/
var path = require('path'),
util = require('util'),
deptree = require('serialize-deptree');
module.exports = function(grunt) {
// Please see the Grunt documentation for more information regarding task
// creation: http://gruntjs.com/creating-tasks
grunt.registerMultiTask('depconcat', 'Concat depended files', function() {
var JS_REQUIRE_TEMPLATE = '\\/\\/@require\\s+([^\\n\\r]+)[\\n\\r]*',
CSS_REQUIRE_TEMPLATE = '@import\\s+url\\(["\']?([^"\'()]+)["\']?\\);?[\\n\\r]*'
;
// Merge task-specific and/or target-specific options with these defaults.
var options = this.options({
separator: grunt.util.linefeed,
requireTemplate: null,
ext: null,
except: [],
});
function isExcept(filepath) {
var except = options.except;
for (var i = 0; i < except.length; i++) {
var e = except[i];
if (!(e instanceof RegExp)) {
e = except[i] = new RegExp(except[i] + '$');
}
if (e.test(filepath)) {
return true;
}
}
return false;
}
// Iterate over all specified file groups.
this.files.forEach(function(f) {
var reg, ext = options.ext || f.dest.match(/\.[a-z]+$/i)[0], tree;
if (!options.requireTemplate) {
if (ext === '.css') {
reg = CSS_REQUIRE_TEMPLATE;
} else {
ext = '.js';
reg = JS_REQUIRE_TEMPLATE;
}
} else if (typeof options.requireTemplate === 'string'){
reg = options.requireTemplate;
} else {
ext = '.js';
reg = JS_REQUIRE_TEMPLATE;
}
reg = new RegExp(reg, 'gi');
if (f.src) {
// Concat specified files.
tree = {};
function parseFile(filepath) {
// extract dependency files
var filedir = path.dirname(filepath),
file = grunt.file.read(filepath),
matches = file.match(reg) || []
;
tree[path.normalize(filepath)] = matches.map(function(match) {
var depfilepath;
reg.lastIndex = 0;
depfilepath = reg.exec(match)[1];
if (!(/\.\w+$/).test(depfilepath)) {
depfilepath = depfilepath + ext;
}
depfilepath = path.normalize(path.join(filedir, depfilepath));
if (!grunt.file.exists(depfilepath)) {
grunt.log.warn('Source file "' + depfilepath + '" not found.');
return;
}
if (!isExcept(depfilepath)) {
parseFile(depfilepath);
return depfilepath;
}
}).filter(function(f) {return f;});
}
// filter non-exists files or except files
f.src.filter(function(filepath) {
if (!grunt.file.exists(filepath)) {
grunt.log.warn('Source file "' + filepath + '" not found.');
return false;
} else {
return !isExcept(filepath);
}
}).forEach(parseFile);
} else if (f.tree) {
// read from tree file
if (typeof f.tree === 'string') {
tree = grunt.file.readJSON(f.tree);
var names = Object.keys(tree),
treedir = path.dirname(f.tree);
names.forEach(function(filepath) {
var deplist = tree[filepath];
delete tree[filepath];
if (!(/\.\w+$/).test(filepath)) {
filepath = filepath + ext;
}
filepath = path.normalize(path.join(treedir, filepath));
tree[filepath] = deplist.map(function(depfilepath) {
if (!(/\.\w+$/).test(depfilepath)) {
depfilepath = depfilepath + ext;
}
depfilepath = path.normalize(path.join(treedir, depfilepath));
if (!grunt.file.exists(depfilepath)) {
grunt.log.warn('Source file "' + depfilepath + '" not found.');
return;
}
if (!isExcept(depfilepath)) {
return depfilepath;
}
}).filter(filterNull);
});
} else {
tree = f.tree;
}
}
var serialized = deptree.serialize(tree).map(function(filepath) {
// Read file source.
return grunt.file.read(filepath).replace(reg, '');
});
grunt.file.write(f.dest, serialized.join(grunt.util.linefeed));
grunt.log.writeln('Dest File "' + f.dest + '" created.');
});
});
};