1313
1414public struct FlagKeyPath : Hashable , Sendable {
1515
16- public enum Key : Hashable , Sendable {
16+ public enum Key : Sendable {
1717 case root
1818 case automatic( String )
1919 case kebabcase( String )
@@ -25,11 +25,26 @@ public struct FlagKeyPath: Hashable, Sendable {
2525 // MARK: - Properties
2626
2727 let keyPath : [ Key ]
28+
29+ public let key : String
2830 public let separator : String
2931 public let strategy : VexilConfiguration . CodingKeyStrategy
3032
3133 // MARK: - Initialisation
3234
35+ /// Memberwise initialiser
36+ init (
37+ _ keyPath: [ Key ] ,
38+ separator: String = " . " ,
39+ strategy: VexilConfiguration . CodingKeyStrategy = . default,
40+ key: String
41+ ) {
42+ self . keyPath = keyPath
43+ self . separator = separator
44+ self . strategy = strategy
45+ self . key = key
46+ }
47+
3348 public init (
3449 _ keyPath: [ Key ] ,
3550 separator: String = " . " ,
@@ -38,6 +53,18 @@ public struct FlagKeyPath: Hashable, Sendable {
3853 self . keyPath = keyPath
3954 self . separator = separator
4055 self . strategy = strategy
56+
57+ self . key = {
58+ var toReturn = [ String] ( )
59+ for path in keyPath {
60+ switch path. stringKeyMode ( strategy: strategy) {
61+ case let . append( key) : toReturn. append ( key)
62+ case let . replace( key) : return key
63+ case . root: break
64+ }
65+ }
66+ return toReturn. joined ( separator: separator)
67+ } ( )
4168 }
4269
4370 public init ( _ key: String , separator: String = " . " , strategy: VexilConfiguration . CodingKeyStrategy = . default) {
@@ -50,27 +77,22 @@ public struct FlagKeyPath: Hashable, Sendable {
5077 FlagKeyPath (
5178 keyPath + [ key ] ,
5279 separator: separator,
53- strategy: strategy
80+ strategy: strategy,
81+ key: {
82+ switch key. stringKeyMode ( strategy: strategy) {
83+ case let . append( string) where self . key. isEmpty:
84+ string
85+ case let . append( string) :
86+ self . key + separator + string
87+ case let . replace( string) :
88+ string
89+ case . root:
90+ self . key // mostly a noop
91+ }
92+ } ( )
5493 )
5594 }
5695
57- public var key : String {
58- var toReturn = [ String] ( )
59- for path in keyPath {
60- switch ( path, strategy) {
61- case let ( . automatic( key) , . default) , let ( . automatic( key) , . kebabcase) , let ( . kebabcase( key) , _) , let ( . customKey( key) , _) :
62- toReturn. append ( key)
63- case let ( . automatic( key) , . snakecase) , let ( . snakecase( key) , _) :
64- toReturn. append ( key. replacingOccurrences ( of: " - " , with: " _ " ) )
65- case let ( . customKeyPath( key) , _) :
66- return key
67- case ( . root, _) :
68- break
69- }
70- }
71- return toReturn. joined ( separator: separator)
72- }
73-
7496 static func root( separator: String , strategy: VexilConfiguration . CodingKeyStrategy ) -> FlagKeyPath {
7597 FlagKeyPath (
7698 [ . root ] ,
@@ -79,4 +101,39 @@ public struct FlagKeyPath: Hashable, Sendable {
79101 )
80102 }
81103
104+ // MARK: - Hashable
105+
106+ // Equality for us is based on the output key, not how it was created. Otherwise
107+ // keys coming back from external sources will never match an internally created one.
108+
109+ public static func == ( lhs: FlagKeyPath , rhs: FlagKeyPath ) -> Bool {
110+ lhs. key == rhs. key
111+ }
112+
113+ public func hash( into hasher: inout Hasher ) {
114+ hasher. combine ( key)
115+ }
116+
117+ }
118+
119+
120+ private extension FlagKeyPath . Key {
121+ enum Mode {
122+ case append( String )
123+ case replace( String )
124+ case root
125+ }
126+
127+ func stringKeyMode( strategy: VexilConfiguration . CodingKeyStrategy ) -> Mode {
128+ switch ( self , strategy) {
129+ case let ( . automatic( key) , . default) , let ( . automatic( key) , . kebabcase) , let ( . kebabcase( key) , _) , let ( . customKey( key) , _) :
130+ . append( key)
131+ case let ( . automatic( key) , . snakecase) , let ( . snakecase( key) , _) :
132+ . append( key. replacingOccurrences ( of: " - " , with: " _ " ) )
133+ case let ( . customKeyPath( key) , _) :
134+ . replace( key)
135+ case ( . root, _) :
136+ . root
137+ }
138+ }
82139}
0 commit comments