From 8fc13398cafdba900ea1fc16f2f5662dc895ce16 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sun, 3 Dec 2023 02:04:34 -0500 Subject: [PATCH] Add regexp plugin --- package.json | 1 + packages/eslint-config/index.js | 1 + packages/eslint-config/package.json | 4 +- packages/eslint-config/rules/regex.js | 208 ++++++++++++++++++++++++++ project-words.txt | 2 + yarn.lock | 64 +++++++- 6 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 packages/eslint-config/rules/regex.js diff --git a/package.json b/package.json index d00e430..c453882 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-regexp": "^2.1.1", "husky": "^8.0.3", "lint-staged": "^15.1.0", "prettier": "^3.1.0", diff --git a/packages/eslint-config/index.js b/packages/eslint-config/index.js index 3964f96..bb98059 100644 --- a/packages/eslint-config/index.js +++ b/packages/eslint-config/index.js @@ -3,6 +3,7 @@ module.exports = { extends: [ "prettier", "./rules/base.js", + "./rules/regex.js", "./rules/typescript.js", "./rules/import.js", "./rules/react.js", diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index 3cf78d1..3b74c21 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -25,6 +25,7 @@ "exports": { ".": "./index.js", "./base": "./rules/base.js", + "./regex": "./rules/regex.js", "./import": "./rules/import.js", "./jsx": "./rules/jsx.js", "./react": "./rules/react.js", @@ -42,7 +43,8 @@ "eslint-plugin-import": "^2.29.0", "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0" + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-regexp": "^2.1.1" }, "peerDependenciesMeta": { "eslint-plugin-header": { diff --git a/packages/eslint-config/rules/regex.js b/packages/eslint-config/rules/regex.js new file mode 100644 index 0000000..c57c5c8 --- /dev/null +++ b/packages/eslint-config/rules/regex.js @@ -0,0 +1,208 @@ +module.exports = { + plugins: ["regexp"], + rules: { + // This rule is unactionable because /T{4}/ cannot be changed to /T{0,4}/ + // even when T matches the empty string. + "regexp/confusing-quantifier": "off", + + "regexp/control-character-escape": "error", + + "regexp/grapheme-string-literal": "error", + + "regexp/hexadecimal-escape": ["error", "never"], + + "regexp/letter-case": [ + "error", + { + caseInsensitive: "lowercase", + controlEscape: "uppercase", + hexadecimalEscape: "lowercase", + unicodeEscape: "lowercase", + }, + ], + + "regexp/match-any": ["warn", { allows: ["dotAll", "[\\s\\S]"] }], + + "regexp/negation": "error", + + "regexp/no-contradiction-with-assertion": "error", + + "regexp/no-control-character": "error", + + "regexp/no-dupe-characters-character-class": "error", + + "regexp/no-dupe-disjunctions": [ + "warn", + { + report: "all", + reportExponentialBacktracking: "potential", + reportUnreachable: "potential", + }, + ], + + "regexp/no-empty-alternative": "error", + + "regexp/no-empty-capturing-group": "error", + + // eslint-disable-next-line sort-keys + "no-empty-character-class": "off", + "regexp/no-empty-character-class": "error", + + "regexp/no-empty-group": "error", + + "regexp/no-empty-lookarounds-assertion": "error", + + "regexp/no-empty-string-literal": "error", + + "regexp/no-escape-backspace": "warn", + + "regexp/no-extra-lookaround-assertions": "error", + + // eslint-disable-next-line sort-keys + "no-invalid-regexp": "off", + "regexp/no-invalid-regexp": "error", + + "regexp/no-invisible-character": "error", + + "regexp/no-lazy-ends": ["error", { ignorePartial: false }], + + "regexp/no-legacy-features": "error", + + "regexp/no-misleading-capturing-group": [ + "warn", + { reportBacktrackingEnds: true }, + ], + + // eslint-disable-next-line sort-keys + "no-misleading-character-class": "off", + "regexp/no-misleading-unicode-character": ["error", { fixable: false }], + + "regexp/no-missing-g-flag": ["error", { strictTypes: true }], + + "regexp/no-non-standard-flag": "error", + + // This probably can be enabled, but it seems too disruptive + "regexp/no-obscure-range": "off", + + "regexp/no-octal": "error", + + "regexp/no-optional-assertion": "error", + + "regexp/no-potentially-useless-backreference": "warn", + + "regexp/no-standalone-backslash": "error", + + "regexp/no-super-linear-backtracking": ["warn", { report: "potential" }], + + "regexp/no-super-linear-move": [ + "warn", + { ignorePartial: false, ignoreSticky: false, report: "potential" }, + ], + + "regexp/no-trivially-nested-assertion": "error", + + "regexp/no-trivially-nested-quantifier": "error", + + "regexp/no-unused-capturing-group": "warn", + + "regexp/no-useless-assertions": "error", + + // eslint-disable-next-line sort-keys + "no-useless-backreference": "off", + "regexp/no-useless-backreference": "error", + + "regexp/no-useless-character-class": ["error", { ignores: [] }], + + "regexp/no-useless-dollar-replacements": "error", + + "regexp/no-useless-escape": "error", + + "regexp/no-useless-flag": "error", + + "regexp/no-useless-lazy": "error", + + "regexp/no-useless-non-capturing-group": ["error", { allowTop: "never" }], + + "regexp/no-useless-quantifier": "error", + + "regexp/no-useless-range": "error", + + "regexp/no-useless-set-operand": "error", + + "regexp/no-useless-string-literal": "error", + + "regexp/no-useless-two-nums-quantifier": "error", + + "regexp/no-zero-quantifier": "error", + + "regexp/optimal-lookaround-quantifier": "error", + + "regexp/optimal-quantifier-concatenation": [ + "error", + { capturingGroups: "report" }, + ], + + "regexp/prefer-character-class": ["error", { minAlternatives: 2 }], + + "regexp/prefer-d": ["error", { insideCharacterClass: "d" }], + + "regexp/prefer-escape-replacement-dollar-char": "error", + + "regexp/prefer-lookaround": ["error", { lookbehind: true }], + + "regexp/prefer-named-backreference": "error", + + // eslint-disable-next-line sort-keys + "prefer-named-capture-group": "off", + "regexp/prefer-named-capture-group": "error", + + "regexp/prefer-named-replacement": "error", + + "regexp/prefer-plus-quantifier": "error", + + "regexp/prefer-predefined-assertion": "error", + + // We disable no-regex-spaces too + "regexp/prefer-quantifier": "off", + + "regexp/prefer-question-quantifier": "error", + + "regexp/prefer-range": "error", + + // Shadowed by @typescript-eslint/prefer-regexp-exec + "regexp/prefer-regexp-exec": "off", + + "regexp/prefer-regexp-test": "warn", + + "regexp/prefer-result-array-groups": "warn", + + "regexp/prefer-set-operation": "error", + + "regexp/prefer-star-quantifier": "error", + + "regexp/prefer-unicode-codepoint-escapes": "error", + + "regexp/prefer-w": "error", + + "require-unicode-regexp": "off", + // eslint-disable-next-line sort-keys + "regexp/require-unicode-regexp": "error", + + // Maybe in the future? + "regexp/require-unicode-sets-regexp": "off", + + "regexp/simplify-set-operations": "error", + + "regexp/sort-alternatives": 0, + + "regexp/sort-character-class-elements": 0, + + "regexp/sort-flags": "error", + + "regexp/strict": "error", + + "regexp/unicode-escape": ["error", "unicodeEscape"], + + "regexp/use-ignore-case": "error", + }, +}; diff --git a/project-words.txt b/project-words.txt index 86552f9..0b23ff5 100644 --- a/project-words.txt +++ b/project-words.txt @@ -20,6 +20,7 @@ isnan jcify lintstagedrc listbox +lookarounds miswritten monkeypatch naïvely @@ -27,6 +28,7 @@ nocheck nonconstructor noninteractive nonoctal +nums pico picocolors plusplus diff --git a/yarn.lock b/yarn.lock index d95115e..a20222d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3584,7 +3584,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": +"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1, @eslint-community/regexpp@npm:^4.8.0, @eslint-community/regexpp@npm:^4.9.1": version: 4.10.0 resolution: "@eslint-community/regexpp@npm:4.10.0" checksum: 8c36169c815fc5d726078e8c71a5b592957ee60d08c6470f9ce0187c8046af1a00afbda0a065cc40ff18d5d83f82aed9793c6818f7304a74a7488dc9f3ecbd42 @@ -6037,6 +6037,13 @@ __metadata: languageName: node linkType: hard +"comment-parser@npm:^1.4.0": + version: 1.4.1 + resolution: "comment-parser@npm:1.4.1" + checksum: 16a3260b5e77819ebd9c99b0b65c7d6723b1ff73487bac9ce2d8f016a2847dd689e8663b88e1fad1444bbea89847c42f785708ac86a2c55f614f7095249bbf6b + languageName: node + linkType: hard + "commondir@npm:^1.0.1": version: 1.0.1 resolution: "commondir@npm:1.0.1" @@ -7449,6 +7456,23 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-regexp@npm:^2.1.1": + version: 2.1.1 + resolution: "eslint-plugin-regexp@npm:2.1.1" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.2.0" + "@eslint-community/regexpp": "npm:^4.9.1" + comment-parser: "npm:^1.4.0" + jsdoc-type-pratt-parser: "npm:^4.0.0" + refa: "npm:^0.12.1" + regexp-ast-analysis: "npm:^0.7.1" + scslre: "npm:^0.3.0" + peerDependencies: + eslint: ">=8.44.0" + checksum: 7639cd728d5b924a556628a11d46d868750cf73e194d1450fc292c15b781ffca91af5309fec9e618295e3a2e2b84d9e9be269fc3c5443c4b83c873a4708231d9 + languageName: node + linkType: hard + "eslint-scope@npm:5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" @@ -9683,6 +9707,13 @@ __metadata: languageName: node linkType: hard +"jsdoc-type-pratt-parser@npm:^4.0.0": + version: 4.0.0 + resolution: "jsdoc-type-pratt-parser@npm:4.0.0" + checksum: a225ab874e56612730dd6c0466ce9f09e8a0e7d85896e9e5f0fa53cfb2e897128a7ec702fd99ed3854b3fbf5a89ad6dce72ca4f4f6149da69f130c2874f06b75 + languageName: node + linkType: hard + "jsesc@npm:^2.5.1": version: 2.5.2 resolution: "jsesc@npm:2.5.2" @@ -12143,6 +12174,15 @@ __metadata: languageName: node linkType: hard +"refa@npm:^0.12.0, refa@npm:^0.12.1": + version: 0.12.1 + resolution: "refa@npm:0.12.1" + dependencies: + "@eslint-community/regexpp": "npm:^4.8.0" + checksum: b89411434e31637a519c065acd8fd1ec9eabc1dec38eec58dbc69a386ec21d88f97fa175e56fb3133e21c090ddb68fe7b5653ffc4bbcc9f069abc0e88c0d290c + languageName: node + linkType: hard + "reflect.getprototypeof@npm:^1.0.4": version: 1.0.4 resolution: "reflect.getprototypeof@npm:1.0.4" @@ -12196,6 +12236,16 @@ __metadata: languageName: node linkType: hard +"regexp-ast-analysis@npm:^0.7.0, regexp-ast-analysis@npm:^0.7.1": + version: 0.7.1 + resolution: "regexp-ast-analysis@npm:0.7.1" + dependencies: + "@eslint-community/regexpp": "npm:^4.8.0" + refa: "npm:^0.12.1" + checksum: 92299636d9c941ee27db7568a775354d36024504c104c5d7981a89dda1b0ff1e2a56db16f92d7e166a50a1164593788c0849c5840ec9d79b39c1c040d59c442c + languageName: node + linkType: hard + "regexp.prototype.flags@npm:^1.5.0, regexp.prototype.flags@npm:^1.5.1": version: 1.5.1 resolution: "regexp.prototype.flags@npm:1.5.1" @@ -12528,6 +12578,7 @@ __metadata: eslint-plugin-jsx-a11y: "npm:^6.8.0" eslint-plugin-react: "npm:^7.33.2" eslint-plugin-react-hooks: "npm:^4.6.0" + eslint-plugin-regexp: "npm:^2.1.1" husky: "npm:^8.0.3" lint-staged: "npm:^15.1.0" prettier: "npm:^3.1.0" @@ -12679,6 +12730,17 @@ __metadata: languageName: node linkType: hard +"scslre@npm:^0.3.0": + version: 0.3.0 + resolution: "scslre@npm:0.3.0" + dependencies: + "@eslint-community/regexpp": "npm:^4.8.0" + refa: "npm:^0.12.0" + regexp-ast-analysis: "npm:^0.7.0" + checksum: 164ec9b9a9d819838240b1df613b6c60ae00c69c4472264f354a191f73b538c064d43c0ac3accf89f5c05880ddab33846077b0cda3ad383701623d468960c005 + languageName: node + linkType: hard + "section-matter@npm:^1.0.0": version: 1.0.0 resolution: "section-matter@npm:1.0.0"