Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
+185
View File
@@ -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);
}
}
+11
View File
@@ -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;
+59
View File
@@ -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;
+131
View File
@@ -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;
+40
View File
@@ -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();
+141
View File
@@ -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;
+55
View File
@@ -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'
}
};
+137
View File
@@ -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;
+223
View File
@@ -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;
+106
View File
@@ -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;
+613
View File
@@ -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 = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': '&quot;',
"'": '&#39;',
"/": '&#x2F;'
};
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;
}())));
+7
View File
@@ -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();
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
task: function () {
return {
tasks: {}
};
}
};
+62
View File
@@ -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;
}
};
+19
View File
@@ -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 %>'
]
};
};
+31
View File
@@ -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'
}
}
};
};
+24
View File
@@ -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/**'
]
}
]
}
};
};
+24
View File
@@ -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')
}
};
};
+54
View File
@@ -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'
})
}
};
}
};
+190
View File
@@ -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');
}
}]
}
};
};
+33
View File
@@ -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
}
};
};
+62
View File
@@ -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'
]
})
}
};
+51
View File
@@ -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
}
]
}
};
};
+78
View File
@@ -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
};
+38
View File
@@ -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');
});
}
};
+142
View File
@@ -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/'
}
};
}
};
+28
View File
@@ -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'
}]
}
};
};
+72
View File
@@ -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;
};
+78
View File
@@ -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
}
}
};
};
+103
View File
@@ -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'
}
};
}
};
+145
View File
@@ -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
};
+10
View File
@@ -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'
});
+43
View File
@@ -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])
+11
View File
@@ -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 = ''