diff --git a/.eslintrc b/.eslintrc
index d4e2ad0c9b53ce75b25d8bbf13346fa88a49a93a..b624e42be8c6d0ad65fd7752f640f4224fc35505 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,4 +1,5 @@
 {
+  "extends": "eslint:recommended",
   "env": {
     "browser": true
   },
@@ -16,31 +17,72 @@
   },
   "rules": {
     // Errors.
+    "array-bracket-spacing": [2, "never"],
     "block-scoped-var": 2,
     "brace-style": [2, "stroustrup", {"allowSingleLine": true}],
+    "comma-dangle": [2, "never"],
+    "comma-spacing": 2,
     "comma-style": [2, "last"],
+    "computed-property-spacing": [2, "never"],
+    "curly": [2, "all"],
+    "eol-last": 2,
     "eqeqeq": [2, "smart"],
     "guard-for-in": 2,
-    "indent": [2, 2, {"indentSwitchCase": true}],
+    "indent": [2, 2, {"SwitchCase": 1}],
     "key-spacing": [2, {"beforeColon": false, "afterColon": true}],
+    "linebreak-style": [2, "unix"],
     "lines-around-comment": [2, {"beforeBlockComment": true, "afterBlockComment": false}],
+    "new-parens": 2,
+    "no-array-constructor": 2,
+    "no-caller": 2,
+    "no-catch-shadow": 2,
+    "no-empty-label": 2,
+    "no-eval": 2,
+    "no-extend-native": 2,
+    "no-extra-bind": 2,
+    "no-extra-parens": [2, "functions"],
     "no-implied-eval": 2,
-    "no-mixed-spaces-and-tabs": 2,
+    "no-iterator": 2,
+    "no-label-var": 2,
+    "no-labels": 2,
+    "no-lone-blocks": 2,
+    "no-loop-func": 2,
+    "no-multi-spaces": 2,
+    "no-multi-str": 2,
+    "no-native-reassign": 2,
     "no-nested-ternary": 2,
-    "no-reserved-keys": 2,
+    "no-new-func": 2,
+    "no-new-object": 2,
+    "no-new-wrappers": 2,
+    "no-octal-escape": 2,
+    "no-process-exit": 2,
+    "no-proto": 2,
+    "no-return-assign": 2,
+    "no-script-url": 2,
+    "no-sequences": 2,
+    "no-shadow-restricted-names": 2,
+    "no-spaced-func": 2,
     "no-trailing-spaces": 2,
-    "no-undef": 2,
+    "no-undef-init": 2,
     "no-undefined": 2,
-    "no-unused-vars": [2, {"vars": "local", "args": "none"}],
+    "no-unused-expressions": 2,
+    "no-unused-vars": [2, {"vars": "all", "args": "none"}],
+    "no-with": 2,
+    "object-curly-spacing": [2, "never"],
     "one-var": [2, "never"],
+    "quote-props": [2, "consistent-as-needed"],
     "semi": [2, "always"],
+    "semi-spacing": [2, {"before": false, "after": true}],
     "space-after-keywords": [2, "always"],
     "space-before-blocks": [2, "always"],
     "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}],
-    "space-in-brackets": [2, "never"],
     "space-in-parens": [2, "never"],
-    "spaced-line-comment": [2, "always"],
+    "space-infix-ops": 2,
+    "space-return-throw-case": 2,
+    "space-unary-ops": [2, { "words": true, "nonwords": false }],
+    "spaced-comment": [2, "always"],
     "strict": 2,
+    "yoda": [2, "never"],
     // Warnings.
     "max-nested-callbacks": [1, 3],
     "valid-jsdoc": [1, {
@@ -49,17 +91,6 @@
         "property": "prop"
       },
       "requireReturn": false
-    }],
-    // Disabled.
-    "camelcase": 0,
-    "consistent-return": 0,
-    "dot-notation": 0,
-    "new-cap": 0,
-    "no-alert": 0,
-    "no-new": 0,
-    "no-shadow": 0,
-    "no-underscore-dangle": 0,
-    "no-use-before-define": 0,
-    "quotes": 0
+    }]
   }
 }
diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index f8a1cb02b1f9af432d2894d60c06deb912f1038a..ba10fe89393a78247d64fe88820f20fcf382e81d 100644
--- a/core/misc/ajax.js
+++ b/core/misc/ajax.js
@@ -46,7 +46,7 @@
       $('.use-ajax').once('ajax').each(function () {
         var element_settings = {};
         // Clicked links look better with the throbber than the progress bar.
-        element_settings.progress = {'type': 'throbber'};
+        element_settings.progress = {type: 'throbber'};
 
         // For anchor tags, these will go to the target of the anchor rather
         // than the usual location.
@@ -75,7 +75,7 @@
         element_settings.event = 'click';
         // Clicked form buttons look better with the throbber than the progress
         // bar.
-        element_settings.progress = {'type': 'throbber'};
+        element_settings.progress = {type: 'throbber'};
         element_settings.base = $(this).attr('id');
         element_settings.element = this;
 
@@ -276,7 +276,7 @@
         message: Drupal.t('Please wait...')
       },
       submit: {
-        'js': true
+        js: true
       }
     };
 
diff --git a/core/misc/dialog/dialog.ajax.js b/core/misc/dialog/dialog.ajax.js
index a18ad23e032982b3ef07916ed0b978058453058d..7f56672bc1ee5af770cd39952862ef26544f8742 100644
--- a/core/misc/dialog/dialog.ajax.js
+++ b/core/misc/dialog/dialog.ajax.js
@@ -74,9 +74,9 @@
           border: 0
         });
         buttons.push({
-          'text': $originalButton.html() || $originalButton.attr('value'),
-          'class': $originalButton.attr('class'),
-          'click': function (e) {
+          text: $originalButton.html() || $originalButton.attr('value'),
+          class: $originalButton.attr('class'),
+          click: function (e) {
             $originalButton.trigger('mousedown').trigger('mouseup').trigger('click');
             e.preventDefault();
           }
diff --git a/core/misc/dropbutton/dropbutton.js b/core/misc/dropbutton/dropbutton.js
index 787cc560e336935612f9416304c85d97b937f3af..4f7645cc4ec7482f59a5254e80ba6e9e551c2c75 100644
--- a/core/misc/dropbutton/dropbutton.js
+++ b/core/misc/dropbutton/dropbutton.js
@@ -60,7 +60,7 @@
    */
   function DropButton(dropbutton, settings) {
     // Merge defaults with settings.
-    var options = $.extend({'title': Drupal.t('List additional actions')}, settings);
+    var options = $.extend({title: Drupal.t('List additional actions')}, settings);
     var $dropbutton = $(dropbutton);
 
     /**
diff --git a/core/misc/states.js b/core/misc/states.js
index b21a048cef71438c714382a1bc16015ca5ed472d..b308a136686aaef2ab343863c5dc35f0d5b0ebc1 100644
--- a/core/misc/states.js
+++ b/core/misc/states.js
@@ -93,14 +93,14 @@
    * @prop {function} Number
    */
   states.Dependent.comparisons = {
-    'RegExp': function (reference, value) {
+    RegExp: function (reference, value) {
       return reference.test(value);
     },
-    'Function': function (reference, value) {
+    Function: function (reference, value) {
       // The "reference" variable is a comparison function.
       return reference(value);
     },
-    'Number': function (reference, value) {
+    Number: function (reference, value) {
       // If "reference" is a number and "value" is a string, then cast
       // reference as a string before applying the strict comparison in
       // compare().
@@ -441,7 +441,7 @@
     // 'empty' describes the state to be monitored.
     empty: {
       // 'keyup' is the (native DOM) event that we watch for.
-      'keyup': function () {
+      keyup: function () {
         // The function associated to that trigger returns the new value for the
         // state.
         return this.val() === '';
@@ -449,7 +449,7 @@
     },
 
     checked: {
-      'change': function () {
+      change: function () {
         // prop() and attr() only takes the first element into account. To
         // support selectors matching multiple checkboxes, iterate over all and
         // return whether any is checked.
@@ -467,7 +467,7 @@
 
     // For radio buttons, only return the value if the radio button is selected.
     value: {
-      'keyup': function () {
+      keyup: function () {
         // Radio buttons share the same :input[name="key"] selector.
         if (this.length > 1) {
           // Initial checked value of radios is undefined, so we return false.
@@ -475,7 +475,7 @@
         }
         return this.val();
       },
-      'change': function () {
+      change: function () {
         // Radio buttons share the same :input[name="key"] selector.
         if (this.length > 1) {
           // Initial checked value of radios is undefined, so we return false.
@@ -486,7 +486,7 @@
     },
 
     collapsed: {
-      'collapsed': function (e) {
+      collapsed: function (e) {
         return (typeof e !== 'undefined' && 'value' in e) ? e.value : !this.is('[open]');
       }
     }
@@ -550,18 +550,18 @@
    * @name Drupal.states.State.aliases
    */
   states.State.aliases = {
-    'enabled': '!disabled',
-    'invisible': '!visible',
-    'invalid': '!valid',
-    'untouched': '!touched',
-    'optional': '!required',
-    'filled': '!empty',
-    'unchecked': '!checked',
-    'irrelevant': '!relevant',
-    'expanded': '!collapsed',
-    'open': '!collapsed',
-    'closed': 'collapsed',
-    'readwrite': '!readonly'
+    enabled: '!disabled',
+    invisible: '!visible',
+    invalid: '!valid',
+    untouched: '!touched',
+    optional: '!required',
+    filled: '!empty',
+    unchecked: '!checked',
+    irrelevant: '!relevant',
+    expanded: '!collapsed',
+    open: '!collapsed',
+    closed: 'collapsed',
+    readwrite: '!readonly'
   };
 
   states.State.prototype = {
diff --git a/core/misc/tabledrag.js b/core/misc/tabledrag.js
index c3a0f5a11f642c5b32ec5eef14bbd0875c127383..8754b98adc6a7546a6e2614873ef9d16c5356aac 100644
--- a/core/misc/tabledrag.js
+++ b/core/misc/tabledrag.js
@@ -1341,7 +1341,7 @@
       }
     }
 
-    return {'min': minIndent, 'max': maxIndent};
+    return {min: minIndent, max: maxIndent};
   };
 
   /**
diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js
index fbdb33c35f284241a104c7cda2f8c38973f18dad..7a212904ee11b47ca2bcf828d1d9248bef47a861 100644
--- a/core/misc/tableheader.js
+++ b/core/misc/tableheader.js
@@ -292,7 +292,7 @@
         $stickyCell = this.$stickyHeaderCells.eq($that.index());
         display = $that.css('display');
         if (display !== 'none') {
-          $stickyCell.css({'width': $that.css('width'), 'display': display});
+          $stickyCell.css({width: $that.css('width'), display: display});
         }
         else {
           $stickyCell.css('display', 'none');
diff --git a/core/misc/tableselect.js b/core/misc/tableselect.js
index fc8e9f2dbb999d07ce32182725d7bd6dce1c2d51..8a776959721355aa98eebc92153fe5d98815808d 100644
--- a/core/misc/tableselect.js
+++ b/core/misc/tableselect.js
@@ -35,7 +35,10 @@
     var checkboxes;
     var lastChecked;
     var $table = $(table);
-    var strings = {'selectAll': Drupal.t('Select all rows in this table'), 'selectNone': Drupal.t('Deselect all rows in this table')};
+    var strings = {
+      selectAll: Drupal.t('Select all rows in this table'),
+      selectNone: Drupal.t('Deselect all rows in this table')
+    };
     var updateSelectAll = function (state) {
       // Update table's select-all checkbox (and sticky header's if available).
       $table.prev('table.sticky-header').addBack().find('th.select-all input[type="checkbox"]').each(function () {
diff --git a/core/modules/ckeditor/js/ckeditor.js b/core/modules/ckeditor/js/ckeditor.js
index 4254f0010e0ef8a6dfe6f9a3905de56571aa532a..ebd84b2a0106a395989284dbdfb80b7c11c35f9d 100644
--- a/core/modules/ckeditor/js/ckeditor.js
+++ b/core/modules/ckeditor/js/ckeditor.js
@@ -213,7 +213,7 @@
         dialogType: 'modal',
         selector: '.ckeditor-dialog-loading-link',
         url: url,
-        progress: {'type': 'throbber'},
+        progress: {type: 'throbber'},
         submit: {
           editor_object: existingValues
         }
diff --git a/core/modules/ckeditor/js/ckeditor.stylescombo.admin.js b/core/modules/ckeditor/js/ckeditor.stylescombo.admin.js
index 76e74212a03725e997f08d37a02f1554e8cb1198..94e027d229f9e5be1d20090ff54ff318f32830d1 100644
--- a/core/modules/ckeditor/js/ckeditor.stylescombo.admin.js
+++ b/core/modules/ckeditor/js/ckeditor.stylescombo.admin.js
@@ -88,7 +88,7 @@
         // Build the data structure CKEditor's stylescombo plugin expects.
         // @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Styles
         stylesSet.push({
-          attributes: {'class': classes.join(' ')},
+          attributes: {class: classes.join(' ')},
           element: element,
           name: label
         });
diff --git a/core/modules/ckeditor/js/views/ControllerView.js b/core/modules/ckeditor/js/views/ControllerView.js
index a0b77b3d58fad78e5ba17e909d308aefffc5e530..caf0b1865b679b4e5144ef763551a630b487f2b5 100644
--- a/core/modules/ckeditor/js/views/ControllerView.js
+++ b/core/modules/ckeditor/js/views/ControllerView.js
@@ -271,7 +271,7 @@
             .detach()
             .appendTo('.ckeditor-toolbar-disabled > .ckeditor-toolbar-available > ul');
           // Update the toolbar value field.
-          this.model.set({'isDirty': true}, {broadcast: false});
+          this.model.set({isDirty: true}, {broadcast: false});
         }
       }
     },
diff --git a/core/modules/color/color.js b/core/modules/color/color.js
index b41672e549892ef4150294e25353343dced9e7ba..437dffeb737d1baf6c27b85a8a73c6ad41764d44 100644
--- a/core/modules/color/color.js
+++ b/core/modules/color/color.js
@@ -166,7 +166,7 @@
         // Set background/foreground colors.
         $(input).css({
           backgroundColor: color,
-          'color': farb.RGBToHSL(farb.unpack(color))[2] > 0.5 ? '#000' : '#fff'
+          color: farb.RGBToHSL(farb.unpack(color))[2] > 0.5 ? '#000' : '#fff'
         });
 
         // Change input value.
diff --git a/core/modules/contextual/js/toolbar/views/VisualView.js b/core/modules/contextual/js/toolbar/views/VisualView.js
index 2e5c4408275b656db86d6a36ed3714800ec8846a..9fb27a4f84b3162d86214008d54762ffa809a796 100644
--- a/core/modules/contextual/js/toolbar/views/VisualView.js
+++ b/core/modules/contextual/js/toolbar/views/VisualView.js
@@ -20,10 +20,10 @@
       };
 
       return {
-        'click': function () {
+        click: function () {
           this.model.set('isViewing', !this.model.get('isViewing'));
         },
-        'touchend': touchEndToClick
+        touchend: touchEndToClick
       };
     },
 
diff --git a/core/modules/editor/js/editor.js b/core/modules/editor/js/editor.js
index 9adaf2b08a8ee93b46a6f670bdb7c06dbc0824a6..d2b9e5b70eff640c095f4099f8620c551bb2d5e3 100644
--- a/core/modules/editor/js/editor.js
+++ b/core/modules/editor/js/editor.js
@@ -89,7 +89,7 @@
         buttons: [
           {
             text: Drupal.t('Continue'),
-            'class': 'button button--primary',
+            class: 'button button--primary',
             click: function () {
               changeTextEditor(field, newFormatID);
               confirmationDialog.close();
@@ -97,7 +97,7 @@
           },
           {
             text: Drupal.t('Cancel'),
-            'class': 'button',
+            class: 'button',
             click: function () {
               // Restore the active format ID: cancel changing text format. We cannot
               // simply call event.preventDefault() because jQuery's change event is
@@ -309,8 +309,8 @@
         url: Drupal.url('editor/filter_xss/' + format.format),
         type: 'POST',
         data: {
-          'value': field.value,
-          'original_format_id': originalFormatID
+          value: field.value,
+          original_format_id: originalFormatID
         },
         dataType: 'json',
         success: function (xssFilteredValue) {
diff --git a/core/modules/quickedit/js/models/EntityModel.js b/core/modules/quickedit/js/models/EntityModel.js
index 2048bde57cd4d1b48ee08aed818e4a4e6c412e02..9f9508629240ce50a9181abcd23746ceee422605 100644
--- a/core/modules/quickedit/js/models/EntityModel.js
+++ b/core/modules/quickedit/js/models/EntityModel.js
@@ -169,9 +169,9 @@
       switch (to) {
         case 'closed':
           this.set({
-            'isActive': false,
-            'inTempStore': false,
-            'isDirty': false
+            isActive: false,
+            inTempStore: false,
+            isDirty: false
           });
           break;
 
@@ -264,8 +264,8 @@
           options.reason = 'stop';
           this.get('fields').each(function (fieldModel) {
             fieldModel.set({
-              'inTempStore': false,
-              'state': 'inactive'
+              inTempStore: false,
+              state: 'inactive'
             }, options);
           });
           break;
@@ -392,9 +392,9 @@
             entityModel.save({
               success: function () {
                 entityModel.set({
-                  'state': 'deactivating',
-                  'isCommitting': false
-                }, {'saved': true});
+                  state: 'deactivating',
+                  isCommitting: false
+                }, {saved: true});
               },
               error: function () {
                 // Reset the "isCommitting" mutex.
diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js
index ed4068c101ff6d272010a39b5913cc2b8d7ce90c..e45021dd086b78d7394ed96bf8bbde9c4996ab27 100644
--- a/core/modules/toolbar/js/toolbar.js
+++ b/core/modules/toolbar/js/toolbar.js
@@ -131,7 +131,7 @@
         // not the first 'Home' toolbar tab).
         if (Drupal.toolbar.models.toolbarModel.get('orientation') === 'horizontal' && Drupal.toolbar.models.toolbarModel.get('activeTab') === null) {
           Drupal.toolbar.models.toolbarModel.set({
-            'activeTab': $('.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a').get(0)
+            activeTab: $('.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a').get(0)
           });
         }
       });
@@ -188,31 +188,31 @@
       switch (label) {
         case 'toolbar.narrow':
           model.set({
-            'isOriented': mql.matches,
-            'isTrayToggleVisible': false
+            isOriented: mql.matches,
+            isTrayToggleVisible: false
           });
           // If the toolbar doesn't have an explicit orientation yet, or if the
           // narrow media query doesn't match then set the orientation to
           // vertical.
           if (!mql.matches || !model.get('orientation')) {
-            model.set({'orientation': 'vertical'}, {validate: true});
+            model.set({orientation: 'vertical'}, {validate: true});
           }
           break;
 
         case 'toolbar.standard':
           model.set({
-            'isFixed': mql.matches
+            isFixed: mql.matches
           });
           break;
 
         case 'toolbar.wide':
           model.set({
-            'orientation': ((mql.matches) ? 'horizontal' : 'vertical')
+            orientation: ((mql.matches) ? 'horizontal' : 'vertical')
           }, {validate: true});
           // The tray orientation toggle visibility does not need to be
           // validated.
           model.set({
-            'isTrayToggleVisible': mql.matches
+            isTrayToggleVisible: mql.matches
           });
           break;
 
diff --git a/core/modules/toolbar/js/toolbar.menu.js b/core/modules/toolbar/js/toolbar.menu.js
index 156c49e5d56731183793cd5c050e389dfb62b65e..990c56a53d9d67305a2d3682b73368dee849dce3 100644
--- a/core/modules/toolbar/js/toolbar.menu.js
+++ b/core/modules/toolbar/js/toolbar.menu.js
@@ -20,8 +20,8 @@
   $.fn.drupalToolbarMenu = function () {
 
     var ui = {
-      'handleOpen': Drupal.t('Extend'),
-      'handleClose': Drupal.t('Collapse')
+      handleOpen: Drupal.t('Extend'),
+      handleClose: Drupal.t('Collapse')
     };
 
     /**
@@ -97,9 +97,9 @@
      */
     function initItems($menu) {
       var options = {
-        'class': 'toolbar-icon toolbar-handle',
-        'action': ui.handleOpen,
-        'text': ''
+        class: 'toolbar-icon toolbar-handle',
+        action: ui.handleOpen,
+        text: ''
       };
       // Initialize items and their links.
       $menu.find('li > a').wrap('<div class="toolbar-box">');
diff --git a/core/modules/tour/js/tour.js b/core/modules/tour/js/tour.js
index 8f05cc0f4980ad3b71d361fc75c332f386e32d54..d6ca172b7bd18864835f20fb55c192bb2595071f 100644
--- a/core/modules/tour/js/tour.js
+++ b/core/modules/tour/js/tour.js
@@ -107,7 +107,7 @@
     /**
      * @type {object}
      */
-    events: {'click': 'onClick'},
+    events: {click: 'onClick'},
 
     /**
      * Handles edit mode toggle interactions.
diff --git a/core/modules/views_ui/js/ajax.js b/core/modules/views_ui/js/ajax.js
index 3079badbd80691284b6bf1e507873f89c3eff025..09a1c0413270725badf3cdb57af5c6407d484a9a 100644
--- a/core/modules/views_ui/js/ajax.js
+++ b/core/modules/views_ui/js/ajax.js
@@ -117,8 +117,8 @@
     collapseReplaced: false,
     attach: function (context, settings) {
       var base_element_settings = {
-        'event': 'click',
-        'progress': {'type': 'fullscreen'}
+        event: 'click',
+        progress: {type: 'fullscreen'}
       };
       // Bind AJAX behaviors to all items showing the class.
       $('a.views-ajax-link', context).once('views-ajax').each(function () {
diff --git a/core/modules/views_ui/js/views-admin.js b/core/modules/views_ui/js/views-admin.js
index 539c406a1758b307a58b3454d40a2e971f66d4d3..d16731f68c25ed6c7e277fdf2ea5cf0eab2752bb 100644
--- a/core/modules/views_ui/js/views-admin.js
+++ b/core/modules/views_ui/js/views-admin.js
@@ -454,11 +454,11 @@
         $description = $option.find('div.description');
         options[i] = {
           // Search on the lowercase version of the label text + description.
-          'searchText': $label.text().toLowerCase() + " " + $description.text().toLowerCase(),
+          searchText: $label.text().toLowerCase() + " " + $description.text().toLowerCase(),
           // Maintain a reference to the jQuery object for each row, so we don't
           // have to create a new object inside the performance-sensitive keyup
           // handler.
-          '$div': $option
+          $div: $option
         };
       }
       return options;