Index: Gruntfile.js
===================================================================
--- Gruntfile.js	(revision 42391)
+++ Gruntfile.js	(working copy)
@@ -1,7 +1,8 @@
 /* jshint node:true */
+/* global module, require, __dirname */
 /* globals Set */
-var webpackConfig = require( './webpack.config.prod' );
-var webpackDevConfig = require( './webpack.config.dev' );
+var webpackConfig = require( './webpack.config.prod' ),
+	webpackDevConfig = require( './webpack.config.dev' );
 
 module.exports = function(grunt) {
 	var path = require('path'),
@@ -10,7 +11,8 @@
 		SOURCE_DIR = 'src/',
 		BUILD_DIR = 'build/',
  		BANNER_TEXT = '/*! This file is auto-generated */',
-		autoprefixer = require( 'autoprefixer' );
+		autoprefixer = require( 'autoprefixer' ),
+		copyFilesOptions = grunt.config.get( 'copy.files.files' );
 
 	// Load tasks.
 	require('matchdep').filterDev(['grunt-*', '!grunt-legacy-util']).forEach( grunt.loadNpmTasks );
@@ -145,7 +147,7 @@
 							version = version.replace( /-[\d]{5}$/, '-' + grunt.template.today( 'yyyymmdd.HHMMss' ) );
 
 							/* jshint quotmark: true */
-							return "$wp_version = '" + version + "';";
+							return '$wp_version = \'' + version + '\';';
 						});
 					}
 				},
@@ -306,10 +308,67 @@
 				src: []
 			}
 		},
+		eslint: {
+			grunt: {
+				options: {
+					configFile: 'node_modules/eslint-config-wordpress/index.js'
+				},
+				src: [ 'Gruntfile.js' ]
+			},
+			core: {
+				options: {
+					configFile: 'node_modules/eslint-config-wordpress/index.js'
+				},
+				cwd: SOURCE_DIR,
+				src: [
+					'wp-admin/js/*.js',
+					'wp-includes/js/*.js',
+
+					// Built scripts.
+					'!wp-includes/js/media-*',
+
+					// WordPress scripts inside directories
+					'wp-includes/js/jquery/jquery.table-hotkeys.js',
+					'wp-includes/js/mediaelement/wp-mediaelement.js',
+					'wp-includes/js/mediaelement/wp-playlist.js',
+					'wp-includes/js/plupload/handlers.js',
+					'wp-includes/js/plupload/wp-plupload.js',
+					'wp-includes/js/tinymce/plugins/wordpress/plugin.js',
+					'wp-includes/js/tinymce/plugins/wp*/plugin.js',
+
+					// Third party scripts
+					'!wp-admin/js/farbtastic.js',
+					'!wp-includes/js/backbone*.js',
+					'!wp-includes/js/swfobject.js',
+					'!wp-includes/js/underscore*.js',
+					'!wp-includes/js/colorpicker.js',
+					'!wp-includes/js/hoverIntent.js',
+					'!wp-includes/js/json2.js',
+					'!wp-includes/js/tw-sack.js',
+					'!wp-includes/js/twemoji.js',
+					'!**/*.min.js'
+				]
+			},
+			themes: {
+				options: {
+					configFile: 'node_modules/eslint-config-wordpress/index.js'
+				},
+				expand: true,
+				cwd: SOURCE_DIR + 'wp-content/themes',
+				src: [
+					'twenty*/**/*.js',
+					'!twenty{eleven,twelve,thirteen}/**',
+
+					// Third party scripts
+					'!twenty{fourteen,fifteen,sixteen,seventeen}/**/html5.js',
+					'!twentyseventeen/assets/js/jquery.scrollTo.js'
+				]
+			}
+		},
 		jshint: {
-			options: grunt.file.readJSON('.jshintrc'),
+			options: grunt.file.readJSON( '.jshintrc' ),
 			grunt: {
-				src: ['Gruntfile.js']
+				src: [ 'Gruntfile.js' ]
 			},
 			tests: {
 				src: [
@@ -748,13 +807,11 @@
 
 	// Allow builds to be minimal
 	if( grunt.option( 'minimal-copy' ) ) {
-		var copyFilesOptions = grunt.config.get( 'copy.files.files' );
 		copyFilesOptions[0].src.push( '!wp-content/plugins/**' );
 		copyFilesOptions[0].src.push( '!wp-content/themes/!(twenty*)/**' );
 		grunt.config.set( 'copy.files.files', copyFilesOptions );
 	}
 
-
 	// Register tasks.
 
 	// Webpack task.
@@ -815,8 +872,8 @@
 	] );
 
 	grunt.registerTask( 'precommit', 'Runs test and build tasks in preparation for a commit', function() {
-		var done = this.async();
-		var map = {
+		var done = this.async(),
+			map = {
 			svn: 'svn status --ignore-externals',
 			git: 'git status --short'
 		};
@@ -832,8 +889,12 @@
 
 			if ( set.length ) {
 				fs.stat( dir = set.shift(), function( error ) {
-					error ? find( set ) : run( path.basename( dir ).substr( 1 ) );
-				} );
+					if ( error ) {
+						find( set );
+					} else {
+						run( path.basename( dir ).substr( 1 ) );
+					}
+				});
 			} else {
 				runAllTasks();
 			}
Index: package.json
===================================================================
--- package.json	(revision 42391)
+++ package.json	(working copy)
@@ -13,6 +13,8 @@
   "license": "GPL-2.0+",
   "devDependencies": {
     "autoprefixer": "^6.5.1",
+    "eslint": "^4.13.1",
+    "eslint-config-wordpress": "^1.0.0",
     "grunt": "~0.4.5",
     "grunt-banner": "^0.6.0",
     "grunt-contrib-clean": "~1.0.0",
@@ -25,6 +27,7 @@
     "grunt-contrib-qunit": "^1.2.0",
     "grunt-contrib-uglify": "~2.0.0",
     "grunt-contrib-watch": "~1.0.0",
+    "grunt-eslint": "^20.1.0",
     "grunt-includes": "~0.5.1",
     "grunt-jsdoc": "^2.1.0",
     "grunt-jsvalidate": "~0.2.2",
@@ -34,8 +37,8 @@
     "grunt-replace": "~1.0.1",
     "grunt-rtlcss": "~2.0.1",
     "grunt-sass": "~1.2.1",
-    "ink-docstrap": "^1.3.0",
     "grunt-webpack": "^3.0.2",
+    "ink-docstrap": "^1.3.0",
     "matchdep": "~1.0.0",
     "webpack": "^3.6.0",
     "webpack-dev-server": "^2.9.1"
