@@ -30,10 +30,10 @@ private func usage() {
3030 exit ( 1 )
3131}
3232
33- private func tabs( intendBy : Int = 0 ) -> String {
33+ private func tabs( indentBy : Int = 0 ) -> String {
3434 var tabsString = " "
3535
36- intend ( by: intendBy )
36+ indent ( by: indentBy )
3737
3838 for _ in 0 ..< countOfTabs {
3939 tabsString += " \t "
@@ -42,7 +42,7 @@ private func tabs(intendBy: Int = 0) -> String {
4242 return tabsString
4343}
4444
45- private func intend ( by indentationLevel: Int = 1 ) {
45+ private func indent ( by indentationLevel: Int = 1 ) {
4646 countOfTabs += indentationLevel
4747}
4848
@@ -83,6 +83,58 @@ private func generateHeader() {
8383 """ )
8484}
8585
86+ private func isKeyPresentInOptionalDictionary( keyToSearch: String , tupleKey: String , optionalDictionary: [ String : [ String : String ] ] ) -> Bool {
87+ guard let optionalKeysAndTypes = optionalDictionary [ keyToSearch] else {
88+ return false
89+ }
90+
91+ let optionalArray = optionalKeysAndTypes. keys
92+ return optionalArray. contains ( tupleKey)
93+ }
94+
95+ private func isKeyAvailableInAllPlists( keyToSearch: String , tupleKey: String , tuplesForPlists: [ String : KeyValueTuples ] ) -> Bool {
96+ for plistPath in tuplesForPlists. keys {
97+ if
98+ let tuples = tuplesForPlists [ plistPath] ,
99+ let dictionary = tuples [ tupleKey] as? Dictionary < String , Any > {
100+
101+ if ( dictionary. keys. contains ( keyToSearch) == false ) {
102+ return false
103+ }
104+ }
105+ }
106+
107+ return true
108+ }
109+
110+ private func generateProtocol( tuplesForPlists: [ String : KeyValueTuples ] , allKeyValueTuples: [ String : KeyValueTuples ] ) -> [ String : [ String : String ] ] {
111+ var dictionaryWithOptionalValues = [ String: [ String: String] ] ( )
112+ for (tupleKey, tuples) in allKeyValueTuples {
113+
114+ let name = tupleKey. uppercaseFirst ( )
115+ let protocolName = name. appending ( " Protocol " )
116+ print ( " protocol \( protocolName) { " )
117+ indent ( )
118+
119+ var optionalKeysAndTypes = [ String: String] ( )
120+ for tuple in tuples. tuples {
121+ let isKeyPresentInAllPlists = isKeyAvailableInAllPlists ( keyToSearch: tuple. key, tupleKey: tupleKey, tuplesForPlists: tuplesForPlists)
122+ var type = typeForValue ( tuple. value as Any )
123+ if ( isKeyPresentInAllPlists == false ) {
124+ type = " \( type) ? "
125+ optionalKeysAndTypes [ tuple. key] = type
126+ }
127+
128+ print ( " \( tabs ( ) ) var \( tuple. key. lowercaseFirst ( ) ) : \( type) { get } " )
129+ }
130+
131+ dictionaryWithOptionalValues [ tupleKey] = optionalKeysAndTypes
132+ print ( " \( tabs ( indentBy: - 1 ) ) } \n " )
133+ }
134+
135+ return dictionaryWithOptionalValues
136+ }
137+
86138/**
87139Generates a protocol with public instance properties. Used to generate protocols that internal structs conform to.
88140
@@ -95,14 +147,14 @@ private func generateProtocol(name: String, tuples: KeyValueTuples) -> String {
95147
96148 let protocolName = name. appending ( " Protocol " )
97149 print ( " protocol \( protocolName) { " )
98- intend ( )
150+ indent ( )
99151
100152 for tuple in tuples. tuples {
101153 let type = typeForValue ( tuple. value as Any )
102154 print ( " \( tabs ( ) ) var \( tuple. key. lowercaseFirst ( ) ) : \( type) { get } " )
103155 }
104156
105- print ( " \( tabs ( intendBy : - 1 ) ) } \n " )
157+ print ( " \( tabs ( indentBy : - 1 ) ) } \n " )
106158 return protocolName
107159}
108160
@@ -117,7 +169,7 @@ Generate the general protocol with class properties.
117169*/
118170private func generateProtocol( name: String , commonKeys: [ String ] , oddKeys: [ String ] , keysAndTypes: [ String : String ] ) {
119171 print ( " \( tabs ( ) ) protocol \( name) { " )
120- intend ( )
172+ indent ( )
121173 print ( " \( tabs ( ) ) // Common Keys " )
122174
123175 for commonKey in commonKeys {
@@ -143,7 +195,7 @@ private func generateProtocol(name: String, commonKeys: [String], oddKeys: [Stri
143195 }
144196 }
145197
146- print ( " \( tabs ( intendBy : - 1 ) ) } \n " )
198+ print ( " \( tabs ( indentBy : - 1 ) ) } \n " )
147199}
148200
149201/**
@@ -157,11 +209,11 @@ Generate structs out of Dictionaries and make them conform to a given protocol.
157209- protocolName: Name of the protocol; It has to end with a "Protocol" suffix; Default is 'nil' - the new generated protocol will be used
158210
159211*/
160- private func generateStructs( name structName : String ? = nil , tuples: KeyValueTuples , keysAndTypes: [ String : String ] ? = nil , oddKeys: [ String ] , protocolName: String ? = nil ) {
212+ private func generateStructs( name key : String ? = nil , tuples: KeyValueTuples , keysAndTypes: [ String : String ] ? = nil , oddKeys: [ String ] , protocolName: String ? = nil , optionalDictionary : [ String : [ String : String ] ] ) {
161213 var configName : String ? = tuples [ configurationKeyName] as? String
162214
163- if ( configName == nil && structName != nil ) {
164- configName = structName ? . uppercaseFirst ( )
215+ if ( configName == nil && key != nil ) {
216+ configName = key
165217 }
166218
167219 guard var structName = configName else {
@@ -205,48 +257,87 @@ private func generateStructs(name structName: String? = nil, tuples: KeyValueTup
205257 }
206258
207259 print ( " \n \( tabs ( ) ) internal struct \( structName) \( conformingToProtocol) { " )
208- intend ( )
260+ indent ( )
209261
262+ var availableKeys = [ String] ( )
210263 for tuple in tuples. tuples {
211264
212- let key = tuple. key
213- let value = tuple. value
265+ let tupleKey = tuple. key
266+ let tupleValue = tuple. value
267+ availableKeys. append ( tupleKey)
214268
215- if ( oddKeys. contains ( key ) ) {
269+ if ( oddKeys. contains ( tupleKey ) ) {
216270 continue
217271 }
218272
219- guard let type = localKeysAndTypes ? [ key ] else {
273+ guard let type = localKeysAndTypes ? [ tupleKey ] else {
220274 return
221275 }
222276
277+ let isOptional : Bool = {
278+ guard let key = key else {
279+ return false
280+ }
281+
282+ return isKeyPresentInOptionalDictionary ( keyToSearch: key, tupleKey: tupleKey, optionalDictionary: optionalDictionary)
283+ } ( )
284+
223285 switch type {
224- case " String " :
225- print ( " \( tabs ( ) ) internal let \( key. lowercaseFirst ( ) ) : \( type) = \" \( value) \" " )
226- case " Int " :
227- print ( " \( tabs ( ) ) internal let \( key. lowercaseFirst ( ) ) : \( type) = \( value) " )
228- case " Bool " :
229- let boolString = ( ( ( value as? Bool ) == true ) ? " true " : " false " )
230- print ( " \( tabs ( ) ) internal let \( key. lowercaseFirst ( ) ) : \( type) = \( boolString) " )
231- case " Array<Any> " :
232- let arrayValue = value as! Array < String >
233- print ( " \( tabs ( ) ) internal let \( key. lowercaseFirst ( ) ) : \( type) = \( arrayValue) " )
286+ case " String " where ( isOptional == false ) :
287+ print ( " \( tabs ( ) ) internal let \( tupleKey. lowercaseFirst ( ) ) : \( type) = \" \( tupleValue) \" " )
288+ case " String " where ( isOptional == true ) :
289+ print ( " \( tabs ( ) ) internal var \( tupleKey. lowercaseFirst ( ) ) : \( type) ? = \" \( tupleValue) \" " )
290+ case " Int " where ( isOptional == false ) :
291+ print ( " \( tabs ( ) ) internal let \( tupleKey. lowercaseFirst ( ) ) : \( type) = \( tupleValue) " )
292+ case " Int " where ( isOptional == true ) :
293+ print ( " \( tabs ( ) ) internal var \( tupleKey. lowercaseFirst ( ) ) : \( type) ? = \( tupleValue) " )
294+ case " Bool " where ( isOptional == false ) :
295+ let boolString = ( ( ( tupleValue as? Bool ) == true ) ? " true " : " false " )
296+ print ( " \( tabs ( ) ) internal let \( tupleKey. lowercaseFirst ( ) ) : \( type) = \( boolString) " )
297+ case " Bool " where ( isOptional == true ) :
298+ let boolString = ( ( ( tupleValue as? Bool ) == true ) ? " true " : " false " )
299+ print ( " \( tabs ( ) ) internal var \( tupleKey. lowercaseFirst ( ) ) : \( type) ? = \( boolString) " )
300+ case " Array<Any> " where ( isOptional == false ) :
301+ if let arrayValue = tupleValue as? Array < String > {
302+ print ( " \( tabs ( ) ) internal let \( tupleKey. lowercaseFirst ( ) ) : \( type) = \( arrayValue) " )
303+ }
304+ case " Array<Any> " where ( isOptional == true ) :
305+ if let arrayValue = tupleValue as? Array < String > {
306+ print ( " \( tabs ( ) ) internal var \( tupleKey. lowercaseFirst ( ) ) : \( type) ? = \( arrayValue) " )
307+ }
234308 default :
235309 // default is a struct
236310 // Generate struct from the Dictionaries and Protocols
237311 if ( type. contains ( " Protocol " ) ) {
238- let dictionary = tuples [ key ] as? Dictionary < String , Any >
312+ let dictionary = tuples [ tupleKey ] as? Dictionary < String , Any >
239313 let sortedDictionary = dictionary? . sorted { ( pairOne, pairTwo) -> Bool in
240314 return pairOne. key < pairTwo. key
241315 }
242316
243- generateStructs ( name: key . uppercaseFirst ( ) , tuples: KeyValueTuples ( tuples: sortedDictionary ?? [ ] ) , oddKeys: oddKeys, protocolName: type)
317+ generateStructs ( name: tupleKey , tuples: KeyValueTuples ( tuples: sortedDictionary ?? [ ] ) , oddKeys: oddKeys, protocolName: type, optionalDictionary : optionalDictionary )
244318
245- print ( " \( tabs ( ) ) internal let \( key . lowercaseFirst ( ) ) : \( type) = \( key . uppercaseFirst ( ) ) () " )
319+ print ( " \( tabs ( ) ) internal let \( tupleKey . lowercaseFirst ( ) ) : \( type) = \( tupleKey . uppercaseFirst ( ) ) () " )
246320 }
321+
247322 }
248323 }
249- print ( " \( tabs ( intendBy: - 1 ) ) } \n " )
324+
325+ guard
326+ let key = key,
327+ let optionalKeysAndTypes = optionalDictionary [ key] else {
328+ print ( " \( tabs ( indentBy: - 1 ) ) } \n " )
329+ return
330+ }
331+
332+ let keysAndTypesToAdd = optionalKeysAndTypes. filter { ( key: String , type: String ) in
333+ return ( availableKeys. contains ( key) == false )
334+ }
335+
336+ for (key, type) in keysAndTypesToAdd {
337+ print ( " \( tabs ( ) ) internal var \( key. lowercaseFirst ( ) ) : \( type) = nil " )
338+ }
339+
340+ print ( " \( tabs ( indentBy: - 1 ) ) } \n " )
250341}
251342
252343/**
@@ -260,7 +351,7 @@ Generates extensions to structs, conforming to protocol
260351- oddKeys: Keys to generate Optional properties from
261352
262353*/
263- private func generateExtensions( enumName: String , protocolName: String , allTuples: [ KeyValueTuples ] , keysAndTypes: Dictionary < String , String > , oddKeys: [ String ] ) {
354+ private func generateExtensions( enumName: String , protocolName: String , allTuples: [ KeyValueTuples ] , keysAndTypes: Dictionary < String , String > , oddKeys: [ String ] , optionalDictionary : [ String : [ String : String ] ] ) {
264355 for tuples in allTuples {
265356
266357 guard let caseName = tuples [ configurationKeyName] as? String else {
@@ -270,7 +361,7 @@ private func generateExtensions(enumName: String, protocolName: String, allTuple
270361 let structName = caseName. uppercaseFirst ( )
271362
272363 print ( " \( tabs ( ) ) extension \( enumName) . \( structName) : \( protocolName) { " )
273- intend ( )
364+ indent ( )
274365
275366 for oddKey in oddKeys {
276367
@@ -288,8 +379,8 @@ private func generateExtensions(enumName: String, protocolName: String, allTuple
288379 } else if ( type. contains ( " Protocol " ) ) {
289380 guard tuples [ oddKey] != nil else {
290381 print ( " \( tabs ( ) ) var \( oddKey. lowercaseFirst ( ) ) : \( type) ? { " )
291- print ( " \( tabs ( intendBy : 1 ) ) return nil " )
292- print ( " \( tabs ( intendBy : - 1 ) ) } " )
382+ print ( " \( tabs ( indentBy : 1 ) ) return nil " )
383+ print ( " \( tabs ( indentBy : - 1 ) ) } " )
293384 continue
294385 }
295386
@@ -298,19 +389,19 @@ private func generateExtensions(enumName: String, protocolName: String, allTuple
298389 return pairOne. key < pairTwo. key
299390 }
300391
301- generateStructs ( name: oddKey. uppercaseFirst ( ) , tuples: KeyValueTuples ( tuples: sortedDictionary ?? [ ] ) , oddKeys: oddKeys, protocolName: type)
392+ generateStructs ( name: oddKey, tuples: KeyValueTuples ( tuples: sortedDictionary ?? [ ] ) , oddKeys: oddKeys, protocolName: type, optionalDictionary : optionalDictionary )
302393 print ( " \( tabs ( ) ) var \( oddKey. lowercaseFirst ( ) ) : \( type) ? { " )
303- print ( " \( tabs ( intendBy : 1 ) ) return \( oddKey. uppercaseFirst ( ) ) () " )
304- print ( " \( tabs ( intendBy : - 1 ) ) } " )
394+ print ( " \( tabs ( indentBy : 1 ) ) return \( oddKey. uppercaseFirst ( ) ) () " )
395+ print ( " \( tabs ( indentBy : - 1 ) ) } " )
305396 } else { // String
306397 print ( " \( tabs ( ) ) var \( oddKey. lowercaseFirst ( ) ) : \( type) ? { " )
307- intend ( )
398+ indent ( )
308399 let returnValue = tuples [ oddKey] as? String
309400 returnValue != nil ? print ( " \( tabs ( ) ) return \" \( returnValue!) \" " ) : print ( " \( tabs ( ) ) return nil " )
310- print ( " \( tabs ( intendBy : - 1 ) ) } " )
401+ print ( " \( tabs ( indentBy : - 1 ) ) } " )
311402 }
312403 }
313- print ( " \( tabs ( intendBy : - 1 ) ) } \n " )
404+ print ( " \( tabs ( indentBy : - 1 ) ) } \n " )
314405 }
315406}
316407
@@ -325,27 +416,27 @@ Generate an enum with structs and properties.
325416- oddKeys: Keys to generate Optional properties from
326417
327418*/
328- private func generateEnum( name enumName: String , protocolName: String , allTuples: [ KeyValueTuples ] , keysAndTypes: Dictionary < String , String > , oddKeys: [ String ] ) {
419+ private func generateEnum( name enumName: String , protocolName: String , allTuples: [ KeyValueTuples ] , keysAndTypes: Dictionary < String , String > , oddKeys: [ String ] , optionalDictionary : [ String : [ String : String ] ] ) {
329420
330421 let cases : [ String ] = allTuples. map { ( tuples: KeyValueTuples ) in
331422 return ( tuples [ configurationKeyName] as? String ?? " " )
332423 }
333424
334425 print ( " \( tabs ( ) ) internal enum \( enumName) { " )
335- intend ( )
426+ indent ( )
336427
337428 for caseName in cases {
338429 print ( " \( tabs ( ) ) case \( caseName. lowercaseFirst ( ) ) " )
339430 }
340431
341432 for tuples in allTuples {
342- generateStructs ( tuples: tuples, keysAndTypes: keysAndTypes, oddKeys: oddKeys)
433+ generateStructs ( tuples: tuples, keysAndTypes: keysAndTypes, oddKeys: oddKeys, optionalDictionary : optionalDictionary )
343434 }
344435
345436 print ( """
346437 \( tabs ( ) ) var configuration: \( protocolName) {
347438
348- \( tabs ( intendBy : 1 ) ) switch self {
439+ \( tabs ( indentBy : 1 ) ) switch self {
349440 """ )
350441
351442 for caseName in cases {
@@ -355,9 +446,9 @@ private func generateEnum(name enumName: String, protocolName: String, allTuples
355446 }
356447
357448 print ( " \( tabs ( ) ) } " )
358- print ( " \( tabs ( intendBy : - 1 ) ) } " )
359- print ( " \( tabs ( intendBy : - 1 ) ) } \n " )
360- generateExtensions ( enumName: enumName, protocolName: protocolName, allTuples: allTuples, keysAndTypes: keysAndTypes, oddKeys: oddKeys)
449+ print ( " \( tabs ( indentBy : - 1 ) ) } " )
450+ print ( " \( tabs ( indentBy : - 1 ) ) } \n " )
451+ generateExtensions ( enumName: enumName, protocolName: protocolName, allTuples: allTuples, keysAndTypes: keysAndTypes, oddKeys: oddKeys, optionalDictionary : optionalDictionary )
361452}
362453
363454/**
@@ -458,7 +549,7 @@ class KeyValueTuples {
458549// MARK: Main
459550
460551let args = CommandLine . arguments
461- var plists : [ String ] = [ ]
552+ var plists = [ String ] ( )
462553var enumName : String = " "
463554
464555if ( args. count < 4 ) {
@@ -494,9 +585,11 @@ if (args.count >= 6 && args[1] == "-e" && args[3] == "-o") {
494585let shouldGenerateOddKeys : Bool = CommandLine . arguments. count >= 5
495586var commonKeys = [ String] ( )
496587var oddKeys = [ String] ( )
497- var keysAndTypes : [ String : String ] = [ : ]
498- var allTuples : [ KeyValueTuples ] = [ ]
588+ var keysAndTypes = [ String: String] ( )
589+ var allTuples = [ KeyValueTuples ] ( )
499590var protocolName : String = enumName. appending ( " Protocol " )
591+ var tuplesForPlists = [ String: KeyValueTuples] ( )
592+ var allKeyValueTuples = [ String: KeyValueTuples] ( )
500593
501594generateHeader ( )
502595
@@ -508,6 +601,7 @@ for plistPath in plists {
508601 exit ( 1 )
509602 }
510603
604+ tuplesForPlists [ plistPath] = tuples
511605 allTuples. append ( tuples)
512606
513607 let allKeys = tuples. keys
@@ -537,8 +631,9 @@ for plistPath in plists {
537631 return pairOne. key < pairTwo. key
538632 }
539633
540- let protocolName = generateProtocol ( name: key. uppercaseFirst ( ) , tuples: KeyValueTuples ( tuples: sortedDictionary ?? [ ] ) )
541- // override type with new protocol
634+ allKeyValueTuples [ key] = KeyValueTuples ( tuples: sortedDictionary ?? [ ] )
635+ let name = key. uppercaseFirst ( )
636+ let protocolName = name. appending ( " Protocol " )
542637 keysAndTypes [ key] = protocolName
543638 }
544639 }
@@ -553,5 +648,6 @@ for plistPath in plists {
553648 }
554649}
555650
651+ let optionalDictionary = generateProtocol ( tuplesForPlists: tuplesForPlists, allKeyValueTuples: allKeyValueTuples)
556652generateProtocol ( name: protocolName, commonKeys: commonKeys, oddKeys: oddKeys, keysAndTypes: keysAndTypes)
557- generateEnum ( name: enumName, protocolName: protocolName, allTuples: allTuples, keysAndTypes: keysAndTypes, oddKeys: oddKeys)
653+ generateEnum ( name: enumName, protocolName: protocolName, allTuples: allTuples, keysAndTypes: keysAndTypes, oddKeys: oddKeys, optionalDictionary : optionalDictionary )
0 commit comments