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/CHANGELOG.md b/CHANGELOG.md index 8ee3cca..d772ebe 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +* 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 #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 +- Fixed an issue with trying to figure the selected language from an UI element outside the UI thread + + +* 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 diff --git a/JSONExport.xcodeproj/project.pbxproj b/JSONExport.xcodeproj/project.pbxproj index c4f6227..9c222c3 100755 --- a/JSONExport.xcodeproj/project.pbxproj +++ b/JSONExport.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 01ACC24B1FBB42E300C410C2 /* Swift-Codable.json in Resources */ = {isa = PBXBuildFile; fileRef = 01ACC24A1FBB42E300C410C2 /* Swift-Codable.json */; }; 166AF5CE1CEF6C3600516EDD /* Swift-Struct-Gloss.json in Resources */ = {isa = PBXBuildFile; fileRef = 166AF5CD1CEF6C3600516EDD /* Swift-Struct-Gloss.json */; }; + 3D41804522559064000A79E3 /* Swift-Codable-Realm.json in Resources */ = {isa = PBXBuildFile; fileRef = 3D41804422559064000A79E3 /* Swift-Codable-Realm.json */; }; 608896441CF278440074CB80 /* Author.swift in Sources */ = {isa = PBXBuildFile; fileRef = 608896431CF278440074CB80 /* Author.swift */; }; 60FB8FF01B9B361600290979 /* Java-Android Realm.json in Resources */ = {isa = PBXBuildFile; fileRef = 60FB8FE61B9B361600290979 /* Java-Android Realm.json */; }; 60FB8FF11B9B361600290979 /* Java-Android.json in Resources */ = {isa = PBXBuildFile; fileRef = 60FB8FE71B9B361600290979 /* Java-Android.json */; }; @@ -30,6 +31,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 */; }; @@ -48,6 +51,7 @@ /* Begin PBXFileReference section */ 01ACC24A1FBB42E300C410C2 /* Swift-Codable.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "Swift-Codable.json"; path = "Supported Languages/Swift-Codable.json"; sourceTree = ""; }; 166AF5CD1CEF6C3600516EDD /* Swift-Struct-Gloss.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "Swift-Struct-Gloss.json"; path = "Supported Languages/Swift-Struct-Gloss.json"; sourceTree = ""; }; + 3D41804422559064000A79E3 /* Swift-Codable-Realm.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Swift-Codable-Realm.json"; sourceTree = ""; }; 608896431CF278440074CB80 /* Author.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Author.swift; sourceTree = ""; }; 60FB8FE61B9B361600290979 /* Java-Android Realm.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "Java-Android Realm.json"; path = "Supported Languages/Java-Android Realm.json"; sourceTree = ""; }; 60FB8FE71B9B361600290979 /* Java-Android.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "Java-Android.json"; path = "Supported Languages/Java-Android.json"; sourceTree = ""; }; @@ -72,6 +76,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 +159,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 */, @@ -168,6 +176,7 @@ 60FB8FEE1B9B361600290979 /* Swift-Struct.json */, 98978FC01D5B6B19000C1846 /* Swift-Struct-Unbox.json */, 01ACC24A1FBB42E300C410C2 /* Swift-Codable.json */, + 3D41804422559064000A79E3 /* Swift-Codable-Realm.json */, 60FB8FEF1B9B361600290979 /* SwiftyJSON-Class.json */, ); name = "Supported Languages"; @@ -255,12 +264,12 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Ahmed Ali"; TargetAttributes = { E2FA87B41A059AC100648EB6 = { CreatedOnToolsVersion = 6.1; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -294,8 +303,10 @@ 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 */, + 3D41804522559064000A79E3 /* Swift-Codable-Realm.json in Resources */, 98978FC11D5B6B19000C1846 /* Swift-Struct-Unbox.json in Resources */, 60FB8FFD1B9B3F6400290979 /* Swift-Realm.json in Resources */, 60FB8FF71B9B361600290979 /* Swift-Mappable.json in Resources */, @@ -303,6 +314,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 */, ); @@ -358,14 +370,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 +413,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; }; name = Debug; }; @@ -404,14 +425,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 +461,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; }; name = Release; }; @@ -447,7 +477,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 +493,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.xcodeproj/project.xcworkspace/xcuserdata/narleiamoreira.xcuserdatad/UserInterfaceState.xcuserstate b/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/narleiamoreira.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..2d83ad7 Binary files /dev/null and b/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/narleiamoreira.xcuserdatad/UserInterfaceState.xcuserstate differ 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 0000000..46a37a2 Binary files /dev/null and b/JSONExport.xcodeproj/project.xcworkspace/xcuserdata/serhii-londar.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JSONExport.xcodeproj/xcuserdata/narleiamoreira.xcuserdatad/xcschemes/xcschememanagement.plist b/JSONExport.xcodeproj/xcuserdata/narleiamoreira.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..1ccfc36 --- /dev/null +++ b/JSONExport.xcodeproj/xcuserdata/narleiamoreira.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + 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 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/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 fb0c6a5..fafc686 100755 --- a/JSONExport/FilePreviewCell.swift +++ b/JSONExport/FilePreviewCell.swift @@ -21,27 +21,29 @@ class FilePreviewCell: NSTableCellView, NSTextViewDelegate { var file: FileRepresenter!{ didSet{ if file != nil{ - var fileName = file.className - fileName += "." - if file is HeaderFileRepresenter{ - fileName += file.lang.headerFileData.headerFileExtension - }else{ - fileName += file.lang.fileExtension - } - classNameLabel.stringValue = fileName - if(textView != nil){ - textView.string = file.toString() - } - - if file.includeConstructors{ - constructors.state = NSOnState - }else{ - constructors.state = NSOffState - } - if file.includeUtilities{ - utilities.state = NSOnState - }else{ - utilities.state = NSOffState + DispatchQueue.main.async { + var fileName = self.file.className + fileName += "." + if self.file is HeaderFileRepresenter{ + fileName += self.file.lang.headerFileData.headerFileExtension + }else{ + fileName += self.file.lang.fileExtension + } + self.classNameLabel.stringValue = fileName + if(self.textView != nil){ + self.textView.string = self.file.toString() + } + + if self.file.includeConstructors{ + self.constructors.state = NSControl.StateValue.on + }else{ + self.constructors.state = NSControl.StateValue.off + } + if self.file.includeUtilities{ + self.utilities.state = NSControl.StateValue.on + }else{ + self.utilities.state = NSControl.StateValue.off + } } }else{ classNameLabel.stringValue = "" @@ -55,7 +57,9 @@ class FilePreviewCell: NSTableCellView, NSTextViewDelegate { super.awakeFromNib() if textView != nil{ textView.delegate = self - setupNumberedTextView() + DispatchQueue.main.async { + self.setupNumberedTextView() + } } } @@ -66,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() } @@ -82,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..4284ccf 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" } } @@ -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) @@ -419,7 +430,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 @@ -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/HeaderFileRepresenter.swift b/JSONExport/HeaderFileRepresenter.swift index c819679..05e2895 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) } } @@ -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/Images.xcassets/AppIcon.appiconset/128x128.png b/JSONExport/Images.xcassets/AppIcon.appiconset/128x128.png deleted file mode 100755 index 0adf9fd..0000000 Binary files a/JSONExport/Images.xcassets/AppIcon.appiconset/128x128.png and /dev/null differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/16x16.png b/JSONExport/Images.xcassets/AppIcon.appiconset/16x16.png deleted file mode 100755 index e7e3250..0000000 Binary files a/JSONExport/Images.xcassets/AppIcon.appiconset/16x16.png and /dev/null differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/256x256.png b/JSONExport/Images.xcassets/AppIcon.appiconset/256x256.png deleted file mode 100755 index dbc42a2..0000000 Binary files a/JSONExport/Images.xcassets/AppIcon.appiconset/256x256.png and /dev/null differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/32x32-1.png b/JSONExport/Images.xcassets/AppIcon.appiconset/32x32-1.png deleted file mode 100755 index bf2071d..0000000 Binary files a/JSONExport/Images.xcassets/AppIcon.appiconset/32x32-1.png and /dev/null differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/32x32.png b/JSONExport/Images.xcassets/AppIcon.appiconset/32x32.png deleted file mode 100755 index bf2071d..0000000 Binary files a/JSONExport/Images.xcassets/AppIcon.appiconset/32x32.png and /dev/null differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/64x64.png b/JSONExport/Images.xcassets/AppIcon.appiconset/64x64.png deleted file mode 100755 index 1cd0dfc..0000000 Binary files a/JSONExport/Images.xcassets/AppIcon.appiconset/64x64.png and /dev/null differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/Contents.json b/JSONExport/Images.xcassets/AppIcon.appiconset/Contents.json old mode 100755 new mode 100644 index 930ec57..8db8046 --- a/JSONExport/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/JSONExport/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,64 +1,68 @@ { + "info" : { + "author" : "xcode", + "version" : 1 + }, "images" : [ { + "filename" : "icon_16x16.png", "size" : "16x16", "idiom" : "mac", - "filename" : "16x16.png", "scale" : "1x" }, { + "filename" : "icon_16x16@2x.png", "size" : "16x16", "idiom" : "mac", - "filename" : "32x32.png", "scale" : "2x" }, { + "filename" : "icon_32x32.png", "size" : "32x32", "idiom" : "mac", - "filename" : "32x32-1.png", "scale" : "1x" }, { + "filename" : "icon_32x32@2x.png", "size" : "32x32", "idiom" : "mac", - "filename" : "64x64.png", "scale" : "2x" }, { + "filename" : "icon_128x128.png", "size" : "128x128", "idiom" : "mac", - "filename" : "128x128.png", "scale" : "1x" }, { + "filename" : "icon_128x128@2x.png", "size" : "128x128", "idiom" : "mac", - "filename" : "256x256.png", "scale" : "2x" }, { - "idiom" : "mac", + "filename" : "icon_256x256.png", "size" : "256x256", + "idiom" : "mac", "scale" : "1x" }, { - "idiom" : "mac", + "filename" : "icon_256x256@2x.png", "size" : "256x256", + "idiom" : "mac", "scale" : "2x" }, { - "idiom" : "mac", + "filename" : "icon_512x512.png", "size" : "512x512", + "idiom" : "mac", "scale" : "1x" }, { - "idiom" : "mac", + "filename" : "icon_512x512@2x.png", "size" : "512x512", + "idiom" : "mac", "scale" : "2x" } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } + ] } \ No newline at end of file diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128.png new file mode 100644 index 0000000..fe91b3a Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128.png differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png new file mode 100644 index 0000000..02209a8 Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16.png new file mode 100644 index 0000000..315e354 Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16.png differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png new file mode 100644 index 0000000..a4cd043 Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256.png new file mode 100644 index 0000000..02209a8 Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256.png differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png new file mode 100644 index 0000000..b10b810 Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32.png new file mode 100644 index 0000000..a4cd043 Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32.png differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png new file mode 100644 index 0000000..d563afa Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512.png new file mode 100644 index 0000000..b10b810 Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512.png differ diff --git a/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png new file mode 100644 index 0000000..6b71f03 Binary files /dev/null and b/JSONExport/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png differ 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/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.. = 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}" } @@ -66,4 +73,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 +} 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", 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/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" }, diff --git a/JSONExport/Swift-Codable-Realm.json b/JSONExport/Swift-Codable-Realm.json new file mode 100755 index 0000000..976ec8e --- /dev/null +++ b/JSONExport/Swift-Codable-Realm.json @@ -0,0 +1,117 @@ +{ + "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", + "dynamic", + "Object" + ], + "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" + }, + { + "fetchBasicTypeWithSpecialNeedsPropertyFromMap": "", + "bodyStart": "{\n\t\tlet values = try decoder.container(keyedBy: CodingKeys.self)\n", + "bodyEnd": "\t}\n", + "fetchBasicTypePropertyFromMap": "\t\t = try values.decodeIfPresent(.self, forKey: .)\n", + "signature": "\tconvenience required init(from decoder: Decoder) throws ", + "fetchArrayOfCustomTypePropertyFromMap": "\t\t = try values.decodeIfPresent(.self, forKey: .)\n", + "comment": "", + "fetchCustomTypePropertyFromMap": "\t\t = try (from: decoder)\n" + } + ], + "modelDefinition": "\nclass : Object,Codable ", + "genericType": "String", + "getter": "", + "setter": "", + "fileExtension": "swift", + "arrayType": "[]", + "basicTypesWithSpecialFetchingNeeds": [ + ], + "displayLangName": "Swift - Codable - Realm", + "instanceVarDefinition": "\t@objc dynamic var : = ()\n", + "supportsFirstLineStatement": "false", + "modelEnd": "\n}", + "staticImports": "import Foundation \nimport RealmSwift", + "langName": "Swift" +} 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 bb7f4a2..c81166e 100755 --- a/JSONExport/ViewController.swift +++ b/JSONExport/ViewController.swift @@ -70,14 +70,16 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl //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! } @@ -99,8 +101,8 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } /** - Sets the values of languagesPopup items' titles - */ + Sets the values of languagesPopup items' titles + */ func setLanguagesSelection() { let langNames = Array(langs.keys).sorted() @@ -110,8 +112,8 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } /** - Sets the needed configurations for show the line numbers in the input text view - */ + Sets the needed configurations for show the line numbers in the input text view + */ func setupNumberedTextView() { let lineNumberView = NoodleLineNumberView(scrollView: scrollView) @@ -119,13 +121,13 @@ 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) } /** - Updates the visible fields according to the selected language - */ + Updates the visible fields according to the selected language + */ func updateUIFieldsForSelectedLanguage() { loadSelectedLanguageModel() @@ -144,7 +146,7 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } /** - Loads last selected language by user + Loads last selected language by user */ func loadLastSelectedLanguage() { @@ -157,11 +159,10 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } } - //MARK: - Handling pre defined languages func loadSupportedLanguages() { - if let langFiles = Bundle.main.urls(forResourcesWithExtension: "json", subdirectory: nil) as [URL]!{ + 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) @@ -170,47 +171,40 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } langs[lang.displayLangName] = lang } - - } } - } - - // MARK: - parse the json file func parseJSONData(jsonData: Data!) { let jsonString = String(data: jsonData, encoding: .utf8) - sourceText.string = jsonString + 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!, completionHandler: { (button : Int) -> 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) @@ -244,7 +238,10 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl { updateUIFieldsForSelectedLanguage() generateClasses() - UserDefaults.standard.set(selectedLanguageName, forKey: "selectedLanguage") + DispatchQueue.main.async { + UserDefaults.standard.set(self.selectedLanguageName, forKey: "selectedLanguage") + } + } @@ -263,14 +260,13 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl //MARK: - Language selection handling func loadSelectedLanguageModel() { - selectedLang = langs[selectedLanguageName] - + selectedLang = langs[self.selectedLanguageName] } //MARK: - NSUserNotificationCenterDelegate func userNotificationCenter(_ center: NSUserNotificationCenter, - shouldPresent notification: NSUserNotification) -> Bool + shouldPresent notification: NSUserNotification) -> Bool { return true } @@ -286,22 +282,20 @@ 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() + } + } } - - /** - Saves all the generated files in the specified path - - parameter path: in which to save the files - */ + /** + Saves all the generated files in the specified path + + - parameter path: in which to save the files + */ func saveToPath(_ path : String) { var error : NSError? @@ -331,23 +325,23 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl //MARK: - Messages /** - Shows the top right notification. Call it after saving the files successfully - */ + Shows the top right notification. Call it after saving the files successfully + */ 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 - */ + Shows an NSAlert for the passed error + */ func showError(_ error: NSError!) { if error == nil{ @@ -358,18 +352,18 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } /** - Shows the passed error status message - */ + Shows the passed error status message + */ func showErrorStatus(_ errorMessage: String) { - + statusTextField.textColor = NSColor.red statusTextField.stringValue = errorMessage } /** - Shows the passed success status message - */ + Shows the passed success status message + */ func showSuccessStatus(_ successMessage: String) { @@ -381,21 +375,23 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl //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 - */ + Validates the sourceText string input, and takes any needed action to generate the model classes and view them in the preview panel + */ func generateClasses() { saveButton.isEnabled = false - var str = sourceText.string! + var str = sourceText.string - if str.characters.count == 0{ - //Nothing to do, just clear any generated files - files.removeAll(keepingCapacity: false) - tableView.reloadData() + if str.count == 0{ + runOnUiThread{ + //Nothing to do, just clear any generated files + self.files.removeAll(keepingCapacity: false) + self.tableView.reloadData() + } return; } var rootClassName = classNameField.stringValue - if rootClassName.characters.count == 0{ + if rootClassName.count == 0{ rootClassName = "RootClass" } sourceText.isEditable = false @@ -409,22 +405,24 @@ 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) } - self.loadSelectedLanguageModel() - self.files.removeAll(keepingCapacity: false) - let fileGenerator = self.prepareAndGetFilesBuilder() - fileGenerator.addFileWithName(&rootClassName, jsonObject: json, files: &self.files) - fileGenerator.fixReferenceMismatches(inFiles: self.files) - self.files = Array(self.files.reversed()) + 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) + self.files = Array(self.files.reversed()) 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 @@ -445,15 +443,15 @@ class ViewController: NSViewController, NSUserNotificationCenterDelegate, NSTabl } /** - 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 - */ + 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 { 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 @@ -474,14 +472,13 @@ 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 return cell } - - + + } - diff --git a/README.md b/README.md index 1238788..25c3865 100755 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ To Do * Beside raw JSON, load the model raw data from plist files as well. -Known Limitions: +Known Limitations: ======================== * When exporting to subclasses of NSManagedObject, some data types can not be exported. For example core data does not have data type for "array of strings"; in turn, if your JSON contains an array of strings, the exported file will not compile without you fixing the type mismatch. * When exporting subclasses of RLMObject, you will have to enter the default values of premitive types manually. This is because of dynamic properties limition that prevents you from having an optional premitive type.