diff --git a/Package.resolved b/Package.resolved index 1426924c..3c71e9da 100644 --- a/Package.resolved +++ b/Package.resolved @@ -24,8 +24,8 @@ "repositoryURL": "https://github.com/tomlokhorst/XcodeEdit", "state": { "branch": null, - "revision": "dc76efefc4370b754c55cc586f8e6603080c6ac8", - "version": "2.7.6" + "revision": "dab519997ca05833470c88f0926b27498911ecbf", + "version": "2.7.7" } } ] diff --git a/Sources/RswiftCore/Generators/NibStructGenerator.swift b/Sources/RswiftCore/Generators/NibStructGenerator.swift index e7480593..e1462824 100644 --- a/Sources/RswiftCore/Generators/NibStructGenerator.swift +++ b/Sources/RswiftCore/Generators/NibStructGenerator.swift @@ -204,12 +204,17 @@ struct NibStructGenerator: StructGenerator { // Validation let validateImagesLines = nib.usedImageIdentifiers.uniqueAndSorted() - .map { - "if UIKit.UIImage(named: \"\($0)\", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: \"[R.swift] Image named '\($0)' is used in nib '\(nib.name)', but couldn't be loaded.\") }" + .map { nameCatalog -> String in + if nameCatalog.isSystemCatalog { + return "if #available(iOS 13.0, *) { if UIKit.UIImage(systemName: \"\(nameCatalog.name)\") == nil { throw Rswift.ValidationError(description: \"[R.swift] System image named '\(nameCatalog.name)' is used in nib '\(nib.name)', but couldn't be loaded.\") } }" + } else { + return "if UIKit.UIImage(named: \"\(nameCatalog.name)\", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: \"[R.swift] Image named '\(nameCatalog.name)' is used in nib '\(nib.name)', but couldn't be loaded.\") }" + } } let validateColorLines = nib.usedColorResources.uniqueAndSorted() - .map { - "if UIKit.UIColor(named: \"\($0)\", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: \"[R.swift] Color named '\($0)' is used in storyboard '\(nib.name)', but couldn't be loaded.\") }" + .compactMap { nameCatalog -> String? in + if nameCatalog.isSystemCatalog { return nil } + return "if UIKit.UIColor(named: \"\(nameCatalog.name)\", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: \"[R.swift] Color named '\(nameCatalog.name)' is used in nib '\(nib.name)', but couldn't be loaded.\") }" } let validateColorLinesWithAvailableIf = ["if #available(iOS 11.0, tvOS 11.0, *) {"] + validateColorLines.map { $0.indent(with: " ") } + diff --git a/Sources/RswiftCore/Generators/StoryboardGenerator.swift b/Sources/RswiftCore/Generators/StoryboardGenerator.swift index ed866563..f85fad43 100644 --- a/Sources/RswiftCore/Generators/StoryboardGenerator.swift +++ b/Sources/RswiftCore/Generators/StoryboardGenerator.swift @@ -163,12 +163,17 @@ struct StoryboardStructGenerator: StructGenerator { // Validation let validateImagesLines = storyboard.usedImageIdentifiers.uniqueAndSorted() - .map { - "if UIKit.UIImage(named: \"\($0)\", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: \"[R.swift] Image named '\($0)' is used in storyboard '\(storyboard.name)', but couldn't be loaded.\") }" + .map { nameCatalog -> String in + if nameCatalog.isSystemCatalog { + return "if #available(iOS 13.0, *) { if UIKit.UIImage(systemName: \"\(nameCatalog.name)\") == nil { throw Rswift.ValidationError(description: \"[R.swift] System image named '\(nameCatalog.name)' is used in storyboard '\(storyboard.name)', but couldn't be loaded.\") } }" + } else { + return "if UIKit.UIImage(named: \"\(nameCatalog.name)\", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: \"[R.swift] Image named '\(nameCatalog.name)' is used in storyboard '\(storyboard.name)', but couldn't be loaded.\") }" + } } let validateColorLines = storyboard.usedColorResources.uniqueAndSorted() - .map { - "if UIKit.UIColor(named: \"\($0)\", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: \"[R.swift] Color named '\($0)' is used in storyboard '\(storyboard.name)', but couldn't be loaded.\") }" + .compactMap { nameCatalog -> String? in + if nameCatalog.isSystemCatalog { return nil } + return "if UIKit.UIColor(named: \"\(nameCatalog.name)\", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: \"[R.swift] Color named '\(nameCatalog.name)' is used in storyboard '\(storyboard.name)', but couldn't be loaded.\") }" } let validateColorLinesWithAvailableIf = ["if #available(iOS 11.0, tvOS 11.0, *) {"] + validateColorLines.map { $0.indent(with: " ") } + diff --git a/Sources/RswiftCore/ResourceTypes/NameCatalog.swift b/Sources/RswiftCore/ResourceTypes/NameCatalog.swift new file mode 100644 index 00000000..80148bae --- /dev/null +++ b/Sources/RswiftCore/ResourceTypes/NameCatalog.swift @@ -0,0 +1,23 @@ +// +// NameCatalog.swift +// RswiftCore +// +// Created by Tom Lokhorst on 2020-05-08. +// + +import Foundation + +struct NameCatalog: Hashable, Comparable { + let name: String + let catalog: String? + + var isSystemCatalog: Bool { + return + catalog == "System" // for colors + || catalog == "system" // for images + } + + static func < (lhs: NameCatalog, rhs: NameCatalog) -> Bool { + lhs.name < lhs.name + } +} diff --git a/Sources/RswiftCore/ResourceTypes/Nib.swift b/Sources/RswiftCore/ResourceTypes/Nib.swift index bf22ee7d..6c05da77 100644 --- a/Sources/RswiftCore/ResourceTypes/Nib.swift +++ b/Sources/RswiftCore/ResourceTypes/Nib.swift @@ -23,8 +23,8 @@ struct Nib: WhiteListedExtensionsResourceType, ReusableContainer { let name: String let rootViews: [Type] let reusables: [Reusable] - let usedImageIdentifiers: [String] - let usedColorResources: [String] + let usedImageIdentifiers: [NameCatalog] + let usedColorResources: [NameCatalog] let usedAccessibilityIdentifiers: [String] init(url: URL) throws { @@ -58,8 +58,8 @@ internal class NibParserDelegate: NSObject, XMLParserDelegate { let ignoredRootViewElements = ["placeholder"] var rootViews: [Type] = [] var reusables: [Reusable] = [] - var usedImageIdentifiers: [String] = [] - var usedColorReferences: [String] = [] + var usedImageIdentifiers: [NameCatalog] = [] + var usedColorReferences: [NameCatalog] = [] var usedAccessibilityIdentifiers: [String] = [] // State @@ -77,12 +77,12 @@ internal class NibParserDelegate: NSObject, XMLParserDelegate { switch elementName { case "image": if let imageIdentifier = attributeDict["name"] { - usedImageIdentifiers.append(imageIdentifier) + usedImageIdentifiers.append(NameCatalog(name: imageIdentifier, catalog: attributeDict["catalog"])) } case "color": if let colorName = attributeDict["name"] { - usedColorReferences.append(colorName) + usedColorReferences.append(NameCatalog(name: colorName, catalog: attributeDict["catalog"])) } case "accessibility": diff --git a/Sources/RswiftCore/ResourceTypes/Storyboard.swift b/Sources/RswiftCore/ResourceTypes/Storyboard.swift index da204194..9639e52b 100644 --- a/Sources/RswiftCore/ResourceTypes/Storyboard.swift +++ b/Sources/RswiftCore/ResourceTypes/Storyboard.swift @@ -30,8 +30,8 @@ struct Storyboard: WhiteListedExtensionsResourceType, ReusableContainer { let viewControllers: [ViewController] let viewControllerPlaceholders: [ViewControllerPlaceholder] let usedAccessibilityIdentifiers: [String] - let usedImageIdentifiers: [String] - let usedColorResources: [String] + let usedImageIdentifiers: [NameCatalog] + let usedColorResources: [NameCatalog] let reusables: [Reusable] var initialViewController: ViewController? { @@ -128,8 +128,8 @@ private class StoryboardParserDelegate: NSObject, XMLParserDelegate { var initialViewControllerIdentifier: String? var viewControllers: [Storyboard.ViewController] = [] var viewControllerPlaceholders: [Storyboard.ViewControllerPlaceholder] = [] - var usedImageIdentifiers: [String] = [] - var usedColorReferences: [String] = [] + var usedImageIdentifiers: [NameCatalog] = [] + var usedColorReferences: [NameCatalog] = [] var usedAccessibilityIdentifiers: [String] = [] var reusables: [Reusable] = [] @@ -167,12 +167,12 @@ private class StoryboardParserDelegate: NSObject, XMLParserDelegate { case "image": if let imageIdentifier = attributeDict["name"] { - usedImageIdentifiers.append(imageIdentifier) + usedImageIdentifiers.append(NameCatalog(name: imageIdentifier, catalog: attributeDict["catalog"])) } case "color": if let colorName = attributeDict["name"] { - usedColorReferences.append(colorName) + usedColorReferences.append(NameCatalog(name: colorName, catalog: attributeDict["catalog"])) } case "accessibility": diff --git a/Sources/RswiftCore/SwiftTypes/Type.swift b/Sources/RswiftCore/SwiftTypes/Type.swift index a1542ae6..de2ad8dd 100644 --- a/Sources/RswiftCore/SwiftTypes/Type.swift +++ b/Sources/RswiftCore/SwiftTypes/Type.swift @@ -29,8 +29,8 @@ struct Type: UsedTypesProvider, CustomStringConvertible, Hashable { static let _UInt = Type(module: .stdLib, name: "UInt") static let _Double = Type(module: .stdLib, name: "Double") static let _Character = Type(module: .stdLib, name: "Character") - static let _CStringPointer = Type(module: .stdLib, name: "UnsafePointer") - static let _VoidPointer = Type(module: .stdLib, name: "UnsafePointer") + static let _CStringPointer = Type(module: .stdLib, name: SwiftIdentifier(rawValue: "UnsafePointer")) + static let _VoidPointer = Type(module: .stdLib, name: SwiftIdentifier(rawValue: "UnsafePointer")) static let _URL = Type(module: "Foundation", name: "URL") static let _Bundle = Type(module: "Foundation", name: "Bundle") static let _Locale = Type(module: "Foundation", name: "Locale")