Repository: eslint/eslint (js)

Issue:
'eslint --init' installs wrong versions of depencies for AirBnB
**Tell us about your environment**
Windows 10
- **ESLint Version:** 3.7.1
- **Node Version:** 5.3.0
- **npm Version:** 3.3.12

**What parser (default, Babel-ESLint, etc.) are you using?**
N/A
**Please show your full configuration:**
AirBnB style guide
**What did you do? Please include the actual source code causing the issue.**

```
npm init
Use a popular style guide
Airbnb
JSON
```

**What did you expect to happen?**
I expected the node modules to install correctly.
**What actually happened? Please include the actual, raw output from ESLint.**
Eslint failed to correctly install dependencies as seen at the bottom of this output:

```
C:\SWDev\job-frontend>eslint --init                                                                                                                                                          
? How would you like to configure ESLint? Use a popular style guide                                                                                                                          
? Which style guide do you want to follow? Airbnb                                                                                                                                            
? What format do you want your config file to be in? JSON                                                                                                                                    
Installing eslint-plugin-react, eslint-plugin-jsx-a11y, eslint-plugin-import, eslint-config-airbnb                                                                                           
npm WARN install Couldn't install optional dependency: Unsupported                                                                                                                           
job-frontend@0.0.0 C:\SWDev\job-frontend                                                                                                                                                     
├─┬ eslint@3.7.1                                                                                                                                                                             
│ └── doctrine@1.3.0                                                                                                                                                                         
├─┬ eslint-config-airbnb@12.0.0                                                                                                                                                              
│ ├── eslint-config-airbnb-base@8.0.0                                                                                                                                                        
│ └── UNMET PEER DEPENDENCY eslint-plugin-import@^1.16.0                                                                                                                                     
├─┬ UNMET PEER DEPENDENCY eslint-plugin-import@2.0.0                                                                                                                                         
│ ├── contains-path@0.1.0                                                                                                                                                                    
│ ├── eslint-import-resolver-node@0.2.3   
│ ├─┬ eslint-module-utils@1.0.0                                                                                                                                                              
│ │ └── pkg-dir@1.0.0                                                                                                                                                                        
│ ├── lodash.cond@4.5.2                                                                                                                                                                      
│ └── pkg-up@1.0.0                                                                                                                                                                           
├─┬ eslint-plugin-jsx-a11y@2.2.3                                                                                                                                                             
│ └── damerau-levenshtein@1.0.3                                                                                                                                                              
└── eslint-plugin-react@6.4.1                                                                                                                                                                

npm WARN EPEERINVALID eslint-config-airbnb@12.0.0 requires a peer of eslint-plugin-import@^1.16.0 but none was installed.                                                                    
npm WARN EPEERINVALID eslint-config-airbnb-base@8.0.0 requires a peer of eslint-plugin-import@^1.16.0 but none was installed.                                                                
npm WARN EPACKAGEJSON job-frontend@0.0.0 No license field.
```

**Workaround**
The AirBnB style guide for standard javascript is actually eslint-config-airbnb-base, the one used by the wizard is for react. So I swapped out that package and chose the versions of the decencies that would work (with either react or standard AirBnB).

Initialized package.json:

```
    "eslint-config-airbnb": "^12.0.0",
    "eslint-plugin-import": "^2.0.0",
    "eslint-plugin-jsx-a11y": "^2.2.3",
```

Updated package.json:

```
    "eslint-config-airbnb-base": "^8.0.0",
    "eslint-plugin-import": "^1.16.0",
    "eslint-plugin-jsx-a11y": "^2.2.2",
```


Pull request description:
Fix: eslint --init installs wrong dependencies of popular styles (fixes #7338)
**What is the purpose of this pull request? (put an "X" next to item)**

[X] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))

Fixes #7338.

In `eslint --init`, if people select a popular style guide, it installs wrong versions of eslint and plugins.

- `airbnb` and `airbnb-base` requires ESLint 3 but it installs ESLint 4.
- `standard` requires `eslint-plugin-standard` and `eslint-plugin-node` but it does not install those plugins.

**What changes did you make? (Give an overview)**

This PR improve `eslint --init`.
If people select a popular style guide, it checks the `peerDependencies` of the shareable config, then installs the correct dependencies.

To install correct versions, this PR's `eslint --init` installs all dependencies even if those have been installed already. This behavior is different to the current master branch.

**Is there anything you'd like reviewers to focus on?**

Nothing in particular.


Patch:
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 000000000..c1ca392fe
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1,1 @@
+package-lock = false
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index 03a1dd794..f48670896 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -147,6 +147,37 @@ console.log(code.text);     // "var foo = bar;"
 
 In this way, you can retrieve the text and AST used for the last run of `linter.verify()`.
 
