Skip to content

Commit 7d6e6e3

Browse files
authored
Merge pull request #101 from smartmobilefactory/STRFRAMEWORK-1674
Strframework 1674
2 parents 9ed78f4 + 90eae53 commit 7d6e6e3

2 files changed

Lines changed: 148 additions & 52 deletions

File tree

Plist2swift/Plist2swift

-5.96 MB
Binary file not shown.

Plist2swift/Plist2swift.swift

Lines changed: 148 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -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
/**
87139
Generates 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
*/
118170
private 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

460551
let args = CommandLine.arguments
461-
var plists: [String] = []
552+
var plists = [String]()
462553
var enumName: String = ""
463554

464555
if (args.count < 4) {
@@ -494,9 +585,11 @@ if (args.count >= 6 && args[1] == "-e" && args[3] == "-o") {
494585
let shouldGenerateOddKeys: Bool = CommandLine.arguments.count >= 5
495586
var commonKeys = [String]()
496587
var oddKeys = [String]()
497-
var keysAndTypes: [String:String] = [:]
498-
var allTuples: [KeyValueTuples] = []
588+
var keysAndTypes = [String:String]()
589+
var allTuples = [KeyValueTuples]()
499590
var protocolName: String = enumName.appending("Protocol")
591+
var tuplesForPlists = [String: KeyValueTuples]()
592+
var allKeyValueTuples = [String: KeyValueTuples]()
500593

501594
generateHeader()
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)
556652
generateProtocol(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

Comments
 (0)