diff --git a/rules/regex-shorthand.js b/rules/regex-shorthand.js index 63e3b2f426..39f4455b82 100644 --- a/rules/regex-shorthand.js +++ b/rules/regex-shorthand.js @@ -1,6 +1,6 @@ 'use strict'; const cleanRegexp = require('clean-regexp'); -const {generate, optimize, parse} = require('regexp-tree'); +const {optimize} = require('regexp-tree'); const getDocumentationUrl = require('./utils/get-documentation-url'); const quoteString = require('./utils/quote-string'); @@ -9,32 +9,21 @@ const message = 'Use regex shorthands to improve readability.'; const create = context => { return { 'Literal[regex]': node => { - const {type, value} = context.getSourceCode().getFirstToken(node); + const {raw: original, regex} = node; - if (type !== 'RegularExpression') { + // Regular Expressions with `u` flag are not well handled by `regexp-tree` + // https://github.com/DmitrySoshnikov/regexp-tree/issues/162 + if (regex.flags.includes('u')) { return; } - let parsedSource; - try { - parsedSource = parse(value); - } catch (error) { - context.report({ - node, - message: '{{original}} can\'t be parsed: {{message}}', - data: { - original: value, - message: error.message - } - }); + let optimized = original; - return; - } - - const originalRegex = generate(parsedSource).toString(); - const optimizedRegex = optimize(value).toString(); + try { + optimized = optimize(original).toString(); + } catch (_) {} - if (originalRegex === optimizedRegex) { + if (original === optimized) { return; } @@ -42,12 +31,10 @@ const create = context => { node, message: '{{original}} can be optimized to {{optimized}}', data: { - original: value, - optimized: optimizedRegex + original, + optimized }, - fix(fixer) { - return fixer.replaceText(node, optimizedRegex); - } + fix: fixer => fixer.replaceText(node, optimized) }); }, 'NewExpression[callee.name="RegExp"]': node => { diff --git a/test/regex-shorthand.js b/test/regex-shorthand.js index d1a6fd6f20..dcceeab680 100644 --- a/test/regex-shorthand.js +++ b/test/regex-shorthand.js @@ -3,11 +3,8 @@ import avaRuleTester from 'eslint-ava-rule-tester'; import rule from '../rules/regex-shorthand'; const ruleTester = avaRuleTester(test, { - env: { - es6: true - }, parserOptions: { - sourceType: 'module' + ecmaVersion: 2020 } }); @@ -20,20 +17,36 @@ ruleTester.run('regex-shorthand', rule, { valid: [ 'const foo = /\\d/', 'const foo = /\\W/i', - 'const foo = /\\w/ig', - 'const foo = /[a-z]/ig', - 'const foo = /\\d*?/ig', + 'const foo = /\\w/gi', + 'const foo = /[a-z]/gi', + 'const foo = /\\d*?/gi', 'const foo = new RegExp(\'\\d\')', 'const foo = new RegExp(\'\\d\', \'ig\')', 'const foo = new RegExp(\'\\d*?\')', 'const foo = new RegExp(\'[a-z]\', \'i\')', 'const foo = new RegExp(/\\d/)', - 'const foo = new RegExp(/\\d/ig)', + 'const foo = new RegExp(/\\d/gi)', 'const foo = new RegExp(/\\d/, \'ig\')', 'const foo = new RegExp(/\\d*?/)', - 'const foo = new RegExp(/[a-z]/, \'i\')' + 'const foo = new RegExp(/[a-z]/, \'i\')', + + // Should not crash ESLint (#446 and #448) + '/\\{\\{verificationUrl\\}\\}/gu', + '/^test-(?[a-zA-Z-\\d]+)$/u', + + // Should not suggest wrong regex (#447) + '/(\\s|\\.|@|_|-)/u', + '/[\\s.@_-]/u' ], invalid: [ + { + code: 'const foo = /\\w/ig', + errors: [{ + ...error, + message: '/\\w/ig can be optimized to /\\w/gi' + }], + output: 'const foo = /\\w/gi' + }, { code: 'const foo = /[0-9]/', errors: [{