@@ -97,6 +97,8 @@ extension SourceRange {
9797
9898/// Represents the kind of ignore directive encountered in the source.
9999enum  IgnoreDirective :  CustomStringConvertible  { 
100+   typealias  RegexExpression  =  Regex < ( Substring ,  ruleNames:  Substring ? ) > 
101+ 
100102  /// A node-level directive that disables rules for the following node and its children.
101103  case  node
102104  /// A file-level directive that disables rules for the entire file.
@@ -111,10 +113,14 @@ enum IgnoreDirective: CustomStringConvertible {
111113    } 
112114  } 
113115
114-   /// Regex pattern to match an ignore comment. This pattern supports 0 or more comma delimited rule
115-   /// names. The rule name(s), when present, are in capture group #3.
116-   fileprivate  var  pattern :  String  { 
117-     return  #"^\s*\/\/\s*"#  +  description +  #"((:\s+(([A-z0-9]+[,\s]*)+))?$|\s+$)"# 
116+   /// Regex pattern to match an ignore directive comment.
117+   /// - Capture group #1 captures the rule names if `":"` is present.
118+   ///
119+   /// Note: We are using a string-based regex instead of a regex literal (`#/regex/#`)
120+   /// because Windows did not have full support for regex literals until Swift 5.10.
121+   fileprivate  func  makeRegex( )  ->  RegexExpression  { 
122+     let  pattern  =  #"^\s*\/\/\s*"#  +  description +  #"(?:\s*:\s*(?<ruleNames>.+))?$"# 
123+     return  try ! Regex ( pattern) 
118124  } 
119125} 
120126
@@ -140,10 +146,10 @@ fileprivate class RuleStatusCollectionVisitor: SyntaxVisitor {
140146  private  let  sourceLocationConverter :  SourceLocationConverter 
141147
142148  /// Cached regex object for ignoring rules at the node.
143-   private  let  ignoreRegex :  NSRegularExpression 
149+   private  let  ignoreRegex :  IgnoreDirective . RegexExpression 
144150
145151  /// Cached regex object for ignoring rules at the file.
146-   private  let  ignoreFileRegex :  NSRegularExpression 
152+   private  let  ignoreFileRegex :  IgnoreDirective . RegexExpression 
147153
148154  /// Stores the source ranges in which all rules are ignored.
149155  var  allRulesIgnoredRanges :  [ SourceRange ]  =  [ ] 
@@ -152,8 +158,8 @@ fileprivate class RuleStatusCollectionVisitor: SyntaxVisitor {
152158  var  ruleMap :  [ String :  [ SourceRange ] ]  =  [ : ] 
153159
154160  init ( sourceLocationConverter:  SourceLocationConverter )  { 
155-     ignoreRegex =  try !   NSRegularExpression ( pattern :   IgnoreDirective . node. pattern ,  options :   [ ] ) 
156-     ignoreFileRegex =  try !   NSRegularExpression ( pattern :   IgnoreDirective . file. pattern ,  options :   [ ] ) 
161+     ignoreRegex =  IgnoreDirective . node. makeRegex ( ) 
162+     ignoreFileRegex =  IgnoreDirective . file. makeRegex ( ) 
157163
158164    self . sourceLocationConverter =  sourceLocationConverter
159165    super. init ( viewMode:  . sourceAccurate) 
@@ -202,7 +208,7 @@ fileprivate class RuleStatusCollectionVisitor: SyntaxVisitor {
202208  private  func  appendRuleStatus( 
203209    from token:  TokenSyntax , 
204210    of sourceRange:  SourceRange , 
205-     using regex:  NSRegularExpression 
211+     using regex:  IgnoreDirective . RegexExpression 
206212  )  ->  SyntaxVisitorContinueKind  { 
207213    let  isFirstInFile  =  token. previousToken ( viewMode:  . sourceAccurate)  ==  nil 
208214    let  comments  =  loneLineComments ( in:  token. leadingTrivia,  isFirstToken:  isFirstInFile) 
@@ -227,18 +233,15 @@ fileprivate class RuleStatusCollectionVisitor: SyntaxVisitor {
227233  /// match, its contents (e.g. list of rule names) are returned.
228234  private  func  ruleStatusDirectiveMatch( 
229235    in text:  String , 
230-     using regex:  NSRegularExpression 
236+     using regex:  IgnoreDirective . RegexExpression 
231237  )  ->  RuleStatusDirectiveMatch ? { 
232-     let  textRange  =  NSRange ( text. startIndex..< text. endIndex,  in:  text) 
233-     guard  let  match =  regex. firstMatch ( in:  text,  options:  [ ] ,  range:  textRange)  else  { 
238+     guard  let  match =  text. firstMatch ( of:  regex)  else  { 
234239      return  nil 
235240    } 
236-     guard  match. numberOfRanges ==  5  else  {  return  . all } 
237-     let  matchRange  =  match. range ( at:  3 ) 
238-     guard  matchRange. location !=  NSNotFound,  let  ruleNamesRange =  Range ( matchRange,  in:  text)  else  { 
241+     guard  let  matchedRuleNames =  match. output. ruleNames else  { 
239242      return  . all
240243    } 
241-     let  rules  =  text [ ruleNamesRange ] . split ( separator:  " , " ) 
244+     let  rules  =  matchedRuleNames . split ( separator:  " , " ) 
242245      . map  {  $0. trimmingCharacters ( in:  . whitespaces)  } 
243246      . filter  {  $0. count >  0  } 
244247    return  . subset( ruleNames:  rules) 
0 commit comments