@@ -23,16 +23,37 @@ struct Config {
2323 /// Files from the target which includes plugin and target dependencies
2424 /// present in current package manifest are checked.
2525 case direct
26- /// Represents to check all local targets .
26+ /// Represents to check all local target dependencies .
2727 ///
2828 /// Files from the target which includes plugin and all targets
29- /// that are in the same project/package.
29+ /// that are in the same project/package that are dependencies
30+ /// of this target.
3031 case local
3132 /// Represents to check current target and all dependencies.
3233 ///
3334 /// Files from the target which includes plugin and all its
3435 /// dependencies are checked.
3536 case recursive
37+
38+ /// Creates a new instance by decoding from the given decoder.
39+ ///
40+ /// This initializer throws an error if reading from the decoder fails,
41+ /// or if the data read is corrupted or otherwise invalid.
42+ ///
43+ /// - Parameter decoder: The decoder to read data from.
44+ init ( from decoder: Decoder ) throws {
45+ let rawValue = try String ( from: decoder) . lowercased ( )
46+ guard let value = Self ( rawValue: rawValue) else {
47+ throw DecodingError . typeMismatch (
48+ Self . self,
49+ . init(
50+ codingPath: decoder. codingPath,
51+ debugDescription: " Data doesn't match any case "
52+ )
53+ )
54+ }
55+ self = value
56+ }
3657 }
3758}
3859
@@ -47,7 +68,7 @@ extension Config: Codable {
4768 let container = try decoder. container ( keyedBy: CodingKeys . self)
4869 self . scan =
4970 try container. decodeIfPresent (
50- ScanMode . self, forKey : . scan
71+ ScanMode . self, forCaseInsensitiveKey : . scan
5172 ) ?? . target
5273 }
5374
@@ -63,3 +84,45 @@ extension Config: Codable {
6384 #endif
6485 }
6586}
87+
88+ extension KeyedDecodingContainerProtocol {
89+ /// Decodes a value of the given type for the given key case-insensitively,
90+ /// if present.
91+ ///
92+ /// This method returns `nil` if the container does not have a value
93+ /// associated with key case-insensitively, or if the value is null.
94+ ///
95+ /// - Parameters:
96+ /// - type: The type of value to decode.
97+ /// - key: The key that the decoded value is associated with.
98+ ///
99+ /// - Returns: A decoded value of the requested type, or `nil`
100+ /// if the `Decoder` does not have an entry associated with the given
101+ /// key, or if the value is a null value.
102+ ///
103+ /// - Throws: `DecodingError.typeMismatch` if the encountered
104+ /// encoded value is not convertible to the requested type or the key
105+ /// value matches multiple value case-insensitively.
106+ func decodeIfPresent< T: Decodable > (
107+ _ type: T . Type ,
108+ forCaseInsensitiveKey key: Key
109+ ) throws -> T ? {
110+ let keys = self . allKeys. filter { eachKey in
111+ eachKey. stringValue. lowercased ( ) == key. stringValue. lowercased ( )
112+ }
113+
114+ guard keys. count <= 1 else {
115+ throw DecodingError . typeMismatch (
116+ type,
117+ . init(
118+ codingPath: codingPath,
119+ debugDescription: """
120+ Duplicate keys found, keys are case-insensitive.
121+ """
122+ )
123+ )
124+ }
125+
126+ return try decodeIfPresent ( type, forKey: keys. first ?? key)
127+ }
128+ }
0 commit comments