diff --git a/docs/rules/no-classes.md b/docs/rules/no-classes.md
index 66c02a38c..50cceebbd 100644
--- a/docs/rules/no-classes.md
+++ b/docs/rules/no-classes.md
@@ -53,43 +53,29 @@ const dogA = {
console.log(`${dogA.name} is ${getAgeInDogYears(dogA.age)} in dog years.`);
```
-### React Examples
+## Options
-Thanks to libraries like [recompose](https://github.com/acdlite/recompose) and Redux's
-[React Container components](http://redux.js.org/docs/basics/UsageWithReact.html), there's not much reason to build
-Components using `React.createClass` or ES6 classes anymore. The `no-this-expressions` rule makes this explicit.
+This rule accepts an options object of the following type:
-```js
-const Message = React.createClass({
- render() {
- return
{this.props.message}
; // <- no this allowed
- },
-});
+```ts
+type Options = {
+ ignoreIdentifierPattern?: string[] | string;
+ ignoreCodePattern?: string[] | string;
+};
```
-Instead of creating classes, you should use React 0.14's
-[Stateless Functional
-Components](https://medium.com/@joshblack/stateless-components-in-react-0-14-f9798f8b992d#.t5z2fdit6)
-and save yourself some keystrokes:
+### Default Options
-```js
-const Message = ({ message }) => {message}
;
+```ts
+const defaults = {};
```
-What about lifecycle methods like `shouldComponentUpdate`?
-We can use the [recompose](https://github.com/acdlite/recompose) library to apply these optimizations to your
-Stateless Functional Components. The [recompose](https://github.com/acdlite/recompose) library relies on the fact that
-your Redux state is immutable to efficiently implement `shouldComponentUpdate` for you.
+### `ignoreIdentifierPattern`
-```js
-import { onlyUpdateForKeys, pure } from "recompose";
-
-const Message = ({ message }) => {message}
;
+This option takes a RegExp string or an array of RegExp strings.
+It allows for the ability to ignore violations based on the class's name.
-// Optimized version of same component, using shallow comparison of props
-// Same effect as React's PureRenderMixin
-const OptimizedMessage = pure(Message);
+### `ignoreCodePattern`
-// Even more optimized: only updates if specific prop keys have changed
-const HyperOptimizedMessage = onlyUpdateForKeys(["message"], Message);
-```
+This option takes a RegExp string or an array of RegExp strings.
+It allows for the ability to ignore violations based on the code itself.
diff --git a/src/rules/no-classes.ts b/src/rules/no-classes.ts
index cc2c52f7e..7f04c9788 100644
--- a/src/rules/no-classes.ts
+++ b/src/rules/no-classes.ts
@@ -1,6 +1,14 @@
import { type JSONSchema4 } from "@typescript-eslint/utils/json-schema";
import { type RuleContext } from "@typescript-eslint/utils/ts-eslint";
+import { deepmerge } from "deepmerge-ts";
+import {
+ type IgnoreCodePatternOption,
+ type IgnoreIdentifierPatternOption,
+ ignoreCodePatternOptionSchema,
+ ignoreIdentifierPatternOptionSchema,
+ shouldIgnorePattern,
+} from "#/options";
import { ruleNameScope } from "#/utils/misc";
import { type ESClass } from "#/utils/node-types";
import {
@@ -23,12 +31,21 @@ export const fullName: `${typeof ruleNameScope}/${typeof name}` = `${ruleNameSco
/**
* The options this rule can take.
*/
-type Options = [{}];
+type Options = [IgnoreIdentifierPatternOption & IgnoreCodePatternOption];
/**
* The schema for the rule options.
*/
-const schema: JSONSchema4[] = [];
+const schema: JSONSchema4[] = [
+ {
+ type: "object",
+ properties: deepmerge(
+ ignoreIdentifierPatternOptionSchema,
+ ignoreCodePatternOptionSchema,
+ ),
+ additionalProperties: false,
+ },
+];
/**
* The default options for the rule.
@@ -64,8 +81,26 @@ const meta: NamedCreateRuleCustomMeta = {
function checkClass(
node: ESClass,
context: Readonly>,
+ options: Readonly,
): RuleResult {
- // All class nodes violate this rule.
+ const [optionsObject] = options;
+ const { ignoreIdentifierPattern, ignoreCodePattern } = optionsObject;
+
+ if (
+ shouldIgnorePattern(
+ node,
+ context,
+ ignoreIdentifierPattern,
+ undefined,
+ ignoreCodePattern,
+ )
+ ) {
+ return {
+ context,
+ descriptors: [],
+ };
+ }
+
return { context, descriptors: [{ node, messageId: "generic" }] };
}
diff --git a/tests/rules/__snapshots__/no-classes.test.ts.snap b/tests/rules/__snapshots__/no-classes.test.ts.snap
index b4d296a36..cc30e10ef 100644
--- a/tests/rules/__snapshots__/no-classes.test.ts.snap
+++ b/tests/rules/__snapshots__/no-classes.test.ts.snap
@@ -1,5 +1,37 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+exports[`no-classes > javascript - es latest > ignoreCodePattern > should report classes with non-matching identifiers 1`] = `
+[
+ {
+ "column": 1,
+ "endColumn": 13,
+ "endLine": 1,
+ "line": 1,
+ "message": "Unexpected class, use functions not classes.",
+ "messageId": "generic",
+ "nodeType": "ClassDeclaration",
+ "ruleId": "no-classes",
+ "severity": 2,
+ },
+]
+`;
+
+exports[`no-classes > javascript - es latest > options > ignoreIdentifierPattern > should report classes with non-matching identifiers 1`] = `
+[
+ {
+ "column": 1,
+ "endColumn": 13,
+ "endLine": 1,
+ "line": 1,
+ "message": "Unexpected class, use functions not classes.",
+ "messageId": "generic",
+ "nodeType": "ClassDeclaration",
+ "ruleId": "no-classes",
+ "severity": 2,
+ },
+]
+`;
+
exports[`no-classes > javascript - es latest > reports class declarations 1`] = `
[
{
diff --git a/tests/rules/no-classes.test.ts b/tests/rules/no-classes.test.ts
index 05346b6c0..b78e8951f 100644
--- a/tests/rules/no-classes.test.ts
+++ b/tests/rules/no-classes.test.ts
@@ -1,3 +1,4 @@
+import dedent from "dedent";
import { createRuleTester } from "eslint-vitest-rule-tester";
import { describe, expect, it } from "vitest";
@@ -30,5 +31,51 @@ describe(name, () => {
});
expect(invalidResult2.messages).toMatchSnapshot();
});
+
+ describe("options", () => {
+ describe("ignoreIdentifierPattern", () => {
+ it("should not report classes with matching identifiers", () => {
+ valid({
+ code: dedent`
+ class Foo {}
+ `,
+ options: [{ ignoreIdentifierPattern: "^Foo$" }],
+ });
+ });
+
+ it("should report classes with non-matching identifiers", () => {
+ const invalidResult = invalid({
+ code: dedent`
+ class Bar {}
+ `,
+ options: [{ ignoreIdentifierPattern: "^Foo$" }],
+ errors: ["generic"],
+ });
+ expect(invalidResult.messages).toMatchSnapshot();
+ });
+ });
+ });
+
+ describe("ignoreCodePattern", () => {
+ it("should not report classes with matching identifiers", () => {
+ valid({
+ code: dedent`
+ class Foo {}
+ `,
+ options: [{ ignoreCodePattern: "class Foo" }],
+ });
+ });
+
+ it("should report classes with non-matching identifiers", () => {
+ const invalidResult = invalid({
+ code: dedent`
+ class Bar {}
+ `,
+ options: [{ ignoreCodePattern: "class Foo" }],
+ errors: ["generic"],
+ });
+ expect(invalidResult.messages).toMatchSnapshot();
+ });
+ });
});
});