From 39e29181a0d84b44f90d9cbd11fa30a0af40cf9a Mon Sep 17 00:00:00 2001 From: Naomi Carrigan Date: Sun, 5 Jan 2025 21:25:03 +0000 Subject: [PATCH] feat: add rules for eslint-disable directives (#11) ### Explanation _No response_ ### Issue _No response_ ### Attestations - [x] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/) - [x] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/). - [x] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/). ### Dependencies - [x] I have pinned the dependencies to a specific patch version. ### Style - [x] I have run the linter and resolved any errors. - [x] My pull request uses an appropriate title, matching the conventional commit standards. - [x] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request. ### Tests - [x] My contribution adds new code, and I have added tests to cover it. - [x] My contribution modifies existing code, and I have updated the tests to reflect these changes. - [x] All new and existing tests pass locally with my changes. - [x] Code coverage remains at or above the configured threshold. ### Documentation _No response_ ### Versioning Minor - My pull request introduces a new non-breaking feature. Reviewed-on: https://codeberg.org/nhcarrigan/eslint-config/pulls/11 Co-authored-by: Naomi Carrigan Co-committed-by: Naomi Carrigan --- .vscode/settings.json | 8 +++++++- package.json | 3 ++- pnpm-lock.yaml | 15 +++++++++++++++ src/index.ts | 21 +++++++++++++++++---- src/rules/comments.ts | 12 ++++++++++++ src/types.d.ts | 1 + test/config.spec.ts | 20 +++++++++++--------- 7 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 src/rules/comments.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 2beb504..4a5dcd2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,11 @@ "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }, - "eslint.validate": ["typescript"] + "eslint.validate": [ + "typescript" + ], + "sonarlint.connectedMode.project": { + "connectionId": "nhcarrigan", + "projectKey": "nhcarrigan_eslint-config" + } } diff --git a/package.json b/package.json index e852ab5..df14d6f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "format": "pnpm build && eslint src test --max-warnings 0 --fix", "lint": "pnpm build && eslint src test --max-warnings 0", "test": "vitest run", - "scan": "SONAR_TOKEN='op://Environment Variables - Development/SonarCloud/eslint-config' op run -- sonar-scanner -Dsonar.organization=nhcarrigan -Dsonar.projectKey=nhcarrigan_eslint-config -Dsonar.sources=. -Dsonar.host.url=https://sonarcloud.io" + "scan": "SONAR_TOKEN='op://Environment Variables - Development/SonarCloud/eslint-config' op run -- sonar-scanner -Dsonar.organization=nhcarrigan -Dsonar.projectKey=nhcarrigan_eslint-config -Dsonar.sources=. -Dsonar.host.url=https://sonarcloud.io" }, "repository": { "type": "git", @@ -30,6 +30,7 @@ }, "homepage": "https://codeberg.org/naomi-lgbt/eslint-config", "dependencies": { + "@eslint-community/eslint-plugin-eslint-comments": "4.4.1", "@eslint/compat": "1.2.4", "@eslint/eslintrc": "3.2.0", "@eslint/js": "9.16.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4b9abcb..051a0ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@eslint-community/eslint-plugin-eslint-comments': + specifier: 4.4.1 + version: 4.4.1(eslint@9.7.0) '@eslint/compat': specifier: 1.2.4 version: 1.2.4(eslint@9.7.0) @@ -239,6 +242,12 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-plugin-eslint-comments@4.4.1': + resolution: {integrity: sha512-lb/Z/MzbTf7CaVYM9WCFNQZ4L1yi3ev2fsFPF99h31ljhSEyUoyEsKsNWiU+qD1glbYTDJdqgyaLKtyTkkqtuQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1981,6 +1990,12 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true + '@eslint-community/eslint-plugin-eslint-comments@4.4.1(eslint@9.7.0)': + dependencies: + escape-string-regexp: 4.0.0 + eslint: 9.7.0 + ignore: 5.3.1 + '@eslint-community/eslint-utils@4.4.0(eslint@9.7.0)': dependencies: eslint: 9.7.0 diff --git a/src/index.ts b/src/index.ts index 8c1f5c7..f335576 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ */ import { fixupPluginRules } from "@eslint/compat"; +import comments from "@eslint-community/eslint-plugin-eslint-comments"; import stylistic from "@stylistic/eslint-plugin"; import tslint from "@typescript-eslint/eslint-plugin"; import parser from "@typescript-eslint/parser"; @@ -17,6 +18,7 @@ import react from "eslint-plugin-react"; import sortKeysFix from "eslint-plugin-sort-keys-fix"; import unicorn from "eslint-plugin-unicorn"; import globals from "globals"; +import { commentsRules } from "./rules/comments.js"; import { deprecationRules } from "./rules/deprecation.js"; import { disabledEslintRules, eslintRules } from "./rules/eslint.js"; import { importRules } from "./rules/import.js"; @@ -50,6 +52,8 @@ const config: Array = [ plugins: { // @ts-expect-error It's a config. It's just not the narrow config. SMH. "@typescript-eslint": tslint, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Not unsafe, just not typed. + "comments": comments, // @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9 "deprecation": fixupPluginRules(deprecation), "import": fixupPluginRules(importPlugin as ESLint.Plugin), @@ -70,6 +74,7 @@ const config: Array = [ ...stylisticRules, ...unicornRules, ...sortKeysFixRules, + ...commentsRules, }, }, // #endregion @@ -90,6 +95,8 @@ const config: Array = [ plugins: { // @ts-expect-error It's a config. It's just not the narrow config. SMH. "@typescript-eslint": tslint, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Not unsafe, just not typed. + "comments": comments, "import": fixupPluginRules(importPlugin as ESLint.Plugin), "jsdoc": jsdoc, "sort-keys-fix": sortKeysFix as ESLint.Plugin, @@ -108,6 +115,7 @@ const config: Array = [ ...stylisticRules, ...unicornRules, ...sortKeysFixRules, + ...commentsRules, }, }, // #endregion @@ -128,14 +136,15 @@ const config: Array = [ plugins: { // @ts-expect-error It's a config. It's just not the narrow config. SMH. "@typescript-eslint": tslint, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Not unsafe, just not typed. + "comments": comments, "import": fixupPluginRules(importPlugin as ESLint.Plugin), "jsdoc": jsdoc, "playwright": playwright, - - "sort-keys-fix": sortKeysFix as ESLint.Plugin, + "sort-keys-fix": sortKeysFix as ESLint.Plugin, // @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9 - "stylistic": fixupPluginRules(stylistic), - "unicorn": unicorn, + "stylistic": fixupPluginRules(stylistic), + "unicorn": unicorn, }, rules: { ...eslintRules, @@ -147,6 +156,7 @@ const config: Array = [ ...stylisticRules, ...unicornRules, ...sortKeysFixRules, + ...commentsRules, }, }, // #endregion @@ -172,6 +182,8 @@ const config: Array = [ plugins: { // @ts-expect-error It's a config. It's just not the narrow config. SMH. "@typescript-eslint": tslint, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Not unsafe, just not typed. + "comments": comments, // @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9 "deprecation": fixupPluginRules(deprecation), "import": fixupPluginRules(importPlugin as ESLint.Plugin), @@ -194,6 +206,7 @@ const config: Array = [ ...unicornRules, ...sortKeysFixRules, ...reactRules, + ...commentsRules, }, }, ]; diff --git a/src/rules/comments.ts b/src/rules/comments.ts new file mode 100644 index 0000000..11c476e --- /dev/null +++ b/src/rules/comments.ts @@ -0,0 +1,12 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import type { Linter } from "eslint"; + +export const commentsRules: Linter.RulesRecord = { + "comments/no-unlimited-disable": "warn", + "comments/require-description": "warn", +}; diff --git a/src/types.d.ts b/src/types.d.ts index a5dc53d..a1a4a68 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -7,3 +7,4 @@ declare module "eslint-plugin-no-only-tests"; declare module "eslint-plugin-import"; declare module "eslint-plugin-sort-keys-fix"; +declare module "@eslint-community/eslint-plugin-eslint-comments"; diff --git a/test/config.spec.ts b/test/config.spec.ts index 8c07503..dfbc70e 100644 --- a/test/config.spec.ts +++ b/test/config.spec.ts @@ -6,6 +6,7 @@ import { describe, expect, it } from "vitest"; import config from "../src/index.ts"; +import { commentsRules } from "../src/rules/comments.ts"; import { deprecationRules } from "../src/rules/deprecation.ts"; import { eslintRules } from "../src/rules/eslint.ts"; import { importRules } from "../src/rules/import.ts"; @@ -39,7 +40,7 @@ expect.extend({ const pass = missingRules.length === 0 && mismatchedRules.length === 0; let message = ""; - // eslint-disable-next-line no-negated-condition + // eslint-disable-next-line no-negated-condition -- This is a test. if (!pass) { message = `${message}Expected rules to contain all specified rules.\n`; if (missingRules.length > 0) { @@ -121,13 +122,14 @@ const baseProperties = ( ruleset?.rules, "missing typescript-eslint rules with types", ).toContainRules(typescriptEslintRulesWithTypes); + expect(ruleset?.rules, "missing comment rules").toContainRules(commentsRules); }; // #endregion describe("global config", () => { // #region Typescript it("should apply the expected plugins for typescript", () => { - expect.assertions(26); + expect.assertions(27); const ruleset = config.find((rule) => { return rule?.files?.includes("src/**/*.ts"); }); @@ -159,13 +161,13 @@ describe("global config", () => { expect( Object.keys(ruleset?.plugins ?? {}), "should not have extraneous plugins", - ).toHaveLength(7); + ).toHaveLength(8); }); // #endregion // #region Vitest it("should apply the expected plugins for vitest files", () => { - expect.assertions(26); + expect.assertions(27); const ruleset = config.find((rule) => { return rule?.files?.includes("test/**/*.spec.ts"); }); @@ -192,13 +194,13 @@ describe("global config", () => { expect( Object.keys(ruleset?.plugins ?? {}), "should not have extraneous plugins", - ).toHaveLength(7); + ).toHaveLength(8); }); // #endregion // #region Playwright it("should apply the expected plugins for playwright", () => { - expect.assertions(26); + expect.assertions(27); const ruleset = config.find((rule) => { return rule?.files?.includes("e2e/**/*.spec.ts"); }); @@ -228,13 +230,13 @@ describe("global config", () => { expect( Object.keys(ruleset?.plugins ?? {}), "should not have extraneous plugins", - ).toHaveLength(7); + ).toHaveLength(8); }); // #endregion // #region React it("should apply the expected plugins for react", () => { - expect.assertions(26); + expect.assertions(27); const ruleset = config.find((rule) => { return rule?.files?.includes("src/**/*.tsx"); }); @@ -262,7 +264,7 @@ describe("global config", () => { expect( Object.keys(ruleset?.plugins ?? {}), "should not have extraneous plugins", - ).toHaveLength(8); + ).toHaveLength(9); }); // #endregion });