diff --git a/docs/no-regexp-lookbehind.md b/docs/no-regexp-lookbehind.md new file mode 100644 index 0000000..5669f6c --- /dev/null +++ b/docs/no-regexp-lookbehind.md @@ -0,0 +1,20 @@ +# no-regexp-lookbehind + +This prevents the use of the RegExp lookbehind feature + +```js +/(?<=a>)b/ + +new RegExp("/(?<=a)b") +``` + +These will not be allowed because they are not supported in the following browsers: + + - Edge < 79 + - Safari (any version at the time of writing) + - Firefox (any version at the time of writing) + - Chrome < 62 + +## What is the Fix? + +You may be able to rewrite your experession using (Negative) Lookaheads, but if not then there is no solution for this, aside from pulling in a custom RegExp library. diff --git a/lib/index.js b/lib/index.js index f1bffd2..e141f4d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -41,6 +41,7 @@ createRule('no-async-iteration', 'edge < 79, safari < 12, firefox < 57, chrome < createRule('no-async-generator', 'edge < 79, safari < 12, firefox < 57, chrome < 63', 'disallow the use of async generator functions') createRule('no-object-rest-spread', 'edge < 79, safari < 11.1, firefox < 55, chrome < 60', 'disallow object rest/spread patterns') createRule('no-regexp-s-flag', 'edge < 79, safari < 11.1, firefox > 0, chrome < 62', 'disallow the use of the RegExp `s` flag') +createRule('no-regexp-lookbehind', 'edge < 79, safari > 0, firefox > 0, chrome < 62', 'disallow the use of RegExp lookbehinds') // ES2019 createRule('no-optional-catch', 'edge < 79, safari < 11.1, firefox < 58, chrome < 66', 'always require catch() to have an argument') @@ -61,7 +62,7 @@ createRule('no-do-expression', 'edge > 0, safari > 0, firefox > 0, chrome > 0', createRule('no-bind-operator', 'edge > 0, safari > 0, firefox > 0, chrome > 0', 'disallow the :: bind operator') createRule('no-pipeline-operator', 'edge > 0, safari > 0, firefox > 0, chrome > 0', 'disallow the > pipeline operator') -const v2breakingRules = new Set(['no-nullish-coalescing', 'no-bigint']) +const v2breakingRules = new Set(['no-nullish-coalescing', 'no-bigint', 'no-regexp-lookbehind']) module.exports.configs.recommended = { plugins: ['escompat'], diff --git a/lib/rules/no-regexp-lookbehind.js b/lib/rules/no-regexp-lookbehind.js new file mode 100644 index 0000000..a41a9fa --- /dev/null +++ b/lib/rules/no-regexp-lookbehind.js @@ -0,0 +1,28 @@ +const hasLookbehind = s => s.includes('(?<=') || s.includes('(? ({ + 'Literal[regex]'(node) { + if (hasLookbehind(node.regex.pattern)) { + context.report(node, `RegExp lookbehinds are not supported in ${badBrowser}`) + } + }, + 'CallExpression[callee.name="RegExp"], NewExpression[callee.name="RegExp"]'(node) { + const [source] = node.arguments; + if ( + source && + ( + ( + source.type === 'Literal' && + typeof source.value === 'string' && + hasLookbehind(source.value) + ) || + ( + source.type === 'TemplateLiteral' && + source.quasis.some(({value: {raw}}) => hasLookbehind(raw)) + ) + ) + ) { + context.report(node, `RegExp lookbehinds are not supported in ${badBrowser}`) + } + } +}) diff --git a/test/no-regexp-lookbehind.js b/test/no-regexp-lookbehind.js new file mode 100644 index 0000000..f549766 --- /dev/null +++ b/test/no-regexp-lookbehind.js @@ -0,0 +1,49 @@ +var rule = require('../lib/rules/no-regexp-lookbehind') +var RuleTester = require('eslint').RuleTester + +var ruleTester = new RuleTester({parserOptions: {ecmaVersion: 2020}}) + +ruleTester.run('no-regexp-lookbehind', rule, { + valid: [ + {code: '/(?:a)b/'}, + {code: '/(?:a)b/g'}, + {code: '/(?)/'}, + {code: 'RegExp("(?:a)b", "g")'}, + {code: 'RegExp("(?:a)b", "g")'}, + {code: 'RegExp("(?)")'}, + ], + invalid: [ + { + code: '/(?<=a)b/', + errors: [ + { + message: 'RegExp lookbehinds are not supported in undefined' + } + ] + }, + { + code: 'new RegExp("/(?<=a)b")', + errors: [ + { + message: 'RegExp lookbehinds are not supported in undefined' + } + ] + }, + { + code: '/(?<=a)b/g', + errors: [ + { + message: 'RegExp lookbehinds are not supported in undefined' + } + ] + }, + { + code: 'new RegExp("/(?<=a)b", "g")', + errors: [ + { + message: 'RegExp lookbehinds are not supported in undefined' + } + ] + }, + ] +})