From c5a4da49eb58b4c578d4ea1292490e6f8aa84ad6 Mon Sep 17 00:00:00 2001 From: superk Date: Mon, 27 Nov 2017 09:44:58 +0800 Subject: [PATCH 01/24] fix a complier error in SwiftyJSON - Class --- JSONExport/Supported Languages/SwiftyJSON-Class.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONExport/Supported Languages/SwiftyJSON-Class.json b/JSONExport/Supported Languages/SwiftyJSON-Class.json index 9159910..af485bf 100755 --- a/JSONExport/Supported Languages/SwiftyJSON-Class.json +++ b/JSONExport/Supported Languages/SwiftyJSON-Class.json @@ -77,7 +77,7 @@ "forEachCustomTypeProperty": "\t\tif != nil{\n\t\t\tdictionary[\"\"] = .toDictionary()\n\t\t}\n", "forEachArrayOfCustomTypeProperty": "\t\tif != nil{\n\t\t\tvar dictionaryElements = [[String:Any]]()\n\t\t\tfor Element in {\n\t\t\t\tdictionaryElements.append(Element.toDictionary())\n\t\t\t}\n\t\t\tdictionary[\"\"] = dictionaryElements\n\t\t}\n", "returnStatement": "\t\treturn dictionary\n", - "body": "\t\tlet dictionary = [String:Any]()\n", + "body": "\t\tvar dictionary = [String:Any]()\n", "comment": "\t/**\n\t * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property\n\t */\n", "bodyStart": "\n\t{\n" }, From 779a06f5dcb26c02cd0b9e48edfa725de1986b72 Mon Sep 17 00:00:00 2001 From: Serhii Londar Date: Wed, 13 Dec 2017 18:33:54 +0200 Subject: [PATCH 02/24] Migrate to Swift 4 --- JSONExport.xcodeproj/project.pbxproj | 4 +-- .../UserInterfaceState.xcuserstate | Bin 0 -> 33880 bytes .../xcschemes/xcschememanagement.plist | 14 ++++++++++ JSONExport/FilePreviewCell.swift | 16 +++++------ JSONExport/ViewController.swift | 26 ++++++++---------- 5 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 JSONExport.xcodeproj/project.xcworkspace/xcuserdata/serhii-londar.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 JSONExport.xcodeproj/xcuserdata/serhii-londar.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/JSONExport.xcodeproj/project.pbxproj b/JSONExport.xcodeproj/project.pbxproj index c4f6227..ff07a60 100755 --- a/JSONExport.xcodeproj/project.pbxproj +++ b/JSONExport.xcodeproj/project.pbxproj @@ -447,7 +447,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "JSONExport/JSONExport-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -462,7 +462,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "ahmed.ali.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "JSONExport/JSONExport-Bridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Release; }; diff --git a/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/serhii-londar.xcuserdatad/UserInterfaceState.xcuserstate b/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/serhii-londar.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..46a37a2a6429fceb6e602df7564f20c3eae1a6b3 GIT binary patch literal 33880 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 literal 0 HcmV?d00001 diff --git a/JSONExport.xcodeproj/xcuserdata/serhii-londar.xcuserdatad/xcschemes/xcschememanagement.plist b/JSONExport.xcodeproj/xcuserdata/serhii-londar.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..1ccfc36 --- /dev/null +++ b/JSONExport.xcodeproj/xcuserdata/serhii-londar.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + JSONExport.xcscheme + + orderHint + 0 + + + + diff --git a/JSONExport/FilePreviewCell.swift b/JSONExport/FilePreviewCell.swift index e31d04c..f4d9a77 100755 --- a/JSONExport/FilePreviewCell.swift +++ b/JSONExport/FilePreviewCell.swift @@ -35,14 +35,14 @@ class FilePreviewCell: NSTableCellView, NSTextViewDelegate { } if self.file.includeConstructors{ - self.constructors.state = NSOnState + self.constructors.state = .on }else{ - self.constructors.state = NSOffState + self.constructors.state = .off } if self.file.includeUtilities{ - self.utilities.state = NSOnState + self.utilities.state = .on }else{ - self.utilities.state = NSOffState + self.utilities.state = .off } } }else{ @@ -70,14 +70,14 @@ class FilePreviewCell: NSTableCellView, NSTextViewDelegate { scrollView.hasVerticalRuler = true scrollView.verticalRulerView = lineNumberView scrollView.rulersVisible = true - textView.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize()) + textView.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize) } @IBAction func toggleConstructors(_ sender: NSButtonCell) { if file != nil{ - file.includeConstructors = (sender.state == NSOnState) + file.includeConstructors = (sender.state == NSControl.StateValue.on) textView.string = file.toString() } @@ -86,13 +86,13 @@ class FilePreviewCell: NSTableCellView, NSTextViewDelegate { @IBAction func toggleUtilityMethods(_ sender: NSButtonCell) { if file != nil{ - file.includeUtilities = (sender.state == NSOnState) + file.includeUtilities = (sender.state == NSControl.StateValue.on) textView.string = file.toString() } } func textDidChange(_ notification: Notification) { - file.fileContent = textView.string ?? file.fileContent + file.fileContent = textView.string } diff --git a/JSONExport/ViewController.swift b/JSONExport/ViewController.swift index 6e55e7a..72bb3b2 100755 --- a/JSONExport/ViewController.swift +++ b/JSONExport/ViewController.swift @@ -119,7 +119,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl scrollView.hasVerticalRuler = true scrollView.verticalRulerView = lineNumberView scrollView.rulersVisible = true - sourceText.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize()) + sourceText.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize) } @@ -185,7 +185,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl { let jsonString = String(data: jsonData, encoding: .utf8) - sourceText.string = jsonString + sourceText.string = jsonString! } //MARK: - Handlind events @@ -199,8 +199,8 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl oPanel.allowedFileTypes = ["json","JSON"] oPanel.prompt = "Choose JSON file" - oPanel.beginSheetModal(for: self.view.window!, completionHandler: { (button : Int) -> Void in - if button == NSFileHandlingPanelOKButton{ + oPanel.beginSheetModal(for: self.view.window!) { (button) in + if button.rawValue == NSFileHandlingPanelOKButton { let jsonPath = oPanel.urls.first!.path let fileHandle = FileHandle(forReadingAtPath: jsonPath) @@ -209,7 +209,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl self.parseJSONData(jsonData: (fileHandle!.readDataToEndOfFile() as NSData!) as Data!) } - }) + } } @@ -286,14 +286,12 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl openPanel.canChooseDirectories = true openPanel.canCreateDirectories = true openPanel.prompt = "Choose" - openPanel.beginSheetModal(for: self.view.window!, completionHandler: { (button : Int) -> Void in - if button == NSFileHandlingPanelOKButton{ - + openPanel.beginSheetModal(for: self.view.window!) { button in + if button.rawValue == NSFileHandlingPanelOKButton{ self.saveToPath(openPanel.url!.path) - self.showDoneSuccessfully() } - }) + } } @@ -386,7 +384,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl func generateClasses() { saveButton.isEnabled = false - var str = sourceText.string! + var str = sourceText.string if str.characters.count == 0{ runOnUiThread{ @@ -455,8 +453,8 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl func prepareAndGetFilesBuilder() -> FilesContentBuilder { let filesBuilder = FilesContentBuilder.instance - filesBuilder.includeConstructors = (generateConstructors.state == NSOnState) - filesBuilder.includeUtilities = (generateUtilityMethods.state == NSOnState) + filesBuilder.includeConstructors = (generateConstructors.state == .on) + filesBuilder.includeUtilities = (generateUtilityMethods.state == .on) filesBuilder.firstLine = firstLineField.stringValue filesBuilder.lang = selectedLang! filesBuilder.classPrefix = classPrefixField.stringValue @@ -477,7 +475,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl //MARK: - NSTableViewDelegate func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - let cell = tableView.make(withIdentifier: "fileCell", owner: self) as! FilePreviewCell + let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "fileCell"), owner: self) as! FilePreviewCell let file = files[row] cell.file = file From e40b25831ea6048626d2556b0146ff877dcb846c Mon Sep 17 00:00:00 2001 From: Muhammad Umer Date: Tue, 26 Dec 2017 11:23:05 +0500 Subject: [PATCH 03/24] Added Swift-Codable-Struct with forced unwrapped option --- JSONExport/FileRepresenter.swift | 2 +- JSONExport/HeaderFileRepresenter.swift | 2 +- JSONExport/Swift-Codable-Unwrapped.json | 105 ++++++++++++++++++++++++ JSONExport/ViewController.swift | 4 +- 4 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 JSONExport/Swift-Codable-Unwrapped.json diff --git a/JSONExport/FileRepresenter.swift b/JSONExport/FileRepresenter.swift index b26a80e..96d286f 100755 --- a/JSONExport/FileRepresenter.swift +++ b/JSONExport/FileRepresenter.swift @@ -189,7 +189,7 @@ class FileRepresenter{ fileContent += ". All rights reserved.\n" } - fileContent += "//\tModel file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport" + // fileContent += "//\tModel file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport" if let langAuthor = lang.author{ fileContent += "\n\n//\tThe \"\(lang.displayLangName!)\" support has been made available by \(langAuthor.name!)" diff --git a/JSONExport/HeaderFileRepresenter.swift b/JSONExport/HeaderFileRepresenter.swift index c819679..dde5b12 100755 --- a/JSONExport/HeaderFileRepresenter.swift +++ b/JSONExport/HeaderFileRepresenter.swift @@ -109,7 +109,7 @@ class HeaderFileRepresenter : FileRepresenter{ } fileContent += ". All rights reserved.\n//\n\n" - fileContent += "//\tModel file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport\n\n" + //fileContent += "//\tModel file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport\n\n" } } diff --git a/JSONExport/Swift-Codable-Unwrapped.json b/JSONExport/Swift-Codable-Unwrapped.json new file mode 100644 index 0000000..9b1a0a4 --- /dev/null +++ b/JSONExport/Swift-Codable-Unwrapped.json @@ -0,0 +1,105 @@ +{ + "modelStart": "{\n", + "importForEachCustomType": "", + "reservedKeywords": [ + "abstract", + "assert", + "boolean", + "break", + "byte", + "case", + "catch", + "char", + "class", + "const", + "continue", + "default", + "do", + "double", + "else", + "enum", + "extends", + "false", + "final", + "finally", + "float", + "for", + "goto", + "if", + "implements", + "import", + "instanceof", + "int", + "interface", + "long", + "native", + "new", + "null", + "package", + "private", + "protected", + "public", + "return", + "short", + "static", + "strictfp", + "super", + "switch", + "synchronized", + "this", + "throw", + "throws", + "transient", + "true", + "try", + "void", + "volatile", + "while", + "class", + "description" + ], + "booleanGetter": "", + "briefDescription": "Defines how your JSON objects can be mapped to Swift structures using the built-in NSJSONSerialization class", + "utilityMethods": [ + ], + "dataTypes": { + "stringType": "String", + "boolType": "Bool", + "floatType": "Float", + "doubleType": "Double", + "characterType": "Character", + "longType": "Double", + "intType": "Int" + }, + "wordsToRemoveToGetArrayElementsType": [ + "[", + "]" + ], + "constructors": [ + { + "fetchBasicTypeWithSpecialNeedsPropertyFromMap": "", + "bodyStart": "{\n", + "body": "", + "bodyEnd": "\t}\n", + "fetchBasicTypePropertyFromMap": "\t\tcase = \"\"\n", + "signature": "\tenum CodingKeys: String, CodingKey ", + "fetchArrayOfCustomTypePropertyFromMap": "\t\tcase = \"\"\n", + "comment": "", + "fetchCustomTypePropertyFromMap": "\t\tcase \n" + } + ], + "modelDefinition": "\nstruct : Codable ", + "genericType": "AnyObject", + "getter": "", + "setter": "", + "fileExtension": "swift", + "arrayType": "[]", + "basicTypesWithSpecialFetchingNeeds": [ + ], + "displayLangName": "Swift - Struct - Codable - Unwrapped", + "instanceVarDefinition": "\tlet : \n", + "supportsFirstLineStatement": "false", + "modelEnd": "\n}", + "staticImports": "import Foundation", + "langName": "Swift" +} diff --git a/JSONExport/ViewController.swift b/JSONExport/ViewController.swift index 6e55e7a..bd6c0ae 100755 --- a/JSONExport/ViewController.swift +++ b/JSONExport/ViewController.swift @@ -388,7 +388,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl saveButton.isEnabled = false var str = sourceText.string! - if str.characters.count == 0{ + if str.count == 0{ runOnUiThread{ //Nothing to do, just clear any generated files self.files.removeAll(keepingCapacity: false) @@ -397,7 +397,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl return; } var rootClassName = classNameField.stringValue - if rootClassName.characters.count == 0{ + if rootClassName.count == 0{ rootClassName = "RootClass" } sourceText.isEditable = false From 2f8ba428bd660d0360d5e96af2d929ff7c39e644 Mon Sep 17 00:00:00 2001 From: Muhammad Umer Date: Tue, 26 Dec 2017 11:29:29 +0500 Subject: [PATCH 04/24] added back credit file --- JSONExport/FileRepresenter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONExport/FileRepresenter.swift b/JSONExport/FileRepresenter.swift index 96d286f..b26a80e 100755 --- a/JSONExport/FileRepresenter.swift +++ b/JSONExport/FileRepresenter.swift @@ -189,7 +189,7 @@ class FileRepresenter{ fileContent += ". All rights reserved.\n" } - // fileContent += "//\tModel file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport" + fileContent += "//\tModel file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport" if let langAuthor = lang.author{ fileContent += "\n\n//\tThe \"\(lang.displayLangName!)\" support has been made available by \(langAuthor.name!)" From df54d97f7d883ce3794908fa408867abefc0698a Mon Sep 17 00:00:00 2001 From: Ankush Kushwaha Date: Mon, 12 Feb 2018 14:58:27 +0200 Subject: [PATCH 05/24] Change generic type from 'AnyObject' to 'String' -> Fixes #105 In Swift-Struct-Codable format 'decodeIfPresent' cannot produce value of type 'Anyobject'. So changing geberic-type from 'AnyObject'to 'String' for null json values will allow to compile the xcode project Fixes #105 --- JSONExport/Supported Languages/Swift-Codable.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONExport/Supported Languages/Swift-Codable.json b/JSONExport/Supported Languages/Swift-Codable.json index 90592fe..69b11f2 100755 --- a/JSONExport/Supported Languages/Swift-Codable.json +++ b/JSONExport/Supported Languages/Swift-Codable.json @@ -99,7 +99,7 @@ } ], "modelDefinition": "\nstruct : Codable ", - "genericType": "AnyObject", + "genericType": "String", "getter": "", "setter": "", "fileExtension": "swift", From 8528d6a1c6bc572ba9dd01592815e0743f8c02c5 Mon Sep 17 00:00:00 2001 From: Yasuaki Tamura Date: Sat, 3 Mar 2018 16:45:08 +0900 Subject: [PATCH 06/24] Java Gson for Android: Fix method name to be "optString" instead of "opt" to get String type value from JSONObject in constructor. --- .gitignore | 31 +++++++++++++++++++ .../Java-Android Gson.json | 6 ++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index b51e80e..1305bc9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,34 @@ JSONExport.xcodeproj/xcuserdata/ahmed.xcuserdatad/xcdebugger/Breakpoints_v2.xcbk JSONExport.xcodeproj/project.xcworkspace/xcuserdata/ahmedali.xcuserdatad/UserInterfaceState.xcuserstate JSONExport.xcodeproj/xcuserdata/ahmedali.xcuserdatad/xcschemes/JSONExport.xcscheme JSONExport.xcodeproj/xcuserdata/ahmedali.xcuserdatad/xcschemes/xcschememanagement.plist + + +# OS X Finder +.DS_Store +.LSOverride + +# Xcode per-user config +*.mode1 +*.mode1v3 +*.mode2v3 +*.perspective +*.perspectivev3 +*.pbxuser +#*.xcworkspace +xcuserdata + + +# Build products +build/ +*.o +*.LinkFileList +*.hmap + +# Automatic backup files +*~.nib/ +*.swp +*~ +*.dat +*.dep + +Breakpoints.xcbkptlist diff --git a/JSONExport/Supported Languages/Java-Android Gson.json b/JSONExport/Supported Languages/Java-Android Gson.json index ed1e58d..58a9e7b 100755 --- a/JSONExport/Supported Languages/Java-Android Gson.json +++ b/JSONExport/Supported Languages/Java-Android Gson.json @@ -36,8 +36,8 @@ "String" ], "basicTypesWithSpecialFetchingNeedsReplacements" : [ - - "","" + "", + "String" ], "constructors": [ { @@ -66,4 +66,4 @@ "returnStatement": "\t\t} catch (JSONException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn jsonObject;\n" } ] -} \ No newline at end of file +} From 02a96ed98549b42f0544398e77c5eed1c1d2e23a Mon Sep 17 00:00:00 2001 From: Yasuaki Tamura Date: Sat, 3 Mar 2018 18:56:02 +0900 Subject: [PATCH 07/24] Fix: float type issue --- JSONExport/FileRepresenter.swift | 35 ++++++++++++++++++- JSONExport/LangModel.swift | 2 ++ JSONExport/SharedConstants.swift | 1 + .../Java-Android Gson.json | 13 +++++-- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/JSONExport/FileRepresenter.swift b/JSONExport/FileRepresenter.swift index b26a80e..2906259 100755 --- a/JSONExport/FileRepresenter.swift +++ b/JSONExport/FileRepresenter.swift @@ -372,7 +372,18 @@ class FileRepresenter{ if let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.type), let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements?[index]{ propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varTypeReplacement, with: replacement) - + var castString = String() + if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index]{ + // if needs cast + if !cast.isEmpty { + castString = "(\(cast)) " + } + else { + castString = cast + } + } + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varTypeCast, with: castString) + let lowerCaseType = property.type.lowercased() propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: lowerCaseVarType, with: lowerCaseType) @@ -468,6 +479,16 @@ class FileRepresenter{ propertyStr = constructor.fetchArrayOfBasicTypePropertyFromMap let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements[index] propertyStr = propertyStr.replacingOccurrences(of: varTypeReplacement, with: replacement) + + // if needs cast + let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast[index] + if !cast.isEmpty { + propertyStr = propertyStr.replacingOccurrences(of: varTypeCast, with: "(\(cast)) ") + } + else { + propertyStr = propertyStr.replacingOccurrences(of: varTypeCast, with: cast) + } + }else{ propertyStr = constructor.fetchBasicTypePropertyFromMap } @@ -500,6 +521,18 @@ class FileRepresenter{ propertyStr = propertyStr.replacingOccurrences(of: varTypeReplacement, with: replacement) } + var castString = String() + if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index!]{ + // if needs cast + if !cast.isEmpty { + castString = "(\(cast)) " + } + else { + castString = cast + } + } + propertyStr = propertyStr.replacingOccurrences(of: varTypeCast, with: castString) + let lowerCaseType = property.type.lowercased() propertyStr = propertyStr.replacingOccurrences(of: lowerCaseVarType, with: lowerCaseType) diff --git a/JSONExport/LangModel.swift b/JSONExport/LangModel.swift index 46d7504..b78f061 100755 --- a/JSONExport/LangModel.swift +++ b/JSONExport/LangModel.swift @@ -12,6 +12,7 @@ class LangModel{ var arrayType : String! var basicTypesWithSpecialFetchingNeeds : [String]! var basicTypesWithSpecialFetchingNeedsReplacements : [String]! + var basicTypesWithSpecialFetchingNeedsTypeCast : [String]! var basicTypesWithSpecialStoringNeeds : [String]! var booleanGetter : String! var briefDescription : String! @@ -50,6 +51,7 @@ class LangModel{ arrayType = dictionary["arrayType"] as? String basicTypesWithSpecialFetchingNeeds = dictionary["basicTypesWithSpecialFetchingNeeds"] as? [String] basicTypesWithSpecialFetchingNeedsReplacements = dictionary["basicTypesWithSpecialFetchingNeedsReplacements"] as? [String] + basicTypesWithSpecialFetchingNeedsTypeCast = dictionary["basicTypesWithSpecialFetchingNeedsTypeCast"] as? [String] basicTypesWithSpecialStoringNeeds = dictionary["basicTypesWithSpecialStoringNeeds"] as? [String] booleanGetter = dictionary["booleanGetter"] as? String briefDescription = dictionary["briefDescription"] as? String diff --git a/JSONExport/SharedConstants.swift b/JSONExport/SharedConstants.swift index 924e434..83591f7 100755 --- a/JSONExport/SharedConstants.swift +++ b/JSONExport/SharedConstants.swift @@ -39,6 +39,7 @@ let varName = "" let capitalizedVarName = "" let varType = "" let varTypeReplacement = "" +let varTypeCast = "" let capitalizedVarType = "" let lowerCaseVarType = "" let lowerCaseModelName = "" diff --git a/JSONExport/Supported Languages/Java-Android Gson.json b/JSONExport/Supported Languages/Java-Android Gson.json index 58a9e7b..a809019 100755 --- a/JSONExport/Supported Languages/Java-Android Gson.json +++ b/JSONExport/Supported Languages/Java-Android Gson.json @@ -33,11 +33,18 @@ ], "basicTypesWithSpecialFetchingNeeds" : [ "Object", - "String" + "String", + "float" ], "basicTypesWithSpecialFetchingNeedsReplacements" : [ "", - "String" + "String", + "Double" + ], + "basicTypesWithSpecialFetchingNeedsTypeCast" : [ + "", + "", + "float" ], "constructors": [ { @@ -47,7 +54,7 @@ "bodyEnd": "\t}\n", "fetchBasicTypePropertyFromMap": "\t\t = jsonObject.opt(\"\");\n", "fetchArrayOfBasicTypePropertyFromMap" : "\t\tJSONArray Tmp = jsonObject.optJSONArray(\"\");\n\t\tif(Tmp != null){\n\t\t\t = new [Tmp.length()];\n\t\t\tfor(int i = 0; i < Tmp.length(); i++){\n\t\t\t\t[i] = Tmp.get(i);\n\t\t\t}\n\t\t}\n", - "fetchBasicTypeWithSpecialNeedsPropertyFromMap": "\t\t = jsonObject.opt(\"\");\n", + "fetchBasicTypeWithSpecialNeedsPropertyFromMap": "\t\t = jsonObject.opt(\"\");\n", "fetchCustomTypePropertyFromMap": "\t\t = new (jsonObject.optJSONObject(\"\"));\n", "fetchArrayOfCustomTypePropertyFromMap": "\t\tJSONArray JsonArray = jsonObject.optJSONArray(\"\");\n\t\tif(JsonArray != null){\n\t\t\tArrayList<> ArrayList = new ArrayList<>();\n\t\t\tfor (int i = 0; i < JsonArray.length(); i++) {\n\t\t\t\tJSONObject Object = JsonArray.optJSONObject(i);\n\t\t\t\tArrayList.add(new (Object));\n\t\t\t}\n\t\t\t = ([]) ArrayList.toArray();\n\t\t}" } From 4c61a93bc8487a626c8671d2d18fd10adf7283ae Mon Sep 17 00:00:00 2001 From: Brychan Odlum Date: Tue, 2 Oct 2018 00:09:01 -0700 Subject: [PATCH 08/24] Update to Swift 4.2 --- JSONExport.xcodeproj/project.pbxproj | 28 ++++++++-- JSONExport/FileContentBuilder.swift | 2 +- JSONExport/FilePreviewCell.swift | 18 +++---- JSONExport/FileRepresenter.swift | 6 +-- JSONExport/HeaderFileRepresenter.swift | 4 +- JSONExport/StringExtension.swift | 29 +++++----- JSONExport/ViewController.swift | 75 ++++++++++++-------------- 7 files changed, 89 insertions(+), 73 deletions(-) diff --git a/JSONExport.xcodeproj/project.pbxproj b/JSONExport.xcodeproj/project.pbxproj index c4f6227..ab51cdf 100755 --- a/JSONExport.xcodeproj/project.pbxproj +++ b/JSONExport.xcodeproj/project.pbxproj @@ -255,12 +255,12 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Ahmed Ali"; TargetAttributes = { E2FA87B41A059AC100648EB6 = { CreatedOnToolsVersion = 6.1; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -358,14 +358,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -393,6 +401,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; }; name = Debug; }; @@ -404,14 +413,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -432,6 +449,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; }; name = Release; }; @@ -447,7 +465,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "JSONExport/JSONExport-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -462,7 +481,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "ahmed.ali.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "JSONExport/JSONExport-Bridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/JSONExport/FileContentBuilder.swift b/JSONExport/FileContentBuilder.swift index 0f85698..2ff5f7a 100755 --- a/JSONExport/FileContentBuilder.swift +++ b/JSONExport/FileContentBuilder.swift @@ -338,7 +338,7 @@ class FilesContentBuilder{ str = str.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) var output = "" var makeNextCharUpperCase = startFromFirstChar - for char in input.characters{ + for char in input { if char == "_" { makeNextCharUpperCase = true }else if makeNextCharUpperCase{ diff --git a/JSONExport/FilePreviewCell.swift b/JSONExport/FilePreviewCell.swift index e31d04c..fafc686 100755 --- a/JSONExport/FilePreviewCell.swift +++ b/JSONExport/FilePreviewCell.swift @@ -35,14 +35,14 @@ class FilePreviewCell: NSTableCellView, NSTextViewDelegate { } if self.file.includeConstructors{ - self.constructors.state = NSOnState + self.constructors.state = NSControl.StateValue.on }else{ - self.constructors.state = NSOffState + self.constructors.state = NSControl.StateValue.off } if self.file.includeUtilities{ - self.utilities.state = NSOnState + self.utilities.state = NSControl.StateValue.on }else{ - self.utilities.state = NSOffState + self.utilities.state = NSControl.StateValue.off } } }else{ @@ -70,14 +70,14 @@ class FilePreviewCell: NSTableCellView, NSTextViewDelegate { scrollView.hasVerticalRuler = true scrollView.verticalRulerView = lineNumberView scrollView.rulersVisible = true - textView.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize()) + textView.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize) } @IBAction func toggleConstructors(_ sender: NSButtonCell) { if file != nil{ - file.includeConstructors = (sender.state == NSOnState) + file.includeConstructors = (sender.state == NSControl.StateValue.off) textView.string = file.toString() } @@ -86,14 +86,12 @@ class FilePreviewCell: NSTableCellView, NSTextViewDelegate { @IBAction func toggleUtilityMethods(_ sender: NSButtonCell) { if file != nil{ - file.includeUtilities = (sender.state == NSOnState) + file.includeUtilities = (sender.state == NSControl.StateValue.on) textView.string = file.toString() } } func textDidChange(_ notification: Notification) { - file.fileContent = textView.string ?? file.fileContent + file.fileContent = textView.string } - - } diff --git a/JSONExport/FileRepresenter.swift b/JSONExport/FileRepresenter.swift index b26a80e..f2d35d9 100755 --- a/JSONExport/FileRepresenter.swift +++ b/JSONExport/FileRepresenter.swift @@ -101,7 +101,7 @@ class FileRepresenter{ appendCustomImports() //start the model defination var definition = "" - if lang.modelDefinitionWithParent != nil && parentClassName.characters.count > 0{ + if lang.modelDefinitionWithParent != nil && parentClassName.count > 0{ definition = lang.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: parentClassName) }else if includeUtilities && lang.defaultParentWithUtilityMethods != nil{ @@ -129,7 +129,7 @@ class FileRepresenter{ */ func appendFirstLineStatement() { - if lang.supportsFirstLineStatement != nil && lang.supportsFirstLineStatement! && firstLine.characters.count > 0{ + if lang.supportsFirstLineStatement != nil && lang.supportsFirstLineStatement! && firstLine.count > 0{ fileContent += "\(firstLine)\n\n" } } @@ -419,7 +419,7 @@ class FileRepresenter{ type = type.replacingOccurrences(of: arrayWord, with: "") } - if type.characters.count == 0{ + if type.count == 0{ type = typeNameForArrayElements(property.sampleValue as! NSArray, lang: lang) } return type diff --git a/JSONExport/HeaderFileRepresenter.swift b/JSONExport/HeaderFileRepresenter.swift index c819679..961373c 100755 --- a/JSONExport/HeaderFileRepresenter.swift +++ b/JSONExport/HeaderFileRepresenter.swift @@ -46,7 +46,7 @@ class HeaderFileRepresenter : FileRepresenter{ //start the model defination var definition = "" - if lang.headerFileData.modelDefinitionWithParent != nil && parentClassName.characters.count > 0{ + if lang.headerFileData.modelDefinitionWithParent != nil && parentClassName.count > 0{ definition = lang.headerFileData.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: parentClassName) }else if includeUtilities && lang.defaultParentWithUtilityMethods != nil{ @@ -82,7 +82,7 @@ class HeaderFileRepresenter : FileRepresenter{ func appendImportParentHeader() { - if lang.headerFileData.importParentHeaderFile != nil && parentClassName.characters.count > 0{ + if lang.headerFileData.importParentHeaderFile != nil && parentClassName.count > 0{ fileContent += lang.headerFileData.importParentHeaderFile.replacingOccurrences(of: modelWithParentClassName, with: parentClassName) } } diff --git a/JSONExport/StringExtension.swift b/JSONExport/StringExtension.swift index e06b22f..6a3e5ca 100755 --- a/JSONExport/StringExtension.swift +++ b/JSONExport/StringExtension.swift @@ -40,20 +40,21 @@ extension String{ func toSingular() -> String { var singular = self - let length = self.characters.count - if length > 3{ - let range = Range(characters.index(endIndex, offsetBy: -3) ..< endIndex) + let length = self.count + if length > 3 { + let range = self.index(self.endIndex, offsetBy: -3).. 2{ - let range = Range(characters.index(endIndex, offsetBy: -1) ..< endIndex) - let lastChar = self.substring(with: range) + if length > 2 { + let range = self.index(self.endIndex, offsetBy: -1).. String{ - if self.characters.count > 0{ - let range = Range(startIndex ..< characters.index(startIndex, offsetBy: 1)) - let firstLowerChar = self.substring(with: range).lowercased() + if self.count > 0 { + let range = self.startIndex.. String{ - if self.characters.count > 0{ - let range = Range(startIndex ..< characters.index(startIndex, offsetBy: 1)) - let firstUpperChar = self.substring(with: range).uppercased() + if self.count > 0 { + let range = startIndex.. Void in - if button == NSFileHandlingPanelOKButton{ - - let jsonPath = oPanel.urls.first!.path - let fileHandle = FileHandle(forReadingAtPath: jsonPath) - let urlStr:String = oPanel.urls.first!.lastPathComponent - self.classNameField.stringValue = urlStr.replacingOccurrences(of: ".json", with: "") - self.parseJSONData(jsonData: (fileHandle!.readDataToEndOfFile() as NSData!) as Data!) - - } - }) - } + @IBAction func openJSONFiles(sender: AnyObject) + { + let oPanel: NSOpenPanel = NSOpenPanel() + oPanel.canChooseDirectories = false + oPanel.canChooseFiles = true + oPanel.allowsMultipleSelection = false + oPanel.allowedFileTypes = ["json","JSON"] + oPanel.prompt = "Choose JSON file" + + oPanel.beginSheetModal(for: self.view.window!) { button in + if button.rawValue == NSFileHandlingPanelOKButton { + let jsonPath = oPanel.urls.first!.path + let fileHandle = FileHandle(forReadingAtPath: jsonPath) + let urlStr:String = oPanel.urls.first!.lastPathComponent + self.classNameField.stringValue = urlStr.replacingOccurrences(of: ".json", with: "") + self.parseJSONData(jsonData: (fileHandle!.readDataToEndOfFile())) + } + } + } @IBAction func toggleConstructors(_ sender: AnyObject) @@ -286,14 +284,12 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl openPanel.canChooseDirectories = true openPanel.canCreateDirectories = true openPanel.prompt = "Choose" - openPanel.beginSheetModal(for: self.view.window!, completionHandler: { (button : Int) -> Void in - if button == NSFileHandlingPanelOKButton{ - - self.saveToPath(openPanel.url!.path) - - self.showDoneSuccessfully() - } - }) + openPanel.beginSheetModal(for: self.view.window!){ button in + if button.rawValue == NSFileHandlingPanelOKButton{ + self.saveToPath(openPanel.url!.path) + self.showDoneSuccessfully() + } + } } @@ -386,9 +382,9 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl func generateClasses() { saveButton.isEnabled = false - var str = sourceText.string! + var str = sourceText.string - if str.characters.count == 0{ + if str.count == 0{ runOnUiThread{ //Nothing to do, just clear any generated files self.files.removeAll(keepingCapacity: false) @@ -397,7 +393,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl return; } var rootClassName = classNameField.stringValue - if rootClassName.characters.count == 0{ + if rootClassName.count == 0{ rootClassName = "RootClass" } sourceText.isEditable = false @@ -411,7 +407,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl var json : NSDictionary! if jsonData is NSDictionary{ //fine nothing to do - json = jsonData as! NSDictionary + json = jsonData as? NSDictionary }else{ json = unionDictionaryFromArrayElements(jsonData as! NSArray) } @@ -455,8 +451,8 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl func prepareAndGetFilesBuilder() -> FilesContentBuilder { let filesBuilder = FilesContentBuilder.instance - filesBuilder.includeConstructors = (generateConstructors.state == NSOnState) - filesBuilder.includeUtilities = (generateUtilityMethods.state == NSOnState) + filesBuilder.includeConstructors = (generateConstructors.state == NSControl.StateValue.on) + filesBuilder.includeUtilities = (generateUtilityMethods.state == NSControl.StateValue.on) filesBuilder.firstLine = firstLineField.stringValue filesBuilder.lang = selectedLang! filesBuilder.classPrefix = classPrefixField.stringValue @@ -477,7 +473,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl //MARK: - NSTableViewDelegate func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - let cell = tableView.make(withIdentifier: "fileCell", owner: self) as! FilePreviewCell + let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier("fileCell"), owner: self) as! FilePreviewCell let file = files[row] cell.file = file @@ -487,4 +483,3 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } - From 0a3d17f8e4071ad973552db0e8fa08350efeaae4 Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 21:57:04 +0000 Subject: [PATCH 09/24] Updating GHANGELOG.md for release 1.0.9 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ee3cca..e0089b1 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +* Version 1.0.9 +- Merged PR #88 : Fix minor typo in the README.MD file. Thanks to @AlexxNica +- Merged PR #93 Changed app icon and fix upside down text. Thanks to @narlei +- Merged PR #96 Adding support for Swift 4 Codable. Thanks to @kashifshaikh + * Version 1.0.8 - Merged PR #72 App now remembers what language user selected last time. Thanks to @TParizek - Merged PR #75 Fix Error for Swift in Xcode 8.2.1 and replace NSDictionary. Thanks to @dimohamdy From 30d87853a861327d3bd85cb7ec225bbcff8b8e13 Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 22:02:30 +0000 Subject: [PATCH 10/24] Updating CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0089b1..b9a6ac1 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +* Version 1.1.0 +- Merged PR #98 : fix a complier error in SwiftyJSON - Class. Thanks to @superk589 + + * Version 1.0.9 - Merged PR #88 : Fix minor typo in the README.MD file. Thanks to @AlexxNica - Merged PR #93 Changed app icon and fix upside down text. Thanks to @narlei From c20cabb86f2d0bdcdd188169bb8e912950defe24 Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 22:04:59 +0000 Subject: [PATCH 11/24] Updating CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9a6ac1..67ab5ba 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ * Version 1.1.0 -- Merged PR #98 : fix a complier error in SwiftyJSON - Class. Thanks to @superk589 +- Merged PR #98 : fix a complier error in SwiftyJSON - Class. Thanks @superk589 +- Merged PR #99 : Migrate to Swift 4. Thanks @serhii-londar * Version 1.0.9 From 9ca6bdc098080b587d5a63d79ed18aa38e25e57e Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 22:08:04 +0000 Subject: [PATCH 12/24] Updating CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67ab5ba..813a2fb 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ * Version 1.1.0 - Merged PR #98 : fix a complier error in SwiftyJSON - Class. Thanks @superk589 - Merged PR #99 : Migrate to Swift 4. Thanks @serhii-londar +- Merged PR #101 Added Codable Option to make Codable Structs with forced up-wrapped properties. Thanks @mumer92 * Version 1.0.9 From 0c5bd0d10caee3504ac5acc9c0e97cd32a25672b Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 22:22:12 +0000 Subject: [PATCH 13/24] Updating CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 813a2fb..6c0ca8c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ * Version 1.1.0 - Merged PR #98 : fix a complier error in SwiftyJSON - Class. Thanks @superk589 - Merged PR #99 : Migrate to Swift 4. Thanks @serhii-londar -- Merged PR #101 Added Codable Option to make Codable Structs with forced up-wrapped properties. Thanks @mumer92 +- Merged PR #101 : Added Codable Option to make Codable Structs with forced up-wrapped properties. Thanks @mumer92 +- Merged PR #106 : Fix Xcode build-time error : Change generic type from 'AnyObject' to 'String' -> Fixes #105. Thanks @ankushkushwaha * Version 1.0.9 From 1e806c9bd085a97fa5bbd8117e1a5c79f37749f8 Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 22:36:31 +0000 Subject: [PATCH 14/24] Updating CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c0ca8c..8f7e18c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Merged PR #99 : Migrate to Swift 4. Thanks @serhii-londar - Merged PR #101 : Added Codable Option to make Codable Structs with forced up-wrapped properties. Thanks @mumer92 - Merged PR #106 : Fix Xcode build-time error : Change generic type from 'AnyObject' to 'String' -> Fixes #105. Thanks @ankushkushwaha +- Merged PR #108 : Java Gson for Android: Fix method name. Thanks @ty0521-fss * Version 1.0.9 From 87f71cbad541e8cbffdd63a0280dca005312650c Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 22:57:41 +0000 Subject: [PATCH 15/24] Updating CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f7e18c..afd70dd 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Merged PR #101 : Added Codable Option to make Codable Structs with forced up-wrapped properties. Thanks @mumer92 - Merged PR #106 : Fix Xcode build-time error : Change generic type from 'AnyObject' to 'String' -> Fixes #105. Thanks @ankushkushwaha - Merged PR #108 : Java Gson for Android: Fix method name. Thanks @ty0521-fss +- Merged PR #123 : Update to Swift 4.2. Thanks @BrychanOdlum * Version 1.0.9 From a507ecff251f17fa73e6822d936012443ee83c47 Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 23:00:58 +0000 Subject: [PATCH 16/24] Fixing the project file --- JSONExport.xcodeproj/project.pbxproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/JSONExport.xcodeproj/project.pbxproj b/JSONExport.xcodeproj/project.pbxproj index dc0f20c..ab51cdf 100755 --- a/JSONExport.xcodeproj/project.pbxproj +++ b/JSONExport.xcodeproj/project.pbxproj @@ -465,12 +465,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "JSONExport/JSONExport-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; -<<<<<<< HEAD - SWIFT_VERSION = 4.0; -======= SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.2; ->>>>>>> 4c61a93bc8487a626c8671d2d18fd10adf7283ae }; name = Debug; }; @@ -485,12 +481,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "ahmed.ali.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "JSONExport/JSONExport-Bridging-Header.h"; -<<<<<<< HEAD - SWIFT_VERSION = 4.0; -======= SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.2; ->>>>>>> 4c61a93bc8487a626c8671d2d18fd10adf7283ae }; name = Release; }; From db500f576c636d6a6941b1818782bc1c514a732e Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 23:08:17 +0000 Subject: [PATCH 17/24] Updating CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index afd70dd..cfbd7e5 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Merged PR #101 : Added Codable Option to make Codable Structs with forced up-wrapped properties. Thanks @mumer92 - Merged PR #106 : Fix Xcode build-time error : Change generic type from 'AnyObject' to 'String' -> Fixes #105. Thanks @ankushkushwaha - Merged PR #108 : Java Gson for Android: Fix method name. Thanks @ty0521-fss +- Merged PR #119 : Suuport for Outlaw. Thanks @LifetimeCode - Merged PR #123 : Update to Swift 4.2. Thanks @BrychanOdlum From 47a897ea413e5212d01c634e4ffa66399dd7c032 Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 23:32:20 +0000 Subject: [PATCH 18/24] Adding Outlaw JSON file to the project as the merge conflicts caused this to not to merge correctly --- JSONExport.xcodeproj/project.pbxproj | 8 + .../Supported Languages/Swift-Outlaw.json | 138 ++++++++++++++++++ JSONExport/ViewController.swift | 15 +- 3 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 JSONExport/Supported Languages/Swift-Outlaw.json diff --git a/JSONExport.xcodeproj/project.pbxproj b/JSONExport.xcodeproj/project.pbxproj index ab51cdf..8b7491f 100755 --- a/JSONExport.xcodeproj/project.pbxproj +++ b/JSONExport.xcodeproj/project.pbxproj @@ -30,6 +30,8 @@ E2197C5D1A0EAEB900549D03 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2197C5C1A0EAEB900549D03 /* StringExtension.swift */; }; E22BA2C51A162B54005CE143 /* FileContentBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22BA2C41A162B54005CE143 /* FileContentBuilder.swift */; }; E230BA2C1A113F8C00AE2054 /* FilePreviewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E230BA2B1A113F8C00AE2054 /* FilePreviewCell.swift */; }; + E24E443221AA12B800435FE7 /* Swift-Outlaw.json in Resources */ = {isa = PBXBuildFile; fileRef = E24E443021AA12B800435FE7 /* Swift-Outlaw.json */; }; + E24E443321AA12B800435FE7 /* Swift3-Mappable.json in Resources */ = {isa = PBXBuildFile; fileRef = E24E443121AA12B800435FE7 /* Swift3-Mappable.json */; }; E278F9C61A2149AC00306EFC /* HeaderFileData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E278F9C51A2149AC00306EFC /* HeaderFileData.swift */; }; E278F9CA1A2152D800306EFC /* HeaderFileRepresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E278F9C91A2152D800306EFC /* HeaderFileRepresenter.swift */; }; E28631521A158CFA0041B178 /* Constructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E286314E1A158CFA0041B178 /* Constructor.swift */; }; @@ -72,6 +74,8 @@ E2197C5C1A0EAEB900549D03 /* StringExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; E22BA2C41A162B54005CE143 /* FileContentBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileContentBuilder.swift; sourceTree = ""; }; E230BA2B1A113F8C00AE2054 /* FilePreviewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilePreviewCell.swift; sourceTree = ""; }; + E24E443021AA12B800435FE7 /* Swift-Outlaw.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "Swift-Outlaw.json"; path = "Supported Languages/Swift-Outlaw.json"; sourceTree = ""; }; + E24E443121AA12B800435FE7 /* Swift3-Mappable.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "Swift3-Mappable.json"; path = "Supported Languages/Swift3-Mappable.json"; sourceTree = ""; }; E278F9C51A2149AC00306EFC /* HeaderFileData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderFileData.swift; sourceTree = ""; }; E278F9C91A2152D800306EFC /* HeaderFileRepresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderFileRepresenter.swift; sourceTree = ""; }; E286314E1A158CFA0041B178 /* Constructor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constructor.swift; sourceTree = ""; }; @@ -153,6 +157,8 @@ E2F07E8A1A0B3192004A1DAA /* Supported Languages */ = { isa = PBXGroup; children = ( + E24E443021AA12B800435FE7 /* Swift-Outlaw.json */, + E24E443121AA12B800435FE7 /* Swift3-Mappable.json */, 166AF5CD1CEF6C3600516EDD /* Swift-Struct-Gloss.json */, 60FB8FFA1B9B3F6400290979 /* ObjectiveC-Realm.json */, A329A7EC1D5DA1ED00FB59E8 /* Java-Android Gson.json */, @@ -294,6 +300,7 @@ 60FB8FF31B9B361600290979 /* ObjectiveC-iOS.json in Resources */, 60FB8FFC1B9B3F6400290979 /* ObjectiveC-Realm.json in Resources */, 60FB8FF11B9B361600290979 /* Java-Android.json in Resources */, + E24E443321AA12B800435FE7 /* Swift3-Mappable.json in Resources */, 60FB8FF81B9B361600290979 /* Swift-Struct.json in Resources */, E2FA87BF1A059AC100648EB6 /* Images.xcassets in Resources */, 98978FC11D5B6B19000C1846 /* Swift-Struct-Unbox.json in Resources */, @@ -303,6 +310,7 @@ 60FB8FF91B9B361600290979 /* SwiftyJSON-Class.json in Resources */, 60FB8FF21B9B361600290979 /* ObjectiveC-CoreData-iOS.json in Resources */, E2FA87C21A059AC100648EB6 /* Main.storyboard in Resources */, + E24E443221AA12B800435FE7 /* Swift-Outlaw.json in Resources */, 166AF5CE1CEF6C3600516EDD /* Swift-Struct-Gloss.json in Resources */, 60FB8FF41B9B361600290979 /* ObjectiveC-Mac.json in Resources */, ); diff --git a/JSONExport/Supported Languages/Swift-Outlaw.json b/JSONExport/Supported Languages/Swift-Outlaw.json new file mode 100644 index 0000000..cbb27d3 --- /dev/null +++ b/JSONExport/Supported Languages/Swift-Outlaw.json @@ -0,0 +1,138 @@ +{ + "modelStart": "{\n", + "importForEachCustomType": "", + "reservedKeywords": [ + "abstract", + "assert", + "boolean", + "break", + "byte", + "case", + "catch", + "char", + "class", + "const", + "continue", + "default", + "do", + "double", + "else", + "enum", + "extends", + "false", + "final", + "finally", + "float", + "for", + "goto", + "if", + "implements", + "import", + "instanceof", + "int", + "interface", + "long", + "native", + "new", + "null", + "package", + "private", + "protected", + "public", + "return", + "short", + "static", + "strictfp", + "super", + "switch", + "synchronized", + "this", + "throw", + "throws", + "transient", + "true", + "try", + "void", + "volatile", + "while", + "class", + "description" + ], + "booleanGetter": "", + "briefDescription": "Defines how your JSON objects can be mapped to Swift classes using the built-in NSJSONSerialization class", + "utilityMethods": [ + { + "forEachProperty": "\t\tif != nil{\n\t\t\tdictionary[\"\"] = \n\t\t}\n", + "bodyEnd": "\t}\n", + "signature": "\tfunc serialized() -> [String:Any]", + "forEachCustomTypeProperty": "\t\tif != nil{\n\t\t\tdictionary[\"\"] = !.serialized()\n\t\t}\n", + "forEachArrayOfCustomTypeProperty": "\t\tif != nil{\n\t\t\tvar dictionaryElements = [[String:Any]]()\n\t\t\tfor Element in ! {\n\t\t\t\tdictionaryElements.append(Element.serialized())\n\t\t\t}\n\t\t\tdictionary[\"\"] = dictionaryElements\n\t\t}\n", + "returnStatement": "\t\treturn dictionary\n", + "body": "\t\tvar dictionary = [String:Any]()\n", + "comment": "\t/**\n\t * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property\n\t */\n", + "bodyStart": "\n\t{\n" + }, + { + "forEachProperty": " = aDecoder.decodeObject(forKey: \"\") as? \n", + "bodyEnd": "\n\t}\n", + "signature": " @objc required init(coder aDecoder: NSCoder)", + "forEachCustomTypeProperty": " = aDecoder.decodeObject(forKey: \"\") as? \n", + "forEachArrayOfCustomTypeProperty": " = aDecoder.decodeObject(forKey :\"\") as? \n", + "returnStatement": "", + "body": "", + "comment": "\n /**\n * NSCoding required initializer.\n * Fills the data from the passed decoder\n */\n", + "bodyStart": "\n\t{\n" + }, + { + "forEachProperty": "\t\tif != nil{\n\t\t\taCoder.encode(, forKey: \"\")\n\t\t}\n", + "bodyEnd": "\n\t}\n", + "signature": " @objc func encode(with aCoder: NSCoder)", + "forEachCustomTypeProperty": "\t\tif != nil{\n\t\t\taCoder.encode(, forKey: \"\")\n\t\t}\n", + "forEachArrayOfCustomTypeProperty": "\t\tif != nil{\n\t\t\taCoder.encode(, forKey: \"\")\n\t\t}\n", + "returnStatement": "", + "body": "", + "comment": "\n /**\n * NSCoding required method.\n * Encodes mode properties into the decoder\n */\n", + "bodyStart": "\n\t{\n" + } + ], + "dataTypes": { + "stringType": "String", + "boolType": "Bool", + "floatType": "Float", + "doubleType": "Double", + "characterType": "Character", + "longType": "Double", + "intType": "Int" + }, + "wordsToRemoveToGetArrayElementsType": [ + "[", + "]" + ], + "defaultParentWithUtilityMethods": "NSObject, DataObject", + "constructors": [ + { + "fetchBasicTypeWithSpecialNeedsPropertyFromMap": "", + "fetchCustomTypePropertyFromMap": "\t\tif let Data = object.optionalAny(for: \"\") as? [String:Any]{\n\t\t\t = try (object: Data)\n\t\t}\n", + "bodyEnd": "\t}\n", + "fetchBasicTypePropertyFromMap": "\t\t = object.value(for: \"\")\n", + "signature": "\trequired init(object: Extractable) throws", + "fetchArrayOfCustomTypePropertyFromMap": "\t\t = ()\n\t\tif let Array = object.optionalAny(for: \"\") as? [[String:Any]]{\n\t\t\tfor dic in Array{\n\t\t\t\tlet value = try (object: dic)\n\t\t\t\t!.append(value)\n\t\t\t}\n\t\t}\n", + "comment": "\t/**\n\t * Instantiate the instance using the passed dictionary values to set the properties values\n\t */\n", + "bodyStart": "{\n" + } + ], + "modelDefinition": "\nclass ", + "genericType": "AnyObject", + "getter": "", + "setter": "", + "displayLangName": "Swift - Outlaw", + "fileExtension": "swift", + "basicTypesWithSpecialFetchingNeeds": [], + "arrayType": "[]", + "modelDefinitionWithParent": "\n\nclass : ", + "instanceVarDefinition": "\tvar : ?\n", + "supportsFirstLineStatement": "false", + "modelEnd": "\n}", + "staticImports": "import Foundation\nimport Outlaw", + "langName": "Swift" +} \ No newline at end of file diff --git a/JSONExport/ViewController.swift b/JSONExport/ViewController.swift index e947b0d..64d4e98 100755 --- a/JSONExport/ViewController.swift +++ b/JSONExport/ViewController.swift @@ -76,8 +76,10 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl var selectedLang : LangModel! //Returns the title of the selected language in the languagesPopup + //Call only from main thread var selectedLanguageName : String { + assert(Thread.isMainThread); return languagesPopup.titleOfSelectedItem! } @@ -242,7 +244,10 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl { updateUIFieldsForSelectedLanguage() generateClasses() - UserDefaults.standard.set(selectedLanguageName, forKey: "selectedLanguage") + DispatchQueue.main.async { + UserDefaults.standard.set(self.selectedLanguageName, forKey: "selectedLanguage") + } + } @@ -261,8 +266,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl //MARK: - Language selection handling func loadSelectedLanguageModel() { - selectedLang = langs[selectedLanguageName] - + selectedLang = langs[self.selectedLanguageName] } @@ -411,9 +415,10 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl }else{ json = unionDictionaryFromArrayElements(jsonData as! NSArray) } - self.loadSelectedLanguageModel() - self.files.removeAll(keepingCapacity: false) + runOnUiThread{ + self.loadSelectedLanguageModel() + self.files.removeAll(keepingCapacity: false) let fileGenerator = self.prepareAndGetFilesBuilder() fileGenerator.addFileWithName(&rootClassName, jsonObject: json, files: &self.files) fileGenerator.fixReferenceMismatches(inFiles: self.files) From a0ec4941a9c27d095150071578434cb9ed57340b Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 23:36:12 +0000 Subject: [PATCH 19/24] nit: removing empty line --- JSONExport/ViewController.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/JSONExport/ViewController.swift b/JSONExport/ViewController.swift index 64d4e98..08f0159 100755 --- a/JSONExport/ViewController.swift +++ b/JSONExport/ViewController.swift @@ -159,7 +159,6 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } } - //MARK: - Handling pre defined languages func loadSupportedLanguages() { From 50e3f93ae08089851bd5f46c3b8a03b036c461d0 Mon Sep 17 00:00:00 2001 From: Ahmed Ali Date: Sat, 24 Nov 2018 23:41:21 +0000 Subject: [PATCH 20/24] Fixed an issue with trying to figure the selected language from an UI element outside the UI thread --- CHANGELOG.md | 1 + JSONExport/ViewController.swift | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfbd7e5..d772ebe 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Merged PR #108 : Java Gson for Android: Fix method name. Thanks @ty0521-fss - Merged PR #119 : Suuport for Outlaw. Thanks @LifetimeCode - Merged PR #123 : Update to Swift 4.2. Thanks @BrychanOdlum +- Fixed an issue with trying to figure the selected language from an UI element outside the UI thread * Version 1.0.9 diff --git a/JSONExport/ViewController.swift b/JSONExport/ViewController.swift index 08f0159..c81166e 100755 --- a/JSONExport/ViewController.swift +++ b/JSONExport/ViewController.swift @@ -171,15 +171,10 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } langs[lang.displayLangName] = lang } - - } } - } - - - + // MARK: - parse the json file func parseJSONData(jsonData: Data!) From fe313c0ee644983bd2b9afb0ff83f1ea1ad94a98 Mon Sep 17 00:00:00 2001 From: hb Date: Fri, 6 Sep 2019 12:43:07 +0800 Subject: [PATCH 21/24] fixed: update the color under Dark Mode --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ JSONExport/ViewController.swift | 1 + 2 files changed, 9 insertions(+) create mode 100644 JSONExport.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/JSONExport.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/JSONExport.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/JSONExport.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/JSONExport/ViewController.swift b/JSONExport/ViewController.swift index c81166e..fe87634 100755 --- a/JSONExport/ViewController.swift +++ b/JSONExport/ViewController.swift @@ -98,6 +98,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl setLanguagesSelection() loadLastSelectedLanguage() updateUIFieldsForSelectedLanguage() + self.tableView.backgroundColor = .clear } /** From 1545cbeb6a503eea69846864ad720fcfe85648df Mon Sep 17 00:00:00 2001 From: PawanJoshi Date: Tue, 24 Dec 2019 09:20:43 +0530 Subject: [PATCH 22/24] Changed code in swift codable so that if any key value pair is not found in json, it will make the property nil. instead of failing to create an object. also. its will print which object has not been found on console. --- JSONExport/Supported Languages/Swift-Codable.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/JSONExport/Supported Languages/Swift-Codable.json b/JSONExport/Supported Languages/Swift-Codable.json index 69b11f2..6a3ed7c 100755 --- a/JSONExport/Supported Languages/Swift-Codable.json +++ b/JSONExport/Supported Languages/Swift-Codable.json @@ -89,13 +89,13 @@ }, { "fetchBasicTypeWithSpecialNeedsPropertyFromMap": "", - "bodyStart": "{\n\t\tlet values = try decoder.container(keyedBy: CodingKeys.self)\n", + "bodyStart": "{\n\t\tguard let values = try? decoder.container(keyedBy: CodingKeys.self) else {\n\t\t\tprint(\"Could not decode coding key container for \")\n\t\t\treturn\n\t\t}\n", "bodyEnd": "\t}\n", - "fetchBasicTypePropertyFromMap": "\t\t = try values.decodeIfPresent(.self, forKey: .)\n", - "signature": "\tinit(from decoder: Decoder) throws ", - "fetchArrayOfCustomTypePropertyFromMap": "\t\t = try values.decodeIfPresent(.self, forKey: .)\n", + "fetchBasicTypePropertyFromMap": "\t\tdo { = try values.decodeIfPresent(.self, forKey: .) } catch {\n\t\t\tprint(\"error in parsing . ---- \",error.localizedDescription)\n\t\t}\n", + "signature": "\tinit(from decoder: Decoder)", + "fetchArrayOfCustomTypePropertyFromMap": "\t\tdo { = try values.decodeIfPresent(.self, forKey: .) } catch {\n\t\t\tprint(\"error in parsing . ---- \",error.localizedDescription)\n\t\t}\n", "comment": "", - "fetchCustomTypePropertyFromMap": "\t\t = try (from: decoder)\n" + "fetchCustomTypePropertyFromMap": "\t\tdo { = try values.decodeIfPresent(.self, forKey: .)} catch {\n\t\t\t = (from: DictionaryDecoder())\n\t\t\tprint(\"error in parsing . ---- \",error.localizedDescription)\n\t\t}\n" } ], "modelDefinition": "\nstruct : Codable ", @@ -107,7 +107,7 @@ "basicTypesWithSpecialFetchingNeeds": [ ], "displayLangName": "Swift - Struct - Codable", - "instanceVarDefinition": "\tlet : ?\n", + "instanceVarDefinition": "\tvar : ?\n", "supportsFirstLineStatement": "false", "modelEnd": "\n}", "staticImports": "import Foundation", From 427f41a31b212511ab7be20ddfdb9d692c2db35f Mon Sep 17 00:00:00 2001 From: PawanJoshi Date: Tue, 24 Dec 2019 09:29:33 +0530 Subject: [PATCH 23/24] swift formatted --- JSONExport/AppDelegate.swift | 10 +- JSONExport/Author.swift | 43 +-- JSONExport/Constructor.swift | 52 ++- JSONExport/DataType.swift | 102 +++--- JSONExport/FileContentBuilder.swift | 398 ++++++++++---------- JSONExport/FilePreviewCell.swift | 62 ++-- JSONExport/FileRepresenter.swift | 478 +++++++++++-------------- JSONExport/HeaderFileData.swift | 46 ++- JSONExport/HeaderFileRepresenter.swift | 144 ++++---- JSONExport/LangModel.swift | 166 +++++---- JSONExport/Property.swift | 151 ++++---- JSONExport/SharedConstants.swift | 1 - JSONExport/SharedUtilityMethods.swift | 171 ++++----- JSONExport/StringExtension.swift | 76 ++-- JSONExport/UtilityMethod.swift | 57 ++- JSONExport/ViewController.swift | 436 ++++++++++------------ 16 files changed, 1095 insertions(+), 1298 deletions(-) diff --git a/JSONExport/AppDelegate.swift b/JSONExport/AppDelegate.swift index 3c5e3de..566a90a 100755 --- a/JSONExport/AppDelegate.swift +++ b/JSONExport/AppDelegate.swift @@ -34,17 +34,11 @@ import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - - - - func applicationDidFinishLaunching(_ aNotification: Notification) { + func applicationDidFinishLaunching(_: Notification) { // Insert code here to initialize your application } - func applicationWillTerminate(_ aNotification: Notification) { + func applicationWillTerminate(_: Notification) { // Insert code here to tear down your application } - - } - diff --git a/JSONExport/Author.swift b/JSONExport/Author.swift index 9101b20..7837e43 100755 --- a/JSONExport/Author.swift +++ b/JSONExport/Author.swift @@ -7,69 +7,60 @@ import Foundation +class Author: NSObject, NSCoding { + var website: String! + var email: String! + var name: String! -class Author : NSObject, NSCoding{ - - var website : String! - var email : String! - var name : String! - - /** * Instantiate the instance using the passed dictionary values to set the properties values */ - init(fromDictionary dictionary: NSDictionary){ + init(fromDictionary dictionary: NSDictionary) { website = dictionary["website"] as? String email = dictionary["email"] as? String name = dictionary["name"] as? String } - + /** * Returns all the available property values in the form of NSDictionary object where the key is the approperiate json key and the value is the value of the corresponding property */ - func toDictionary() -> NSDictionary - { + func toDictionary() -> NSDictionary { let dictionary = NSMutableDictionary() - if website != nil{ + if website != nil { dictionary["website"] = website } - if email != nil{ + if email != nil { dictionary["email"] = email } - if name != nil{ + if name != nil { dictionary["name"] = name } return dictionary } - + /** * NSCoding required initializer. * Fills the data from the passed decoder */ - @objc required init(coder aDecoder: NSCoder) - { + @objc required init(coder aDecoder: NSCoder) { website = aDecoder.decodeObject(forKey: "website") as? String email = aDecoder.decodeObject(forKey: "email") as? String name = aDecoder.decodeObject(forKey: "name") as? String - } - + /** * NSCoding required method. * Encodes mode properties into the decoder */ - @objc func encode(with aCoder: NSCoder) - { - if website != nil{ + @objc func encode(with aCoder: NSCoder) { + if website != nil { aCoder.encode(website, forKey: "website") } - if email != nil{ + if email != nil { aCoder.encode(email, forKey: "email") } - if name != nil{ + if name != nil { aCoder.encode(name, forKey: "name") } - } - } diff --git a/JSONExport/Constructor.swift b/JSONExport/Constructor.swift index 194903f..b45be55 100755 --- a/JSONExport/Constructor.swift +++ b/JSONExport/Constructor.swift @@ -7,33 +7,29 @@ import Foundation -class Constructor{ +class Constructor { + var bodyEnd: String! + var bodyStart: String! + var comment: String! + var fetchArrayOfCustomTypePropertyFromMap: String! + var fetchArrayOfBasicTypePropertyFromMap: String! + var fetchBasicTypePropertyFromMap: String! + var fetchBasicTypeWithSpecialNeedsPropertyFromMap: String! + var fetchCustomTypePropertyFromMap: String! + var signature: String! - var bodyEnd : String! - var bodyStart : String! - var comment : String! - var fetchArrayOfCustomTypePropertyFromMap : String! - var fetchArrayOfBasicTypePropertyFromMap : String! - var fetchBasicTypePropertyFromMap : String! - var fetchBasicTypeWithSpecialNeedsPropertyFromMap : String! - var fetchCustomTypePropertyFromMap : String! - var signature : String! - - - /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary){ - bodyEnd = dictionary["bodyEnd"] as? String - bodyStart = dictionary["bodyStart"] as? String - comment = dictionary["comment"] as? String - fetchArrayOfCustomTypePropertyFromMap = dictionary["fetchArrayOfCustomTypePropertyFromMap"] as? String + /** + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary) { + bodyEnd = dictionary["bodyEnd"] as? String + bodyStart = dictionary["bodyStart"] as? String + comment = dictionary["comment"] as? String + fetchArrayOfCustomTypePropertyFromMap = dictionary["fetchArrayOfCustomTypePropertyFromMap"] as? String fetchArrayOfBasicTypePropertyFromMap = dictionary["fetchArrayOfBasicTypePropertyFromMap"] as? String - fetchBasicTypePropertyFromMap = dictionary["fetchBasicTypePropertyFromMap"] as? String - fetchBasicTypeWithSpecialNeedsPropertyFromMap = dictionary["fetchBasicTypeWithSpecialNeedsPropertyFromMap"] as? String - fetchCustomTypePropertyFromMap = dictionary["fetchCustomTypePropertyFromMap"] as? String - signature = dictionary["signature"] as? String - } - - -} \ No newline at end of file + fetchBasicTypePropertyFromMap = dictionary["fetchBasicTypePropertyFromMap"] as? String + fetchBasicTypeWithSpecialNeedsPropertyFromMap = dictionary["fetchBasicTypeWithSpecialNeedsPropertyFromMap"] as? String + fetchCustomTypePropertyFromMap = dictionary["fetchCustomTypePropertyFromMap"] as? String + signature = dictionary["signature"] as? String + } +} diff --git a/JSONExport/DataType.swift b/JSONExport/DataType.swift index 6d6f75e..7398ee2 100755 --- a/JSONExport/DataType.swift +++ b/JSONExport/DataType.swift @@ -7,58 +7,54 @@ import Foundation -class DataType{ +class DataType { + var boolType: String! + var characterType: String! + var doubleType: String! + var floatType: String! + var intType: String! + var longType: String! + var stringType: String! - var boolType : String! - var characterType : String! - var doubleType : String! - var floatType : String! - var intType : String! - var longType : String! - var stringType : String! + /** + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary) { + boolType = dictionary["boolType"] as? String + characterType = dictionary["characterType"] as? String + doubleType = dictionary["doubleType"] as? String + floatType = dictionary["floatType"] as? String + intType = dictionary["intType"] as? String + longType = dictionary["longType"] as? String + stringType = dictionary["stringType"] as? String + } - - /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary){ - boolType = dictionary["boolType"] as? String - characterType = dictionary["characterType"] as? String - doubleType = dictionary["doubleType"] as? String - floatType = dictionary["floatType"] as? String - intType = dictionary["intType"] as? String - longType = dictionary["longType"] as? String - stringType = dictionary["stringType"] as? String - } - - /** - * Returns all the available property values in the form of NSDictionary object where the key is the approperiate json key and the value is the value of the corresponding property - */ - func toDictionary() -> NSDictionary - { - let dictionary = NSMutableDictionary() - if boolType != nil{ - dictionary["boolType"] = boolType - } - if characterType != nil{ - dictionary["characterType"] = characterType - } - if doubleType != nil{ - dictionary["doubleType"] = doubleType - } - if floatType != nil{ - dictionary["floatType"] = floatType - } - if intType != nil{ - dictionary["intType"] = intType - } - if longType != nil{ - dictionary["longType"] = longType - } - if stringType != nil{ - dictionary["stringType"] = stringType - } - return dictionary - } - -} \ No newline at end of file + /** + * Returns all the available property values in the form of NSDictionary object where the key is the approperiate json key and the value is the value of the corresponding property + */ + func toDictionary() -> NSDictionary { + let dictionary = NSMutableDictionary() + if boolType != nil { + dictionary["boolType"] = boolType + } + if characterType != nil { + dictionary["characterType"] = characterType + } + if doubleType != nil { + dictionary["doubleType"] = doubleType + } + if floatType != nil { + dictionary["floatType"] = floatType + } + if intType != nil { + dictionary["intType"] = intType + } + if longType != nil { + dictionary["longType"] = longType + } + if stringType != nil { + dictionary["stringType"] = stringType + } + return dictionary + } +} diff --git a/JSONExport/FileContentBuilder.swift b/JSONExport/FileContentBuilder.swift index 2ff5f7a..66faa5b 100755 --- a/JSONExport/FileContentBuilder.swift +++ b/JSONExport/FileContentBuilder.swift @@ -9,139 +9,131 @@ import Foundation /** -Singleton used to build the file content with the current configurations -*/ -class FilesContentBuilder{ - + Singleton used to build the file content with the current configurations + */ +class FilesContentBuilder { private init() {} - + /** Lazely load and return the singleton instance of the FilesContentBuilder */ struct Static { - static var onceToken : Int = 0 - static var instance : FilesContentBuilder? = nil + static var onceToken: Int = 0 + static var instance: FilesContentBuilder? } - class var instance : FilesContentBuilder { - + + class var instance: FilesContentBuilder { _ = FilesContentBuilder.__once return Static.instance! } - + private static var __once: () = { - Static.instance = FilesContentBuilder() - }() + Static.instance = FilesContentBuilder() + }() + /** - The prefix used for first level type names (and file names as well) - */ + The prefix used for first level type names (and file names as well) + */ var classPrefix = "" - + /** - The language for which the files' content should be created - */ - var lang : LangModel! - + The language for which the files' content should be created + */ + var lang: LangModel! + /** - Whether to include utility methods in the generated content - */ + Whether to include utility methods in the generated content + */ var includeUtilities = true - + /** - Whether to include constructors (aka initializers) - */ + Whether to include constructors (aka initializers) + */ var includeConstructors = true - + /** - Whatever value will be assinged to the firstLine property, will appear as the first line in every file if the target language supports first line statement - */ + Whatever value will be assinged to the firstLine property, will appear as the first line in every file if the target language supports first line statement + */ var firstLine = "" - + /** - If the target language supports inheritance, all the generated classes will be subclasses of this class - */ + If the target language supports inheritance, all the generated classes will be subclasses of this class + */ var parentClassName = "" - - - var mismatchedTypes = [String : String]() - - - + + var mismatchedTypes = [String: String]() + /** - Generates a file using the passed className and jsonObject example and appends it in the passed files array - - - parameter className: for the file to be generated, if the file already exist with different name, this className will be changed - - parameter jsonObject: acts as an example of the json object, which the generated fill be able to handle - - parameter files: the generated file will be appended to this array - */ - func addFileWithName(_ className: inout String, jsonObject: NSDictionary, files : inout [FileRepresenter], toOneRelationWithProperty: Property! = nil) - { + Generates a file using the passed className and jsonObject example and appends it in the passed files array + + - parameter className: for the file to be generated, if the file already exist with different name, this className will be changed + - parameter jsonObject: acts as an example of the json object, which the generated fill be able to handle + - parameter files: the generated file will be appended to this array + */ + func addFileWithName(_ className: inout String, jsonObject: NSDictionary, files: inout [FileRepresenter], toOneRelationWithProperty: Property! = nil) { var properties = [Property]() - if !className.hasPrefix(classPrefix){ + if !className.hasPrefix(classPrefix) { className = "\(classPrefix)\(className)" } - if toOneRelationWithProperty != nil && lang.supportMutualRelationships != nil && lang.supportMutualRelationships!{ + if toOneRelationWithProperty != nil, lang.supportMutualRelationships != nil, lang.supportMutualRelationships! { properties.append(toOneRelationWithProperty) - } - //sort all the keys in the passed json dictionary + // sort all the keys in the passed json dictionary let jsonProperties = (jsonObject.allKeys as! [String]).sorted() - - //loop all the json properties and handle each one individually - for jsonPropertyName in jsonProperties{ - let value : AnyObject = jsonObject[jsonPropertyName]! as AnyObject + + // loop all the json properties and handle each one individually + for jsonPropertyName in jsonProperties { + let value: AnyObject = jsonObject[jsonPropertyName]! as AnyObject let property = propertyForValue(value, jsonKeyName: jsonPropertyName) - //Avoid duplicated property names - if properties.map({$0.nativeName}).index(of: property.nativeName) != nil{ + // Avoid duplicated property names + if properties.map({ $0.nativeName }).index(of: property.nativeName) != nil { continue } - //recursively handle custom types - if property.isCustomClass{ + // recursively handle custom types + if property.isCustomClass { let rProperty = relationProperty(className) - addFileWithName(&property.type, jsonObject: value as! NSDictionary, files:&files, toOneRelationWithProperty: rProperty) - }else if property.isArray{ + addFileWithName(&property.type, jsonObject: value as! NSDictionary, files: &files, toOneRelationWithProperty: rProperty) + } else if property.isArray { let array = value as! NSArray - if array.firstObject is NSDictionary{ - - //complicated enough..... + if array.firstObject is NSDictionary { + // complicated enough..... var type = property.elementsType let relatedProperty = relationProperty(className) - let allProperties = unionDictionaryFromArrayElements(array); - addFileWithName(&type, jsonObject: allProperties, files:&files, toOneRelationWithProperty: relatedProperty) + let allProperties = unionDictionaryFromArrayElements(array) + addFileWithName(&type, jsonObject: allProperties, files: &files, toOneRelationWithProperty: relatedProperty) } } - + properties.append(property) - } - - //create the file - - let file = FileRepresenter(className: className, properties: properties, lang:lang) - + + // create the file + + let file = FileRepresenter(className: className, properties: properties, lang: lang) + file.includeUtilities = includeUtilities file.includeConstructors = includeConstructors file.firstLine = firstLine file.parentClassName = parentClassName - + var exactMatchFound = false - if let similarFile = findSimilarFile(file, inFiles: files, exactMatchFound: &exactMatchFound){ + if let similarFile = findSimilarFile(file, inFiles: files, exactMatchFound: &exactMatchFound) { //there is a similar file - if !exactMatchFound{ - //If the found file is no exact, then any additional properties to the alread exist file instead of creating new one + if !exactMatchFound { + // If the found file is no exact, then any additional properties to the alread exist file instead of creating new one mergeProperties(fromFile: file, toFile: similarFile) - } - //Hold list of mismatches to be fixed later + // Hold list of mismatches to be fixed later mismatchedTypes[className] = similarFile.className className = similarFile.className - - }else{ + + } else { files.append(file) - - if lang.headerFileData != nil{ - //add header file first - let headerFile = HeaderFileRepresenter(className: className, properties: properties, lang:lang) + + if lang.headerFileData != nil { + // add header file first + let headerFile = HeaderFileRepresenter(className: className, properties: properties, lang: lang) headerFile.includeUtilities = includeUtilities headerFile.includeConstructors = includeConstructors headerFile.parentClassName = parentClassName @@ -150,224 +142,208 @@ class FilesContentBuilder{ } } } - + /** - Merges the properties from the passed fromFile to the pass toFile - - parameter fromFile: in which to find any new properties - - parameter toFile: to which to add any found new properties - */ - func mergeProperties(fromFile: FileRepresenter, toFile: FileRepresenter) - { - for property in fromFile.properties{ - if toFile.properties.index(of: property) == nil{ + Merges the properties from the passed fromFile to the pass toFile + - parameter fromFile: in which to find any new properties + - parameter toFile: to which to add any found new properties + */ + func mergeProperties(fromFile: FileRepresenter, toFile: FileRepresenter) { + for property in fromFile.properties { + if toFile.properties.index(of: property) == nil { toFile.properties.append(property) } } } - + /** - Finds the first file in the passed files which has the same class name as the passed file - - - parameter file: the file to compare against - - parameter inFiles: the files array to search in - - parameter exactMathFound: inout param, will have the value of 'true' if any file is found that has exactly the same properties as the passed file - - returns: similar file if any - */ - func findSimilarFile(_ file: FileRepresenter, inFiles files: [FileRepresenter], exactMatchFound: inout Bool) -> FileRepresenter?{ - var similarFile : FileRepresenter? - for targetFile in files{ - + Finds the first file in the passed files which has the same class name as the passed file + + - parameter file: the file to compare against + - parameter inFiles: the files array to search in + - parameter exactMathFound: inout param, will have the value of 'true' if any file is found that has exactly the same properties as the passed file + - returns: similar file if any + */ + func findSimilarFile(_ file: FileRepresenter, inFiles files: [FileRepresenter], exactMatchFound: inout Bool) -> FileRepresenter? { + var similarFile: FileRepresenter? + for targetFile in files { exactMatchFound = bothFilesHasSamePropreties(file1: targetFile, file2: file) - - if exactMatchFound || targetFile.className == file.className{ + + if exactMatchFound || targetFile.className == file.className { similarFile = targetFile - + break } } - + return similarFile } - + /** - Compares the properties of both files to determine if they exactly similar or no. - - - parameter file1: first file to compare against the second file - - parameter file2: the second file to compare against the first file - - returns: whether both files has exactly the same properties - */ - func bothFilesHasSamePropreties(file1: FileRepresenter, file2: FileRepresenter) -> Bool - { + Compares the properties of both files to determine if they exactly similar or no. + + - parameter file1: first file to compare against the second file + - parameter file2: the second file to compare against the first file + - returns: whether both files has exactly the same properties + */ + func bothFilesHasSamePropreties(file1: FileRepresenter, file2: FileRepresenter) -> Bool { var bothHasSameProperties = true - if file1.properties.count == file2.properties.count{ + if file1.properties.count == file2.properties.count { //there is a propability they both has the same properties - for property in file1.properties{ - if file2.properties.index(of: property) == nil{ - //property not found, no need to keep looking + for property in file1.properties { + if file2.properties.index(of: property) == nil { + // property not found, no need to keep looking bothHasSameProperties = false break } } - }else{ + } else { bothHasSameProperties = false } - + return bothHasSameProperties } - - - func fixReferenceMismatches(inFiles files: [FileRepresenter]) - { - for file in files{ - for property in file.properties{ - if property.isCustomClass, let toType = mismatchedTypes[property.type]{ + + func fixReferenceMismatches(inFiles files: [FileRepresenter]) { + for file in files { + for property in file.properties { + if property.isCustomClass, let toType = mismatchedTypes[property.type] { property.type = toType - }else if property.isArray, let toType = mismatchedTypes[property.elementsType]{ + } else if property.isArray, let toType = mismatchedTypes[property.elementsType] { property.elementsType = toType property.type = lang.arrayType.replacingOccurrences(of: elementType, with: toType) } } } } - + /** - Creates and returns a Property object whiche represents a to-one relation property - - - parameter relationClassName: to which the relation relates - - parameter headerProperty: optional whether this property is for header file - - - returns: the relation property - */ - func relationProperty(_ relationClassName : String) -> Property - { - + Creates and returns a Property object whiche represents a to-one relation property + + - parameter relationClassName: to which the relation relates + - parameter headerProperty: optional whether this property is for header file + + - returns: the relation property + */ + func relationProperty(_ relationClassName: String) -> Property { let nativeName = relationClassName.lowercaseFirstChar() let property = Property(jsonName: nativeName, nativeName: nativeName, type: relationClassName, lang: lang) property.isCustomClass = true - + return property } - + /** - Creates and returns a Property object passed on the passed value and json key name - - - parameter value: example value for the property - - parameter jsonKeyName: for the property - - returns: a Property instance - */ - func propertyForValue(_ value: AnyObject, jsonKeyName: String) -> Property - { + Creates and returns a Property object passed on the passed value and json key name + + - parameter value: example value for the property + - parameter jsonKeyName: for the property + - returns: a Property instance + */ + func propertyForValue(_ value: AnyObject, jsonKeyName: String) -> Property { let nativePropertyName = propertyNativeName(jsonKeyName) - var type = propertyTypeName(value, lang:lang) + var type = propertyTypeName(value, lang: lang) // var isDictionary = false // var isArray = false - + var property: Property! if value is NSDictionary { type = typeNameForPropertyName(jsonKeyName) - property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray:false, isCustomClass: true, lang: lang) - - }else if value is NSArray{ - //we need to check its elements... + property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: false, isCustomClass: true, lang: lang) + + } else if value is NSArray { + // we need to check its elements... let array = value as! NSArray - - if array.firstObject is NSDictionary{ - //wow complicated + + if array.firstObject is NSDictionary { + // wow complicated let leafClassName = typeNameForPropertyName(jsonKeyName) type = lang.arrayType.replacingOccurrences(of: elementType, with: leafClassName) - - property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: true, isCustomClass: false, lang:lang) + + property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: true, isCustomClass: false, lang: lang) property.elementsType = leafClassName - //Create a class for this type as well! - + // Create a class for this type as well! + property.elementsAreOfCustomType = true - }else{ - property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: true, isCustomClass: false, lang:lang) - property.elementsType = typeNameForArrayElements(value as! NSArray, lang:lang) + } else { + property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: true, isCustomClass: false, lang: lang) + property.elementsType = typeNameForArrayElements(value as! NSArray, lang: lang) } - }else{ - property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, lang:lang) + } else { + property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, lang: lang) } property.sampleValue = value return property } - - - /** - Returns a camel case presentation from the passed json key - - - parameter jsonKeyName: the name of the json key to convert to suitable native property name - - - returns: property name - */ - func propertyNativeName(_ jsonKeyName : String) -> String - { + Returns a camel case presentation from the passed json key + + - parameter jsonKeyName: the name of the json key to convert to suitable native property name + + - returns: property name + */ + func propertyNativeName(_ jsonKeyName: String) -> String { var propertyName = cleanUpVersionOfPropertyNamed(jsonKeyName) propertyName = underscoresToCamelCaseForString(propertyName, startFromFirstChar: false).lowercaseFirstChar() - //Fix property name that could be a reserved keyword - if lang.reservedKeywords != nil && lang.reservedKeywords.contains(propertyName.lowercased()){ - //Property name need to be suffixed by proper suffix, any ideas of better generlized prefix/suffix? + // Fix property name that could be a reserved keyword + if lang.reservedKeywords != nil, lang.reservedKeywords.contains(propertyName.lowercased()) { + // Property name need to be suffixed by proper suffix, any ideas of better generlized prefix/suffix? propertyName += "Field" } return propertyName } - - - func cleanUpVersionOfPropertyNamed(_ propertyName: String) -> String - { + + func cleanUpVersionOfPropertyNamed(_ propertyName: String) -> String { let allowedCharacters = NSMutableCharacterSet.alphanumeric() allowedCharacters.addCharacters(in: "_1234567890") let cleanVersion = propertyName.components(separatedBy: allowedCharacters.inverted).joined(separator: "") return cleanVersion } - + /** - Returns the input string with white spaces removed, and underscors converted to camel case - - - parameter inputString: to convert - - parameter startFromFirstChar: whether to start with upper case letter - - returns: the camel case version of the input - */ - func underscoresToCamelCaseForString(_ input: String, startFromFirstChar: Bool) -> String - { + Returns the input string with white spaces removed, and underscors converted to camel case + + - parameter inputString: to convert + - parameter startFromFirstChar: whether to start with upper case letter + - returns: the camel case version of the input + */ + func underscoresToCamelCaseForString(_ input: String, startFromFirstChar: Bool) -> String { var str = input.replacingOccurrences(of: " ", with: "") - + str = str.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) var output = "" var makeNextCharUpperCase = startFromFirstChar for char in input { if char == "_" { makeNextCharUpperCase = true - }else if makeNextCharUpperCase{ + } else if makeNextCharUpperCase { let upperChar = String(char).uppercased() output += upperChar makeNextCharUpperCase = false - }else{ + } else { makeNextCharUpperCase = false output += String(char) } } - + return output } - + /** - Creats and returns the class name for the passed proeprty name - - - parameter propertyName: to be converted to a type name - - returns: the type name - */ - func typeNameForPropertyName(_ propertyName : String) -> String{ + Creats and returns the class name for the passed proeprty name + + - parameter propertyName: to be converted to a type name + - returns: the type name + */ + func typeNameForPropertyName(_ propertyName: String) -> String { var swiftClassName = underscoresToCamelCaseForString(propertyName, startFromFirstChar: true).toSingular() - - if !swiftClassName.hasPrefix(classPrefix){ + + if !swiftClassName.hasPrefix(classPrefix) { swiftClassName = "\(classPrefix)\(swiftClassName)" } - + return swiftClassName } - } diff --git a/JSONExport/FilePreviewCell.swift b/JSONExport/FilePreviewCell.swift index fafc686..c9ef48c 100755 --- a/JSONExport/FilePreviewCell.swift +++ b/JSONExport/FilePreviewCell.swift @@ -9,89 +9,79 @@ import Cocoa class FilePreviewCell: NSTableCellView, NSTextViewDelegate { - - @IBOutlet var classNameLabel: NSTextFieldCell! @IBOutlet var constructors: NSButton! @IBOutlet var utilities: NSButton! @IBOutlet var textView: NSTextView! @IBOutlet var scrollView: NSScrollView! - - - var file: FileRepresenter!{ - didSet{ - if file != nil{ + + var file: FileRepresenter! { + didSet { + if file != nil { DispatchQueue.main.async { var fileName = self.file.className fileName += "." - if self.file is HeaderFileRepresenter{ + if self.file is HeaderFileRepresenter { fileName += self.file.lang.headerFileData.headerFileExtension - }else{ + } else { fileName += self.file.lang.fileExtension } self.classNameLabel.stringValue = fileName - if(self.textView != nil){ + if self.textView != nil { self.textView.string = self.file.toString() } - - if self.file.includeConstructors{ + + if self.file.includeConstructors { self.constructors.state = NSControl.StateValue.on - }else{ + } else { self.constructors.state = NSControl.StateValue.off } - if self.file.includeUtilities{ + if self.file.includeUtilities { self.utilities.state = NSControl.StateValue.on - }else{ + } else { self.utilities.state = NSControl.StateValue.off } } - }else{ + } else { classNameLabel.stringValue = "" } } } - - - + override func awakeFromNib() { super.awakeFromNib() - if textView != nil{ + if textView != nil { textView.delegate = self DispatchQueue.main.async { self.setupNumberedTextView() } } } - - func setupNumberedTextView() - { + + func setupNumberedTextView() { let lineNumberView = NoodleLineNumberView(scrollView: scrollView) scrollView.hasHorizontalRuler = false scrollView.hasVerticalRuler = true scrollView.verticalRulerView = lineNumberView scrollView.rulersVisible = true textView.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize) - } - - @IBAction func toggleConstructors(_ sender: NSButtonCell) - { - if file != nil{ + + @IBAction func toggleConstructors(_ sender: NSButtonCell) { + if file != nil { file.includeConstructors = (sender.state == NSControl.StateValue.off) textView.string = file.toString() - } } - - @IBAction func toggleUtilityMethods(_ sender: NSButtonCell) - { - if file != nil{ + + @IBAction func toggleUtilityMethods(_ sender: NSButtonCell) { + if file != nil { file.includeUtilities = (sender.state == NSControl.StateValue.on) textView.string = file.toString() } } - - func textDidChange(_ notification: Notification) { - file.fileContent = textView.string + + func textDidChange(_: Notification) { + file.fileContent = textView.string } } diff --git a/JSONExport/FileRepresenter.swift b/JSONExport/FileRepresenter.swift index 4284ccf..194b01f 100755 --- a/JSONExport/FileRepresenter.swift +++ b/JSONExport/FileRepresenter.swift @@ -30,68 +30,66 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -import Foundation import AddressBook +import Foundation /** -FileRepresenter is used to generate a valid syntax for the target language that represents JSON object -*/ -class FileRepresenter{ + FileRepresenter is used to generate a valid syntax for the target language that represents JSON object + */ +class FileRepresenter { /** - Holds the class (or type) name - */ - var className : String - + Holds the class (or type) name + */ + var className: String + /** - Array of properties which will be included in the file content - */ - var properties : [Property] - + Array of properties which will be included in the file content + */ + var properties: [Property] + /** - The target language meta instance - */ - var lang : LangModel - + The target language meta instance + */ + var lang: LangModel + /** - Whether to include constructors (aka initializers in Swift) in the file content - */ + Whether to include constructors (aka initializers in Swift) in the file content + */ var includeConstructors = true - + /** - Whether to include utility methods in the file content. Utility methods such as toDictionary method - */ + Whether to include utility methods in the file content. Utility methods such as toDictionary method + */ var includeUtilities = true - + /** - If the target language supports first line statement (i.e package names in Java), then you can set the value of this property to whatever the first line statement is. - */ + If the target language supports first line statement (i.e package names in Java), then you can set the value of this property to whatever the first line statement is. + */ var firstLine = "" - + /** - If the target language supports inheritance, all the generated classes will be subclasses of this class - */ + If the target language supports inheritance, all the generated classes will be subclasses of this class + */ var parentClassName = "" - + /** - After the first time you use the toString() method, this property will contain the file content. - */ + After the first time you use the toString() method, this property will contain the file content. + */ var fileContent = "" - - + /** - Designated initializer - */ - init(className: String, properties: [Property], lang: LangModel) - { + Designated initializer + */ + init(className: String, properties: [Property], lang: LangModel) { self.className = className self.properties = properties self.lang = lang } - + /** - Generates the file content and stores it in the fileContent property - */ - func toString() -> String{ + Generates the file content and stores it in the fileContent property + */ + func toString() -> String { fileContent = "" appendFirstLineStatement() appendCopyrights() @@ -99,127 +97,116 @@ class FileRepresenter{ appendHeaderFileImport() appendConstVarDefinition() appendCustomImports() - //start the model defination + // start the model defination var definition = "" - if lang.modelDefinitionWithParent != nil && parentClassName.count > 0{ + if lang.modelDefinitionWithParent != nil, parentClassName.count > 0 { definition = lang.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: parentClassName) - }else if includeUtilities && lang.defaultParentWithUtilityMethods != nil{ + } else if includeUtilities, lang.defaultParentWithUtilityMethods != nil { definition = lang.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: lang.defaultParentWithUtilityMethods) - }else{ + } else { definition = lang.modelDefinition.replacingOccurrences(of: modelName, with: className) } fileContent += definition - //start the model content body + // start the model content body fileContent += "\(lang.modelStart)" - + appendProperties() appendSettersAndGetters() appendInitializers() appendUtilityMethods() - fileContent = fileContent.replacingOccurrences(of: lowerCaseModelName, with:className.lowercaseFirstChar()) - fileContent = fileContent.replacingOccurrences(of: modelName, with:className) + fileContent = fileContent.replacingOccurrences(of: lowerCaseModelName, with: className.lowercaseFirstChar()) + fileContent = fileContent.replacingOccurrences(of: modelName, with: className) fileContent += lang.modelEnd return fileContent } - + /** - Appneds the firstLine value (if any) to the fileContent if the lang.supportsFirstLineStatement is true - */ - func appendFirstLineStatement() - { - if lang.supportsFirstLineStatement != nil && lang.supportsFirstLineStatement! && firstLine.count > 0{ + Appneds the firstLine value (if any) to the fileContent if the lang.supportsFirstLineStatement is true + */ + func appendFirstLineStatement() { + if lang.supportsFirstLineStatement != nil, lang.supportsFirstLineStatement!, firstLine.count > 0 { fileContent += "\(firstLine)\n\n" } } - - /** - Appends the lang.staticImports if any - */ - func appendStaticImports() - { - if lang.staticImports != nil{ + + /** + Appends the lang.staticImports if any + */ + func appendStaticImports() { + if lang.staticImports != nil { fileContent += lang.staticImports! fileContent += "\n" } } - func appendHeaderFileImport() - { - if lang.importHeaderFile != nil{ + func appendHeaderFileImport() { + if lang.importHeaderFile != nil { fileContent += "\n" fileContent += lang.importHeaderFile! fileContent = fileContent.replacingOccurrences(of: modelName, with: className) } } - - func appendConstVarDefinition() - { + + func appendConstVarDefinition() { if lang.constVarDefinition != nil { fileContent += "\n" } - for property in properties{ + for property in properties { fileContent += property.toConstVar(className) } } - + /** - Tries to access the address book in order to fetch basic information about the author so it can include a nice copyright statment - */ - func appendCopyrights() - { + Tries to access the address book in order to fetch basic information about the author so it can include a nice copyright statment + */ + func appendCopyrights() { fileContent += "//\n//\t\(className).\(lang.fileExtension)\n" - if let me = ABAddressBook.shared()?.me(){ - - if let firstName = me.value(forProperty: kABFirstNameProperty as String) as? String{ + if let me = ABAddressBook.shared()?.me() { + if let firstName = me.value(forProperty: kABFirstNameProperty as String) as? String { fileContent += "//\n//\tCreate by \(firstName)" - if let lastName = me.value(forProperty: kABLastNameProperty as String) as? String{ - fileContent += " \(lastName)" + if let lastName = me.value(forProperty: kABLastNameProperty as String) as? String { + fileContent += " \(lastName)" } } - - + fileContent += " on \(getTodayFormattedDay())\n//\tCopyright © \(getYear())" - - if let organization = me.value(forProperty: kABOrganizationProperty as String) as? String{ + + if let organization = me.value(forProperty: kABOrganizationProperty as String) as? String { fileContent += " \(organization)" } - + fileContent += ". All rights reserved.\n" } - + fileContent += "//\tModel file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport" - - if let langAuthor = lang.author{ + + if let langAuthor = lang.author { fileContent += "\n\n//\tThe \"\(lang.displayLangName!)\" support has been made available by \(langAuthor.name!)" - if let email = langAuthor.email{ + if let email = langAuthor.email { fileContent += "(\(email))" } - - if let website = langAuthor.website{ + + if let website = langAuthor.website { fileContent += "\n//\tMore about him/her can be found at his/her website: \(website)" } - } - - + fileContent += "\n\n" } - + /** - Returns the current year as String - */ - func getYear() -> String - { + Returns the current year as String + */ + func getYear() -> String { return "\((Calendar.current as NSCalendar).component(.year, from: Date()))" } - + /** - Returns today date in the format dd/mm/yyyy - */ - func getTodayFormattedDay() -> String - { + Returns today date in the format dd/mm/yyyy + */ + func getTodayFormattedDay() -> String { let components = (Calendar.current as NSCalendar).components([.day, .month, .year], from: Date()) return "\(components.day!)/\(components.month!)/\(components.year!)" } @@ -227,158 +214,147 @@ class FileRepresenter{ /** Loops on all properties which has a custom type and appends the custom import from the lang's importForEachCustomType property - */ - func appendCustomImports() - { - if lang.importForEachCustomType != nil{ - for property in properties{ - if property.isCustomClass{ + */ + func appendCustomImports() { + if lang.importForEachCustomType != nil { + for property in properties { + if property.isCustomClass { fileContent += lang.importForEachCustomType.replacingOccurrences(of: modelName, with: property.type) - }else if property.isArray && property.elementsAreOfCustomType{ + } else if property.isArray, property.elementsAreOfCustomType { fileContent += lang.importForEachCustomType.replacingOccurrences(of: modelName, with: property.elementsType) } } } } - + /** - Appends all the properties using the Property.toString(forHeaderFile: false) method - */ - func appendProperties() - { + Appends all the properties using the Property.toString(forHeaderFile: false) method + */ + func appendProperties() { fileContent += "\n" - for property in properties{ - + for property in properties { fileContent += property.toString(false) } } - + /** - Appends the setter and getter for each property if the current target language supports them (i.e the convension in Java is to use private instance variables with public setters and getters). The method will use special getter for boolean properties if required by the target language - */ - func appendSettersAndGetters() - { + Appends the setter and getter for each property if the current target language supports them (i.e the convension in Java is to use private instance variables with public setters and getters). The method will use special getter for boolean properties if required by the target language + */ + func appendSettersAndGetters() { fileContent += "\n" - for property in properties{ - //append the setter + for property in properties { + // append the setter let capVarName = property.nativeName.uppercaseFirstChar() - if lang.setter != nil{ + if lang.setter != nil { var set = lang.setter - + set = set?.replacingOccurrences(of: capitalizedVarName, with: capVarName) set = set?.replacingOccurrences(of: varName, with: property.nativeName) set = set?.replacingOccurrences(of: varType, with: property.type) fileContent += set! } - + // append the getters - var get : String! - //if the property is a boolean property determine if there is a special getter for boolean properties - if property.type == lang.dataTypes.boolType{ - if lang.booleanGetter != nil{ + var get: String! + // if the property is a boolean property determine if there is a special getter for boolean properties + if property.type == lang.dataTypes.boolType { + if lang.booleanGetter != nil { get = lang.booleanGetter - - }else{ - //use normal getter + + } else { + // use normal getter get = lang.getter } - }else{ + } else { get = lang.getter } - - if get != nil{ + + if get != nil { get = get.replacingOccurrences(of: capitalizedVarName, with: capVarName) get = get.replacingOccurrences(of: varName, with: property.nativeName) get = get.replacingOccurrences(of: varType, with: property.type) fileContent += get } - } } - + /** - Appends all the defined constructors (aka initializers) in lang.constructors to the fileContent - */ - func appendInitializers() - { - if !includeConstructors{ + Appends all the defined constructors (aka initializers) in lang.constructors to the fileContent + */ + func appendInitializers() { + if !includeConstructors { return } fileContent += "\n" - for constructor in lang.constructors{ - if constructor.comment != nil{ + for constructor in lang.constructors { + if constructor.comment != nil { fileContent += constructor.comment } - + fileContent += constructor.signature fileContent += constructor.bodyStart - - for property in properties{ - + + for property in properties { fileContent += propertyFetchFromJsonSyntaxForProperty(property, constructor: constructor) } - + fileContent += constructor.bodyEnd fileContent = fileContent.replacingOccurrences(of: modelName, with: className) } } - - + /** - Appends all the defined utility methods in lang.utilityMethods to the fileContent - */ - func appendUtilityMethods() - { - if !includeUtilities{ + Appends all the defined utility methods in lang.utilityMethods to the fileContent + */ + func appendUtilityMethods() { + if !includeUtilities { return } fileContent += "\n" - for method in lang.utilityMethods{ - if method.comment != nil{ + for method in lang.utilityMethods { + if method.comment != nil { fileContent += method.comment } fileContent += method.signature fileContent += method.bodyStart fileContent += method.body - for property in properties{ + for property in properties { var propertyHandlingStr = "" - if property.isArray{ - if propertyTypeIsBasicType(property){ + if property.isArray { + if propertyTypeIsBasicType(property) { propertyHandlingStr = method.forEachProperty - - }else{ + + } else { propertyHandlingStr = method.forEachArrayOfCustomTypeProperty } propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: elementType, with: property.elementsType) - }else{ - if lang.basicTypesWithSpecialStoringNeeds != nil && method.forEachPropertyWithSpecialStoringNeeds != nil && lang.basicTypesWithSpecialStoringNeeds.index(of: property.type) != nil{ + } else { + if lang.basicTypesWithSpecialStoringNeeds != nil, method.forEachPropertyWithSpecialStoringNeeds != nil, lang.basicTypesWithSpecialStoringNeeds.index(of: property.type) != nil { propertyHandlingStr = method.forEachPropertyWithSpecialStoringNeeds - }else{ + } else { propertyHandlingStr = method.forEachProperty - if property.isCustomClass{ + if property.isCustomClass { propertyHandlingStr = method.forEachCustomTypeProperty } } - } - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varName, with:property.nativeName) - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: constKeyName, with:property.constName!) - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varType, with:property.type) - - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: jsonKeyName, with:property.jsonName) - - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: additionalCustomTypeProperty, with:"") - if lang.basicTypesWithSpecialFetchingNeeds != nil{ - if let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.type), let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements?[index]{ - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varTypeReplacement, with: replacement) - + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varName, with: property.nativeName) + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: constKeyName, with: property.constName!) + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varType, with: property.type) + + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: jsonKeyName, with: property.jsonName) + + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: additionalCustomTypeProperty, with: "") + if lang.basicTypesWithSpecialFetchingNeeds != nil { + if let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.type), let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements?[index] { + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varTypeReplacement, with: replacement) + var castString = String() - if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index]{ + if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index] { // if needs cast if !cast.isEmpty { castString = "(\(cast)) " - } - else { + } else { castString = cast } } @@ -386,7 +362,6 @@ class FileRepresenter{ let lowerCaseType = property.type.lowercased() propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: lowerCaseVarType, with: lowerCaseType) - } } fileContent += propertyHandlingStr @@ -394,140 +369,125 @@ class FileRepresenter{ fileContent += method.returnStatement fileContent += method.bodyEnd } - - } - + /** - Returns true if the passed property.type is one of the basic types or an array of any of the basic types, otherwise returns false - */ - func propertyTypeIsBasicType(_ property: Property) -> Bool{ + Returns true if the passed property.type is one of the basic types or an array of any of the basic types, otherwise returns false + */ + func propertyTypeIsBasicType(_ property: Property) -> Bool { var isBasicType = false let type = propertyTypeWithoutArrayWords(property) - if lang.genericType == type{ + if lang.genericType == type { isBasicType = true - }else{ + } else { let basicTypes = lang.dataTypes.toDictionary().allValues as! [String] - - if basicTypes.index(of: type) != nil{ + + if basicTypes.index(of: type) != nil { isBasicType = true } } - - + return isBasicType } - + /** - Removes any "array-specific character or words" from the passed type to return the type of the array elements. The "array-specific character or words" are fetched from the lang.wordsToRemoveToGetArrayElementsType property - */ - func propertyTypeWithoutArrayWords(_ property: Property) -> String - { - + Removes any "array-specific character or words" from the passed type to return the type of the array elements. The "array-specific character or words" are fetched from the lang.wordsToRemoveToGetArrayElementsType property + */ + func propertyTypeWithoutArrayWords(_ property: Property) -> String { var type = property.type - - for arrayWord in lang.wordsToRemoveToGetArrayElementsType{ + + for arrayWord in lang.wordsToRemoveToGetArrayElementsType { type = type.replacingOccurrences(of: arrayWord, with: "") } - - if type.count == 0{ + + if type.count == 0 { type = typeNameForArrayElements(property.sampleValue as! NSArray, lang: lang) } return type } - - //MARK: - Fetching property from a JSON object + + // MARK: - Fetching property from a JSON object + /** - Returns the suitable syntax to fetch the value of the property from a JSON object for the passed constructor - */ - func propertyFetchFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String - { + Returns the suitable syntax to fetch the value of the property from a JSON object for the passed constructor + */ + func propertyFetchFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String { var propertyStr = "" - if property.isCustomClass{ - + if property.isCustomClass { propertyStr = constructor.fetchCustomTypePropertyFromMap - - }else if property.isArray{ + + } else if property.isArray { propertyStr = fetchArrayFromJsonSyntaxForProperty(property, constructor: constructor) - - }else { + + } else { propertyStr = fetchBasicTypePropertyFromJsonSyntaxForProperty(property, constructor: constructor) - } - //Apply all the basic replacements + // Apply all the basic replacements propertyStr = propertyStr.replacingOccurrences(of: varName, with: property.nativeName) propertyStr = propertyStr.replacingOccurrences(of: jsonKeyName, with: property.jsonName) propertyStr = propertyStr.replacingOccurrences(of: constKeyName, with: property.constName!) propertyStr = propertyStr.replacingOccurrences(of: varType, with: property.type) let capVarName = property.nativeName.capitalized - let capVarType = property.type.capitalized; + let capVarType = property.type.capitalized propertyStr = propertyStr.replacingOccurrences(of: capitalizedVarName, with: capVarName) propertyStr = propertyStr.replacingOccurrences(of: capitalizedVarType, with: capVarType) return propertyStr } - + /** - Returns valid syntax to fetch an array from a JSON object - */ - func fetchArrayFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String - { + Returns valid syntax to fetch an array from a JSON object + */ + func fetchArrayFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String { var propertyStr = "" - if(propertyTypeIsBasicType(property)){ - - if constructor.fetchArrayOfBasicTypePropertyFromMap != nil{ - if let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.elementsType){ + if propertyTypeIsBasicType(property) { + if constructor.fetchArrayOfBasicTypePropertyFromMap != nil { + if let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.elementsType) { propertyStr = constructor.fetchArrayOfBasicTypePropertyFromMap let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements[index] propertyStr = propertyStr.replacingOccurrences(of: varTypeReplacement, with: replacement) - + // if needs cast let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast[index] if !cast.isEmpty { propertyStr = propertyStr.replacingOccurrences(of: varTypeCast, with: "(\(cast)) ") - } - else { + } else { propertyStr = propertyStr.replacingOccurrences(of: varTypeCast, with: cast) } - }else{ + } else { propertyStr = constructor.fetchBasicTypePropertyFromMap } - }else{ + } else { propertyStr = constructor.fetchBasicTypePropertyFromMap } - - }else{ - //array of custom type + + } else { + // array of custom type propertyStr = constructor.fetchArrayOfCustomTypePropertyFromMap - - - } - propertyStr = propertyStr.replacingOccurrences(of: elementType, with: property.elementsType) + propertyStr = propertyStr.replacingOccurrences(of: elementType, with: property.elementsType) return propertyStr } - + /** - Returns valid syntax to fetch any property with basic type from a JSON object - */ - func fetchBasicTypePropertyFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String - { + Returns valid syntax to fetch any property with basic type from a JSON object + */ + func fetchBasicTypePropertyFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String { var propertyStr = "" - if lang.basicTypesWithSpecialFetchingNeeds != nil{ + if lang.basicTypesWithSpecialFetchingNeeds != nil { let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.type) - if index != nil{ + if index != nil { propertyStr = constructor.fetchBasicTypeWithSpecialNeedsPropertyFromMap - if let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements?[index!]{ + if let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements?[index!] { propertyStr = propertyStr.replacingOccurrences(of: varTypeReplacement, with: replacement) } - + var castString = String() - if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index!]{ + if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index!] { // if needs cast if !cast.isEmpty { castString = "(\(cast)) " - } - else { + } else { castString = cast } } @@ -535,15 +495,15 @@ class FileRepresenter{ let lowerCaseType = property.type.lowercased() propertyStr = propertyStr.replacingOccurrences(of: lowerCaseVarType, with: lowerCaseType) - - }else{ + + } else { propertyStr = constructor.fetchBasicTypePropertyFromMap } - - }else{ + + } else { propertyStr = constructor.fetchBasicTypePropertyFromMap } - + return propertyStr } } diff --git a/JSONExport/HeaderFileData.swift b/JSONExport/HeaderFileData.swift index 162e3f2..01a1d8a 100755 --- a/JSONExport/HeaderFileData.swift +++ b/JSONExport/HeaderFileData.swift @@ -7,34 +7,32 @@ import Foundation -class HeaderFileData{ - - var constructorSignatures : [String]! - var headerFileExtension : String! - var importForEachCustomType : String! - var importParentHeaderFile : String! - var instanceVarDefinition : String! - var instanceVarWithSpeicalDefinition : String! - var modelDefinition : String! - var modelDefinitionWithParent : String! - var defaultParentWithUtilityMethods : String! - var modelEnd : String! - var modelStart : String! - var staticImports : String! - var typesNeedSpecialDefinition : [String]! - var utilityMethodSignatures : [String]! - - +class HeaderFileData { + var constructorSignatures: [String]! + var headerFileExtension: String! + var importForEachCustomType: String! + var importParentHeaderFile: String! + var instanceVarDefinition: String! + var instanceVarWithSpeicalDefinition: String! + var modelDefinition: String! + var modelDefinitionWithParent: String! + var defaultParentWithUtilityMethods: String! + var modelEnd: String! + var modelStart: String! + var staticImports: String! + var typesNeedSpecialDefinition: [String]! + var utilityMethodSignatures: [String]! + /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary){ + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary) { constructorSignatures = dictionary["constructorSignatures"] as? [String] headerFileExtension = dictionary["headerFileExtension"] as? String importForEachCustomType = dictionary["importForEachCustomType"] as? String importParentHeaderFile = dictionary["importParentHeaderFile"] as? String instanceVarDefinition = dictionary["instanceVarDefinition"] as? String - + instanceVarWithSpeicalDefinition = dictionary["instanceVarWithSpeicalDefinition"] as? String modelDefinition = dictionary["modelDefinition"] as? String modelDefinitionWithParent = dictionary["modelDefinitionWithParent"] as? String @@ -44,7 +42,5 @@ class HeaderFileData{ staticImports = dictionary["staticImports"] as? String typesNeedSpecialDefinition = dictionary["typesNeedSpecialDefinition"] as? [String] utilityMethodSignatures = dictionary["utilityMethodSignatures"] as? [String] - } - -} \ No newline at end of file +} diff --git a/JSONExport/HeaderFileRepresenter.swift b/JSONExport/HeaderFileRepresenter.swift index 05e2895..c12321b 100755 --- a/JSONExport/HeaderFileRepresenter.swift +++ b/JSONExport/HeaderFileRepresenter.swift @@ -29,155 +29,139 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. - -import Foundation import AddressBook +import Foundation -class HeaderFileRepresenter : FileRepresenter{ +class HeaderFileRepresenter: FileRepresenter { /** - Generates the header file content and stores it in the fileContent property - */ - override func toString() -> String{ + Generates the header file content and stores it in the fileContent property + */ + override func toString() -> String { fileContent = "" appendCopyrights() appendStaticImports() appendImportParentHeader() appendCustomImports() - - //start the model defination + + // start the model defination var definition = "" - if lang.headerFileData.modelDefinitionWithParent != nil && parentClassName.count > 0{ + if lang.headerFileData.modelDefinitionWithParent != nil, parentClassName.count > 0 { definition = lang.headerFileData.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: parentClassName) - }else if includeUtilities && lang.defaultParentWithUtilityMethods != nil{ + } else if includeUtilities, lang.defaultParentWithUtilityMethods != nil { definition = lang.headerFileData.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: lang.headerFileData.defaultParentWithUtilityMethods) - }else{ + } else { definition = lang.headerFileData.modelDefinition.replacingOccurrences(of: modelName, with: className) } - + fileContent += definition - //start the model content body + // start the model content body fileContent += "\(lang.modelStart)" - + appendProperties() appendInitializers() appendUtilityMethods() fileContent += lang.modelEnd return fileContent } - - - + /** - Appends the lang.headerFileData.staticImports if any - */ - override func appendStaticImports() - { - if lang.headerFileData.staticImports != nil{ + Appends the lang.headerFileData.staticImports if any + */ + override func appendStaticImports() { + if lang.headerFileData.staticImports != nil { fileContent += lang.headerFileData.staticImports fileContent += "\n" } } - - func appendImportParentHeader() - { - if lang.headerFileData.importParentHeaderFile != nil && parentClassName.count > 0{ + + func appendImportParentHeader() { + if lang.headerFileData.importParentHeaderFile != nil, parentClassName.count > 0 { fileContent += lang.headerFileData.importParentHeaderFile.replacingOccurrences(of: modelWithParentClassName, with: parentClassName) } } - + /** - Tries to access the address book in order to fetch basic information about the author so it can include a nice copyright statment - */ - override func appendCopyrights() - { - if let me = ABAddressBook.shared()?.me(){ - fileContent += "//\n//\t\(self.className).\(lang.headerFileData.headerFileExtension!)\n" - if let firstName = me.value(forProperty: kABFirstNameProperty as String) as? String{ + Tries to access the address book in order to fetch basic information about the author so it can include a nice copyright statment + */ + override func appendCopyrights() { + if let me = ABAddressBook.shared()?.me() { + fileContent += "//\n//\t\(className).\(lang.headerFileData.headerFileExtension!)\n" + if let firstName = me.value(forProperty: kABFirstNameProperty as String) as? String { fileContent += "//\n//\tCreate by \(firstName)" - if let lastName = me.value(forProperty: kABLastNameProperty as String) as? String{ + if let lastName = me.value(forProperty: kABLastNameProperty as String) as? String { fileContent += " \(lastName)" } } - - + fileContent += " on \(getTodayFormattedDay())\n//\tCopyright © \(getYear())" - - if let organization = me.value(forProperty: kABOrganizationProperty as String) as? String{ + + if let organization = me.value(forProperty: kABOrganizationProperty as String) as? String { fileContent += " \(organization)" } - + fileContent += ". All rights reserved.\n//\n\n" - //fileContent += "//\tModel file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport\n\n" + // fileContent += "//\tModel file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport\n\n" } - } - - + /** - Loops on all properties which has a custom type and appends the custom import from the lang.headerFileData's importForEachCustomType property - - */ - override func appendCustomImports() - { - if lang.importForEachCustomType != nil{ - for property in properties{ - if property.isCustomClass{ + Loops on all properties which has a custom type and appends the custom import from the lang.headerFileData's importForEachCustomType property + + */ + override func appendCustomImports() { + if lang.importForEachCustomType != nil { + for property in properties { + if property.isCustomClass { fileContent += lang.headerFileData.importForEachCustomType.replacingOccurrences(of: modelName, with: property.type) - }else if property.isArray{ - //if it is an array of custom types - if(property.elementsType != lang.genericType){ + } else if property.isArray { + // if it is an array of custom types + if property.elementsType != lang.genericType { let basicTypes = lang.dataTypes.toDictionary().allValues as! [String] - if basicTypes.index(of: property.elementsType) == nil{ + if basicTypes.index(of: property.elementsType) == nil { fileContent += lang.headerFileData.importForEachCustomType.replacingOccurrences(of: modelName, with: property.elementsType) } } - } } } } - + /** - Appends all the properties using the Property.stringPresentation method - */ - override func appendProperties() - { + Appends all the properties using the Property.stringPresentation method + */ + override func appendProperties() { fileContent += "\n" - for property in properties{ + for property in properties { fileContent += property.toString(true) } } - + /** - Appends all the defined constructors (aka initializers) in lang.constructors to the fileContent - */ - override func appendInitializers() - { - if !includeConstructors{ + Appends all the defined constructors (aka initializers) in lang.constructors to the fileContent + */ + override func appendInitializers() { + if !includeConstructors { return } fileContent += "\n" - for constructorSignature in lang.headerFileData.constructorSignatures{ - + for constructorSignature in lang.headerFileData.constructorSignatures { fileContent += constructorSignature - + fileContent = fileContent.replacingOccurrences(of: modelName, with: className) } } - - + /** - Appends all the defined utility methods in lang.utilityMethods to the fileContent - */ - override func appendUtilityMethods() - { - if !includeUtilities{ + Appends all the defined utility methods in lang.utilityMethods to the fileContent + */ + override func appendUtilityMethods() { + if !includeUtilities { return } fileContent += "\n" - for methodSignature in lang.headerFileData.utilityMethodSignatures{ + for methodSignature in lang.headerFileData.utilityMethodSignatures { fileContent += methodSignature } } diff --git a/JSONExport/LangModel.swift b/JSONExport/LangModel.swift index b78f061..dd2a042 100755 --- a/JSONExport/LangModel.swift +++ b/JSONExport/LangModel.swift @@ -7,109 +7,105 @@ import Foundation -class LangModel{ - - var arrayType : String! - var basicTypesWithSpecialFetchingNeeds : [String]! - var basicTypesWithSpecialFetchingNeedsReplacements : [String]! - var basicTypesWithSpecialFetchingNeedsTypeCast : [String]! - var basicTypesWithSpecialStoringNeeds : [String]! - var booleanGetter : String! - var briefDescription : String! - var constructors : [Constructor]! - var dataTypes : DataType! - var displayLangName : String! - var fileExtension : String = "" - var genericType : String! - var getter : String! - var importForEachCustomType : String! - var importHeaderFile : String! - var instanceVarDefinition : String! - var instanceVarWithSpeicalDefinition : String! - var typesNeedSpecialDefinition : [String]! - var langName : String = "" - var constVarDefinition : String! - var modelDefinition : String! - var modelDefinitionWithParent : String! - var defaultParentWithUtilityMethods : String! - var modelEnd : String! - var modelStart : String = "" - var setter : String! - var staticImports : String! - var supportsFirstLineStatement : Bool! - var firstLineHint : String! - var utilityMethods : [UtilityMethod]! - var reservedKeywords : [String]! - var wordsToRemoveToGetArrayElementsType : [String]! - var headerFileData : HeaderFileData! - var supportMutualRelationships : Bool! - var author : Author! - /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary){ - arrayType = dictionary["arrayType"] as? String - basicTypesWithSpecialFetchingNeeds = dictionary["basicTypesWithSpecialFetchingNeeds"] as? [String] +class LangModel { + var arrayType: String! + var basicTypesWithSpecialFetchingNeeds: [String]! + var basicTypesWithSpecialFetchingNeedsReplacements: [String]! + var basicTypesWithSpecialFetchingNeedsTypeCast: [String]! + var basicTypesWithSpecialStoringNeeds: [String]! + var booleanGetter: String! + var briefDescription: String! + var constructors: [Constructor]! + var dataTypes: DataType! + var displayLangName: String! + var fileExtension: String = "" + var genericType: String! + var getter: String! + var importForEachCustomType: String! + var importHeaderFile: String! + var instanceVarDefinition: String! + var instanceVarWithSpeicalDefinition: String! + var typesNeedSpecialDefinition: [String]! + var langName: String = "" + var constVarDefinition: String! + var modelDefinition: String! + var modelDefinitionWithParent: String! + var defaultParentWithUtilityMethods: String! + var modelEnd: String! + var modelStart: String = "" + var setter: String! + var staticImports: String! + var supportsFirstLineStatement: Bool! + var firstLineHint: String! + var utilityMethods: [UtilityMethod]! + var reservedKeywords: [String]! + var wordsToRemoveToGetArrayElementsType: [String]! + var headerFileData: HeaderFileData! + var supportMutualRelationships: Bool! + var author: Author! + /** + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary) { + arrayType = dictionary["arrayType"] as? String + basicTypesWithSpecialFetchingNeeds = dictionary["basicTypesWithSpecialFetchingNeeds"] as? [String] basicTypesWithSpecialFetchingNeedsReplacements = dictionary["basicTypesWithSpecialFetchingNeedsReplacements"] as? [String] basicTypesWithSpecialFetchingNeedsTypeCast = dictionary["basicTypesWithSpecialFetchingNeedsTypeCast"] as? [String] basicTypesWithSpecialStoringNeeds = dictionary["basicTypesWithSpecialStoringNeeds"] as? [String] - booleanGetter = dictionary["booleanGetter"] as? String + booleanGetter = dictionary["booleanGetter"] as? String briefDescription = dictionary["briefDescription"] as? String - - constructors = [Constructor]() - if let constructorsArray = dictionary["constructors"] as? [NSDictionary]{ - for dic in constructorsArray{ - let value = Constructor(fromDictionary: dic) - constructors.append(value) - } - } - if let dataTypesData = dictionary["dataTypes"] as? NSDictionary{ - dataTypes = DataType(fromDictionary: dataTypesData) - } + + constructors = [Constructor]() + if let constructorsArray = dictionary["constructors"] as? [NSDictionary] { + for dic in constructorsArray { + let value = Constructor(fromDictionary: dic) + constructors.append(value) + } + } + if let dataTypesData = dictionary["dataTypes"] as? NSDictionary { + dataTypes = DataType(fromDictionary: dataTypesData) + } importHeaderFile = dictionary["importHeaderFile"] as? String - displayLangName = dictionary["displayLangName"] as? String - fileExtension = dictionary["fileExtension"] as! String - genericType = dictionary["genericType"] as? String - getter = dictionary["getter"] as? String - importForEachCustomType = dictionary["importForEachCustomType"] as? String - instanceVarDefinition = dictionary["instanceVarDefinition"] as? String + displayLangName = dictionary["displayLangName"] as? String + fileExtension = dictionary["fileExtension"] as! String + genericType = dictionary["genericType"] as? String + getter = dictionary["getter"] as? String + importForEachCustomType = dictionary["importForEachCustomType"] as? String + instanceVarDefinition = dictionary["instanceVarDefinition"] as? String instanceVarWithSpeicalDefinition = dictionary["instanceVarWithSpeicalDefinition"] as? String typesNeedSpecialDefinition = dictionary["typesNeedSpecialDefinition"] as? [String] - - langName = dictionary["langName"] as! String + + langName = dictionary["langName"] as! String constVarDefinition = dictionary["constVarDefinition"] as? String - modelDefinition = dictionary["modelDefinition"] as? String + modelDefinition = dictionary["modelDefinition"] as? String modelDefinitionWithParent = dictionary["modelDefinitionWithParent"] as? String defaultParentWithUtilityMethods = dictionary["defaultParentWithUtilityMethods"] as? String - modelEnd = dictionary["modelEnd"] as? String - if let mStart = dictionary["modelStart"] as? String{ + modelEnd = dictionary["modelEnd"] as? String + if let mStart = dictionary["modelStart"] as? String { modelStart = mStart } - setter = dictionary["setter"] as? String - staticImports = dictionary["staticImports"] as? String - supportsFirstLineStatement = (dictionary["supportsFirstLineStatement"] as? NSString)?.boolValue + setter = dictionary["setter"] as? String + staticImports = dictionary["staticImports"] as? String + supportsFirstLineStatement = (dictionary["supportsFirstLineStatement"] as? NSString)?.boolValue firstLineHint = dictionary["firstLineHint"] as? String - utilityMethods = [UtilityMethod]() - if let utilityMethodsArray = dictionary["utilityMethods"] as? [NSDictionary]{ - for dic in utilityMethodsArray{ - let value = UtilityMethod(fromDictionary: dic) - utilityMethods.append(value) - } - } + utilityMethods = [UtilityMethod]() + if let utilityMethodsArray = dictionary["utilityMethods"] as? [NSDictionary] { + for dic in utilityMethodsArray { + let value = UtilityMethod(fromDictionary: dic) + utilityMethods.append(value) + } + } reservedKeywords = dictionary["reservedKeywords"] as? [String] - wordsToRemoveToGetArrayElementsType = dictionary["wordsToRemoveToGetArrayElementsType"] as? [String] - - if let headerFileDataData = dictionary["headerFileData"] as? NSDictionary{ + wordsToRemoveToGetArrayElementsType = dictionary["wordsToRemoveToGetArrayElementsType"] as? [String] + + if let headerFileDataData = dictionary["headerFileData"] as? NSDictionary { headerFileData = HeaderFileData(fromDictionary: headerFileDataData) } - + supportMutualRelationships = (dictionary["supportMutualRelationships"] as? NSString)?.boolValue - if let authorDictionary = dictionary["author"] as? NSDictionary{ + if let authorDictionary = dictionary["author"] as? NSDictionary { author = Author(fromDictionary: authorDictionary) } - } - - - + } } diff --git a/JSONExport/Property.swift b/JSONExport/Property.swift index eae73ab..d57a284 100755 --- a/JSONExport/Property.swift +++ b/JSONExport/Property.swift @@ -33,107 +33,100 @@ import Foundation /** -Represents all the meta data needed to export a JSON property in a valid syntax for the target language -*/ -class Property : Equatable{ - + Represents all the meta data needed to export a JSON property in a valid syntax for the target language + */ +class Property: Equatable { /** - The native name that is suitable to export the JSON property in the target language - */ - var nativeName : String - + The native name that is suitable to export the JSON property in the target language + */ + var nativeName: String + /** - The JSON property name to fetch the value of this property from a JSON object - */ - var jsonName : String - - var constName : String? - + The JSON property name to fetch the value of this property from a JSON object + */ + var jsonName: String + + var constName: String? + /** - The string representation for the property type - */ - var type : String - + The string representation for the property type + */ + var type: String + /** - Whether the property represents a custom type - */ - var isCustomClass : Bool - + Whether the property represents a custom type + */ + var isCustomClass: Bool + /** - Whether the property represents an array - */ - var isArray : Bool - + Whether the property represents an array + */ + var isArray: Bool + /** - The target language model - */ - var lang : LangModel - + The target language model + */ + var lang: LangModel + /** - A sample value which this property represents - */ - var sampleValue : AnyObject! - - + A sample value which this property represents + */ + var sampleValue: AnyObject! + /** - If this property is an array, this property should contain the type for its elements - */ - var elementsType = "" - + If this property is an array, this property should contain the type for its elements + */ + var elementsType = "" + /** - For array properties, depetermines if the elements type is a custom type - */ + For array properties, depetermines if the elements type is a custom type + */ var elementsAreOfCustomType = false - + /** - Returns a valid property declaration using the LangModel.instanceVarDefinition value - */ - func toString(_ forHeaderFile: Bool = false) -> String - { - var string : String! - if forHeaderFile{ - if lang.headerFileData.instanceVarWithSpeicalDefinition != nil && lang.headerFileData.typesNeedSpecialDefinition.index(of: type) != nil{ + Returns a valid property declaration using the LangModel.instanceVarDefinition value + */ + func toString(_ forHeaderFile: Bool = false) -> String { + var string: String! + if forHeaderFile { + if lang.headerFileData.instanceVarWithSpeicalDefinition != nil, lang.headerFileData.typesNeedSpecialDefinition.index(of: type) != nil { string = lang.headerFileData.instanceVarWithSpeicalDefinition - }else{ + } else { string = lang.headerFileData.instanceVarDefinition } - - - }else{ - if lang.instanceVarWithSpeicalDefinition != nil && lang.typesNeedSpecialDefinition.index(of: type) != nil{ + + } else { + if lang.instanceVarWithSpeicalDefinition != nil, lang.typesNeedSpecialDefinition.index(of: type) != nil { string = lang.instanceVarWithSpeicalDefinition - }else{ + } else { string = lang.instanceVarDefinition } } - + string = string.replacingOccurrences(of: varType, with: type) string = string.replacingOccurrences(of: varName, with: nativeName) string = string.replacingOccurrences(of: jsonKeyName, with: jsonName) return string } - - func toConstVar(_ className: String) -> String - { - var string : String! + + func toConstVar(_ className: String) -> String { + var string: String! if lang.constVarDefinition != nil { string = lang.constVarDefinition } else { string = "" } - self.constName = "k"+className+nativeName.uppercaseFirstChar() - + constName = "k" + className + nativeName.uppercaseFirstChar() + string = string.replacingOccurrences(of: constKeyName, with: constName!) string = string.replacingOccurrences(of: jsonKeyName, with: jsonName) return string } - - - /** - The designated initializer for the class - */ - init(jsonName: String, nativeName: String, type: String, isArray: Bool, isCustomClass: Bool, lang: LangModel) - { + + /** + The designated initializer for the class + */ + init(jsonName: String, nativeName: String, type: String, isArray: Bool, isCustomClass: Bool, lang: LangModel) { self.jsonName = jsonName.replacingOccurrences(of: " ", with: "") self.nativeName = nativeName.replacingOccurrences(of: " ", with: "") self.type = type @@ -141,25 +134,19 @@ class Property : Equatable{ self.isCustomClass = isCustomClass self.lang = lang } - - + /** - Convenience initializer which calls the designated initializer with isArray = false and isCustomClass = false - */ - convenience init(jsonName: String, nativeName: String, type: String, lang: LangModel){ + Convenience initializer which calls the designated initializer with isArray = false and isCustomClass = false + */ + convenience init(jsonName: String, nativeName: String, type: String, lang: LangModel) { self.init(jsonName: jsonName, nativeName: nativeName, type: type, isArray: false, isCustomClass: false, lang: lang) } - - - - } -//For Equatable implementation -func ==(lhs: Property, rhs: Property) -> Bool -{ +// For Equatable implementation +func == (lhs: Property, rhs: Property) -> Bool { var matched = ObjectIdentifier(lhs) == ObjectIdentifier(rhs) - if !matched{ + if !matched { matched = (lhs.nativeName == rhs.nativeName && lhs.jsonName == rhs.jsonName && lhs.type == rhs.type && lhs.isCustomClass == rhs.isCustomClass && lhs.isArray == rhs.isArray && lhs.elementsType == rhs.elementsType && lhs.elementsAreOfCustomType == rhs.elementsAreOfCustomType) } return matched diff --git a/JSONExport/SharedConstants.swift b/JSONExport/SharedConstants.swift index 83591f7..a6dda87 100755 --- a/JSONExport/SharedConstants.swift +++ b/JSONExport/SharedConstants.swift @@ -46,4 +46,3 @@ let lowerCaseModelName = "" let jsonKeyName = "" let constKeyName = "" let additionalCustomTypeProperty = "" - diff --git a/JSONExport/SharedUtilityMethods.swift b/JSONExport/SharedUtilityMethods.swift index b322001..c901289 100755 --- a/JSONExport/SharedUtilityMethods.swift +++ b/JSONExport/SharedUtilityMethods.swift @@ -8,114 +8,111 @@ import Foundation - /** -Creats and returns the type name for the passed value + Creats and returns the type name for the passed value -- parameter value: example value to figure out its type -- returns: the type name -*/ -func propertyTypeName(_ value : AnyObject, lang: LangModel) -> String -{ + - parameter value: example value to figure out its type + - returns: the type name + */ +func propertyTypeName(_ value: AnyObject, lang: LangModel) -> String { var name = "" - if value is NSArray{ - name = typeNameForArrayOfElements(value as! NSArray, lang:lang) - }else if value is NSNumber{ + if value is NSArray { + name = typeNameForArrayOfElements(value as! NSArray, lang: lang) + } else if value is NSNumber { name = typeForNumber(value as! NSNumber, lang: lang) - }else if value is NSString{ - let booleans : [String] = ["True", "true", "TRUE", "False", "false", "FALSE"] - if booleans.index(of: (value as! String)) != nil{ + } else if value is NSString { + let booleans: [String] = ["True", "true", "TRUE", "False", "false", "FALSE"] + if booleans.index(of: value as! String) != nil { name = lang.dataTypes.boolType - }else{ + } else { name = lang.dataTypes.stringType } - }else if value is NSNull{ + } else if value is NSNull { name = lang.genericType } - + return name } /** -Tries to figur out the type of the elements of the passed array and returns the type that can be used as the type of any element in the array + Tries to figur out the type of the elements of the passed array and returns the type that can be used as the type of any element in the array -- parameter elements: array to try to find out which type is suitable for its elements + - parameter elements: array to try to find out which type is suitable for its elements -- returns: typeName the type name as String -*/ + - returns: typeName the type name as String + */ -func typeNameForArrayElements(_ elements: NSArray, lang: LangModel) -> String{ - var typeName : String! +func typeNameForArrayElements(_ elements: NSArray, lang: LangModel) -> String { + var typeName: String! let genericType = lang.genericType - if elements.count == 0{ + if elements.count == 0 { typeName = genericType } - for element in elements{ + for element in elements { let currElementTypeName = propertyTypeName(element as AnyObject, lang: lang) - - if typeName == nil{ + + if typeName == nil { typeName = currElementTypeName - - }else{ - if typeName != currElementTypeName{ + + } else { + if typeName != currElementTypeName { typeName = genericType break } } } - + return typeName } /** -Tries to figur out the type of the elements of the passed array and returns the type of the array that can hold these values + Tries to figur out the type of the elements of the passed array and returns the type of the array that can hold these values -- parameter elements: array to try to find out which type is suitable for its elements + - parameter elements: array to try to find out which type is suitable for its elements -- returns: the type name -*/ -func typeNameForArrayOfElements(_ elements: NSArray, lang: LangModel) -> String{ - var typeName : String! + - returns: the type name + */ +func typeNameForArrayOfElements(_ elements: NSArray, lang: LangModel) -> String { + var typeName: String! let genericType = lang.arrayType.replacingOccurrences(of: elementType, with: lang.genericType) - if elements.count == 0{ + if elements.count == 0 { typeName = genericType } - for element in elements{ + for element in elements { let currElementTypeName = propertyTypeName(element as AnyObject, lang: lang) - + let arrayTypeName = lang.arrayType.replacingOccurrences(of: elementType, with: currElementTypeName) - - if typeName == nil{ + + if typeName == nil { typeName = arrayTypeName - - }else{ - if typeName != arrayTypeName{ + + } else { + if typeName != arrayTypeName { typeName = genericType break } } } - + return typeName } /** -Returns one of the possible types for any numeric value (int, float, double, etc...) + Returns one of the possible types for any numeric value (int, float, double, etc...) -- parameter number: the numeric value -- returns: the type name -*/ -func typeForNumber(_ number : NSNumber, lang: LangModel) -> String -{ + - parameter number: the numeric value + - returns: the type name + */ +func typeForNumber(_ number: NSNumber, lang: LangModel) -> String { let numberType = CFNumberGetType(number as CFNumber) - - var typeName : String! - switch numberType{ + + var typeName: String! + switch numberType { case .charType: - if (number.int32Value == 0 || number.int32Value == 1){ - //it seems to be boolean + if number.int32Value == 0 || number.int32Value == 1 { + // it seems to be boolean typeName = lang.dataTypes.boolType - }else{ + } else { typeName = lang.dataTypes.characterType } case .shortType, .intType: @@ -129,24 +126,22 @@ func typeForNumber(_ number : NSNumber, lang: LangModel) -> String default: typeName = lang.dataTypes.intType } - + return typeName } - /** -Creates and returns a dictionary who is built up by combining all the dictionary elements in the passed array. + Creates and returns a dictionary who is built up by combining all the dictionary elements in the passed array. -- parameter array: array of dictionaries. -- returns: dictionary that combines all the dictionary elements in the array. -*/ -func unionDictionaryFromArrayElements(_ array: NSArray) -> NSDictionary -{ + - parameter array: array of dictionaries. + - returns: dictionary that combines all the dictionary elements in the array. + */ +func unionDictionaryFromArrayElements(_ array: NSArray) -> NSDictionary { let dictionary = NSMutableDictionary() - for item in array{ - if let dic = item as? NSDictionary{ - //loop all over its keys - for key in dic.allKeys as! [String]{ + for item in array { + if let dic = item as? NSDictionary { + // loop all over its keys + for key in dic.allKeys as! [String] { dictionary[key] = dic[key] } } @@ -154,43 +149,33 @@ func unionDictionaryFromArrayElements(_ array: NSArray) -> NSDictionary return dictionary } - - - /** -Cleans up the passed string from any control characters. + Cleans up the passed string from any control characters. -- parameter string: the string to be cleaned up -- returns: a clean version of the passed string -*/ + - parameter string: the string to be cleaned up + - returns: a clean version of the passed string + */ -func stringByRemovingControlCharacters(_ string: String) -> String -{ +func stringByRemovingControlCharacters(_ string: String) -> String { let controlChars = CharacterSet.controlCharacters var range = string.rangeOfCharacter(from: controlChars) - var cleanString = string; - while range != nil && !range!.isEmpty{ + var cleanString = string + while range != nil, !range!.isEmpty { cleanString = cleanString.replacingCharacters(in: range!, with: "") range = cleanString.rangeOfCharacter(from: controlChars) } - + return cleanString - } - - -func runOnBackground(_ task: @escaping () -> Void) -{ +func runOnBackground(_ task: @escaping () -> Void) { DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async { - task(); + task() } } -func runOnUiThread(_ task: @escaping () -> Void) -{ - DispatchQueue.main.async(execute: { () -> Void in - task(); - }) +func runOnUiThread(_ task: @escaping () -> Void) { + DispatchQueue.main.async { () -> Void in + task() + } } - diff --git a/JSONExport/StringExtension.swift b/JSONExport/StringExtension.swift index 6a3e5ca..924acc7 100755 --- a/JSONExport/StringExtension.swift +++ b/JSONExport/StringExtension.swift @@ -32,70 +32,66 @@ import Foundation -extension String{ +extension String { /** - Very simple method converts the last characters of a string to convert from plural to singular. For example "parties" will be changed to "party" and "stars" will be changed to "star" - The method does not handle any special cases, like uncountable name i.e "people" will not be converted to "person" - */ - func toSingular() -> String - { + Very simple method converts the last characters of a string to convert from plural to singular. For example "parties" will be changed to "party" and "stars" will be changed to "star" + The method does not handle any special cases, like uncountable name i.e "people" will not be converted to "person" + */ + func toSingular() -> String { var singular = self - let length = self.count + let length = count if length > 3 { - let range = self.index(self.endIndex, offsetBy: -3).. 2 { - let range = self.index(self.endIndex, offsetBy: -1).. String{ - if self.count > 0 { - let range = self.startIndex.. String { + if count > 0 { + let range = startIndex ..< index(startIndex, offsetBy: 1) + let firstLowerChar = self[range].lowercased() - - return self.replacingCharacters(in: range, with: firstLowerChar) - }else{ + + return replacingCharacters(in: range, with: firstLowerChar) + } else { return self } - } - + /** - Converts the first character to its upper case version - - - returns: the converted version - */ - func uppercaseFirstChar() -> String{ - if self.count > 0 { - let range = startIndex.. String { + if count > 0 { + let range = startIndex ..< index(startIndex, offsetBy: 1) + let firstUpperChar = self[range].uppercased() - - return self.replacingCharacters(in: range, with: firstUpperChar) - }else{ + + return replacingCharacters(in: range, with: firstUpperChar) + } else { return self } - } } diff --git a/JSONExport/UtilityMethod.swift b/JSONExport/UtilityMethod.swift index 38a4512..79ac02c 100755 --- a/JSONExport/UtilityMethod.swift +++ b/JSONExport/UtilityMethod.swift @@ -7,36 +7,31 @@ import Foundation -class UtilityMethod{ +class UtilityMethod { + var body: String! + var bodyEnd: String! + var bodyStart: String! + var comment: String! + var forEachArrayOfCustomTypeProperty: String! + var forEachProperty: String! + var forEachCustomTypeProperty: String! + var returnStatement: String! + var signature: String! + var forEachPropertyWithSpecialStoringNeeds: String! - - var body : String! - var bodyEnd : String! - var bodyStart : String! - var comment : String! - var forEachArrayOfCustomTypeProperty : String! - var forEachProperty : String! - var forEachCustomTypeProperty : String! - var returnStatement : String! - var signature : String! - var forEachPropertyWithSpecialStoringNeeds : String! - - /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary){ - forEachCustomTypeProperty = dictionary["forEachCustomTypeProperty"] as? String - body = dictionary["body"] as? String - bodyEnd = dictionary["bodyEnd"] as? String - bodyStart = dictionary["bodyStart"] as? String - comment = dictionary["comment"] as? String - forEachArrayOfCustomTypeProperty = dictionary["forEachArrayOfCustomTypeProperty"] as? String - forEachProperty = dictionary["forEachProperty"] as? String - returnStatement = dictionary["returnStatement"] as? String - signature = dictionary["signature"] as? String + /** + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary) { + forEachCustomTypeProperty = dictionary["forEachCustomTypeProperty"] as? String + body = dictionary["body"] as? String + bodyEnd = dictionary["bodyEnd"] as? String + bodyStart = dictionary["bodyStart"] as? String + comment = dictionary["comment"] as? String + forEachArrayOfCustomTypeProperty = dictionary["forEachArrayOfCustomTypeProperty"] as? String + forEachProperty = dictionary["forEachProperty"] as? String + returnStatement = dictionary["returnStatement"] as? String + signature = dictionary["signature"] as? String forEachPropertyWithSpecialStoringNeeds = dictionary["forEachPropertyWithSpecialStoringNeeds"] as? String - } - - - -} \ No newline at end of file + } +} diff --git a/JSONExport/ViewController.swift b/JSONExport/ViewController.swift index fe87634..db40a34 100755 --- a/JSONExport/ViewController.swift +++ b/JSONExport/ViewController.swift @@ -34,61 +34,58 @@ import Cocoa class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTableViewDelegate, NSTableViewDataSource, NSTextViewDelegate { - - //Shows the list of files' preview - @IBOutlet weak var tableView: NSTableView! - - //Connected to the top right corner to show the current parsing status - @IBOutlet weak var statusTextField: NSTextField! - - //Connected to the save button - @IBOutlet weak var saveButton: NSButton! - - //Connected to the JSON input text view + // Shows the list of files' preview + @IBOutlet var tableView: NSTableView! + + // Connected to the top right corner to show the current parsing status + @IBOutlet var statusTextField: NSTextField! + + // Connected to the save button + @IBOutlet var saveButton: NSButton! + + // Connected to the JSON input text view @IBOutlet var sourceText: NSTextView! - - //Connected to the scroll view which wraps the sourceText - @IBOutlet weak var scrollView: NSScrollView! - - //Connected to Constructors check box - @IBOutlet weak var generateConstructors: NSButtonCell! - - //Connected to Utility Methods check box - @IBOutlet weak var generateUtilityMethods: NSButtonCell! - - //Connected to root class name field - @IBOutlet weak var classNameField: NSTextFieldCell! - - //Connected to parent class name field - @IBOutlet weak var parentClassName: NSTextField! - - //Connected to class prefix field - @IBOutlet weak var classPrefixField: NSTextField! - - //Connected to the first line statement field - @IBOutlet weak var firstLineField: NSTextField! - - //Connected to the languages pop up - @IBOutlet weak var languagesPopup: NSPopUpButton! - - - //Holds the currently selected language - var selectedLang : LangModel! - - //Returns the title of the selected language in the languagesPopup - //Call only from main thread - var selectedLanguageName : String - { - assert(Thread.isMainThread); + + // Connected to the scroll view which wraps the sourceText + @IBOutlet var scrollView: NSScrollView! + + // Connected to Constructors check box + @IBOutlet var generateConstructors: NSButtonCell! + + // Connected to Utility Methods check box + @IBOutlet var generateUtilityMethods: NSButtonCell! + + // Connected to root class name field + @IBOutlet var classNameField: NSTextFieldCell! + + // Connected to parent class name field + @IBOutlet var parentClassName: NSTextField! + + // Connected to class prefix field + @IBOutlet var classPrefixField: NSTextField! + + // Connected to the first line statement field + @IBOutlet var firstLineField: NSTextField! + + // Connected to the languages pop up + @IBOutlet var languagesPopup: NSPopUpButton! + + // Holds the currently selected language + var selectedLang: LangModel! + + // Returns the title of the selected language in the languagesPopup + // Call only from main thread + var selectedLanguageName: String { + assert(Thread.isMainThread) return languagesPopup.titleOfSelectedItem! } - - //Should hold list of supported languages, where the key is the language name and the value is LangModel instance - var langs : [String : LangModel] = [String : LangModel]() - - //Holds list of the generated files - var files : [FileRepresenter] = [FileRepresenter]() - + + // Should hold list of supported languages, where the key is the language name and the value is LangModel instance + var langs: [String: LangModel] = [String: LangModel]() + + // Holds list of the generated files + var files: [FileRepresenter] = [FileRepresenter]() + override func viewDidLoad() { super.viewDidLoad() saveButton.isEnabled = false @@ -98,76 +95,70 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl setLanguagesSelection() loadLastSelectedLanguage() updateUIFieldsForSelectedLanguage() - self.tableView.backgroundColor = .clear + tableView.backgroundColor = .clear } - + /** Sets the values of languagesPopup items' titles */ - func setLanguagesSelection() - { + func setLanguagesSelection() { let langNames = Array(langs.keys).sorted() languagesPopup.removeAllItems() languagesPopup.addItems(withTitles: langNames) - } - + /** Sets the needed configurations for show the line numbers in the input text view */ - func setupNumberedTextView() - { + func setupNumberedTextView() { let lineNumberView = NoodleLineNumberView(scrollView: scrollView) scrollView.hasHorizontalRuler = false scrollView.hasVerticalRuler = true scrollView.verticalRulerView = lineNumberView scrollView.rulersVisible = true sourceText.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize) - } - + /** Updates the visible fields according to the selected language */ - func updateUIFieldsForSelectedLanguage() - { + func updateUIFieldsForSelectedLanguage() { loadSelectedLanguageModel() - if selectedLang.supportsFirstLineStatement != nil && selectedLang.supportsFirstLineStatement!{ + if selectedLang.supportsFirstLineStatement != nil && selectedLang.supportsFirstLineStatement! { firstLineField.isHidden = false firstLineField.placeholderString = selectedLang.firstLineHint - }else{ + } else { firstLineField.isHidden = true } - - if selectedLang.modelDefinitionWithParent != nil || selectedLang.headerFileData?.modelDefinitionWithParent != nil{ + + if selectedLang.modelDefinitionWithParent != nil || selectedLang.headerFileData?.modelDefinitionWithParent != nil { parentClassName.isHidden = false - }else{ + } else { parentClassName.isHidden = true } } - + /** Loads last selected language by user */ - func loadLastSelectedLanguage() - { - guard let lastSelectedLanguage = UserDefaults.standard.value(forKey: "selectedLanguage") as? String else{ + func loadLastSelectedLanguage() { + guard let lastSelectedLanguage = UserDefaults.standard.value(forKey: "selectedLanguage") as? String else { return } - - if langs[lastSelectedLanguage] != nil{ + + if langs[lastSelectedLanguage] != nil { languagesPopup.selectItem(withTitle: lastSelectedLanguage) } } - - //MARK: - Handling pre defined languages - func loadSupportedLanguages() - { - if let langFiles = Bundle.main.urls(forResourcesWithExtension: "json", subdirectory: nil){ - for langFile in langFiles{ - if let data = try? Data(contentsOf: langFile), let langDictionary = (try? JSONSerialization.jsonObject(with: data, options: [])) as? NSDictionary{ + + // MARK: - Handling pre defined languages + + func loadSupportedLanguages() { + if let langFiles = Bundle.main.urls(forResourcesWithExtension: "json", subdirectory: nil) { + for langFile in langFiles { + if let data = try? Data(contentsOf: langFile), let langDictionary = (try? JSONSerialization.jsonObject(with: data, options: [])) as? NSDictionary { let lang = LangModel(fromDictionary: langDictionary) - if langs[lang.displayLangName] != nil{ + if langs[lang.displayLangName] != nil { continue } langs[lang.displayLangName] = lang @@ -176,106 +167,89 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } } - // MARK: - parse the json file - func parseJSONData(jsonData: Data!) - { + + func parseJSONData(jsonData: Data!) { let jsonString = String(data: jsonData, encoding: .utf8) - + sourceText.string = jsonString! } - - //MARK: - Handlind events - - @IBAction func openJSONFiles(sender: AnyObject) - { - let oPanel: NSOpenPanel = NSOpenPanel() - oPanel.canChooseDirectories = false - oPanel.canChooseFiles = true - oPanel.allowsMultipleSelection = false - oPanel.allowedFileTypes = ["json","JSON"] - oPanel.prompt = "Choose JSON file" - - oPanel.beginSheetModal(for: self.view.window!) { button in - if button.rawValue == NSFileHandlingPanelOKButton { - let jsonPath = oPanel.urls.first!.path - let fileHandle = FileHandle(forReadingAtPath: jsonPath) - let urlStr:String = oPanel.urls.first!.lastPathComponent - self.classNameField.stringValue = urlStr.replacingOccurrences(of: ".json", with: "") - self.parseJSONData(jsonData: (fileHandle!.readDataToEndOfFile())) - } - } - } - - - @IBAction func toggleConstructors(_ sender: AnyObject) - { + + // MARK: - Handlind events + + @IBAction func openJSONFiles(sender _: AnyObject) { + let oPanel: NSOpenPanel = NSOpenPanel() + oPanel.canChooseDirectories = false + oPanel.canChooseFiles = true + oPanel.allowsMultipleSelection = false + oPanel.allowedFileTypes = ["json", "JSON"] + oPanel.prompt = "Choose JSON file" + + oPanel.beginSheetModal(for: view.window!) { button in + if button.rawValue == NSFileHandlingPanelOKButton { + let jsonPath = oPanel.urls.first!.path + let fileHandle = FileHandle(forReadingAtPath: jsonPath) + let urlStr: String = oPanel.urls.first!.lastPathComponent + self.classNameField.stringValue = urlStr.replacingOccurrences(of: ".json", with: "") + self.parseJSONData(jsonData: fileHandle!.readDataToEndOfFile()) + } + } + } + + @IBAction func toggleConstructors(_: AnyObject) { generateClasses() } - - - @IBAction func toggleUtilities(_ sender: AnyObject) - { + + @IBAction func toggleUtilities(_: AnyObject) { generateClasses() } - - @IBAction func rootClassNameChanged(_ sender: AnyObject) { + + @IBAction func rootClassNameChanged(_: AnyObject) { generateClasses() } - - @IBAction func parentClassNameChanged(_ sender: AnyObject) - { + + @IBAction func parentClassNameChanged(_: AnyObject) { generateClasses() } - - - @IBAction func classPrefixChanged(_ sender: AnyObject) - { + + @IBAction func classPrefixChanged(_: AnyObject) { generateClasses() } - - - @IBAction func selectedLanguageChanged(_ sender: AnyObject) - { + + @IBAction func selectedLanguageChanged(_: AnyObject) { updateUIFieldsForSelectedLanguage() generateClasses() DispatchQueue.main.async { UserDefaults.standard.set(self.selectedLanguageName, forKey: "selectedLanguage") } - } - - - @IBAction func firstLineChanged(_ sender: AnyObject) - { + + @IBAction func firstLineChanged(_: AnyObject) { generateClasses() } - - //MARK: - NSTextDelegate - - func textDidChange(_ notification: Notification) { + + // MARK: - NSTextDelegate + + func textDidChange(_: Notification) { generateClasses() } - - - //MARK: - Language selection handling - func loadSelectedLanguageModel() - { - selectedLang = langs[self.selectedLanguageName] + + // MARK: - Language selection handling + + func loadSelectedLanguageModel() { + selectedLang = langs[self.selectedLanguageName] } - - - //MARK: - NSUserNotificationCenterDelegate - func userNotificationCenter(_ center: NSUserNotificationCenter, - shouldPresent notification: NSUserNotification) -> Bool - { + + // MARK: - NSUserNotificationCenterDelegate + + func userNotificationCenter(_: NSUserNotificationCenter, + shouldPresent _: NSUserNotification) -> Bool { return true } - - - //MARK: - Showing the open panel and save files - @IBAction func saveFiles(_ sender: AnyObject) - { + + // MARK: - Showing the open panel and save files + + @IBAction func saveFiles(_: AnyObject) { let openPanel = NSOpenPanel() openPanel.allowsOtherFileTypes = false openPanel.treatsFilePackagesAsDirectories = false @@ -283,135 +257,125 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl openPanel.canChooseDirectories = true openPanel.canCreateDirectories = true openPanel.prompt = "Choose" - openPanel.beginSheetModal(for: self.view.window!){ button in - if button.rawValue == NSFileHandlingPanelOKButton{ - self.saveToPath(openPanel.url!.path) - self.showDoneSuccessfully() - } - } + openPanel.beginSheetModal(for: view.window!) { button in + if button.rawValue == NSFileHandlingPanelOKButton { + self.saveToPath(openPanel.url!.path) + self.showDoneSuccessfully() + } + } } - - + /** Saves all the generated files in the specified path - + - parameter path: in which to save the files */ - func saveToPath(_ path : String) - { - var error : NSError? - for file in files{ + func saveToPath(_ path: String) { + var error: NSError? + for file in files { var fileContent = file.fileContent - if fileContent == ""{ + if fileContent == "" { fileContent = file.toString() } var fileExtension = selectedLang.fileExtension - if file is HeaderFileRepresenter{ + if file is HeaderFileRepresenter { fileExtension = selectedLang.headerFileData.headerFileExtension } let filePath = "\(path)/\(file.className).\(fileExtension)" - + do { try fileContent.write(toFile: filePath, atomically: false, encoding: String.Encoding.utf8) } catch let error1 as NSError { error = error1 } - if error != nil{ + if error != nil { showError(error!) break } } } - - - //MARK: - Messages + + // MARK: - Messages + /** Shows the top right notification. Call it after saving the files successfully */ - func showDoneSuccessfully() - { + func showDoneSuccessfully() { let notification = NSUserNotification() notification.title = "Success!" notification.informativeText = "Your \(selectedLang.langName) model files have been generated successfully." notification.deliveryDate = Date() - + let center = NSUserNotificationCenter.default center.delegate = self center.deliver(notification) } - + /** Shows an NSAlert for the passed error */ - func showError(_ error: NSError!) - { - if error == nil{ - return; + func showError(_ error: NSError!) { + if error == nil { + return } let alert = NSAlert(error: error) alert.runModal() } - + /** Shows the passed error status message */ - func showErrorStatus(_ errorMessage: String) - { - + func showErrorStatus(_ errorMessage: String) { statusTextField.textColor = NSColor.red statusTextField.stringValue = errorMessage } - + /** Shows the passed success status message */ - func showSuccessStatus(_ successMessage: String) - { - + func showSuccessStatus(_ successMessage: String) { statusTextField.textColor = NSColor.green statusTextField.stringValue = successMessage } - - - - //MARK: - Generate files content + + // MARK: - Generate files content + /** Validates the sourceText string input, and takes any needed action to generate the model classes and view them in the preview panel */ - func generateClasses() - { + func generateClasses() { saveButton.isEnabled = false var str = sourceText.string - - if str.count == 0{ - runOnUiThread{ - //Nothing to do, just clear any generated files + + if str.count == 0 { + runOnUiThread { + // Nothing to do, just clear any generated files self.files.removeAll(keepingCapacity: false) self.tableView.reloadData() } - return; + return } var rootClassName = classNameField.stringValue - if rootClassName.count == 0{ + if rootClassName.count == 0 { rootClassName = "RootClass" } sourceText.isEditable = false - //Do the lengthy process in background, it takes time with more complicated JSONs + // Do the lengthy process in background, it takes time with more complicated JSONs runOnBackground { str = stringByRemovingControlCharacters(str) - if let data = str.data(using: String.Encoding.utf8){ - var error : NSError? + if let data = str.data(using: String.Encoding.utf8) { + var error: NSError? do { - let jsonData : Any = try JSONSerialization.jsonObject(with: data, options: []) - var json : NSDictionary! - if jsonData is NSDictionary{ - //fine nothing to do - json = jsonData as? NSDictionary - }else{ + let jsonData: Any = try JSONSerialization.jsonObject(with: data, options: []) + var json: NSDictionary! + if jsonData is NSDictionary { + // fine nothing to do + json = jsonData as? NSDictionary + } else { json = unionDictionaryFromArrayElements(jsonData as! NSArray) } - - runOnUiThread{ + + runOnUiThread { self.loadSelectedLanguageModel() self.files.removeAll(keepingCapacity: false) let fileGenerator = self.prepareAndGetFilesBuilder() @@ -421,35 +385,34 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl self.sourceText.isEditable = true self.showSuccessStatus("Valid JSON structure") self.saveButton.isEnabled = true - + self.tableView.reloadData() self.tableView.layout() } } catch let error1 as NSError { error = error1 - runOnUiThread({ () -> Void in + runOnUiThread { () -> Void in self.sourceText.isEditable = true self.saveButton.isEnabled = false - if error != nil{ + if error != nil { print(error!) } self.showErrorStatus("It seems your JSON object is not valid!") - }) - + } + } catch { fatalError() } } } } - + /** Creates and returns an instance of FilesContentBuilder. It also configure the values from the UI components to the instance. I.e includeConstructors - + - returns: instance of configured FilesContentBuilder */ - func prepareAndGetFilesBuilder() -> FilesContentBuilder - { + func prepareAndGetFilesBuilder() -> FilesContentBuilder { let filesBuilder = FilesContentBuilder.instance filesBuilder.includeConstructors = (generateConstructors.state == NSControl.StateValue.on) filesBuilder.includeUtilities = (generateUtilityMethods.state == NSControl.StateValue.on) @@ -459,27 +422,20 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl filesBuilder.parentClassName = parentClassName.stringValue return filesBuilder } - - - - - //MARK: - NSTableViewDataSource - func numberOfRows(in tableView: NSTableView) -> Int - { + + // MARK: - NSTableViewDataSource + + func numberOfRows(in _: NSTableView) -> Int { return files.count } - - - //MARK: - NSTableViewDelegate - func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? - { + + // MARK: - NSTableViewDelegate + + func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? { let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier("fileCell"), owner: self) as! FilePreviewCell let file = files[row] cell.file = file - + return cell } - - - } From 54e9ead1e9708c0366c964331f51d7b270246802 Mon Sep 17 00:00:00 2001 From: Pawan Joshi Date: Thu, 23 Jul 2020 10:55:39 +0530 Subject: [PATCH 24/24] Formatting changed for some swift model jsons --- .gitignore | 0 .../UserInterfaceState.xcuserstate | Bin 22011 -> 0 bytes .../UserInterfaceState.xcuserstate | Bin 18035 -> 0 bytes .../UserInterfaceState.xcuserstate | Bin 14281 -> 0 bytes .../UserInterfaceState.xcuserstate | Bin 33880 -> 0 bytes .../UserInterfaceState.xcuserstate | Bin 22384 -> 0 bytes .../xcschemes/JSONExport.xcscheme | 91 ---- .../xcschemes/xcschememanagement.plist | 22 - .../xcschemes/xcschememanagement.plist | 14 - .../xcschemes/xcschememanagement.plist | 14 - .../xcdebugger/Breakpoints_v2.xcbkptlist | 5 - .../xcschemes/JSONExport.xcscheme | 91 ---- .../xcschemes/xcschememanagement.plist | 22 - JSONExport/AppDelegate.swift | 10 +- JSONExport/Author.swift | 43 +- JSONExport/Constructor.swift | 52 +- JSONExport/DataType.swift | 102 ++-- JSONExport/FileContentBuilder.swift | 398 ++++++++------- JSONExport/FilePreviewCell.swift | 62 ++- JSONExport/FileRepresenter.swift | 480 ++++++++++-------- JSONExport/HeaderFileData.swift | 46 +- JSONExport/HeaderFileRepresenter.swift | 144 +++--- .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/icon_128x128.png | Bin .../AppIcon.appiconset/icon_128x128@2x.png | Bin .../AppIcon.appiconset/icon_16x16.png | Bin .../AppIcon.appiconset/icon_16x16@2x.png | Bin .../AppIcon.appiconset/icon_256x256.png | Bin .../AppIcon.appiconset/icon_256x256@2x.png | Bin .../AppIcon.appiconset/icon_32x32.png | Bin .../AppIcon.appiconset/icon_32x32@2x.png | Bin .../AppIcon.appiconset/icon_512x512.png | Bin .../AppIcon.appiconset/icon_512x512@2x.png | Bin JSONExport/LangModel.swift | 166 +++--- JSONExport/Property.swift | 151 +++--- JSONExport/SharedConstants.swift | 1 + JSONExport/SharedUtilityMethods.swift | 171 ++++--- JSONExport/StringExtension.swift | 76 +-- .../Supported Languages/Swift-Outlaw.json | 0 .../Supported Languages/Swift-Struct.json | 10 +- .../Supported Languages/SwiftyJSON-Class.json | 40 +- JSONExport/Swift-Codable-Unwrapped.json | 0 JSONExport/UtilityMethod.swift | 57 ++- JSONExport/ViewController.swift | 435 +++++++++------- 44 files changed, 1334 insertions(+), 1369 deletions(-) mode change 100644 => 100755 .gitignore delete mode 100644 JSONExport.xcodeproj/project.xcworkspace/xcuserdata/Robin.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 JSONExport.xcodeproj/project.xcworkspace/xcuserdata/binaryboy.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 JSONExport.xcodeproj/project.xcworkspace/xcuserdata/narleiamoreira.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 JSONExport.xcodeproj/project.xcworkspace/xcuserdata/serhii-londar.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 JSONExport.xcodeproj/project.xcworkspace/xcuserdata/zhangrunliang.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 JSONExport.xcodeproj/xcuserdata/binaryboy.xcuserdatad/xcschemes/JSONExport.xcscheme delete mode 100644 JSONExport.xcodeproj/xcuserdata/binaryboy.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 JSONExport.xcodeproj/xcuserdata/narleiamoreira.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 JSONExport.xcodeproj/xcuserdata/serhii-londar.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcschemes/JSONExport.xcscheme delete mode 100644 JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcschemes/xcschememanagement.plist mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/Contents.json mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128.png mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16.png mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256.png mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32.png mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512.png mode change 100644 => 100755 JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png mode change 100644 => 100755 JSONExport/Supported Languages/Swift-Outlaw.json mode change 100644 => 100755 JSONExport/Swift-Codable-Unwrapped.json diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/Robin.xcuserdatad/UserInterfaceState.xcuserstate b/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/Robin.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index ed71e6e7c5c0c2d14cf025b13f271b785923474c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22011 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 diff --git a/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/binaryboy.xcuserdatad/UserInterfaceState.xcuserstate b/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/binaryboy.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 9f79c1eed77314afb9c3ef7d07c999b0cdc188c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18035 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 diff --git a/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/serhii-londar.xcuserdatad/UserInterfaceState.xcuserstate b/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/serhii-londar.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 46a37a2a6429fceb6e602df7564f20c3eae1a6b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33880 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 diff --git a/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/zhangrunliang.xcuserdatad/UserInterfaceState.xcuserstate b/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/zhangrunliang.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 203ca51ef24b1c13b1cf568f34337746084eb61a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22384 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�oq8!+s^)12h_4a%-uIdAZ5lTv!xB#-xYu} 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 X{!IBxVs?(A#J}7z@vrOu^1c5Ln8mBO diff --git a/JSONExport.xcodeproj/xcuserdata/binaryboy.xcuserdatad/xcschemes/JSONExport.xcscheme b/JSONExport.xcodeproj/xcuserdata/binaryboy.xcuserdatad/xcschemes/JSONExport.xcscheme deleted file mode 100644 index 657c867..0000000 --- a/JSONExport.xcodeproj/xcuserdata/binaryboy.xcuserdatad/xcschemes/JSONExport.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/JSONExport.xcodeproj/xcuserdata/binaryboy.xcuserdatad/xcschemes/xcschememanagement.plist b/JSONExport.xcodeproj/xcuserdata/binaryboy.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index c31d8f8..0000000 --- a/JSONExport.xcodeproj/xcuserdata/binaryboy.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - JSONExport.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - E2FA87B41A059AC100648EB6 - - primary - - - - - diff --git a/JSONExport.xcodeproj/xcuserdata/narleiamoreira.xcuserdatad/xcschemes/xcschememanagement.plist b/JSONExport.xcodeproj/xcuserdata/narleiamoreira.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 1ccfc36..0000000 --- a/JSONExport.xcodeproj/xcuserdata/narleiamoreira.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - JSONExport.xcscheme - - orderHint - 0 - - - - diff --git a/JSONExport.xcodeproj/xcuserdata/serhii-londar.xcuserdatad/xcschemes/xcschememanagement.plist b/JSONExport.xcodeproj/xcuserdata/serhii-londar.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 1ccfc36..0000000 --- a/JSONExport.xcodeproj/xcuserdata/serhii-londar.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - JSONExport.xcscheme - - orderHint - 0 - - - - diff --git a/JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index fe2b454..0000000 --- a/JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcschemes/JSONExport.xcscheme b/JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcschemes/JSONExport.xcscheme deleted file mode 100644 index 245983f..0000000 --- a/JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcschemes/JSONExport.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcschemes/xcschememanagement.plist b/JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index c31d8f8..0000000 --- a/JSONExport.xcodeproj/xcuserdata/zhangrunliang.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - JSONExport.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - E2FA87B41A059AC100648EB6 - - primary - - - - - diff --git a/JSONExport/AppDelegate.swift b/JSONExport/AppDelegate.swift index 566a90a..3c5e3de 100755 --- a/JSONExport/AppDelegate.swift +++ b/JSONExport/AppDelegate.swift @@ -34,11 +34,17 @@ import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - func applicationDidFinishLaunching(_: Notification) { + + + + func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application } - func applicationWillTerminate(_: Notification) { + func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application } + + } + diff --git a/JSONExport/Author.swift b/JSONExport/Author.swift index 7837e43..9101b20 100755 --- a/JSONExport/Author.swift +++ b/JSONExport/Author.swift @@ -7,60 +7,69 @@ import Foundation -class Author: NSObject, NSCoding { - var website: String! - var email: String! - var name: String! +class Author : NSObject, NSCoding{ + + var website : String! + var email : String! + var name : String! + + /** * Instantiate the instance using the passed dictionary values to set the properties values */ - init(fromDictionary dictionary: NSDictionary) { + init(fromDictionary dictionary: NSDictionary){ website = dictionary["website"] as? String email = dictionary["email"] as? String name = dictionary["name"] as? String } - + /** * Returns all the available property values in the form of NSDictionary object where the key is the approperiate json key and the value is the value of the corresponding property */ - func toDictionary() -> NSDictionary { + func toDictionary() -> NSDictionary + { let dictionary = NSMutableDictionary() - if website != nil { + if website != nil{ dictionary["website"] = website } - if email != nil { + if email != nil{ dictionary["email"] = email } - if name != nil { + if name != nil{ dictionary["name"] = name } return dictionary } - + /** * NSCoding required initializer. * Fills the data from the passed decoder */ - @objc required init(coder aDecoder: NSCoder) { + @objc required init(coder aDecoder: NSCoder) + { website = aDecoder.decodeObject(forKey: "website") as? String email = aDecoder.decodeObject(forKey: "email") as? String name = aDecoder.decodeObject(forKey: "name") as? String + } - + /** * NSCoding required method. * Encodes mode properties into the decoder */ - @objc func encode(with aCoder: NSCoder) { - if website != nil { + @objc func encode(with aCoder: NSCoder) + { + if website != nil{ aCoder.encode(website, forKey: "website") } - if email != nil { + if email != nil{ aCoder.encode(email, forKey: "email") } - if name != nil { + if name != nil{ aCoder.encode(name, forKey: "name") } + } + } diff --git a/JSONExport/Constructor.swift b/JSONExport/Constructor.swift index b45be55..194903f 100755 --- a/JSONExport/Constructor.swift +++ b/JSONExport/Constructor.swift @@ -7,29 +7,33 @@ import Foundation -class Constructor { - var bodyEnd: String! - var bodyStart: String! - var comment: String! - var fetchArrayOfCustomTypePropertyFromMap: String! - var fetchArrayOfBasicTypePropertyFromMap: String! - var fetchBasicTypePropertyFromMap: String! - var fetchBasicTypeWithSpecialNeedsPropertyFromMap: String! - var fetchCustomTypePropertyFromMap: String! - var signature: String! +class Constructor{ - /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary) { - bodyEnd = dictionary["bodyEnd"] as? String - bodyStart = dictionary["bodyStart"] as? String - comment = dictionary["comment"] as? String - fetchArrayOfCustomTypePropertyFromMap = dictionary["fetchArrayOfCustomTypePropertyFromMap"] as? String + var bodyEnd : String! + var bodyStart : String! + var comment : String! + var fetchArrayOfCustomTypePropertyFromMap : String! + var fetchArrayOfBasicTypePropertyFromMap : String! + var fetchBasicTypePropertyFromMap : String! + var fetchBasicTypeWithSpecialNeedsPropertyFromMap : String! + var fetchCustomTypePropertyFromMap : String! + var signature : String! + + + /** + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary){ + bodyEnd = dictionary["bodyEnd"] as? String + bodyStart = dictionary["bodyStart"] as? String + comment = dictionary["comment"] as? String + fetchArrayOfCustomTypePropertyFromMap = dictionary["fetchArrayOfCustomTypePropertyFromMap"] as? String fetchArrayOfBasicTypePropertyFromMap = dictionary["fetchArrayOfBasicTypePropertyFromMap"] as? String - fetchBasicTypePropertyFromMap = dictionary["fetchBasicTypePropertyFromMap"] as? String - fetchBasicTypeWithSpecialNeedsPropertyFromMap = dictionary["fetchBasicTypeWithSpecialNeedsPropertyFromMap"] as? String - fetchCustomTypePropertyFromMap = dictionary["fetchCustomTypePropertyFromMap"] as? String - signature = dictionary["signature"] as? String - } -} + fetchBasicTypePropertyFromMap = dictionary["fetchBasicTypePropertyFromMap"] as? String + fetchBasicTypeWithSpecialNeedsPropertyFromMap = dictionary["fetchBasicTypeWithSpecialNeedsPropertyFromMap"] as? String + fetchCustomTypePropertyFromMap = dictionary["fetchCustomTypePropertyFromMap"] as? String + signature = dictionary["signature"] as? String + } + + +} \ No newline at end of file diff --git a/JSONExport/DataType.swift b/JSONExport/DataType.swift index 7398ee2..6d6f75e 100755 --- a/JSONExport/DataType.swift +++ b/JSONExport/DataType.swift @@ -7,54 +7,58 @@ import Foundation -class DataType { - var boolType: String! - var characterType: String! - var doubleType: String! - var floatType: String! - var intType: String! - var longType: String! - var stringType: String! +class DataType{ - /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary) { - boolType = dictionary["boolType"] as? String - characterType = dictionary["characterType"] as? String - doubleType = dictionary["doubleType"] as? String - floatType = dictionary["floatType"] as? String - intType = dictionary["intType"] as? String - longType = dictionary["longType"] as? String - stringType = dictionary["stringType"] as? String - } + var boolType : String! + var characterType : String! + var doubleType : String! + var floatType : String! + var intType : String! + var longType : String! + var stringType : String! - /** - * Returns all the available property values in the form of NSDictionary object where the key is the approperiate json key and the value is the value of the corresponding property - */ - func toDictionary() -> NSDictionary { - let dictionary = NSMutableDictionary() - if boolType != nil { - dictionary["boolType"] = boolType - } - if characterType != nil { - dictionary["characterType"] = characterType - } - if doubleType != nil { - dictionary["doubleType"] = doubleType - } - if floatType != nil { - dictionary["floatType"] = floatType - } - if intType != nil { - dictionary["intType"] = intType - } - if longType != nil { - dictionary["longType"] = longType - } - if stringType != nil { - dictionary["stringType"] = stringType - } - return dictionary - } -} + + /** + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary){ + boolType = dictionary["boolType"] as? String + characterType = dictionary["characterType"] as? String + doubleType = dictionary["doubleType"] as? String + floatType = dictionary["floatType"] as? String + intType = dictionary["intType"] as? String + longType = dictionary["longType"] as? String + stringType = dictionary["stringType"] as? String + } + + /** + * Returns all the available property values in the form of NSDictionary object where the key is the approperiate json key and the value is the value of the corresponding property + */ + func toDictionary() -> NSDictionary + { + let dictionary = NSMutableDictionary() + if boolType != nil{ + dictionary["boolType"] = boolType + } + if characterType != nil{ + dictionary["characterType"] = characterType + } + if doubleType != nil{ + dictionary["doubleType"] = doubleType + } + if floatType != nil{ + dictionary["floatType"] = floatType + } + if intType != nil{ + dictionary["intType"] = intType + } + if longType != nil{ + dictionary["longType"] = longType + } + if stringType != nil{ + dictionary["stringType"] = stringType + } + return dictionary + } + +} \ No newline at end of file diff --git a/JSONExport/FileContentBuilder.swift b/JSONExport/FileContentBuilder.swift index 66faa5b..2ff5f7a 100755 --- a/JSONExport/FileContentBuilder.swift +++ b/JSONExport/FileContentBuilder.swift @@ -9,131 +9,139 @@ import Foundation /** - Singleton used to build the file content with the current configurations - */ -class FilesContentBuilder { +Singleton used to build the file content with the current configurations +*/ +class FilesContentBuilder{ + private init() {} - + /** Lazely load and return the singleton instance of the FilesContentBuilder */ struct Static { - static var onceToken: Int = 0 - static var instance: FilesContentBuilder? + static var onceToken : Int = 0 + static var instance : FilesContentBuilder? = nil } - - class var instance: FilesContentBuilder { + class var instance : FilesContentBuilder { + _ = FilesContentBuilder.__once return Static.instance! } - + private static var __once: () = { - Static.instance = FilesContentBuilder() - }() - + Static.instance = FilesContentBuilder() + }() /** - The prefix used for first level type names (and file names as well) - */ + The prefix used for first level type names (and file names as well) + */ var classPrefix = "" - + /** - The language for which the files' content should be created - */ - var lang: LangModel! - + The language for which the files' content should be created + */ + var lang : LangModel! + /** - Whether to include utility methods in the generated content - */ + Whether to include utility methods in the generated content + */ var includeUtilities = true - + /** - Whether to include constructors (aka initializers) - */ + Whether to include constructors (aka initializers) + */ var includeConstructors = true - + /** - Whatever value will be assinged to the firstLine property, will appear as the first line in every file if the target language supports first line statement - */ + Whatever value will be assinged to the firstLine property, will appear as the first line in every file if the target language supports first line statement + */ var firstLine = "" - + /** - If the target language supports inheritance, all the generated classes will be subclasses of this class - */ + If the target language supports inheritance, all the generated classes will be subclasses of this class + */ var parentClassName = "" - - var mismatchedTypes = [String: String]() - + + + var mismatchedTypes = [String : String]() + + + /** - Generates a file using the passed className and jsonObject example and appends it in the passed files array - - - parameter className: for the file to be generated, if the file already exist with different name, this className will be changed - - parameter jsonObject: acts as an example of the json object, which the generated fill be able to handle - - parameter files: the generated file will be appended to this array - */ - func addFileWithName(_ className: inout String, jsonObject: NSDictionary, files: inout [FileRepresenter], toOneRelationWithProperty: Property! = nil) { + Generates a file using the passed className and jsonObject example and appends it in the passed files array + + - parameter className: for the file to be generated, if the file already exist with different name, this className will be changed + - parameter jsonObject: acts as an example of the json object, which the generated fill be able to handle + - parameter files: the generated file will be appended to this array + */ + func addFileWithName(_ className: inout String, jsonObject: NSDictionary, files : inout [FileRepresenter], toOneRelationWithProperty: Property! = nil) + { var properties = [Property]() - if !className.hasPrefix(classPrefix) { + if !className.hasPrefix(classPrefix){ className = "\(classPrefix)\(className)" } - if toOneRelationWithProperty != nil, lang.supportMutualRelationships != nil, lang.supportMutualRelationships! { + if toOneRelationWithProperty != nil && lang.supportMutualRelationships != nil && lang.supportMutualRelationships!{ properties.append(toOneRelationWithProperty) + } - // sort all the keys in the passed json dictionary + //sort all the keys in the passed json dictionary let jsonProperties = (jsonObject.allKeys as! [String]).sorted() - - // loop all the json properties and handle each one individually - for jsonPropertyName in jsonProperties { - let value: AnyObject = jsonObject[jsonPropertyName]! as AnyObject + + //loop all the json properties and handle each one individually + for jsonPropertyName in jsonProperties{ + let value : AnyObject = jsonObject[jsonPropertyName]! as AnyObject let property = propertyForValue(value, jsonKeyName: jsonPropertyName) - // Avoid duplicated property names - if properties.map({ $0.nativeName }).index(of: property.nativeName) != nil { + //Avoid duplicated property names + if properties.map({$0.nativeName}).index(of: property.nativeName) != nil{ continue } - // recursively handle custom types - if property.isCustomClass { + //recursively handle custom types + if property.isCustomClass{ let rProperty = relationProperty(className) - addFileWithName(&property.type, jsonObject: value as! NSDictionary, files: &files, toOneRelationWithProperty: rProperty) - } else if property.isArray { + addFileWithName(&property.type, jsonObject: value as! NSDictionary, files:&files, toOneRelationWithProperty: rProperty) + }else if property.isArray{ let array = value as! NSArray - if array.firstObject is NSDictionary { - // complicated enough..... + if array.firstObject is NSDictionary{ + + //complicated enough..... var type = property.elementsType let relatedProperty = relationProperty(className) - let allProperties = unionDictionaryFromArrayElements(array) - addFileWithName(&type, jsonObject: allProperties, files: &files, toOneRelationWithProperty: relatedProperty) + let allProperties = unionDictionaryFromArrayElements(array); + addFileWithName(&type, jsonObject: allProperties, files:&files, toOneRelationWithProperty: relatedProperty) } } - + properties.append(property) + } - - // create the file - - let file = FileRepresenter(className: className, properties: properties, lang: lang) - + + //create the file + + let file = FileRepresenter(className: className, properties: properties, lang:lang) + file.includeUtilities = includeUtilities file.includeConstructors = includeConstructors file.firstLine = firstLine file.parentClassName = parentClassName - + var exactMatchFound = false - if let similarFile = findSimilarFile(file, inFiles: files, exactMatchFound: &exactMatchFound) { + if let similarFile = findSimilarFile(file, inFiles: files, exactMatchFound: &exactMatchFound){ //there is a similar file - if !exactMatchFound { - // If the found file is no exact, then any additional properties to the alread exist file instead of creating new one + if !exactMatchFound{ + //If the found file is no exact, then any additional properties to the alread exist file instead of creating new one mergeProperties(fromFile: file, toFile: similarFile) + } - // Hold list of mismatches to be fixed later + //Hold list of mismatches to be fixed later mismatchedTypes[className] = similarFile.className className = similarFile.className - - } else { + + }else{ files.append(file) - - if lang.headerFileData != nil { - // add header file first - let headerFile = HeaderFileRepresenter(className: className, properties: properties, lang: lang) + + if lang.headerFileData != nil{ + //add header file first + let headerFile = HeaderFileRepresenter(className: className, properties: properties, lang:lang) headerFile.includeUtilities = includeUtilities headerFile.includeConstructors = includeConstructors headerFile.parentClassName = parentClassName @@ -142,208 +150,224 @@ class FilesContentBuilder { } } } - + /** - Merges the properties from the passed fromFile to the pass toFile - - parameter fromFile: in which to find any new properties - - parameter toFile: to which to add any found new properties - */ - func mergeProperties(fromFile: FileRepresenter, toFile: FileRepresenter) { - for property in fromFile.properties { - if toFile.properties.index(of: property) == nil { + Merges the properties from the passed fromFile to the pass toFile + - parameter fromFile: in which to find any new properties + - parameter toFile: to which to add any found new properties + */ + func mergeProperties(fromFile: FileRepresenter, toFile: FileRepresenter) + { + for property in fromFile.properties{ + if toFile.properties.index(of: property) == nil{ toFile.properties.append(property) } } } - + /** - Finds the first file in the passed files which has the same class name as the passed file - - - parameter file: the file to compare against - - parameter inFiles: the files array to search in - - parameter exactMathFound: inout param, will have the value of 'true' if any file is found that has exactly the same properties as the passed file - - returns: similar file if any - */ - func findSimilarFile(_ file: FileRepresenter, inFiles files: [FileRepresenter], exactMatchFound: inout Bool) -> FileRepresenter? { - var similarFile: FileRepresenter? - for targetFile in files { + Finds the first file in the passed files which has the same class name as the passed file + + - parameter file: the file to compare against + - parameter inFiles: the files array to search in + - parameter exactMathFound: inout param, will have the value of 'true' if any file is found that has exactly the same properties as the passed file + - returns: similar file if any + */ + func findSimilarFile(_ file: FileRepresenter, inFiles files: [FileRepresenter], exactMatchFound: inout Bool) -> FileRepresenter?{ + var similarFile : FileRepresenter? + for targetFile in files{ + exactMatchFound = bothFilesHasSamePropreties(file1: targetFile, file2: file) - - if exactMatchFound || targetFile.className == file.className { + + if exactMatchFound || targetFile.className == file.className{ similarFile = targetFile - + break } } - + return similarFile } - + /** - Compares the properties of both files to determine if they exactly similar or no. - - - parameter file1: first file to compare against the second file - - parameter file2: the second file to compare against the first file - - returns: whether both files has exactly the same properties - */ - func bothFilesHasSamePropreties(file1: FileRepresenter, file2: FileRepresenter) -> Bool { + Compares the properties of both files to determine if they exactly similar or no. + + - parameter file1: first file to compare against the second file + - parameter file2: the second file to compare against the first file + - returns: whether both files has exactly the same properties + */ + func bothFilesHasSamePropreties(file1: FileRepresenter, file2: FileRepresenter) -> Bool + { var bothHasSameProperties = true - if file1.properties.count == file2.properties.count { + if file1.properties.count == file2.properties.count{ //there is a propability they both has the same properties - for property in file1.properties { - if file2.properties.index(of: property) == nil { - // property not found, no need to keep looking + for property in file1.properties{ + if file2.properties.index(of: property) == nil{ + //property not found, no need to keep looking bothHasSameProperties = false break } } - } else { + }else{ bothHasSameProperties = false } - + return bothHasSameProperties } - - func fixReferenceMismatches(inFiles files: [FileRepresenter]) { - for file in files { - for property in file.properties { - if property.isCustomClass, let toType = mismatchedTypes[property.type] { + + + func fixReferenceMismatches(inFiles files: [FileRepresenter]) + { + for file in files{ + for property in file.properties{ + if property.isCustomClass, let toType = mismatchedTypes[property.type]{ property.type = toType - } else if property.isArray, let toType = mismatchedTypes[property.elementsType] { + }else if property.isArray, let toType = mismatchedTypes[property.elementsType]{ property.elementsType = toType property.type = lang.arrayType.replacingOccurrences(of: elementType, with: toType) } } } } - + /** - Creates and returns a Property object whiche represents a to-one relation property - - - parameter relationClassName: to which the relation relates - - parameter headerProperty: optional whether this property is for header file - - - returns: the relation property - */ - func relationProperty(_ relationClassName: String) -> Property { + Creates and returns a Property object whiche represents a to-one relation property + + - parameter relationClassName: to which the relation relates + - parameter headerProperty: optional whether this property is for header file + + - returns: the relation property + */ + func relationProperty(_ relationClassName : String) -> Property + { + let nativeName = relationClassName.lowercaseFirstChar() let property = Property(jsonName: nativeName, nativeName: nativeName, type: relationClassName, lang: lang) property.isCustomClass = true - + return property } - + /** - Creates and returns a Property object passed on the passed value and json key name - - - parameter value: example value for the property - - parameter jsonKeyName: for the property - - returns: a Property instance - */ - func propertyForValue(_ value: AnyObject, jsonKeyName: String) -> Property { + Creates and returns a Property object passed on the passed value and json key name + + - parameter value: example value for the property + - parameter jsonKeyName: for the property + - returns: a Property instance + */ + func propertyForValue(_ value: AnyObject, jsonKeyName: String) -> Property + { let nativePropertyName = propertyNativeName(jsonKeyName) - var type = propertyTypeName(value, lang: lang) + var type = propertyTypeName(value, lang:lang) // var isDictionary = false // var isArray = false - + var property: Property! if value is NSDictionary { type = typeNameForPropertyName(jsonKeyName) - property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: false, isCustomClass: true, lang: lang) - - } else if value is NSArray { - // we need to check its elements... + property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray:false, isCustomClass: true, lang: lang) + + }else if value is NSArray{ + //we need to check its elements... let array = value as! NSArray - - if array.firstObject is NSDictionary { - // wow complicated + + if array.firstObject is NSDictionary{ + //wow complicated let leafClassName = typeNameForPropertyName(jsonKeyName) type = lang.arrayType.replacingOccurrences(of: elementType, with: leafClassName) - - property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: true, isCustomClass: false, lang: lang) + + property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: true, isCustomClass: false, lang:lang) property.elementsType = leafClassName - // Create a class for this type as well! - + //Create a class for this type as well! + property.elementsAreOfCustomType = true - } else { - property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: true, isCustomClass: false, lang: lang) - property.elementsType = typeNameForArrayElements(value as! NSArray, lang: lang) + }else{ + property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, isArray: true, isCustomClass: false, lang:lang) + property.elementsType = typeNameForArrayElements(value as! NSArray, lang:lang) } - } else { - property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, lang: lang) + }else{ + property = Property(jsonName: jsonKeyName, nativeName: nativePropertyName, type: type, lang:lang) } property.sampleValue = value return property } + + + /** - Returns a camel case presentation from the passed json key - - - parameter jsonKeyName: the name of the json key to convert to suitable native property name - - - returns: property name - */ - func propertyNativeName(_ jsonKeyName: String) -> String { + Returns a camel case presentation from the passed json key + + - parameter jsonKeyName: the name of the json key to convert to suitable native property name + + - returns: property name + */ + func propertyNativeName(_ jsonKeyName : String) -> String + { var propertyName = cleanUpVersionOfPropertyNamed(jsonKeyName) propertyName = underscoresToCamelCaseForString(propertyName, startFromFirstChar: false).lowercaseFirstChar() - // Fix property name that could be a reserved keyword - if lang.reservedKeywords != nil, lang.reservedKeywords.contains(propertyName.lowercased()) { - // Property name need to be suffixed by proper suffix, any ideas of better generlized prefix/suffix? + //Fix property name that could be a reserved keyword + if lang.reservedKeywords != nil && lang.reservedKeywords.contains(propertyName.lowercased()){ + //Property name need to be suffixed by proper suffix, any ideas of better generlized prefix/suffix? propertyName += "Field" } return propertyName } - - func cleanUpVersionOfPropertyNamed(_ propertyName: String) -> String { + + + func cleanUpVersionOfPropertyNamed(_ propertyName: String) -> String + { let allowedCharacters = NSMutableCharacterSet.alphanumeric() allowedCharacters.addCharacters(in: "_1234567890") let cleanVersion = propertyName.components(separatedBy: allowedCharacters.inverted).joined(separator: "") return cleanVersion } - + /** - Returns the input string with white spaces removed, and underscors converted to camel case - - - parameter inputString: to convert - - parameter startFromFirstChar: whether to start with upper case letter - - returns: the camel case version of the input - */ - func underscoresToCamelCaseForString(_ input: String, startFromFirstChar: Bool) -> String { + Returns the input string with white spaces removed, and underscors converted to camel case + + - parameter inputString: to convert + - parameter startFromFirstChar: whether to start with upper case letter + - returns: the camel case version of the input + */ + func underscoresToCamelCaseForString(_ input: String, startFromFirstChar: Bool) -> String + { var str = input.replacingOccurrences(of: " ", with: "") - + str = str.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) var output = "" var makeNextCharUpperCase = startFromFirstChar for char in input { if char == "_" { makeNextCharUpperCase = true - } else if makeNextCharUpperCase { + }else if makeNextCharUpperCase{ let upperChar = String(char).uppercased() output += upperChar makeNextCharUpperCase = false - } else { + }else{ makeNextCharUpperCase = false output += String(char) } } - + return output } - + /** - Creats and returns the class name for the passed proeprty name - - - parameter propertyName: to be converted to a type name - - returns: the type name - */ - func typeNameForPropertyName(_ propertyName: String) -> String { + Creats and returns the class name for the passed proeprty name + + - parameter propertyName: to be converted to a type name + - returns: the type name + */ + func typeNameForPropertyName(_ propertyName : String) -> String{ var swiftClassName = underscoresToCamelCaseForString(propertyName, startFromFirstChar: true).toSingular() - - if !swiftClassName.hasPrefix(classPrefix) { + + if !swiftClassName.hasPrefix(classPrefix){ swiftClassName = "\(classPrefix)\(swiftClassName)" } - + return swiftClassName } + } diff --git a/JSONExport/FilePreviewCell.swift b/JSONExport/FilePreviewCell.swift index c9ef48c..fafc686 100755 --- a/JSONExport/FilePreviewCell.swift +++ b/JSONExport/FilePreviewCell.swift @@ -9,79 +9,89 @@ import Cocoa class FilePreviewCell: NSTableCellView, NSTextViewDelegate { + + @IBOutlet var classNameLabel: NSTextFieldCell! @IBOutlet var constructors: NSButton! @IBOutlet var utilities: NSButton! @IBOutlet var textView: NSTextView! @IBOutlet var scrollView: NSScrollView! - - var file: FileRepresenter! { - didSet { - if file != nil { + + + var file: FileRepresenter!{ + didSet{ + if file != nil{ DispatchQueue.main.async { var fileName = self.file.className fileName += "." - if self.file is HeaderFileRepresenter { + if self.file is HeaderFileRepresenter{ fileName += self.file.lang.headerFileData.headerFileExtension - } else { + }else{ fileName += self.file.lang.fileExtension } self.classNameLabel.stringValue = fileName - if self.textView != nil { + if(self.textView != nil){ self.textView.string = self.file.toString() } - - if self.file.includeConstructors { + + if self.file.includeConstructors{ self.constructors.state = NSControl.StateValue.on - } else { + }else{ self.constructors.state = NSControl.StateValue.off } - if self.file.includeUtilities { + if self.file.includeUtilities{ self.utilities.state = NSControl.StateValue.on - } else { + }else{ self.utilities.state = NSControl.StateValue.off } } - } else { + }else{ classNameLabel.stringValue = "" } } } - + + + override func awakeFromNib() { super.awakeFromNib() - if textView != nil { + if textView != nil{ textView.delegate = self DispatchQueue.main.async { self.setupNumberedTextView() } } } - - func setupNumberedTextView() { + + func setupNumberedTextView() + { let lineNumberView = NoodleLineNumberView(scrollView: scrollView) scrollView.hasHorizontalRuler = false scrollView.hasVerticalRuler = true scrollView.verticalRulerView = lineNumberView scrollView.rulersVisible = true textView.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize) + } - - @IBAction func toggleConstructors(_ sender: NSButtonCell) { - if file != nil { + + @IBAction func toggleConstructors(_ sender: NSButtonCell) + { + if file != nil{ file.includeConstructors = (sender.state == NSControl.StateValue.off) textView.string = file.toString() + } } - - @IBAction func toggleUtilityMethods(_ sender: NSButtonCell) { - if file != nil { + + @IBAction func toggleUtilityMethods(_ sender: NSButtonCell) + { + if file != nil{ file.includeUtilities = (sender.state == NSControl.StateValue.on) textView.string = file.toString() } } - - func textDidChange(_: Notification) { - file.fileContent = textView.string + + func textDidChange(_ notification: Notification) { + file.fileContent = textView.string } } diff --git a/JSONExport/FileRepresenter.swift b/JSONExport/FileRepresenter.swift index 194b01f..f6e8d21 100755 --- a/JSONExport/FileRepresenter.swift +++ b/JSONExport/FileRepresenter.swift @@ -30,66 +30,68 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -import AddressBook import Foundation +import AddressBook /** - FileRepresenter is used to generate a valid syntax for the target language that represents JSON object - */ -class FileRepresenter { +FileRepresenter is used to generate a valid syntax for the target language that represents JSON object +*/ +class FileRepresenter{ /** - Holds the class (or type) name - */ - var className: String - + Holds the class (or type) name + */ + var className : String + /** - Array of properties which will be included in the file content - */ - var properties: [Property] - + Array of properties which will be included in the file content + */ + var properties : [Property] + /** - The target language meta instance - */ - var lang: LangModel - + The target language meta instance + */ + var lang : LangModel + /** - Whether to include constructors (aka initializers in Swift) in the file content - */ + Whether to include constructors (aka initializers in Swift) in the file content + */ var includeConstructors = true - + /** - Whether to include utility methods in the file content. Utility methods such as toDictionary method - */ + Whether to include utility methods in the file content. Utility methods such as toDictionary method + */ var includeUtilities = true - + /** - If the target language supports first line statement (i.e package names in Java), then you can set the value of this property to whatever the first line statement is. - */ + If the target language supports first line statement (i.e package names in Java), then you can set the value of this property to whatever the first line statement is. + */ var firstLine = "" - + /** - If the target language supports inheritance, all the generated classes will be subclasses of this class - */ + If the target language supports inheritance, all the generated classes will be subclasses of this class + */ var parentClassName = "" - + /** - After the first time you use the toString() method, this property will contain the file content. - */ + After the first time you use the toString() method, this property will contain the file content. + */ var fileContent = "" - + + /** - Designated initializer - */ - init(className: String, properties: [Property], lang: LangModel) { + Designated initializer + */ + init(className: String, properties: [Property], lang: LangModel) + { self.className = className self.properties = properties self.lang = lang } - + /** - Generates the file content and stores it in the fileContent property - */ - func toString() -> String { + Generates the file content and stores it in the fileContent property + */ + func toString() -> String{ fileContent = "" appendFirstLineStatement() appendCopyrights() @@ -97,116 +99,127 @@ class FileRepresenter { appendHeaderFileImport() appendConstVarDefinition() appendCustomImports() - // start the model defination + //start the model defination var definition = "" - if lang.modelDefinitionWithParent != nil, parentClassName.count > 0 { + if lang.modelDefinitionWithParent != nil && parentClassName.count > 0{ definition = lang.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: parentClassName) - } else if includeUtilities, lang.defaultParentWithUtilityMethods != nil { + }else if includeUtilities && lang.defaultParentWithUtilityMethods != nil{ definition = lang.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: lang.defaultParentWithUtilityMethods) - } else { + }else{ definition = lang.modelDefinition.replacingOccurrences(of: modelName, with: className) } fileContent += definition - // start the model content body + //start the model content body fileContent += "\(lang.modelStart)" - + appendProperties() appendSettersAndGetters() appendInitializers() appendUtilityMethods() - fileContent = fileContent.replacingOccurrences(of: lowerCaseModelName, with: className.lowercaseFirstChar()) - fileContent = fileContent.replacingOccurrences(of: modelName, with: className) + fileContent = fileContent.replacingOccurrences(of: lowerCaseModelName, with:className.lowercaseFirstChar()) + fileContent = fileContent.replacingOccurrences(of: modelName, with:className) fileContent += lang.modelEnd return fileContent } - + /** - Appneds the firstLine value (if any) to the fileContent if the lang.supportsFirstLineStatement is true - */ - func appendFirstLineStatement() { - if lang.supportsFirstLineStatement != nil, lang.supportsFirstLineStatement!, firstLine.count > 0 { + Appneds the firstLine value (if any) to the fileContent if the lang.supportsFirstLineStatement is true + */ + func appendFirstLineStatement() + { + if lang.supportsFirstLineStatement != nil && lang.supportsFirstLineStatement! && firstLine.count > 0{ fileContent += "\(firstLine)\n\n" } } - - /** - Appends the lang.staticImports if any - */ - func appendStaticImports() { - if lang.staticImports != nil { + + /** + Appends the lang.staticImports if any + */ + func appendStaticImports() + { + if lang.staticImports != nil{ fileContent += lang.staticImports! fileContent += "\n" } } - func appendHeaderFileImport() { - if lang.importHeaderFile != nil { + func appendHeaderFileImport() + { + if lang.importHeaderFile != nil{ fileContent += "\n" fileContent += lang.importHeaderFile! fileContent = fileContent.replacingOccurrences(of: modelName, with: className) } } - - func appendConstVarDefinition() { + + func appendConstVarDefinition() + { if lang.constVarDefinition != nil { fileContent += "\n" } - for property in properties { + for property in properties{ fileContent += property.toConstVar(className) } } - + /** - Tries to access the address book in order to fetch basic information about the author so it can include a nice copyright statment - */ - func appendCopyrights() { + Tries to access the address book in order to fetch basic information about the author so it can include a nice copyright statment + */ + func appendCopyrights() + { fileContent += "//\n//\t\(className).\(lang.fileExtension)\n" - if let me = ABAddressBook.shared()?.me() { - if let firstName = me.value(forProperty: kABFirstNameProperty as String) as? String { + if let me = ABAddressBook.shared()?.me(){ + + if let firstName = me.value(forProperty: kABFirstNameProperty as String) as? String{ fileContent += "//\n//\tCreate by \(firstName)" - if let lastName = me.value(forProperty: kABLastNameProperty as String) as? String { - fileContent += " \(lastName)" + if let lastName = me.value(forProperty: kABLastNameProperty as String) as? String{ + fileContent += " \(lastName)" } } - + + fileContent += " on \(getTodayFormattedDay())\n//\tCopyright © \(getYear())" - - if let organization = me.value(forProperty: kABOrganizationProperty as String) as? String { + + if let organization = me.value(forProperty: kABOrganizationProperty as String) as? String{ fileContent += " \(organization)" } - + fileContent += ". All rights reserved.\n" } - - fileContent += "//\tModel file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport" - - if let langAuthor = lang.author { + + //fileContent += "//\tModel file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport" + + if let langAuthor = lang.author{ fileContent += "\n\n//\tThe \"\(lang.displayLangName!)\" support has been made available by \(langAuthor.name!)" - if let email = langAuthor.email { + if let email = langAuthor.email{ fileContent += "(\(email))" } - - if let website = langAuthor.website { + + if let website = langAuthor.website{ fileContent += "\n//\tMore about him/her can be found at his/her website: \(website)" } + } - + + fileContent += "\n\n" } - + /** - Returns the current year as String - */ - func getYear() -> String { + Returns the current year as String + */ + func getYear() -> String + { return "\((Calendar.current as NSCalendar).component(.year, from: Date()))" } - + /** - Returns today date in the format dd/mm/yyyy - */ - func getTodayFormattedDay() -> String { + Returns today date in the format dd/mm/yyyy + */ + func getTodayFormattedDay() -> String + { let components = (Calendar.current as NSCalendar).components([.day, .month, .year], from: Date()) return "\(components.day!)/\(components.month!)/\(components.year!)" } @@ -214,147 +227,158 @@ class FileRepresenter { /** Loops on all properties which has a custom type and appends the custom import from the lang's importForEachCustomType property - */ - func appendCustomImports() { - if lang.importForEachCustomType != nil { - for property in properties { - if property.isCustomClass { + */ + func appendCustomImports() + { + if lang.importForEachCustomType != nil{ + for property in properties{ + if property.isCustomClass{ fileContent += lang.importForEachCustomType.replacingOccurrences(of: modelName, with: property.type) - } else if property.isArray, property.elementsAreOfCustomType { + }else if property.isArray && property.elementsAreOfCustomType{ fileContent += lang.importForEachCustomType.replacingOccurrences(of: modelName, with: property.elementsType) } } } } - + /** - Appends all the properties using the Property.toString(forHeaderFile: false) method - */ - func appendProperties() { + Appends all the properties using the Property.toString(forHeaderFile: false) method + */ + func appendProperties() + { fileContent += "\n" - for property in properties { + for property in properties{ + fileContent += property.toString(false) } } - + /** - Appends the setter and getter for each property if the current target language supports them (i.e the convension in Java is to use private instance variables with public setters and getters). The method will use special getter for boolean properties if required by the target language - */ - func appendSettersAndGetters() { + Appends the setter and getter for each property if the current target language supports them (i.e the convension in Java is to use private instance variables with public setters and getters). The method will use special getter for boolean properties if required by the target language + */ + func appendSettersAndGetters() + { fileContent += "\n" - for property in properties { - // append the setter + for property in properties{ + //append the setter let capVarName = property.nativeName.uppercaseFirstChar() - if lang.setter != nil { + if lang.setter != nil{ var set = lang.setter - + set = set?.replacingOccurrences(of: capitalizedVarName, with: capVarName) set = set?.replacingOccurrences(of: varName, with: property.nativeName) set = set?.replacingOccurrences(of: varType, with: property.type) fileContent += set! } - + // append the getters - var get: String! - // if the property is a boolean property determine if there is a special getter for boolean properties - if property.type == lang.dataTypes.boolType { - if lang.booleanGetter != nil { + var get : String! + //if the property is a boolean property determine if there is a special getter for boolean properties + if property.type == lang.dataTypes.boolType{ + if lang.booleanGetter != nil{ get = lang.booleanGetter - - } else { - // use normal getter + + }else{ + //use normal getter get = lang.getter } - } else { + }else{ get = lang.getter } - - if get != nil { + + if get != nil{ get = get.replacingOccurrences(of: capitalizedVarName, with: capVarName) get = get.replacingOccurrences(of: varName, with: property.nativeName) get = get.replacingOccurrences(of: varType, with: property.type) fileContent += get } + } } - + /** - Appends all the defined constructors (aka initializers) in lang.constructors to the fileContent - */ - func appendInitializers() { - if !includeConstructors { + Appends all the defined constructors (aka initializers) in lang.constructors to the fileContent + */ + func appendInitializers() + { + if !includeConstructors{ return } fileContent += "\n" - for constructor in lang.constructors { - if constructor.comment != nil { + for constructor in lang.constructors{ + if constructor.comment != nil{ fileContent += constructor.comment } - + fileContent += constructor.signature fileContent += constructor.bodyStart - - for property in properties { + + for property in properties{ + fileContent += propertyFetchFromJsonSyntaxForProperty(property, constructor: constructor) } - + fileContent += constructor.bodyEnd fileContent = fileContent.replacingOccurrences(of: modelName, with: className) } } - + + /** - Appends all the defined utility methods in lang.utilityMethods to the fileContent - */ - func appendUtilityMethods() { - if !includeUtilities { + Appends all the defined utility methods in lang.utilityMethods to the fileContent + */ + func appendUtilityMethods() + { + if !includeUtilities{ return } fileContent += "\n" - for method in lang.utilityMethods { - if method.comment != nil { + for method in lang.utilityMethods{ + if method.comment != nil{ fileContent += method.comment } fileContent += method.signature fileContent += method.bodyStart fileContent += method.body - for property in properties { + for property in properties{ var propertyHandlingStr = "" - if property.isArray { - if propertyTypeIsBasicType(property) { + if property.isArray{ + if propertyTypeIsBasicType(property){ propertyHandlingStr = method.forEachProperty - - } else { + + }else{ propertyHandlingStr = method.forEachArrayOfCustomTypeProperty } propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: elementType, with: property.elementsType) - } else { - if lang.basicTypesWithSpecialStoringNeeds != nil, method.forEachPropertyWithSpecialStoringNeeds != nil, lang.basicTypesWithSpecialStoringNeeds.index(of: property.type) != nil { + }else{ + if lang.basicTypesWithSpecialStoringNeeds != nil && method.forEachPropertyWithSpecialStoringNeeds != nil && lang.basicTypesWithSpecialStoringNeeds.index(of: property.type) != nil{ propertyHandlingStr = method.forEachPropertyWithSpecialStoringNeeds - } else { + }else{ propertyHandlingStr = method.forEachProperty - if property.isCustomClass { + if property.isCustomClass{ propertyHandlingStr = method.forEachCustomTypeProperty } } + } - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varName, with: property.nativeName) - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: constKeyName, with: property.constName!) - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varType, with: property.type) - - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: jsonKeyName, with: property.jsonName) - - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: additionalCustomTypeProperty, with: "") - if lang.basicTypesWithSpecialFetchingNeeds != nil { - if let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.type), let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements?[index] { - propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varTypeReplacement, with: replacement) - + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varName, with:property.nativeName) + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: constKeyName, with:property.constName!) + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varType, with:property.type) + + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: jsonKeyName, with:property.jsonName) + + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: additionalCustomTypeProperty, with:"") + if lang.basicTypesWithSpecialFetchingNeeds != nil{ + if let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.type), let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements?[index]{ + propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: varTypeReplacement, with: replacement) + var castString = String() - if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index] { + if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index]{ // if needs cast if !cast.isEmpty { castString = "(\(cast)) " - } else { + } + else { castString = cast } } @@ -362,6 +386,7 @@ class FileRepresenter { let lowerCaseType = property.type.lowercased() propertyHandlingStr = propertyHandlingStr.replacingOccurrences(of: lowerCaseVarType, with: lowerCaseType) + } } fileContent += propertyHandlingStr @@ -369,125 +394,140 @@ class FileRepresenter { fileContent += method.returnStatement fileContent += method.bodyEnd } + + } - + /** - Returns true if the passed property.type is one of the basic types or an array of any of the basic types, otherwise returns false - */ - func propertyTypeIsBasicType(_ property: Property) -> Bool { + Returns true if the passed property.type is one of the basic types or an array of any of the basic types, otherwise returns false + */ + func propertyTypeIsBasicType(_ property: Property) -> Bool{ var isBasicType = false let type = propertyTypeWithoutArrayWords(property) - if lang.genericType == type { + if lang.genericType == type{ isBasicType = true - } else { + }else{ let basicTypes = lang.dataTypes.toDictionary().allValues as! [String] - - if basicTypes.index(of: type) != nil { + + if basicTypes.index(of: type) != nil{ isBasicType = true } } - + + return isBasicType } - + /** - Removes any "array-specific character or words" from the passed type to return the type of the array elements. The "array-specific character or words" are fetched from the lang.wordsToRemoveToGetArrayElementsType property - */ - func propertyTypeWithoutArrayWords(_ property: Property) -> String { + Removes any "array-specific character or words" from the passed type to return the type of the array elements. The "array-specific character or words" are fetched from the lang.wordsToRemoveToGetArrayElementsType property + */ + func propertyTypeWithoutArrayWords(_ property: Property) -> String + { + var type = property.type - - for arrayWord in lang.wordsToRemoveToGetArrayElementsType { + + for arrayWord in lang.wordsToRemoveToGetArrayElementsType{ type = type.replacingOccurrences(of: arrayWord, with: "") } - - if type.count == 0 { + + if type.count == 0{ type = typeNameForArrayElements(property.sampleValue as! NSArray, lang: lang) } return type } - - // MARK: - Fetching property from a JSON object - + + //MARK: - Fetching property from a JSON object /** - Returns the suitable syntax to fetch the value of the property from a JSON object for the passed constructor - */ - func propertyFetchFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String { + Returns the suitable syntax to fetch the value of the property from a JSON object for the passed constructor + */ + func propertyFetchFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String + { var propertyStr = "" - if property.isCustomClass { + if property.isCustomClass{ + propertyStr = constructor.fetchCustomTypePropertyFromMap - - } else if property.isArray { + + }else if property.isArray{ propertyStr = fetchArrayFromJsonSyntaxForProperty(property, constructor: constructor) - - } else { + + }else { propertyStr = fetchBasicTypePropertyFromJsonSyntaxForProperty(property, constructor: constructor) + } - // Apply all the basic replacements + //Apply all the basic replacements propertyStr = propertyStr.replacingOccurrences(of: varName, with: property.nativeName) propertyStr = propertyStr.replacingOccurrences(of: jsonKeyName, with: property.jsonName) propertyStr = propertyStr.replacingOccurrences(of: constKeyName, with: property.constName!) propertyStr = propertyStr.replacingOccurrences(of: varType, with: property.type) let capVarName = property.nativeName.capitalized - let capVarType = property.type.capitalized + let capVarType = property.type.capitalized; propertyStr = propertyStr.replacingOccurrences(of: capitalizedVarName, with: capVarName) propertyStr = propertyStr.replacingOccurrences(of: capitalizedVarType, with: capVarType) return propertyStr } - + /** - Returns valid syntax to fetch an array from a JSON object - */ - func fetchArrayFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String { + Returns valid syntax to fetch an array from a JSON object + */ + func fetchArrayFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String + { var propertyStr = "" - if propertyTypeIsBasicType(property) { - if constructor.fetchArrayOfBasicTypePropertyFromMap != nil { - if let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.elementsType) { + if(propertyTypeIsBasicType(property)){ + + if constructor.fetchArrayOfBasicTypePropertyFromMap != nil{ + if let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.elementsType){ propertyStr = constructor.fetchArrayOfBasicTypePropertyFromMap let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements[index] propertyStr = propertyStr.replacingOccurrences(of: varTypeReplacement, with: replacement) - + // if needs cast let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast[index] if !cast.isEmpty { propertyStr = propertyStr.replacingOccurrences(of: varTypeCast, with: "(\(cast)) ") - } else { + } + else { propertyStr = propertyStr.replacingOccurrences(of: varTypeCast, with: cast) } - } else { + }else{ propertyStr = constructor.fetchBasicTypePropertyFromMap } - } else { + }else{ propertyStr = constructor.fetchBasicTypePropertyFromMap } - - } else { - // array of custom type + + }else{ + //array of custom type propertyStr = constructor.fetchArrayOfCustomTypePropertyFromMap + + + } - propertyStr = propertyStr.replacingOccurrences(of: elementType, with: property.elementsType) + propertyStr = propertyStr.replacingOccurrences(of: elementType, with: property.elementsType) return propertyStr } - + /** - Returns valid syntax to fetch any property with basic type from a JSON object - */ - func fetchBasicTypePropertyFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String { + Returns valid syntax to fetch any property with basic type from a JSON object + */ + func fetchBasicTypePropertyFromJsonSyntaxForProperty(_ property: Property, constructor: Constructor) -> String + { var propertyStr = "" - if lang.basicTypesWithSpecialFetchingNeeds != nil { + if lang.basicTypesWithSpecialFetchingNeeds != nil{ let index = lang.basicTypesWithSpecialFetchingNeeds.index(of: property.type) - if index != nil { + if index != nil{ propertyStr = constructor.fetchBasicTypeWithSpecialNeedsPropertyFromMap - if let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements?[index!] { + if let replacement = lang.basicTypesWithSpecialFetchingNeedsReplacements?[index!]{ propertyStr = propertyStr.replacingOccurrences(of: varTypeReplacement, with: replacement) } - + var castString = String() - if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index!] { + if let cast = lang.basicTypesWithSpecialFetchingNeedsTypeCast?[index!]{ // if needs cast if !cast.isEmpty { castString = "(\(cast)) " - } else { + } + else { castString = cast } } @@ -495,15 +535,15 @@ class FileRepresenter { let lowerCaseType = property.type.lowercased() propertyStr = propertyStr.replacingOccurrences(of: lowerCaseVarType, with: lowerCaseType) - - } else { + + }else{ propertyStr = constructor.fetchBasicTypePropertyFromMap } - - } else { + + }else{ propertyStr = constructor.fetchBasicTypePropertyFromMap } - + return propertyStr } } diff --git a/JSONExport/HeaderFileData.swift b/JSONExport/HeaderFileData.swift index 01a1d8a..162e3f2 100755 --- a/JSONExport/HeaderFileData.swift +++ b/JSONExport/HeaderFileData.swift @@ -7,32 +7,34 @@ import Foundation -class HeaderFileData { - var constructorSignatures: [String]! - var headerFileExtension: String! - var importForEachCustomType: String! - var importParentHeaderFile: String! - var instanceVarDefinition: String! - var instanceVarWithSpeicalDefinition: String! - var modelDefinition: String! - var modelDefinitionWithParent: String! - var defaultParentWithUtilityMethods: String! - var modelEnd: String! - var modelStart: String! - var staticImports: String! - var typesNeedSpecialDefinition: [String]! - var utilityMethodSignatures: [String]! - +class HeaderFileData{ + + var constructorSignatures : [String]! + var headerFileExtension : String! + var importForEachCustomType : String! + var importParentHeaderFile : String! + var instanceVarDefinition : String! + var instanceVarWithSpeicalDefinition : String! + var modelDefinition : String! + var modelDefinitionWithParent : String! + var defaultParentWithUtilityMethods : String! + var modelEnd : String! + var modelStart : String! + var staticImports : String! + var typesNeedSpecialDefinition : [String]! + var utilityMethodSignatures : [String]! + + /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary) { + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary){ constructorSignatures = dictionary["constructorSignatures"] as? [String] headerFileExtension = dictionary["headerFileExtension"] as? String importForEachCustomType = dictionary["importForEachCustomType"] as? String importParentHeaderFile = dictionary["importParentHeaderFile"] as? String instanceVarDefinition = dictionary["instanceVarDefinition"] as? String - + instanceVarWithSpeicalDefinition = dictionary["instanceVarWithSpeicalDefinition"] as? String modelDefinition = dictionary["modelDefinition"] as? String modelDefinitionWithParent = dictionary["modelDefinitionWithParent"] as? String @@ -42,5 +44,7 @@ class HeaderFileData { staticImports = dictionary["staticImports"] as? String typesNeedSpecialDefinition = dictionary["typesNeedSpecialDefinition"] as? [String] utilityMethodSignatures = dictionary["utilityMethodSignatures"] as? [String] + } -} + +} \ No newline at end of file diff --git a/JSONExport/HeaderFileRepresenter.swift b/JSONExport/HeaderFileRepresenter.swift index c12321b..05e2895 100755 --- a/JSONExport/HeaderFileRepresenter.swift +++ b/JSONExport/HeaderFileRepresenter.swift @@ -29,139 +29,155 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -import AddressBook + import Foundation +import AddressBook -class HeaderFileRepresenter: FileRepresenter { +class HeaderFileRepresenter : FileRepresenter{ /** - Generates the header file content and stores it in the fileContent property - */ - override func toString() -> String { + Generates the header file content and stores it in the fileContent property + */ + override func toString() -> String{ fileContent = "" appendCopyrights() appendStaticImports() appendImportParentHeader() appendCustomImports() - - // start the model defination + + //start the model defination var definition = "" - if lang.headerFileData.modelDefinitionWithParent != nil, parentClassName.count > 0 { + if lang.headerFileData.modelDefinitionWithParent != nil && parentClassName.count > 0{ definition = lang.headerFileData.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: parentClassName) - } else if includeUtilities, lang.defaultParentWithUtilityMethods != nil { + }else if includeUtilities && lang.defaultParentWithUtilityMethods != nil{ definition = lang.headerFileData.modelDefinitionWithParent.replacingOccurrences(of: modelName, with: className) definition = definition.replacingOccurrences(of: modelWithParentClassName, with: lang.headerFileData.defaultParentWithUtilityMethods) - } else { + }else{ definition = lang.headerFileData.modelDefinition.replacingOccurrences(of: modelName, with: className) } - + fileContent += definition - // start the model content body + //start the model content body fileContent += "\(lang.modelStart)" - + appendProperties() appendInitializers() appendUtilityMethods() fileContent += lang.modelEnd return fileContent } - + + + /** - Appends the lang.headerFileData.staticImports if any - */ - override func appendStaticImports() { - if lang.headerFileData.staticImports != nil { + Appends the lang.headerFileData.staticImports if any + */ + override func appendStaticImports() + { + if lang.headerFileData.staticImports != nil{ fileContent += lang.headerFileData.staticImports fileContent += "\n" } } - - func appendImportParentHeader() { - if lang.headerFileData.importParentHeaderFile != nil, parentClassName.count > 0 { + + func appendImportParentHeader() + { + if lang.headerFileData.importParentHeaderFile != nil && parentClassName.count > 0{ fileContent += lang.headerFileData.importParentHeaderFile.replacingOccurrences(of: modelWithParentClassName, with: parentClassName) } } - + /** - Tries to access the address book in order to fetch basic information about the author so it can include a nice copyright statment - */ - override func appendCopyrights() { - if let me = ABAddressBook.shared()?.me() { - fileContent += "//\n//\t\(className).\(lang.headerFileData.headerFileExtension!)\n" - if let firstName = me.value(forProperty: kABFirstNameProperty as String) as? String { + Tries to access the address book in order to fetch basic information about the author so it can include a nice copyright statment + */ + override func appendCopyrights() + { + if let me = ABAddressBook.shared()?.me(){ + fileContent += "//\n//\t\(self.className).\(lang.headerFileData.headerFileExtension!)\n" + if let firstName = me.value(forProperty: kABFirstNameProperty as String) as? String{ fileContent += "//\n//\tCreate by \(firstName)" - if let lastName = me.value(forProperty: kABLastNameProperty as String) as? String { + if let lastName = me.value(forProperty: kABLastNameProperty as String) as? String{ fileContent += " \(lastName)" } } - + + fileContent += " on \(getTodayFormattedDay())\n//\tCopyright © \(getYear())" - - if let organization = me.value(forProperty: kABOrganizationProperty as String) as? String { + + if let organization = me.value(forProperty: kABOrganizationProperty as String) as? String{ fileContent += " \(organization)" } - + fileContent += ". All rights reserved.\n//\n\n" - // fileContent += "//\tModel file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport\n\n" + //fileContent += "//\tModel file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport\n\n" } + } - + + /** - Loops on all properties which has a custom type and appends the custom import from the lang.headerFileData's importForEachCustomType property - - */ - override func appendCustomImports() { - if lang.importForEachCustomType != nil { - for property in properties { - if property.isCustomClass { + Loops on all properties which has a custom type and appends the custom import from the lang.headerFileData's importForEachCustomType property + + */ + override func appendCustomImports() + { + if lang.importForEachCustomType != nil{ + for property in properties{ + if property.isCustomClass{ fileContent += lang.headerFileData.importForEachCustomType.replacingOccurrences(of: modelName, with: property.type) - } else if property.isArray { - // if it is an array of custom types - if property.elementsType != lang.genericType { + }else if property.isArray{ + //if it is an array of custom types + if(property.elementsType != lang.genericType){ let basicTypes = lang.dataTypes.toDictionary().allValues as! [String] - if basicTypes.index(of: property.elementsType) == nil { + if basicTypes.index(of: property.elementsType) == nil{ fileContent += lang.headerFileData.importForEachCustomType.replacingOccurrences(of: modelName, with: property.elementsType) } } + } } } } - + /** - Appends all the properties using the Property.stringPresentation method - */ - override func appendProperties() { + Appends all the properties using the Property.stringPresentation method + */ + override func appendProperties() + { fileContent += "\n" - for property in properties { + for property in properties{ fileContent += property.toString(true) } } - + /** - Appends all the defined constructors (aka initializers) in lang.constructors to the fileContent - */ - override func appendInitializers() { - if !includeConstructors { + Appends all the defined constructors (aka initializers) in lang.constructors to the fileContent + */ + override func appendInitializers() + { + if !includeConstructors{ return } fileContent += "\n" - for constructorSignature in lang.headerFileData.constructorSignatures { + for constructorSignature in lang.headerFileData.constructorSignatures{ + fileContent += constructorSignature - + fileContent = fileContent.replacingOccurrences(of: modelName, with: className) } } - + + /** - Appends all the defined utility methods in lang.utilityMethods to the fileContent - */ - override func appendUtilityMethods() { - if !includeUtilities { + Appends all the defined utility methods in lang.utilityMethods to the fileContent + */ + override func appendUtilityMethods() + { + if !includeUtilities{ return } fileContent += "\n" - for methodSignature in lang.headerFileData.utilityMethodSignatures { + for methodSignature in lang.headerFileData.utilityMethodSignatures{ fileContent += methodSignature } } diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/Contents.json b/JSONExport/Images.xcassets/AppIcon.appiconset/Contents.json old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128.png old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16.png old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256.png old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32.png old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512.png old mode 100644 new mode 100755 diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png old mode 100644 new mode 100755 diff --git a/JSONExport/LangModel.swift b/JSONExport/LangModel.swift index dd2a042..b78f061 100755 --- a/JSONExport/LangModel.swift +++ b/JSONExport/LangModel.swift @@ -7,105 +7,109 @@ import Foundation -class LangModel { - var arrayType: String! - var basicTypesWithSpecialFetchingNeeds: [String]! - var basicTypesWithSpecialFetchingNeedsReplacements: [String]! - var basicTypesWithSpecialFetchingNeedsTypeCast: [String]! - var basicTypesWithSpecialStoringNeeds: [String]! - var booleanGetter: String! - var briefDescription: String! - var constructors: [Constructor]! - var dataTypes: DataType! - var displayLangName: String! - var fileExtension: String = "" - var genericType: String! - var getter: String! - var importForEachCustomType: String! - var importHeaderFile: String! - var instanceVarDefinition: String! - var instanceVarWithSpeicalDefinition: String! - var typesNeedSpecialDefinition: [String]! - var langName: String = "" - var constVarDefinition: String! - var modelDefinition: String! - var modelDefinitionWithParent: String! - var defaultParentWithUtilityMethods: String! - var modelEnd: String! - var modelStart: String = "" - var setter: String! - var staticImports: String! - var supportsFirstLineStatement: Bool! - var firstLineHint: String! - var utilityMethods: [UtilityMethod]! - var reservedKeywords: [String]! - var wordsToRemoveToGetArrayElementsType: [String]! - var headerFileData: HeaderFileData! - var supportMutualRelationships: Bool! - var author: Author! - /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary) { - arrayType = dictionary["arrayType"] as? String - basicTypesWithSpecialFetchingNeeds = dictionary["basicTypesWithSpecialFetchingNeeds"] as? [String] +class LangModel{ + + var arrayType : String! + var basicTypesWithSpecialFetchingNeeds : [String]! + var basicTypesWithSpecialFetchingNeedsReplacements : [String]! + var basicTypesWithSpecialFetchingNeedsTypeCast : [String]! + var basicTypesWithSpecialStoringNeeds : [String]! + var booleanGetter : String! + var briefDescription : String! + var constructors : [Constructor]! + var dataTypes : DataType! + var displayLangName : String! + var fileExtension : String = "" + var genericType : String! + var getter : String! + var importForEachCustomType : String! + var importHeaderFile : String! + var instanceVarDefinition : String! + var instanceVarWithSpeicalDefinition : String! + var typesNeedSpecialDefinition : [String]! + var langName : String = "" + var constVarDefinition : String! + var modelDefinition : String! + var modelDefinitionWithParent : String! + var defaultParentWithUtilityMethods : String! + var modelEnd : String! + var modelStart : String = "" + var setter : String! + var staticImports : String! + var supportsFirstLineStatement : Bool! + var firstLineHint : String! + var utilityMethods : [UtilityMethod]! + var reservedKeywords : [String]! + var wordsToRemoveToGetArrayElementsType : [String]! + var headerFileData : HeaderFileData! + var supportMutualRelationships : Bool! + var author : Author! + /** + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary){ + arrayType = dictionary["arrayType"] as? String + basicTypesWithSpecialFetchingNeeds = dictionary["basicTypesWithSpecialFetchingNeeds"] as? [String] basicTypesWithSpecialFetchingNeedsReplacements = dictionary["basicTypesWithSpecialFetchingNeedsReplacements"] as? [String] basicTypesWithSpecialFetchingNeedsTypeCast = dictionary["basicTypesWithSpecialFetchingNeedsTypeCast"] as? [String] basicTypesWithSpecialStoringNeeds = dictionary["basicTypesWithSpecialStoringNeeds"] as? [String] - booleanGetter = dictionary["booleanGetter"] as? String + booleanGetter = dictionary["booleanGetter"] as? String briefDescription = dictionary["briefDescription"] as? String - - constructors = [Constructor]() - if let constructorsArray = dictionary["constructors"] as? [NSDictionary] { - for dic in constructorsArray { - let value = Constructor(fromDictionary: dic) - constructors.append(value) - } - } - if let dataTypesData = dictionary["dataTypes"] as? NSDictionary { - dataTypes = DataType(fromDictionary: dataTypesData) - } + + constructors = [Constructor]() + if let constructorsArray = dictionary["constructors"] as? [NSDictionary]{ + for dic in constructorsArray{ + let value = Constructor(fromDictionary: dic) + constructors.append(value) + } + } + if let dataTypesData = dictionary["dataTypes"] as? NSDictionary{ + dataTypes = DataType(fromDictionary: dataTypesData) + } importHeaderFile = dictionary["importHeaderFile"] as? String - displayLangName = dictionary["displayLangName"] as? String - fileExtension = dictionary["fileExtension"] as! String - genericType = dictionary["genericType"] as? String - getter = dictionary["getter"] as? String - importForEachCustomType = dictionary["importForEachCustomType"] as? String - instanceVarDefinition = dictionary["instanceVarDefinition"] as? String + displayLangName = dictionary["displayLangName"] as? String + fileExtension = dictionary["fileExtension"] as! String + genericType = dictionary["genericType"] as? String + getter = dictionary["getter"] as? String + importForEachCustomType = dictionary["importForEachCustomType"] as? String + instanceVarDefinition = dictionary["instanceVarDefinition"] as? String instanceVarWithSpeicalDefinition = dictionary["instanceVarWithSpeicalDefinition"] as? String typesNeedSpecialDefinition = dictionary["typesNeedSpecialDefinition"] as? [String] - - langName = dictionary["langName"] as! String + + langName = dictionary["langName"] as! String constVarDefinition = dictionary["constVarDefinition"] as? String - modelDefinition = dictionary["modelDefinition"] as? String + modelDefinition = dictionary["modelDefinition"] as? String modelDefinitionWithParent = dictionary["modelDefinitionWithParent"] as? String defaultParentWithUtilityMethods = dictionary["defaultParentWithUtilityMethods"] as? String - modelEnd = dictionary["modelEnd"] as? String - if let mStart = dictionary["modelStart"] as? String { + modelEnd = dictionary["modelEnd"] as? String + if let mStart = dictionary["modelStart"] as? String{ modelStart = mStart } - setter = dictionary["setter"] as? String - staticImports = dictionary["staticImports"] as? String - supportsFirstLineStatement = (dictionary["supportsFirstLineStatement"] as? NSString)?.boolValue + setter = dictionary["setter"] as? String + staticImports = dictionary["staticImports"] as? String + supportsFirstLineStatement = (dictionary["supportsFirstLineStatement"] as? NSString)?.boolValue firstLineHint = dictionary["firstLineHint"] as? String - utilityMethods = [UtilityMethod]() - if let utilityMethodsArray = dictionary["utilityMethods"] as? [NSDictionary] { - for dic in utilityMethodsArray { - let value = UtilityMethod(fromDictionary: dic) - utilityMethods.append(value) - } - } + utilityMethods = [UtilityMethod]() + if let utilityMethodsArray = dictionary["utilityMethods"] as? [NSDictionary]{ + for dic in utilityMethodsArray{ + let value = UtilityMethod(fromDictionary: dic) + utilityMethods.append(value) + } + } reservedKeywords = dictionary["reservedKeywords"] as? [String] - wordsToRemoveToGetArrayElementsType = dictionary["wordsToRemoveToGetArrayElementsType"] as? [String] - - if let headerFileDataData = dictionary["headerFileData"] as? NSDictionary { + wordsToRemoveToGetArrayElementsType = dictionary["wordsToRemoveToGetArrayElementsType"] as? [String] + + if let headerFileDataData = dictionary["headerFileData"] as? NSDictionary{ headerFileData = HeaderFileData(fromDictionary: headerFileDataData) } - + supportMutualRelationships = (dictionary["supportMutualRelationships"] as? NSString)?.boolValue - if let authorDictionary = dictionary["author"] as? NSDictionary { + if let authorDictionary = dictionary["author"] as? NSDictionary{ author = Author(fromDictionary: authorDictionary) } - } + } + + + } diff --git a/JSONExport/Property.swift b/JSONExport/Property.swift index d57a284..eae73ab 100755 --- a/JSONExport/Property.swift +++ b/JSONExport/Property.swift @@ -33,100 +33,107 @@ import Foundation /** - Represents all the meta data needed to export a JSON property in a valid syntax for the target language - */ -class Property: Equatable { +Represents all the meta data needed to export a JSON property in a valid syntax for the target language +*/ +class Property : Equatable{ + /** - The native name that is suitable to export the JSON property in the target language - */ - var nativeName: String - + The native name that is suitable to export the JSON property in the target language + */ + var nativeName : String + /** - The JSON property name to fetch the value of this property from a JSON object - */ - var jsonName: String - - var constName: String? - + The JSON property name to fetch the value of this property from a JSON object + */ + var jsonName : String + + var constName : String? + /** - The string representation for the property type - */ - var type: String - + The string representation for the property type + */ + var type : String + /** - Whether the property represents a custom type - */ - var isCustomClass: Bool - + Whether the property represents a custom type + */ + var isCustomClass : Bool + /** - Whether the property represents an array - */ - var isArray: Bool - + Whether the property represents an array + */ + var isArray : Bool + /** - The target language model - */ - var lang: LangModel - + The target language model + */ + var lang : LangModel + /** - A sample value which this property represents - */ - var sampleValue: AnyObject! - + A sample value which this property represents + */ + var sampleValue : AnyObject! + + /** - If this property is an array, this property should contain the type for its elements - */ - var elementsType = "" - + If this property is an array, this property should contain the type for its elements + */ + var elementsType = "" + /** - For array properties, depetermines if the elements type is a custom type - */ + For array properties, depetermines if the elements type is a custom type + */ var elementsAreOfCustomType = false - + /** - Returns a valid property declaration using the LangModel.instanceVarDefinition value - */ - func toString(_ forHeaderFile: Bool = false) -> String { - var string: String! - if forHeaderFile { - if lang.headerFileData.instanceVarWithSpeicalDefinition != nil, lang.headerFileData.typesNeedSpecialDefinition.index(of: type) != nil { + Returns a valid property declaration using the LangModel.instanceVarDefinition value + */ + func toString(_ forHeaderFile: Bool = false) -> String + { + var string : String! + if forHeaderFile{ + if lang.headerFileData.instanceVarWithSpeicalDefinition != nil && lang.headerFileData.typesNeedSpecialDefinition.index(of: type) != nil{ string = lang.headerFileData.instanceVarWithSpeicalDefinition - } else { + }else{ string = lang.headerFileData.instanceVarDefinition } - - } else { - if lang.instanceVarWithSpeicalDefinition != nil, lang.typesNeedSpecialDefinition.index(of: type) != nil { + + + }else{ + if lang.instanceVarWithSpeicalDefinition != nil && lang.typesNeedSpecialDefinition.index(of: type) != nil{ string = lang.instanceVarWithSpeicalDefinition - } else { + }else{ string = lang.instanceVarDefinition } } - + string = string.replacingOccurrences(of: varType, with: type) string = string.replacingOccurrences(of: varName, with: nativeName) string = string.replacingOccurrences(of: jsonKeyName, with: jsonName) return string } - - func toConstVar(_ className: String) -> String { - var string: String! + + func toConstVar(_ className: String) -> String + { + var string : String! if lang.constVarDefinition != nil { string = lang.constVarDefinition } else { string = "" } - constName = "k" + className + nativeName.uppercaseFirstChar() - + self.constName = "k"+className+nativeName.uppercaseFirstChar() + string = string.replacingOccurrences(of: constKeyName, with: constName!) string = string.replacingOccurrences(of: jsonKeyName, with: jsonName) return string } - - /** - The designated initializer for the class - */ - init(jsonName: String, nativeName: String, type: String, isArray: Bool, isCustomClass: Bool, lang: LangModel) { + + + /** + The designated initializer for the class + */ + init(jsonName: String, nativeName: String, type: String, isArray: Bool, isCustomClass: Bool, lang: LangModel) + { self.jsonName = jsonName.replacingOccurrences(of: " ", with: "") self.nativeName = nativeName.replacingOccurrences(of: " ", with: "") self.type = type @@ -134,19 +141,25 @@ class Property: Equatable { self.isCustomClass = isCustomClass self.lang = lang } - + + /** - Convenience initializer which calls the designated initializer with isArray = false and isCustomClass = false - */ - convenience init(jsonName: String, nativeName: String, type: String, lang: LangModel) { + Convenience initializer which calls the designated initializer with isArray = false and isCustomClass = false + */ + convenience init(jsonName: String, nativeName: String, type: String, lang: LangModel){ self.init(jsonName: jsonName, nativeName: nativeName, type: type, isArray: false, isCustomClass: false, lang: lang) } + + + + } -// For Equatable implementation -func == (lhs: Property, rhs: Property) -> Bool { +//For Equatable implementation +func ==(lhs: Property, rhs: Property) -> Bool +{ var matched = ObjectIdentifier(lhs) == ObjectIdentifier(rhs) - if !matched { + if !matched{ matched = (lhs.nativeName == rhs.nativeName && lhs.jsonName == rhs.jsonName && lhs.type == rhs.type && lhs.isCustomClass == rhs.isCustomClass && lhs.isArray == rhs.isArray && lhs.elementsType == rhs.elementsType && lhs.elementsAreOfCustomType == rhs.elementsAreOfCustomType) } return matched diff --git a/JSONExport/SharedConstants.swift b/JSONExport/SharedConstants.swift index a6dda87..83591f7 100755 --- a/JSONExport/SharedConstants.swift +++ b/JSONExport/SharedConstants.swift @@ -46,3 +46,4 @@ let lowerCaseModelName = "" let jsonKeyName = "" let constKeyName = "" let additionalCustomTypeProperty = "" + diff --git a/JSONExport/SharedUtilityMethods.swift b/JSONExport/SharedUtilityMethods.swift index c901289..b322001 100755 --- a/JSONExport/SharedUtilityMethods.swift +++ b/JSONExport/SharedUtilityMethods.swift @@ -8,111 +8,114 @@ import Foundation + /** - Creats and returns the type name for the passed value +Creats and returns the type name for the passed value - - parameter value: example value to figure out its type - - returns: the type name - */ -func propertyTypeName(_ value: AnyObject, lang: LangModel) -> String { +- parameter value: example value to figure out its type +- returns: the type name +*/ +func propertyTypeName(_ value : AnyObject, lang: LangModel) -> String +{ var name = "" - if value is NSArray { - name = typeNameForArrayOfElements(value as! NSArray, lang: lang) - } else if value is NSNumber { + if value is NSArray{ + name = typeNameForArrayOfElements(value as! NSArray, lang:lang) + }else if value is NSNumber{ name = typeForNumber(value as! NSNumber, lang: lang) - } else if value is NSString { - let booleans: [String] = ["True", "true", "TRUE", "False", "false", "FALSE"] - if booleans.index(of: value as! String) != nil { + }else if value is NSString{ + let booleans : [String] = ["True", "true", "TRUE", "False", "false", "FALSE"] + if booleans.index(of: (value as! String)) != nil{ name = lang.dataTypes.boolType - } else { + }else{ name = lang.dataTypes.stringType } - } else if value is NSNull { + }else if value is NSNull{ name = lang.genericType } - + return name } /** - Tries to figur out the type of the elements of the passed array and returns the type that can be used as the type of any element in the array +Tries to figur out the type of the elements of the passed array and returns the type that can be used as the type of any element in the array - - parameter elements: array to try to find out which type is suitable for its elements +- parameter elements: array to try to find out which type is suitable for its elements - - returns: typeName the type name as String - */ +- returns: typeName the type name as String +*/ -func typeNameForArrayElements(_ elements: NSArray, lang: LangModel) -> String { - var typeName: String! +func typeNameForArrayElements(_ elements: NSArray, lang: LangModel) -> String{ + var typeName : String! let genericType = lang.genericType - if elements.count == 0 { + if elements.count == 0{ typeName = genericType } - for element in elements { + for element in elements{ let currElementTypeName = propertyTypeName(element as AnyObject, lang: lang) - - if typeName == nil { + + if typeName == nil{ typeName = currElementTypeName - - } else { - if typeName != currElementTypeName { + + }else{ + if typeName != currElementTypeName{ typeName = genericType break } } } - + return typeName } /** - Tries to figur out the type of the elements of the passed array and returns the type of the array that can hold these values +Tries to figur out the type of the elements of the passed array and returns the type of the array that can hold these values - - parameter elements: array to try to find out which type is suitable for its elements +- parameter elements: array to try to find out which type is suitable for its elements - - returns: the type name - */ -func typeNameForArrayOfElements(_ elements: NSArray, lang: LangModel) -> String { - var typeName: String! +- returns: the type name +*/ +func typeNameForArrayOfElements(_ elements: NSArray, lang: LangModel) -> String{ + var typeName : String! let genericType = lang.arrayType.replacingOccurrences(of: elementType, with: lang.genericType) - if elements.count == 0 { + if elements.count == 0{ typeName = genericType } - for element in elements { + for element in elements{ let currElementTypeName = propertyTypeName(element as AnyObject, lang: lang) - + let arrayTypeName = lang.arrayType.replacingOccurrences(of: elementType, with: currElementTypeName) - - if typeName == nil { + + if typeName == nil{ typeName = arrayTypeName - - } else { - if typeName != arrayTypeName { + + }else{ + if typeName != arrayTypeName{ typeName = genericType break } } } - + return typeName } /** - Returns one of the possible types for any numeric value (int, float, double, etc...) +Returns one of the possible types for any numeric value (int, float, double, etc...) - - parameter number: the numeric value - - returns: the type name - */ -func typeForNumber(_ number: NSNumber, lang: LangModel) -> String { +- parameter number: the numeric value +- returns: the type name +*/ +func typeForNumber(_ number : NSNumber, lang: LangModel) -> String +{ let numberType = CFNumberGetType(number as CFNumber) - - var typeName: String! - switch numberType { + + var typeName : String! + switch numberType{ case .charType: - if number.int32Value == 0 || number.int32Value == 1 { - // it seems to be boolean + if (number.int32Value == 0 || number.int32Value == 1){ + //it seems to be boolean typeName = lang.dataTypes.boolType - } else { + }else{ typeName = lang.dataTypes.characterType } case .shortType, .intType: @@ -126,22 +129,24 @@ func typeForNumber(_ number: NSNumber, lang: LangModel) -> String { default: typeName = lang.dataTypes.intType } - + return typeName } + /** - Creates and returns a dictionary who is built up by combining all the dictionary elements in the passed array. +Creates and returns a dictionary who is built up by combining all the dictionary elements in the passed array. - - parameter array: array of dictionaries. - - returns: dictionary that combines all the dictionary elements in the array. - */ -func unionDictionaryFromArrayElements(_ array: NSArray) -> NSDictionary { +- parameter array: array of dictionaries. +- returns: dictionary that combines all the dictionary elements in the array. +*/ +func unionDictionaryFromArrayElements(_ array: NSArray) -> NSDictionary +{ let dictionary = NSMutableDictionary() - for item in array { - if let dic = item as? NSDictionary { - // loop all over its keys - for key in dic.allKeys as! [String] { + for item in array{ + if let dic = item as? NSDictionary{ + //loop all over its keys + for key in dic.allKeys as! [String]{ dictionary[key] = dic[key] } } @@ -149,33 +154,43 @@ func unionDictionaryFromArrayElements(_ array: NSArray) -> NSDictionary { return dictionary } + + + /** - Cleans up the passed string from any control characters. +Cleans up the passed string from any control characters. - - parameter string: the string to be cleaned up - - returns: a clean version of the passed string - */ +- parameter string: the string to be cleaned up +- returns: a clean version of the passed string +*/ -func stringByRemovingControlCharacters(_ string: String) -> String { +func stringByRemovingControlCharacters(_ string: String) -> String +{ let controlChars = CharacterSet.controlCharacters var range = string.rangeOfCharacter(from: controlChars) - var cleanString = string - while range != nil, !range!.isEmpty { + var cleanString = string; + while range != nil && !range!.isEmpty{ cleanString = cleanString.replacingCharacters(in: range!, with: "") range = cleanString.rangeOfCharacter(from: controlChars) } - + return cleanString + } -func runOnBackground(_ task: @escaping () -> Void) { + + +func runOnBackground(_ task: @escaping () -> Void) +{ DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async { - task() + task(); } } -func runOnUiThread(_ task: @escaping () -> Void) { - DispatchQueue.main.async { () -> Void in - task() - } +func runOnUiThread(_ task: @escaping () -> Void) +{ + DispatchQueue.main.async(execute: { () -> Void in + task(); + }) } + diff --git a/JSONExport/StringExtension.swift b/JSONExport/StringExtension.swift index 924acc7..6a3e5ca 100755 --- a/JSONExport/StringExtension.swift +++ b/JSONExport/StringExtension.swift @@ -32,66 +32,70 @@ import Foundation -extension String { +extension String{ /** - Very simple method converts the last characters of a string to convert from plural to singular. For example "parties" will be changed to "party" and "stars" will be changed to "star" - The method does not handle any special cases, like uncountable name i.e "people" will not be converted to "person" - */ - func toSingular() -> String { + Very simple method converts the last characters of a string to convert from plural to singular. For example "parties" will be changed to "party" and "stars" will be changed to "star" + The method does not handle any special cases, like uncountable name i.e "people" will not be converted to "person" + */ + func toSingular() -> String + { var singular = self - let length = count + let length = self.count if length > 3 { - let range = index(endIndex, offsetBy: -3) ..< endIndex - + let range = self.index(self.endIndex, offsetBy: -3).. 2 { - let range = index(endIndex, offsetBy: -1) ..< endIndex - + let range = self.index(self.endIndex, offsetBy: -1).. String { - if count > 0 { - let range = startIndex ..< index(startIndex, offsetBy: 1) - + Converts the first character to its lower case version + + - returns: the converted version + */ + func lowercaseFirstChar() -> String{ + if self.count > 0 { + let range = self.startIndex.. String { - if count > 0 { - let range = startIndex ..< index(startIndex, offsetBy: 1) - + Converts the first character to its upper case version + + - returns: the converted version + */ + func uppercaseFirstChar() -> String{ + if self.count > 0 { + let range = startIndex.. != nil{\n\t\t\tdictionary[\"\"] = \n\t\t}\n", "bodyEnd": "\t}\n", "signature": "\tfunc toDictionary() -> [String:Any]", - "forEachCustomTypeProperty": "\t\tif != nil{\n\t\t\tdictionary[\"\"] = .toDictionary()\n\t\t}\n", + "forEachCustomTypeProperty": "\t\tif != nil{\n\t\t\tdictionary[\"\"] = !.toDictionary()\n\t\t}\n", "forEachArrayOfCustomTypeProperty": "\t\tif != nil{\n\t\t\tvar dictionaryElements = [[String:Any]]()\n\t\t\tfor Element in {\n\t\t\t\tdictionaryElements.append(Element.toDictionary())\n\t\t\t}\n\t\t\tdictionary[\"\"] = dictionaryElements\n\t\t}\n", "returnStatement": "\t\treturn dictionary\n", "body": "\t\tvar dictionary = [String:Any]()\n", @@ -92,13 +92,13 @@ "bodyStart": "{\n", "bodyEnd": "\t}\n", "fetchBasicTypePropertyFromMap": "\t\t = dictionary[\"\"] as? \n", - "signature": "\tinit(fromDictionary dictionary: [String:Any])", + "signature": "\tinit(fromDictionary dictionary: [String: Any]) ", "fetchArrayOfCustomTypePropertyFromMap": "\t\t = ()\n\t\tif let Array = dictionary[\"\"] as? [[String:Any]]{\n\t\t\tfor dic in Array{\n\t\t\t\tlet value = (fromDictionary: dic)\n\t\t\t\t.append(value)\n\t\t\t}\n\t\t}\n", "comment": "\t/**\n\t * Instantiate the instance using the passed dictionary values to set the properties values\n\t */\n", - "fetchCustomTypePropertyFromMap": "\t\tif let Data = dictionary[\"\"] as? [String:Any]{\n\t\t\t\t = (fromDictionary: Data)\n\t\t\t}\n" + "fetchCustomTypePropertyFromMap": "\t\tif let Data = dictionary[\"\"] as? [String:Any] {\n\t\t\t = (fromDictionary: Data)\n\t\t}\n" } ], - "modelDefinition": "\nstruct ", + "modelDefinition": "\nstruct ", "genericType": "AnyObject", "getter": "", "setter": "", @@ -107,7 +107,7 @@ "basicTypesWithSpecialFetchingNeeds": [ ], "displayLangName": "Swift - Struct", - "instanceVarDefinition": "\tvar : !\n", + "instanceVarDefinition": "\tvar : ?\n", "supportsFirstLineStatement": "false", "modelEnd": "\n}", "staticImports": "import Foundation", diff --git a/JSONExport/Supported Languages/SwiftyJSON-Class.json b/JSONExport/Supported Languages/SwiftyJSON-Class.json index af485bf..6c707f8 100755 --- a/JSONExport/Supported Languages/SwiftyJSON-Class.json +++ b/JSONExport/Supported Languages/SwiftyJSON-Class.json @@ -71,15 +71,15 @@ "briefDescription": "Defines how your JSON objects can be mapped to Swift classes using the SwiftyJSON library", "utilityMethods": [ { - "forEachProperty": "\t\tif != nil{\n\t\t\tdictionary[\"\"] = \n\t\t}\n", + "forEachProperty": "\t\tif != nil {\n\t\t\tdictionary[\"\"] = \n\t\t}\n", "bodyEnd": "\t}\n", - "signature": "\tfunc toDictionary() -> [String:Any]", - "forEachCustomTypeProperty": "\t\tif != nil{\n\t\t\tdictionary[\"\"] = .toDictionary()\n\t\t}\n", - "forEachArrayOfCustomTypeProperty": "\t\tif != nil{\n\t\t\tvar dictionaryElements = [[String:Any]]()\n\t\t\tfor Element in {\n\t\t\t\tdictionaryElements.append(Element.toDictionary())\n\t\t\t}\n\t\t\tdictionary[\"\"] = dictionaryElements\n\t\t}\n", + "signature": "\tvar dictonaryValue: [String:Any] {", + "forEachCustomTypeProperty": "\t\tif != nil {\n\t\t\tdictionary[\"\"] = .toDictionary()\n\t\t}\n", + "forEachArrayOfCustomTypeProperty": "\t\tif != nil {\n\t\t\tvar dictionaryElements = [[String:Any]]()\n\t\t\tfor Element in {\n\t\t\t\tdictionaryElements.append(Element.toDictionary())\n\t\t\t}\n\t\t\tdictionary[\"\"] = dictionaryElements\n\t\t}\n", "returnStatement": "\t\treturn dictionary\n", "body": "\t\tvar dictionary = [String:Any]()\n", "comment": "\t/**\n\t * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property\n\t */\n", - "bodyStart": "\n\t{\n" + "bodyStart": "\n\t\n" }, { "forEachProperty": " = aDecoder.decodeObject(forKey: \"\") as? \n", @@ -119,13 +119,35 @@ ], "defaultParentWithUtilityMethods": "NSObject, NSCoding", "constructors": [ + { + "fetchArrayOfBasicTypePropertyFromMap": "", + "fetchBasicTypeWithSpecialNeedsPropertyFromMap": "", + "bodyStart": "{\n\t\tsuper.init()\t\n", + "bodyEnd": "\t}\n", + "fetchBasicTypePropertyFromMap": "", + "signature": "\toverride init() ", + "fetchArrayOfCustomTypePropertyFromMap": "", + "comment": "\t/**\n\t * Initiates the instance.\n\t */\n", + "fetchCustomTypePropertyFromMap": "" + }, + { + "fetchArrayOfBasicTypePropertyFromMap": "", + "fetchBasicTypeWithSpecialNeedsPropertyFromMap": "", + "bodyStart": "{\n\t\tself.init(json: JSON(object))\t\n", + "bodyEnd": "\t}\n", + "fetchBasicTypePropertyFromMap": "", + "signature": "\tconvenience init(object: Any) ", + "fetchArrayOfCustomTypePropertyFromMap": "", + "comment": "\t/**\n\t * Initiates the instance based on the object.\n\t */\n", + "fetchCustomTypePropertyFromMap": "" + }, { "fetchArrayOfBasicTypePropertyFromMap": "\t\t = ()\n\t\tlet Array = json[\"\"].arrayValue\n\t\tfor Json in Array{\n\t\t\t.append(Json.)\n\t\t}\n", "fetchBasicTypeWithSpecialNeedsPropertyFromMap": "\t\t = json[\"\"].\n", - "bodyStart": "{\n\t\tif json.isEmpty{\n\t\t\treturn\n\t\t}\n", + "bodyStart": "{\n\t\t\n", "bodyEnd": "\t}\n", "fetchBasicTypePropertyFromMap": "", - "signature": "\tinit(fromJson json: JSON!)", + "signature": "\trequired init(json: JSON)", "fetchArrayOfCustomTypePropertyFromMap": "\t\t = ()\n\t\tlet Array = json[\"\"].arrayValue\n\t\tfor Json in Array{\n\t\t\tlet value = (fromJson: Json)\n\t\t\t.append(value)\n\t\t}\n", "comment": "\t/**\n\t * Instantiate the instance using the passed json values to set the properties values\n\t */\n", "fetchCustomTypePropertyFromMap": "\t\tlet Json = json[\"\"]\n\t\tif !Json.isEmpty{\n\t\t\t = (fromJson: Json)\n\t\t}\n" @@ -147,8 +169,8 @@ "AnyObject" ], "arrayType": "[]", - "modelDefinitionWithParent": "\n\nclass : ", - "instanceVarDefinition": "\tvar : !\n", + "modelDefinitionWithParent": "\n\nclass : ", + "instanceVarDefinition": "\tvar : ?\n", "supportsFirstLineStatement": "false", "modelEnd": "\n}", "staticImports": "import Foundation \nimport SwiftyJSON", diff --git a/JSONExport/Swift-Codable-Unwrapped.json b/JSONExport/Swift-Codable-Unwrapped.json old mode 100644 new mode 100755 diff --git a/JSONExport/UtilityMethod.swift b/JSONExport/UtilityMethod.swift index 79ac02c..38a4512 100755 --- a/JSONExport/UtilityMethod.swift +++ b/JSONExport/UtilityMethod.swift @@ -7,31 +7,36 @@ import Foundation -class UtilityMethod { - var body: String! - var bodyEnd: String! - var bodyStart: String! - var comment: String! - var forEachArrayOfCustomTypeProperty: String! - var forEachProperty: String! - var forEachCustomTypeProperty: String! - var returnStatement: String! - var signature: String! - var forEachPropertyWithSpecialStoringNeeds: String! +class UtilityMethod{ - /** - * Instantiate the instance using the passed dictionary values to set the properties values - */ - init(fromDictionary dictionary: NSDictionary) { - forEachCustomTypeProperty = dictionary["forEachCustomTypeProperty"] as? String - body = dictionary["body"] as? String - bodyEnd = dictionary["bodyEnd"] as? String - bodyStart = dictionary["bodyStart"] as? String - comment = dictionary["comment"] as? String - forEachArrayOfCustomTypeProperty = dictionary["forEachArrayOfCustomTypeProperty"] as? String - forEachProperty = dictionary["forEachProperty"] as? String - returnStatement = dictionary["returnStatement"] as? String - signature = dictionary["signature"] as? String + + var body : String! + var bodyEnd : String! + var bodyStart : String! + var comment : String! + var forEachArrayOfCustomTypeProperty : String! + var forEachProperty : String! + var forEachCustomTypeProperty : String! + var returnStatement : String! + var signature : String! + var forEachPropertyWithSpecialStoringNeeds : String! + + /** + * Instantiate the instance using the passed dictionary values to set the properties values + */ + init(fromDictionary dictionary: NSDictionary){ + forEachCustomTypeProperty = dictionary["forEachCustomTypeProperty"] as? String + body = dictionary["body"] as? String + bodyEnd = dictionary["bodyEnd"] as? String + bodyStart = dictionary["bodyStart"] as? String + comment = dictionary["comment"] as? String + forEachArrayOfCustomTypeProperty = dictionary["forEachArrayOfCustomTypeProperty"] as? String + forEachProperty = dictionary["forEachProperty"] as? String + returnStatement = dictionary["returnStatement"] as? String + signature = dictionary["signature"] as? String forEachPropertyWithSpecialStoringNeeds = dictionary["forEachPropertyWithSpecialStoringNeeds"] as? String - } -} + } + + + +} \ No newline at end of file diff --git a/JSONExport/ViewController.swift b/JSONExport/ViewController.swift index db40a34..c81166e 100755 --- a/JSONExport/ViewController.swift +++ b/JSONExport/ViewController.swift @@ -34,58 +34,61 @@ import Cocoa class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTableViewDelegate, NSTableViewDataSource, NSTextViewDelegate { - // Shows the list of files' preview - @IBOutlet var tableView: NSTableView! - - // Connected to the top right corner to show the current parsing status - @IBOutlet var statusTextField: NSTextField! - - // Connected to the save button - @IBOutlet var saveButton: NSButton! - - // Connected to the JSON input text view + + //Shows the list of files' preview + @IBOutlet weak var tableView: NSTableView! + + //Connected to the top right corner to show the current parsing status + @IBOutlet weak var statusTextField: NSTextField! + + //Connected to the save button + @IBOutlet weak var saveButton: NSButton! + + //Connected to the JSON input text view @IBOutlet var sourceText: NSTextView! - - // Connected to the scroll view which wraps the sourceText - @IBOutlet var scrollView: NSScrollView! - - // Connected to Constructors check box - @IBOutlet var generateConstructors: NSButtonCell! - - // Connected to Utility Methods check box - @IBOutlet var generateUtilityMethods: NSButtonCell! - - // Connected to root class name field - @IBOutlet var classNameField: NSTextFieldCell! - - // Connected to parent class name field - @IBOutlet var parentClassName: NSTextField! - - // Connected to class prefix field - @IBOutlet var classPrefixField: NSTextField! - - // Connected to the first line statement field - @IBOutlet var firstLineField: NSTextField! - - // Connected to the languages pop up - @IBOutlet var languagesPopup: NSPopUpButton! - - // Holds the currently selected language - var selectedLang: LangModel! - - // Returns the title of the selected language in the languagesPopup - // Call only from main thread - var selectedLanguageName: String { - assert(Thread.isMainThread) + + //Connected to the scroll view which wraps the sourceText + @IBOutlet weak var scrollView: NSScrollView! + + //Connected to Constructors check box + @IBOutlet weak var generateConstructors: NSButtonCell! + + //Connected to Utility Methods check box + @IBOutlet weak var generateUtilityMethods: NSButtonCell! + + //Connected to root class name field + @IBOutlet weak var classNameField: NSTextFieldCell! + + //Connected to parent class name field + @IBOutlet weak var parentClassName: NSTextField! + + //Connected to class prefix field + @IBOutlet weak var classPrefixField: NSTextField! + + //Connected to the first line statement field + @IBOutlet weak var firstLineField: NSTextField! + + //Connected to the languages pop up + @IBOutlet weak var languagesPopup: NSPopUpButton! + + + //Holds the currently selected language + var selectedLang : LangModel! + + //Returns the title of the selected language in the languagesPopup + //Call only from main thread + var selectedLanguageName : String + { + assert(Thread.isMainThread); return languagesPopup.titleOfSelectedItem! } - - // Should hold list of supported languages, where the key is the language name and the value is LangModel instance - var langs: [String: LangModel] = [String: LangModel]() - - // Holds list of the generated files - var files: [FileRepresenter] = [FileRepresenter]() - + + //Should hold list of supported languages, where the key is the language name and the value is LangModel instance + var langs : [String : LangModel] = [String : LangModel]() + + //Holds list of the generated files + var files : [FileRepresenter] = [FileRepresenter]() + override func viewDidLoad() { super.viewDidLoad() saveButton.isEnabled = false @@ -95,70 +98,75 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl setLanguagesSelection() loadLastSelectedLanguage() updateUIFieldsForSelectedLanguage() - tableView.backgroundColor = .clear } - + /** Sets the values of languagesPopup items' titles */ - func setLanguagesSelection() { + func setLanguagesSelection() + { let langNames = Array(langs.keys).sorted() languagesPopup.removeAllItems() languagesPopup.addItems(withTitles: langNames) + } - + /** Sets the needed configurations for show the line numbers in the input text view */ - func setupNumberedTextView() { + func setupNumberedTextView() + { let lineNumberView = NoodleLineNumberView(scrollView: scrollView) scrollView.hasHorizontalRuler = false scrollView.hasVerticalRuler = true scrollView.verticalRulerView = lineNumberView scrollView.rulersVisible = true sourceText.font = NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize) + } - + /** Updates the visible fields according to the selected language */ - func updateUIFieldsForSelectedLanguage() { + func updateUIFieldsForSelectedLanguage() + { loadSelectedLanguageModel() - if selectedLang.supportsFirstLineStatement != nil && selectedLang.supportsFirstLineStatement! { + if selectedLang.supportsFirstLineStatement != nil && selectedLang.supportsFirstLineStatement!{ firstLineField.isHidden = false firstLineField.placeholderString = selectedLang.firstLineHint - } else { + }else{ firstLineField.isHidden = true } - - if selectedLang.modelDefinitionWithParent != nil || selectedLang.headerFileData?.modelDefinitionWithParent != nil { + + if selectedLang.modelDefinitionWithParent != nil || selectedLang.headerFileData?.modelDefinitionWithParent != nil{ parentClassName.isHidden = false - } else { + }else{ parentClassName.isHidden = true } } - + /** Loads last selected language by user */ - func loadLastSelectedLanguage() { - guard let lastSelectedLanguage = UserDefaults.standard.value(forKey: "selectedLanguage") as? String else { + func loadLastSelectedLanguage() + { + guard let lastSelectedLanguage = UserDefaults.standard.value(forKey: "selectedLanguage") as? String else{ return } - - if langs[lastSelectedLanguage] != nil { + + if langs[lastSelectedLanguage] != nil{ languagesPopup.selectItem(withTitle: lastSelectedLanguage) } } - - // MARK: - Handling pre defined languages - - func loadSupportedLanguages() { - if let langFiles = Bundle.main.urls(forResourcesWithExtension: "json", subdirectory: nil) { - for langFile in langFiles { - if let data = try? Data(contentsOf: langFile), let langDictionary = (try? JSONSerialization.jsonObject(with: data, options: [])) as? NSDictionary { + + //MARK: - Handling pre defined languages + func loadSupportedLanguages() + { + if let langFiles = Bundle.main.urls(forResourcesWithExtension: "json", subdirectory: nil){ + for langFile in langFiles{ + if let data = try? Data(contentsOf: langFile), let langDictionary = (try? JSONSerialization.jsonObject(with: data, options: [])) as? NSDictionary{ let lang = LangModel(fromDictionary: langDictionary) - if langs[lang.displayLangName] != nil { + if langs[lang.displayLangName] != nil{ continue } langs[lang.displayLangName] = lang @@ -167,89 +175,106 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } } + // MARK: - parse the json file - - func parseJSONData(jsonData: Data!) { + func parseJSONData(jsonData: Data!) + { let jsonString = String(data: jsonData, encoding: .utf8) - + sourceText.string = jsonString! } - - // MARK: - Handlind events - - @IBAction func openJSONFiles(sender _: AnyObject) { - let oPanel: NSOpenPanel = NSOpenPanel() - oPanel.canChooseDirectories = false - oPanel.canChooseFiles = true - oPanel.allowsMultipleSelection = false - oPanel.allowedFileTypes = ["json", "JSON"] - oPanel.prompt = "Choose JSON file" - - oPanel.beginSheetModal(for: view.window!) { button in - if button.rawValue == NSFileHandlingPanelOKButton { - let jsonPath = oPanel.urls.first!.path - let fileHandle = FileHandle(forReadingAtPath: jsonPath) - let urlStr: String = oPanel.urls.first!.lastPathComponent - self.classNameField.stringValue = urlStr.replacingOccurrences(of: ".json", with: "") - self.parseJSONData(jsonData: fileHandle!.readDataToEndOfFile()) - } - } - } - - @IBAction func toggleConstructors(_: AnyObject) { + + //MARK: - Handlind events + + @IBAction func openJSONFiles(sender: AnyObject) + { + let oPanel: NSOpenPanel = NSOpenPanel() + oPanel.canChooseDirectories = false + oPanel.canChooseFiles = true + oPanel.allowsMultipleSelection = false + oPanel.allowedFileTypes = ["json","JSON"] + oPanel.prompt = "Choose JSON file" + + oPanel.beginSheetModal(for: self.view.window!) { button in + if button.rawValue == NSFileHandlingPanelOKButton { + let jsonPath = oPanel.urls.first!.path + let fileHandle = FileHandle(forReadingAtPath: jsonPath) + let urlStr:String = oPanel.urls.first!.lastPathComponent + self.classNameField.stringValue = urlStr.replacingOccurrences(of: ".json", with: "") + self.parseJSONData(jsonData: (fileHandle!.readDataToEndOfFile())) + } + } + } + + + @IBAction func toggleConstructors(_ sender: AnyObject) + { generateClasses() } - - @IBAction func toggleUtilities(_: AnyObject) { + + + @IBAction func toggleUtilities(_ sender: AnyObject) + { generateClasses() } - - @IBAction func rootClassNameChanged(_: AnyObject) { + + @IBAction func rootClassNameChanged(_ sender: AnyObject) { generateClasses() } - - @IBAction func parentClassNameChanged(_: AnyObject) { + + @IBAction func parentClassNameChanged(_ sender: AnyObject) + { generateClasses() } - - @IBAction func classPrefixChanged(_: AnyObject) { + + + @IBAction func classPrefixChanged(_ sender: AnyObject) + { generateClasses() } - - @IBAction func selectedLanguageChanged(_: AnyObject) { + + + @IBAction func selectedLanguageChanged(_ sender: AnyObject) + { updateUIFieldsForSelectedLanguage() generateClasses() DispatchQueue.main.async { UserDefaults.standard.set(self.selectedLanguageName, forKey: "selectedLanguage") } + } - - @IBAction func firstLineChanged(_: AnyObject) { + + + @IBAction func firstLineChanged(_ sender: AnyObject) + { generateClasses() } - - // MARK: - NSTextDelegate - - func textDidChange(_: Notification) { + + //MARK: - NSTextDelegate + + func textDidChange(_ notification: Notification) { generateClasses() } - - // MARK: - Language selection handling - - func loadSelectedLanguageModel() { - selectedLang = langs[self.selectedLanguageName] + + + //MARK: - Language selection handling + func loadSelectedLanguageModel() + { + selectedLang = langs[self.selectedLanguageName] } - - // MARK: - NSUserNotificationCenterDelegate - - func userNotificationCenter(_: NSUserNotificationCenter, - shouldPresent _: NSUserNotification) -> Bool { + + + //MARK: - NSUserNotificationCenterDelegate + func userNotificationCenter(_ center: NSUserNotificationCenter, + shouldPresent notification: NSUserNotification) -> Bool + { return true } - - // MARK: - Showing the open panel and save files - - @IBAction func saveFiles(_: AnyObject) { + + + //MARK: - Showing the open panel and save files + @IBAction func saveFiles(_ sender: AnyObject) + { let openPanel = NSOpenPanel() openPanel.allowsOtherFileTypes = false openPanel.treatsFilePackagesAsDirectories = false @@ -257,125 +282,135 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl openPanel.canChooseDirectories = true openPanel.canCreateDirectories = true openPanel.prompt = "Choose" - openPanel.beginSheetModal(for: view.window!) { button in - if button.rawValue == NSFileHandlingPanelOKButton { - self.saveToPath(openPanel.url!.path) - self.showDoneSuccessfully() - } - } + openPanel.beginSheetModal(for: self.view.window!){ button in + if button.rawValue == NSFileHandlingPanelOKButton{ + self.saveToPath(openPanel.url!.path) + self.showDoneSuccessfully() + } + } } - + + /** Saves all the generated files in the specified path - + - parameter path: in which to save the files */ - func saveToPath(_ path: String) { - var error: NSError? - for file in files { + func saveToPath(_ path : String) + { + var error : NSError? + for file in files{ var fileContent = file.fileContent - if fileContent == "" { + if fileContent == ""{ fileContent = file.toString() } var fileExtension = selectedLang.fileExtension - if file is HeaderFileRepresenter { + if file is HeaderFileRepresenter{ fileExtension = selectedLang.headerFileData.headerFileExtension } let filePath = "\(path)/\(file.className).\(fileExtension)" - + do { try fileContent.write(toFile: filePath, atomically: false, encoding: String.Encoding.utf8) } catch let error1 as NSError { error = error1 } - if error != nil { + if error != nil{ showError(error!) break } } } - - // MARK: - Messages - + + + //MARK: - Messages /** Shows the top right notification. Call it after saving the files successfully */ - func showDoneSuccessfully() { + func showDoneSuccessfully() + { let notification = NSUserNotification() notification.title = "Success!" notification.informativeText = "Your \(selectedLang.langName) model files have been generated successfully." notification.deliveryDate = Date() - + let center = NSUserNotificationCenter.default center.delegate = self center.deliver(notification) } - + /** Shows an NSAlert for the passed error */ - func showError(_ error: NSError!) { - if error == nil { - return + func showError(_ error: NSError!) + { + if error == nil{ + return; } let alert = NSAlert(error: error) alert.runModal() } - + /** Shows the passed error status message */ - func showErrorStatus(_ errorMessage: String) { + func showErrorStatus(_ errorMessage: String) + { + statusTextField.textColor = NSColor.red statusTextField.stringValue = errorMessage } - + /** Shows the passed success status message */ - func showSuccessStatus(_ successMessage: String) { + func showSuccessStatus(_ successMessage: String) + { + statusTextField.textColor = NSColor.green statusTextField.stringValue = successMessage } - - // MARK: - Generate files content - + + + + //MARK: - Generate files content /** Validates the sourceText string input, and takes any needed action to generate the model classes and view them in the preview panel */ - func generateClasses() { + func generateClasses() + { saveButton.isEnabled = false var str = sourceText.string - - if str.count == 0 { - runOnUiThread { - // Nothing to do, just clear any generated files + + if str.count == 0{ + runOnUiThread{ + //Nothing to do, just clear any generated files self.files.removeAll(keepingCapacity: false) self.tableView.reloadData() } - return + return; } var rootClassName = classNameField.stringValue - if rootClassName.count == 0 { + if rootClassName.count == 0{ rootClassName = "RootClass" } sourceText.isEditable = false - // Do the lengthy process in background, it takes time with more complicated JSONs + //Do the lengthy process in background, it takes time with more complicated JSONs runOnBackground { str = stringByRemovingControlCharacters(str) - if let data = str.data(using: String.Encoding.utf8) { - var error: NSError? + if let data = str.data(using: String.Encoding.utf8){ + var error : NSError? do { - let jsonData: Any = try JSONSerialization.jsonObject(with: data, options: []) - var json: NSDictionary! - if jsonData is NSDictionary { - // fine nothing to do - json = jsonData as? NSDictionary - } else { + let jsonData : Any = try JSONSerialization.jsonObject(with: data, options: []) + var json : NSDictionary! + if jsonData is NSDictionary{ + //fine nothing to do + json = jsonData as? NSDictionary + }else{ json = unionDictionaryFromArrayElements(jsonData as! NSArray) } - - runOnUiThread { + + runOnUiThread{ self.loadSelectedLanguageModel() self.files.removeAll(keepingCapacity: false) let fileGenerator = self.prepareAndGetFilesBuilder() @@ -385,34 +420,35 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl self.sourceText.isEditable = true self.showSuccessStatus("Valid JSON structure") self.saveButton.isEnabled = true - + self.tableView.reloadData() self.tableView.layout() } } catch let error1 as NSError { error = error1 - runOnUiThread { () -> Void in + runOnUiThread({ () -> Void in self.sourceText.isEditable = true self.saveButton.isEnabled = false - if error != nil { + if error != nil{ print(error!) } self.showErrorStatus("It seems your JSON object is not valid!") - } - + }) + } catch { fatalError() } } } } - + /** Creates and returns an instance of FilesContentBuilder. It also configure the values from the UI components to the instance. I.e includeConstructors - + - returns: instance of configured FilesContentBuilder */ - func prepareAndGetFilesBuilder() -> FilesContentBuilder { + func prepareAndGetFilesBuilder() -> FilesContentBuilder + { let filesBuilder = FilesContentBuilder.instance filesBuilder.includeConstructors = (generateConstructors.state == NSControl.StateValue.on) filesBuilder.includeUtilities = (generateUtilityMethods.state == NSControl.StateValue.on) @@ -422,20 +458,27 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl filesBuilder.parentClassName = parentClassName.stringValue return filesBuilder } - - // MARK: - NSTableViewDataSource - - func numberOfRows(in _: NSTableView) -> Int { + + + + + //MARK: - NSTableViewDataSource + func numberOfRows(in tableView: NSTableView) -> Int + { return files.count } - - // MARK: - NSTableViewDelegate - - func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? { + + + //MARK: - NSTableViewDelegate + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? + { let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier("fileCell"), owner: self) as! FilePreviewCell let file = files[row] cell.file = file - + return cell } + + + }