From dd109379f730a988a9e6c0102bcfe443ad0b4b94 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Fri, 3 Sep 2021 20:17:04 -0400 Subject: [PATCH] Update: added ignoreExpressions option to max-classes-per-file (#15000) * Update: added ignoreExpressions option to max-classes-per-file * Apply suggestions from code review Co-authored-by: Nicholas C. Zakas * Missed a spot Co-authored-by: Nicholas C. Zakas --- docs/rules/max-classes-per-file.md | 35 +++++++++++++++++-- lib/rules/max-classes-per-file.js | 38 ++++++++++++++++---- tests/lib/rules/max-classes-per-file.js | 46 +++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 10 deletions(-) diff --git a/docs/rules/max-classes-per-file.md b/docs/rules/max-classes-per-file.md index 98ca1d1003d..70f3348a0fa 100644 --- a/docs/rules/max-classes-per-file.md +++ b/docs/rules/max-classes-per-file.md @@ -28,8 +28,12 @@ class Foo {} ## Options -This rule has a numeric option (defaulted to 1) to specify the -maximum number of classes. +This rule may be configured with either an object or a number. + +If the option is an object, it may contain one or both of: + +- `ignoreExpressions`: a boolean option (defaulted to `false`) to ignore class expressions. +- `max`: a numeric option (defaulted to 1) to specify the maximum number of classes. For example: @@ -39,7 +43,16 @@ For example: } ``` -Examples of **correct** code for this rule with the numeric option set to `2`: +```json +{ + "max-classes-per-file": [ + "error", + { "ignoreExpressions": true, "max": 2 } + ] +} +``` + +Examples of **correct** code for this rule with the `max` option set to `2`: ```js /* eslint max-classes-per-file: ["error", 2] */ @@ -47,3 +60,19 @@ Examples of **correct** code for this rule with the numeric option set to `2`: class Foo {} class Bar {} ``` + +Examples of **correct** code for this rule with the `ignoreExpressions` option set to `true`: + +```js +/* eslint max-classes-per-file: ["error", { ignoreExpressions: true }] */ + +class VisitorFactory { + forDescriptor(descriptor) { + return class { + visit(node) { + return `Visiting ${descriptor}.`; + } + }; + } +} +``` diff --git a/lib/rules/max-classes-per-file.js b/lib/rules/max-classes-per-file.js index 3f3eef6213c..3d26108a715 100644 --- a/lib/rules/max-classes-per-file.js +++ b/lib/rules/max-classes-per-file.js @@ -25,8 +25,25 @@ module.exports = { schema: [ { - type: "integer", - minimum: 1 + oneOf: [ + { + type: "integer", + minimum: 1 + }, + { + type: "object", + properties: { + ignoreExpressions: { + type: "boolean" + }, + max: { + type: "integer", + minimum: 1 + } + }, + additionalProperties: false + } + ] } ], @@ -35,8 +52,10 @@ module.exports = { } }, create(context) { - - const maxClasses = context.options[0] || 1; + const [option = {}] = context.options; + const [ignoreExpressions, max] = typeof option === "number" + ? [false, option || 1] + : [option.ignoreExpressions, option.max || 1]; let classCount = 0; @@ -45,19 +64,24 @@ module.exports = { classCount = 0; }, "Program:exit"(node) { - if (classCount > maxClasses) { + if (classCount > max) { context.report({ node, messageId: "maximumExceeded", data: { classCount, - max: maxClasses + max } }); } }, - "ClassDeclaration, ClassExpression"() { + "ClassDeclaration"() { classCount++; + }, + "ClassExpression"() { + if (!ignoreExpressions) { + classCount++; + } } }; } diff --git a/tests/lib/rules/max-classes-per-file.js b/tests/lib/rules/max-classes-per-file.js index ca9cba7a4a2..b5e87261e72 100644 --- a/tests/lib/rules/max-classes-per-file.js +++ b/tests/lib/rules/max-classes-per-file.js @@ -29,6 +29,29 @@ ruleTester.run("max-classes-per-file", rule, { { code: "class Foo {}\nclass Bar {}", options: [2] + }, + { + code: "class Foo {}", + options: [{ max: 1 }] + }, + { + code: "class Foo {}\nclass Bar {}", + options: [{ max: 2 }] + }, + { + code: ` + class Foo {} + const myExpression = class {} + `, + options: [{ ignoreExpressions: true, max: 1 }] + }, + { + code: ` + class Foo {} + class Bar {} + const myExpression = class {} + `, + options: [{ ignoreExpressions: true, max: 2 }] } ], @@ -37,6 +60,10 @@ ruleTester.run("max-classes-per-file", rule, { code: "class Foo {}\nclass Bar {}", errors: [{ messageId: "maximumExceeded", type: "Program" }] }, + { + code: "class Foo {}\nconst myExpression = class {}", + errors: [{ messageId: "maximumExceeded", type: "Program" }] + }, { code: "var x = class {};\nvar y = class {};", errors: [{ messageId: "maximumExceeded", type: "Program" }] @@ -54,6 +81,25 @@ ruleTester.run("max-classes-per-file", rule, { code: "class Foo {} class Bar {} class Baz {}", options: [2], errors: [{ messageId: "maximumExceeded", type: "Program" }] + }, + { + code: ` + class Foo {} + class Bar {} + const myExpression = class {} + `, + options: [{ ignoreExpressions: true, max: 1 }], + errors: [{ messageId: "maximumExceeded", type: "Program" }] + }, + { + code: ` + class Foo {} + class Bar {} + class Baz {} + const myExpression = class {} + `, + options: [{ ignoreExpressions: true, max: 2 }], + errors: [{ messageId: "maximumExceeded", type: "Program" }] } ] });