Skip to content

Commit

Permalink
MDL-52127 grunt: be aware of third party paths
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
danpoltawski committed Jun 13, 2016
1 parent be4b3cc commit 30db70a
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 15 deletions.
6 changes: 0 additions & 6 deletions .eslintignore

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -36,3 +36,4 @@ composer.phar
/lib/yuilib/*/*/*-coverage.js
atlassian-ide-plugin.xml
/node_modules/
.eslintignore
77 changes: 69 additions & 8 deletions Gruntfile.js
Expand Up @@ -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.
Expand Down Expand Up @@ -63,27 +66,76 @@ 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: {
options: {jshintrc: '.jshintrc'},
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: {
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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']);
Expand Down
10 changes: 10 additions & 0 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Expand Up @@ -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"
}
}

0 comments on commit 30db70a

Please sign in to comment.