backoffice/node_modules/grunt-includes/tasks/includes.js

237 lines
6.0 KiB
JavaScript

/**
* grunt-includes
* https://github.com/vanetix/grunt-includes
*
* Copyright (c) 2013 Matt McFarland
* Licensed under the MIT license.
*/
module.exports = function(grunt) {
/**
* Dependencies
*/
var path = require('path');
// Regex for matching new lines
var newlineRegexp = /\r?\n/g;
// Regex for parsing includes
var defaultRegexp = /^(\s*)include\s+"(\S+)"\s*$/;
// Regexp to replace with the file inside a template
var defaultTemplateFileRegexp = /\{\{\s?file\s?\}\}/;
// Regexp for inerpolating the filename in the template
var templateFilenameRegexp = /\{\{\s?fileName\s?\}\}/;
/**
* Core `grunt-includes` task
* Iterates over all source files and calls `recurse(path)` on each
*/
grunt.registerMultiTask('includes', 'Include other files within files.', function() {
var banner;
// Default options
var opts = this.options({
debug: false,
banner: '',
silent: false,
duplicates: true,
includeRegexp: defaultRegexp,
includePath: '',
filenamePrefix: '',
filenameSuffix: '',
template: '',
templateFileRegexp: defaultTemplateFileRegexp
});
if(grunt.util.kindOf(opts.includeRegexp) === 'string') {
opts.includeRegexp = new RegExp(opts.includeRegexp);
}
if(grunt.util.kindOf(opts.templateFileRegexp) === 'string') {
opts.templateFileRegexp = new RegExp(opts.templateFileRegexp);
}
// Render banner
banner = grunt.template.process(opts.banner);
this.files.forEach(function(f) {
var src, cwd = f.cwd;
src = f.src.filter(function(p) {
if(cwd) {
p = path.join(f.cwd, p);
}
if(grunt.file.isFile(p)) {
return true;
} else {
grunt.fail.fatal('Source "' + p + '" is not a file');
return false;
}
});
if(src.length > 1 && isFilename(f.dest)) {
grunt.fail.fatal('Source file cannot be more than one when dest is a file.');
}
src.forEach(function(p) {
var fileName = f.flatten ? path.basename(p) : p;
var outFile = isFilename(f.dest) ? f.dest : path.join(f.dest, fileName);
if(cwd) {
p = path.join(cwd, p);
}
grunt.file.write(outFile, banner + recurse(p, opts));
if(!opts.silent) {
grunt.log.oklns('Saved ' + outFile);
}
});
});
});
/**
* Checks if `p` is a filepath, being it has an extension.
*
* @param {String} p
* @return {Boolean}
*/
function isFilename(p) {
return !!path.extname(p);
}
/**
* Returns the comment style for file `p`
*
* @param {String} p
* @return {String}
*/
function commentStyle(p) {
var comments,
ext = path.extname(p).slice(1);
comments = {
js: "/* %s */",
css: "/* %s */",
html: "<!-- %s -->"
};
return comments[ext] || '/* %s */';
}
/**
* Returns the new line style for file `p`
*
* @param {String} p
* @return {String}
*/
function newlineStyle(p) {
var matches = grunt.file.read(p).match(newlineRegexp);
return (matches && matches[0]) || grunt.util.linefeed;
}
/**
* Helper for `includes` builds all includes for `p`
*
* @param {String} p
* @return {String}
*/
function recurse(p, opts, included, indents) {
var src, next, match, error, comment, content,
newline, compiled, indent, fileLocation,
currentTemplate;
if(!grunt.file.isFile(p)) {
grunt.fail.warn('Included file "' + p + '" not found.');
return 'Error including "' + p + '".';
}
indents = indents || '';
comment = commentStyle(p);
newline = newlineStyle(p);
included = included || [];
// If `opts.duplicates` is false and file has been included, error
if(!opts.duplicates && ~included.indexOf(p)) {
error = 'Duplicate include: ' + p + ' skipping.';
grunt.log.error(error);
if(opts.debug) {
return comment.replace(/%s/g, error);
} else {
return '';
}
}
// At this point the file is considered included
included.push(p);
// Split the file on newlines
src = grunt.file.read(p).split(newline);
// Loop through the file calling `recurse` if an include is found
compiled = src.map(function(line) {
match = line.match(opts.includeRegexp);
// If the line has an include statement, recurse
if(match) {
indent = match[1];
fileLocation = match[2];
if (!fileLocation) {
fileLocation = indent;
indent = '';
}
fileLocation = opts.filenamePrefix + fileLocation + opts.filenameSuffix;
next = path.join((opts.includePath || path.dirname(p)), fileLocation);
content = recurse(next, opts, included, indents + indent);
// Wrap file around in template if `opts.template` has '{{file}}' in it.
if(opts.template !== '' && opts.template.match(opts.templateFileRegexp)) {
currentTemplate = opts.template.split(newline).map(function(line) {
line = line.replace(templateFilenameRegexp, fileLocation);
if (line.match(opts.templateFileRegexp)) {
return line;
} else {
return indent + indents + line;
}
});
// Safe guard against $ replacements - this can probably be improved
content = content.replace(/\$/g, '$$$$');
content = currentTemplate.join(newline).replace(opts.templateFileRegexp, content);
}
// Safe guard against $ replacements, change $ to $$
content = content.replace(/\$/g, '$$$$');
line = line.replace(opts.includeRegexp, content);
// Include debug comments if `opts.debug`
if(opts.debug) {
line = comment.replace(/%s/g, 'Begin: ' + next) +
newline + line + comment.replace(/%s/g, 'End: ' + next);
}
}
// If there are indents and not a match, add them to the line
return line && indents && !match ? indents + line : line;
});
return compiled.join(newline);
}
};