Initial commit
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* affectedFiles
|
||||
*
|
||||
* This program outputs a list of files affected by changes in other files that are in the former ones dependency tree.
|
||||
* The problem that inspired this program is to know what test files can be broken because of modifications on
|
||||
* another files in the code base. This way, we'll know the exact test files that we must run to check that
|
||||
* nothing breaks.
|
||||
*
|
||||
* It needs a config file called `tree.config.json` with the next properties:
|
||||
* - testsFolder: the folder to build the dependency tree from. In our case, the specs folder.
|
||||
* ex: "testsFolder": "lib/assets/test/spec/builder/"
|
||||
* - filesRegex: the regular expression for knowing what files must be taken into account for building the dependency tree.
|
||||
* ex: "filesRegex": "spec\\.js$"
|
||||
*
|
||||
* Input: the program needs a list of files to check against. See example below for an explanation.
|
||||
* Output: it outputs the list of affected files between the tags <affected></affected>
|
||||
*
|
||||
* Example:
|
||||
* Say we have two spec files in folder specs/ with its own dependencies.
|
||||
*
|
||||
* spec/
|
||||
* +
|
||||
* |-- foo.spec.js - require('lib/component'), require('lib/calendar'), require('lib/tools/dropdown')
|
||||
* |
|
||||
* |-- baz.spec.js - require('lib/whatever'), require('lib/calendar')
|
||||
*
|
||||
* Run 1: What spec files are affected by a change in files 'lib/tools/dropdown.js' and 'lib/common/utils.js'? (It's only required in foo.spec.js dependency tree)
|
||||
* > affectedFiles lib/tools/drowndown.js lib/common/utils.js
|
||||
* output
|
||||
* <affected>
|
||||
* spec/foo.spec.js
|
||||
* </affected>
|
||||
*
|
||||
* Run 2: What spec files are affected by a change in file 'lib/calendar.js'? (It's required in both specs)
|
||||
* > affectedFiles lib/tools/calendar.js
|
||||
* output
|
||||
* <affected>
|
||||
* spec/foo.spec.js
|
||||
* spec/baz.spec.js
|
||||
* </affected>
|
||||
*/
|
||||
|
||||
|
||||
var fs = require('fs-extra');
|
||||
var colors = require('colors');
|
||||
var recursive = require('recursive-readdir');
|
||||
var minimist = require('minimist');
|
||||
var _ = require('underscore');
|
||||
var FileTrie = require('./fileTrie');
|
||||
|
||||
var configFile = './tree.config.json';
|
||||
var start = Date.now();
|
||||
var trie = new FileTrie();
|
||||
var error = false;
|
||||
var config;
|
||||
|
||||
var addTrigger = function (triggers, currentTrigger, affectedSpecs) {
|
||||
if (!triggers[currentTrigger]) {
|
||||
triggers[currentTrigger] = [];
|
||||
}
|
||||
triggers[currentTrigger] = _.uniq(triggers[currentTrigger].concat(affectedSpecs));
|
||||
return triggers;
|
||||
};
|
||||
|
||||
var logTriggers = function (triggers) {
|
||||
var keys = Object.keys(triggers);
|
||||
keys.forEach(function (key) {
|
||||
console.log('');
|
||||
console.log(colors.yellow(key));
|
||||
console.log(colors.yellow(new Array(key.length + 1).join('-')));
|
||||
triggers[key].forEach(function (trigger) {
|
||||
console.log(trigger);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var main = function (testsFolder, modifiedFiles, filesRegex) {
|
||||
filesRegex = filesRegex || 'spec\\.js$';
|
||||
|
||||
var onlyTheseFiles = function (file, stats) {
|
||||
var theRegex = new RegExp(filesRegex);
|
||||
return !stats.isDirectory() && !theRegex.test(file);
|
||||
};
|
||||
|
||||
function promiseMap (xs, f) {
|
||||
const reducer = (ysAcc$, x) =>
|
||||
ysAcc$.then(ysAcc => f(x).then(y => ysAcc.push(y) && ysAcc));
|
||||
return xs.reduce(reducer, Promise.resolve([]));
|
||||
}
|
||||
|
||||
function readFiles (folder) {
|
||||
return recursive(folder, [onlyTheseFiles]);
|
||||
}
|
||||
|
||||
function getAffectedFilesFrom (files) {
|
||||
if (!files || files.length === 0) {
|
||||
console.error('Spec files not found.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('Found ' + files.length + ' spec files.');
|
||||
var allFilePromises = files.reduce(function (acc, file) {
|
||||
acc.push(trie.addFileRequires(file));
|
||||
return acc;
|
||||
}, []);
|
||||
Promise.all(allFilePromises)
|
||||
.then(function () {
|
||||
console.log('Dependency tree created.');
|
||||
console.log(colors.magenta('Took ' + (Date.now() - start)));
|
||||
|
||||
console.log('Getting reverse spec dependencies...');
|
||||
|
||||
var markStart = Date.now();
|
||||
files.forEach(function (file) {
|
||||
trie.markSubTree(file);
|
||||
});
|
||||
console.log(colors.magenta('Took ' + (Date.now() - markStart)));
|
||||
|
||||
var specsInfo = _.chain(modifiedFiles)
|
||||
.reduce(function (acc, modifiedFile) {
|
||||
console.log(colors.magenta(acc.affectedSpecs.length));
|
||||
|
||||
var node = trie.getNode(modifiedFile);
|
||||
if (node && node.marks && node.marks.length > 0) {
|
||||
acc.affectedSpecs = acc.affectedSpecs.concat(node.marks);
|
||||
acc.triggers = addTrigger(acc.triggers, modifiedFile, node.marks);
|
||||
return acc;
|
||||
}
|
||||
return acc;
|
||||
}, {
|
||||
affectedSpecs: [],
|
||||
triggers: {}
|
||||
})
|
||||
.value();
|
||||
|
||||
var targetSpecs = _.uniq(specsInfo.affectedSpecs);
|
||||
|
||||
logTriggers(specsInfo.triggers);
|
||||
|
||||
console.log('');
|
||||
console.log('<affected>');
|
||||
targetSpecs.forEach(function (spec) {
|
||||
console.log(spec);
|
||||
});
|
||||
console.log('</affected>');
|
||||
})
|
||||
.catch(function (reason) {
|
||||
console.error(colors.red(reason));
|
||||
process.exit(-1);
|
||||
});
|
||||
}
|
||||
|
||||
promiseMap(testsFolder, readFiles)
|
||||
.then(function (files) {
|
||||
const flattenFiles = [].concat.apply([], files);
|
||||
getAffectedFilesFrom(flattenFiles);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
};
|
||||
|
||||
// Read configuration & run program
|
||||
try {
|
||||
if (fs.statSync(configFile)) {
|
||||
config = fs.readJsonSync(configFile);
|
||||
if (!config.testsFolder) {
|
||||
console.error('`testsFolder` not found in config file.');
|
||||
error = true;
|
||||
} else {
|
||||
var modifiedFiles = minimist(process.argv.slice(2))._;
|
||||
main(config.testsFolder, modifiedFiles, config.filesRegex);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.code && err.code === 'ENOENT') {
|
||||
console.error('Config file `tree.config.json` not found!');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
function cleanArray (actual) {
|
||||
var newArray = [];
|
||||
for (var i = 0; i < actual.length; i++) {
|
||||
if (actual[i]) {
|
||||
newArray.push(actual[i]);
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
module.exports = cleanArray;
|
||||
@@ -0,0 +1,7 @@
|
||||
var cfg = {
|
||||
requirePattern: "require\\('(\\..+)'\\)",
|
||||
defaultExt: '.js',
|
||||
validExtensions: ['.tpl', '.json', '.js', '.mustache']
|
||||
}
|
||||
|
||||
module.exports = cfg;
|
||||
@@ -0,0 +1,59 @@
|
||||
var fs = require('fs-extra');
|
||||
var path = require('path');
|
||||
var config = require('./fetchRequires.config.js');
|
||||
|
||||
function checkConfig () {
|
||||
if (!config.requirePattern) {
|
||||
throw new Error("requirePattern needed at fetchRequires.config.js - Use it to define the regular expression to use for finding require invocations. Example: require\\('(\\..+)'\\)");
|
||||
}
|
||||
if (!config.defaultExt) {
|
||||
throw new Error("defaultExt needed at fetchRequires.config.js - Use it to define the default extension to use for modules. Example: '.js'");
|
||||
}
|
||||
if (!config.validExtensions) {
|
||||
throw new Error("validExtensions needed at fetchRequires.config.js - Use it to laod modules as is. That's it, to define valid extensions that don't need appending the default extension. Example: ['.tpl', '.json']");
|
||||
}
|
||||
}
|
||||
|
||||
var fetchRequires = function (absoluteFilePath) {
|
||||
checkConfig();
|
||||
var requirePattern = config.requirePattern;
|
||||
var requireGlobalRegex = new RegExp(requirePattern, 'g');
|
||||
var requireRegex = new RegExp(requirePattern);
|
||||
var defaultExt = config.defaultExt;
|
||||
var validExtensions = config.validExtensions;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.readFile(absoluteFilePath, 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
if (err.code && err.code === 'ENOENT') {
|
||||
var error = new Error("ENOENT: no such file '" + err.path + "'. Perhaps we're adding the default extension to a valid file. Check `validExtensions` in fetchRequires.config.js and add a new one if needed.");
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var requires = [];
|
||||
if (data) {
|
||||
var matchData = data.match(requireGlobalRegex);
|
||||
if (matchData) {
|
||||
matchData.forEach(function (require) {
|
||||
var exec = requireRegex.exec(require);
|
||||
if (exec) {
|
||||
var absolutePath = path.resolve(path.dirname(absoluteFilePath), exec[1]);
|
||||
var ext = path.extname(absolutePath);
|
||||
if (validExtensions.indexOf(ext) === -1) {
|
||||
absolutePath += defaultExt;
|
||||
}
|
||||
requires.push(absolutePath);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
resolve(requires);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = fetchRequires;
|
||||
@@ -0,0 +1,131 @@
|
||||
var path = require('path');
|
||||
var colors = require('colors');
|
||||
|
||||
var fetchRequires = require('./fetchRequires');
|
||||
var cleanArray = require('./cleanArray');
|
||||
|
||||
var FileTrie = function () {
|
||||
var trie = {
|
||||
root: {}
|
||||
};
|
||||
|
||||
var addFileRequires = function (filePath) {
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
if (!path.extname(filePath)) {
|
||||
reject('filePath must contain a valid file path.');
|
||||
return;
|
||||
}
|
||||
|
||||
var key = _buildKey(filePath, true);
|
||||
var fileName = path.basename(filePath);
|
||||
var lastNode = _writeKey(key);
|
||||
if (!lastNode[fileName]) {
|
||||
fetchRequires(filePath)
|
||||
.then(function (requires) {
|
||||
lastNode[fileName] = {};
|
||||
if (requires.length > 0) {
|
||||
lastNode[fileName].requires = requires;
|
||||
lastNode[fileName].fetched = false;
|
||||
var allRequirePromises = requires.reduce(function (acc, require) {
|
||||
acc.push(addFileRequires(require));
|
||||
return acc;
|
||||
}, []);
|
||||
Promise.all(allRequirePromises)
|
||||
.then(function () {
|
||||
lastNode[fileName].fetched = true;
|
||||
resolve();
|
||||
})
|
||||
.catch(function (reason) {
|
||||
reject(reason);
|
||||
});
|
||||
} else {
|
||||
lastNode[fileName].requires = [];
|
||||
lastNode[fileName].fetched = true;
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
.catch(function (reason) {
|
||||
reject(reason);
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
return promise;
|
||||
};
|
||||
|
||||
var markSubTree = function (entryFilePath, mark) {
|
||||
var filesToMark;
|
||||
var fileToMark;
|
||||
var node;
|
||||
|
||||
mark = mark || entryFilePath;
|
||||
filesToMark = [entryFilePath];
|
||||
while (filesToMark.length > 0) {
|
||||
fileToMark = filesToMark.pop();
|
||||
node = getNode(fileToMark);
|
||||
if (!node.marks) {
|
||||
node.marks = [];
|
||||
}
|
||||
if (node.marks.indexOf(mark) === -1) {
|
||||
node.marks.push(mark);
|
||||
if (node.requires && node.requires.length > 0) {
|
||||
filesToMark = filesToMark.concat(node.requires);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var getNode = function (filePath) {
|
||||
var key = _buildKey(filePath);
|
||||
var node = trie.root;
|
||||
var validKey = true;
|
||||
for (var i = 0; i < key.length && validKey; i++) {
|
||||
if (!node[key[i]]) {
|
||||
validKey = false;
|
||||
} else {
|
||||
node = node[key[i]];
|
||||
}
|
||||
}
|
||||
|
||||
if (!validKey) {
|
||||
return null;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
var _buildKey = function (filePath, onlyDir) {
|
||||
var key = filePath;
|
||||
if (onlyDir) {
|
||||
key = path.dirname(filePath);
|
||||
}
|
||||
return cleanArray(key.split(path.sep));
|
||||
};
|
||||
|
||||
var _writeKey = function (key) {
|
||||
var node = trie.root;
|
||||
var subKey;
|
||||
|
||||
for (var i = 0; i < key.length; i++) {
|
||||
subKey = key[i];
|
||||
if (!node[subKey]) {
|
||||
node[subKey] = {};
|
||||
}
|
||||
node = node[subKey];
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
var print = function () {
|
||||
console.log(colors.yellow(JSON.stringify(trie)));
|
||||
};
|
||||
|
||||
return {
|
||||
addFileRequires: addFileRequires,
|
||||
getNode: getNode,
|
||||
markSubTree: markSubTree,
|
||||
print: print
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = FileTrie;
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* branchFiles
|
||||
*
|
||||
* Outputs the list of modified files in the current branch compared to master.
|
||||
* Includes already commited files and the ones unstaged.
|
||||
*/
|
||||
|
||||
var _ = require('underscore');
|
||||
var colors = require('colors');
|
||||
var modifiedFiles = require('./modifiedFiles');
|
||||
|
||||
var fileList = [];
|
||||
|
||||
var getModifiedFiles = function () {
|
||||
modifiedFiles()
|
||||
.then(function (files) {
|
||||
var newFiles = _.difference(files, fileList);
|
||||
var removedFiles = _.difference(fileList, files);
|
||||
var change = false;
|
||||
fileList = files;
|
||||
|
||||
if (newFiles.length > 0) {
|
||||
change = true;
|
||||
}
|
||||
if (removedFiles.length > 0) {
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (change) {
|
||||
fileList.forEach(function file (file) {
|
||||
console.log(file);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(function (reason) {
|
||||
console.log(colors.red(reason));
|
||||
});
|
||||
};
|
||||
|
||||
getModifiedFiles();
|
||||
@@ -0,0 +1,141 @@
|
||||
var child = require('child_process');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var recursive = require('recursive-readdir');
|
||||
var _ = require('underscore');
|
||||
|
||||
/**
|
||||
* getCurrentBranchName
|
||||
*
|
||||
* @returns {string} The name of the current git branch
|
||||
*/
|
||||
function getCurrentBranchName () {
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
child.exec('git rev-parse --abbrev-ref HEAD', function (error, stdout, stderr) {
|
||||
if (!error) {
|
||||
resolve(stdout.replace(/(\r\n|\n|\r)/gm, ''));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* getFilesModifiedInBranch
|
||||
*
|
||||
* @param {string} branchName The branch name to get the list of modified file list from.
|
||||
* @returns {Promise} result.
|
||||
* @resolves {string[]} The list of modified files in the given branch.
|
||||
*/
|
||||
function getFilesModifiedInBranch (branchName) {
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
var files;
|
||||
var command = 'git diff --name-only ' + branchName + ' `git merge-base ' + branchName + ' master`';
|
||||
|
||||
child.exec(command, function (error, stdout, stderr) {
|
||||
if (!error) {
|
||||
var newLine = /(\r\n|\n|\r)/;
|
||||
files = stdout.split(newLine).filter(function (file) {
|
||||
return file.trim().length > 0;
|
||||
});
|
||||
files = files.map(function (file) {
|
||||
return path.resolve('.', file);
|
||||
});
|
||||
resolve(files);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
var notNodeModules = function (file, stats) {
|
||||
return stats.isDirectory() && file.toLowerCase().indexOf('node_modules') > -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* getFilesInStatus
|
||||
*
|
||||
* @returns {Promise} result.
|
||||
* @resolves {string[]} The list of working tree files as shown by `git status --short` but without status codes.
|
||||
*/
|
||||
function getFilesInStatus () {
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
child.exec('git status --short', function (error, stdout, stderr) {
|
||||
if (!error) {
|
||||
var newLine = /\n/;
|
||||
var files = stdout.split(newLine);
|
||||
var promises = files.reduce(function (acc, file) {
|
||||
if (file.trim().length > 0) {
|
||||
var name = file.slice(3);
|
||||
var resolvedPath = path.resolve('.', name);
|
||||
|
||||
try {
|
||||
var stats = fs.statSync(resolvedPath);
|
||||
if (stats.isFile()) {
|
||||
acc.push(Promise.resolve(resolvedPath));
|
||||
return acc;
|
||||
} else if (stats.isDirectory()) {
|
||||
acc.push(new Promise(function (resolve, reject) {
|
||||
recursive(resolvedPath, [notNodeModules], function (err, files) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
resolve(files);
|
||||
});
|
||||
}));
|
||||
return acc;
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
acc.push(Promise.resolve(resolvedPath));
|
||||
return acc;
|
||||
} else {
|
||||
throw new Error(err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return acc;
|
||||
}
|
||||
}, []);
|
||||
|
||||
Promise.all(promises)
|
||||
.then(function (fileList) {
|
||||
resolve(_.uniq(_.compact(_.flatten(fileList))));
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* getModifiedFiles
|
||||
*
|
||||
* @returns {Promise} result.
|
||||
* @resolves {string[]} The list of all modified files of the working branch compared to master. It includes already committed files and the ones unstaged.
|
||||
*/
|
||||
var getModifiedFiles = function () {
|
||||
var files = [];
|
||||
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
getCurrentBranchName()
|
||||
.then(function (branchName) {
|
||||
return getFilesModifiedInBranch(branchName);
|
||||
})
|
||||
.then(function (modifiedFiles) {
|
||||
files = files.concat(modifiedFiles);
|
||||
return getFilesInStatus();
|
||||
})
|
||||
.then(function (filesInStatus) {
|
||||
files = _.uniq(files.concat(filesInStatus));
|
||||
resolve(files);
|
||||
});
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
module.exports = getModifiedFiles;
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Entry point bundles that are expected to be minimized and distributed on CDNs goes here.
|
||||
*
|
||||
* Format:
|
||||
* name_of_bundle: {
|
||||
* src: [
|
||||
* 'some/path/file.js',
|
||||
* 'another/path/sfile.js',
|
||||
* //...
|
||||
* ]
|
||||
*
|
||||
* The defined files in the "src" array will be written to public/assets/javascripts/X.X.X/name_of_bundle.js, where X.X.X
|
||||
* is the current frontend version. Grunt will then take care of minification etc.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
user_feed: {
|
||||
src: [
|
||||
'lib/assets/javascripts/cartodb/user_feed/entry.js'
|
||||
]
|
||||
},
|
||||
editor: {
|
||||
src: [
|
||||
'lib/assets/javascripts/cartodb/editor.js'
|
||||
]
|
||||
},
|
||||
public_dashboard: {
|
||||
src: [
|
||||
'lib/assets/javascripts/cartodb/public_dashboard/entry.js'
|
||||
]
|
||||
},
|
||||
public_map: {
|
||||
src: [
|
||||
'lib/assets/javascripts/cartodb/public_map/entry.js'
|
||||
]
|
||||
},
|
||||
test_specs_for_browserify_modules: {
|
||||
src: [
|
||||
'lib/build/source-map-support.js',
|
||||
|
||||
// Dependency for editor specs
|
||||
'lib/assets/javascripts/cartodb/editor.js',
|
||||
|
||||
// Add specs for browserify module code here:
|
||||
'lib/assets/test/spec/cartodb/common/**/*.spec.js',
|
||||
'lib/assets/test/spec/cartodb/components/**/*.spec.js',
|
||||
'lib/assets/test/spec/cartodb/editor/**/*.spec.js',
|
||||
'lib/assets/test/spec/cartodb/public_dashboard/**/*.spec.js',
|
||||
'lib/assets/test/spec/cartodb/feed/**/*.spec.js',
|
||||
'lib/assets/test/spec/cartodb/show/**/*.spec.js',
|
||||
'lib/assets/test/spec/cartodb/public/**/*.spec.js'
|
||||
],
|
||||
dest: '.grunt/browserify_modules_tests.js'
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,137 @@
|
||||
var css_files;
|
||||
module.exports = css_files = {
|
||||
cdb: [
|
||||
'<%= editor_assets_dir %>/stylesheets/map/leaflet.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/vendor/cartodb.css'
|
||||
],
|
||||
|
||||
old_common: [
|
||||
'<%= editor_assets_dir %>/stylesheets/old_common/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/old_elements/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/plugins/**/*.css',
|
||||
'!<%= editor_assets_dir %>/stylesheets/old_common/upload.css'
|
||||
],
|
||||
|
||||
old_common_without_core: [
|
||||
'<%= editor_assets_dir %>/stylesheets/old_common/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/old_elements/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/plugins/**/*.css',
|
||||
// Core is replaced by a retrofitted set of styles, to make the old core styles work with new_common/default
|
||||
'!<%= editor_assets_dir %>/stylesheets/old_common/core.css',
|
||||
'!<%= editor_assets_dir %>/stylesheets/old_common/upload.css'
|
||||
],
|
||||
|
||||
common: [
|
||||
'<%= editor_assets_dir %>/stylesheets/old_common/video_player.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/common/utilities.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/common/icon-font-specials.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/common/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/cartoassets/entry.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/client/**/*.css'
|
||||
],
|
||||
|
||||
password_protected: [
|
||||
'<%= editor_assets_dir %>/stylesheets/public/password_protected.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/cartoassets/entry.css'
|
||||
],
|
||||
|
||||
public_dashboard: [
|
||||
'<%= editor_assets_dir %>/stylesheets/public_dashboard/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public_map/public_map_buttons.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public_map/public_map_footer.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/cartoassets/entry.css'
|
||||
],
|
||||
|
||||
public_table: [
|
||||
'<%= editor_assets_dir %>/stylesheets/table/table.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/old_elements/modal.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/old_elements/dialog_small_edit.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/old_elements/dropdown.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public/public_map_wrapper.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public/public_table_wrapper.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public/public_map_data.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public/public_map_body.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public/public_map_info.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public/public_export.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public_table/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public/public_map_fullscreen.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/map/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/cartoassets/entry.css'
|
||||
],
|
||||
|
||||
public_map: [
|
||||
'<%= editor_assets_dir %>/stylesheets/public_map/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/cartoassets/entry.css'
|
||||
],
|
||||
|
||||
embed_map: [
|
||||
'<%= editor_assets_dir %>/stylesheets/embed/**/*.css'
|
||||
],
|
||||
|
||||
explore: [
|
||||
'<%= editor_assets_dir %>/stylesheets/explore/**/*.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public_map/public_map_buttons.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/public_map/public_map_footer.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/cartoassets/entry.css'
|
||||
],
|
||||
|
||||
user_feed: [
|
||||
'<%= editor_assets_dir %>/stylesheets/user_feed/**/*.css'
|
||||
],
|
||||
|
||||
leaflet: [
|
||||
'<%= editor_assets_dir %>/stylesheets/map/leaflet.css'
|
||||
],
|
||||
|
||||
map: [
|
||||
'<%= editor_assets_dir %>/stylesheets/map/**/*.css'
|
||||
],
|
||||
|
||||
cartodb: [
|
||||
'<%= editor_assets_dir %>/stylesheets/vendor/cartodb.css'
|
||||
],
|
||||
|
||||
table: [
|
||||
'<%= editor_assets_dir %>/stylesheets/vendor/codemirror.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/vendor/show-hint.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/vendor/cartodb.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/table/**/*.css'
|
||||
],
|
||||
|
||||
editor: [
|
||||
'<%= editor_assets_dir %>/stylesheets/editor/core_retrofit.css',
|
||||
|
||||
// From table bundle
|
||||
'<%= editor_assets_dir %>/stylesheets/vendor/codemirror.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/vendor/show-hint.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/table/**/*.css',
|
||||
|
||||
// New styles
|
||||
'<%= editor_assets_dir %>/stylesheets/dashboard/delete-items.css',
|
||||
|
||||
// Overrides for older styles, to work as expected with new_common/default
|
||||
'<%= editor_assets_dir %>/stylesheets/editor/**/*.css'
|
||||
],
|
||||
|
||||
front: [
|
||||
'<%= editor_assets_dir %>/stylesheets/front/*.css'
|
||||
],
|
||||
|
||||
deep_insights: [
|
||||
'<%= editor_assets_dir %>/stylesheets/deep-insights/entry.css',
|
||||
'<%= editor_assets_dir %>/stylesheets/cartodbjs_v4/entry.css'
|
||||
],
|
||||
|
||||
api_keys: [
|
||||
'<%= editor_assets_dir %>/stylesheets/api_keys/*.css'
|
||||
]
|
||||
};
|
||||
|
||||
var _all_css = [];
|
||||
|
||||
var all_css = [];
|
||||
for (var f in _all_css) {
|
||||
all_css = all_css.concat(css_files[_all_css[f]]);
|
||||
}
|
||||
|
||||
module.exports.all_css = all_css;
|
||||
@@ -0,0 +1,223 @@
|
||||
var files = {
|
||||
cdb: [
|
||||
'vendor/assets/javascripts/cartodb.uncompressed.js',
|
||||
'vendor/assets/javascripts/cartodb.mod.torque.uncompressed.js',
|
||||
'lib/assets/javascripts/cartodb/config.js',
|
||||
'lib/assets/javascripts/cartodb/app.js',
|
||||
'lib/build/app_config.js'
|
||||
],
|
||||
|
||||
embed: [
|
||||
'vendor/assets/javascripts/cartodb.uncompressed.js',
|
||||
'vendor/assets/javascripts/cartodb.mod.torque.uncompressed.js',
|
||||
'lib/assets/javascripts/cartodb/config.js',
|
||||
'lib/assets/javascripts/cartodb/app.js'
|
||||
],
|
||||
|
||||
app: [
|
||||
'lib/assets/javascripts/cartodb/config.js',
|
||||
'lib/assets/javascripts/cartodb/app.js',
|
||||
'lib/build/app_config.js'
|
||||
],
|
||||
|
||||
models: [
|
||||
'lib/assets/javascripts/cartodb/models/table.js',
|
||||
'lib/assets/javascripts/cartodb/models/tabledata.js',
|
||||
'lib/assets/javascripts/cartodb/models/sqlview.js',
|
||||
'lib/assets/javascripts/cartodb/models/cartodb_layer.js',
|
||||
'lib/assets/javascripts/cartodb/models/map.js',
|
||||
'lib/assets/javascripts/cartodb/models/group.js',
|
||||
'lib/assets/javascripts/cartodb/models/user_groups.js',
|
||||
'lib/assets/javascripts/cartodb/models/organization_groups.js',
|
||||
'lib/assets/javascripts/cartodb/models/user.js',
|
||||
'lib/assets/javascripts/cartodb/models/permissions.js',
|
||||
'lib/assets/javascripts/cartodb/models/group_users.js',
|
||||
'lib/assets/javascripts/cartodb/models/grantable.js',
|
||||
'lib/assets/javascripts/cartodb/models/grantables.js',
|
||||
'lib/assets/javascripts/cartodb/models/organization.js',
|
||||
'lib/assets/javascripts/cartodb/models/carto/*.js',
|
||||
'lib/assets/javascripts/cartodb/models/**/*.js',
|
||||
'lib/assets/javascripts/cartodb/table/overlays/overlays.js'
|
||||
],
|
||||
|
||||
specs: [
|
||||
'lib/assets/test/spec/cartodb/**/*.js',
|
||||
// Test files that use browserify should be added in the tests bundle defined in lib/build/tasks/browserify.js
|
||||
'!lib/assets/test/spec/cartodb/common/**/*.js',
|
||||
'!lib/assets/test/spec/cartodb/public_dashboard/**/*.js',
|
||||
'!lib/assets/test/spec/cartodb/keys/**/*.js',
|
||||
'!lib/assets/test/spec/cartodb/account/*.js',
|
||||
'!lib/assets/test/spec/cartodb/feed/**/*.js',
|
||||
'!lib/assets/test/spec/cartodb/explore/**/*.js',
|
||||
'!lib/assets/test/spec/cartodb/editor/**/*.js',
|
||||
'!lib/assets/test/spec/cartodb/public_map/**/*.spec.js',
|
||||
'!lib/assets/test/spec/cartodb/embed_map/**/*.spec.js',
|
||||
'!lib/assets/test/spec/cartodb/public/**/*.spec.js',
|
||||
'.grunt/browserify_modules_tests.js'
|
||||
],
|
||||
|
||||
_spec_helpers: [
|
||||
'node_modules/jasmine-ajax/lib/mock-ajax.js',
|
||||
'lib/assets/test/lib/sinon-1.3.4.js',
|
||||
'lib/assets/test/spec/SpecHelper.js'
|
||||
],
|
||||
|
||||
_spec_helpers3: [
|
||||
'lib/assets/test/spec/SpecHelper3.js'
|
||||
],
|
||||
|
||||
table: [
|
||||
'vendor/assets/javascripts/codemirror.js',
|
||||
'vendor/assets/javascripts/show-hint.js',
|
||||
'vendor/assets/javascripts/anyword-hint.js',
|
||||
'vendor/assets/javascripts/custom-list-hint.js',
|
||||
'vendor/assets/javascripts/custom-list-with-type-hint.js',
|
||||
'vendor/assets/javascripts/select2.min.js',
|
||||
'vendor/assets/javascripts/jquery.faviconNotify.js',
|
||||
'vendor/assets/javascripts/rgbcolor.js',
|
||||
'vendor/assets/javascripts/crossfilter.js',
|
||||
'vendor/assets/javascripts/jquery-ui/**/*.js',
|
||||
'vendor/assets/javascripts/jquery.caret.js',
|
||||
'vendor/assets/javascripts/moment.js',
|
||||
'vendor/assets/javascripts/ZeroClipboard.js',
|
||||
'vendor/assets/javascripts/tag-it.js',
|
||||
'vendor/assets/javascripts/jquery.tipsy.js',
|
||||
'vendor/assets/javascripts/d3.v2.js',
|
||||
'vendor/assets/javascripts/colorpicker.js',
|
||||
'vendor/assets/javascripts/leaflet.draw.js',
|
||||
'vendor/assets/javascripts/moment.js',
|
||||
'vendor/assets/javascripts/markdown.js',
|
||||
'vendor/assets/javascripts/datepicker.js',
|
||||
'vendor/assets/javascripts/dragster.js',
|
||||
'vendor/assets/javascripts/dropzone.js',
|
||||
'vendor/assets/javascripts/backbone-model-file-upload.js',
|
||||
'vendor/assets/javascripts/html2canvas.js',
|
||||
'lib/assets/javascripts/utils/postgres.codemirror.js',
|
||||
'lib/assets/javascripts/utils/xml.codemirror.js',
|
||||
'lib/assets/javascripts/utils/draggable.js',
|
||||
'lib/assets/javascripts/utils/carto.codemirror.js',
|
||||
'lib/assets/javascripts/utils/color.keywords.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/utils.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/dropdown_menu.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/forms/string_field.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/forms/widgets.js',
|
||||
'lib/assets/javascripts/cartodb/table/overlays/text.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/url.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/dashboard_vis_url.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/**/*.js',
|
||||
'lib/assets/javascripts/cartodb/table/right_menu.js',
|
||||
'lib/assets/javascripts/cartodb/table/default_layers.js',
|
||||
'lib/assets/javascripts/cartodb/table/menu_module.js',
|
||||
'lib/assets/javascripts/cartodb/table/menu_modules/carto_editor.js',
|
||||
'lib/assets/javascripts/cartodb/table/menu_modules/carto_wizard.js',
|
||||
'lib/assets/javascripts/cartodb/table/menu_modules/wizards/torque.js',
|
||||
'lib/assets/javascripts/cartodb/table/**/*.js',
|
||||
'lib/assets/javascripts/cartodb/table/table.js',
|
||||
'lib/assets/javascripts/cartodb/table/views/**/*.js'
|
||||
],
|
||||
|
||||
public_dashboard_deps: [
|
||||
'vendor/assets/javascripts/moment.js',
|
||||
'lib/assets/javascripts/cartodb/public/authenticated_user.js',
|
||||
'lib/assets/javascripts/cartodb/models/cartodb_layer.js',
|
||||
'lib/assets/javascripts/cartodb/models/map.js',
|
||||
'lib/assets/javascripts/cartodb/models/group.js',
|
||||
'lib/assets/javascripts/cartodb/models/user_groups.js',
|
||||
'lib/assets/javascripts/cartodb/models/organization_groups.js',
|
||||
'lib/assets/javascripts/cartodb/models/user.js',
|
||||
'lib/assets/javascripts/cartodb/models/permissions.js',
|
||||
'lib/assets/javascripts/cartodb/models/group_users.js',
|
||||
'lib/assets/javascripts/cartodb/models/grantable.js',
|
||||
'lib/assets/javascripts/cartodb/models/grantables.js',
|
||||
'lib/assets/javascripts/cartodb/models/organization.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/dropdown_menu.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/utils.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/url.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/dashboard_vis_url.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/**/*.js'
|
||||
],
|
||||
|
||||
public_map_deps: [
|
||||
'lib/assets/javascripts/cartodb/public/authenticated_user.js',
|
||||
'lib/assets/javascripts/cartodb/models/cartodb_layer.js',
|
||||
'lib/assets/javascripts/cartodb/models/map.js',
|
||||
'lib/assets/javascripts/cartodb/models/group.js',
|
||||
'lib/assets/javascripts/cartodb/models/user_groups.js',
|
||||
'lib/assets/javascripts/cartodb/models/organization_groups.js',
|
||||
'lib/assets/javascripts/cartodb/models/user.js',
|
||||
'lib/assets/javascripts/cartodb/models/permissions.js',
|
||||
'lib/assets/javascripts/cartodb/models/group_users.js',
|
||||
'lib/assets/javascripts/cartodb/models/grantable.js',
|
||||
'lib/assets/javascripts/cartodb/models/grantables.js',
|
||||
'lib/assets/javascripts/cartodb/models/organization.js',
|
||||
'lib/assets/javascripts/cartodb/models/export_map_model.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/dropdown_menu.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/url.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/dashboard_vis_url.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/**/*.js'
|
||||
],
|
||||
|
||||
user_feed_deps: [
|
||||
'vendor/assets/javascripts/moment.js',
|
||||
'vendor/assets/javascripts/markdown.js',
|
||||
'lib/assets/javascripts/cartodb/public/authenticated_user.js',
|
||||
'lib/assets/javascripts/cartodb/models/cartodb_layer.js',
|
||||
'lib/assets/javascripts/cartodb/models/map.js',
|
||||
'lib/assets/javascripts/cartodb/models/group.js',
|
||||
'lib/assets/javascripts/cartodb/models/user_groups.js',
|
||||
'lib/assets/javascripts/cartodb/models/organization_groups.js',
|
||||
'lib/assets/javascripts/cartodb/models/user.js',
|
||||
'lib/assets/javascripts/cartodb/models/permissions.js',
|
||||
'lib/assets/javascripts/cartodb/models/group_users.js',
|
||||
'lib/assets/javascripts/cartodb/models/grantable.js',
|
||||
'lib/assets/javascripts/cartodb/models/grantables.js',
|
||||
'lib/assets/javascripts/cartodb/models/organization.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/utils.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/dropdown_menu.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/url.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/dashboard_vis_url.js',
|
||||
'lib/assets/javascripts/cartodb/old_common/urls/**/*.js'
|
||||
],
|
||||
|
||||
statsc: [
|
||||
'vendor/assets/javascripts/statsc.min.js'
|
||||
],
|
||||
|
||||
_templates: [
|
||||
'lib/assets/javascripts/cartodb/**/*.jst.ejs'
|
||||
],
|
||||
|
||||
_public_templates: [
|
||||
'lib/assets/javascripts/cartodb/public/**/*.jst.ejs'
|
||||
],
|
||||
|
||||
_public_map_templates: [
|
||||
'lib/assets/javascripts/cartodb/common/**/*.jst.ejs',
|
||||
'lib/assets/javascripts/cartodb/public_map/**/*.jst.ejs'
|
||||
],
|
||||
|
||||
_templates_mustache: [
|
||||
'lib/assets/javascripts/cartodb/**/*.jst.mustache'
|
||||
]
|
||||
};
|
||||
|
||||
// Required by jasmine tests, so we can't
|
||||
// remove it
|
||||
var _all = [
|
||||
'cdb',
|
||||
'embed',
|
||||
'app',
|
||||
'models',
|
||||
'table',
|
||||
'public_dashboard_deps',
|
||||
'user_feed_deps',
|
||||
'statsc'
|
||||
];
|
||||
|
||||
var all = [];
|
||||
for (var f in _all) {
|
||||
all = all.concat(files[_all[f]]);
|
||||
}
|
||||
|
||||
module.exports = files;
|
||||
module.exports.all = all;
|
||||
@@ -0,0 +1,106 @@
|
||||
var files = {
|
||||
dashboard: {
|
||||
page: 'dashboard',
|
||||
stylesheets: [
|
||||
'/stylesheets/common_new.css',
|
||||
'/stylesheets/new_dashboard.css'
|
||||
],
|
||||
scripts: [
|
||||
'/javascripts/common.js',
|
||||
'/javascripts/common_vendor.js',
|
||||
'/javascripts/new_dashboard.js'
|
||||
]
|
||||
},
|
||||
profile: {
|
||||
page: 'profile',
|
||||
stylesheets: [
|
||||
'/stylesheets/common_new.css',
|
||||
'/stylesheets/header.css',
|
||||
'/stylesheets/footer.css'
|
||||
],
|
||||
scripts: [
|
||||
'/javascripts/header.js',
|
||||
'/javascripts/footer.js',
|
||||
'/javascripts/common.js',
|
||||
'/javascripts/common_vendor.js',
|
||||
'/javascripts/profile.js'
|
||||
]
|
||||
},
|
||||
// public_map: {
|
||||
// stylesheets: [
|
||||
// '/stylesheets/cartodb.css',
|
||||
// '/stylesheets/common.css',
|
||||
// '/stylesheets/public_map.css',
|
||||
// '/stylesheets/password_protected.css'
|
||||
// ],
|
||||
// scripts: [
|
||||
// '/javascripts/cdb.js',
|
||||
// '/javascripts/models.js',
|
||||
// '/javascripts/carto_node.js',
|
||||
// '/javascripts/templates_mustache.js',
|
||||
// '/javascripts/public_like.js',
|
||||
// '/javascripts/public_map_templates_static.js',
|
||||
// '/javascripts/public_map_deps_static.js',
|
||||
// '/javascripts/public_map_static.js'
|
||||
// ],
|
||||
// images: [
|
||||
// '/images/layout/carto_logo.svg'
|
||||
// ],
|
||||
// visualization: {
|
||||
// params: {
|
||||
// show_permission: true,
|
||||
// show_liked: true,
|
||||
// show_stats: true,
|
||||
// fetch_user: true,
|
||||
// fetch_related_canonical_visualizations: false
|
||||
// }
|
||||
// },
|
||||
// vendor: {
|
||||
// hubspot_form: true
|
||||
// }
|
||||
// },
|
||||
// embed_map: {
|
||||
// stylesheets: [
|
||||
// '/stylesheets/cartodb.css',
|
||||
// '/stylesheets/embed_map.css',
|
||||
// '/stylesheets/password_protected.css'
|
||||
// ],
|
||||
// scripts: [
|
||||
// '/javascripts/cdb.js',
|
||||
// '/javascripts/models.js',
|
||||
// '/javascripts/carto_node.js',
|
||||
// '/javascripts/public_like.js',
|
||||
// '/javascripts/embed_map_templates_static.js',
|
||||
// '/javascripts/embed_map_static.js'
|
||||
// ],
|
||||
// images: [
|
||||
// '/images/layout/carto_logo.svg'
|
||||
// ],
|
||||
// visualization: {
|
||||
// params: {
|
||||
// show_permission: true,
|
||||
// show_liked: true,
|
||||
// show_stats: true,
|
||||
// fetch_user: true,
|
||||
// fetch_related_canonical_visualizations: false
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
account: {
|
||||
page: 'account',
|
||||
stylesheets: [
|
||||
'/stylesheets/header.css',
|
||||
'/stylesheets/footer.css',
|
||||
'/stylesheets/common_new.css'
|
||||
],
|
||||
scripts: [
|
||||
'/javascripts/header.js',
|
||||
'/javascripts/footer.js',
|
||||
'/javascripts/common.js',
|
||||
'/javascripts/common_vendor.js',
|
||||
'/javascripts/account.js'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = files;
|
||||
@@ -0,0 +1,613 @@
|
||||
/*!
|
||||
* mustache.js - Logic-less {{mustache}} templates with JavaScript
|
||||
* http://github.com/janl/mustache.js
|
||||
*/
|
||||
|
||||
/*global define: false*/
|
||||
|
||||
var Mustache;
|
||||
|
||||
(function (exports) {
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = exports; // CommonJS
|
||||
} else if (typeof define === "function") {
|
||||
define(exports); // AMD
|
||||
} else {
|
||||
Mustache = exports; // <script>
|
||||
}
|
||||
}((function () {
|
||||
var exports = {};
|
||||
|
||||
exports.name = "mustache.js";
|
||||
exports.version = "0.5.2";
|
||||
exports.tags = ["{{", "}}"];
|
||||
|
||||
exports.parse = parse;
|
||||
exports.clearCache = clearCache;
|
||||
exports.compile = compile;
|
||||
exports.compilePartial = compilePartial;
|
||||
exports.render = render;
|
||||
|
||||
exports.Scanner = Scanner;
|
||||
exports.Context = Context;
|
||||
exports.Renderer = Renderer;
|
||||
|
||||
// This is here for backwards compatibility with 0.4.x.
|
||||
exports.to_html = function (template, view, partials, send) {
|
||||
var result = render(template, view, partials);
|
||||
|
||||
if (typeof send === "function") {
|
||||
send(result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
var whiteRe = /\s*/;
|
||||
var spaceRe = /\s+/;
|
||||
var nonSpaceRe = /\S/;
|
||||
var eqRe = /\s*=/;
|
||||
var curlyRe = /\s*\}/;
|
||||
var tagRe = /#|\^|\/|>|\{|&|=|!/;
|
||||
|
||||
// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
|
||||
// See https://github.com/janl/mustache.js/issues/189
|
||||
function testRe(re, string) {
|
||||
return RegExp.prototype.test.call(re, string);
|
||||
}
|
||||
|
||||
function isWhitespace(string) {
|
||||
return !testRe(nonSpaceRe, string);
|
||||
}
|
||||
|
||||
var isArray = Array.isArray || function (obj) {
|
||||
return Object.prototype.toString.call(obj) === "[object Array]";
|
||||
};
|
||||
|
||||
// OSWASP Guidelines: escape all non alphanumeric characters in ASCII space.
|
||||
var jsCharsRe = /[\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\xFF\u2028\u2029]/gm;
|
||||
|
||||
function quote(text) {
|
||||
var escaped = text.replace(jsCharsRe, function (c) {
|
||||
return "\\u" + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
|
||||
});
|
||||
|
||||
return '"' + escaped + '"';
|
||||
}
|
||||
|
||||
function escapeRe(string) {
|
||||
return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
|
||||
}
|
||||
|
||||
var entityMap = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
"/": '/'
|
||||
};
|
||||
|
||||
function escapeHtml(string) {
|
||||
return String(string).replace(/[&<>"'\/]/g, function (s) {
|
||||
return entityMap[s];
|
||||
});
|
||||
}
|
||||
|
||||
// Export these utility functions.
|
||||
exports.isWhitespace = isWhitespace;
|
||||
exports.isArray = isArray;
|
||||
exports.quote = quote;
|
||||
exports.escapeRe = escapeRe;
|
||||
exports.escapeHtml = escapeHtml;
|
||||
|
||||
function Scanner(string) {
|
||||
this.string = string;
|
||||
this.tail = string;
|
||||
this.pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the tail is empty (end of string).
|
||||
*/
|
||||
Scanner.prototype.eos = function () {
|
||||
return this.tail === "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Tries to match the given regular expression at the current position.
|
||||
* Returns the matched text if it can match, the empty string otherwise.
|
||||
*/
|
||||
Scanner.prototype.scan = function (re) {
|
||||
var match = this.tail.match(re);
|
||||
|
||||
if (match && match.index === 0) {
|
||||
this.tail = this.tail.substring(match[0].length);
|
||||
this.pos += match[0].length;
|
||||
return match[0];
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Skips all text until the given regular expression can be matched. Returns
|
||||
* the skipped string, which is the entire tail if no match can be made.
|
||||
*/
|
||||
Scanner.prototype.scanUntil = function (re) {
|
||||
var match, pos = this.tail.search(re);
|
||||
|
||||
switch (pos) {
|
||||
case -1:
|
||||
match = this.tail;
|
||||
this.pos += this.tail.length;
|
||||
this.tail = "";
|
||||
break;
|
||||
case 0:
|
||||
match = "";
|
||||
break;
|
||||
default:
|
||||
match = this.tail.substring(0, pos);
|
||||
this.tail = this.tail.substring(pos);
|
||||
this.pos += pos;
|
||||
}
|
||||
|
||||
return match;
|
||||
};
|
||||
|
||||
function Context(view, parent) {
|
||||
this.view = view;
|
||||
this.parent = parent;
|
||||
this.clearCache();
|
||||
}
|
||||
|
||||
Context.make = function (view) {
|
||||
return (view instanceof Context) ? view : new Context(view);
|
||||
};
|
||||
|
||||
Context.prototype.clearCache = function () {
|
||||
this._cache = {};
|
||||
};
|
||||
|
||||
Context.prototype.push = function (view) {
|
||||
return new Context(view, this);
|
||||
};
|
||||
|
||||
Context.prototype.lookup = function (name) {
|
||||
var value = this._cache[name];
|
||||
|
||||
if (!value) {
|
||||
if (name === ".") {
|
||||
value = this.view;
|
||||
} else {
|
||||
var context = this;
|
||||
|
||||
while (context) {
|
||||
if (name.indexOf(".") > 0) {
|
||||
var names = name.split("."), i = 0;
|
||||
|
||||
value = context.view;
|
||||
|
||||
while (value && i < names.length) {
|
||||
value = value[names[i++]];
|
||||
}
|
||||
} else {
|
||||
value = context.view[name];
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
context = context.parent;
|
||||
}
|
||||
}
|
||||
|
||||
this._cache[name] = value;
|
||||
}
|
||||
|
||||
if (typeof value === "function") {
|
||||
value = value.call(this.view);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
function Renderer() {
|
||||
this.clearCache();
|
||||
}
|
||||
|
||||
Renderer.prototype.clearCache = function () {
|
||||
this._cache = {};
|
||||
this._partialCache = {};
|
||||
};
|
||||
|
||||
Renderer.prototype.compile = function (tokens, tags) {
|
||||
if (typeof tokens === "string") {
|
||||
tokens = parse(tokens, tags);
|
||||
}
|
||||
|
||||
var fn = compileTokens(tokens),
|
||||
self = this;
|
||||
|
||||
return function (view) {
|
||||
return fn(Context.make(view), self);
|
||||
};
|
||||
};
|
||||
|
||||
Renderer.prototype.compilePartial = function (name, tokens, tags) {
|
||||
this._partialCache[name] = this.compile(tokens, tags);
|
||||
return this._partialCache[name];
|
||||
};
|
||||
|
||||
Renderer.prototype.render = function (template, view) {
|
||||
var fn = this._cache[template];
|
||||
|
||||
if (!fn) {
|
||||
fn = this.compile(template);
|
||||
this._cache[template] = fn;
|
||||
}
|
||||
|
||||
return fn(view);
|
||||
};
|
||||
|
||||
Renderer.prototype._section = function (name, context, callback) {
|
||||
var value = context.lookup(name);
|
||||
|
||||
switch (typeof value) {
|
||||
case "object":
|
||||
if (isArray(value)) {
|
||||
var buffer = "";
|
||||
|
||||
for (var i = 0, len = value.length; i < len; ++i) {
|
||||
buffer += callback(context.push(value[i]), this);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return value ? callback(context.push(value), this) : "";
|
||||
case "function":
|
||||
// TODO: The text should be passed to the callback plain, not rendered.
|
||||
var sectionText = callback(context, this),
|
||||
self = this;
|
||||
|
||||
var scopedRender = function (template) {
|
||||
return self.render(template, context);
|
||||
};
|
||||
|
||||
return value.call(context.view, sectionText, scopedRender) || "";
|
||||
default:
|
||||
if (value) {
|
||||
return callback(context, this);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
Renderer.prototype._inverted = function (name, context, callback) {
|
||||
var value = context.lookup(name);
|
||||
|
||||
// From the spec: inverted sections may render text once based on the
|
||||
// inverse value of the key. That is, they will be rendered if the key
|
||||
// doesn't exist, is false, or is an empty list.
|
||||
if (value == null || value === false || (isArray(value) && value.length === 0)) {
|
||||
return callback(context, this);
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
Renderer.prototype._partial = function (name, context) {
|
||||
var fn = this._partialCache[name];
|
||||
|
||||
if (fn) {
|
||||
return fn(context);
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
Renderer.prototype._name = function (name, context, escape) {
|
||||
var value = context.lookup(name);
|
||||
|
||||
if (typeof value === "function") {
|
||||
value = value.call(context.view);
|
||||
}
|
||||
|
||||
var string = (value == null) ? "" : String(value);
|
||||
|
||||
if (escape) {
|
||||
return escapeHtml(string);
|
||||
}
|
||||
|
||||
return string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Low-level function that compiles the given `tokens` into a
|
||||
* function that accepts two arguments: a Context and a
|
||||
* Renderer. Returns the body of the function as a string if
|
||||
* `returnBody` is true.
|
||||
*/
|
||||
function compileTokens(tokens, returnBody) {
|
||||
var body = ['""'];
|
||||
var token, method, escape;
|
||||
|
||||
for (var i = 0, len = tokens.length; i < len; ++i) {
|
||||
token = tokens[i];
|
||||
|
||||
switch (token.type) {
|
||||
case "#":
|
||||
case "^":
|
||||
method = (token.type === "#") ? "_section" : "_inverted";
|
||||
body.push("r." + method + "(" + quote(token.value) + ", c, function (c, r) {\n" +
|
||||
" " + compileTokens(token.tokens, true) + "\n" +
|
||||
"})");
|
||||
break;
|
||||
case "{":
|
||||
case "&":
|
||||
case "name":
|
||||
escape = token.type === "name" ? "true" : "false";
|
||||
body.push("r._name(" + quote(token.value) + ", c, " + escape + ")");
|
||||
break;
|
||||
case ">":
|
||||
body.push("r._partial(" + quote(token.value) + ", c)");
|
||||
break;
|
||||
case "text":
|
||||
body.push(quote(token.value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to a string body.
|
||||
body = "return " + body.join(" + ") + ";";
|
||||
|
||||
// Good for debugging.
|
||||
// console.log(body);
|
||||
|
||||
if (returnBody) {
|
||||
return body;
|
||||
}
|
||||
|
||||
// For great evil!
|
||||
return new Function("c, r", body);
|
||||
}
|
||||
|
||||
function escapeTags(tags) {
|
||||
if (tags.length === 2) {
|
||||
return [
|
||||
new RegExp(escapeRe(tags[0]) + "\\s*"),
|
||||
new RegExp("\\s*" + escapeRe(tags[1]))
|
||||
];
|
||||
}
|
||||
|
||||
throw new Error("Invalid tags: " + tags.join(" "));
|
||||
}
|
||||
|
||||
/**
|
||||
* Forms the given linear array of `tokens` into a nested tree structure
|
||||
* where tokens that represent a section have a "tokens" array property
|
||||
* that contains all tokens that are in that section.
|
||||
*/
|
||||
function nestTokens(tokens) {
|
||||
var tree = [];
|
||||
var collector = tree;
|
||||
var sections = [];
|
||||
var token, section;
|
||||
|
||||
for (var i = 0; i < tokens.length; ++i) {
|
||||
token = tokens[i];
|
||||
|
||||
switch (token.type) {
|
||||
case "#":
|
||||
case "^":
|
||||
token.tokens = [];
|
||||
sections.push(token);
|
||||
collector.push(token);
|
||||
collector = token.tokens;
|
||||
break;
|
||||
case "/":
|
||||
if (sections.length === 0) {
|
||||
throw new Error("Unopened section: " + token.value);
|
||||
}
|
||||
|
||||
section = sections.pop();
|
||||
|
||||
if (section.value !== token.value) {
|
||||
throw new Error("Unclosed section: " + section.value);
|
||||
}
|
||||
|
||||
if (sections.length > 0) {
|
||||
collector = sections[sections.length - 1].tokens;
|
||||
} else {
|
||||
collector = tree;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
collector.push(token);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure there were no open sections when we're done.
|
||||
section = sections.pop();
|
||||
|
||||
if (section) {
|
||||
throw new Error("Unclosed section: " + section.value);
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines the values of consecutive text tokens in the given `tokens` array
|
||||
* to a single token.
|
||||
*/
|
||||
function squashTokens(tokens) {
|
||||
var lastToken;
|
||||
|
||||
for (var i = 0; i < tokens.length; ++i) {
|
||||
var token = tokens[i];
|
||||
|
||||
if (lastToken && lastToken.type === "text" && token.type === "text") {
|
||||
lastToken.value += token.value;
|
||||
tokens.splice(i--, 1); // Remove this token from the array.
|
||||
} else {
|
||||
lastToken = token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks up the given `template` string into a tree of token objects. If
|
||||
* `tags` is given here it must be an array with two string values: the
|
||||
* opening and closing tags used in the template (e.g. ["<%", "%>"]). Of
|
||||
* course, the default is to use mustaches (i.e. Mustache.tags).
|
||||
*/
|
||||
function parse(template, tags) {
|
||||
tags = tags || exports.tags;
|
||||
|
||||
var tagRes = escapeTags(tags);
|
||||
var scanner = new Scanner(template);
|
||||
|
||||
var tokens = [], // Buffer to hold the tokens
|
||||
spaces = [], // Indices of whitespace tokens on the current line
|
||||
hasTag = false, // Is there a {{tag}} on the current line?
|
||||
nonSpace = false; // Is there a non-space char on the current line?
|
||||
|
||||
// Strips all whitespace tokens array for the current line
|
||||
// if there was a {{#tag}} on it and otherwise only space.
|
||||
var stripSpace = function () {
|
||||
if (hasTag && !nonSpace) {
|
||||
while (spaces.length) {
|
||||
tokens.splice(spaces.pop(), 1);
|
||||
}
|
||||
} else {
|
||||
spaces = [];
|
||||
}
|
||||
|
||||
hasTag = false;
|
||||
nonSpace = false;
|
||||
};
|
||||
|
||||
var type, value, chr;
|
||||
|
||||
while (!scanner.eos()) {
|
||||
value = scanner.scanUntil(tagRes[0]);
|
||||
|
||||
if (value) {
|
||||
for (var i = 0, len = value.length; i < len; ++i) {
|
||||
chr = value.charAt(i);
|
||||
|
||||
if (isWhitespace(chr)) {
|
||||
spaces.push(tokens.length);
|
||||
} else {
|
||||
nonSpace = true;
|
||||
}
|
||||
|
||||
tokens.push({type: "text", value: chr});
|
||||
|
||||
if (chr === "\n") {
|
||||
stripSpace(); // Check for whitespace on the current line.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Match the opening tag.
|
||||
if (!scanner.scan(tagRes[0])) {
|
||||
break;
|
||||
}
|
||||
|
||||
hasTag = true;
|
||||
type = scanner.scan(tagRe) || "name";
|
||||
|
||||
// Skip any whitespace between tag and value.
|
||||
scanner.scan(whiteRe);
|
||||
|
||||
// Extract the tag value.
|
||||
if (type === "=") {
|
||||
value = scanner.scanUntil(eqRe);
|
||||
scanner.scan(eqRe);
|
||||
scanner.scanUntil(tagRes[1]);
|
||||
} else if (type === "{") {
|
||||
var closeRe = new RegExp("\\s*" + escapeRe("}" + tags[1]));
|
||||
value = scanner.scanUntil(closeRe);
|
||||
scanner.scan(curlyRe);
|
||||
scanner.scanUntil(tagRes[1]);
|
||||
} else {
|
||||
value = scanner.scanUntil(tagRes[1]);
|
||||
}
|
||||
|
||||
// Match the closing tag.
|
||||
if (!scanner.scan(tagRes[1])) {
|
||||
throw new Error("Unclosed tag at " + scanner.pos);
|
||||
}
|
||||
|
||||
tokens.push({type: type, value: value});
|
||||
|
||||
if (type === "name" || type === "{" || type === "&") {
|
||||
nonSpace = true;
|
||||
}
|
||||
|
||||
// Set the tags for the next time around.
|
||||
if (type === "=") {
|
||||
tags = value.split(spaceRe);
|
||||
tagRes = escapeTags(tags);
|
||||
}
|
||||
}
|
||||
|
||||
squashTokens(tokens);
|
||||
|
||||
return nestTokens(tokens);
|
||||
}
|
||||
|
||||
// The high-level clearCache, compile, compilePartial, and render functions
|
||||
// use this default renderer.
|
||||
var _renderer = new Renderer();
|
||||
|
||||
/**
|
||||
* Clears all cached templates and partials.
|
||||
*/
|
||||
function clearCache() {
|
||||
_renderer.clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* High-level API for compiling the given `tokens` down to a reusable
|
||||
* function. If `tokens` is a string it will be parsed using the given `tags`
|
||||
* before it is compiled.
|
||||
*/
|
||||
function compile(tokens, tags) {
|
||||
return _renderer.compile(tokens, tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* High-level API for compiling the `tokens` for the partial with the given
|
||||
* `name` down to a reusable function. If `tokens` is a string it will be
|
||||
* parsed using the given `tags` before it is compiled.
|
||||
*/
|
||||
function compilePartial(name, tokens, tags) {
|
||||
return _renderer.compilePartial(name, tokens, tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* High-level API for rendering the `template` using the given `view`. The
|
||||
* optional `partials` object may be given here for convenience, but note that
|
||||
* it will cause all partials to be re-compiled, thus hurting performance. Of
|
||||
* course, this only matters if you're going to render the same template more
|
||||
* than once. If so, it is best to call `compilePartial` before calling this
|
||||
* function and to leave the `partials` argument blank.
|
||||
*/
|
||||
function render(template, view, partials) {
|
||||
if (partials) {
|
||||
for (var name in partials) {
|
||||
compilePartial(name, partials[name]);
|
||||
}
|
||||
}
|
||||
|
||||
return _renderer.render(template, view);
|
||||
}
|
||||
|
||||
return exports;
|
||||
}())));
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* See https://github.com/evanw/node-source-map-support#browser-support
|
||||
* This is expected to be included in a browserify-module to give proper stack traces, based on browserify's source maps.
|
||||
*/
|
||||
if (window.location.search.indexOf('disablesourcemaps') === -1) {
|
||||
require('source-map-support').install();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
task: function () {
|
||||
return {
|
||||
tasks: {}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
var bundles = require('../files/browserify_files');
|
||||
|
||||
module.exports = {
|
||||
task: function () {
|
||||
var cfg = {};
|
||||
for (var name in bundles) {
|
||||
var bundle = bundles[name];
|
||||
var options = {
|
||||
transform: [
|
||||
[
|
||||
'stringify', {
|
||||
appliesTo: {
|
||||
includeExtensions: ['.mustache']
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'babelify', {
|
||||
'presets': ['es2015'],
|
||||
'extensions': ['.babel']
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
// enables watchify when grunt is run with a watch task
|
||||
// must be evaluated lazily (using template var) to allow override by setConfig task.
|
||||
watch: '<%= env.browserify_watch %>',
|
||||
|
||||
browserifyOptions: {
|
||||
debug: true,
|
||||
cache: {}
|
||||
}
|
||||
};
|
||||
|
||||
if (bundle.options) {
|
||||
if (bundle.options.transform) {
|
||||
options.transform = options.transform.concat(bundle.options.transform);
|
||||
}
|
||||
if (bundle.options.external) {
|
||||
options.external = bundle.options.external;
|
||||
}
|
||||
if (bundle.options.require) {
|
||||
options.require = bundle.options.require;
|
||||
}
|
||||
if (bundle.options.plugin) {
|
||||
options.plugin = bundle.options.plugin;
|
||||
}
|
||||
if (bundle.options.cache) {
|
||||
options.cache = bundle.options.cache;
|
||||
}
|
||||
}
|
||||
|
||||
cfg[name] = {
|
||||
src: bundle.src,
|
||||
dest: bundle.dest || ('<%= editor_assets_dir %>/javascripts/' + name + '.js'),
|
||||
options: options
|
||||
};
|
||||
}
|
||||
|
||||
return cfg;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Clean task config
|
||||
*/
|
||||
|
||||
exports.task = function () {
|
||||
return {
|
||||
options: {
|
||||
force: true
|
||||
},
|
||||
dist: [
|
||||
'.grunt',
|
||||
'.sass-cache',
|
||||
'tmp/sass',
|
||||
'lib/build/app_config.js',
|
||||
'<%= assets_dir %>',
|
||||
'<%= editor_assets_dir %>'
|
||||
]
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Compass task config
|
||||
*/
|
||||
|
||||
exports.task = function () {
|
||||
return {
|
||||
dist: {
|
||||
options: {
|
||||
importPath: [
|
||||
'tmp/sass/cartoassets'
|
||||
],
|
||||
sassDir: 'tmp/sass/editor',
|
||||
cssDir: '<%= editor_assets_dir %>/stylesheets',
|
||||
fontsDir: '<%= editor_assets_dir %>/fonts',
|
||||
httpFontsPath: '<%= env.http_path_prefix %>/assets/editor/<%= editor_assets_version %>/fonts',
|
||||
|
||||
imagesDir: 'app/assets/images/',
|
||||
generatedImagesDir: '<%= editor_assets_dir %>/images/',
|
||||
httpImagesPath: '<%= env.http_path_prefix %>/assets/editor/<%= editor_assets_version %>/images/',
|
||||
httpGeneratedImagesPath: '<%= env.http_path_prefix %>/assets/editor/<%= editor_assets_version %>/images/',
|
||||
|
||||
environment: 'production',
|
||||
outputStyle: 'compressed',
|
||||
noLineComments: true,
|
||||
force: false,
|
||||
time: true,
|
||||
raw: 'Encoding.default_external = \'utf-8\'\n'
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
exports.task = function () {
|
||||
return {
|
||||
main: {
|
||||
options: {
|
||||
archive: '<%= public_dir %>/static.tar.gz'
|
||||
},
|
||||
files: [
|
||||
{
|
||||
expand: true,
|
||||
cwd: '<%= public_dir %>',
|
||||
dest: '/',
|
||||
src: [
|
||||
'*.html',
|
||||
'crossdomain.xml',
|
||||
'robots.txt',
|
||||
'static/**',
|
||||
'maintenance/**',
|
||||
'favicons/**'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Concat assets generation task
|
||||
*/
|
||||
|
||||
var srcToDestHash = function (files, basePath, fileExt) {
|
||||
var hash = {};
|
||||
for (var f in files) {
|
||||
if (f[0] !== '_') {
|
||||
hash[basePath + f + fileExt] = files[f];
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
};
|
||||
|
||||
exports.task = function () {
|
||||
return {
|
||||
js: {
|
||||
files: srcToDestHash(require('../files/js_files'), '<%= editor_assets_dir %>/javascripts/', '.js')
|
||||
},
|
||||
css: {
|
||||
files: srcToDestHash(require('../files/css_files'), '<%= editor_assets_dir %>/stylesheets/', '.css')
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
const DEFAULT_CONFIG = {
|
||||
livereload: false,
|
||||
hostname: '0.0.0.0', // to be able to access the server not only from localhost
|
||||
base: {
|
||||
path: '.'
|
||||
}
|
||||
};
|
||||
|
||||
function generateConfig (cfg) {
|
||||
return Object.assign({}, DEFAULT_CONFIG, cfg);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
task: function () {
|
||||
return {
|
||||
server: {
|
||||
options: {
|
||||
port: 8089,
|
||||
livereload: false,
|
||||
open: 'http://localhost:8089/editor_specs.html',
|
||||
hostname: '0.0.0.0', // to be able to access the server not only from localhost
|
||||
base: {
|
||||
path: '.'
|
||||
}
|
||||
}
|
||||
},
|
||||
// For Headless chrome tests (grunt test)
|
||||
test: {
|
||||
options: {
|
||||
port: 8088,
|
||||
livereload: false,
|
||||
hostname: '0.0.0.0', // to be able to access the server not only from localhost
|
||||
base: {
|
||||
path: '.'
|
||||
}
|
||||
}
|
||||
},
|
||||
// Watching the specs during development
|
||||
specs_dashboard: {
|
||||
options: generateConfig({
|
||||
port: 8090,
|
||||
open: 'http://localhost:8090/_SpecRunner_dashboard.html'
|
||||
})
|
||||
},
|
||||
|
||||
specs_builder: {
|
||||
options: generateConfig({
|
||||
port: 8088,
|
||||
open: 'http://localhost:8088/_SpecRunner_builder.html'
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* Copy task config
|
||||
*/
|
||||
|
||||
exports.task = function (grunt) {
|
||||
return {
|
||||
vendor: {
|
||||
expand: true,
|
||||
cwd: 'vendor/assets/stylesheets/',
|
||||
src: ['**/*.css'],
|
||||
dest: 'tmp/sass/vendor/',
|
||||
rename: function (dest, src) {
|
||||
return dest + src.replace(/\.css$/, '.scss');
|
||||
},
|
||||
options: {
|
||||
// Change all routes from img to asset version path
|
||||
process: function (content, srcpath) {
|
||||
// return content.replace(/\.\.\/img/gi,"/assets/<%= pkg.version %>/images/themes");
|
||||
var path = grunt.template.process('<%= env.http_path_prefix %>/assets/editor/<%= editor_assets_version %>/images/themes');
|
||||
return content.replace(/\.\.\/img/gi, path);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
app: {
|
||||
files: [{
|
||||
expand: true,
|
||||
dot: true,
|
||||
cwd: 'node_modules/cartoassets/src/fonts',
|
||||
src: '**/*.*',
|
||||
dest: '<%= editor_assets_dir %>/fonts/'
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'node_modules/cartoassets/src/scss/',
|
||||
src: '**/*.scss',
|
||||
dest: 'tmp/sass/cartoassets/'
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'node_modules/bootstrap-colorpicker/dist/css/',
|
||||
src: 'bootstrap-colorpicker.css',
|
||||
dest: 'tmp/sass/colorpicker/bootstrap-colorpicker/',
|
||||
rename: function (dest, src) {
|
||||
return dest + src.replace(/\.css$/, '.scss');
|
||||
}
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'app/assets/stylesheets/deep-insights/themes/scss',
|
||||
src: '**/*.scss',
|
||||
dest: 'tmp/sass/deep-insights/'
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'node_modules/internal-carto.js/themes/scss',
|
||||
src: '**/*.scss',
|
||||
dest: 'tmp/sass/cartodbjs_v4/'
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'lib/assets/javascripts/cdb/themes/css/',
|
||||
src: ['cartodb.css'],
|
||||
dest: '<%= editor_assets_dir %>/stylesheets/tmp/embeds/',
|
||||
rename: function (dest, src) {
|
||||
return dest + src.replace(/\.css$/, '.scss');
|
||||
}
|
||||
}, {
|
||||
// Client stylesheets
|
||||
expand: true,
|
||||
cwd: 'app/assets/client/stylesheets/',
|
||||
src: ['**/*.scss'],
|
||||
dest: 'tmp/sass/client/',
|
||||
rename: function (dest, src) {
|
||||
return dest + src.replace(/\.css.scss$/, '.scss');
|
||||
}
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'app/assets/images/',
|
||||
src: ['**/*'],
|
||||
dest: '<%= editor_assets_dir %>/images/'
|
||||
}, {
|
||||
// Some images should be placed in a unversioned folder
|
||||
expand: true,
|
||||
cwd: 'app/assets/images/',
|
||||
src: ['avatars/*.png', 'alphamarker.png', 'google-maps-basemap-icons/*.jpg', 'carto.png'],
|
||||
dest: '<%= root_assets_dir %>/unversioned/images/'
|
||||
}, {
|
||||
// CARTO.js images
|
||||
expand: true,
|
||||
cwd: 'lib/assets/javascripts/cdb/themes/img/',
|
||||
src: ['**/*'],
|
||||
dest: '<%= editor_assets_dir %>/images/themes/'
|
||||
}, {
|
||||
// Fonts
|
||||
expand: true,
|
||||
cwd: 'app/assets/fonts/',
|
||||
src: ['*.{svg,ttf,eot,woff,woff2}'],
|
||||
dest: '<%= editor_assets_dir %>/fonts/'
|
||||
}, {
|
||||
// Client fonts
|
||||
expand: true,
|
||||
cwd: 'app/assets/client/fonts/',
|
||||
src: ['*.{svg,ttf,eot,woff,woff2}'],
|
||||
dest: '<%= editor_assets_dir %>/fonts/'
|
||||
}, {
|
||||
// Flash
|
||||
expand: true,
|
||||
cwd: 'app/assets/flash/',
|
||||
src: ['**/*'],
|
||||
dest: '<%= editor_assets_dir %>/flash/'
|
||||
}, {
|
||||
// Favicons
|
||||
expand: true,
|
||||
cwd: 'public/favicons/',
|
||||
src: ['**/*'],
|
||||
dest: '<%= editor_assets_dir %>/favicons/'
|
||||
}, {
|
||||
// Client favicons
|
||||
expand: true,
|
||||
cwd: 'app/assets/client/favicons/',
|
||||
src: ['**/*'],
|
||||
dest: '<%= editor_assets_dir %>/favicons/'
|
||||
}]
|
||||
},
|
||||
|
||||
css_cartodb: {
|
||||
files: [{
|
||||
// TODO: remove editor
|
||||
expand: true,
|
||||
cwd: 'app/assets/stylesheets',
|
||||
src: [
|
||||
'**/*.scss',
|
||||
'!editor-3/**/*.scss',
|
||||
'!new_dashboard/**/*.scss'
|
||||
],
|
||||
dest: 'tmp/sass/editor/',
|
||||
rename: function (dest, src) {
|
||||
return dest + src.replace(/\.css.scss$/, '.scss');
|
||||
}
|
||||
}]
|
||||
},
|
||||
|
||||
css_builder: {
|
||||
files: [{
|
||||
// TODO: remove editor
|
||||
expand: true,
|
||||
cwd: 'app/assets/stylesheets/editor-3/',
|
||||
src: ['**/*.scss'],
|
||||
dest: 'tmp/sass/editor-3/'
|
||||
}]
|
||||
},
|
||||
|
||||
css_dashboard: {
|
||||
files: [{
|
||||
// TODO: remove editor
|
||||
expand: true,
|
||||
cwd: 'app/assets/stylesheets/new_dashboard/',
|
||||
src: ['**/*.scss'],
|
||||
dest: 'tmp/sass/new_dashboard/'
|
||||
}]
|
||||
},
|
||||
|
||||
css_vendor_builder: {
|
||||
files: [{
|
||||
expand: true,
|
||||
cwd: 'node_modules/cartoassets/src/scss/',
|
||||
src: '**/*.scss',
|
||||
dest: 'tmp/sass/cartoassets/'
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'app/assets/stylesheets/deep-insights/themes/scss',
|
||||
src: '**/*.scss',
|
||||
dest: 'tmp/sass/deep-insights/'
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'node_modules/internal-carto.js/themes/scss',
|
||||
src: '**/*.scss',
|
||||
dest: 'tmp/sass/cartodbjs_v4/'
|
||||
}]
|
||||
},
|
||||
|
||||
js: {
|
||||
files: [{
|
||||
expand: true,
|
||||
cwd: '<%= editor_assets_dir %>/javascripts/',
|
||||
src: ['**/*.js'],
|
||||
dest: '<%= editor_assets_dir %>/javascripts/',
|
||||
rename: function (dest, src) {
|
||||
return dest + src.replace(/\.js$/, '.uncompressed.js');
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
var browserifyBundles = require('../files/browserify_files');
|
||||
var _ = require('underscore');
|
||||
|
||||
/**
|
||||
* Extracts inlined source map from files (browserify bundles in this case).
|
||||
*
|
||||
* Expected to be run after copy:js task
|
||||
*/
|
||||
exports.task = function () {
|
||||
var excludedBundles = [
|
||||
'test_specs_for_browserify_modules',
|
||||
'dashboard_static',
|
||||
'show_static',
|
||||
'public_map_static'
|
||||
];
|
||||
var files = {};
|
||||
|
||||
for (var bundleName in browserifyBundles) {
|
||||
if (!_.contains(excludedBundles, bundleName)) {
|
||||
var filePath = '<%= editor_assets_dir %>/javascripts/' + bundleName + '.uncompressed.js';
|
||||
files[filePath + '.map'] = filePath;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
bundle: {
|
||||
options: {
|
||||
strict: true // fail task if sourcemaps are missing
|
||||
},
|
||||
files: files
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
var js_files = require('../files/js_files');
|
||||
|
||||
const DEFAULT_CONFIG = {
|
||||
browser: 'phantomjs',
|
||||
headless: true,
|
||||
timeout: 20000,
|
||||
keepRunner: true,
|
||||
// grunt:test (CI) always generates a server on port 8088
|
||||
host: 'http://localhost:8088',
|
||||
summary: true,
|
||||
display: 'none',
|
||||
helpers: js_files._spec_helpers3,
|
||||
reportSlowerThan: 2000,
|
||||
vendor: [
|
||||
'node_modules/jasmine-ajax/lib/mock-ajax.js',
|
||||
'node_modules/underscore/underscore-min.js'
|
||||
]
|
||||
};
|
||||
|
||||
const getJasmineConfig = (config) => (Object.assign({}, DEFAULT_CONFIG, config));
|
||||
|
||||
module.exports = {
|
||||
cartodbui: {
|
||||
src: js_files.all.concat([
|
||||
'lib/build/user_data.js',
|
||||
'<%= editor_assets_dir %>/javascripts/templates_mustache.js',
|
||||
'<%= editor_assets_dir %>/javascripts/templates.js',
|
||||
'lib/build/test_init.js']),
|
||||
options: {
|
||||
browser: 'phantomjs',
|
||||
headless: true,
|
||||
keepRunner: true, // do not delete the runner (added to gitignore anyway), makes sure the runner is up-to-date
|
||||
outfile: '_SpecRunner.html',
|
||||
host: 'http://localhost:8088',
|
||||
summary: true,
|
||||
display: 'none',
|
||||
specs: js_files.specs,
|
||||
helpers: ['http://maps.googleapis.com/maps/api/js?v=3.32&sensor=false'].concat(js_files._spec_helpers)
|
||||
// '--remote-debugger-port': 9000
|
||||
}
|
||||
},
|
||||
|
||||
dashboard: {
|
||||
options: getJasmineConfig({
|
||||
outfile: '_SpecRunner_dashboard.html',
|
||||
specs: [
|
||||
'.grunt/dashboard_specs/vendor.affected-specs.js',
|
||||
'.grunt/dashboard_specs/main.affected-specs.js'
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
builder: {
|
||||
options: getJasmineConfig({
|
||||
outfile: '_SpecRunner_builder.html',
|
||||
specs: [
|
||||
'.grunt/builder_specs/vendor.affected-specs.js',
|
||||
'.grunt/builder_specs/main.affected-specs.js'
|
||||
]
|
||||
})
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
var jsFiles = require('../files/js_files');
|
||||
|
||||
var jsFiles_PATH_REGEX = /^lib\/assets\/javascripts\//;
|
||||
var jsFiles_EXTENSION_REGEX = /\.jst\.ejs$/;
|
||||
var MUSTACHE_EXTENSION_REGEX = /\.jst\.mustache/;
|
||||
|
||||
exports.task = function () {
|
||||
return {
|
||||
compile: {
|
||||
options: {
|
||||
processName: function (filename) {
|
||||
return filename
|
||||
.replace(jsFiles_PATH_REGEX, '')
|
||||
.replace(jsFiles_EXTENSION_REGEX, '');
|
||||
}
|
||||
},
|
||||
files: [
|
||||
{
|
||||
src: jsFiles._templates,
|
||||
dest: '<%= editor_assets_dir %>/javascripts/templates.js'
|
||||
}, {
|
||||
src: jsFiles._public_map_templates,
|
||||
dest: '<%= editor_assets_dir %>/javascripts/public_map_templates.js'
|
||||
}, {
|
||||
src: jsFiles._public_templates,
|
||||
dest: '<%= editor_assets_dir %>/javascripts/public_templates.js'
|
||||
}
|
||||
]
|
||||
},
|
||||
mustache: {
|
||||
options: {
|
||||
processName: function (filename) {
|
||||
return filename
|
||||
.replace(jsFiles_PATH_REGEX, '')
|
||||
.replace(MUSTACHE_EXTENSION_REGEX, '');
|
||||
},
|
||||
template: function (source) {
|
||||
var src = source.replace(/\n/g, '\\n').replace(/'/g, '\\\'');
|
||||
return {
|
||||
source: 'cdb.core.Template.compile(\'' + src + '\', \'mustache\')'
|
||||
};
|
||||
}
|
||||
},
|
||||
files: [
|
||||
{
|
||||
'<%= editor_assets_dir %>/javascripts/templates_mustache.js': jsFiles._templates_mustache
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
function alldeps (mod, deps, name, parentVersion) {
|
||||
name = name || mod.name;
|
||||
return Object.keys(mod.dependencies).reduce(function (all, dependency) {
|
||||
if (!all.hasOwnProperty(dependency)) {
|
||||
all[dependency] = {};
|
||||
}
|
||||
|
||||
var version = mod.dependencies[dependency].version;
|
||||
var resolved = mod.dependencies[dependency].resolved;
|
||||
if (!all[dependency].hasOwnProperty(version)) {
|
||||
all[dependency][resolved] = {};
|
||||
}
|
||||
|
||||
all[dependency][resolved][name] = parentVersion || version;
|
||||
if (mod.dependencies[dependency].dependencies) {
|
||||
alldeps(mod.dependencies[dependency], all, dependency, version);
|
||||
}
|
||||
return all;
|
||||
}, deps || {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks all modules dependencies versions within a package-lock to not be
|
||||
* duplicated from different parent dependencies.
|
||||
*
|
||||
* For instance if there are a couple of dependencies using a different version
|
||||
* of backbone it will return backbone with its parent dependencies.
|
||||
*/
|
||||
function duplicatedDependencies (lockFileContent, modulesToValidate) {
|
||||
var all = alldeps(lockFileContent);
|
||||
|
||||
modulesToValidate = modulesToValidate || Object.keys(all);
|
||||
|
||||
return modulesToValidate.reduce(function (duplicatedMods, mod) {
|
||||
if (all[mod] === undefined) {
|
||||
console.error('!!! ERROR !!!');
|
||||
console.error('Trying to get all dependencies from ', mod, ' but it does not exist.');
|
||||
console.error('!!! ERROR !!!');
|
||||
}
|
||||
var modVersions = Object.keys(all[mod]);
|
||||
if (modVersions.length > 1) {
|
||||
var invalidMod = { name: mod, versions: [] };
|
||||
|
||||
modVersions.forEach(function (modVersion) {
|
||||
invalidMod.versions.push({version: modVersion, from: all[mod][modVersion]});
|
||||
});
|
||||
duplicatedMods.push(invalidMod);
|
||||
}
|
||||
return duplicatedMods;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the version of a package-lock file matches with the version of another lock file.
|
||||
* It is necessary to pass the modules to validate.
|
||||
*
|
||||
* It will return the modules where the version differs.
|
||||
*/
|
||||
function dependenciesVersion (lockFileContentOne, lockFileContentTwo, modulesToValidate) {
|
||||
var allDependenciesOne = alldeps(lockFileContentOne);
|
||||
var allDependenciesTwo = alldeps(lockFileContentTwo);
|
||||
|
||||
return modulesToValidate.reduce(function (depWithDiffVer, mod) {
|
||||
var verDepFromOne = Object.keys(allDependenciesOne[mod])[0];
|
||||
var verDepFromTwo = Object.keys(allDependenciesTwo[mod])[0];
|
||||
|
||||
if (verDepFromOne !== verDepFromTwo) {
|
||||
depWithDiffVer.push(mod);
|
||||
}
|
||||
|
||||
return depWithDiffVer;
|
||||
}, []);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkDuplicatedDependencies: duplicatedDependencies,
|
||||
checkDependenciesVersion: dependenciesVersion
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
module.exports = {
|
||||
task: function () {
|
||||
return {};
|
||||
},
|
||||
|
||||
register: function (grunt, ASSETS_DIR) {
|
||||
grunt.registerTask('manifest', 'creates rails manifest', function () {
|
||||
var assets = grunt.template.process(ASSETS_DIR);
|
||||
var version = grunt.template.process('<%= pkg.version %>');
|
||||
var s = assets + '/**/*';
|
||||
var mapping = grunt.file.expandMapping(s);
|
||||
var manifest = assets.replace(version, '') + '/manifest.yml';
|
||||
var minify_js = grunt.config.get('env').use_minify;
|
||||
|
||||
grunt.file.write(manifest, '---\n' + mapping.filter(function (s) {
|
||||
return !grunt.file.isDir(s.src[0]);
|
||||
}).map(function (s) {
|
||||
function fixResource (p) {
|
||||
return p.replace(assets + '/', '')
|
||||
.replace('javascripts/', '')
|
||||
.replace('stylesheets/', '')
|
||||
.replace('images/', '');
|
||||
}
|
||||
|
||||
function fixPath (p) {
|
||||
p = p.replace(assets, version);
|
||||
if (minify_js) {
|
||||
p = p.replace('.js', '.min.js');
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
return fixResource(s.src[0]) + ': ' + fixPath(s.dest);
|
||||
}).join('\n'));
|
||||
grunt.log.write(manifest + ' generated');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
module.exports = {
|
||||
task: function () {
|
||||
return {
|
||||
options: {
|
||||
accessKeyId: '<%= aws.key%>',
|
||||
secretAccessKey: '<%= aws.secret %>',
|
||||
bucket: '<%= aws.bucket %>'
|
||||
},
|
||||
frozen: {
|
||||
options: {
|
||||
headers: {
|
||||
'CacheControl': 'max-age=630720000, public',
|
||||
'Expires': new Date(Date.now() + 63072000000).toUTCString()
|
||||
},
|
||||
gzip: true
|
||||
},
|
||||
cwd: '<%= editor_assets_dir %>',
|
||||
src: [
|
||||
'javascripts/*.js',
|
||||
'javascripts/**/*.map',
|
||||
'!javascripts/all.js',
|
||||
'stylesheets/*.css',
|
||||
'!stylesheets/all_css.css',
|
||||
'images/**/*',
|
||||
'fonts/*',
|
||||
'flash/*.swf',
|
||||
'favicons/*'
|
||||
],
|
||||
dest: 'cartodbui/assets/editor/<%= editor_assets_version %>/'
|
||||
},
|
||||
js: {
|
||||
options: {
|
||||
headers: {
|
||||
'CacheControl': 'max-age=630720000, public',
|
||||
'Expires': new Date(Date.now() + 63072000000).toUTCString()
|
||||
},
|
||||
gzip: true
|
||||
},
|
||||
cwd: '<%= assets_dir %>',
|
||||
src: [
|
||||
'javascripts/*.js',
|
||||
'javascripts/**/*.map',
|
||||
'!javascripts/all.js'
|
||||
],
|
||||
dest: 'cartodbui/assets/<%= pkg.version %>/'
|
||||
},
|
||||
css: {
|
||||
options: {
|
||||
headers: {
|
||||
'CacheControl': 'max-age=630720000, public',
|
||||
'Expires': new Date(Date.now() + 63072000000).toUTCString()
|
||||
},
|
||||
gzip: true
|
||||
},
|
||||
cwd: '<%= assets_dir %>',
|
||||
src: [
|
||||
'stylesheets/*.css',
|
||||
'!stylesheets/all_css.css'
|
||||
],
|
||||
dest: 'cartodbui/assets/<%= pkg.version %>/'
|
||||
},
|
||||
images: {
|
||||
options: {
|
||||
headers: {
|
||||
'CacheControl': 'max-age=630720000, public',
|
||||
'Expires': new Date(Date.now() + 63072000000).toUTCString()
|
||||
}
|
||||
},
|
||||
cwd: '<%= assets_dir %>',
|
||||
src: 'images/**/*',
|
||||
dest: 'cartodbui/assets/<%= pkg.version %>/'
|
||||
},
|
||||
|
||||
fonts: {
|
||||
options: {
|
||||
headers: {
|
||||
'CacheControl': 'max-age=630720000, public',
|
||||
'Expires': new Date(Date.now() + 63072000000).toUTCString()
|
||||
}
|
||||
},
|
||||
cwd: '<%= assets_dir %>',
|
||||
src: 'fonts/*',
|
||||
dest: 'cartodbui/assets/<%= pkg.version %>/'
|
||||
},
|
||||
|
||||
flash: {
|
||||
options: {
|
||||
headers: {
|
||||
'CacheControl': 'max-age=630720000, public',
|
||||
'Expires': new Date(Date.now() + 63072000000).toUTCString()
|
||||
}
|
||||
},
|
||||
cwd: '<%= assets_dir %>',
|
||||
src: 'flash/*.swf',
|
||||
dest: 'cartodbui/assets/<%= pkg.version %>/'
|
||||
},
|
||||
|
||||
favicons: {
|
||||
options: {
|
||||
headers: {
|
||||
'CacheControl': 'max-age=630720000, public',
|
||||
'Expires': new Date(Date.now() + 63072000000).toUTCString()
|
||||
}
|
||||
},
|
||||
cwd: '<%= assets_dir %>',
|
||||
src: 'favicons/*',
|
||||
dest: 'cartodbui/assets/<%= pkg.version %>/'
|
||||
},
|
||||
|
||||
unversioned: {
|
||||
options: {
|
||||
headers: {
|
||||
'CacheControl': 'max-age=864000, public',
|
||||
'Expires': new Date(Date.now() + 86400000).toUTCString()
|
||||
}
|
||||
},
|
||||
cwd: '<%= assets_dir %>',
|
||||
src: ['images/avatars/*.png', 'images/alphamarker.png', 'images/google-maps-basemap-icons/*.jpg', 'images/carto.png'],
|
||||
dest: 'cartodbui/assets/unversioned/'
|
||||
},
|
||||
|
||||
unversioned_onboarding: {
|
||||
options: {
|
||||
headers: {
|
||||
'ContentType': 'application/octet-stream',
|
||||
'CacheControl': 'max-age=864000, public',
|
||||
'Expires': new Date(Date.now() + 86400000).toUTCString()
|
||||
}
|
||||
},
|
||||
cwd: '<%= root_assets_dir %>',
|
||||
src: ['unversioned/onboarding/*'],
|
||||
dest: 'cartodbui/assets/'
|
||||
},
|
||||
|
||||
static_pages: {
|
||||
cwd: '<%= public_dir %>',
|
||||
src: ['static.tar.gz'],
|
||||
dest: 'cartodbui/'
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Compass task config
|
||||
*/
|
||||
|
||||
exports.task = function () {
|
||||
return {
|
||||
options: {
|
||||
sourceMap: true,
|
||||
sourceMapEmbed: true,
|
||||
sourceMapContents: true,
|
||||
includePaths: [
|
||||
'node_modules/cartoassets/src/scss'
|
||||
]
|
||||
},
|
||||
dist: {
|
||||
files: [{
|
||||
expand: true,
|
||||
cwd: 'tmp/sass/',
|
||||
src: [
|
||||
'**/*.scss',
|
||||
'!editor/**/*'
|
||||
],
|
||||
dest: '<%= editor_assets_dir %>/stylesheets',
|
||||
ext: '.css'
|
||||
}]
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
var jsBundles = require('../files/js_files');
|
||||
var browserifyBundles = require('../files/browserify_files');
|
||||
var _ = require('underscore');
|
||||
|
||||
exports.task = function () {
|
||||
var js = {};
|
||||
var bundleName;
|
||||
var excludedBundles = [
|
||||
'test_specs_for_browserify_modules',
|
||||
'dashboard_static',
|
||||
'profile_static',
|
||||
'show_static',
|
||||
'public_map_static',
|
||||
'embed_map_static',
|
||||
'account_static'
|
||||
];
|
||||
|
||||
// Files to be uglified that are created outside of this process
|
||||
var files = [
|
||||
'templates',
|
||||
'templates_mustache'
|
||||
];
|
||||
|
||||
for (var i in files) {
|
||||
var f = files[i];
|
||||
|
||||
if (f[0] !== '_' && f !== 'all') {
|
||||
js['<%= editor_assets_dir %>/javascripts/' + f + '.js'] = ['<%= editor_assets_dir %>/javascripts/' + f + '.uncompressed.js'];
|
||||
}
|
||||
}
|
||||
|
||||
// Bundle definitions, concat'ed and uglified in one go
|
||||
for (bundleName in jsBundles) {
|
||||
var src = jsBundles[bundleName];
|
||||
if (bundleName[0] !== '_' && bundleName !== 'all') {
|
||||
js['<%= editor_assets_dir %>/javascripts/' + bundleName + '.js'] = src;
|
||||
}
|
||||
}
|
||||
|
||||
var defaultOptions = {
|
||||
sourceMap: true,
|
||||
banner: '/*! v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> */'
|
||||
};
|
||||
|
||||
var cfg = {
|
||||
production: {
|
||||
options: _.extend({
|
||||
sourceMapIncludeSources: true
|
||||
}, defaultOptions),
|
||||
files: js
|
||||
}
|
||||
};
|
||||
|
||||
// Uglify browserify bundles too, but maintain original sourcemaps (expected to be extracted by 'exorcise' task, prior to this task)
|
||||
for (bundleName in browserifyBundles) {
|
||||
if (!_.contains(excludedBundles, bundleName)) {
|
||||
files = {};
|
||||
var basePath = '<%= editor_assets_dir %>/javascripts/' + bundleName;
|
||||
var filePath = basePath + '.uncompressed.js';
|
||||
files[basePath + '.js'] = [filePath];
|
||||
|
||||
cfg[bundleName] = {
|
||||
options: _.extend({
|
||||
sourceMapIn: filePath + '.map'
|
||||
}, defaultOptions),
|
||||
files: files
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return cfg;
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Watch/listen for assets
|
||||
*/
|
||||
|
||||
exports.task = function () {
|
||||
return {
|
||||
css: {
|
||||
files: [
|
||||
'app/assets/stylesheets/editor-3/**/*.scss',
|
||||
'app/assets/stylesheets/deep-insights/**/*.scss',
|
||||
'app/assets/stylesheets/new_dashboard/**/*.scss',
|
||||
'node_modules/cartoassets/src/scss/**/*.scss',
|
||||
'node_modules/internal-carto.js/themes/scss/**/*.scss'
|
||||
],
|
||||
tasks: [
|
||||
'copy:css_vendor_builder',
|
||||
'copy:css_builder',
|
||||
'copy:css_dashboard',
|
||||
'sass',
|
||||
'concat:css'
|
||||
],
|
||||
options: {
|
||||
spawn: false,
|
||||
atBegin: false
|
||||
}
|
||||
},
|
||||
js_affected: {
|
||||
files: [
|
||||
'lib/assets/javascripts/builder/**/*',
|
||||
'lib/assets/test/spec/builder/**/*',
|
||||
'lib/assets/javascripts/deep-insights/**/*',
|
||||
'lib/assets/test/spec/deep-insights/**/*',
|
||||
'lib/assets/javascripts/locale/*'
|
||||
],
|
||||
tasks: [
|
||||
'generate_builder_specs',
|
||||
'webpack:builder_specs',
|
||||
'jasmine:builder:build'
|
||||
],
|
||||
options: {
|
||||
spawn: false,
|
||||
atBegin: false
|
||||
}
|
||||
},
|
||||
dashboard_specs: {
|
||||
files: [
|
||||
'lib/assets/javascripts/dashboard/**/*',
|
||||
'lib/assets/test/spec/dashboard/**/*',
|
||||
'lib/assets/javascripts/locale/*',
|
||||
'lib/assets/test/spec/fixtures/**/*'
|
||||
],
|
||||
tasks: [
|
||||
'generate_dashboard_specs',
|
||||
'webpack:dashboard_specs',
|
||||
'jasmine:dashboard:build'
|
||||
],
|
||||
options: {
|
||||
spawn: false,
|
||||
atBegin: false
|
||||
}
|
||||
},
|
||||
js_affected_editor: {
|
||||
files: [
|
||||
'lib/assets/javascripts/cartodb/**/*',
|
||||
'lib/assets/test/spec/cartodb/**/*'
|
||||
],
|
||||
tasks: [
|
||||
'concat:js',
|
||||
'jst',
|
||||
'jasmine:cartodbui:build'
|
||||
],
|
||||
options: {
|
||||
spawn: false,
|
||||
atBegin: false
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
|
||||
/*
|
||||
This function will be called with the config name (dashboard_specs, builder_spec) so
|
||||
you have a change to customize webpack for each bundle.
|
||||
*/
|
||||
module.exports = {
|
||||
task: function (config) {
|
||||
return {
|
||||
mode: 'development',
|
||||
entry: {
|
||||
main: [
|
||||
// To be filled by grunt
|
||||
]
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(path.resolve('.'), '.grunt', config),
|
||||
filename: '[name].affected-specs.js'
|
||||
},
|
||||
resolve: {
|
||||
symlinks: false,
|
||||
modules: require('../../../../webpack/common/modules.js'),
|
||||
alias: require('../../../../webpack/common/alias')
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'shim-loader',
|
||||
query: {
|
||||
shim: {
|
||||
'html-css-sanitizer': {
|
||||
exports: 'html'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
include: [
|
||||
path.resolve(path.resolve('.'), 'lib/assets/javascripts/carto-node'),
|
||||
path.resolve(path.resolve('.'), 'lib/assets/test/spec/carto-node'),
|
||||
path.resolve(path.resolve('.'), 'lib/assets/javascripts/dashboard'),
|
||||
path.resolve(path.resolve('.'), 'lib/assets/javascripts/builder'),
|
||||
path.resolve(path.resolve('.'), 'lib/assets/test/spec/dashboard'),
|
||||
path.resolve(path.resolve('.'), 'lib/assets/test/spec/fixtures'),
|
||||
path.resolve(path.resolve('.'), 'lib/assets/test/spec/builder'),
|
||||
path.resolve(path.resolve('.'), 'node_modules/internal-carto.js')
|
||||
],
|
||||
options: {
|
||||
presets: [
|
||||
['es2015', { 'modules': false }]
|
||||
],
|
||||
plugins: ['transform-object-assign', 'transform-object-rest-spread']
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.tpl$/,
|
||||
use: 'tpl-loader'
|
||||
},
|
||||
{
|
||||
test: /\.mustache$/,
|
||||
use: 'raw-loader'
|
||||
}
|
||||
],
|
||||
exprContextRegExp: /$^/,
|
||||
exprContextCritical: false
|
||||
},
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
vendor: {
|
||||
name: 'vendor',
|
||||
chunks: 'all',
|
||||
test: /[\\/]node_modules[\\/]/
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
$: 'jquery',
|
||||
jQuery: 'jquery',
|
||||
L: 'leaflet',
|
||||
'window.jQuery': 'jquery'
|
||||
}),
|
||||
new webpack.SourceMapDevToolPlugin({
|
||||
filename: '[file].map',
|
||||
exclude: /vendor/
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
__ENV__: JSON.stringify('test')
|
||||
})
|
||||
],
|
||||
target: 'web',
|
||||
node: {
|
||||
fs: 'empty'
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,145 @@
|
||||
var webpack = require('webpack');
|
||||
var _ = require('underscore');
|
||||
var colors = require('colors');
|
||||
var pretty = require('prettysize');
|
||||
var glob = require('glob');
|
||||
var StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin;
|
||||
var configGenerator = require('./webpack.config.js').task;
|
||||
|
||||
var compiler = {};
|
||||
var affectedSpecs = [];
|
||||
var cache = {};
|
||||
var paths = {
|
||||
builder_specs: './lib/assets/test/spec/builder/**/*.spec.js',
|
||||
dashboard_specs: './lib/assets/test/spec/dashboard/**/*.spec.js',
|
||||
deep_insights_specs: './lib/assets/test/spec/deep-insights/**/*.spec.js'
|
||||
};
|
||||
|
||||
// Filter a list of files with a string
|
||||
// the string will be converted to a RegExp
|
||||
function filterSpecs (affectedSpecs, match) {
|
||||
const re = new RegExp(match);
|
||||
return affectedSpecs.filter(specFile => {
|
||||
const fileName = specFile.split(/spec\//)[1];
|
||||
return re.test(fileName);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* affected - To be used as part of a 'registerTask' Grunt definition
|
||||
*/
|
||||
var affected = function (option, grunt) {
|
||||
var done = this.async();
|
||||
|
||||
affectedSpecs = [
|
||||
'./lib/assets/javascripts/builder/components/form-components/index.js',
|
||||
'./lib/assets/test/spec/builder/components/modals/add-analysis/analysis-options.spec.js',
|
||||
'./lib/assets/test/spec/builder/routes/router.spec.js'
|
||||
];
|
||||
|
||||
let allSpecs = glob.sync(paths.builder_specs).concat(glob.sync(paths.deep_insights_specs));
|
||||
const match = grunt.option('match');
|
||||
|
||||
if (match) {
|
||||
allSpecs = filterSpecs(allSpecs, match);
|
||||
}
|
||||
|
||||
console.log(colors.yellow('All specs. ' + allSpecs.length + ' specs found.'));
|
||||
|
||||
affectedSpecs = affectedSpecs.concat(allSpecs);
|
||||
affectedSpecs = _.uniq(affectedSpecs);
|
||||
|
||||
done();
|
||||
};
|
||||
|
||||
/**
|
||||
* dashboard - To be used as part of a 'registerTask' Grunt definition
|
||||
*/
|
||||
var dashboard = function (option, grunt) {
|
||||
affectedSpecs = glob.sync(paths.dashboard_specs);
|
||||
const match = grunt.option('match');
|
||||
|
||||
if (match) {
|
||||
affectedSpecs = filterSpecs(affectedSpecs, match);
|
||||
}
|
||||
|
||||
affectedSpecs = _.uniq(affectedSpecs);
|
||||
|
||||
console.log(colors.yellow('All specs. ' + affectedSpecs.length + ' specs found.'));
|
||||
};
|
||||
|
||||
var bootstrap = function (config, grunt) {
|
||||
if (!config) {
|
||||
throw new Error('Please provide subconfiguration key for webpack.');
|
||||
}
|
||||
|
||||
const cfg = configGenerator(config);
|
||||
|
||||
cfg.entry.main = affectedSpecs;
|
||||
|
||||
compiler[config] = webpack(cfg);
|
||||
cache[config] = {};
|
||||
compiler[config].apply(new webpack.CachePlugin(cache[config]));
|
||||
|
||||
// Flag stats === true -> write stats.json
|
||||
if (grunt.option('stats')) {
|
||||
compiler[config].apply(new StatsWriterPlugin({
|
||||
transform: function (data, opts) {
|
||||
var stats = opts.compiler.getStats().toJson({chunkModules: true});
|
||||
return JSON.stringify(stats, null, 2);
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
function logAssets (assets) {
|
||||
_.each(assets, function (asset) {
|
||||
var trace = asset.name;
|
||||
trace += ' ' + pretty(asset.size);
|
||||
console.log(colors.yellow(trace));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* compile - To be used as part of a 'registerTask' Grunt definition
|
||||
*/
|
||||
var compile = function (config) {
|
||||
if (!config) {
|
||||
throw new Error('Please provide subconfiguration key for webpack.');
|
||||
}
|
||||
|
||||
var done = this.async();
|
||||
|
||||
compiler[config].run(function (err, stats) {
|
||||
if (err) {
|
||||
console.error(err.stack || err);
|
||||
if (err.details) {
|
||||
console.error(err.details);
|
||||
}
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
var info = stats.toJson();
|
||||
|
||||
if (stats.hasErrors()) {
|
||||
console.error(colors.red(info.errors));
|
||||
console.error('');
|
||||
console.error('🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥');
|
||||
console.error(colors.red('THERE WAS AN ERROR WHILE BUNDLING!!!'));
|
||||
console.error('🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥');
|
||||
}
|
||||
if (!stats.hasErrors()) {
|
||||
logAssets(info.assets);
|
||||
console.log(colors.yellow('Time: ' + info.time));
|
||||
}
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
affected: affected,
|
||||
dashboard: dashboard,
|
||||
bootstrap: bootstrap,
|
||||
compile: compile
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
var old_init = cdb.init;
|
||||
cdb.init = function() { old_init(); };
|
||||
cdb.templates.namespace = 'cartodb/';
|
||||
|
||||
cdb.config.set({
|
||||
sql_api_port: 80,
|
||||
sql_api_domain: 'carto.com',
|
||||
sql_api_endpoint: '/api/v1/sql'
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
import sys
|
||||
import os.path
|
||||
|
||||
if (len(sys.argv) != 4):
|
||||
print "rails2grunt type rails_file grunt.json"
|
||||
sys.exit()
|
||||
|
||||
file_type = sys.argv[1]
|
||||
rails_file = sys.argv[2];
|
||||
rails_path = os.path.abspath(rails_file)
|
||||
name = os.path.basename(rails_file).split('.')[0]
|
||||
|
||||
def normalize(f):
|
||||
return f \
|
||||
.replace('../../../lib/assets/javascripts/', 'javascripts/') \
|
||||
.replace('../../../vendor/assets/javascripts/', 'javascripts/vendor/')
|
||||
|
||||
lines = []
|
||||
for x in open(rails_file):
|
||||
tk = x.strip().split(' ')
|
||||
if tk[0] == '//=' or tk[0] == '*=':
|
||||
f = tk[2].replace("//=", "").replace("*=", "")
|
||||
if tk[1] == 'require':
|
||||
if '/' not in f:
|
||||
if file_type == 'scss':
|
||||
lines.append("'vendor/assets/stylesheets/" + f + ".css',")
|
||||
else:
|
||||
lines.append("'vendor/assets/javascripts/" + f + ".js',")
|
||||
else:
|
||||
if file_type == 'scss':
|
||||
lines.append("'%s'," % (normalize(f) + ".scss"))
|
||||
else:
|
||||
lines.append("'%s'," % (normalize(f) + ".js"))
|
||||
elif tk[1] == 'require_tree':
|
||||
if file_type == 'scss':
|
||||
lines.append("'%s'," % (normalize(f) + "/**/*.scss"))
|
||||
else:
|
||||
lines.append("'%s'," % (normalize(f) + "/**/*.js"))
|
||||
|
||||
print "%s: [\n%s\n]" % (name, '\n'.join(lines)[:-1])
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
window.user_data = {
|
||||
account_type: '',
|
||||
remaining_byte_quota: 0,
|
||||
twitter: { enabled: true },
|
||||
mailchimp: { enabled: false }
|
||||
}
|
||||
window.upgrade_url = ''
|
||||
window.config = {}
|
||||
window.account_host = ''
|
||||
window.username = ''
|
||||
Reference in New Issue
Block a user