0025e7e961
index.html, mail/, bootstrap and jquery bower components will build to the dist folder when running grunt
209 lines
6.8 KiB
JavaScript
209 lines
6.8 KiB
JavaScript
/*
|
|
* grunt-contrib-concat
|
|
* http://gruntjs.com/
|
|
*
|
|
* Copyright (c) 2013 "Cowboy" Ben Alman, contributors
|
|
* Licensed under the MIT license.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
exports.init = function(grunt) {
|
|
var exports = {};
|
|
|
|
// Node first party libs
|
|
var path = require('path');
|
|
|
|
// Third party libs
|
|
var chalk = require('chalk');
|
|
var SourceMapConsumer = require('source-map').SourceMapConsumer;
|
|
var SourceMapGenerator = require('source-map').SourceMapGenerator;
|
|
var SourceNode = require('source-map').SourceNode;
|
|
|
|
// Return an object that is used to track sourcemap data between calls.
|
|
exports.helper = function(files, options) {
|
|
// Figure out the source map destination.
|
|
var dest = files.dest;
|
|
if (options.sourceMapStyle === 'inline') {
|
|
// Leave dest as is. It will be used to compute relative sources.
|
|
} else if (typeof options.sourceMapName === 'string') {
|
|
dest = options.sourceMapName;
|
|
} else if (typeof options.sourceMapName === 'function') {
|
|
dest = options.sourceMapName(dest);
|
|
} else {
|
|
dest = dest + '.map';
|
|
}
|
|
|
|
// Inline style and sourceMapName together doesn't work
|
|
if (options.sourceMapStyle === 'inline' && options.sourceMapName) {
|
|
grunt.log.warn(
|
|
'Source map will be inlined, sourceMapName option ignored.'
|
|
);
|
|
}
|
|
|
|
return new SourceMapConcatHelper({
|
|
files: files,
|
|
dest: dest,
|
|
options: options
|
|
});
|
|
};
|
|
|
|
function SourceMapConcatHelper(options) {
|
|
this.files = options.files;
|
|
this.dest = options.dest;
|
|
this.options = options.options;
|
|
|
|
// Create the source map node we'll add concat files into.
|
|
this.node = new SourceNode();
|
|
|
|
// Create an array to store source maps that are referenced from files
|
|
// being concatenated.
|
|
this.maps = [];
|
|
}
|
|
|
|
// Construct a node split by a zero-length regex.
|
|
SourceMapConcatHelper.prototype._dummyNode = function(src, name) {
|
|
var node = new SourceNode();
|
|
var lineIndex = 1;
|
|
var charIndex = 0;
|
|
var tokens = src.split(/\b/g);
|
|
|
|
tokens.forEach(function(token, i) {
|
|
node.add(new SourceNode(lineIndex, charIndex, name, token));
|
|
// Count lines and chars.
|
|
token.split('\n').forEach(function(subtoken, j, subtokens) {
|
|
if (j < subtokens.length - 1) {
|
|
lineIndex++;
|
|
charIndex = 0;
|
|
} else {
|
|
charIndex += subtoken.length;
|
|
}
|
|
});
|
|
});
|
|
|
|
return node;
|
|
};
|
|
|
|
// Add some arbitraty text to the sourcemap.
|
|
SourceMapConcatHelper.prototype.add = function(src) {
|
|
// Use the dummy node to track new lines and character offset in the unnamed
|
|
// concat pieces (banner, footer, separator).
|
|
this.node.add(this._dummyNode(src));
|
|
};
|
|
|
|
// Add the lines of a given file to the sourcemap. If in the file, store a
|
|
// prior sourcemap and return src with sourceMappingURL removed.
|
|
SourceMapConcatHelper.prototype.addlines = function(src, filename) {
|
|
var relativeFilename = path.relative(path.dirname(this.dest), filename);
|
|
|
|
var node;
|
|
if (
|
|
/\/\/[@#]\s+sourceMappingURL=(.+)/.test(src) ||
|
|
/\/\*#\s+sourceMappingURL=(\S+)\s+\*\//.test(src)
|
|
) {
|
|
var sourceMapFile = RegExp.$1;
|
|
var sourceMapPath;
|
|
|
|
var sourceContent;
|
|
// Browserify, as an example, stores a datauri at sourceMappingURL.
|
|
if (/data:application\/json;base64,([^\s]+)/.test(sourceMapFile)) {
|
|
// Set sourceMapPath to the file that the map is inlined.
|
|
sourceMapPath = filename;
|
|
sourceContent = new Buffer(RegExp.$1, 'base64').toString();
|
|
} else {
|
|
// If sourceMapPath is relative, expand relative to the file
|
|
// refering to it.
|
|
sourceMapPath = path.resolve(path.dirname(filename), sourceMapFile);
|
|
sourceContent = grunt.file.read(sourceMapPath);
|
|
}
|
|
var sourceMap = JSON.parse(sourceContent);
|
|
var sourceMapConsumer = new SourceMapConsumer(sourceMap);
|
|
// Consider the relative path from source files to new sourcemap.
|
|
var sourcePathToSourceMapPath =
|
|
path.relative(path.dirname(this.dest), path.dirname(sourceMapPath));
|
|
// Store the sourceMap so that it may later be consumed.
|
|
this.maps.push([
|
|
sourceMapConsumer, relativeFilename, sourcePathToSourceMapPath
|
|
]);
|
|
// Remove the old sourceMappingURL.
|
|
src = src.replace(/[@#]\s+sourceMappingURL=[^\s]+/, '');
|
|
// Create a node from the source map for the file.
|
|
node = SourceNode.fromStringWithSourceMap(
|
|
src, sourceMapConsumer, sourcePathToSourceMapPath
|
|
);
|
|
} else {
|
|
// Use a dummy node. Performs a rudimentary tokenization of the source.
|
|
node = this._dummyNode(src, relativeFilename);
|
|
}
|
|
|
|
this.node.add(node);
|
|
|
|
if (this.options.sourceMapStyle !== 'link') {
|
|
this.node.setSourceContent(relativeFilename, src);
|
|
}
|
|
|
|
return src;
|
|
};
|
|
|
|
// Return the comment sourceMappingURL that must be appended to the
|
|
// concatenated file.
|
|
SourceMapConcatHelper.prototype.url = function() {
|
|
// Create the map filepath. Either datauri or destination path.
|
|
var mapfilepath;
|
|
if (this.options.sourceMapStyle === 'inline') {
|
|
var inlineMap = new Buffer(this._write()).toString('base64');
|
|
mapfilepath = 'data:application/json;base64,' + inlineMap;
|
|
} else {
|
|
// Compute relative path to source map destination.
|
|
mapfilepath = path.relative(path.dirname(this.files.dest), this.dest);
|
|
}
|
|
// Create the sourceMappingURL.
|
|
var url;
|
|
if (/\.css$/.test(this.files.dest)) {
|
|
url = '\n/*# sourceMappingURL=' + mapfilepath + ' */';
|
|
} else {
|
|
url = '\n//# sourceMappingURL=' + mapfilepath;
|
|
}
|
|
|
|
return url;
|
|
};
|
|
|
|
// Return a string for inline use or write the source map to disk.
|
|
SourceMapConcatHelper.prototype._write = function() {
|
|
var code_map = this.node.toStringWithSourceMap({
|
|
file: path.relative(path.dirname(this.dest), this.files.dest)
|
|
});
|
|
// Consume the new sourcemap.
|
|
var generator = SourceMapGenerator.fromSourceMap(
|
|
new SourceMapConsumer(code_map.map.toJSON())
|
|
);
|
|
// Consume sourcemaps for source files.
|
|
this.maps.forEach(Function.apply.bind(generator.applySourceMap, generator));
|
|
// New sourcemap.
|
|
var newSourceMap = generator.toJSON();
|
|
// Return a string for inline use or write the map.
|
|
if (this.options.sourceMapStyle === 'inline') {
|
|
grunt.log.writeln(
|
|
'Source map for ' + chalk.cyan(this.files.dest) + ' inlined.'
|
|
);
|
|
return JSON.stringify(newSourceMap, null, '');
|
|
} else {
|
|
grunt.file.write(
|
|
this.dest,
|
|
JSON.stringify(newSourceMap, null, '')
|
|
);
|
|
grunt.log.writeln('Source map ' + chalk.cyan(this.dest) + ' created.');
|
|
}
|
|
};
|
|
|
|
// Non-private function to write the sourcemap. Shortcuts if writing a inline
|
|
// style map.
|
|
SourceMapConcatHelper.prototype.write = function() {
|
|
if (this.options.sourceMapStyle !== 'inline') {
|
|
this._write();
|
|
}
|
|
};
|
|
|
|
return exports;
|
|
};
|