Repository: eslint/eslint (JavaScript)

Issue:
Indent level (parameters: first) for async arrow functions
Probably the same as #10531 which was automatically closed due to inactivity 2 years ago.

**Tell us about your environment**

ESLint Version: **7.4.0**
Node Version: **14.5.0**
yarn Version: **1.22.4**
What parser (default, Babel-ESLint, etc.) are you using? **espree & @typescript-eslint/parser**

**Configuration**

```javascript
const indentOptions = {
  "FunctionDeclaration": { "parameters": "first" },
  "FunctionExpression": { "parameters": "first" },
};
const indent = ["error", 2, indentOptions];

module.exports = {
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: "module"
  },
  overrides: [
    {
      files: ["*.js"],
      parser: "espree",
      rules: {
        indent: indent
      }
    }
  ]
};
```

**What did you do?**

```javascript
const foo = async (arg1,
                   arg2) =>
{
  return arg1 + arg2;
}
```

```node_modules/.bin/eslint foo.js```

**What did you expect to happen?**

Run without errors

**What actually happened?**

```bash
/private/tmp/foo/foo.js
  2:1  error  Expected indentation of 2 spaces but found 19  indent

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.
```

**Note:** if I remove the async then the error goes away (the "parameters": "first" is honoured).


Discussion:
Thanks for the report 👍 

