Skip to content

Commit 3554c17

Browse files
jdanilsindresorhus
authored andcommitted
Make regex-shorthand rule use regexp-tree for regex literals (#437)
1 parent bda7769 commit 3554c17

15 files changed

+167
-69
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"lodash.topairs": "^4.3.0",
4545
"lodash.upperfirst": "^4.3.1",
4646
"read-pkg-up": "^7.0.0",
47+
"regexp-tree": "^0.1.16",
4748
"regexpp": "^3.0.0",
4849
"reserved-words": "^0.1.2",
4950
"safe-regex": "^2.1.1",

rules/custom-error-definition.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const getDocumentationUrl = require('./utils/get-documentation-url');
44

55
const MESSAGE_ID_INVALID_EXPORT = 'invalidExport';
66

7-
const nameRegexp = /^(?:[A-Z][a-z\d]*)*Error$/;
7+
const nameRegexp = /^(?:[A-Z][\da-z]*)*Error$/;
88

99
const getClassName = name => upperfirst(name).replace(/(error|)$/i, 'Error');
1010

rules/escape-case.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ const {
66

77
const getDocumentationUrl = require('./utils/get-documentation-url');
88

9-
const escapeWithLowercase = /((?:^|[^\\])(?:\\\\)*)\\(x[a-f\d]{2}|u[a-f\d]{4}|u{(?:[a-f\d]+)})/;
10-
const escapePatternWithLowercase = /((?:^|[^\\])(?:\\\\)*)\\(x[a-f\d]{2}|u[a-f\d]{4}|u{(?:[a-f\d]+)}|c[a-z])/;
9+
const escapeWithLowercase = /((?:^|[^\\])(?:\\\\)*)\\(x[\da-f]{2}|u[\da-f]{4}|u{[\da-f]+})/;
10+
const escapePatternWithLowercase = /((?:^|[^\\])(?:\\\\)*)\\(x[\da-f]{2}|u[\da-f]{4}|u{[\da-f]+}|c[a-z])/;
1111
const hasLowercaseCharacter = /[a-z]+/;
1212
const message = 'Use uppercase characters for the value of the escape sequence.';
1313

rules/expiring-todo-comments.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ const packageDependencies = {
2626
...packageJson.devDependencies
2727
};
2828

29-
const DEPENDENCY_INCLUSION_RE = /^[+|-]\s*@?[\S+]\/?\S+/;
30-
const VERSION_COMPARISON_RE = /^(@?[\S+]\/?\S+)@(>|>=)([\d]+(\.\d+){0,2}(-[\da-z-]+(\.[\da-z-]+)*)?(\+[\da-z-]+(\.[\da-z-]+)*)?)/i;
31-
const PKG_VERSION_RE = /^(>|>=)([\d]+(\.\d+){0,2}(-[\da-z-]+(\.[\da-z-]+)*)?(\+[\da-z-]+(\.[\da-z-]+)*)?)\s*$/;
29+
const DEPENDENCY_INCLUSION_RE = /^[+-]\s*@?\S+\/?\S+/;
30+
const VERSION_COMPARISON_RE = /^(@?\S\/?\S+)@(>|>=)(\d+(\.\d+){0,2}(-[\d\-a-z]+(\.[\d\-a-z]+)*)?(\+[\d\-a-z]+(\.[\d\-a-z]+)*)?)/i;
31+
const PKG_VERSION_RE = /^(>|>=)(\d+(\.\d+){0,2}(-[\d-a-z]+(\.[\d-a-z]+)*)?(\+[\d-a-z]+(\.[\d-a-z]+)*)?)\s*$/;
3232
const ISO8601_DATE = /(\d{4})-(\d{2})-(\d{2})/;
3333

3434
function parseTodoWithArguments(string, {terms}) {
@@ -40,7 +40,7 @@ function parseTodoWithArguments(string, {terms}) {
4040
return false;
4141
}
4242

43-
const TODO_ARGUMENT_RE = /\[([^}]+)\]/i;
43+
const TODO_ARGUMENT_RE = /\[([^}]+)]/i;
4444
const result = TODO_ARGUMENT_RE.exec(string);
4545

4646
if (!result) {

rules/import-index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22
const getDocumentationUrl = require('./utils/get-documentation-url');
33

4-
const regexp = /^(@.*?\/.*?|[./]+?.*?)(?:\/(\.|(?:index(?:\.js)?))?)$/;
4+
const regexp = /^(@.*?\/.*?|[./]+?.*?)\/(\.|(?:index(?:\.js)?))?$/;
55
const isImportingIndex = value => regexp.test(value);
66
const normalize = value => value.replace(regexp, '$1');
77

rules/no-abusive-eslint-disable.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22
const getDocumentationUrl = require('./utils/get-documentation-url');
33

4-
const disableRegex = /^eslint-disable(-next-line|-line)?($|(\s+(@[\w-]+\/(?:[\w-]+\/)?)?[\w-]+)?)/;
4+
const disableRegex = /^eslint-disable(-next-line|-line)?($|(\s+(@(?:[\w-]+\/){1,2})?[\w-]+)?)/;
55

66
const create = context => ({
77
Program: node => {

rules/number-literal-case.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
const getDocumentationUrl = require('./utils/get-documentation-url');
33

44
const fix = value => {
5-
if (!/^0[a-zA-Z]/.test(value)) {
5+
if (!/^0[A-Za-z]/.test(value)) {
66
return value;
77
}
88

rules/prevent-abbreviations.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ const getNameReplacements = (name, options, limit = 3) => {
274274
}
275275

276276
// Split words
277-
const words = name.split(/(?=[^a-z])|(?<=[^a-zA-Z])/).filter(Boolean);
277+
const words = name.split(/(?=[^a-z])|(?<=[^A-Za-z])/).filter(Boolean);
278278

279279
let hasReplacements = false;
280280
const combinations = words.map(word => {

rules/regex-shorthand.js

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
const cleanRegexp = require('clean-regexp');
3+
const {generate, optimize, parse} = require('regexp-tree');
34
const getDocumentationUrl = require('./utils/get-documentation-url');
45
const quoteString = require('./utils/quote-string');
56

@@ -8,23 +9,46 @@ const message = 'Use regex shorthands to improve readability.';
89
const create = context => {
910
return {
1011
'Literal[regex]': node => {
11-
const oldPattern = node.regex.pattern;
12-
const {flags} = node.regex;
12+
const {type, value} = context.getSourceCode().getFirstToken(node);
1313

14-
const newPattern = cleanRegexp(oldPattern, flags);
15-
16-
// Handle regex literal inside RegExp constructor in the other handler
17-
if (node.parent.type === 'NewExpression' && node.parent.callee.name === 'RegExp') {
14+
if (type !== 'RegularExpression') {
1815
return;
1916
}
2017

21-
if (oldPattern !== newPattern) {
18+
let parsedSource;
19+
try {
20+
parsedSource = parse(value);
21+
} catch (error) {
2222
context.report({
2323
node,
24-
message,
25-
fix: fixer => fixer.replaceText(node, `/${newPattern}/${flags}`)
24+
message: '{{original}} can\'t be parsed: {{message}}',
25+
data: {
26+
original: value,
27+
message: error.message
28+
}
2629
});
30+
31+
return;
2732
}
33+
34+
const originalRegex = generate(parsedSource).toString();
35+
const optimizedRegex = optimize(value).toString();
36+
37+
if (originalRegex === optimizedRegex) {
38+
return;
39+
}
40+
41+
context.report({
42+
node,
43+
message: '{{original}} can be optimized to {{optimized}}',
44+
data: {
45+
original: value,
46+
optimized: optimizedRegex
47+
},
48+
fix(fixer) {
49+
return fixer.replaceText(node, optimizedRegex);
50+
}
51+
});
2852
},
2953
'NewExpression[callee.name="RegExp"]': node => {
3054
const arguments_ = node.arguments;
@@ -35,27 +59,18 @@ const create = context => {
3559

3660
const hasRegExp = arguments_[0].regex;
3761

38-
let oldPattern;
39-
let flags;
4062
if (hasRegExp) {
41-
oldPattern = arguments_[0].regex.pattern;
42-
flags = arguments_[1] && arguments_[1].type === 'Literal' ? arguments_[1].value : arguments_[0].regex.flags;
43-
} else {
44-
oldPattern = arguments_[0].value;
45-
flags = arguments_[1] && arguments_[1].type === 'Literal' ? arguments_[1].value : '';
63+
return;
4664
}
4765

66+
const oldPattern = arguments_[0].value;
67+
const flags = arguments_[1] && arguments_[1].type === 'Literal' ? arguments_[1].value : '';
68+
4869
const newPattern = cleanRegexp(oldPattern, flags);
4970

5071
if (oldPattern !== newPattern) {
51-
let fixed;
52-
if (hasRegExp) {
53-
fixed = `/${newPattern}/`;
54-
} else {
55-
// Escape backslash
56-
fixed = (newPattern || '').replace(/\\/g, '\\\\');
57-
fixed = quoteString(fixed);
58-
}
72+
// Escape backslash
73+
const fixed = quoteString((newPattern || '').replace(/\\/g, '\\\\'));
5974

6075
context.report({
6176
node,

rules/throw-new-error.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22
const getDocumentationUrl = require('./utils/get-documentation-url');
33

4-
const customError = /^(?:[A-Z][a-z\d]*)*Error$/;
4+
const customError = /^(?:[A-Z][\da-z]*)*Error$/;
55

66
const create = context => ({
77
ThrowStatement: node => {

0 commit comments

Comments
 (0)