+### verifyAndFix()
+
+This method is similar to verify except that it also runs autofixing logic, similar to the `--fix` flag on the command line. The result object will contain the autofixed code, along with any remaining linting messages for the code that were not autofixed.
+
+```js
+var Linter = require("eslint").Linter;
+var linter = new Linter();
+
+var messages = linter.verifyAndFix("var foo", {
+    rules: {
+        semi: 2
+    }
+}, { filename: "foo.js" });
+```
+
+Output object from this method:
+
+```js
+{
+    fixed: true,
+    text: "var foo;",
+    messages: []
+}
+```
+
+The information available is:
+
+* `fixed` - True, if the code was fixed.
+* `text` - Fixed code text (might be the same as input if no fixes were applied).
+* `messages` - Collection of all messages for the given code (It has the same information as explained above under `verify` block).
+
 ## linter
 
 The `eslint.linter` object (deprecated) is an instance of the `Linter` class as defined [above](#Linter). `eslint.linter` exists for backwards compatibility, but we do not recommend using it because any mutations to it are shared among every module that uses `eslint`. Instead, please create your own instance of `eslint.Linter`.
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 3f59e8672..86469a5af 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -775,6 +775,22 @@ You can also use your `.gitignore` file:
 
 Any file that follows the standard ignore file format can be used. Keep in mind that specifying `--ignore-path` means that any existing `.eslintignore` file will not be used. Note that globbing rules in `.eslintignore` follow those of `.gitignore`.
 
+### Using eslintIgnore in package.json
+
+If an `.eslintignore` file is not found and an alternate file is not specified, eslint will look in package.json for an `eslintIgnore` key to check for files to ignore.
+
+    {
+      "name": "mypackage",
+      "version": "0.0.1",
+      "eslintConfig": {
+          "env": {
+              "browser": true,
+              "node": true
+          }
+      },
+      "eslintIgnore": ["hello.js", "world.js"]
+    }
+
 ### Ignored File Warnings
 
 When you pass directories to ESLint, files and directories are silently ignored. If you pass a specific file to ESLint, then you will see a warning indicating that the file was skipped. For example, suppose you have an `.eslintignore` file that looks like this:
diff --git a/lib/cli-engine.js b/lib/cli-engine.js
index d0abc0a55..f53c2e76a 100644
--- a/lib/cli-engine.js
+++ b/lib/cli-engine.js
@@ -23,11 +23,9 @@ const fs = require("fs"),
     Config = require("./config"),
     fileEntryCache = require("file-entry-cache"),
     globUtil = require("./util/glob-util"),
-    SourceCodeFixer = require("./util/source-code-fixer"),
     validator = require("./config/config-validator"),
     stringify = require("json-stable-stringify"),
     hash = require("./util/hash"),
-
     pkg = require("../package.json");
 
 const debug = require("debug")("eslint:cli-engine");
@@ -132,80 +130,6 @@ function calculateStatsPerRun(results) {
     });
 }
 
