@@ -95,6 +95,34 @@ extension SourceRange {
9595 }
9696}
9797
98+ /// Represents the kind of ignore directive encountered in the source.
99+ enum IgnoreDirective : CustomStringConvertible {
100+ /// A node-level directive that disables rules for the following node and its children.
101+ case node
102+ /// A file-level directive that disables rules for the entire file.
103+ case file
104+
105+ var description : String {
106+ switch self {
107+ case . node:
108+ return " swift-format-ignore "
109+ case . file:
110+ return " swift-format-ignore-file "
111+ }
112+ }
113+
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+ private var pattern : String {
117+ return #"^\s*\/\/\s*"# + description + #"((:\s+(([A-z0-9]+[,\s]*)+))?$|\s+$)"#
118+ }
119+
120+ /// Rule ignore regex object.
121+ fileprivate var regex : NSRegularExpression {
122+ return try ! NSRegularExpression ( pattern: pattern, options: [ ] )
123+ }
124+ }
125+
98126/// A syntax visitor that finds `SourceRange`s of nodes that have rule status modifying comment
99127/// directives. The changes requested in each comment is parsed and collected into a map to support
100128/// status lookup per rule name.
@@ -116,30 +144,13 @@ fileprivate class RuleStatusCollectionVisitor: SyntaxVisitor {
116144 /// Computes source locations and ranges for syntax nodes in a source file.
117145 private let sourceLocationConverter : SourceLocationConverter
118146
119- /// Regex pattern to match an ignore comment. This pattern supports 0 or more comma delimited rule
120- /// names. The rule name(s), when present, are in capture group #3.
121- private let ignorePattern =
122- #"^\s*\/\/\s*swift-format-ignore((:\s+(([A-z0-9]+[,\s]*)+))?$|\s+$)"#
123-
124- /// Rule ignore regex object.
125- private let ignoreRegex : NSRegularExpression
126-
127- /// Regex pattern to match an ignore comment that applies to an entire file.
128- private let ignoreFilePattern = #"^\s*\/\/\s*swift-format-ignore-file((:\s+(([A-z0-9]+[,\s]*)+))?$|\s+$)"#
129-
130- /// Rule ignore regex object.
131- private let ignoreFileRegex : NSRegularExpression
132-
133147 /// Stores the source ranges in which all rules are ignored.
134148 var allRulesIgnoredRanges : [ SourceRange ] = [ ]
135149
136150 /// Map of rule names to list ranges in the source where the rule is ignored.
137151 var ruleMap : [ String : [ SourceRange ] ] = [ : ]
138152
139153 init ( sourceLocationConverter: SourceLocationConverter ) {
140- ignoreRegex = try ! NSRegularExpression ( pattern: ignorePattern, options: [ ] )
141- ignoreFileRegex = try ! NSRegularExpression ( pattern: ignoreFilePattern, options: [ ] )
142-
143154 self . sourceLocationConverter = sourceLocationConverter
144155 super. init ( viewMode: . sourceAccurate)
145156 }
@@ -155,23 +166,23 @@ fileprivate class RuleStatusCollectionVisitor: SyntaxVisitor {
155166 afterLeadingTrivia: false ,
156167 afterTrailingTrivia: true
157168 )
158- return appendRuleStatusDirectives ( from: firstToken, of: sourceRange, using : ignoreFileRegex )
169+ return appendRuleStatus ( from: firstToken, of: sourceRange, for : . file )
159170 }
160171
161172 override func visit( _ node: CodeBlockItemSyntax ) -> SyntaxVisitorContinueKind {
162173 guard let firstToken = node. firstToken ( viewMode: . sourceAccurate) else {
163174 return . visitChildren
164175 }
165176 let sourceRange = node. sourceRange ( converter: sourceLocationConverter)
166- return appendRuleStatusDirectives ( from: firstToken, of: sourceRange, using : ignoreRegex )
177+ return appendRuleStatus ( from: firstToken, of: sourceRange, for : . node )
167178 }
168179
169180 override func visit( _ node: MemberBlockItemSyntax ) -> SyntaxVisitorContinueKind {
170181 guard let firstToken = node. firstToken ( viewMode: . sourceAccurate) else {
171182 return . visitChildren
172183 }
173184 let sourceRange = node. sourceRange ( converter: sourceLocationConverter)
174- return appendRuleStatusDirectives ( from: firstToken, of: sourceRange, using : ignoreRegex )
185+ return appendRuleStatus ( from: firstToken, of: sourceRange, for : . node )
175186 }
176187
177188 // MARK: - Helper Methods
@@ -183,16 +194,16 @@ fileprivate class RuleStatusCollectionVisitor: SyntaxVisitor {
183194 /// - token: A token that may have comments that modify the status of rules.
184195 /// - sourceRange: The range covering the node to which `token` belongs. If an ignore directive
185196 /// is found among the comments, this entire range is used to ignore the specified rules.
186- /// - regex : The regular expression used to detect ignore directives .
187- private func appendRuleStatusDirectives (
197+ /// - directive : The type of ignore directive to look for .
198+ private func appendRuleStatus (
188199 from token: TokenSyntax ,
189200 of sourceRange: SourceRange ,
190- using regex : NSRegularExpression
201+ for directive : IgnoreDirective
191202 ) -> SyntaxVisitorContinueKind {
192203 let isFirstInFile = token. previousToken ( viewMode: . sourceAccurate) == nil
193204 let comments = loneLineComments ( in: token. leadingTrivia, isFirstToken: isFirstInFile)
194205 for comment in comments {
195- guard let matchResult = ruleStatusDirectiveMatch ( in: comment, using: regex) else { continue }
206+ guard let matchResult = ruleStatusDirectiveMatch ( in: comment, using: directive . regex) else { continue }
196207 switch matchResult {
197208 case . all:
198209 allRulesIgnoredRanges. append ( sourceRange)
0 commit comments