diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index a6821676629..00000000000 --- a/.eslintignore +++ /dev/null @@ -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 diff --git a/.gitignore b/.gitignore index 1dab0f7a5c1..71a7224e0ab 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ composer.phar /lib/yuilib/*/*/*-coverage.js atlassian-ide-plugin.xml /node_modules/ +.eslintignore diff --git a/Gruntfile.js b/Gruntfile.js index 2ec167eaa64..3cc3bb07530 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -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']); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 45c770463de..6411bc5d0b2 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -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", diff --git a/package.json b/package.json index d6d275db0c5..5989a0ea0c3 100644 --- a/package.json +++ b/package.json @@ -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" } }