I think this is a bug and I can reproduce this. [demo](https://eslint.org/demo#eyJ0ZXh0IjoiLyplc2xpbnQgaW5kZW50OiBbXCJlcnJvclwiLCAyLCB7IFwiRnVuY3Rpb25EZWNsYXJhdGlvblwiOiB7XCJwYXJhbWV0ZXJzXCI6IFwiZmlyc3RcIn0sXCJGdW5jdGlvbkV4cHJlc3Npb25cIjoge1wicGFyYW1ldGVyc1wiOiBcImZpcnN0XCJ9IH1dKi9cblxuY29uc3QgZm9vID0gYXN5bmMgKGFyZzEsXG4gICAgICAgICAgICAgICAgICAgYXJnMikgPT5cbntcbiAgcmV0dXJuIGFyZzEgKyBhcmcyO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmKGFyZzEsXG4gICAgICAgICAgICAgICAgIGFyZzIpe1xufVxuXG5jb25zdCBmZiA9IGFzeW5jIGZ1bmN0aW9uKGFyZzEsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGFyZzIpe30iLCJvcHRpb25zIjp7InBhcnNlck9wdGlvbnMiOnsiZWNtYVZlcnNpb24iOjExLCJzb3VyY2VUeXBlIjoic2NyaXB0IiwiZWNtYUZlYXR1cmVzIjp7fX0sInJ1bGVzIjp7ImluZGVudCI6Mn0sImVudiI6e319fQ==)
I agree 👍  It seems a bug to me



Patch:
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index 22b633845b59..1c0dccc5c989 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -1084,16 +1084,17 @@ module.exports = {
             },
 
             ArrowFunctionExpression(node) {
-                const firstToken = sourceCode.getFirstToken(node);
+                const maybeOpeningParen = sourceCode.getFirstToken(node, { skip: node.async ? 1 : 0 });
 
-                if (astUtils.isOpeningParenToken(firstToken)) {
-                    const openingParen = firstToken;
+                if (astUtils.isOpeningParenToken(maybeOpeningParen)) {
+                    const openingParen = maybeOpeningParen;
                     const closingParen = sourceCode.getTokenBefore(node.body, astUtils.isClosingParenToken);
 
                     parameterParens.add(openingParen);
                     parameterParens.add(closingParen);
                     addElementListIndent(node.params, openingParen, closingParen, options.FunctionExpression.parameters);
                 }
+
                 addBlocklessNodeIndent(node.body);
             },
 


Test patch:
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index b253be220675..ad35ad09c70d 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -5724,6 +5724,105 @@ ruleTester.run("indent", rule, {
             `,
             options: [4, { MemberExpression: 2 }],
             parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: unIndent`
+                const foo = async (arg1,
+                                   arg2) =>
+                {
+                  return arg1 + arg2;
+                }
+            `,
+            options: [2, { FunctionDeclaration: { parameters: "first" }, FunctionExpression: { parameters: "first" } }]
+        },
+        {
+            code: unIndent`
+                const foo = async /* some comments */(arg1,
+                                                      arg2) =>
+                {
+                  return arg1 + arg2;
+                }
+            `,
+            options: [2, { FunctionDeclaration: { parameters: "first" }, FunctionExpression: { parameters: "first" } }]
+        },
+        {
+            code: unIndent`
+                const a = async
+                b => {}
+            `,
+            options: [2]
+        },
+        {
+            code: unIndent`
+                const foo = (arg1,
+                             arg2) => async (arr1,
+                                             arr2) =>
+                {
+                  return arg1 + arg2;
+                }
+            `,
+            options: [2, { FunctionDeclaration: { parameters: "first" }, FunctionExpression: { parameters: "first" } }]
+        },
+        {
+            code: unIndent`
+                const foo = async (arg1,
+                  arg2) =>
+                {
+                  return arg1 + arg2;
+                }
+            `,
+            options: [2]
+        },
+        {
+            code: unIndent`
+                const foo = async /*comments*/(arg1,
+                  arg2) =>
+                {
+                  return arg1 + arg2;
+                }
+            `,
+            options: [2]
+        },
+        {
+            code: unIndent`
+                const foo = async (arg1,
+                        arg2) =>
+                {
+                  return arg1 + arg2;
+                }
+            `,
+            options: [2, { FunctionDeclaration: { parameters: 4 }, FunctionExpression: { parameters: 4 } }]
+        },
+        {
+            code: unIndent`
+                const foo = (arg1,
+                        arg2) =>
+                {
+                  return arg1 + arg2;
+                }
+            `,
+            options: [2, { FunctionDeclaration: { parameters: 4 }, FunctionExpression: { parameters: 4 } }]
+        },
+        {
+            code: unIndent`
+                async function fn(ar1,
+                                  ar2){}
+            `,
+            options: [2, { FunctionDeclaration: { parameters: "first" }, FunctionExpression: { parameters: "first" } }]
+        },
+        {
+            code: unIndent`
+                async function /* some comments */ fn(ar1,
+                                                      ar2){}
+            `,
+            options: [2, { FunctionDeclaration: { parameters: "first" }, FunctionExpression: { parameters: "first" } }]
+        },
+        {
+            code: unIndent`
+                async  /* some comments */  function fn(ar1,
+                                                        ar2){}
+            `,
+            options: [2, { FunctionDeclaration: { parameters: "first" }, FunctionExpression: { parameters: "first" } }]
         }
     ],
 
@@ -11473,6 +11572,41 @@ ruleTester.run("indent", rule, {
                 [6, 4, 0, "Punctuator"],
                 [7, 4, 0, "Punctuator"]
             ])
+        },
+        {
+            code: unIndent`
+                const foo = async (arg1,
+                                    arg2) =>
+                {
+                  return arg1 + arg2;
+                }
+            `,
+            output: unIndent`
+                const foo = async (arg1,
+                                   arg2) =>
+                {
+                  return arg1 + arg2;
+                }
+            `,
+            options: [2, { FunctionDeclaration: { parameters: "first" }, FunctionExpression: { parameters: "first" } }],
+            parserOptions: { ecmaVersion: 2020 },
+            errors: expectedErrors([
+                [2, 19, 20, "Identifier"]
+            ])
+        },
+        {
+            code: unIndent`
+                const a = async
+                 b => {}
+            `,
+            output: unIndent`
+                const a = async
+                b => {}
+            `,
+            options: [2],
+            errors: expectedErrors([
+                [2, 0, 1, "Identifier"]
+            ])
         }
     ]
 });