Repository: eslint/eslint
Pull request #8876 (2017-07-04 14:47:16)

Docs: Clarified PR guidelines in maintainer guide
<!--
    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)**

[x] 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: Modifying PR guidelines in maintainer guide

<!--
    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 (http://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)**

In the PR guide for maintainers:

* Separated human verification steps (check that commit tag is correct for issue) from bot verification steps (check that commit tag is present)
* Removed note about doc-only PRs not requiring an issue, since we only require issues for core changes
* Added human verification step to check that commit tag is correct for issue/problem
* Added human verification step to check for presence of issue, if PR is making a change to core
* Added note that team members can merge chores

**Is there anything you'd like reviewers to focus on?**

I tried to make changes that were either obvious clarifications/reorganizations, or that reflected our actual practices. Nonetheless, this might need TSC review to make sure I'm not inadvertently proposing to change maintainer guidelines.

eslintbot: LGTM
platinumazure: **TSC Summary**: Goal is to clarify and improve the PR guidelines in the maintainer guide. I tried to make changes that were either obvious clarifications/reorganizations, or that reflected our actual practices. Nonetheless, this might need TSC review to make sure I'm not inadvertently proposing to change maintainer guidelines.

**TSC Question**: Are the proposed changes acceptable and accurate?

Patch:
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 8675e4491..16822fd97 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -20,14 +20,18 @@
 
 **Please show your full configuration:**
 
-<!-- Paste your configuration below: -->
-```
+<details>
+<summary>Configuration</summary>
 
+<!-- Paste your configuration below: -->
+```js
 
 
 
 ```
 
+</details>
+
 **What did you do? Please include the actual source code causing the issue.**
 
 <!-- Paste the source code below: -->
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ffe6b574c..3826c28e8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,7 +17,7 @@ Before filing an issue, please be sure to read the guidelines for what you're re
 
 ## Contributing Code
 
-Please sign our [Contributor License Agreement](https://contribute.jquery.org/CLA/) and read over the [Pull Request Guidelines](http://eslint.org/docs/developer-guide/contributing/pull-requests).
+Please sign our [Contributor License Agreement](https://js.foundation/CLA) and read over the [Pull Request Guidelines](http://eslint.org/docs/developer-guide/contributing/pull-requests).
 
 ## Full Documentation
 
diff --git a/docs/maintainer-guide/pullrequests.md b/docs/maintainer-guide/pullrequests.md
index fffeb75b5..3b5618389 100644
--- a/docs/maintainer-guide/pullrequests.md
+++ b/docs/maintainer-guide/pullrequests.md
@@ -11,14 +11,14 @@ Anyone, both team members and the public, may leave comments on pull requests.
 When a pull request is opened, the bot will check the following:
 
 1. Has the submitter signed a CLA?
-1. Is the commit message summary in the correct format? Double-check that the tag ("Fix:", "New:", etc.) is correct based on the issue. Documentation-only pull requests do not require an issue.
-1. Does the commit summary reference an issue?
+1. Is the commit message summary in the correct format?
 1. Is the commit summary too long?
 
 The bot will add a comment specifying the problems that it finds. You do not need to look at the pull request any further until those problems have been addressed (there's no need to comment on the pull request to ask the submitter to do what the bot asked - that's why we have the bot!).
 
 Once the bot checks have been satisfied, you check the following:
 
+1. Double-check that the commit message tag ("Fix:", "New:", etc.) is correct based on the issue (or, if no issue is referenced, based on the stated problem).
 1. Does the code follow our conventions (including header comments, JSDoc comments, etc.)? If not, please leave that feedback and reference the conventions document.
 1. For code changes:
     * Are there tests that verify the change? If not, please ask for them.
@@ -38,6 +38,7 @@ Committers may merge a pull request if it is a non-breaking change and is:
 1. A bug fix (for either rules or core)
 1. A dependency upgrade
 1. Related to the build system
+1. A chore
 
 In addition, committers may merge any non-breaking pull request if it has been approved by at least one TSC member.
 
diff --git a/docs/rules/object-curly-newline.md b/docs/rules/object-curly-newline.md
index 40f5368e5..a4907046f 100644
--- a/docs/rules/object-curly-newline.md
+++ b/docs/rules/object-curly-newline.md
@@ -16,7 +16,7 @@ This rule has either a string option:
 Or an object option:
 
 * `"multiline": true` (default) requires line breaks if there are line breaks inside properties or between properties
-* `"minProperties"` requires line breaks if the number of properties is more than the given integer. By default, an error will also be reported if an object contains linebreaks and has fewer properties than the given integer. However, the second behavior is disabled if the `consistent` option is set to `true`
+* `"minProperties"` requires line breaks if the number of properties is at least the given integer. By default, an error will also be reported if an object contains linebreaks and has fewer properties than the given integer. However, the second behavior is disabled if the `consistent` option is set to `true`
 * `"consistent": true` requires that either both curly braces, or neither, directly enclose newlines. Note that enabling this option will also change the behavior of the `minProperties` option. (See `minProperties` above for more information)
 
 You can specify different options for object literals and destructuring assignments:
diff --git a/lib/cli.js b/lib/cli.js
index 530bfbc42..d39847718 100644
--- a/lib/cli.js
+++ b/lib/cli.js
@@ -28,6 +28,17 @@ const debug = require("debug")("eslint:cli");
 // Helpers
 //------------------------------------------------------------------------------
 
+/**
+ * Predicate function for whether or not to apply fixes in quiet mode.
+ * If a message is a warning, do not apply a fix.
+ * @param {LintResult} lintResult The lint result.
+ * @returns {boolean} True if the lint message is an error (and thus should be
+ * autofixed), false otherwise.
+ */
+function quietFixPredicate(lintResult) {
+    return lintResult.severity === 2;
+}
+
 /**
  * Translates the CLI options into the options expected by the CLIEngine.
  * @param {Object} cliOptions The CLI options to translate.
@@ -52,7 +63,7 @@ function translateOptions(cliOptions) {
         cache: cliOptions.cache,
         cacheFile: cliOptions.cacheFile,
         cacheLocation: cliOptions.cacheLocation,
-        fix: cliOptions.fix,
+        fix: cliOptions.fix && (cliOptions.quiet ? quietFixPredicate : true),
         allowInlineConfig: cliOptions.inlineConfig
     };
 }
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index 78c8bb9af..c8195c7d7 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -1030,7 +1030,7 @@ module.exports = {
                 const nodeTokens = getTokensAndComments(node);
                 const tokensFromOperator = nodeTokens.slice(lodash.sortedIndexBy(nodeTokens, operator, token => token.range[0]));
 
-                offsets.setDesiredOffsets(tokensFromOperator, sourceCode.getFirstToken(node.left), 1);
+                offsets.setDesiredOffsets(tokensFromOperator, sourceCode.getLastToken(node.left), 1);
                 offsets.ignoreToken(tokensFromOperator[0]);
                 offsets.ignoreToken(tokensFromOperator[1]);
             },
@@ -1325,12 +1325,12 @@ module.exports = {
             VariableDeclarator(node) {
                 if (node.init) {
                     const equalOperator = sourceCode.getTokenBefore(node.init, astUtils.isNotOpeningParenToken);
-                    const tokenAfterOperator = sourceCode.getTokenAfter(equalOperator);
+                    const tokensAfterOperator = sourceCode.getTokensAfter(equalOperator, token => token.range[1] <= node.range[1]);
 
                     offsets.ignoreToken(equalOperator);
-                    offsets.ignoreToken(tokenAfterOperator);
-                    offsets.matchIndentOf(equalOperator, tokenAfterOperator);
-                    offsets.matchIndentOf(sourceCode.getFirstToken(node), equalOperator);
+                    offsets.ignoreToken(tokensAfterOperator[0]);
+                    offsets.setDesiredOffsets(tokensAfterOperator, equalOperator, 1);
+                    offsets.matchIndentOf(sourceCode.getLastToken(node.id), equalOperator);
                 }
             },
 
diff --git a/lib/rules/no-sync.js b/lib/rules/no-sync.js
index 885b1eb62..06305969a 100644
--- a/lib/rules/no-sync.js
+++ b/lib/rules/no-sync.js
@@ -19,14 +19,26 @@ module.exports = {
             recommended: false
         },
 
-        schema: []
+        schema: [
+            {
+                type: "object",
+                properties: {
+                    allowAtRootLevel: {
+                        type: "boolean"
+                    }
+                },
+                additionalProperties: false
+            }
+        ]
     },
 
     create(context) {
+        const selector = context.options[0] && context.options[0].allowAtRootLevel
+            ? ":function MemberExpression[property.name=/.*Sync$/]"
+            : "MemberExpression[property.name=/.*Sync$/]";
 
         return {
-
-            "MemberExpression[property.name=/.*Sync$/]"(node) {
+            [selector](node) {
                 context.report({
                     node,
                     message: "Unexpected sync method: '{{propertyName}}'.",


Test patch:
diff --git a/tests/bin/eslint.js b/tests/bin/eslint.js
index c7e97a00c..7c5cd6552 100644
--- a/tests/bin/eslint.js
+++ b/tests/bin/eslint.js
@@ -112,6 +112,7 @@ describe("bin/eslint.js", () => {
         const tempFilePath = `${fixturesPath}/temp.js`;
         const startingText = fs.readFileSync(`${fixturesPath}/left-pad.js`).toString();
         const expectedFixedText = fs.readFileSync(`${fixturesPath}/left-pad-expected.js`).toString();
+        const expectedFixedTextQuiet = fs.readFileSync(`${fixturesPath}/left-pad-expected-quiet.js`).toString();
 
         beforeEach(() => {
             fs.writeFileSync(tempFilePath, startingText);
@@ -127,6 +128,17 @@ describe("bin/eslint.js", () => {
             return Promise.all([exitCodeAssertion, outputFileAssertion]);
         });
 
+        it("has exit code 0, fixes errors in a file, and does not report or fix warnings if --quiet and --fix are used", () => {
+            const child = runESLint(["--fix", "--quiet", "--no-eslintrc", "--no-ignore", tempFilePath]);
+            const exitCodeAssertion = assertExitCode(child, 0);
+            const stdoutAssertion = getStdout(child).then(stdout => assert.strictEqual(stdout, ""));
+            const outputFileAssertion = awaitExit(child).then(() => {
+                assert.strictEqual(fs.readFileSync(tempFilePath).toString(), expectedFixedTextQuiet);
+            });
+
+            return Promise.all([exitCodeAssertion, stdoutAssertion, outputFileAssertion]);
+        });
+
         it("has exit code 1 and fixes a file if not all rules can be fixed", () => {
             const child = runESLint(["--fix", "--no-eslintrc", "--no-ignore", "--rule", "max-len: [2, 10]", tempFilePath]);
             const exitCodeAssertion = assertExitCode(child, 1);
diff --git a/tests/fixtures/autofix-integration/left-pad-expected-quiet.js b/tests/fixtures/autofix-integration/left-pad-expected-quiet.js
new file mode 100644
index 000000000..b189698bf
--- /dev/null
+++ b/tests/fixtures/autofix-integration/left-pad-expected-quiet.js
@@ -0,0 +1,33 @@
+/* eslint dot-notation: 2 */
+/* eslint indent: [2, 2] */
+/* eslint no-extra-parens: 2 */
+/* eslint no-implicit-coercion: 2 */
+/* eslint no-whitespace-before-property: 2 */
+/* eslint quotes: [2, "single"] */
+/* eslint semi: 2 */
+/* eslint semi-spacing: 2 */
+/* eslint space-before-function-paren: 2 */
+/* eslint space-before-blocks: 1 */
+
+/*
+* left-pad@0.0.3
+* WTFPL https://github.com/stevemao/left-pad/blob/aff6d744155a70b81f09effb8185a1564f348462/COPYING
+*/
+
+module.exports = leftpad;
+
+function leftpad (str, len, ch){
+  str = String(str);
+
+  var i = -1;
+
+  ch || (ch = ' ');
+  len = len - str.length;
+
+
+  while (++i < len) {
+    str = ch + str;
+  }
+
+  return str;
+}
diff --git a/tests/fixtures/autofix-integration/left-pad-expected.js b/tests/fixtures/autofix-integration/left-pad-expected.js
index 9e2a8321d..24da3ce17 100644
--- a/tests/fixtures/autofix-integration/left-pad-expected.js
+++ b/tests/fixtures/autofix-integration/left-pad-expected.js
@@ -7,6 +7,7 @@
 /* eslint semi: 2 */
 /* eslint semi-spacing: 2 */
 /* eslint space-before-function-paren: 2 */
+/* eslint space-before-blocks: 1 */
 
 /*
 * left-pad@0.0.3
diff --git a/tests/fixtures/autofix-integration/left-pad.js b/tests/fixtures/autofix-integration/left-pad.js
index 1dd798ff8..7b673577e 100644
--- a/tests/fixtures/autofix-integration/left-pad.js
+++ b/tests/fixtures/autofix-integration/left-pad.js
@@ -7,6 +7,7 @@
 /* eslint semi: 2 */
 /* eslint semi-spacing: 2 */
 /* eslint space-before-function-paren: 2 */
+/* eslint space-before-blocks: 1 */
 
 /*
 * left-pad@0.0.3
@@ -15,7 +16,7 @@
 
 module.exports = (leftpad)
 
-   function leftpad(str, len, ch) {
+   function leftpad(str, len, ch){
   str = ("" + str);
 
          var i = -1 ;
diff --git a/tests/lib/cli.js b/tests/lib/cli.js
index a0bcb37cf..b75640d4a 100644
--- a/tests/lib/cli.js
+++ b/tests/lib/cli.js
@@ -804,7 +804,7 @@ describe("cli", () => {
 
         });
 
-        it("should rewrite files when in fix mode and quiet mode", () => {
+        it("should provide fix predicate and rewrite files when in fix mode and quiet mode", () => {
 
             const report = {
                 errorCount: 0,
@@ -822,7 +822,7 @@ describe("cli", () => {
             };
 
             // create a fake CLIEngine to test with
-            const fakeCLIEngine = sandbox.mock().withExactArgs(sinon.match({ fix: true }));
+            const fakeCLIEngine = sandbox.mock().withExactArgs(sinon.match({ fix: sinon.match.func }));
 
             fakeCLIEngine.prototype = leche.fake(CLIEngine.prototype);
             sandbox.stub(fakeCLIEngine.prototype, "executeOnFiles").returns(report);
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index f5a57e1ee..17e5b5357 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -67,7 +67,7 @@ function unIndent(strings) {
     return lines.map(line => line.slice(minLineIndent)).join("\n");
 }
 
-const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } });
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8, ecmaFeatures: { jsx: true } } });
 
 ruleTester.run("indent", rule, {
     valid: [
@@ -3891,6 +3891,67 @@ ruleTester.run("indent", rule, {
             `
         },
 
