Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite85d27a

Browse files
mdjermanovicmysticatea
authored andcommitted
Fix: no-regex-spaces false positives and invalid autofix (fixes#12226) (#12231)
1 parentb349bf7 commite85d27a

File tree

2 files changed

+359
-48
lines changed

2 files changed

+359
-48
lines changed

‎lib/rules/no-regex-spaces.js‎

Lines changed: 106 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,29 @@
55

66
"use strict";
77

8+
//------------------------------------------------------------------------------
9+
// Requirements
10+
//------------------------------------------------------------------------------
11+
812
constastUtils=require("./utils/ast-utils");
13+
constregexpp=require("regexpp");
14+
15+
//------------------------------------------------------------------------------
16+
// Helpers
17+
//------------------------------------------------------------------------------
18+
19+
constregExpParser=newregexpp.RegExpParser();
20+
constDOUBLE_SPACE=/{2}/u;
21+
22+
/**
23+
* Check if node is a string
24+
*@param {ASTNode} node node to evaluate
25+
*@returns {boolean} True if its a string
26+
*@private
27+
*/
28+
functionisString(node){
29+
returnnode&&node.type==="Literal"&&typeofnode.value==="string";
30+
}
931

1032
//------------------------------------------------------------------------------
1133
// Rule Definition
@@ -27,40 +49,70 @@ module.exports = {
2749
},
2850

2951
create(context){
30-
constsourceCode=context.getSourceCode();
3152

3253
/**
33-
* Validate regular expressions
34-
*@param {ASTNode} node node to validate
35-
*@param {string} value regular expression to validate
36-
*@param {number} valueStart The start location of the regex/string literal. It will always be the case that
37-
* `sourceCode.getText().slice(valueStart, valueStart + value.length) === value`
54+
* Validate regular expression
55+
*
56+
*@param {ASTNode} nodeToReport Node to report.
57+
*@param {string} pattern Regular expression pattern to validate.
58+
*@param {string} rawPattern Raw representation of the pattern in the source code.
59+
*@param {number} rawPatternStartRange Start range of the pattern in the source code.
60+
*@param {string} flags Regular expression flags.
3861
*@returns {void}
3962
*@private
4063
*/
41-
functioncheckRegex(node,value,valueStart){
42-
constmultipleSpacesRegex=/({2,})([+*{?]|[^+*{?]|$)/u,
43-
regexResults=multipleSpacesRegex.exec(value);
64+
functioncheckRegex(nodeToReport,pattern,rawPattern,rawPatternStartRange,flags){
4465

45-
if(regexResults!==null){
46-
constcount=regexResults[1].length;
66+
// Skip if there are no consecutive spaces in the source code, to avoid reporting e.g., RegExp(' \ ').
67+
if(!DOUBLE_SPACE.test(rawPattern)){
68+
return;
69+
}
4770

48-
context.report({
49-
node,
50-
message:"Spaces are hard to count. Use {{{count}}}.",
51-
data:{ count},
52-
fix(fixer){
53-
returnfixer.replaceTextRange(
54-
[valueStart+regexResults.index,valueStart+regexResults.index+count],
55-
` {${count}}`
56-
);
57-
}
58-
});
59-
60-
/*
61-
* TODO: (platinumazure) Fix message to use rule message
62-
* substitution when api.report is fixed in lib/eslint.js.
63-
*/
71+
constcharacterClassNodes=[];
72+
letregExpAST;
73+
74+
try{
75+
regExpAST=regExpParser.parsePattern(pattern,0,pattern.length,flags.includes("u"));
76+
}catch(e){
77+
78+
// Ignore regular expressions with syntax errors
79+
return;
80+
}
81+
82+
regexpp.visitRegExpAST(regExpAST,{
83+
onCharacterClassEnter(ccNode){
84+
characterClassNodes.push(ccNode);
85+
}
86+
});
87+
88+
constspacesPattern=/({2,})(?:[+*{?]|[^+*{?]|$)/gu;
89+
letmatch;
90+
91+
while((match=spacesPattern.exec(pattern))){
92+
const{1:{ length}, index}=match;
93+
94+
// Report only consecutive spaces that are not in character classes.
95+
if(
96+
characterClassNodes.every(({ start, end})=>index<start||end<=index)
97+
){
98+
context.report({
99+
node:nodeToReport,
100+
message:"Spaces are hard to count. Use {{{length}}}.",
101+
data:{ length},
102+
fix(fixer){
103+
if(pattern!==rawPattern){
104+
returnnull;
105+
}
106+
returnfixer.replaceTextRange(
107+
[rawPatternStartRange+index,rawPatternStartRange+index+length],
108+
` {${length}}`
109+
);
110+
}
111+
});
112+
113+
// Report only the first occurence of consecutive spaces
114+
return;
115+
}
64116
}
65117
}
66118

@@ -71,25 +123,22 @@ module.exports = {
71123
*@private
72124
*/
73125
functioncheckLiteral(node){
74-
consttoken=sourceCode.getFirstToken(node),
75-
nodeType=token.type,
76-
nodeValue=token.value;
126+
if(node.regex){
127+
constpattern=node.regex.pattern;
128+
constrawPattern=node.raw.slice(1,node.raw.lastIndexOf("/"));
129+
constrawPatternStartRange=node.range[0]+1;
130+
constflags=node.regex.flags;
77131

78-
if(nodeType==="RegularExpression"){
79-
checkRegex(node,nodeValue,token.range[0]);
132+
checkRegex(
133+
node,
134+
pattern,
135+
rawPattern,
136+
rawPatternStartRange,
137+
flags
138+
);
80139
}
81140
}
82141

83-
/**
84-
* Check if node is a string
85-
*@param {ASTNode} node node to evaluate
86-
*@returns {boolean} True if its a string
87-
*@private
88-
*/
89-
functionisString(node){
90-
returnnode&&node.type==="Literal"&&typeofnode.value==="string";
91-
}
92-
93142
/**
94143
* Validate strings passed to the RegExp constructor
95144
*@param {ASTNode} node node to validate
@@ -100,9 +149,22 @@ module.exports = {
100149
constscope=context.getScope();
101150
constregExpVar=astUtils.getVariableByName(scope,"RegExp");
102151
constshadowed=regExpVar&&regExpVar.defs.length>0;
152+
constpatternNode=node.arguments[0];
153+
constflagsNode=node.arguments[1];
103154

104-
if(node.callee.type==="Identifier"&&node.callee.name==="RegExp"&&isString(node.arguments[0])&&!shadowed){
105-
checkRegex(node,node.arguments[0].value,node.arguments[0].range[0]+1);
155+
if(node.callee.type==="Identifier"&&node.callee.name==="RegExp"&&isString(patternNode)&&!shadowed){
156+
constpattern=patternNode.value;
157+
constrawPattern=patternNode.raw.slice(1,-1);
158+
constrawPatternStartRange=patternNode.range[0]+1;
159+
constflags=isString(flagsNode) ?flagsNode.value :"";
160+
161+
checkRegex(
162+
node,
163+
pattern,
164+
rawPattern,
165+
rawPatternStartRange,
166+
flags
167+
);
106168
}
107169
}
108170

@@ -111,6 +173,5 @@ module.exports = {
111173
CallExpression:checkFunction,
112174
NewExpression:checkFunction
113175
};
114-
115176
}
116177
};

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp