Repository: eslint/eslint
Pull request #9813 (2018-01-06 21:49:59)

Build: Fix JSDoc syntax errors
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

- [ ] Documentation update
- [ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
- [ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
- [ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
- [ ] Add autofixing to a rule
- [ ] Add a CLI option
- [ ] Add something to the core
- [x] Other, please explain: I fixed the `docs` script which was failing due to JSDoc syntax errors.

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**

I fixed the `docs` script that was failing due to JSDoc syntax errors.

- JSDoc doesn't yet support specifying array content, i.e. "[number,
  number]" is a syntax error, so I'm using "number[]" instead. (source:
  https://github.com/jsdoc3/jsdoc/issues/1073)

- JSDoc doesn't support multiline objects, e.g. returning report information
  was a syntax error, so I extracted it into a typedef, as well as the
  disable directive.

**Is there anything you'd like reviewers to focus on?**
  
- I added two additional `@typedef`s, which now show up in the docs. Is that acceptable or should I inline them?
- The `[number, number]` syntax isn't a valid way to describe arrays, so I had to turn it into `number[]`, which is less descriptive. I could perhaps extract it into a separate typedef and add a description, but it sounds like an overkill.

jsf-clabot: [![CLA assistant check](https://cla.js.foundation/pull/badge/not_signed)](https://cla.js.foundation/eslint/eslint?pullRequest=9813) <br/>Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla.js.foundation/eslint/eslint?pullRequest=9813) before we can accept your contribution.<br/>
silvenon: I'm not sure why my commit message is invalid. 😄 
j-f1: I think you have to have a colon (`:`) after `Fix`.
silvenon: @j-f1 lol, yeah, I added the colon at the wrong place. Now it works, yay. 🎉 

Patch:
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index b72425262..c774666e0 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -334,7 +334,7 @@ The `CLIEngine` is a constructor, and you can create a new instance by passing i
 * `cache` - Operate only on changed files (default: `false`). Corresponds to `--cache`.
 * `cacheFile` - Name of the file where the cache will be stored (default: `.eslintcache`). Corresponds to `--cache-file`. Deprecated: use `cacheLocation` instead.
 * `cacheLocation` - Name of the file or directory where the cache will be stored (default: `.eslintcache`). Corresponds to `--cache-location`.
-* `configFile` - The configuration file to use (default: null). Corresponds to `-c`.
+* `configFile` - The configuration file to use (default: null). If `useEslintrc` is true or not specified, this configuration will be merged with any configuration defined in `.eslintrc.*` files, with options in this configuration having precedence. Corresponds to `-c`.
 * `cwd` - Path to a directory that should be considered as the current working directory.
 * `envs` - An array of environments to load (default: empty array). Corresponds to `--env`.
 * `extensions` - An array of filename extensions that should be checked for code. The default is an array containing just `".js"`. Corresponds to `--ext`. It is only used in conjunction with directories, not with filenames or glob patterns.
@@ -820,9 +820,9 @@ In addition to the properties above, invalid test cases can also have the follow
     * `message` (string/regexp): The message for the error
     * `type` (string): The type of the reported AST node
     * `line` (number): The 1-based line number of the reported location
-    * `column` (number): The 0-based column number of the reported location
+    * `column` (number): The 1-based column number of the reported location
     * `endLine` (number): The 1-based line number of the end of the reported location
-    * `endColumn` (number): The 0-based column number of the end of the reported location
+    * `endColumn` (number): The 1-based column number of the end of the reported location
 
     If a string is provided as an error instead of an object, the string is used to assert the `message` of the error.
 * `output` (string, optional): Asserts the output that will be produced when using this rule for a single pass of autofixing (e.g. with the `--fix` command line flag). If this is `null`, asserts that none of the reported problems suggest autofixes.
diff --git a/docs/developer-guide/working-with-rules.md b/docs/developer-guide/working-with-rules.md
index 8c9db815c..f345f7cdc 100644
--- a/docs/developer-guide/working-with-rules.md
+++ b/docs/developer-guide/working-with-rules.md
@@ -2,10 +2,11 @@
 
 **Note:** This page covers the most recent rule format for ESLint >= 3.0.0. There is also a [deprecated rule format](./working-with-rules-deprecated.md).
 
-Each rule in ESLint has two files named with its identifier (for example, `no-extra-semi`).
+Each rule in ESLint has three files named with its identifier (for example, `no-extra-semi`).
 
 * in the `lib/rules` directory: a source file (for example, `no-extra-semi.js`)
 * in the `tests/lib/rules` directory: a test file (for example, `no-extra-semi.js`)
+* in the `docs/rules` directory: a Markdown documentation file (for example, `no-extra-semi.md`)
 
 **Important:** If you submit a **core** rule to the ESLint repository, you **must** follow some conventions explained below.
 
@@ -28,7 +29,8 @@ module.exports = {
         docs: {
             description: "disallow unnecessary semicolons",
             category: "Possible Errors",
-            recommended: true
+            recommended: true,
+            url: "https://eslint.org/docs/rules/no-extra-semi"
         },
         fixable: "code",
         schema: [] // no options
@@ -52,6 +54,7 @@ The source file for a rule exports an object with the following properties.
     * `description` (string) provides the short description of the rule in the [rules index](../rules/)
     * `category` (string) specifies the heading under which the rule is listed in the [rules index](../rules/)
     * `recommended` (boolean) is whether the `"extends": "eslint:recommended"` property in a [configuration file](../user-guide/configuring.md#extending-configuration-files) enables the rule
+    * `url` (string) specifies the URL at which the full documentation can be accessed
 
     In a custom rule or plugin, you can omit `docs` or include any properties that you need in it.
 
@@ -188,6 +191,7 @@ Instead of typing out messages in both the `context.report()` call and your test
 This allows you to avoid retyping error messages. It also prevents errors reported in different sections of your rule from having out-of-date messages.
 
 ```js
+{% raw %}
 // in your rule
 module.exports = {
     meta: {
@@ -204,7 +208,7 @@ module.exports = {
                         messageId: "avoidName",
                         data: {
                             name: "foo",
-                        },
+                        }
                     });
                 }
             }
@@ -214,14 +218,14 @@ module.exports = {
 
 // in the file to lint:
 
-var foo = 2
+var foo = 2;
 //  ^ error: Avoid using variables named 'foo'
 
 // In your tests:
-var rule = require('../../../lib/rules/no-insecure-random')
-var RuleTester = require('eslint').RuleTester
+var rule = require('../../../lib/rules/no-insecure-random');
+var RuleTester = require('eslint').RuleTester;
 
-var ruleTester = new RuleTester()
+var ruleTester = new RuleTester();
 ruleTester.run('my-rule', rule, {
   valid: ['bar', 'baz'],
 
@@ -231,11 +235,12 @@ ruleTester.run('my-rule', rule, {
       errors: [
         {
           messageId: 'foo',
-        },
-      ],
-    },
-  ],
-})
+        }
+      ]
+    }
+  ]
+});
+{% endraw %}
 ```
 
 ### Applying Fixes
diff --git a/docs/rules/keyword-spacing.md b/docs/rules/keyword-spacing.md
index b8d97a73e..becc9ef32 100644
--- a/docs/rules/keyword-spacing.md
+++ b/docs/rules/keyword-spacing.md
@@ -59,44 +59,44 @@ if (foo) {
     //...
 }
 
-// no conflict with `array-bracket-spacing`
+// Avoid conflict with `array-bracket-spacing`
 let a = [this];
 let b = [function() {}];
 
-// no conflict with `arrow-spacing`
+// Avoid conflict with `arrow-spacing`
 let a = ()=> this.foo;
 
-// no conflict with `block-spacing`
+// Avoid conflict with `block-spacing`
 {function foo() {}}
 
-// no conflict with `comma-spacing`
+// Avoid conflict with `comma-spacing`
 let a = [100,this.foo, this.bar];
 
-// not conflict with `computed-property-spacing`
+// Avoid conflict with `computed-property-spacing`
 obj[this.foo] = 0;
 
-// no conflict with `generator-star-spacing`
+// Avoid conflict with `generator-star-spacing`
 function *foo() {}
 
-// no conflict with `key-spacing`
+// Avoid conflict with `key-spacing`
 let obj = {
     foo:function() {}
 };
 
-// no conflict with `object-curly-spacing`
+// Avoid conflict with `object-curly-spacing`
 let obj = {foo: this};
 
-// no conflict with `semi-spacing`
+// Avoid conflict with `semi-spacing`
 let a = this;function foo() {}
 
-// no conflict with `space-in-parens`
+// Avoid conflict with `space-in-parens`
 (function () {})();
 
-// no conflict with `space-infix-ops`
+// Avoid conflict with `space-infix-ops`
 if ("foo"in {foo: 0}) {}
 if (10+this.foo<= this.bar) {}
 
-// no conflict with `jsx-curly-spacing`
+// Avoid conflict with `jsx-curly-spacing`
 let a = <A foo={this.foo} bar={function(){}} />
 ```
 
@@ -157,57 +157,57 @@ if (foo) {
     //...
 }
 
-// not conflict with `array-bracket-spacing`
+// Avoid conflict with `array-bracket-spacing`
 let a = [this];
 
-// not conflict with `arrow-spacing`
+// Avoid conflict with `arrow-spacing`
 let a = ()=> this.foo;
 
-// not conflict with `comma-spacing`
+// Avoid conflict with `comma-spacing`
 let a = [100, this.foo, this.bar];
 
-// not conflict with `computed-property-spacing`
+// Avoid conflict with `computed-property-spacing`
 obj[this.foo] = 0;
 
-// not conflict with `generator-star-spacing`
+// Avoid conflict with `generator-star-spacing`
 function* foo() {}
 
-// not conflict with `key-spacing`
+// Avoid conflict with `key-spacing`
 let obj = {
     foo:function() {}
 };
 
-// not conflict with `func-call-spacing`
+// Avoid conflict with `func-call-spacing`
 class A {
     constructor() {
         super();
     }
 }
 
-// not conflict with `object-curly-spacing`
+// Avoid conflict with `object-curly-spacing`
 let obj = {foo: this};
 
-// not conflict with `semi-spacing`
+// Avoid conflict with `semi-spacing`
 let a = this;function foo() {}
 
-// not conflict with `space-before-function-paren`
+// Avoid conflict with `space-before-function-paren`
 function() {}
 
-// no conflict with `space-infix-ops`
+// Avoid conflict with `space-infix-ops`
 if ("foo"in{foo: 0}) {}
 if (10+this.foo<= this.bar) {}
 
-// no conflict with `space-unary-ops`
+// Avoid conflict with `space-unary-ops`
 function* foo(a) {
     return yield+a;
 }
 
-// no conflict with `yield-star-spacing`
+// Avoid conflict with `yield-star-spacing`
 function* foo(a) {
     return yield* a;
 }
 
-// no conflict with `jsx-curly-spacing`
+// Avoid conflict with `jsx-curly-spacing`
 let a = <A foo={this.foo} bar={function(){}} />
 ```
 
diff --git a/docs/rules/no-useless-escape.md b/docs/rules/no-useless-escape.md
index 2bb0c1cc3..6088c5cb0 100644
--- a/docs/rules/no-useless-escape.md
+++ b/docs/rules/no-useless-escape.md
@@ -41,8 +41,8 @@ Examples of **correct** code for this rule:
 "\371";
 "xs\u2111";
 `\``;
-`\${${foo}\}`;
-`$\{${foo}\}`;
+`\${${foo}}`;
+`$\{${foo}}`;
 /\\/g;
 /\t/g;
 /\w\$\*\^\./;
diff --git a/docs/rules/object-property-newline.md b/docs/rules/object-property-newline.md
index 8cc73b05e..15d8ee0a0 100644
--- a/docs/rules/object-property-newline.md
+++ b/docs/rules/object-property-newline.md
@@ -74,7 +74,7 @@ Another benefit of this rule is specificity of diffs when a property is changed:
 
 ### Optional Exception
 
-The rule offers one object option, `allowMultiplePropertiesPerLine`. If you set it to `true`, object literals such as the first two above, with all property specifications on the same line, will be permitted, but one like
+The rule offers one object option, `allowAllPropertiesOnSameLine` (a deprecated synonym is `allowMultiplePropertiesPerLine`). If you set it to `true`, object literals such as the first two above, with all property specifications on the same line, will be permitted, but one like
 
 ```js
 const newObject = {
@@ -172,7 +172,7 @@ As illustrated above, the `--fix` option, applied to this rule, does not comply
 
 ## Examples
 
-Examples of **incorrect** code for this rule, with no object option or with `allowMultiplePropertiesPerLine` set to `false`:
+Examples of **incorrect** code for this rule, with no object option or with `allowAllPropertiesOnSameLine` set to `false`:
 
 ```js
 /*eslint object-property-newline: "error"*/
@@ -208,7 +208,7 @@ const obj5 = {
 ]: true};
 ```
 
-Examples of **correct** code for this rule, with no object option or with `allowMultiplePropertiesPerLine` set to `false`:
+Examples of **correct** code for this rule, with no object option or with `allowAllPropertiesOnSameLine` set to `false`:
 
 ```js
 /*eslint object-property-newline: "error"*/
@@ -238,10 +238,10 @@ const obj3 = {
 };
 ```
 
-Examples of additional **correct** code for this rule with the `{ "allowMultiplePropertiesPerLine": true }` option:
+Examples of additional **correct** code for this rule with the `{ "allowAllPropertiesOnSameLine": true }` option:
 
 ```js
-/*eslint object-property-newline: ["error", { "allowMultiplePropertiesPerLine": true }]*/
+/*eslint object-property-newline: ["error", { "allowAllPropertiesOnSameLine": true }]*/
 
 const obj = { foo: "foo", bar: "bar", baz: "baz" };
 
diff --git a/docs/user-guide/command-line-interface.md b/docs/user-guide/command-line-interface.md
index 8235f7b6c..39a297c79 100644
--- a/docs/user-guide/command-line-interface.md
+++ b/docs/user-guide/command-line-interface.md
@@ -30,8 +30,8 @@ The command line utility has several options. You can view the options by runnin
 eslint [options] file.js [file.js] [dir]
 
 Basic configuration:
-  -c, --config path::String      Use configuration from this file or shareable config
-  --no-eslintrc                  Disable use of configuration from .eslintrc
+  --no-eslintrc                  Disable use of configuration from .eslintrc.*
+  -c, --config path::String      Use this configuration, overriding .eslintrc.* config options if present
   --env [String]                 Specify environments
   --ext [String]                 Specify JavaScript file extensions - default: .js
   --global [String]              Define global variables
@@ -92,6 +92,14 @@ Example:
 
 ### Basic configuration
 
+#### `--no-eslintrc`
+
+Disables use of configuration from `.eslintrc.*` and `package.json` files.
+
+Example:
+
+    eslint --no-eslintrc file.js
+
 #### `-c`, `--config`
 
 This option allows you to specify an additional configuration file for ESLint (see [Configuring ESLint](configuring) for more).
@@ -110,13 +118,7 @@ Example:
 
 This example directly uses the sharable config `eslint-config-myconfig`.
 
-#### `--no-eslintrc`
-
-Disables use of configuration from `.eslintrc` and `package.json` files.
-
-Example:
-
-    eslint --no-eslintrc file.js
+If `.eslintrc.*` and/or `package.json` files are also used for configuration (i.e., `--no-eslintrc` was not specified), the configurations will be merged. Options from this configuration file have precedence over the options from `.eslintrc.*` and `package.json` files.
 
 #### `--env`
 
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 8b1bcba4a..098fcdf43 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -3,7 +3,7 @@
 ESLint is designed to be completely configurable, meaning you can turn off every rule and run only with basic syntax validation, or mix and match the bundled rules and your custom rules to make ESLint perfect for your project. There are two primary ways to configure ESLint:
 
 1. **Configuration Comments** - use JavaScript comments to embed configuration information directly into a file.
-1. **Configuration Files** - use a JavaScript, JSON or YAML file to specify configuration information for an entire directory (other than your home directory) and all of its subdirectories. This can be in the form of an [.eslintrc.*](#configuration-file-formats) file or an `eslintConfig` field in a [`package.json`](https://docs.npmjs.com/files/package.json) file, both of which ESLint will look for and read automatically, or you can specify a configuration file on the [command line](command-line-interface).
+1. **Configuration Files** - use a JavaScript, JSON or YAML file to specify configuration information for an entire directory (other than your home directory) and all of its subdirectories. This can be in the form of an [`.eslintrc.*`](#configuration-file-formats) file or an `eslintConfig` field in a [`package.json`](https://docs.npmjs.com/files/package.json) file, both of which ESLint will look for and read automatically, or you can specify a configuration file on the [command line](command-line-interface).
 
     If you have a configuration file in your home directory (generally `~/`), ESLint uses it **only** if ESLint cannot find any other configuration file.
 
@@ -26,7 +26,7 @@ For ES6 syntax, use `{ "parserOptions": { "ecmaVersion": 6 } }`; for new ES6 glo
 { "es6": true } }` (this setting enables ES6 syntax automatically).
 Parser options are set in your `.eslintrc.*` file by using the `parserOptions` property. The available options are:
 
-* `ecmaVersion` - set to 3, 5 (default), 6, 7, or 8 to specify the version of ECMAScript syntax you want to use. You can also set to 2015 (same as 6), 2016 (same as 7), or 2017 (same as 8) to use the year-based naming.
+* `ecmaVersion` - set to 3, 5 (default), 6, 7, 8, or 9 to specify the version of ECMAScript syntax you want to use. You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), or 2018 (same as 9) to use the year-based naming.
 * `sourceType` - set to `"script"` (default) or `"module"` if your code is in ECMAScript modules.
 * `ecmaFeatures` - an object indicating which additional language features you'd like to use:
     * `globalReturn` - allow `return` statements in the global scope
@@ -453,11 +453,15 @@ And in YAML:
 
 ## Using Configuration Files
 
-There are two ways to use configuration files. The first is to save the file wherever you would like and pass its location to the CLI using the `-c` option, such as:
+There are two ways to use configuration files.
+
+The first way to use configuration files is via `.eslintrc.*` and `package.json` files. ESLint will automatically look for them in the directory of the file to be linted, and in successive parent directories all the way up to the root directory of the filesystem (unless `root: true` is specified). This option is useful when you want different configurations for different parts of a project or when you want others to be able to use ESLint directly without needing to remember to pass in the configuration file.
+
+The second is to save the file wherever you would like and pass its location to the CLI using the `-c` option, such as:
 
     eslint -c myconfig.json myfiletotest.js
 
-The second way to use configuration files is via `.eslintrc.*` and `package.json` files. ESLint will automatically look for them in the directory of the file to be linted, and in successive parent directories all the way up to the root directory of the filesystem. This option is useful when you want different configurations for different parts of a project or when you want others to be able to use ESLint directly without needing to remember to pass in the configuration file.
+If you are using one configuration file and want ESLint to ignore any `.eslintrc.*` files, make sure to use `--no-eslintrc` along with the `-c` flag.
 
 In each case, the settings in the configuration file override default settings.
 
@@ -548,15 +552,15 @@ The complete configuration hierarchy, from highest precedence to lowest preceden
     1. `/*global*/`
     1. `/*eslint*/`
     1. `/*eslint-env*/`
-2. Command line options:
+1. Command line options (or CLIEngine equivalents):
     1. `--global`
     1. `--rule`
     1. `--env`
     1. `-c`, `--config`
-3. Project-level configuration:
+1. Project-level configuration:
     1. `.eslintrc.*` or `package.json` file in same directory as linted file
     1. Continue searching for `.eslintrc` and `package.json` files in ancestor directories (parent has highest precedence, then grandparent, etc.), up to and including the root directory or until a config with `"root": true` is found.
-    1. In the absence of any configuration from (1) thru (3), fall back to a personal default configuration in  `~/.eslintrc`.
+1. In the absence of any configuration from (1) thru (3), fall back to a personal default configuration in  `~/.eslintrc`.
 
 ## Extending Configuration Files
 
diff --git a/lib/config/config-validator.js b/lib/config/config-validator.js
index 3d98b5104..1a5b3ef13 100644
--- a/lib/config/config-validator.js
+++ b/lib/config/config-validator.js
@@ -98,7 +98,8 @@ function validateRuleSchema(rule, localOptions) {
  * @param {{create: Function}|null} rule The rule that the config is being validated for
  * @param {string} ruleId The rule's unique name.
  * @param {array|number} options The given options for the rule.
- * @param {string} source The name of the configuration source to report in any errors.
+ * @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
+ * no source is prepended to the message.
  * @returns {void}
  */
 function validateRuleOptions(rule, ruleId, options, source) {
@@ -112,7 +113,13 @@ function validateRuleOptions(rule, ruleId, options, source) {
             validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
         }
     } catch (err) {
-        throw new Error(`${source}:\n\tConfiguration for rule "${ruleId}" is invalid:\n${err.message}`);
+        const enhancedMessage = `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
+
+        if (typeof source === "string") {
+            throw new Error(`${source}:\n\t${enhancedMessage}`);
+        } else {
+            throw new Error(enhancedMessage);
+        }
     }
 }
 
diff --git a/lib/linter.js b/lib/linter.js
index 2238c5be0..d71a79a7c 100755
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -48,6 +48,14 @@ const MAX_AUTOFIX_PASSES = 10;
  * @property {Object|null} visitorKeys The visitor keys to traverse this AST.
  */
 
+/**
+ * @typedef {Object} DisableDirective
+ * @property {("disable"|"enable"|"disable-line"|"disable-next-line")} type
+ * @property {number} line
+ * @property {number} column
+ * @property {(string|null)} ruleId
+ */
+
 //------------------------------------------------------------------------------
 // Helpers
 //------------------------------------------------------------------------------
@@ -260,12 +268,7 @@ function addDeclaredGlobals(globalScope, config, envContext) {
  * @param {{line: number, column: number}} loc The 0-based location of the comment token
  * @param {string} value The value after the directive in the comment
  * comment specified no specific rules, so it applies to all rules (e.g. `eslint-disable`)
- * @returns {{
- *     type: ("disable"|"enable"|"disable-line"|"disable-next-line"),
- *     line: number,
- *     column: number,
- *     ruleId: (string|null)
- * }[]} Directives from the comment
+ * @returns {DisableDirective[]} Directives from the comment
  */
 function createDisableDirectives(type, loc, value) {
     const ruleIds = Object.keys(parseListConfig(value));
@@ -282,17 +285,8 @@ function createDisableDirectives(type, loc, value) {
  * @param {ASTNode} ast The top node of the AST.
  * @param {Object} config The existing configuration data.
  * @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
- * @returns {{
- *      config: Object,
- *      problems: Problem[],
- *      disableDirectives: {
- *          type: ("disable"|"enable"|"disable-line"|"disable-next-line"),
- *          line: number,
- *          column: number,
- *          ruleId: (string|null)
- *      }[]
- * }} Modified config object, along with any problems encountered
- * while parsing config comments
+ * @returns {{config: Object, problems: Problem[], disableDirectives: DisableDirective[]}}
+ * Modified config object, along with any problems encountered while parsing config comments
  */
 function modifyConfigsFromComments(filename, ast, config, ruleMapper) {
 
@@ -340,7 +334,21 @@ function modifyConfigsFromComments(filename, ast, config, ruleMapper) {
                             Object.keys(parseResult.config).forEach(name => {
                                 const ruleValue = parseResult.config[name];
 
-                                validator.validateRuleOptions(ruleMapper(name), name, ruleValue, `${filename} line ${comment.loc.start.line}`);
+                                try {
+                                    validator.validateRuleOptions(ruleMapper(name), name, ruleValue);
+                                } catch (err) {
+                                    problems.push({
+                                        ruleId: name,
+                                        severity: 2,
+                                        source: null,
+                                        message: err.message,
+                                        line: comment.loc.start.line,
+                                        column: comment.loc.start.column + 1,
+                                        endLine: comment.loc.end.line,
+                                        endColumn: comment.loc.end.column + 1,
+                                        nodeType: null
+                                    });
+                                }
                                 commentRules[name] = ruleValue;
                             });
                         } else {
diff --git a/lib/options.js b/lib/options.js
index c8005d444..9265d151d 100644
--- a/lib/options.js
+++ b/lib/options.js
@@ -26,17 +26,17 @@ module.exports = optionator({
         {
             heading: "Basic configuration"
         },
-        {
-            option: "config",
-            alias: "c",
-            type: "path::String",
-            description: "Use configuration from this file or shareable config"
-        },
         {
             option: "eslintrc",
             type: "Boolean",
             default: "true",
-            description: "Disable use of configuration from .eslintrc"
+            description: "Disable use of configuration from .eslintrc.*"
+        },
+        {
+            option: "config",
+            alias: "c",
+            type: "path::String",
+            description: "Use this configuration, overriding .eslintrc.* config options if present"
         },
         {
             option: "env",
diff --git a/lib/report-translator.js b/lib/report-translator.js
index 8e5b587f9..7893a1f7a 100644
--- a/lib/report-translator.js
+++ b/lib/report-translator.js
@@ -28,6 +28,22 @@ const interpolate = require("./util/interpolate");
  * @property {Function} [fix] The function to call that creates a fix command.
  */
 
+/**
+ * Information about the report
+ * @typedef {Object} ReportInfo
+ * @property {string} ruleId
+ * @property {(0|1|2)} severity
+ * @property {(string|undefined)} message
+ * @property {(string|undefined)} messageId
+ * @property {number} line
+ * @property {number} column
+ * @property {(number|undefined)} endLine
+ * @property {(number|undefined)} endColumn
+ * @property {(string|null)} nodeType
+ * @property {string} source
+ * @property {({text: string, range: (number[]|null)}|null)} fix
+ */
+
 //------------------------------------------------------------------------------
 // Module Definition
 //------------------------------------------------------------------------------
@@ -121,7 +137,7 @@ function compareFixesByRange(a, b) {
  * Merges the given fixes array into one.
  * @param {Fix[]} fixes The fixes to merge.
  * @param {SourceCode} sourceCode The source code object to get the text between fixes.
- * @returns {{text: string, range: [number, number]}} The merged fixes
+ * @returns {{text: string, range: number[]}} The merged fixes
  */
 function mergeFixes(fixes, sourceCode) {
     if (fixes.length === 0) {
@@ -158,7 +174,7 @@ function mergeFixes(fixes, sourceCode) {
  * If the descriptor retrieves multiple fixes, this merges those to one.
  * @param {MessageDescriptor} descriptor The report descriptor.
  * @param {SourceCode} sourceCode The source code object to get text between fixes.
- * @returns {({text: string, range: [number, number]}|null)} The fix for the descriptor
+ * @returns {({text: string, range: number[]}|null)} The fix for the descriptor
  */
 function normalizeFixes(descriptor, sourceCode) {
     if (typeof descriptor.fix !== "function") {
@@ -177,27 +193,15 @@ function normalizeFixes(descriptor, sourceCode) {
 
 /**
  * Creates information about the report from a descriptor
- * @param {{
- *     ruleId: string,
- *     severity: (0|1|2),
- *     node: (ASTNode|null),
- *     message: string,
- *     loc: {start: SourceLocation, end: (SourceLocation|null)},
- *     fix: ({text: string, range: [number, number]}|null),
- *     sourceLines: string[]
- * }} options Information about the problem
- * @returns {function(...args): {
- *      ruleId: string,
- *      severity: (0|1|2),
- *      message: string,
- *      line: number,
- *      column: number,
- *      endLine: (number|undefined),
- *      endColumn: (number|undefined),
- *      nodeType: (string|null),
- *      source: string,
- *      fix: ({text: string, range: [number, number]}|null)
- * }} Information about the report
+ * @param {Object} options Information about the problem
+ * @param {string} options.ruleId Rule ID
+ * @param {(0|1|2)} options.severity Rule severity
+ * @param {(ASTNode|null)} options.node Node
+ * @param {string} options.message Error message
+ * @param {{start: SourceLocation, end: (SourceLocation|null)}} options.loc Start and end location
+ * @param {{text: string, range: (number[]|null)}} options.fix The fix object
+ * @param {string[]} options.sourceLines Source lines
+ * @returns {function(...args): ReportInfo} Function that returns information about the report
  */
 function createProblem(options) {
     const problem = {
@@ -235,20 +239,7 @@ function createProblem(options) {
  * problem for the Node.js API.
  * @param {{ruleId: string, severity: number, sourceCode: SourceCode, messageIds: Object}} metadata Metadata for the reported problem
  * @param {SourceCode} sourceCode The `SourceCode` instance for the text being linted
- * @returns {function(...args): {
- *      ruleId: string,
- *      severity: (0|1|2),
- *      message: (string|undefined),
- *      messageId: (string|undefined),
- *      line: number,
- *      column: number,
- *      endLine: (number|undefined),
- *      endColumn: (number|undefined),
- *      nodeType: (string|null),
- *      source: string,
- *      fix: ({text: string, range: [number, number]}|null)
- * }}
- * Information about the report
+ * @returns {function(...args): ReportInfo} Function that returns information about the report
  */
 
 module.exports = function createReportTranslator(metadata) {
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index 2159880f8..79a0f25ca 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -442,6 +442,7 @@ class OffsetStorage {
                 const offset = (
                     offsetInfo.from &&
                     offsetInfo.from.loc.start.line === token.loc.start.line &&
+                    !/^\s*?\n/.test(token.value) &&
                     !offsetInfo.force
                 ) ? 0 : offsetInfo.offset * this._indentSize;
 
@@ -836,7 +837,7 @@ module.exports = {
                     const previousElement = elements[index - 1];
                     const firstTokenOfPreviousElement = previousElement && getFirstToken(previousElement);
 
-                    if (previousElement && sourceCode.getLastToken(previousElement).loc.start.line > startToken.loc.end.line) {
+                    if (previousElement && sourceCode.getLastToken(previousElement).loc.end.line > startToken.loc.end.line) {
                         offsets.setDesiredOffsets(element.range, firstTokenOfPreviousElement, 0);
                     }
                 }
@@ -1094,8 +1095,8 @@ module.exports = {
                     const questionMarkToken = sourceCode.getFirstTokenBetween(node.test, node.consequent, token => token.type === "Punctuator" && token.value === "?");
                     const colonToken = sourceCode.getFirstTokenBetween(node.consequent, node.alternate, token => token.type === "Punctuator" && token.value === ":");
 
-                    const firstConsequentToken = sourceCode.getTokenAfter(questionMarkToken, { includeComments: true });
-                    const lastConsequentToken = sourceCode.getTokenBefore(colonToken, { includeComments: true });
+                    const firstConsequentToken = sourceCode.getTokenAfter(questionMarkToken);
+                    const lastConsequentToken = sourceCode.getTokenBefore(colonToken);
                     const firstAlternateToken = sourceCode.getTokenAfter(colonToken);
 
                     offsets.setDesiredOffset(questionMarkToken, firstToken, 1);
diff --git a/lib/rules/no-eq-null.js b/lib/rules/no-eq-null.js
index befb9d46f..22dbd49d4 100644
--- a/lib/rules/no-eq-null.js
+++ b/lib/rules/no-eq-null.js
@@ -31,7 +31,7 @@ module.exports = {
 
                 if (node.right.type === "Literal" && node.right.raw === "null" && badOperator ||
                         node.left.type === "Literal" && node.left.raw === "null" && badOperator) {
-                    context.report({ node, message: "Use ‘===’ to compare with ‘null’." });
+                    context.report({ node, message: "Use '===' to compare with null." });
                 }
             }
         };
diff --git a/lib/rules/object-property-newline.js b/lib/rules/object-property-newline.js
index 56ca26940..65baf0a95 100644
--- a/lib/rules/object-property-newline.js
+++ b/lib/rules/object-property-newline.js
@@ -22,7 +22,10 @@ module.exports = {
             {
                 type: "object",
                 properties: {
-                    allowMultiplePropertiesPerLine: {
+                    allowAllPropertiesOnSameLine: {
+                        type: "boolean"
+                    },
+                    allowMultiplePropertiesPerLine: { // Deprecated
                         type: "boolean"
                     }
                 },
@@ -34,7 +37,10 @@ module.exports = {
     },
 
     create(context) {
-        const allowSameLine = context.options[0] && Boolean(context.options[0].allowMultiplePropertiesPerLine);
+        const allowSameLine = context.options[0] && (
+            Boolean(context.options[0].allowAllPropertiesOnSameLine) ||
+            Boolean(context.options[0].allowMultiplePropertiesPerLine) // Deprecated
+        );
         const errorMessage = allowSameLine
             ? "Object properties must go on a new line if they aren't all on the same line."
             : "Object properties must go on a new line.";
diff --git a/lib/rules/prefer-destructuring.js b/lib/rules/prefer-destructuring.js
index e9d02da3a..112ea6461 100644
--- a/lib/rules/prefer-destructuring.js
+++ b/lib/rules/prefer-destructuring.js
@@ -165,8 +165,10 @@ module.exports = {
             if (shouldCheck(reportNode.type, "object")) {
                 const property = rightNode.property;
 
-                if ((property.type === "Literal" && leftNode.name === property.value) || (property.type === "Identifier" &&
-                    leftNode.name === property.name)) {
+                if (
+                    (property.type === "Literal" && leftNode.name === property.value) ||
+                    (property.type === "Identifier" && leftNode.name === property.name && !rightNode.computed)
+                ) {
                     report(reportNode, "object");
                 }
             }
diff --git a/lib/rules/valid-jsdoc.js b/lib/rules/valid-jsdoc.js
index 5e1af10de..c213c50f1 100644
--- a/lib/rules/valid-jsdoc.js
+++ b/lib/rules/valid-jsdoc.js
@@ -57,7 +57,9 @@ module.exports = {
                 },
                 additionalProperties: false
             }
-        ]
+        ],
+
+        fixable: "code"
     },
 
     create(context) {
@@ -145,23 +147,35 @@ module.exports = {
         /**
          * Extract the current and expected type based on the input type object
          * @param {Object} type JSDoc tag
-         * @returns {Object} current and expected type object
+         * @returns {{currentType: Doctrine.Type, expectedTypeName: string}} The current type annotation and
+         * the expected name of the annotation
          * @private
          */
         function getCurrentExpectedTypes(type) {
             let currentType;
 
             if (type.name) {
-                currentType = type.name;
+                currentType = type;
             } else if (type.expression) {
-                currentType = type.expression.name;
+                currentType = type.expression;
             }
 
-            const expectedType = currentType && preferType[currentType];
-
             return {
                 currentType,
-                expectedType
+                expectedTypeName: currentType && preferType[currentType.name]
+            };
+        }
+
+        /**
+         * Gets the location of a JSDoc node in a file
+         * @param {Token} jsdocComment The comment that this node is parsed from
+         * @param {{range: number[]}} parsedJsdocNode A tag or other node which was parsed from this comment
+         * @returns {{start: SourceLocation, end: SourceLocation}} The 0-based source location for the tag
+         */
+        function getAbsoluteRange(jsdocComment, parsedJsdocNode) {
+            return {
+                start: sourceCode.getLocFromIndex(jsdocComment.range[0] + 2 + parsedJsdocNode.range[0]),
+                end: sourceCode.getLocFromIndex(jsdocComment.range[0] + 2 + parsedJsdocNode.range[1])
             };
         }
 
@@ -204,14 +218,21 @@ module.exports = {
             elements.forEach(validateType.bind(null, jsdocNode));
 
             typesToCheck.forEach(typeToCheck => {
-                if (typeToCheck.expectedType &&
-                    typeToCheck.expectedType !== typeToCheck.currentType) {
+                if (typeToCheck.expectedTypeName &&
+                    typeToCheck.expectedTypeName !== typeToCheck.currentType.name) {
                     context.report({
                         node: jsdocNode,
-                        message: "Use '{{expectedType}}' instead of '{{currentType}}'.",
+                        message: "Use '{{expectedTypeName}}' instead of '{{currentTypeName}}'.",
+                        loc: getAbsoluteRange(jsdocNode, typeToCheck.currentType),
                         data: {
-                            currentType: typeToCheck.currentType,
-                            expectedType: typeToCheck.expectedType
+                            currentTypeName: typeToCheck.currentType.name,
+                            expectedTypeName: typeToCheck.expectedTypeName
+                        },
+                        fix(fixer) {
+                            return fixer.replaceTextRange(
+                                typeToCheck.currentType.range.map(indexInComment => jsdocNode.range[0] + 2 + indexInComment),
+                                typeToCheck.expectedTypeName
+                            );
                         }
                     });
                 }
@@ -227,8 +248,8 @@ module.exports = {
         function checkJSDoc(node) {
             const jsdocNode = sourceCode.getJSDocComment(node),
                 functionData = fns.pop(),
-                params = Object.create(null),
-                paramsTags = [];
+                paramTagsByName = Object.create(null),
+                paramTags = [];
             let hasReturns = false,
                 returnsTag,
                 hasConstructor = false,
@@ -244,7 +265,8 @@ module.exports = {
                     jsdoc = doctrine.parse(jsdocNode.value, {
                         strict: true,
                         unwrap: true,
-                        sloppy: true
+                        sloppy: true,
+                        range: true
                     });
                 } catch (ex) {
 
@@ -264,7 +286,7 @@ module.exports = {
                         case "param":
                         case "arg":
                         case "argument":
-                            paramsTags.push(tag);
+                            paramTags.push(tag);
                             break;
 
                         case "return":
@@ -297,7 +319,29 @@ module.exports = {
 
                     // check tag preferences
                     if (prefer.hasOwnProperty(tag.title) && tag.title !== prefer[tag.title]) {
-                        context.report({ node: jsdocNode, message: "Use @{{name}} instead.", data: { name: prefer[tag.title] } });
+                        const entireTagRange = getAbsoluteRange(jsdocNode, tag);
+
+                        context.report({
+                            node: jsdocNode,
+                            message: "Use @{{name}} instead.",
+                            loc: {
+                                start: entireTagRange.start,
+                                end: {
+                                    line: entireTagRange.start.line,
+                                    column: entireTagRange.start.column + `@${tag.title}`.length
+                                }
+                            },
+                            data: { name: prefer[tag.title] },
+                            fix(fixer) {
+                                return fixer.replaceTextRange(
+                                    [
+                                        jsdocNode.range[0] + tag.range[0] + 3,
+                                        jsdocNode.range[0] + tag.range[0] + tag.title.length + 3
+                                    ],
+                                    prefer[tag.title]
+                                );
+                            }
+                        });
                     }
 
                     // validate the types
@@ -306,17 +350,32 @@ module.exports = {
                     }
                 });
 
-                paramsTags.forEach(param => {
+                paramTags.forEach(param => {
                     if (!param.type) {
-                        context.report({ node: jsdocNode, message: "Missing JSDoc parameter type for '{{name}}'.", data: { name: param.name } });
+                        context.report({
+                            node: jsdocNode,
+                            message: "Missing JSDoc parameter type for '{{name}}'.",
+                            loc: getAbsoluteRange(jsdocNode, param),
+                            data: { name: param.name }
+                        });
                     }
                     if (!param.description && requireParamDescription) {
-                        context.report({ node: jsdocNode, message: "Missing JSDoc parameter description for '{{name}}'.", data: { name: param.name } });
+                        context.report({
+                            node: jsdocNode,
+                            message: "Missing JSDoc parameter description for '{{name}}'.",
+                            loc: getAbsoluteRange(jsdocNode, param),
+                            data: { name: param.name }
+                        });
                     }
-                    if (params[param.name]) {
-                        context.report({ node: jsdocNode, message: "Duplicate JSDoc parameter '{{name}}'.", data: { name: param.name } });
+                    if (paramTagsByName[param.name]) {
+                        context.report({
+                            node: jsdocNode,
+                            message: "Duplicate JSDoc parameter '{{name}}'.",
+                            loc: getAbsoluteRange(jsdocNode, param),
+                            data: { name: param.name }
+                        });
                     } else if (param.name.indexOf(".") === -1) {
-                        params[param.name] = 1;
+                        paramTagsByName[param.name] = param;
                     }
                 });
 
@@ -325,6 +384,7 @@ module.exports = {
                         context.report({
                             node: jsdocNode,
                             message: "Unexpected @{{title}} tag; function has no return statement.",
+                            loc: getAbsoluteRange(jsdocNode, returnsTag),
                             data: {
                                 title: returnsTag.title
                             }
@@ -356,10 +416,10 @@ module.exports = {
                 }
 
                 // check the parameters
-                const jsdocParams = Object.keys(params);
+                const jsdocParamNames = Object.keys(paramTagsByName);
 
                 if (node.params) {
-                    node.params.forEach((param, i) => {
+                    node.params.forEach((param, paramsIndex) => {
                         if (param.type === "AssignmentPattern") {
                             param = param.left;
                         }
@@ -368,16 +428,17 @@ module.exports = {
 
                         // TODO(nzakas): Figure out logical things to do with destructured, default, rest params
                         if (param.type === "Identifier") {
-                            if (jsdocParams[i] && (name !== jsdocParams[i])) {
+                            if (jsdocParamNames[paramsIndex] && (name !== jsdocParamNames[paramsIndex])) {
                                 context.report({
                                     node: jsdocNode,
                                     message: "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.",
+                                    loc: getAbsoluteRange(jsdocNode, paramTagsByName[jsdocParamNames[paramsIndex]]),
                                     data: {
                                         name,
-                                        jsdocName: jsdocParams[i]
+                                        jsdocName: jsdocParamNames[paramsIndex]
                                     }
                                 });
-                            } else if (!params[name] && !isOverride) {
+                            } else if (!paramTagsByName[name] && !isOverride) {
                                 context.report({
                                     node: jsdocNode,
                                     message: "Missing JSDoc for parameter '{{name}}'.",
diff --git a/package.json b/package.json
index ae3bce395..286e52a63 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,7 @@
     "concat-stream": "^1.6.0",
     "cross-spawn": "^5.1.0",
     "debug": "^3.1.0",
-    "doctrine": "^2.0.2",
+    "doctrine": "^2.1.0",
     "eslint-scope": "^3.7.1",
     "eslint-visitor-keys": "^1.0.0",
     "espree": "^3.5.2",
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index f901651e6..f8f20d9e2 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -129,7 +129,7 @@ rules:
     no-var: "error"
     object-curly-newline: ["error", { "consistent": true, "multiline": true }]
     object-curly-spacing: ["error", "always"]
-    object-property-newline: ["error", { "allowMultiplePropertiesPerLine": true }]
+    object-property-newline: ["error", { "allowAllPropertiesOnSameLine": true }]
     object-shorthand: "error"
     one-var-declaration-per-line: "error"
     operator-assignment: "error"
diff --git a/tools/internal-rules/.eslintrc.yml b/tools/internal-rules/.eslintrc.yml
index 64b3cee7f..55398c72b 100644
--- a/tools/internal-rules/.eslintrc.yml
+++ b/tools/internal-rules/.eslintrc.yml
@@ -1,4 +1,4 @@
 rules:
     rulesdir/no-invalid-meta: "error"
     rulesdir/consistent-docs-description: "error"
-    rulesdir/consistent-docs-url: "error"
+    rulesdir/consistent-docs-url: "off"
diff --git a/tools/internal-rules/consistent-docs-description.js b/tools/internal-rules/consistent-docs-description.js
index 3120a0d81..55e2a6c76 100644
--- a/tools/internal-rules/consistent-docs-description.js
+++ b/tools/internal-rules/consistent-docs-description.js
@@ -104,7 +104,7 @@ function checkMetaDocsDescription(context, exportsNode) {
 
 module.exports = {
     meta: {
-        docs: {// eslint-disable-line rulesdir/consistent-docs-url
+        docs: {
             description: "enforce correct conventions of `meta.docs.description` property in core rules",
             category: "Internal",
             recommended: false
diff --git a/tools/internal-rules/consistent-docs-url.js b/tools/internal-rules/consistent-docs-url.js
index b08783911..ae7fe67d3 100644
--- a/tools/internal-rules/consistent-docs-url.js
+++ b/tools/internal-rules/consistent-docs-url.js
@@ -75,7 +75,7 @@ function checkMetaDocsUrl(context, exportsNode) {
 
 module.exports = {
     meta: {
-        docs: {// eslint-disable-line rulesdir/consistent-docs-url
+        docs: {
             description: "enforce correct conventions of `meta.docs.url` property in core rules",
             category: "Internal",
             recommended: false
diff --git a/tools/internal-rules/no-invalid-meta.js b/tools/internal-rules/no-invalid-meta.js
index 670cd0899..8082d1000 100644
--- a/tools/internal-rules/no-invalid-meta.js
+++ b/tools/internal-rules/no-invalid-meta.js
@@ -151,7 +151,7 @@ function isCorrectExportsFormat(node) {
 
 module.exports = {
     meta: {
-        docs: {// eslint-disable-line rulesdir/consistent-docs-url
+        docs: {
             description: "enforce correct use of `meta` property in core rules",
             category: "Internal",
             recommended: false


Test patch:
diff --git a/tests/lib/linter.js b/tests/lib/linter.js
index 481a0846f..fc4298d56 100644
--- a/tests/lib/linter.js
+++ b/tests/lib/linter.js
@@ -1615,14 +1615,42 @@ describe("Linter", () => {
     });
 
     describe("when evaluating code with invalid comments to enable rules", () => {
-        const code = "/*eslint no-alert:true*/ alert('test');";
-
-        it("should report a violation", () => {
-            const config = { rules: {} };
-
-            const fn = linter.verify.bind(linter, code, config, filename);
+        it("should report a violation when the config is not a valid rule configuration", () => {
+            assert.deepStrictEqual(
+                linter.verify("/*eslint no-alert:true*/ alert('test');", {}),
+                [
+                    {
+                        severity: 2,
+                        ruleId: "no-alert",
+                        message: "Configuration for rule \"no-alert\" is invalid:\n\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed 'true').\n",
+                        line: 1,
+                        column: 1,
+                        endLine: 1,
+                        endColumn: 25,
+                        source: null,
+                        nodeType: null
+                    }
+                ]
+            );
+        });
 
-            assert.throws(fn, "filename.js line 1:\n\tConfiguration for rule \"no-alert\" is invalid:\n\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed 'true').\n");
+        it("should report a violation when the config violates a rule's schema", () => {
+            assert.deepStrictEqual(
+                linter.verify("/* eslint no-alert: [error, {nonExistentPropertyName: true}]*/", {}),
+                [
+                    {
+                        severity: 2,
+                        ruleId: "no-alert",
+                        message: "Configuration for rule \"no-alert\" is invalid:\n\tValue [{\"nonExistentPropertyName\":true}] should NOT have more than 0 items.\n",
+                        line: 1,
+                        column: 1,
+                        endLine: 1,
+                        endColumn: 63,
+                        source: null,
+                        nodeType: null
+                    }
+                ]
+            );
         });
     });
 
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index 4ec4975bc..6ffa72ce4 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -2830,6 +2830,13 @@ ruleTester.run("indent", rule, {
             `,
             options: [2]
         },
+        unIndent`
+            foo(\`
+                bar
+            \`, {
+                baz: 1
+            });
+        `,
         unIndent`
             function foo() {
                 \`foo\${bar}baz\${
@@ -3856,21 +3863,20 @@ ruleTester.run("indent", rule, {
         unIndent`
             foo(\`foo
                     \`, {
-                    ok: true
-                },
-                {
-                    ok: false
-                }
-            )
+                ok: true
+            },
+            {
+                ok: false
+            })
         `,
         unIndent`
             foo(tag\`foo
                     \`, {
-                    ok: true
-                },
-                {
-                    ok: false
-                }
+                ok: true
+            },
+            {
+                ok: false
+            }
             )
         `,
 
@@ -4796,7 +4802,16 @@ ruleTester.run("indent", rule, {
                 }
             `,
             options: [4, { ignoreComments: true }]
-        }
+        },
+        unIndent`
+            const obj = {
+                foo () {
+                    return condition ? // comment
+                        1 :
+                        2
+                }
+            }
+        `
     ],
 
     invalid: [
@@ -9261,6 +9276,27 @@ ruleTester.run("indent", rule, {
             `,
             options: [4, { ignoreComments: false }],
             errors: expectedErrors([4, 4, 0, "Block"])
+        },
+        {
+            code: unIndent`
+                const obj = {
+                    foo () {
+                        return condition ? // comment
+                        1 :
+                            2
+                    }
+                }
+            `,
+            output: unIndent`
+                const obj = {
+                    foo () {
+                        return condition ? // comment
+                            1 :
+                            2
+                    }
+                }
+            `,
+            errors: expectedErrors([4, 12, 8, "Numeric"])
         }
     ]
 });
diff --git a/tests/lib/rules/no-eq-null.js b/tests/lib/rules/no-eq-null.js
index 7fdb1e440..23d992dc5 100644
--- a/tests/lib/rules/no-eq-null.js
+++ b/tests/lib/rules/no-eq-null.js
@@ -18,14 +18,16 @@ const rule = require("../../../lib/rules/no-eq-null"),
 
 const ruleTester = new RuleTester();
 
+const MESSAGE = "Use '===' to compare with null.";
+
 ruleTester.run("no-eq-null", rule, {
     valid: [
         "if (x === null) { }",
         "if (null === f()) { }"
     ],
     invalid: [
-        { code: "if (x == null) { }", errors: [{ message: "Use ‘===’ to compare with ‘null’.", type: "BinaryExpression" }] },
-        { code: "if (x != null) { }", errors: [{ message: "Use ‘===’ to compare with ‘null’.", type: "BinaryExpression" }] },
-        { code: "do {} while (null == x)", errors: [{ message: "Use ‘===’ to compare with ‘null’.", type: "BinaryExpression" }] }
+        { code: "if (x == null) { }", errors: [{ message: MESSAGE, type: "BinaryExpression" }] },
+        { code: "if (x != null) { }", errors: [{ message: MESSAGE, type: "BinaryExpression" }] },
+        { code: "do {} while (null == x)", errors: [{ message: MESSAGE, type: "BinaryExpression" }] }
     ]
 });
diff --git a/tests/lib/rules/object-property-newline.js b/tests/lib/rules/object-property-newline.js
index 2d0df640f..ed0e24db2 100644
--- a/tests/lib/rules/object-property-newline.js
+++ b/tests/lib/rules/object-property-newline.js
@@ -44,24 +44,27 @@ ruleTester.run("object-property-newline", rule, {
         { code: "foo({ k1: 'val1',\nk2: 'val2',\n...{} });", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
         { code: "foo({ ...{} });", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
 
-        // allowMultiplePropertiesPerLine: true
-        { code: "var obj = { k1: 'val1', k2: 'val2', k3: 'val3' };", options: [{ allowMultiplePropertiesPerLine: true }] },
-        { code: "var obj = {\nk1: 'val1', k2: 'val2', k3: 'val3'\n};", options: [{ allowMultiplePropertiesPerLine: true }] },
-        { code: "var obj = { k1: 'val1' };", options: [{ allowMultiplePropertiesPerLine: true }] },
-        { code: "var obj = {\nk1: 'val1'\n};", options: [{ allowMultiplePropertiesPerLine: true }] },
-        { code: "var obj = {};", options: [{ allowMultiplePropertiesPerLine: true }] },
-        { code: "var obj = { 'k1': 'val1', k2: 'val2', ...{} };", options: [{ allowMultiplePropertiesPerLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
-        { code: "var obj = {\n'k1': 'val1', k2: 'val2', ...{}\n};", options: [{ allowMultiplePropertiesPerLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
-        { code: "foo({ k1: 'val1', k2: 'val2' });", options: [{ allowMultiplePropertiesPerLine: true }] },
-        { code: "foo({\nk1: 'val1', k2: 'val2'\n});", options: [{ allowMultiplePropertiesPerLine: true }] },
-        { code: "foo({ a, b });", options: [{ allowMultiplePropertiesPerLine: true }], parserOptions: { ecmaVersion: 6 } },
-        { code: "foo({ bar() {}, baz });", options: [{ allowMultiplePropertiesPerLine: true }], parserOptions: { ecmaVersion: 6 } },
-        { code: "foo({ [bar]: 'baz', baz })", options: [{ allowMultiplePropertiesPerLine: true }], parserOptions: { ecmaVersion: 6 } },
-        { code: "foo({ 'k1': 'val1', k2: 'val2', ...{} });", options: [{ allowMultiplePropertiesPerLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
-        { code: "foo({\n'k1': 'val1', k2: 'val2', ...{}\n});", options: [{ allowMultiplePropertiesPerLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
-        { code: "var obj = {k1: ['foo', 'bar'], k2: 'val1', k3: 'val2'};", options: [{ allowMultiplePropertiesPerLine: true }] },
-        { code: "var obj = {\nk1: ['foo', 'bar'], k2: 'val1', k3: 'val2'\n};", options: [{ allowMultiplePropertiesPerLine: true }] },
-        { code: "var obj = {\nk1: 'val1', k2: {e1: 'foo', e2: 'bar'}, k3: 'val2'\n};", options: [{ allowMultiplePropertiesPerLine: true }] }
+        // allowAllPropertiesOnSameLine: true
+        { code: "var obj = { k1: 'val1', k2: 'val2', k3: 'val3' };", options: [{ allowAllPropertiesOnSameLine: true }] },
+        { code: "var obj = {\nk1: 'val1', k2: 'val2', k3: 'val3'\n};", options: [{ allowAllPropertiesOnSameLine: true }] },
+        { code: "var obj = { k1: 'val1' };", options: [{ allowAllPropertiesOnSameLine: true }] },
+        { code: "var obj = {\nk1: 'val1'\n};", options: [{ allowAllPropertiesOnSameLine: true }] },
+        { code: "var obj = {};", options: [{ allowAllPropertiesOnSameLine: true }] },
+        { code: "var obj = { 'k1': 'val1', k2: 'val2', ...{} };", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "var obj = {\n'k1': 'val1', k2: 'val2', ...{}\n};", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "foo({ k1: 'val1', k2: 'val2' });", options: [{ allowAllPropertiesOnSameLine: true }] },
+        { code: "foo({\nk1: 'val1', k2: 'val2'\n});", options: [{ allowAllPropertiesOnSameLine: true }] },
+        { code: "foo({ a, b });", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6 } },
+        { code: "foo({ bar() {}, baz });", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6 } },
+        { code: "foo({ [bar]: 'baz', baz })", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6 } },
+        { code: "foo({ 'k1': 'val1', k2: 'val2', ...{} });", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "foo({\n'k1': 'val1', k2: 'val2', ...{}\n});", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "var obj = {k1: ['foo', 'bar'], k2: 'val1', k3: 'val2'};", options: [{ allowAllPropertiesOnSameLine: true }] },
+        { code: "var obj = {\nk1: ['foo', 'bar'], k2: 'val1', k3: 'val2'\n};", options: [{ allowAllPropertiesOnSameLine: true }] },
+        { code: "var obj = {\nk1: 'val1', k2: {e1: 'foo', e2: 'bar'}, k3: 'val2'\n};", options: [{ allowAllPropertiesOnSameLine: true }] },
+
+        // allowMultiplePropertiesPerLine: true (deprecated)
+        { code: "var obj = { k1: 'val1', k2: 'val2', k3: 'val3' };", options: [{ allowMultiplePropertiesPerLine: true }] }
     ],
 
     invalid: [
@@ -378,11 +381,11 @@ ruleTester.run("object-property-newline", rule, {
             ]
         },
 
-        // allowMultiplePropertiesPerLine: true
+        // allowAllPropertiesOnSameLine: true
         {
             code: "var obj = {\nk1: 'val1',\nk2: 'val2', k3: 'val3'\n};",
             output: "var obj = {\nk1: 'val1',\nk2: 'val2',\nk3: 'val3'\n};",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             errors: [
                 {
                     message: "Object properties must go on a new line if they aren't all on the same line.",
@@ -395,7 +398,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "var obj = {\nk1:\n'val1', k2: 'val2', k3:\n'val3'\n};",
             output: "var obj = {\nk1:\n'val1',\nk2: 'val2',\nk3:\n'val3'\n};",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             errors: [
                 {
                     message: "Object properties must go on a new line if they aren't all on the same line.",
@@ -414,7 +417,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "var obj = {k1: [\n'foo',\n'bar'\n], k2: 'val1'};",
             output: "var obj = {k1: [\n'foo',\n'bar'\n],\nk2: 'val1'};",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             errors: [
                 {
                     message: "Object properties must go on a new line if they aren't all on the same line.",
@@ -427,7 +430,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "var obj = {k1: [\n'foo', 'bar'\n], k2: 'val1'};",
             output: "var obj = {k1: [\n'foo', 'bar'\n],\nk2: 'val1'};",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             errors: [
                 {
                     message: "Object properties must go on a new line if they aren't all on the same line.",
@@ -440,7 +443,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "var obj = {\nk1: 'val1', k2: {\ne1: 'foo', e2: 'bar'\n}, k3: 'val2'\n};",
             output: "var obj = {\nk1: 'val1',\nk2: {\ne1: 'foo', e2: 'bar'\n},\nk3: 'val2'\n};",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             errors: [
                 {
                     message: "Object properties must go on a new line if they aren't all on the same line.",
@@ -459,7 +462,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "var obj = { k1: 'val1',\nk2: [\n'val2a', 'val2b', 'val2c'\n], k3: 'val3' };",
             output: "var obj = { k1: 'val1',\nk2: [\n'val2a', 'val2b', 'val2c'\n],\nk3: 'val3' };",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             errors: [
                 {
                     message: "Object properties must go on a new line if they aren't all on the same line.",
@@ -472,7 +475,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "var obj = { [\nk1]: 'val1', k2: 'val2' };",
             output: "var obj = { [\nk1]: 'val1',\nk2: 'val2' };",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             parserOptions: { ecmaVersion: 6 },
             errors: [
                 {
@@ -486,7 +489,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "var obj = {\nk1: 'val1',\nk2: 'val2', ...{}\n};",
             output: "var obj = {\nk1: 'val1',\nk2: 'val2',\n...{}\n};",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [
                 {
@@ -500,7 +503,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "var obj = {\n...{},\nk1: 'val1', k2: 'val2'\n};",
             output: "var obj = {\n...{},\nk1: 'val1',\nk2: 'val2'\n};",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [
                 {
@@ -514,7 +517,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "foo({ [\nk1]: 'val1', k2: 'val2' })",
             output: "foo({ [\nk1]: 'val1',\nk2: 'val2' })",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             parserOptions: { ecmaVersion: 6 },
             errors: [
                 {
@@ -528,7 +531,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "foo({\nk1: 'val1',\nk2: 'val2', ...{}\n})",
             output: "foo({\nk1: 'val1',\nk2: 'val2',\n...{}\n})",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [
                 {
@@ -542,7 +545,7 @@ ruleTester.run("object-property-newline", rule, {
         {
             code: "foo({\n...{},\nk1: 'val1', k2: 'val2'\n})",
             output: "foo({\n...{},\nk1: 'val1',\nk2: 'val2'\n})",
-            options: [{ allowMultiplePropertiesPerLine: true }],
+            options: [{ allowAllPropertiesOnSameLine: true }],
             parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [
                 {
@@ -552,6 +555,21 @@ ruleTester.run("object-property-newline", rule, {
                     column: 13
                 }
             ]
+        },
+
+        // allowMultiplePropertiesPerLine: true (deprecated)
+        {
+            code: "var obj = {\nk1: 'val1',\nk2: 'val2', k3: 'val3'\n};",
+            output: "var obj = {\nk1: 'val1',\nk2: 'val2',\nk3: 'val3'\n};",
+            options: [{ allowMultiplePropertiesPerLine: true }],
+            errors: [
+                {
+                    message: "Object properties must go on a new line if they aren't all on the same line.",
+                    type: "ObjectExpression",
+                    line: 3,
+                    column: 13
+                }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/prefer-destructuring.js b/tests/lib/rules/prefer-destructuring.js
index e60535e7e..a0e4aa79b 100644
--- a/tests/lib/rules/prefer-destructuring.js
+++ b/tests/lib/rules/prefer-destructuring.js
@@ -131,7 +131,9 @@ ruleTester.run("prefer-destructuring", rule, {
             code: "var foo = object.foo;",
             options: [{ VariableDeclarator: { object: false }, AssignmentExpression: { object: true } }]
         },
-        "class Foo extends Bar { static foo() {var foo = super.foo} }"
+        "class Foo extends Bar { static foo() {var foo = super.foo} }",
+        "foo = bar[foo];",
+        "var foo = bar[foo];"
     ],
 
     invalid: [
diff --git a/tests/lib/rules/valid-jsdoc.js b/tests/lib/rules/valid-jsdoc.js
index 54fea8d8f..d6e0219c5 100644
--- a/tests/lib/rules/valid-jsdoc.js
+++ b/tests/lib/rules/valid-jsdoc.js
@@ -1044,14 +1044,20 @@ ruleTester.run("valid-jsdoc", rule, {
                 "    return 'the return';\n" +
                 "  }\n" +
                 ");\n",
+            output: null,
             options: [{ requireReturn: false }],
             errors: [{
                 message: "Expected JSDoc for 'argName' but found 'bogusName'.",
-                type: "Block"
+                type: "Block",
+                line: 4,
+                column: 6,
+                endLine: 4,
+                endColumn: 62
             }]
         },
         {
             code: "/** @@foo */\nfunction foo(){}",
+            output: null,
             errors: [{
                 message: "JSDoc syntax error.",
                 type: "Block"
@@ -1070,6 +1076,7 @@ ruleTester.run("valid-jsdoc", rule, {
                 "    return 'bar';\n" +
                 "  }\n" +
                 "});\n",
+            output: null,
             options: [{ requireReturn: false }],
             errors: [{
                 message: "Missing JSDoc @returns for function.",
@@ -1078,6 +1085,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** @@returns {void} Foo */\nfunction foo(){}",
+            output: null,
             errors: [{
                 message: "JSDoc syntax error.",
                 type: "Block"
@@ -1085,6 +1093,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** Foo \n@returns {void Foo\n */\nfunction foo(){}",
+            output: null,
             errors: [{
                 message: "JSDoc type missing brace.",
                 type: "Block"
@@ -1092,25 +1101,36 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** Foo \n@return {void} Foo\n */\nfunction foo(){}",
+            output: "/** Foo \n@returns {void} Foo\n */\nfunction foo(){}",
             options: [{ prefer: { return: "returns" } }],
             errors: [{
                 message: "Use @returns instead.",
-                type: "Block"
+                type: "Block",
+                line: 2,
+                column: 1,
+                endLine: 2,
+                endColumn: 8
             }]
         },
         {
             code: "/** Foo \n@argument {int} bar baz\n */\nfunction foo(bar){}",
+            output: "/** Foo \n@arg {int} bar baz\n */\nfunction foo(bar){}",
             options: [{ prefer: { argument: "arg" } }],
             errors: [{
-                message: "Use @arg instead.",
-                type: "Block"
-            }, {
                 message: "Missing JSDoc @returns for function.",
                 type: "Block"
+            }, {
+                message: "Use @arg instead.",
+                type: "Block",
+                line: 2,
+                column: 1,
+                endLine: 2,
+                endColumn: 10
             }]
         },
         {
             code: "/** Foo \n */\nfunction foo(){}",
+            output: null,
             options: [{ prefer: { returns: "return" } }],
             errors: [{
                 message: "Missing JSDoc @return for function.",
@@ -1119,15 +1139,21 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** Foo \n@return {void} Foo\n */\nfoo.bar = () => {}",
+            output: "/** Foo \n@returns {void} Foo\n */\nfoo.bar = () => {}",
             options: [{ prefer: { return: "returns" } }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
                 message: "Use @returns instead.",
-                type: "Block"
+                type: "Block",
+                line: 2,
+                column: 1,
+                endLine: 2,
+                endColumn: 8
             }]
         },
         {
             code: "/** Foo \n@param {void Foo\n */\nfunction foo(){}",
+            output: null,
             errors: [{
                 message: "JSDoc type missing brace.",
                 type: "Block"
@@ -1135,6 +1161,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** Foo \n@param {} p Bar\n */\nfunction foo(){}",
+            output: null,
             errors: [{
                 message: "JSDoc syntax error.",
                 type: "Block"
@@ -1142,6 +1169,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** Foo \n@param {void Foo */\nfunction foo(){}",
+            output: null,
             errors: [{
                 message: "JSDoc type missing brace.",
                 type: "Block"
@@ -1149,42 +1177,62 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** Foo\n* @param p Desc \n*/\nfunction foo(){}",
+            output: null,
             errors: [{
-                message: "Missing JSDoc parameter type for 'p'.",
-                type: "Block"
-            }, {
                 message: "Missing JSDoc @returns for function.",
                 type: "Block"
+            }, {
+                message: "Missing JSDoc parameter type for 'p'.",
+                type: "Block",
+                line: 2,
+                column: 3,
+                endLine: 2,
+                endColumn: 16
             }]
         },
         {
             code: "/**\n* Foo\n* @param {string} p \n*/\nfunction foo(){}",
+            output: null,
             errors: [{
-                message: "Missing JSDoc parameter description for 'p'.",
-                type: "Block"
-            }, {
                 message: "Missing JSDoc @returns for function.",
                 type: "Block"
+            }, {
+                message: "Missing JSDoc parameter description for 'p'.",
+                type: "Block",
+                line: 3,
+                column: 3,
+                endLine: 3,
+                endColumn: 20
             }]
         },
         {
             code: "/**\n* Foo\n* @param {string} p \n*/\nvar foo = function(){}",
+            output: null,
             errors: [{
-                message: "Missing JSDoc parameter description for 'p'.",
-                type: "Block"
-            }, {
                 message: "Missing JSDoc @returns for function.",
                 type: "Block"
+            }, {
+                message: "Missing JSDoc parameter description for 'p'.",
+                type: "Block",
+                line: 3,
+                column: 3,
+                endLine: 3,
+                endColumn: 20
             }]
         },
         {
             code: "/**\n* Foo\n* @param {string} p \n*/\nvar foo = \nfunction(){}",
+            output: null,
             errors: [{
-                message: "Missing JSDoc parameter description for 'p'.",
-                type: "Block"
-            }, {
                 message: "Missing JSDoc @returns for function.",
                 type: "Block"
+            }, {
+                message: "Missing JSDoc parameter description for 'p'.",
+                type: "Block",
+                line: 3,
+                column: 3,
+                endLine: 3,
+                endColumn: 20
             }]
         },
         {
@@ -1202,6 +1250,7 @@ ruleTester.run("valid-jsdoc", rule, {
             "        this.a = xs;" +
             "    }\n" +
             "};",
+            output: null,
             options: [{
                 requireReturn: true,
                 matchDescription: "^[A-Z][A-Za-z0-9\\s]*[.]$"
@@ -1222,6 +1271,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/**\n* Foo\n* @returns {string} \n*/\nfunction foo(){}",
+            output: null,
             errors: [{
                 message: "Missing JSDoc return description.",
                 type: "Block"
@@ -1229,6 +1279,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/**\n* Foo\n* @returns {string} something \n*/\nfunction foo(p){}",
+            output: null,
             errors: [{
                 message: "Missing JSDoc for parameter 'p'.",
                 type: "Block"
@@ -1236,6 +1287,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/**\n* Foo\n* @returns {string} something \n*/\nvar foo = \nfunction foo(a = 1){}",
+            output: null,
             parserOptions: { ecmaVersion: 6 },
             errors: [{
                 message: "Missing JSDoc for parameter 'a'.",
@@ -1244,49 +1296,79 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/**\n* Foo\n* @param {string} a Description \n* @param {string} b Description \n* @returns {string} something \n*/\nvar foo = \nfunction foo(b, a = 1){}",
+            output: null,
             parserOptions: { ecmaVersion: 6 },
             errors: [{
                 message: "Expected JSDoc for 'b' but found 'a'.",
-                type: "Block"
+                type: "Block",
+                line: 3,
+                column: 3,
+                endLine: 3,
+                endColumn: 32
             },
             {
                 message: "Expected JSDoc for 'a' but found 'b'.",
-                type: "Block"
+                type: "Block",
+                line: 4,
+                column: 3,
+                endLine: 4,
+                endColumn: 32
             }]
         },
         {
             code: "/**\n* Foo\n* @param {string} p desc\n* @param {string} p desc \n*/\nfunction foo(){}",
+            output: null,
             errors: [{
-                message: "Duplicate JSDoc parameter 'p'.",
-                type: "Block"
-            }, {
                 message: "Missing JSDoc @returns for function.",
                 type: "Block"
+            }, {
+                message: "Duplicate JSDoc parameter 'p'.",
+                type: "Block",
+                line: 4,
+                column: 3,
+                endLine: 4,
+                endColumn: 25
             }]
         },
         {
             code: "/**\n* Foo\n* @param {string} a desc\n@returns {void}*/\nfunction foo(b){}",
+            output: null,
             errors: [{
                 message: "Expected JSDoc for 'b' but found 'a'.",
-                type: "Block"
+                type: "Block",
+                line: 3,
+                column: 3,
+                endLine: 3,
+                endColumn: 25
             }]
         },
         {
             code: "/**\n* Foo\n* @override\n* @param {string} a desc\n */\nfunction foo(b){}",
+            output: null,
             errors: [{
                 message: "Expected JSDoc for 'b' but found 'a'.",
-                type: "Block"
+                type: "Block",
+                line: 4,
+                column: 3,
+                endLine: 4,
+                endColumn: 25
             }]
         },
         {
             code: "/**\n* Foo\n* @inheritdoc\n* @param {string} a desc\n */\nfunction foo(b){}",
+            output: null,
             errors: [{
                 message: "Expected JSDoc for 'b' but found 'a'.",
-                type: "Block"
+                type: "Block",
+                line: 4,
+                column: 3,
+                endLine: 4,
+                endColumn: 25
             }]
         },
         {
             code: "/**\n* Foo\n* @param {string} a desc\n*/\nfunction foo(a){var t = false; if(t) {return t;}}",
+            output: null,
             options: [{ requireReturn: false }],
             errors: [{
                 message: "Missing JSDoc @returns for function.",
@@ -1295,6 +1377,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/**\n* Foo\n* @param {string} a desc\n*/\nfunction foo(a){var t = false; if(t) {return null;}}",
+            output: null,
             options: [{ requireReturn: false }],
             errors: [{
                 message: "Missing JSDoc @returns for function.",
@@ -1303,32 +1386,48 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/**\n* Foo\n* @param {string} a desc\n@returns {MyClass}*/\nfunction foo(a){var t = false; if(t) {process(t);}}",
+            output: null,
             options: [{ requireReturn: false }],
             errors: [{
                 message: "Unexpected @returns tag; function has no return statement.",
-                type: "Block"
+                type: "Block",
+                line: 4,
+                column: 1,
+                endLine: 4,
+                endColumn: 19
             }]
         },
         {
             code: "/**\n * Does something. \n* @param {string} a - this is a \n* @return {Array<number>} The result of doing it \n*/\n export function doSomething(a) { }",
+            output: "/**\n * Does something. \n* @param {string} a - this is a \n* @returns {Array<number>} The result of doing it \n*/\n export function doSomething(a) { }",
             options: [{ prefer: { return: "returns" } }],
             parserOptions: { sourceType: "module" },
             errors: [{
                 message: "Use @returns instead.",
-                type: "Block"
+                type: "Block",
+                line: 4,
+                column: 3,
+                endLine: 4,
+                endColumn: 10
             }]
         },
         {
             code: "/**\n * Does something. \n* @param {string} a - this is a \n* @return {Array<number>} The result of doing it \n*/\n export default function doSomething(a) { }",
+            output: "/**\n * Does something. \n* @param {string} a - this is a \n* @returns {Array<number>} The result of doing it \n*/\n export default function doSomething(a) { }",
             options: [{ prefer: { return: "returns" } }],
             parserOptions: { sourceType: "module" },
             errors: [{
                 message: "Use @returns instead.",
-                type: "Block"
+                type: "Block",
+                line: 4,
+                column: 3,
+                endLine: 4,
+                endColumn: 10
             }]
         },
         {
             code: "/** foo */ var foo = () => bar();",
+            output: null,
             options: [{ requireReturn: false }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1338,6 +1437,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** foo */ var foo = () => { return bar(); };",
+            output: null,
             options: [{ requireReturn: false }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1347,28 +1447,39 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** @returns {object} foo */ var foo = () => { bar(); };",
+            output: null,
             options: [{ requireReturn: false }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
                 message: "Unexpected @returns tag; function has no return statement.",
-                type: "Block"
+                type: "Block",
+                line: 1,
+                column: 5,
+                endLine: 1,
+                endColumn: 26
             }]
         },
         {
             code: "/**\n* @param fields [Array]\n */\n function foo(){}",
+            output: null,
             errors: [
                 {
-                    message: "Missing JSDoc parameter type for 'fields'.",
+                    message: "Missing JSDoc @returns for function.",
                     type: "Block"
                 },
                 {
-                    message: "Missing JSDoc @returns for function.",
-                    type: "Block"
+                    message: "Missing JSDoc parameter type for 'fields'.",
+                    type: "Block",
+                    line: 2,
+                    column: 3,
+                    endLine: 2,
+                    endColumn: 24
                 }
             ]
         },
         {
             code: "/**\n* Start with caps and end with period\n* @return {void} */\nfunction foo(){}",
+            output: null,
             options: [{
                 matchDescription: "^[A-Z][A-Za-z0-9\\s]*[.]$"
             }],
@@ -1379,6 +1490,7 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** Foo \n@return Foo\n */\nfunction foo(){}",
+            output: null,
             options: [{ prefer: { return: "return" } }],
             errors: [{
                 message: "Missing JSDoc return type.",
@@ -1387,13 +1499,18 @@ ruleTester.run("valid-jsdoc", rule, {
         },
         {
             code: "/** Foo \n@return sdf\n */\nfunction foo(){}",
+            output: null,
             options: [{
                 prefer: { return: "return" },
                 requireReturn: false
             }],
             errors: [{
                 message: "Unexpected @return tag; function has no return statement.",
-                type: "Block"
+                type: "Block",
+                line: 2,
+                column: 1,
+                endLine: 2,
+                endColumn: 12
             }]
         },
 
@@ -1412,6 +1529,7 @@ ruleTester.run("valid-jsdoc", rule, {
                 "        this.a = xs;" +
                 "    }\n" +
                 "}",
+            output: null,
             options: [{
                 requireReturn: false,
                 matchDescription: "^[A-Z][A-Za-z0-9\\s]*[.]$"
@@ -1444,6 +1562,7 @@ ruleTester.run("valid-jsdoc", rule, {
                 "        this.a = xs;" +
                 "    }\n" +
                 "};",
+            output: null,
             options: [{
                 requireReturn: true,
                 matchDescription: "^[A-Z][A-Za-z0-9\\s]*[.]$"
@@ -1483,6 +1602,7 @@ ruleTester.run("valid-jsdoc", rule, {
                 "        this.a = xs;" +
                 "    }\n" +
                 "}",
+            output: null,
             options: [],
             parserOptions: {
                 ecmaVersion: 6
@@ -1505,6 +1625,7 @@ ruleTester.run("valid-jsdoc", rule, {
                 " * @this {not.a.valid.type.expression\n" +
                 " */\n" +
                 "function foo() {}",
+            output: null,
             options: [{ requireReturn: false }],
             errors: [{
                 message: "JSDoc type missing brace.",
@@ -1518,6 +1639,7 @@ ruleTester.run("valid-jsdoc", rule, {
                 " * @this {Array<string>}\n" +
                 " */\n" +
                 "function foo() {}",
+            output: null,
             options: [{ requireReturn: false }],
             errors: [{
                 message: "JSDoc syntax error.",
@@ -1534,6 +1656,13 @@ ruleTester.run("valid-jsdoc", rule, {
             "* @returns {Astnode} returns a node\n" +
             "*/\n" +
             "function foo(hi){}",
+            output:
+            "/**\n" +
+            "* Foo\n" +
+            "* @param {string} hi - desc\n" +
+            "* @returns {ASTNode} returns a node\n" +
+            "*/\n" +
+            "function foo(hi){}",
             options: [{
                 preferType: {
                     String: "string",
@@ -1543,11 +1672,19 @@ ruleTester.run("valid-jsdoc", rule, {
             errors: [
                 {
                     message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 11,
+                    endLine: 3,
+                    endColumn: 17
                 },
                 {
                     message: "Use 'ASTNode' instead of 'Astnode'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 4,
+                    column: 13,
+                    endLine: 4,
+                    endColumn: 20
                 }
             ]
         },
@@ -1559,6 +1696,13 @@ ruleTester.run("valid-jsdoc", rule, {
             "* @returns {Astnode} returns a node\n" +
             "*/\n" +
             "function foo(hi){}",
+            output:
+            "/**\n" +
+            "* Foo\n" +
+            "* @param {{20:string}} hi - desc\n" +
+            "* @returns {ASTNode} returns a node\n" +
+            "*/\n" +
+            "function foo(hi){}",
             options: [{
                 preferType: {
                     String: "string",
@@ -1568,11 +1712,19 @@ ruleTester.run("valid-jsdoc", rule, {
             errors: [
                 {
                     message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 15,
+                    endLine: 3,
+                    endColumn: 21
                 },
                 {
                     message: "Use 'ASTNode' instead of 'Astnode'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 4,
+                    column: 13,
+                    endLine: 4,
+                    endColumn: 20
                 }
             ]
         },
@@ -1584,6 +1736,13 @@ ruleTester.run("valid-jsdoc", rule, {
             "* @returns {Astnode} returns a node\n" +
             "*/\n" +
             "function foo(hi){}",
+            output:
+            "/**\n" +
+            "* Foo\n" +
+            "* @param {String|number|Test} hi - desc\n" +
+            "* @returns {Astnode} returns a node\n" +
+            "*/\n" +
+            "function foo(hi){}",
             options: [{
                 preferType: {
                     test: "Test"
@@ -1592,7 +1751,11 @@ ruleTester.run("valid-jsdoc", rule, {
             errors: [
                 {
                     message: "Use 'Test' instead of 'test'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 25,
+                    endLine: 3,
+                    endColumn: 29
                 }
             ]
         },
@@ -1604,6 +1767,13 @@ ruleTester.run("valid-jsdoc", rule, {
             "* @returns {Astnode} returns a node\n" +
             "*/\n" +
             "function foo(hi){}",
+            output:
+            "/**\n" +
+            "* Foo\n" +
+            "* @param {Array.<string>} hi - desc\n" +
+            "* @returns {Astnode} returns a node\n" +
+            "*/\n" +
+            "function foo(hi){}",
             options: [{
                 preferType: {
                     String: "string",
@@ -1613,7 +1783,11 @@ ruleTester.run("valid-jsdoc", rule, {
             errors: [
                 {
                     message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 18,
+                    endLine: 3,
+                    endColumn: 24
                 }
             ]
         },
@@ -1625,6 +1799,13 @@ ruleTester.run("valid-jsdoc", rule, {
             "* @returns {Array.<{summary: String}>} desc\n" +
             "*/\n" +
             "function foo(hi){}",
+            output:
+            "/**\n" +
+            "* Foo\n" +
+            "* @param {Array.<{id: number, votes: number}>} hi - desc\n" +
+            "* @returns {Array.<{summary: string}>} desc\n" +
+            "*/\n" +
+            "function foo(hi){}",
             options: [{
                 preferType: {
                     Number: "number",
@@ -1634,15 +1815,27 @@ ruleTester.run("valid-jsdoc", rule, {
             errors: [
                 {
                     message: "Use 'number' instead of 'Number'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 23,
+                    endLine: 3,
+                    endColumn: 29
                 },
                 {
                     message: "Use 'number' instead of 'Number'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 38,
+                    endLine: 3,
+                    endColumn: 44
                 },
                 {
                     message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 4,
+                    column: 30,
+                    endLine: 4,
+                    endColumn: 36
                 }
             ]
         },
@@ -1654,6 +1847,13 @@ ruleTester.run("valid-jsdoc", rule, {
             "* @returns {Array.<[String, String]>} desc\n" +
             "*/\n" +
             "function foo(hi){}",
+            output:
+            "/**\n" +
+            "* Foo\n" +
+            "* @param {Array.<[string, number]>} hi - desc\n" +
+            "* @returns {Array.<[string, string]>} desc\n" +
+            "*/\n" +
+            "function foo(hi){}",
             options: [{
                 preferType: {
                     Number: "number",
@@ -1663,19 +1863,35 @@ ruleTester.run("valid-jsdoc", rule, {
             errors: [
                 {
                     message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 19,
+                    endLine: 3,
+                    endColumn: 25
                 },
                 {
                     message: "Use 'number' instead of 'Number'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 27,
+                    endLine: 3,
+                    endColumn: 33
                 },
                 {
                     message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 4,
+                    column: 21,
+                    endLine: 4,
+                    endColumn: 27
                 },
                 {
                     message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 4,
+                    column: 29,
+                    endLine: 4,
+                    endColumn: 35
                 }
             ]
         },
@@ -1687,6 +1903,13 @@ ruleTester.run("valid-jsdoc", rule, {
             "* @returns {Boolean} desc\n" +
             "*/\n" +
             "function foo(hi){}",
+            output:
+            "/**\n" +
+            "* Foo\n" +
+            "* @param {Object<string,Object<string, number>>} hi - because why not\n" +
+            "* @returns {Boolean} desc\n" +
+            "*/\n" +
+            "function foo(hi){}",
             options: [{
                 preferType: {
                     Number: "number",
@@ -1696,24 +1919,44 @@ ruleTester.run("valid-jsdoc", rule, {
             }],
             errors: [
                 {
-                    message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    message: "Use 'Object' instead of 'object'.",
+                    type: "Block",
+                    line: 3,
+                    column: 11,
+                    endLine: 3,
+                    endColumn: 17
                 },
                 {
                     message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 18,
+                    endLine: 3,
+                    endColumn: 24
                 },
                 {
-                    message: "Use 'number' instead of 'Number'.",
-                    type: "Block"
+                    message: "Use 'Object' instead of 'object'.",
+                    type: "Block",
+                    line: 3,
+                    column: 25,
+                    endLine: 3,
+                    endColumn: 31
                 },
                 {
-                    message: "Use 'Object' instead of 'object'.",
-                    type: "Block"
+                    message: "Use 'string' instead of 'String'.",
+                    type: "Block",
+                    line: 3,
+                    column: 32,
+                    endLine: 3,
+                    endColumn: 38
                 },
                 {
-                    message: "Use 'Object' instead of 'object'.",
-                    type: "Block"
+                    message: "Use 'number' instead of 'Number'.",
+                    type: "Block",
+                    line: 3,
+                    column: 40,
+                    endLine: 3,
+                    endColumn: 46
                 }
             ]
         },
@@ -1727,6 +1970,13 @@ ruleTester.run("valid-jsdoc", rule, {
             "* @returns {ASTnode} returns a node\n" +
             "*/\n" +
             "function foo(hi){}",
+            output:
+            "/**\n" +
+            "* Foo\n" +
+            "* @param {{foo:string, astnode:Object, bar}} hi - desc\n" +
+            "* @returns {ASTnode} returns a node\n" +
+            "*/\n" +
+            "function foo(hi){}",
             options: [{
                 preferType: {
                     String: "string",
@@ -1736,7 +1986,11 @@ ruleTester.run("valid-jsdoc", rule, {
             errors: [
                 {
                     message: "Use 'string' instead of 'String'.",
-                    type: "Block"
+                    type: "Block",
+                    line: 3,
+                    column: 16,
+                    endLine: 3,
+                    endColumn: 22
                 }
             ]
         }