+        // https://github.com/eslint/eslint/issues/8815
+        {
+            code: unIndent`
+                async function test() {
+                    const {
+                        foo,
+                        bar,
+                    } = await doSomethingAsync(
+                        1,
+                        2,
+                        3,
+                    );
+                }
+            `
+        },
+        {
+            code: unIndent`
+                function* test() {
+                    const {
+                        foo,
+                        bar,
+                    } = yield doSomethingAsync(
+                        1,
+                        2,
+                        3,
+                    );
+                }
+            `
+        },
+        {
+            code: unIndent`
+                ({
+                    a: b
+                } = +foo(
+                    bar
+                ));
+            `
+        },
+        {
+            code: unIndent`
+                const {
+                    foo,
+                    bar,
+                } = typeof foo(
+                    1,
+                    2,
+                    3,
+                );
+            `
+        },
+        {
+            code: unIndent`
+                const {
+                    foo,
+                    bar,
+                } = +(
+                    foo
+                );
+            `
+        },
+
         //----------------------------------------------------------------------
         // JSX tests
         // https://github.com/eslint/eslint/issues/8425
diff --git a/tests/lib/rules/no-sync.js b/tests/lib/rules/no-sync.js
index 349e198cb..026db6862 100644
--- a/tests/lib/rules/no-sync.js
+++ b/tests/lib/rules/no-sync.js
@@ -20,10 +20,18 @@ const ruleTester = new RuleTester();
 
 ruleTester.run("no-sync", rule, {
     valid: [
-        "var foo = fs.foo.foo();"
+        "var foo = fs.foo.foo();",
+        { code: "var foo = fs.fooSync;", options: [{ allowAtRootLevel: true }] },
+        { code: "if (true) {fs.fooSync();}", options: [{ allowAtRootLevel: true }] }
     ],
     invalid: [
         { code: "var foo = fs.fooSync();", errors: [{ message: "Unexpected sync method: 'fooSync'.", type: "MemberExpression" }] },
-        { code: "var foo = fs.fooSync;", errors: [{ message: "Unexpected sync method: 'fooSync'.", type: "MemberExpression" }] }
+        { code: "var foo = fs.fooSync();", options: [{ allowAtRootLevel: false }], errors: [{ message: "Unexpected sync method: 'fooSync'.", type: "MemberExpression" }] },
+        { code: "if (true) {fs.fooSync();}", errors: [{ message: "Unexpected sync method: 'fooSync'.", type: "MemberExpression" }] },
+        { code: "var foo = fs.fooSync;", errors: [{ message: "Unexpected sync method: 'fooSync'.", type: "MemberExpression" }] },
+        { code: "function someFunction() {fs.fooSync();}", errors: [{ message: "Unexpected sync method: 'fooSync'.", type: "MemberExpression" }] },
+        { code: "function someFunction() {fs.fooSync();}", options: [{ allowAtRootLevel: true }], errors: [{ message: "Unexpected sync method: 'fooSync'.", type: "MemberExpression" }] },
+        { code: "var a = function someFunction() {fs.fooSync();}", options: [{ allowAtRootLevel: true }], errors: [{ message: "Unexpected sync method: 'fooSync'.", type: "MemberExpression" }] }
+
     ]
 });