MDL-52127 grunt: be aware of third party paths

1) Parse thirdpartylibs.xml and generate an array of third party
file paths to use in grunt tasks
2) In the lint tasks, we filter third party files from being linted
3) We add a new task to generate ignore files - currently for eslint,
but will be potentially useful for other things in the future
4) Remove .eslintignore from source control

Why have the ability to generate a .eslintignore file? For tooling
integration - by having the eslintignore file people can use other
eslint tools without having to just use grunt (e.g. editor
integrations).
This commit is contained in:
Dan Poltawski
2016-06-14 00:37:29 +01:00
parent be4b3cc6c7
commit 30db70abdc
5 changed files with 83 additions and 15 deletions
-6
View File
@@ -1,6 +0,0 @@
theme/bootstrapbase/amd/src/bootstrap.js
lib/amd/src/mustache.js
lib/amd/src/loglevel.js
lib/editor/atto/yui/src/rangy/
**/yui/src/*/meta/*.js
lib/yui/src/notification/js/shared.js
+1
View File
@@ -36,3 +36,4 @@ composer.phar
/lib/yuilib/*/*/*-coverage.js
atlassian-ide-plugin.xml
/node_modules/
.eslintignore
+69 -8
View File
@@ -27,7 +27,10 @@
module.exports = function(grunt) {
var path = require('path'),
tasks = {},
cwd = process.env.PWD || process.cwd();
cwd = process.env.PWD || process.cwd(),
async = require('async'),
DOMParser = require('xmldom').DOMParser,
xpath = require('xpath');
// Windows users can't run grunt in a subdirectory, so allow them to set
// the root by passing --root=path/to/dir.
@@ -63,6 +66,55 @@ module.exports = function(grunt) {
return destPath;
};
/**
* Find thirdpartylibs.xml and generate an array of paths contained within
* them (used to generate ignore files and so on).
*
* @return {array} The list of thirdparty paths.
*/
var getThirdPartyPathsFromXML = function() {
var thirdpartyfiles = grunt.file.expand('*/**/thirdpartylibs.xml');
var libs = ['node_modules/', 'vendor/'];
thirdpartyfiles.forEach( function(file) {
var dirname = path.dirname(file);
var doc = new DOMParser().parseFromString(grunt.file.read(file));
var nodes = xpath.select("/libraries/library/location/text()", doc);
nodes.forEach(function(node) {
var lib = path.join(dirname, node.toString());
if (grunt.file.isDir(lib)) {
// Ensure trailing slash on dirs.
lib = lib.replace(/\/?$/, '/');
}
// Look for duplicate paths before adding to array.
if (libs.indexOf(lib) === -1) {
libs.push(lib);
}
});
});
return libs;
};
// An array of paths to third party directories.
var thirdPartyPaths = getThirdPartyPathsFromXML();
/**
* Determine if the file is a Moodle file, or its listed in
* the thirdpartylibs.xml file paths as a third party file.
*
* @param {string} file The file path to determine if thirdparty
* @return {bool} false If thid party file.
*/
var isMoodleFile = function(file) {
if (grunt.file.isMatch(thirdPartyPaths, file)) {
return false;
}
return true;
};
// Project configuration.
grunt.initConfig({
jshint: {
@@ -70,20 +122,20 @@ module.exports = function(grunt) {
amd: { src: amdSrc }
},
eslint: {
// Even though warnings dont stop the build we don't display warnings by default because:
// * At this moment we've got too many core warnings
// * It will complain about ignored files (https://github.com/sindresorhus/grunt-eslint/issues/119)
// * It's better experience to use editor integrations or eslint natively
// Even though warnings dont stop the build we don't display warnings by default because
// at this moment we've got too many core warnings.
options: { quiet: !grunt.option('show-lint-warnings') },
// Check AMD files. We add some stricter rules which we can't apply to the default configuration due
// to YUI rollups.
amd: {
src: amdSrc,
filter: isMoodleFile,
options: { rules: {'no-undef': 'error', 'no-unused-vars': 'error', 'no-empty': 'error', 'no-unused-expressions': 'error'} }
},
// Check YUI module source files.
yui: {
src: ['**/yui/src/**/*.js']
src: ['**/yui/src/**/*.js', '!*/**/yui/src/*/meta/*.js'],
filter: isMoodleFile
}
},
uglify: {
@@ -131,6 +183,15 @@ module.exports = function(grunt) {
}
});
/**
* Generate ignore files (utilising thirdpartylibs.xml data)
*/
tasks.ignorefiles = function() {
// Generate .eslintignore.
var eslintIgnores = ['# Generated by "grunt ignorefiles"', '*/**/yui/src/*/meta/', '*/**/build/'].concat(thirdPartyPaths);
grunt.file.write('.eslintignore', eslintIgnores.join('\n'));
};
/**
* Shifter task. Is configured with a path to a specific file or a directory,
* in the case of a specific file it will work out the right module to be built.
@@ -139,8 +200,7 @@ module.exports = function(grunt) {
* so be careful to to call done().
*/
tasks.shifter = function() {
var async = require('async'),
done = this.async(),
var done = this.async(),
options = grunt.config('shifter.options');
// Run the shifter processes one at a time to avoid confusing output.
@@ -260,6 +320,7 @@ module.exports = function(grunt) {
// Register JS tasks.
grunt.registerTask('shifter', 'Run Shifter against the current directory', tasks.shifter);
grunt.registerTask('ignorefiles', 'Generate ignore files for linters', tasks.ignorefiles);
grunt.registerTask('yui', ['eslint:yui', 'shifter']);
grunt.registerTask('amd', ['eslint:amd', 'jshint', 'uglify']);
grunt.registerTask('js', ['amd', 'yui']);
+10
View File
@@ -1969,6 +1969,16 @@
"from": "xml2js@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz"
},
"xmldom": {
"version": "0.1.22",
"from": "xmldom@latest",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.22.tgz"
},
"xpath": {
"version": "0.0.23",
"from": "xpath@latest",
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.23.tgz"
},
"xregexp": {
"version": "3.1.1",
"from": "xregexp@>=3.0.0 <4.0.0",
+3 -1
View File
@@ -10,6 +10,8 @@
"grunt-contrib-uglify": "0.11.0",
"grunt-contrib-watch": "0.6.1",
"grunt-eslint": "^18.1.0",
"shifter": "0.5.0"
"shifter": "0.5.0",
"xmldom": "^0.1.22",
"xpath": "0.0.23"
}
}