Repository: sindresorhus/eslint-plugin-unicorn (JavaScript)

Issue:
prefer-top-level-await flags code that can't be top-level-awaited
<!-- ✨ Thanks for reporting a bug! ➡️ Please don't ignore this template -->

<!-- 1️⃣ Explain here what's wrong -->

In class definitions top-level-await is not available but this rule still marks the code as wrong

<!-- 2️⃣ Specify which rule is buggy here and in the title -->

The rule: [unicorn/prefer-top-level-await](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v43.0.0/docs/rules/prefer-top-level-await.md)

<!-- 3️⃣ Add some examples where the issue appears -->

```js
class Example {
    property = Promise // Can't await here
        .resolve(1)
        .then(i => i+1); // Error here <- Prefer top-level await over using a promise chain.
}
```



Discussion:
I'm confused, I can't find anything forbid TLA in class member, [the spec](https://tc39.es/proposal-top-level-await/), [acorn PR](https://github.com/acornjs/acorn/commit/65a9137ac9501d27e41aa37a48e1eddc0c605cda), [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await). 

But Node.js/browsers/parsers all(except `@typescript-eslint/parser` which can't be trust) failed to pase `class A {foo = await 1}`. 

So the real question is where the TLA expression can be?


Because when parsing class member, the parser enters a non-async function? Need more time to learn the spec.
Maybe the Initializer which runs for ClassFields is a part of the constructor which doesn't allow async?



Patch:
diff --git a/rules/prefer-top-level-await.js b/rules/prefer-top-level-await.js
index ea279c9241..615fd858cb 100644
--- a/rules/prefer-top-level-await.js
+++ b/rules/prefer-top-level-await.js
@@ -1,6 +1,6 @@
 'use strict';
 const {findVariable, getFunctionHeadLocation} = require('eslint-utils');
-const {matches, memberExpressionSelector} = require('./selectors/index.js');
+const {matches, not, memberExpressionSelector} = require('./selectors/index.js');
 
 const ERROR_PROMISE = 'promise';
 const ERROR_IIFE = 'iife';
@@ -15,7 +15,10 @@ const messages = {
 
 const promiseMethods = ['then', 'catch', 'finally'];
 
-const topLevelCallExpression = 'CallExpression:not(:function *)';
+const topLevelCallExpression = [
+	'CallExpression',
+	not([':function *', 'ClassDeclaration *', 'ClassExpression *']),
+].join('');
 const iife = [
 	topLevelCallExpression,
 	matches([


Test patch:
diff --git a/test/prefer-top-level-await.mjs b/test/prefer-top-level-await.mjs
index 8d7ef97be8..b4bdd083d7 100644
--- a/test/prefer-top-level-await.mjs
+++ b/test/prefer-top-level-await.mjs
@@ -47,6 +47,30 @@ test.snapshot({
 		'await foo.then?.(bar)',
 		'await foo.then(bar)?.catch(bar)',
 		'await foo.then(bar)?.catch?.(bar)',
+		outdent`
+			class Example {
+				property = promise.then(bar)
+			}
+		`,
+		outdent`
+			const Example = class Example {
+				property = promise.then(bar)
+			}
+		`,
+		outdent`
+			class Example {
+				static {
+					promise.then(bar)
+				}
+			}
+		`,
+		outdent`
+			const Example = class Example {
+				static {
+					promise.then(bar)
+				}
+			}
+		`,
 	],
 	invalid: [
 		'foo.then(bar)',