@@ -15,6 +15,8 @@ const {
1515 ReferenceTracker,
1616 getStringIfConstant
1717} = require ( "@eslint-community/eslint-utils" ) ;
18+ const astUtils = require ( "./utils/ast-utils.js" ) ;
19+ const { isValidWithUnicodeFlag } = require ( "./utils/regular-expressions" ) ;
1820
1921//------------------------------------------------------------------------------
2022// Rule Definition
@@ -31,7 +33,10 @@ module.exports = {
3133 url : "https://eslint.org/docs/rules/require-unicode-regexp"
3234 } ,
3335
36+ hasSuggestions : true ,
37+
3438 messages : {
39+ addUFlag : "Add the 'u' flag." ,
3540 requireUFlag : "Use the 'u' flag."
3641 } ,
3742
@@ -47,7 +52,20 @@ module.exports = {
4752 const flags = node . regex . flags || "" ;
4853
4954 if ( ! flags . includes ( "u" ) ) {
50- context . report ( { node, messageId : "requireUFlag" } ) ;
55+ context . report ( {
56+ messageId : "requireUFlag" ,
57+ node,
58+ suggest : isValidWithUnicodeFlag ( context . languageOptions . ecmaVersion , node . regex . pattern )
59+ ? [
60+ {
61+ fix ( fixer ) {
62+ return fixer . insertTextAfter ( node , "u" ) ;
63+ } ,
64+ messageId : "addUFlag"
65+ }
66+ ]
67+ : null
68+ } ) ;
5169 }
5270 } ,
5371
@@ -59,11 +77,46 @@ module.exports = {
5977 } ;
6078
6179 for ( const { node : refNode } of tracker . iterateGlobalReferences ( trackMap ) ) {
62- const flagsNode = refNode . arguments [ 1 ] ;
80+ const [ patternNode , flagsNode ] = refNode . arguments ;
81+ const pattern = getStringIfConstant ( patternNode , scope ) ;
6382 const flags = getStringIfConstant ( flagsNode , scope ) ;
6483
6584 if ( ! flagsNode || ( typeof flags === "string" && ! flags . includes ( "u" ) ) ) {
66- context . report ( { node : refNode , messageId : "requireUFlag" } ) ;
85+ context . report ( {
86+ messageId : "requireUFlag" ,
87+ node : refNode ,
88+ suggest : typeof pattern === "string" && isValidWithUnicodeFlag ( context . languageOptions . ecmaVersion , pattern )
89+ ? [
90+ {
91+ fix ( fixer ) {
92+ if ( flagsNode ) {
93+ if ( ( flagsNode . type === "Literal" && typeof flagsNode . value === "string" ) || flagsNode . type === "TemplateLiteral" ) {
94+ const flagsNodeText = sourceCode . getText ( flagsNode ) ;
95+
96+ return fixer . replaceText ( flagsNode , [
97+ flagsNodeText . slice ( 0 , flagsNodeText . length - 1 ) ,
98+ flagsNodeText . slice ( flagsNodeText . length - 1 )
99+ ] . join ( "u" ) ) ;
100+ }
101+
102+ // We intentionally don't suggest concatenating + "u" to non-literals
103+ return null ;
104+ }
105+
106+ const penultimateToken = sourceCode . getLastToken ( refNode , { skip : 1 } ) ; // skip closing parenthesis
107+
108+ return fixer . insertTextAfter (
109+ penultimateToken ,
110+ astUtils . isCommaToken ( penultimateToken )
111+ ? ' "u",'
112+ : ', "u"'
113+ ) ;
114+ } ,
115+ messageId : "addUFlag"
116+ }
117+ ]
118+ : null
119+ } ) ;
67120 }
68121 }
69122 }
0 commit comments