Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add new rule no-empty-static-block #16325

Merged
merged 11 commits into from Nov 6, 2022
7 changes: 7 additions & 0 deletions docs/src/_data/further_reading_links.json
Expand Up @@ -698,5 +698,12 @@
"logo": "https://eslint.org/apple-touch-icon.png",
"title": "Interesting bugs caught by no-constant-binary-expression - ESLint - Pluggable JavaScript Linter",
"description": "A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease."
},
"https://github.com/tc39/proposal-class-static-block": {
"domain": "github.com",
"url": "https://github.com/tc39/proposal-class-static-block",
"logo": "https://github.com/fluidicon.png",
"title": "GitHub - tc39/proposal-class-static-block: ECMAScript class static initialization blocks",
"description": "ECMAScript class static initialization blocks. Contribute to tc39/proposal-class-static-block development by creating an account on GitHub."
}
}
56 changes: 56 additions & 0 deletions docs/src/rules/no-empty-static-block.md
@@ -0,0 +1,56 @@
---
title: no-empty-static-block
layout: doc
rule_type: suggestion
related_rules:
- no-empty
- no-empty-function
further_reading:
- https://github.com/tc39/proposal-class-static-block
---

Empty static blocks, while not technically errors, usually occur due to refactoring that wasn't completed. They can cause confusion when reading code.

## Rule Details

This rule disallows empty static blocks. This rule ignores static blocks which contain a comment.

Examples of **incorrect** code for this rule:

::: incorrect

```js
/*eslint no-empty-static-block: "error"*/

class Foo {
static {}
}
```

:::

Examples of **correct** code for this rule:

:::correct

```js
/*eslint no-empty-static-block: "error"*/

class Foo {
static {
bar();
}
}

class Foo {
static {
// comment
}
}
```

:::

## When Not To Use It

This rule should not be used in environments prior to ES2022.
1 change: 1 addition & 0 deletions lib/rules/index.js
Expand Up @@ -123,6 +123,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
"no-empty-character-class": () => require("./no-empty-character-class"),
"no-empty-function": () => require("./no-empty-function"),
"no-empty-pattern": () => require("./no-empty-pattern"),
"no-empty-static-block": () => require("./no-empty-static-block"),
"no-eq-null": () => require("./no-eq-null"),
"no-eval": () => require("./no-eval"),
"no-ex-assign": () => require("./no-ex-assign"),
Expand Down
49 changes: 49 additions & 0 deletions lib/rules/no-empty-static-block.js
@@ -0,0 +1,49 @@
/**
* @fileoverview Rule to disallow empty static blocks.
* @author Sosuke Suzuki
*/
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
type: "suggestion",

docs: {
description: "Disallow empty static blocks",
recommended: false,
url: "https://eslint.org/docs/rules/no-empty-static-block"
},

schema: [],

messages: {
unexpected: "Unexpected empty static block."
}
},

create(context) {
const sourceCode = context.getSourceCode();

return {
StaticBlock(node) {
const [blockOpenToken] = sourceCode.getFirstTokens(node, {
filter: token => token.type === "Punctuator" && token.value === "{"
});
const innerComments =
sourceCode.getCommentsInside(node).filter(commentToken => blockOpenToken.range[1] < commentToken.range[0]);

if (node.body.length === 0 && innerComments.length === 0) {
context.report({
node,
messageId: "unexpected"
});
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should move token calculations into if (node.body.length === 0) {}, for performance reasons.

It could be something like this:

Suggested change
StaticBlock(node) {
const [blockOpenToken] = sourceCode.getFirstTokens(node, {
filter: token => token.type === "Punctuator" && token.value === "{"
});
const innerComments =
sourceCode.getCommentsInside(node).filter(commentToken => blockOpenToken.range[1] < commentToken.range[0]);
if (node.body.length === 0 && innerComments.length === 0) {
context.report({
node,
messageId: "unexpected"
});
}
}
StaticBlock(node) {
if (node.body.length === 0) {
const closingBrace = sourceCode.getLastToken(node);
if (sourceCode.getCommentsBefore(closingBrace).length === 0) {
context.report({
node,
messageId: "unexpected"
});
}
}
}

};
}
};
51 changes: 51 additions & 0 deletions tests/lib/rules/no-empty-static-block.js
@@ -0,0 +1,51 @@
/**
* @fileoverview Tests for no-empty-static-block rule.
* @author Sosuke Suzuki
*/
"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const rule = require("../../../lib/rules/no-empty-static-block"),
{ RuleTester } = require("../../../lib/rule-tester");

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

const ruleTester = new RuleTester({
parserOptions: { ecmaVersion: 2022 }
});

ruleTester.run("no-empty-static-block", rule, {
valid: [
"class Foo { static { bar(); } }",
"class Foo { static { /* comments */ } }",
"class Foo { static {\n// comment\n} }",
"class Foo { static { bar(); } static { bar(); } }"
],
invalid: [
{
code: "class Foo { static {} }",
errors: [{ messageId: "unexpected" }]
},
{
code: "class Foo { static { } }",
errors: [{ messageId: "unexpected" }]
},
{
code: "class Foo { static { \n\n } }",
errors: [{ messageId: "unexpected" }]
},
{
code: "class Foo { static { bar(); } static {} }",
errors: [{ messageId: "unexpected" }]
},
{
code: "class Foo { static // comment\n {} }",
errors: [{ messageId: "unexpected" }]
}
]
});
1 change: 1 addition & 0 deletions tools/rule-types.json
Expand Up @@ -110,6 +110,7 @@
"no-empty-character-class": "problem",
"no-empty-function": "suggestion",
"no-empty-pattern": "problem",
"no-empty-static-block": "suggestion",
"no-eq-null": "suggestion",
"no-eval": "suggestion",
"no-ex-assign": "problem",
Expand Down