From 58260bff436cb310813e6726734eb9d1698264c2 Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Wed, 24 Jul 2024 21:59:06 +0800 Subject: [PATCH] feat: add `no-regexp-v-flag` (and bump to ES2024) (#31) * feat: add `no-regexp-v-flag` (and bump to ES2024) Also: - fix: ensures no-hashbang-comment rule is in TS 2023 - docs: remove unneeded backticks in no-regexp-s-flag rule docs * docs: update docs/no-regexp-v-flag.md Co-authored-by: Keith Cirkel * docs: update docs/no-regexp-v-flag.md Co-authored-by: Keith Cirkel --------- Co-authored-by: Keith Cirkel --- README.md | 1 + docs/no-regexp-s-flag.md | 8 +++--- docs/no-regexp-v-flag.md | 27 ++++++++++++++++++ lib/index.js | 14 ++++++++-- lib/rules/no-regexp-v-flag.js | 28 +++++++++++++++++++ test/no-regexp-v-flag.js | 52 +++++++++++++++++++++++++++++++++++ 6 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 docs/no-regexp-v-flag.md create mode 100644 lib/rules/no-regexp-v-flag.js create mode 100644 test/no-regexp-v-flag.js diff --git a/README.md b/README.md index 905628c..abbd98d 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ for configuration. Here's some examples: - [no-regexp-lookbehind](./docs/no-regexp-lookbehind.md) - [no-regexp-named-group](./docs/no-regexp-named-group.md) - [no-regexp-s-flag](./docs/no-regexp-s-flag.md) +- [no-regexp-v-flag](./docs/no-regexp-v-flag.md) - [no-top-level-await](./docs/no-top-level-await.md) ## Inspiration diff --git a/docs/no-regexp-s-flag.md b/docs/no-regexp-s-flag.md index a047ea8..8c762a3 100644 --- a/docs/no-regexp-s-flag.md +++ b/docs/no-regexp-s-flag.md @@ -21,17 +21,17 @@ These will not be allowed because they are not supported in the following browse The `s` flag is relatively simple sugar for `[\0-\uFFFF]`, so you can simply opt to write the un-sugared syntax: ```js -let dotAll = `/./s` +let dotAll = /./s -let dotAll = `/[\0-\uFFFF]/` +let dotAll = /[\0-\uFFFF]/ ``` If you are using it in combination with the `u` flag then you may adjust the pattern: ```js -let dotAll = `/./su` +let dotAll = /./su -let dotAll = `/[\0-\u{10FFFF}]/` +let dotAll = /[\0-\u{10FFFF}]/ ``` This can be safely disabled if you intend to compile code with the `@babel/plugin-transform-dotall-regex` Babel plugin, or `@babel/preset-env`. diff --git a/docs/no-regexp-v-flag.md b/docs/no-regexp-v-flag.md new file mode 100644 index 0000000..1960fd5 --- /dev/null +++ b/docs/no-regexp-v-flag.md @@ -0,0 +1,27 @@ +# no-regexp-v-flag + +This prevents the use of the `v` flag in RegExps + +```js +/[\p{Letter}]/v + +new RegExp('[\\p{Letter}]', 'v') +``` + +These will not be allowed because they are not supported in the following browsers: + + - Edge > 0 + - Safari < 17 + - Firefox < 116 + - Chrome < 112 + +## What is the Fix? + +You can avoid using the `v` flag by expanding the sets to their unicode ranges: + +```js +let vFlag = /[\p{ASCII}]/v; +let noVFlag = /[\0-\x7F]/; +``` + +This can be safely disabled if you intend to compile code with the `@babel/plugin-transform-unicode-sets-regex` Babel plugin, or `@babel/preset-env`. diff --git a/lib/index.js b/lib/index.js index 41873b7..4a3415c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -217,7 +217,15 @@ createRule( "no-hashbang-comment", "edge < 79, safari < 13.1, firefox < 67, chrome < 74", "disallow hashbang comments", - { ts: 2022 } + { ts: 2023 } +); + +// ES2024 +createRule( + "no-regexp-v-flag", + "edge > 0, safari < 17, firefox < 116, chrome < 112", + "disallow the use of the RegExp `v` flag", + { ts: 2024 } ); // Proposals... @@ -239,7 +247,7 @@ createRule( module.exports.configs.recommended = { plugins: ["escompat"], - parserOptions: { ecmaVersion: 2023 }, + parserOptions: { ecmaVersion: 2024 }, rules: Object.keys(module.exports.rules).reduce( (o, r) => ((o["escompat/" + r] = ["error"]), o), {} @@ -252,7 +260,7 @@ module.exports.configs["flat/recommended"] = { escompat: module.exports }, languageOptions: { - ecmaVersion: 2023 + ecmaVersion: 2024 }, rules: Object.keys(module.exports.rules).reduce( (o, r) => ((o["escompat/" + r] = ["error"]), o), diff --git a/lib/rules/no-regexp-v-flag.js b/lib/rules/no-regexp-v-flag.js new file mode 100644 index 0000000..f6e501a --- /dev/null +++ b/lib/rules/no-regexp-v-flag.js @@ -0,0 +1,28 @@ +'use strict'; + +module.exports = (context, badBrowser) => ({ + 'Literal[regex]'(node) { + if (node.regex.flags.includes('v')) { + context.report(node, `RegExp "v" flag is not supported in ${badBrowser}`) + } + }, + 'CallExpression[callee.name="RegExp"], NewExpression[callee.name="RegExp"]'(node) { + const [, flags] = node.arguments; + if ( + flags && + ( + ( + flags.type === 'Literal' && + typeof flags.value === 'string' && + flags.value.includes('v') + ) || + ( + flags.type === 'TemplateLiteral' && + flags.quasis.some(({value: {raw}}) => raw.includes('v')) + ) + ) + ) { + context.report(node, `RegExp "v" flag is not supported in ${badBrowser}`) + } + } +}) diff --git a/test/no-regexp-v-flag.js b/test/no-regexp-v-flag.js new file mode 100644 index 0000000..0b8815d --- /dev/null +++ b/test/no-regexp-v-flag.js @@ -0,0 +1,52 @@ +'use strict'; + +const rule = require('../lib/index').rules['no-regexp-v-flag'] +const RuleTester = require('eslint').RuleTester + +const ruleTester = new RuleTester({languageOptions: {ecmaVersion: 2024}}) + +ruleTester.run('no-regexp-v-flag', rule, { + valid: [ + {code: '/foo.bar/'}, + {code: '/foo.bar/g'}, + {code: 'new RegExp("foo.bar")'}, + {code: 'new RegExp("foo.bar", flags)'}, + {code: 'new RegExp("foo.bar", "u")'}, + {code: 'new RegExp("foo.bar", "g")'}, + {code: 'RegExp("foo.bar", "g")'}, + ], + invalid: [ + { + code: '/foo.bar/v', + errors: [ + { + message: 'RegExp "v" flag is not supported in undefined' + } + ] + }, + { + code: 'new RegExp("foo.bar", "v")', + errors: [ + { + message: 'RegExp "v" flag is not supported in undefined' + } + ] + }, + { + code: 'new RegExp("foo.bar", `v`)', + errors: [ + { + message: 'RegExp "v" flag is not supported in undefined' + } + ] + }, + { + code: 'RegExp("foo.bar", "v")', + errors: [ + { + message: 'RegExp "v" flag is not supported in undefined' + } + ] + }, + ] +})