-/**
- * Performs multiple autofix passes over the text until as many fixes as possible
- * have been applied.
- * @param {string} text The source text to apply fixes to.
- * @param {Object} config The ESLint config object to use.
- * @param {Object} options The ESLint options object to use.
- * @param {string} options.filename The filename from which the text was read.
- * @param {boolean} options.allowInlineConfig Flag indicating if inline comments
- *      should be allowed.
- * @param {Linter} linter Linter context
- * @returns {Object} The result of the fix operation as returned from the
- *      SourceCodeFixer.
- * @private
- */
-function multipassFix(text, config, options, linter) {
-    const MAX_PASSES = 10;
-    let messages = [],
-        fixedResult,
-        fixed = false,
-        passNumber = 0;
-
-    /**
-     * This loop continues until one of the following is true:
-     *
-     * 1. No more fixes have been applied.
-     * 2. Ten passes have been made.
-     *
-     * That means anytime a fix is successfully applied, there will be another pass.
-     * Essentially, guaranteeing a minimum of two passes.
-     */
-    do {
-        passNumber++;
-
-        debug(`Linting code for ${options.filename} (pass ${passNumber})`);
-        messages = linter.verify(text, config, options);
-
-        debug(`Generating fixed text for ${options.filename} (pass ${passNumber})`);
-        fixedResult = SourceCodeFixer.applyFixes(linter.getSourceCode(), messages);
-
-        // stop if there are any syntax errors.
-        // 'fixedResult.output' is a empty string.
-        if (messages.length === 1 && messages[0].fatal) {
-            break;
-        }
-
-        // keep track if any fixes were ever applied - important for return value
-        fixed = fixed || fixedResult.fixed;
-
-        // update to use the fixed output instead of the original text
-        text = fixedResult.output;
-
-    } while (
-        fixedResult.fixed &&
-        passNumber < MAX_PASSES
-    );
-
-
-    /*
-     * If the last result had fixes, we need to lint again to be sure we have
-     * the most up-to-date information.
-     */
-    if (fixedResult.fixed) {
-        fixedResult.messages = linter.verify(text, config, options);
-    }
-
-
-    // ensure the last result properly reflects if fixes were done
-    fixedResult.fixed = fixed;
-    fixedResult.output = text;
-
-    return fixedResult;
-
-}
-
 /**
  * Processes an source code using ESLint.
  * @param {string} text The source code to check.
@@ -269,10 +193,10 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, linte
     } else {
 
         if (fix) {
-            fixedResult = multipassFix(text, config, {
+            fixedResult = linter.verifyAndFix(text, config, {
                 filename,
                 allowInlineConfig
-            }, linter);
+            });
             messages = fixedResult.messages;
         } else {
             messages = linter.verify(text, config, {
diff --git a/lib/config/config-initializer.js b/lib/config/config-initializer.js
index ed4bde875..e87cb79b6 100644
--- a/lib/config/config-initializer.js
+++ b/lib/config/config-initializer.js
@@ -62,42 +62,47 @@ function writeFile(config, format) {
  * @returns {void}
  */
 function installModules(config) {
-    let modules = [];
+    const modules = {};
 
     // Create a list of modules which should be installed based on config
     if (config.plugins) {
-        modules = modules.concat(config.plugins.map(name => `eslint-plugin-${name}`));
+        for (const plugin of config.plugins) {
+            modules[`eslint-plugin-${plugin}`] = "latest";
+        }
     }
     if (config.extends && config.extends.indexOf("eslint:") === -1) {
-        modules.push(`eslint-config-${config.extends}`);
+        const moduleName = `eslint-config-${config.extends}`;
+
+        log.info(`Checking peerDependencies of ${moduleName}`);
+        modules[moduleName] = "latest";
+        Object.assign(
+            modules,
+            npmUtil.fetchPeerDependencies(`${moduleName}@latest`)
+        );
     }
 
-    // Determine which modules are already installed
-    if (modules.length === 0) {
+    // If no modules, do nothing.
+    if (Object.keys(modules).length === 0) {
         return;
     }
 
     // Add eslint to list in case user does not have it installed locally
-    modules.unshift("eslint");
+    modules.eslint = modules.eslint || "latest";
 
-    const installStatus = npmUtil.checkDevDeps(modules);
+    // Mark to show messages if it's new installation of eslint.
+    const installStatus = npmUtil.checkDevDeps(["eslint"]);
 
-    // Install packages which aren't already installed
-    const modulesToInstall = Object.keys(installStatus).filter(module => {
-        const notInstalled = installStatus[module] === false;
+    if (installStatus.eslint === false) {
+        log.info("Local ESLint installation not found.");
+        config.installedESLint = true;
+    }
 
-        if (module === "eslint" && notInstalled) {
-            log.info("Local ESLint installation not found.");
-            config.installedESLint = true;
-        }
+    // Install packages
+    const modulesToInstall = Object.keys(modules).map(name => `${name}@${modules[name]}`);
 
-        return notInstalled;
-    });
+    log.info(`Installing ${modulesToInstall.join(", ")}`);
 
-    if (modulesToInstall.length > 0) {
-        log.info(`Installing ${modulesToInstall.join(", ")}`);
-        npmUtil.installSyncSaveDev(modulesToInstall);
-    }
+    npmUtil.installSyncSaveDev(modulesToInstall);
 }
 
 /**
@@ -265,9 +270,9 @@ function processAnswers(answers) {
 function getConfigForStyleGuide(guide) {
     const guides = {
         google: { extends: "google" },
-        airbnb: { extends: "airbnb", plugins: ["react", "jsx-a11y", "import"] },
-        "airbnb-base": { extends: "airbnb-base", plugins: ["import"] },
-        standard: { extends: "standard", plugins: ["standard", "promise"] }
+        airbnb: { extends: "airbnb" },
+        "airbnb-base": { extends: "airbnb-base" },
+        standard: { extends: "standard" }
     };
 
     if (!guides[guide]) {
diff --git a/lib/ignored-paths.js b/lib/ignored-paths.js
index 0d9152495..2923ee1a6 100644
--- a/lib/ignored-paths.js
+++ b/lib/ignored-paths.js
@@ -16,7 +16,6 @@ const fs = require("fs"),
 
 const debug = require("debug")("eslint:ignored-paths");
 
-
 //------------------------------------------------------------------------------
 // Constants
 //------------------------------------------------------------------------------
@@ -37,25 +36,42 @@ const DEFAULT_OPTIONS = {
     cwd: process.cwd()
 };
 
-
 //------------------------------------------------------------------------------
 // Helpers
 //------------------------------------------------------------------------------
 
-
 /**
- * Find an ignore file in the current directory.
+ * Find a file in the current directory.
  * @param {string} cwd Current working directory
+ * @param {string} name File name
  * @returns {string} Path of ignore file or an empty string.
  */
-function findIgnoreFile(cwd) {
+function findFile(cwd, name) {
     cwd = cwd || DEFAULT_OPTIONS.cwd;
 
-    const ignoreFilePath = path.resolve(cwd, ESLINT_IGNORE_FILENAME);
+    const ignoreFilePath = path.resolve(cwd, name);
 
     return fs.existsSync(ignoreFilePath) && fs.statSync(ignoreFilePath).isFile() ? ignoreFilePath : "";
 }
 
+/**
+ * Find an ignore file in the current directory.
+ * @param {string} cwd Current working directory
+ * @returns {string} Path of ignore file or an empty string.
+ */
+function findIgnoreFile(cwd) {
+    return findFile(cwd, ESLINT_IGNORE_FILENAME);
+}
+
+/**
+ * Find an package.json file in the current directory.
+ * @param {string} cwd Current working directory
+ * @returns {string} Path of package.json file or an empty string.
+ */
+function findPackageJSONFile(cwd) {
+    return findFile(cwd, "package.json");
+}
+
 /**
  * Merge options with defaults
  * @param {Object} options Options to merge with DEFAULT_OPTIONS constant
@@ -80,6 +96,7 @@ class IgnoredPaths {
      */
     constructor(options) {
         options = mergeDefaultOptions(options);
+        this.cache = {};
 
         /**
          * add pattern to node-ignore instance
@@ -91,17 +108,6 @@ class IgnoredPaths {
             return ig.addPattern(pattern);
         }
 
-        /**
-         * add ignore file to node-ignore instance
-         * @param {Object} ig, instance of node-ignore
-         * @param {string} filepath, file to add to ig
-         * @returns {array} raw ignore rules
-         */
-        function addIgnoreFile(ig, filepath) {
-            ig.ignoreFiles.push(filepath);
-            return ig.add(fs.readFileSync(filepath, "utf8"));
-        }
-
         this.defaultPatterns = [].concat(DEFAULT_IGNORE_DIRS, options.patterns || []);
         this.baseDir = options.cwd;
 
@@ -155,8 +161,39 @@ class IgnoredPaths {
             if (ignorePath) {
                 debug(`Adding ${ignorePath}`);
                 this.baseDir = path.dirname(path.resolve(options.cwd, ignorePath));
-                addIgnoreFile(this.ig.custom, ignorePath);
-                addIgnoreFile(this.ig.default, ignorePath);
+                this.addIgnoreFile(this.ig.custom, ignorePath);
+                this.addIgnoreFile(this.ig.default, ignorePath);
+            } else {
+                try {
+
+                    // if the ignoreFile does not exist, check package.json for eslintIgnore
+                    const packageJSONPath = findPackageJSONFile(options.cwd);
+
+                    if (packageJSONPath) {
+                        let packageJSONOptions;
+
+                        try {
+                            packageJSONOptions = JSON.parse(fs.readFileSync(packageJSONPath, "utf8"));
+                        } catch (e) {
+                            debug("Could not read package.json file to check eslintIgnore property");
+                            throw e;
+                        }
+
+                        if (packageJSONOptions.eslintIgnore) {
+                            if (Array.isArray(packageJSONOptions.eslintIgnore)) {
+                                packageJSONOptions.eslintIgnore.forEach(pattern => {
+                                    addPattern(this.ig.custom, pattern);
+                                    addPattern(this.ig.default, pattern);
+                                });
+                            } else {
+                                throw new Error("Package.json eslintIgnore property requires an array of paths");
+                            }
+                        }
+                    }
+                } catch (e) {
+                    debug("Could not find package.json to check eslintIgnore property");
+                    throw e;
+                }
             }
 
             if (options.ignorePattern) {
@@ -168,6 +205,29 @@ class IgnoredPaths {
         this.options = options;
     }
 
+    /**
+     * read ignore filepath
+     * @param {string} filePath, file to add to ig
+     * @returns {array} raw ignore rules
+     */
+    readIgnoreFile(filePath) {
+        if (typeof this.cache[filePath] === "undefined") {
+            this.cache[filePath] = fs.readFileSync(filePath, "utf8");
+        }
+        return this.cache[filePath];
+    }
+
+    /**
+     * add ignore file to node-ignore instance
+     * @param {Object} ig, instance of node-ignore
+     * @param {string} filePath, file to add to ig
+     * @returns {array} raw ignore rules
+     */
+    addIgnoreFile(ig, filePath) {
+        ig.ignoreFiles.push(filePath);
+        return ig.add(this.readIgnoreFile(filePath));
+    }
+
     /**
      * Determine whether a file path is included in the default or custom ignore patterns
      * @param {string} filepath Path to check
diff --git a/lib/linter.js b/lib/linter.js
index 25af05223..0b0d06a86 100755
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -27,9 +27,11 @@ const assert = require("assert"),
     Rules = require("./rules"),
     timing = require("./timing"),
     astUtils = require("./ast-utils"),
+    pkg = require("../package.json"),
+    SourceCodeFixer = require("./util/source-code-fixer");
 
-    pkg = require("../package.json");
-
+const debug = require("debug")("eslint:linter");
+const MAX_AUTOFIX_PASSES = 10;
 
 //------------------------------------------------------------------------------
 // Typedefs
@@ -1185,6 +1187,74 @@ class Linter extends EventEmitter {
     getDeclaredVariables(node) {
         return (this.scopeManager && this.scopeManager.getDeclaredVariables(node)) || [];
     }
+
+    /**
+     * Performs multiple autofix passes over the text until as many fixes as possible
+     * have been applied.
+     * @param {string} text The source text to apply fixes to.
+     * @param {Object} config The ESLint config object to use.
+     * @param {Object} options The ESLint options object to use.
+     * @param {string} options.filename The filename from which the text was read.
+     * @param {boolean} options.allowInlineConfig Flag indicating if inline comments
+     *      should be allowed.
+     * @returns {Object} The result of the fix operation as returned from the
+     *      SourceCodeFixer.
+     */
+    verifyAndFix(text, config, options) {
+        let messages = [],
+            fixedResult,
+            fixed = false,
+            passNumber = 0;
+
+        /**
+         * This loop continues until one of the following is true:
+         *
+         * 1. No more fixes have been applied.
+         * 2. Ten passes have been made.
+         *
+         * That means anytime a fix is successfully applied, there will be another pass.
+         * Essentially, guaranteeing a minimum of two passes.
+         */
+        do {
+            passNumber++;
+
+            debug(`Linting code for ${options.filename} (pass ${passNumber})`);
+            messages = this.verify(text, config, options);
+
+            debug(`Generating fixed text for ${options.filename} (pass ${passNumber})`);
+            fixedResult = SourceCodeFixer.applyFixes(this.getSourceCode(), messages);
+
+            // stop if there are any syntax errors.
+            // 'fixedResult.output' is a empty string.
+            if (messages.length === 1 && messages[0].fatal) {
+                break;
+            }
+
+            // keep track if any fixes were ever applied - important for return value
+            fixed = fixed || fixedResult.fixed;
+
+            // update to use the fixed output instead of the original text
+            text = fixedResult.output;
+
+        } while (
+            fixedResult.fixed &&
+            passNumber < MAX_AUTOFIX_PASSES
+        );
+
+        /*
+         * If the last result had fixes, we need to lint again to be sure we have
+         * the most up-to-date information.
+         */
+        if (fixedResult.fixed) {
+            fixedResult.messages = this.verify(text, config, options);
+        }
+
+        // ensure the last result properly reflects if fixes were done
+        fixedResult.fixed = fixed;
+        fixedResult.output = text;
+
+        return fixedResult;
+    }
 }
 
 // methods that exist on SourceCode object
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index 82268975d..5a8feee8f 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -816,7 +816,6 @@ module.exports = {
 
             offsets.ignoreToken(operator);
             offsets.ignoreToken(tokensAfterOperator[0]);
-            offsets.setDesiredOffset(tokensAfterOperator[0], sourceCode.getFirstToken(node), 1);
             offsets.setDesiredOffsets(tokensAfterOperator, tokensAfterOperator[0], 1);
         }
 
@@ -882,6 +881,13 @@ module.exports = {
 
                 // We only want to handle parens around expressions, so exclude parentheses that are in function parameters and function call arguments.
                 if (!parameterParens.has(leftParen) && !parameterParens.has(rightParen)) {
+                    const parenthesizedTokens = new Set(sourceCode.getTokensBetween(leftParen, rightParen));
+
+                    parenthesizedTokens.forEach(token => {
+                        if (!parenthesizedTokens.has(offsets.getFirstDependency(token))) {
+                            offsets.setDesiredOffset(token, leftParen, 1);
+                        }
+                    });
                     offsets.setDesiredOffset(sourceCode.getTokenAfter(leftParen), leftParen, 1);
                 }
 
@@ -1114,28 +1120,29 @@ module.exports = {
                 const tokenBeforeObject = sourceCode.getTokenBefore(node.object, token => astUtils.isNotOpeningParenToken(token) || parameterParens.has(token));
                 const firstObjectToken = tokenBeforeObject ? sourceCode.getTokenAfter(tokenBeforeObject) : sourceCode.ast.tokens[0];
                 const lastObjectToken = sourceCode.getTokenBefore(firstNonObjectToken);
+                const firstPropertyToken = node.computed ? firstNonObjectToken : secondNonObjectToken;
 
                 if (node.computed) {
 
                     // For computed MemberExpressions, match the closing bracket with the opening bracket.
                     offsets.matchIndentOf(firstNonObjectToken, sourceCode.getLastToken(node));
+                    offsets.setDesiredOffsets(getTokensAndComments(node.property), firstNonObjectToken, 1);
                 }
 
-                if (typeof options.MemberExpression === "number") {
-                    const firstPropertyToken = node.computed ? firstNonObjectToken : secondNonObjectToken;
+                /*
+                 * If the object ends on the same line that the property starts, match against the last token
+                 * of the object, to ensure that the MemberExpression is not indented.
+                 *
+                 * Otherwise, match against the first token of the object, e.g.
+                 * foo
+                 *   .bar
+                 *   .baz // <-- offset by 1 from `foo`
+                 */
+                const offsetBase = lastObjectToken.loc.end.line === firstPropertyToken.loc.start.line
+                    ? lastObjectToken
+                    : firstObjectToken;
 
-                    /*
-                     * If the object ends on the same line that the property starts, match against the last token
-                     * of the object, to ensure that the MemberExpression is not indented.
-                     *
-                     * Otherwise, match against the first token of the object, e.g.
-                     * foo
-                     *   .bar
-                     *   .baz // <-- offset by 1 from `foo`
-                     */
-                    const offsetBase = lastObjectToken.loc.end.line === firstPropertyToken.loc.start.line
-                        ? lastObjectToken
-                        : firstObjectToken;
+                if (typeof options.MemberExpression === "number") {
 
                     // Match the dot (for non-computed properties) or the opening bracket (for computed properties) against the object.
                     offsets.setDesiredOffset(firstNonObjectToken, offsetBase, options.MemberExpression);
@@ -1150,6 +1157,9 @@ module.exports = {
                     // If the MemberExpression option is off, ignore the dot and the first token of the property.
                     offsets.ignoreToken(firstNonObjectToken);
                     offsets.ignoreToken(secondNonObjectToken);
+
+                    // To ignore the property indentation, ensure that the property tokens depend on the ignored tokens.
+                    offsets.matchIndentOf(offsetBase, firstNonObjectToken);
                     offsets.matchIndentOf(firstNonObjectToken, secondNonObjectToken);
                 }
             },
diff --git a/lib/util/npm-util.js b/lib/util/npm-util.js
index 4859fabc9..057dbfea4 100644
--- a/lib/util/npm-util.js
+++ b/lib/util/npm-util.js
@@ -56,6 +56,20 @@ function installSyncSaveDev(packages) {
     childProcess.execSync(`npm i --save-dev ${packages}`, { stdio: "inherit", encoding: "utf8" });
 }
 
+/**
+ * Fetch `peerDependencies` of the given package by `npm show` command.
+ * @param {string} packageName The package name to fetch peerDependencies.
+ * @returns {string[]} Gotten peerDependencies.
+ */
+function fetchPeerDependencies(packageName) {
+    const fetchedText = childProcess.execSync(
+        `npm show --json ${packageName} peerDependencies`,
+        { encoding: "utf8" }
+    ).trim();
+
+    return JSON.parse(fetchedText || "{}");
+}
+
 /**
  * Check whether node modules are include in a project's package.json.
  *
@@ -140,6 +154,7 @@ function checkPackageJson(startDir) {
 
 module.exports = {
     installSyncSaveDev,
+    fetchPeerDependencies,
     checkDeps,
     checkDevDeps,
     checkPackageJson


Test patch:
diff --git a/tests/fixtures/ignored-paths/bad-package-json-ignore/package.json b/tests/fixtures/ignored-paths/bad-package-json-ignore/package.json
new file mode 100644
index 000000000..37174a849
--- /dev/null
+++ b/tests/fixtures/ignored-paths/bad-package-json-ignore/package.json
@@ -0,0 +1,11 @@
+{
+    "name": "mypackage",
+    "version": "0.0.1",
+    "eslintConfig": {
+        "env": {
+            "browser": true,
+            "node": true
+        }
+    },
+    "eslintIgnore": "hello.js"
+}
diff --git a/tests/fixtures/ignored-paths/package-json-ignore/package.json b/tests/fixtures/ignored-paths/package-json-ignore/package.json
new file mode 100644
index 000000000..05436bdb5
--- /dev/null
+++ b/tests/fixtures/ignored-paths/package-json-ignore/package.json
@@ -0,0 +1,11 @@
+{
+    "name": "mypackage",
+    "version": "0.0.1",
+    "eslintConfig": {
+        "env": {
+            "browser": true,
+            "node": true
+        }
+    },
+    "eslintIgnore": ["hello.js", "world.js"]
+}
diff --git a/tests/fixtures/ignored-paths/package.json b/tests/fixtures/ignored-paths/package.json
new file mode 100644
index 000000000..05436bdb5
--- /dev/null
+++ b/tests/fixtures/ignored-paths/package.json
@@ -0,0 +1,11 @@
+{
+    "name": "mypackage",
+    "version": "0.0.1",
+    "eslintConfig": {
+        "env": {
+            "browser": true,
+            "node": true
+        }
+    },
+    "eslintIgnore": ["hello.js", "world.js"]
+}
diff --git a/tests/lib/config/config-initializer.js b/tests/lib/config/config-initializer.js
index d313dca5f..1a7d0a906 100644
--- a/tests/lib/config/config-initializer.js
+++ b/tests/lib/config/config-initializer.js
@@ -32,6 +32,7 @@ describe("configInitializer", () => {
     let fixtureDir,
         npmCheckStub,
         npmInstallStub,
+        npmFetchPeerDependenciesStub,
         init;
 
     const log = {
@@ -75,6 +76,14 @@ describe("configInitializer", () => {
             status[pkg] = false;
             return status;
         }, {}));
+        npmFetchPeerDependenciesStub = sinon
+            .stub(npmUtil, "fetchPeerDependencies")
+            .returns({
+                eslint: "^3.19.0",
+                "eslint-plugin-jsx-a11y": "^5.0.1",
+                "eslint-plugin-import": "^2.2.0",
+                "eslint-plugin-react": "^7.0.1"
+            });
         init = proxyquire("../../../lib/config/config-initializer", requireStubs);
     });
 
@@ -83,6 +92,7 @@ describe("configInitializer", () => {
         log.error.reset();
         npmInstallStub.restore();
         npmCheckStub.restore();
+        npmFetchPeerDependenciesStub.restore();
     });
 
     after(() => {
@@ -185,19 +195,19 @@ describe("configInitializer", () => {
             it("should support the airbnb style guide", () => {
                 const config = init.getConfigForStyleGuide("airbnb");
 
-                assert.deepEqual(config, { extends: "airbnb", installedESLint: true, plugins: ["react", "jsx-a11y", "import"] });
+                assert.deepEqual(config, { extends: "airbnb", installedESLint: true });
             });
 
             it("should support the airbnb base style guide", () => {
                 const config = init.getConfigForStyleGuide("airbnb-base");
 
-                assert.deepEqual(config, { extends: "airbnb-base", installedESLint: true, plugins: ["import"] });
+                assert.deepEqual(config, { extends: "airbnb-base", installedESLint: true });
             });
 
             it("should support the standard style guide", () => {
                 const config = init.getConfigForStyleGuide("standard");
 
-                assert.deepEqual(config, { extends: "standard", installedESLint: true, plugins: ["standard", "promise"] });
+                assert.deepEqual(config, { extends: "standard", installedESLint: true });
             });
 
             it("should throw when encountering an unsupported style guide", () => {
@@ -209,13 +219,31 @@ describe("configInitializer", () => {
             it("should install required sharable config", () => {
                 init.getConfigForStyleGuide("google");
                 assert(npmInstallStub.calledOnce);
-                assert.deepEqual(npmInstallStub.firstCall.args[0][1], "eslint-config-google");
+                assert(npmInstallStub.firstCall.args[0].some(name => name.startsWith("eslint-config-google@")));
             });
 
             it("should install ESLint if not installed locally", () => {
                 init.getConfigForStyleGuide("google");
                 assert(npmInstallStub.calledOnce);
-                assert.deepEqual(npmInstallStub.firstCall.args[0][0], "eslint");
+                assert(npmInstallStub.firstCall.args[0].some(name => name.startsWith("eslint@")));
+            });
+
+            it("should install peerDependencies of the sharable config", () => {
+                init.getConfigForStyleGuide("airbnb");
+
+                assert(npmFetchPeerDependenciesStub.calledOnce);
+                assert(npmFetchPeerDependenciesStub.firstCall.args[0] === "eslint-config-airbnb@latest");
+                assert(npmInstallStub.calledOnce);
+                assert.deepEqual(
+                    npmInstallStub.firstCall.args[0],
+                    [
+                        "eslint-config-airbnb@latest",
+                        "eslint@^3.19.0",
+                        "eslint-plugin-jsx-a11y@^5.0.1",
+                        "eslint-plugin-import@^2.2.0",
+                        "eslint-plugin-react@^7.0.1"
+                    ]
+                );
             });
         });
 
diff --git a/tests/lib/ignored-paths.js b/tests/lib/ignored-paths.js
index 07d96672d..1ef1f29cd 100644
--- a/tests/lib/ignored-paths.js
+++ b/tests/lib/ignored-paths.js
@@ -164,6 +164,51 @@ describe("IgnoredPaths", () => {
                 )
             );
         });
+
+        it("should use package.json's eslintIgnore files if no specified .eslintignore file", () => {
+            const ignoredPaths = new IgnoredPaths({ ignore: true, cwd: getFixturePath("package-json-ignore") });
+
+            assert.isTrue(ignoredPaths.contains("hello.js"));
+            assert.isTrue(ignoredPaths.contains("world.js"));
+        });
+
+        it("should not use package.json's eslintIgnore files if specified .eslintignore file", () => {
+            const ignoredPaths = new IgnoredPaths({ ignore: true, cwd: getFixturePath() });
+
+            assert.isFalse(ignoredPaths.contains("hello.js"));
+            assert.isFalse(ignoredPaths.contains("world.js"));
+            assert.isTrue(ignoredPaths.contains("sampleignorepattern"));
+        });
+
+        it("should error if package.json's eslintIgnore is not an array of file paths", () => {
+            assert.throws(() => {
+                const ignoredPaths = new IgnoredPaths({ ignore: true, cwd: getFixturePath("bad-package-json-ignore") });
+
+                assert.ok(ignoredPaths);
+            }, "Package.json eslintIgnore property requires an array of paths");
+        });
+    });
+
+    describe("caching file reads", () => {
+
+        let readFileSyncCount;
+
+        before(() => {
+            readFileSyncCount = sinon.spy(fs, "readFileSync");
+        });
+
+        after(() => {
+            readFileSyncCount.restore();
+        });
+
+        it("should cache readFileSync on same file paths", () => {
+            const ignoreFilePath = getFixturePath(".eslintignore");
+            const ignoredPaths = new IgnoredPaths({ ignore: true, cwd: getFixturePath() });
+
+            ignoredPaths.readIgnoreFile(ignoreFilePath);
+            assert.isTrue(ignoredPaths.contains(ignoreFilePath));
+            sinon.assert.calledOnce(readFileSyncCount);
+        });
     });
 
     describe("initialization with ignorePattern", () => {
diff --git a/tests/lib/linter.js b/tests/lib/linter.js
index ed5fb2238..9c47fafe5 100644
--- a/tests/lib/linter.js
+++ b/tests/lib/linter.js
@@ -70,4 +70,18 @@ describe("Linter", () => {
             });
         });
     });
+
+    describe("verifyAndFix", () => {
+        it("Fixes the code", () => {
+            const linter = new Linter();
+            const messages = linter.verifyAndFix("var a", {
+                rules: {
+                    semi: 2
+                }
+            }, { filename: "test.js" });
+
+            assert.equal(messages.output, "var a;", "Fixes were applied correctly");
+            assert.isTrue(messages.fixed);
+        });
+    });
 });
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index 335e8882f..fd2619ef9 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -2563,6 +2563,40 @@ ruleTester.run("indent", rule, {
             `,
             options: [4]
         },
+        {
+            code: unIndent`
+                [
+                ] || [
+                ]
+            `
+        },
+        {
+            code: unIndent`
+                (
+                    [
+                    ] || [
+                    ]
+                )
+            `
+        },
+        {
+            code: unIndent`
+                1
+                + (
+                    1
+                )
+            `
+        },
+        {
+            code: unIndent`
+                (
+                    foo && (
+                        bar ||
+                        baz
+                    )
+                )
+            `
+        },
         {
             code: unIndent`
                 var foo =
@@ -2983,6 +3017,41 @@ ruleTester.run("indent", rule, {
             `,
             options: [4, { flatTernaryExpressions: true }]
         },
+        {
+            code: unIndent`
+                function wrap() {
+                    return (
+                        foo ? bar :
+                        baz ? qux :
+                        foobar ? boop :
+                        /*else*/ beep
+                    )
+                }
+            `,
+            options: [4, { flatTernaryExpressions: true }]
+        },
+        {
+            code: unIndent`
+                function wrap() {
+                    return foo
+                        ? bar
+                        : baz
+                }
+            `,
+            options: [4, { flatTernaryExpressions: true }]
+        },
+        {
+            code: unIndent`
+                function wrap() {
+                    return (
+                        foo
+                            ? bar
+                            : baz
+                    )
+                }
+            `,
+            options: [4, { flatTernaryExpressions: true }]
+        },
         {
             code: unIndent`
                 foo(
@@ -3376,6 +3445,23 @@ ruleTester.run("indent", rule, {
             `,
             options: [4, { MemberExpression: "off" }]
         },
+        {
+            code: unIndent`
+                  foo = bar(
+                  ).baz(
+                  )
+            `,
+            options: [4, { MemberExpression: "off" }]
+        },
+        {
+            code: unIndent`
+                foo[
+                    bar ? baz :
+                    qux
+                ]
+            `,
+            options: [4, { flatTernaryExpressions: true }]
+        },
         {
             code: unIndent`
                   foo
@@ -7036,6 +7122,34 @@ ruleTester.run("indent", rule, {
             options: [4],
             errors: expectedErrors([2, 4, 8, "Identifier"])
         },
+        {
+            code: unIndent`
+                [
+                ] || [
+                    ]
+            `,
+            output: unIndent`
+                [
+                ] || [
+                ]
+            `,
+            errors: expectedErrors([3, 0, 4, "Punctuator"])
+        },
+        {
+            code: unIndent`
+                1
+                + (
+                        1
+                    )
+            `,
+            output: unIndent`
+                1
+                + (
+                    1
+                )
+            `,
+            errors: expectedErrors([[3, 4, 8, "Numeric"], [4, 0, 4, "Punctuator"]])
+        },
 
         // Template curlies
         {
diff --git a/tests/lib/util/npm-util.js b/tests/lib/util/npm-util.js
index 48a41aa50..c8c7d8f2d 100644
--- a/tests/lib/util/npm-util.js
+++ b/tests/lib/util/npm-util.js
@@ -187,4 +187,15 @@ describe("npmUtil", () => {
             stub.restore();
         });
     });
+
+    describe("fetchPeerDependencies()", () => {
+        it("should execute 'npm show --json <packageName> peerDependencies' command", () => {
+            const stub = sandbox.stub(childProcess, "execSync").returns("");
+
+            npmUtil.fetchPeerDependencies("desired-package");
+            assert(stub.calledOnce);
+            assert.equal(stub.firstCall.args[0], "npm show --json desired-package peerDependencies");
+            stub.restore();
+        });
+    });
 });