From 23d740609d0d064e26af414eeb067936f1539e2b Mon Sep 17 00:00:00 2001 From: Tom Lokhorst Date: Sat, 30 Jul 2016 15:47:19 +0200 Subject: [PATCH 1/5] Introduce SwiftIdentifier --- R.swift.xcodeproj/project.pbxproj | 12 ++--- R.swift/Generators/ColorGenerator.swift | 2 +- R.swift/Generators/ImageGenerator.swift | 2 +- R.swift/Generators/NibGenerator.swift | 2 +- .../Generators/ResourceFileGenerator.swift | 2 +- .../Generators/ReuseIdentifierGenerator.swift | 2 +- R.swift/Generators/SegueGenerator.swift | 2 +- R.swift/Generators/StoryboardGenerator.swift | 4 +- R.swift/Generators/StringsGenerator.swift | 4 +- ...dSwiftName.swift => SwiftIdentifier.swift} | 52 +++++++++++++++---- 10 files changed, 59 insertions(+), 25 deletions(-) rename R.swift/Util/{SanitizedSwiftName.swift => SwiftIdentifier.swift} (64%) diff --git a/R.swift.xcodeproj/project.pbxproj b/R.swift.xcodeproj/project.pbxproj index 6908438e..65ce1b73 100644 --- a/R.swift.xcodeproj/project.pbxproj +++ b/R.swift.xcodeproj/project.pbxproj @@ -62,9 +62,9 @@ D5B799771C199755009EA901 /* StoryboardGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B799671C1993B7009EA901 /* StoryboardGenerator.swift */; }; D5B799791C19C082009EA901 /* WhiteListedExtensionsResourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B799781C19C082009EA901 /* WhiteListedExtensionsResourceType.swift */; }; D5B7997A1C19C1BD009EA901 /* WhiteListedExtensionsResourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B799781C19C082009EA901 /* WhiteListedExtensionsResourceType.swift */; }; - D5B7997D1C1B07C3009EA901 /* SanitizedSwiftName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B7997C1C1B07C3009EA901 /* SanitizedSwiftName.swift */; }; + D5B7997D1C1B07C3009EA901 /* SwiftIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B7997C1C1B07C3009EA901 /* SwiftIdentifier.swift */; }; D5B7997F1C1B07EB009EA901 /* ErrorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B7997E1C1B07EB009EA901 /* ErrorOutput.swift */; }; - D5B799801C1B0943009EA901 /* SanitizedSwiftName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B7997C1C1B07C3009EA901 /* SanitizedSwiftName.swift */; }; + D5B799801C1B0943009EA901 /* SwiftIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B7997C1C1B07C3009EA901 /* SwiftIdentifier.swift */; }; D5B799811C1B0943009EA901 /* ErrorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B7997E1C1B07EB009EA901 /* ErrorOutput.swift */; }; D5B799831C1B8C78009EA901 /* Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B799821C1B8C78009EA901 /* Module.swift */; }; D5B7998A1C1B91A9009EA901 /* Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B799821C1B8C78009EA901 /* Module.swift */; }; @@ -139,7 +139,7 @@ D5B7996D1C19940F009EA901 /* ResourceFileGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResourceFileGenerator.swift; sourceTree = ""; }; D5B7996F1C199420009EA901 /* FontGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FontGenerator.swift; sourceTree = ""; }; D5B799781C19C082009EA901 /* WhiteListedExtensionsResourceType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhiteListedExtensionsResourceType.swift; sourceTree = ""; }; - D5B7997C1C1B07C3009EA901 /* SanitizedSwiftName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SanitizedSwiftName.swift; sourceTree = ""; }; + D5B7997C1C1B07C3009EA901 /* SwiftIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftIdentifier.swift; sourceTree = ""; }; D5B7997E1C1B07EB009EA901 /* ErrorOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorOutput.swift; sourceTree = ""; }; D5B799821C1B8C78009EA901 /* Module.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Module.swift; sourceTree = ""; }; D5C4227D1B711FDF004EA9B9 /* rswiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = rswiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -227,7 +227,7 @@ isa = PBXGroup; children = ( D5B7997E1C1B07EB009EA901 /* ErrorOutput.swift */, - D5B7997C1C1B07C3009EA901 /* SanitizedSwiftName.swift */, + D5B7997C1C1B07C3009EA901 /* SwiftIdentifier.swift */, D56F923E1C2942B400177FF7 /* Struct+ChildValidation.swift */, D58672481C21FC9700A760EC /* TypeSequenceProvider.swift */, D5EA0DFE1A3DF4E300FFEBC4 /* UtilExtensions.swift */, @@ -482,7 +482,7 @@ D5B799731C199755009EA901 /* NibGenerator.swift in Sources */, D5B129B31C3BA75A00A1C5FC /* Let.swift in Sources */, D5F97E491C1819160066D7C0 /* Font.swift in Sources */, - D5B799801C1B0943009EA901 /* SanitizedSwiftName.swift in Sources */, + D5B799801C1B0943009EA901 /* SwiftIdentifier.swift in Sources */, D5B799711C199755009EA901 /* FontGenerator.swift in Sources */, D586D1C61BE20D8600F18FEC /* Extensions.swift in Sources */, D586D1C81BE20D8600F18FEC /* Serialization.swift in Sources */, @@ -539,7 +539,7 @@ D5646DE51BE2016E0034F4D7 /* PBXObject.swift in Sources */, D56DC76D1C41758800623437 /* AccessModifier.swift in Sources */, D5B129AF1C3BA5F900A1C5FC /* Let.swift in Sources */, - D5B7997D1C1B07C3009EA901 /* SanitizedSwiftName.swift in Sources */, + D5B7997D1C1B07C3009EA901 /* SwiftIdentifier.swift in Sources */, D5A0A82A1C47920A0089ED2C /* SwiftCodeConverible.swift in Sources */, D5B799681C1993B7009EA901 /* StoryboardGenerator.swift in Sources */, D5B799701C199420009EA901 /* FontGenerator.swift in Sources */, diff --git a/R.swift/Generators/ColorGenerator.swift b/R.swift/Generators/ColorGenerator.swift index 7efa28e1..047474a6 100644 --- a/R.swift/Generators/ColorGenerator.swift +++ b/R.swift/Generators/ColorGenerator.swift @@ -29,7 +29,7 @@ struct ColorGenerator: Generator { if palette.colors.isEmpty { return nil } let name = sanitizedSwiftName(palette.filename) - let groupedColors = palette.colors.groupBySwiftNames { $0.0 } + let groupedColors = palette.colors.groupBySwiftIdentifiers { $0.0 } for (sanitizedName, duplicates) in groupedColors.duplicates { warn("Skipping \(duplicates.count) colors in palette '\(palette.filename)' because symbol '\(sanitizedName)' would be generated for all of these colors: \(duplicates.joinWithSeparator(", "))") diff --git a/R.swift/Generators/ImageGenerator.swift b/R.swift/Generators/ImageGenerator.swift index c53fe007..91acda7e 100644 --- a/R.swift/Generators/ImageGenerator.swift +++ b/R.swift/Generators/ImageGenerator.swift @@ -62,7 +62,7 @@ struct ImageGenerator: Generator { } let allFunctions = assetFolderImageFunctions + imageFunctions - let groupedFunctions = allFunctions.groupBySwiftNames { $0.name } + let groupedFunctions = allFunctions.groupBySwiftIdentifiers { $0.name } for (sanitizedName, duplicates) in groupedFunctions.duplicates { warn("Skipping \(duplicates.count) images because symbol '\(sanitizedName)' would be generated for all of these images: \(duplicates.joinWithSeparator(", "))") diff --git a/R.swift/Generators/NibGenerator.swift b/R.swift/Generators/NibGenerator.swift index 085c4340..8fe4f811 100644 --- a/R.swift/Generators/NibGenerator.swift +++ b/R.swift/Generators/NibGenerator.swift @@ -36,7 +36,7 @@ struct NibGenerator: Generator { let internalStruct: Struct? init(nibs: [Nib]) { - let groupedNibs = nibs.groupBySwiftNames { $0.name } + let groupedNibs = nibs.groupBySwiftIdentifiers { $0.name } for (name, duplicates) in groupedNibs.duplicates { warn("Skipping \(duplicates.count) xibs because symbol '\(name)' would be generated for all of these xibs: \(duplicates.joinWithSeparator(", "))") diff --git a/R.swift/Generators/ResourceFileGenerator.swift b/R.swift/Generators/ResourceFileGenerator.swift index 7e5ae4b4..cd9ae12c 100644 --- a/R.swift/Generators/ResourceFileGenerator.swift +++ b/R.swift/Generators/ResourceFileGenerator.swift @@ -13,7 +13,7 @@ struct ResourceFileGenerator: Generator { let internalStruct: Struct? = nil init(resourceFiles: [ResourceFile]) { - let groupedResourceFiles = resourceFiles.groupBySwiftNames { $0.fullname } + let groupedResourceFiles = resourceFiles.groupBySwiftIdentifiers { $0.fullname } for (name, duplicates) in groupedResourceFiles.duplicates { warn("Skipping \(duplicates.count) resource files because symbol '\(name)' would be generated for all of these files: \(duplicates.joinWithSeparator(", "))") diff --git a/R.swift/Generators/ReuseIdentifierGenerator.swift b/R.swift/Generators/ReuseIdentifierGenerator.swift index d7c5ccd5..522b2056 100644 --- a/R.swift/Generators/ReuseIdentifierGenerator.swift +++ b/R.swift/Generators/ReuseIdentifierGenerator.swift @@ -18,7 +18,7 @@ struct ReuseIdentifierGenerator: Generator { .values .flatMap { $0.first } - let groupedReusables = deduplicatedReusables.groupBySwiftNames { $0.identifier } + let groupedReusables = deduplicatedReusables.groupBySwiftIdentifiers { $0.identifier } for (name, duplicates) in groupedReusables.duplicates { warn("Skipping \(duplicates.count) reuseIdentifiers because symbol '\(name)' would be generated for all of these reuseIdentifiers: \(duplicates.joinWithSeparator(", "))") diff --git a/R.swift/Generators/SegueGenerator.swift b/R.swift/Generators/SegueGenerator.swift index a1ffa180..1241557e 100644 --- a/R.swift/Generators/SegueGenerator.swift +++ b/R.swift/Generators/SegueGenerator.swift @@ -44,7 +44,7 @@ struct SegueGenerator: Generator { var structs: [Struct] = [] for (sourceType, seguesBySourceType) in deduplicatedSeguesWithInfo.groupBy({ $0.sourceType }) { - let groupedSeguesWithInfo = seguesBySourceType.groupBySwiftNames { $0.segue.identifier } + let groupedSeguesWithInfo = seguesBySourceType.groupBySwiftIdentifiers { $0.segue.identifier } for (name, duplicates) in groupedSeguesWithInfo.duplicates { warn("Skipping \(duplicates.count) segues for '\(sourceType)' because symbol '\(name)' would be generated for all of these segues, but with a different destination or segue type: \(duplicates.joinWithSeparator(", "))") diff --git a/R.swift/Generators/StoryboardGenerator.swift b/R.swift/Generators/StoryboardGenerator.swift index 834f6537..f07768b6 100644 --- a/R.swift/Generators/StoryboardGenerator.swift +++ b/R.swift/Generators/StoryboardGenerator.swift @@ -13,7 +13,7 @@ struct StoryboardGenerator: Generator { let internalStruct: Struct? init(storyboards: [Storyboard]) { - let groupedStoryboards = storyboards.groupBySwiftNames { $0.name } + let groupedStoryboards = storyboards.groupBySwiftIdentifiers { $0.name } for (name, duplicates) in groupedStoryboards.duplicates { warn("Skipping \(duplicates.count) storyboards because symbol '\(name)' would be generated for all of these storyboards: \(duplicates.joinWithSeparator(", "))") @@ -108,7 +108,7 @@ struct StoryboardGenerator: Generator { guard let storyboardIdentifier = vc.storyboardIdentifier else { return nil } return (vc, storyboardIdentifier) } - .groupBySwiftNames { $0.identifier } + .groupBySwiftIdentifiers { $0.identifier } for (name, duplicates) in groupedViewControllersWithIdentifier.duplicates { warn("Skipping \(duplicates.count) view controllers because symbol '\(name)' would be generated for all of these view controller identifiers: \(duplicates.joinWithSeparator(", "))") diff --git a/R.swift/Generators/StringsGenerator.swift b/R.swift/Generators/StringsGenerator.swift index 124169c2..b50c816e 100644 --- a/R.swift/Generators/StringsGenerator.swift +++ b/R.swift/Generators/StringsGenerator.swift @@ -15,7 +15,7 @@ struct StringsGenerator: Generator { init(localizableStrings: [LocalizableStrings]) { let localized = localizableStrings.groupBy { $0.filename } - let groupedLocalized = localized.groupBySwiftNames { $0.0 } + let groupedLocalized = localized.groupBySwiftIdentifiers { $0.0 } for (sanitizedName, duplicates) in groupedLocalized.duplicates { warn("Skipping \(duplicates.count) strings files because symbol '\(sanitizedName)' would be generated for all of these filenames: \(duplicates.joinWithSeparator(", "))") @@ -73,7 +73,7 @@ struct StringsGenerator: Generator { // Warnings about duplicates and empties for ls in strings { let filenameLocale = ls.locale.withFilename(filename) - let groupedKeys = ls.dictionary.keys.groupBySwiftNames { $0 } + let groupedKeys = ls.dictionary.keys.groupBySwiftIdentifiers { $0 } for (sanitizedName, duplicates) in groupedKeys.duplicates { warn("Skipping \(duplicates.count) strings in \(filenameLocale) because symbol '\(sanitizedName)' would be generated for all of these keys: \(duplicates.map { "'\($0)'" }.joinWithSeparator(", "))") diff --git a/R.swift/Util/SanitizedSwiftName.swift b/R.swift/Util/SwiftIdentifier.swift similarity index 64% rename from R.swift/Util/SanitizedSwiftName.swift rename to R.swift/Util/SwiftIdentifier.swift index ce152125..66a00451 100644 --- a/R.swift/Util/SanitizedSwiftName.swift +++ b/R.swift/Util/SwiftIdentifier.swift @@ -1,5 +1,5 @@ // -// SanitizedSwiftName.swift +// SwiftIdentifier.swift // R.swift // // Created by Mathijs Kadijk on 11-12-15. @@ -8,10 +8,43 @@ import Foundation +private let numberRegex = try! NSRegularExpression(pattern: "^[0-9]+", options: .CaseInsensitive) + /* -Disallowed characters: whitespace, mathematical symbols, arrows, private-use and invalid Unicode points, line- and boxdrawing characters -Special rules: Can't begin with a number -*/ + Disallowed characters: whitespace, mathematical symbols, arrows, private-use and invalid Unicode points, line- and boxdrawing characters + Special rules: Can't begin with a number + */ +struct SwiftIdentifier : CustomStringConvertible, Hashable { + let description: String + + init(name: String, lowercaseFirstCharacter: Bool = true) { + var nameComponents = name.componentsSeparatedByCharactersInSet(BlacklistedCharacters) + + let firstComponent = nameComponents.removeAtIndex(0) + let cleanedSwiftName = nameComponents.reduce(firstComponent) { $0 + $1.uppercaseFirstCharacter } + + let fullRange = NSRange(location: 0, length: cleanedSwiftName.characters.count) + let sanitizedSwiftName = numberRegex.stringByReplacingMatchesInString(cleanedSwiftName, options: [], range: fullRange, withTemplate: "") + + let capitalizedSwiftName = lowercaseFirstCharacter ? sanitizedSwiftName.lowercaseFirstCharacter : sanitizedSwiftName + + if SwiftKeywords.contains(capitalizedSwiftName) { + description = "`\(capitalizedSwiftName)`" + } + else { + description = capitalizedSwiftName + } + } + + var hashValue: Int { + return description.hashValue + } +} + +func ==(lhs: SwiftIdentifier, rhs: SwiftIdentifier) -> Bool { + return lhs.description == rhs.description +} + func sanitizedSwiftName(name: String, lowercaseFirstCharacter: Bool = true) -> String { var nameComponents = name.componentsSeparatedByCharactersInSet(BlacklistedCharacters) @@ -32,15 +65,16 @@ func sanitizedSwiftName(name: String, lowercaseFirstCharacter: Bool = true) -> S struct SwiftNameGroups { let uniques: [T] - let duplicates: [(String, [String])] // Identifiers that result in duplicate Swift names + let duplicates: [(SwiftIdentifier, [String])] // Identifiers that result in duplicate Swift names let empties: [String] // Identifiers (wrapped in quotes) that result in empty swift names } extension SequenceType { - func groupBySwiftNames(identifierSelector: Generator.Element -> String) -> SwiftNameGroups { - var groupedBy = groupBy { sanitizedSwiftName(identifierSelector($0)) } - let empties = groupedBy[""]?.map { "'\(identifierSelector($0))'" }.sort() - groupedBy[""] = nil + func groupBySwiftIdentifiers(identifierSelector: Generator.Element -> String) -> SwiftNameGroups { + var groupedBy = groupBy { SwiftIdentifier(name: identifierSelector($0)) } + let empty = SwiftIdentifier(name: "") + let empties = groupedBy[empty]?.map { "'\(identifierSelector($0))'" }.sort() + groupedBy[empty] = nil let uniques = Array(groupedBy.values.filter { $0.count == 1 }.flatten()) let duplicates = groupedBy From 5ecc967f2e40de9bd47be96713526701a9991cf7 Mon Sep 17 00:00:00 2001 From: Tom Lokhorst Date: Sat, 30 Jul 2016 18:45:31 +0200 Subject: [PATCH 2/5] Use SwiftIdentifier in Let/Var/Function --- R.swift/Generators/ColorGenerator.swift | 6 +- R.swift/Generators/FontGenerator.swift | 6 +- R.swift/Generators/ImageGenerator.swift | 80 +++++++------------ R.swift/Generators/NibGenerator.swift | 18 ++--- .../Generators/ResourceFileGenerator.swift | 6 +- .../Generators/ReuseIdentifierGenerator.swift | 2 +- R.swift/Generators/SegueGenerator.swift | 8 +- R.swift/Generators/StoryboardGenerator.swift | 6 +- R.swift/Generators/StringsGenerator.swift | 8 +- R.swift/ResourceTypes/Nib.swift | 8 +- R.swift/ResourceTypes/Storyboard.swift | 12 ++- R.swift/SwiftTypes/Function.swift | 18 ++--- R.swift/SwiftTypes/Let.swift | 8 +- R.swift/SwiftTypes/Property.swift | 8 +- R.swift/SwiftTypes/Struct.swift | 6 +- R.swift/SwiftTypes/Type.swift | 6 +- R.swift/SwiftTypes/Var.swift | 4 +- R.swift/Util/SwiftIdentifier.swift | 35 +++++--- R.swiftTests/MainTests.swift | 4 +- 19 files changed, 121 insertions(+), 128 deletions(-) diff --git a/R.swift/Generators/ColorGenerator.swift b/R.swift/Generators/ColorGenerator.swift index 047474a6..26d42aa1 100644 --- a/R.swift/Generators/ColorGenerator.swift +++ b/R.swift/Generators/ColorGenerator.swift @@ -28,7 +28,7 @@ struct ColorGenerator: Generator { private static func colorStructFromPalette(palette: ColorPalette) -> Struct? { if palette.colors.isEmpty { return nil } - let name = sanitizedSwiftName(palette.filename) + let name = SwiftIdentifier(name: palette.filename) let groupedColors = palette.colors.groupBySwiftIdentifiers { $0.0 } for (sanitizedName, duplicates) in groupedColors.duplicates { @@ -60,7 +60,7 @@ struct ColorGenerator: Generator { "#\(color.hexString) \(name)" ], isStatic: true, - name: name, + name: SwiftIdentifier(name: name), typeDefinition: .Inferred(Type.ColorResource), value: "ColorResource(name: \"\(name)\", red: \(color.redComponent), green: \(color.greenComponent), blue: \(color.blueComponent), alpha: \(color.alphaComponent))" ) @@ -74,7 +74,7 @@ struct ColorGenerator: Generator { "UIColor(red: \(color.redComponent), green: \(color.greenComponent), blue: \(color.blueComponent), alpha: \(color.alphaComponent))" ], isStatic: true, - name: name, + name: SwiftIdentifier(name: name), generics: nil, parameters: [ Function.Parameter(name: "_", type: Type._Void) diff --git a/R.swift/Generators/FontGenerator.swift b/R.swift/Generators/FontGenerator.swift index f40e0857..a1f0f49e 100644 --- a/R.swift/Generators/FontGenerator.swift +++ b/R.swift/Generators/FontGenerator.swift @@ -18,7 +18,7 @@ struct FontGenerator: Generator { Let( comments: ["Font `\($0.name)`."], isStatic: true, - name: $0.name, + name: SwiftIdentifier(name: $0.name), typeDefinition: .Inferred(Type.FontResource), value: "FontResource(fontName: \"\($0.name)\")" ) @@ -39,14 +39,14 @@ struct FontGenerator: Generator { return Function( comments: ["`UIFont(name: \"\(font.name)\", size: ...)`"], isStatic: true, - name: font.name, + name: SwiftIdentifier(name: font.name), generics: nil, parameters: [ Function.Parameter(name: "size", localName: "size", type: Type._CGFloat) ], doesThrow: false, returnType: Type._UIFont.asOptional(), - body: "return UIFont(resource: \(sanitizedSwiftName(font.name)), size: size)" + body: "return UIFont(resource: \(SwiftIdentifier(name: font.name)), size: size)" ) } } diff --git a/R.swift/Generators/ImageGenerator.swift b/R.swift/Generators/ImageGenerator.swift index 91acda7e..45bbaeba 100644 --- a/R.swift/Generators/ImageGenerator.swift +++ b/R.swift/Generators/ImageGenerator.swift @@ -13,56 +13,16 @@ struct ImageGenerator: Generator { let internalStruct: Struct? = nil init(assetFolders: [AssetFolder], images: [Image]) { - let assetFolderImageFunctions = assetFolders + let assetFolderImageNames = assetFolders .flatMap { $0.imageAssets } - .map { - Function( - comments: ["`UIImage(named: \"\($0)\", bundle: ..., traitCollection: ...)`"], - isStatic: true, - name: $0, - generics: nil, - parameters: [ - Function.Parameter( - name: "compatibleWithTraitCollection", - localName: "traitCollection", - type: Type._UITraitCollection.asOptional(), - defaultValue: "nil" - ) - ], - doesThrow: false, - returnType: Type._UIImage.asOptional(), - body: "return UIImage(resource: R.image.\(sanitizedSwiftName($0)), compatibleWithTraitCollection: traitCollection)" - ) - } - let uniqueImages = images + let imagesNames = images .groupBy { $0.name } .values - .flatMap { $0.first } + .flatMap { $0.first?.name } - let imageFunctions = uniqueImages - .map { - Function( - comments: ["`UIImage(named: \"\($0.name)\", bundle: ..., traitCollection: ...)`"], - isStatic: true, - name: $0.name, - generics: nil, - parameters: [ - Function.Parameter( - name: "compatibleWithTraitCollection", - localName: "traitCollection", - type: Type._UITraitCollection.asOptional(), - defaultValue: "nil" - ) - ], - doesThrow: false, - returnType: Type._UIImage.asOptional(), - body: "return \(Type._UIImage.name)(resource: R.image.\(sanitizedSwiftName($0.name)), compatibleWithTraitCollection: traitCollection)" - ) - } - - let allFunctions = assetFolderImageFunctions + imageFunctions - let groupedFunctions = allFunctions.groupBySwiftIdentifiers { $0.name } + let allFunctions = assetFolderImageNames + imagesNames + let groupedFunctions = allFunctions.groupBySwiftIdentifiers { $0 } for (sanitizedName, duplicates) in groupedFunctions.duplicates { warn("Skipping \(duplicates.count) images because symbol '\(sanitizedName)' would be generated for all of these images: \(duplicates.joinWithSeparator(", "))") @@ -78,13 +38,13 @@ struct ImageGenerator: Generator { let imageLets = groupedFunctions .uniques - .map { + .map { name in Let( - comments: ["Image `\($0.name)`."], + comments: ["Image `\(name)`."], isStatic: true, - name: $0.name, + name: SwiftIdentifier(name: name), typeDefinition: .Inferred(Type.ImageResource), - value: "\(Type.ImageResource.name)(bundle: _R.hostingBundle, name: \"\($0.name)\")" + value: "\(Type.ImageResource.name)(bundle: _R.hostingBundle, name: \"\(name)\")" ) } @@ -94,8 +54,28 @@ struct ImageGenerator: Generator { implements: [], typealiasses: [], properties: imageLets.map(anyProperty), - functions: groupedFunctions.uniques, + functions: groupedFunctions.uniques.map(ImageGenerator.functionForImageName), structs: [] ) } + + static func functionForImageName(name: String) -> Function { + return Function( + comments: ["`UIImage(named: \"\(name)\", bundle: ..., traitCollection: ...)`"], + isStatic: true, + name: SwiftIdentifier(name: name), + generics: nil, + parameters: [ + Function.Parameter( + name: "compatibleWithTraitCollection", + localName: "traitCollection", + type: Type._UITraitCollection.asOptional(), + defaultValue: "nil" + ) + ], + doesThrow: false, + returnType: Type._UIImage.asOptional(), + body: "return \(Type._UIImage.name)(resource: R.image.\(SwiftIdentifier(name: name)), compatibleWithTraitCollection: traitCollection)" + ) + } } diff --git a/R.swift/Generators/NibGenerator.swift b/R.swift/Generators/NibGenerator.swift index 8fe4f811..4e6728d1 100644 --- a/R.swift/Generators/NibGenerator.swift +++ b/R.swift/Generators/NibGenerator.swift @@ -83,24 +83,24 @@ struct NibGenerator: Generator { return Function( comments: ["`UINib(name: \"\(nib.name)\", bundle: ...)`"], isStatic: true, - name: nib.name, + name: SwiftIdentifier(name: nib.name), generics: nil, parameters: [ Function.Parameter(name: "_", type: Type._Void) ], doesThrow: false, returnType: Type._UINib, - body: "return UINib(resource: R.nib.\(sanitizedSwiftName(nib.name)))" + body: "return UINib(resource: R.nib.\(SwiftIdentifier(name: nib.name)))" ) } private static func nibVarForNib(nib: Nib) -> Let { - let nibStructName = sanitizedSwiftName("_\(nib.name)") - let structType = Type(module: .Host, name: "_R.nib.\(nibStructName)") + let nibStructName = SwiftIdentifier(name: "_\(nib.name)") + let structType = Type(module: .Host, name: SwiftIdentifier(rawValue: "_R.nib.\(nibStructName)")) return Let( comments: ["Nib `\(nib.name)`."], isStatic: true, - name: nib.name, + name: SwiftIdentifier(name: nib.name), typeDefinition: .Inferred(structType), value: "\(structType)()" ) @@ -110,7 +110,7 @@ struct NibGenerator: Generator { let instantiateParameters = [ Function.Parameter(name: "owner", localName: "ownerOrNil", type: Type._AnyObject.asOptional()), - Function.Parameter(name: "options", localName: "optionsOrNil", type: Type(module: .StdLib, name: "[NSObject : AnyObject]", optional: true), defaultValue: "nil") + Function.Parameter(name: "options", localName: "optionsOrNil", type: Type(module: .StdLib, name: SwiftIdentifier(rawValue: "[NSObject : AnyObject]"), optional: true), defaultValue: "nil") ] let bundleLet = Let( @@ -134,7 +134,7 @@ struct NibGenerator: Generator { let viewTypeString = viewInfo.view.description return Function( isStatic: false, - name: "\(viewInfo.ordinal.word)View", + name: SwiftIdentifier(name: "\(viewInfo.ordinal.word)View"), generics: nil, parameters: instantiateParameters, doesThrow: false, @@ -161,9 +161,9 @@ struct NibGenerator: Generator { reuseProtocols = [] } - let sanitizedName = sanitizedSwiftName(nib.name, lowercaseFirstCharacter: false) + let sanitizedName = SwiftIdentifier(name: nib.name, lowercaseFirstCharacter: false) return Struct( - type: Type(module: .Host, name: "_\(sanitizedName)"), + type: Type(module: .Host, name: SwiftIdentifier(name: "_\(sanitizedName)")), implements: ([Type.NibResourceType] + reuseProtocols).map(TypePrinter.init), typealiasses: reuseTypealiasses, properties: [bundleLet, nameVar] + reuseIdentifierProperties, diff --git a/R.swift/Generators/ResourceFileGenerator.swift b/R.swift/Generators/ResourceFileGenerator.swift index cd9ae12c..7e21f9e2 100644 --- a/R.swift/Generators/ResourceFileGenerator.swift +++ b/R.swift/Generators/ResourceFileGenerator.swift @@ -34,7 +34,7 @@ struct ResourceFileGenerator: Generator { return Let( comments: ["Resource file `\($0.fullname)`."], isStatic: true, - name: $0.fullname, + name: SwiftIdentifier(name: $0.fullname), typeDefinition: .Inferred(Type.FileResource), value: "FileResource(bundle: _R.hostingBundle, name: \"\($0.filename)\", pathExtension: \(pathExtensionOrNilString))" ) @@ -50,14 +50,14 @@ struct ResourceFileGenerator: Generator { Function( comments: ["`bundle.URLForResource(\"\(filename)\", withExtension: \(pathExtension))`"], isStatic: true, - name: fullname, + name: SwiftIdentifier(name: fullname), generics: nil, parameters: [ Function.Parameter(name: "_", type: Type._Void) ], doesThrow: false, returnType: Type._NSURL.asOptional(), - body: "let fileResource = R.file.\(sanitizedSwiftName(fullname))\nreturn fileResource.bundle.URLForResource(fileResource)" + body: "let fileResource = R.file.\(SwiftIdentifier(name: fullname))\nreturn fileResource.bundle.URLForResource(fileResource)" ) ] } diff --git a/R.swift/Generators/ReuseIdentifierGenerator.swift b/R.swift/Generators/ReuseIdentifierGenerator.swift index 522b2056..1d8b9714 100644 --- a/R.swift/Generators/ReuseIdentifierGenerator.swift +++ b/R.swift/Generators/ReuseIdentifierGenerator.swift @@ -51,7 +51,7 @@ struct ReuseIdentifierGenerator: Generator { return Let( comments: ["Reuse identifier `\(reusable.identifier)`."], isStatic: true, - name: reusable.identifier, + name: SwiftIdentifier(name: reusable.identifier), typeDefinition: .Specified(Type.ReuseIdentifier.withGenericArgs([reusable.type])), value: "\(Type.ReuseIdentifier.name)(identifier: \"\(reusable.identifier)\")" ) diff --git a/R.swift/Generators/SegueGenerator.swift b/R.swift/Generators/SegueGenerator.swift index 1241557e..2b85fb8e 100644 --- a/R.swift/Generators/SegueGenerator.swift +++ b/R.swift/Generators/SegueGenerator.swift @@ -116,7 +116,7 @@ struct SegueGenerator: Generator { return Let( comments: ["Segue identifier `\(segueWithInfo.segue.identifier)`."], isStatic: true, - name: segueWithInfo.segue.identifier, + name: SwiftIdentifier(name: segueWithInfo.segue.identifier), typeDefinition: .Specified(type), value: "StoryboardSegueIdentifier(identifier: \"\(segueWithInfo.segue.identifier)\")" ) @@ -130,7 +130,7 @@ struct SegueGenerator: Generator { "For use inside `prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)`." ], isStatic: true, - name: segueWithInfo.segue.identifier, + name: SwiftIdentifier(name: segueWithInfo.segue.identifier), generics: nil, parameters: [ Function.Parameter.init(name: "segue", localName: "segue", type: Type._UIStoryboardSegue) @@ -139,11 +139,11 @@ struct SegueGenerator: Generator { returnType: Type.TypedStoryboardSegueInfo .asOptional() .withGenericArgs([segueWithInfo.segue.type, segueWithInfo.sourceType, segueWithInfo.destinationType]), - body: "return TypedStoryboardSegueInfo(segueIdentifier: R.segue.\(sanitizedSwiftName(sourceType.description)).\(sanitizedSwiftName(segueWithInfo.segue.identifier)), segue: segue)" + body: "return TypedStoryboardSegueInfo(segueIdentifier: R.segue.\(SwiftIdentifier(name: sourceType.description)).\(SwiftIdentifier(name: segueWithInfo.segue.identifier)), segue: segue)" ) } - let typeName = sanitizedSwiftName(sourceType.description) + let typeName = SwiftIdentifier(name: sourceType.description) return Struct( comments: ["This struct is generated for `\(sourceType.name)`, and contains static references to \(properties.count) segues."], diff --git a/R.swift/Generators/StoryboardGenerator.swift b/R.swift/Generators/StoryboardGenerator.swift index f07768b6..d930021c 100644 --- a/R.swift/Generators/StoryboardGenerator.swift +++ b/R.swift/Generators/StoryboardGenerator.swift @@ -120,7 +120,7 @@ struct StoryboardGenerator: Generator { vc, Let( isStatic: false, - name: sanitizedSwiftName(identifier), + name: SwiftIdentifier(name: identifier), typeDefinition: .Inferred(Type.StoryboardViewControllerResource), value: "\(Type.StoryboardViewControllerResource.name)<\(vc.type)>(identifier: \"\(identifier)\")" ) @@ -153,7 +153,7 @@ struct StoryboardGenerator: Generator { let validateViewControllersLines = storyboard.viewControllers .flatMap { vc in vc.storyboardIdentifier.map { - "if _R.storyboard.\(sanitizedSwiftName(storyboard.name))().\(sanitizedSwiftName($0))() == nil { throw ValidationError(description:\"[R.swift] ViewController with identifier '\(sanitizedSwiftName($0))' could not be loaded from storyboard '\(storyboard.name)' as '\(vc.type)'.\") }" + "if _R.storyboard.\(SwiftIdentifier(name: storyboard.name))().\(SwiftIdentifier(name: $0))() == nil { throw ValidationError(description:\"[R.swift] ViewController with identifier '\(SwiftIdentifier(name: $0))' could not be loaded from storyboard '\(storyboard.name)' as '\(vc.type)'.\") }" } } let validateLines = validateImagesLines + validateViewControllersLines @@ -174,7 +174,7 @@ struct StoryboardGenerator: Generator { // Return return Struct( - type: Type(module: .Host, name: sanitizedSwiftName(storyboard.name)), + type: Type(module: .Host, name: SwiftIdentifier(name: storyboard.name)), implements: implements, typealiasses: typealiasses, properties: properties, diff --git a/R.swift/Generators/StringsGenerator.swift b/R.swift/Generators/StringsGenerator.swift index b50c816e..33cea31c 100644 --- a/R.swift/Generators/StringsGenerator.swift +++ b/R.swift/Generators/StringsGenerator.swift @@ -42,7 +42,7 @@ struct StringsGenerator: Generator { private static func stringStructFromLocalizableStrings(filename: String, strings: [LocalizableStrings]) -> Struct? { - let name = sanitizedSwiftName(filename) + let name = SwiftIdentifier(name: filename) let params = computeParams(filename, strings: strings) return Struct( @@ -186,7 +186,7 @@ struct StringsGenerator: Generator { return Let( comments: values.comments, isStatic: true, - name: values.key, + name: SwiftIdentifier(name: values.key), typeDefinition: .Inferred(Type.StringResource), value: "StringResource(key: \"\(escapedKey)\", tableName: \"\(values.tableName)\", locales: [\(locales)])" ) @@ -206,7 +206,7 @@ struct StringsGenerator: Generator { return Function( comments: values.comments, isStatic: true, - name: values.key, + name: SwiftIdentifier(name: values.key), generics: nil, parameters: [ Function.Parameter(name: "_", type: Type._Void) @@ -240,7 +240,7 @@ struct StringsGenerator: Generator { return Function( comments: values.comments, isStatic: true, - name: values.key, + name: SwiftIdentifier(name: values.key), generics: nil, parameters: params, doesThrow: false, diff --git a/R.swift/ResourceTypes/Nib.swift b/R.swift/ResourceTypes/Nib.swift index 609c75d3..8087371a 100644 --- a/R.swift/ResourceTypes/Nib.swift +++ b/R.swift/ResourceTypes/Nib.swift @@ -85,7 +85,9 @@ private class NibParserDelegate: NSObject, NSXMLParserDelegate { let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] - let customType = customClass.map { Type(module: Module(name: customModule), name: $0, optional: false) } + let customType = customClass + .map { SwiftIdentifier(name: $0, lowercaseFirstCharacter: false) } + .map { Type(module: Module(name: customModule), name: $0, optional: false) } return customType ?? ElementNameToTypeMapping[elementName] ?? Type._UIView } @@ -98,7 +100,9 @@ private class NibParserDelegate: NSObject, NSXMLParserDelegate { let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] - let customType = customClass.map { Type(module: Module(name: customModule), name: $0, optional: false) } + let customType = customClass + .map { SwiftIdentifier(name: $0, lowercaseFirstCharacter: false) } + .map { Type(module: Module(name: customModule), name: $0, optional: false) } let type = customType ?? ElementNameToTypeMapping[elementName] ?? Type._UIView diff --git a/R.swift/ResourceTypes/Storyboard.swift b/R.swift/ResourceTypes/Storyboard.swift index 8ef06ad4..0b2e0adf 100644 --- a/R.swift/ResourceTypes/Storyboard.swift +++ b/R.swift/ResourceTypes/Storyboard.swift @@ -132,7 +132,9 @@ private class StoryboardParserDelegate: NSObject, NSXMLParserDelegate { let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] - let customType = customClass.map { Type(module: Module(name: customModule), name: $0, optional: false) } + let customType = customClass + .map { SwiftIdentifier(name: $0, lowercaseFirstCharacter: false) } + .map { Type(module: Module(name: customModule), name: $0, optional: false) } if let customType = customType where attributeDict["kind"] != "custom" { warn("Set the segue of class \(customType) with identifier '\(attributeDict["identifier"] ?? "-no identifier-")' to type custom, using segue subclasses with other types can cause crashes on iOS 8 and lower.") @@ -192,7 +194,9 @@ private class StoryboardParserDelegate: NSObject, NSXMLParserDelegate { let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] - let customType = customClass.map { Type(module: Module(name: customModule), name: $0, optional: false) } + let customType = customClass + .map { SwiftIdentifier(name: $0, lowercaseFirstCharacter: false) } + .map { Type(module: Module(name: customModule), name: $0, optional: false) } let type = customType ?? ElementNameToTypeMapping[elementName] ?? Type._UIViewController @@ -207,7 +211,9 @@ private class StoryboardParserDelegate: NSObject, NSXMLParserDelegate { let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] - let customType = customClass.map { Type(module: Module(name: customModule), name: $0, optional: false) } + let customType = customClass + .map { SwiftIdentifier(name: $0, lowercaseFirstCharacter: false) } + .map { Type(module: Module(name: customModule), name: $0, optional: false) } let type = customType ?? ElementNameToTypeMapping[elementName] ?? Type._UIView diff --git a/R.swift/SwiftTypes/Function.swift b/R.swift/SwiftTypes/Function.swift index 5847aecb..bbb467ab 100644 --- a/R.swift/SwiftTypes/Function.swift +++ b/R.swift/SwiftTypes/Function.swift @@ -11,14 +11,14 @@ import Foundation struct Function: UsedTypesProvider { let comments: [String] let isStatic: Bool - let name: String + let name: SwiftIdentifier let generics: String? let parameters: [Parameter] let doesThrow: Bool let returnType: Type let body: String - init(isStatic: Bool, name: String, generics: String?, parameters: [Parameter], doesThrow: Bool, returnType: Type, body: String) { + init(isStatic: Bool, name: SwiftIdentifier, generics: String?, parameters: [Parameter], doesThrow: Bool, returnType: Type, body: String) { self.comments = [] self.isStatic = isStatic self.name = name @@ -29,7 +29,7 @@ struct Function: UsedTypesProvider { self.body = body } - init(comments: [String], isStatic: Bool, name: String, generics: String?, parameters: [Parameter], doesThrow: Bool, returnType: Type, body: String) { + init(comments: [String], isStatic: Bool, name: SwiftIdentifier, generics: String?, parameters: [Parameter], doesThrow: Bool, returnType: Type, body: String) { self.comments = comments self.isStatic = isStatic self.name = name @@ -47,10 +47,6 @@ struct Function: UsedTypesProvider { ].flatten() } - var callName: String { - return sanitizedSwiftName(name, lowercaseFirstCharacter: true) - } - var description: String { let commentsString = comments.map { "/// \($0)\n" }.joinWithSeparator("") let staticString = isStatic ? "static " : "" @@ -60,7 +56,7 @@ struct Function: UsedTypesProvider { let returnString = Type._Void == returnType ? "" : " -> \(returnType)" let bodyString = body.indentWithString(IndentationString) - return "\(commentsString)\(staticString)func \(callName)\(genericsString)(\(parameterString))\(throwString)\(returnString) {\n\(bodyString)\n}" + return "\(commentsString)\(staticString)func \(name)\(genericsString)(\(parameterString))\(throwString)\(returnString) {\n\(bodyString)\n}" } struct Parameter: UsedTypesProvider, CustomStringConvertible { @@ -73,12 +69,12 @@ struct Function: UsedTypesProvider { return type.usedTypes } - var swiftName: String { - return sanitizedSwiftName(name, lowercaseFirstCharacter: true) + var swiftIdentifier: SwiftIdentifier { + return SwiftIdentifier(name: name, lowercaseFirstCharacter: true) } var description: String { - let definition = localName.map({ "\(self.swiftName) \($0): \(type)" }) ?? "\(swiftName): \(type)" + let definition = localName.map({ "\(swiftIdentifier) \($0): \(type)" }) ?? "\(swiftIdentifier): \(type)" return defaultValue.map({ "\(definition) = \($0)" }) ?? definition } diff --git a/R.swift/SwiftTypes/Let.swift b/R.swift/SwiftTypes/Let.swift index e01ae02f..52577e9d 100644 --- a/R.swift/SwiftTypes/Let.swift +++ b/R.swift/SwiftTypes/Let.swift @@ -27,11 +27,11 @@ enum TypeDefinition: UsedTypesProvider { struct Let: Property { let comments: [String] let isStatic: Bool - let name: String + let name: SwiftIdentifier let typeDefinition: TypeDefinition let value: String - init(isStatic: Bool, name: String, typeDefinition: TypeDefinition, value: String) { + init(isStatic: Bool, name: SwiftIdentifier, typeDefinition: TypeDefinition, value: String) { self.comments = [] self.isStatic = isStatic self.name = name @@ -39,7 +39,7 @@ struct Let: Property { self.value = value } - init(comments: [String], isStatic: Bool, name: String, typeDefinition: TypeDefinition, value: String) { + init(comments: [String], isStatic: Bool, name: SwiftIdentifier, typeDefinition: TypeDefinition, value: String) { self.comments = comments self.isStatic = isStatic self.name = name @@ -61,6 +61,6 @@ struct Let: Property { case .Inferred: typeString = "" } - return "\(commentsString)\(staticString)let \(callName)\(typeString) = \(value)" + return "\(commentsString)\(staticString)let \(name)\(typeString) = \(value)" } } diff --git a/R.swift/SwiftTypes/Property.swift b/R.swift/SwiftTypes/Property.swift index 5ed8a58f..d7f86f16 100644 --- a/R.swift/SwiftTypes/Property.swift +++ b/R.swift/SwiftTypes/Property.swift @@ -9,13 +9,7 @@ import Foundation protocol Property: UsedTypesProvider, CustomStringConvertible { - var name: String { get } -} - -extension Property { - var callName: String { - return sanitizedSwiftName(name, lowercaseFirstCharacter: true) - } + var name: SwiftIdentifier { get } } /// Type-erasure function diff --git a/R.swift/SwiftTypes/Struct.swift b/R.swift/SwiftTypes/Struct.swift index e9973352..9c6a812f 100644 --- a/R.swift/SwiftTypes/Struct.swift +++ b/R.swift/SwiftTypes/Struct.swift @@ -68,12 +68,14 @@ struct Struct: UsedTypesProvider, CustomStringConvertible { .joinWithSeparator("\n") let varsString = properties - .sort { $0.callName < $1.callName } +// .sort { $0.name.description < $1.name.description } .map { $0.description } + .sort() .joinWithSeparator("\n") let functionsString = functions - .sort { $0.callName < $1.callName } +// .sort { $0.name.description < $1.name.description } .map { $0.description } + .sort() .joinWithSeparator("\n\n") let structsString = structs .sort { $0.type.description < $1.type.description } diff --git a/R.swift/SwiftTypes/Type.swift b/R.swift/SwiftTypes/Type.swift index 53f89d2a..ca188e4f 100644 --- a/R.swift/SwiftTypes/Type.swift +++ b/R.swift/SwiftTypes/Type.swift @@ -61,7 +61,7 @@ struct Type: UsedTypesProvider, CustomStringConvertible, Hashable { static let TypedStoryboardSegueInfo = Type(module: "Rswift", name: "TypedStoryboardSegueInfo", genericArgs: [TypeVar(description: "Segue", usedTypes: []), TypeVar(description: "Source", usedTypes: []), TypeVar(description: "Destination", usedTypes: [])]) let module: Module - let name: String + let name: SwiftIdentifier let genericArgs: [TypeVar] let optional: Bool @@ -77,14 +77,14 @@ struct Type: UsedTypesProvider, CustomStringConvertible, Hashable { return description.hashValue } - init(module: Module, name: String, genericArgs: [TypeVar] = [], optional: Bool = false) { + init(module: Module, name: SwiftIdentifier, genericArgs: [TypeVar] = [], optional: Bool = false) { self.module = module self.name = name self.genericArgs = genericArgs self.optional = optional } - init(module: Module, name: String, genericArgs: [Type], optional: Bool = false) { + init(module: Module, name: SwiftIdentifier, genericArgs: [Type], optional: Bool = false) { self.module = module self.name = name self.genericArgs = genericArgs.map(TypeVar.init) diff --git a/R.swift/SwiftTypes/Var.swift b/R.swift/SwiftTypes/Var.swift index 60b48c82..30e344e0 100644 --- a/R.swift/SwiftTypes/Var.swift +++ b/R.swift/SwiftTypes/Var.swift @@ -10,7 +10,7 @@ import Foundation struct Var: Property { let isStatic: Bool - let name: String + let name: SwiftIdentifier let type: Type let getter: String @@ -20,6 +20,6 @@ struct Var: Property { var description: String { let staticString = isStatic ? "static " : "" - return "\(staticString)var \(callName): \(type) { \(getter) }" + return "\(staticString)var \(name): \(type) { \(getter) }" } } diff --git a/R.swift/Util/SwiftIdentifier.swift b/R.swift/Util/SwiftIdentifier.swift index 66a00451..42b7de7a 100644 --- a/R.swift/Util/SwiftIdentifier.swift +++ b/R.swift/Util/SwiftIdentifier.swift @@ -14,7 +14,7 @@ private let numberRegex = try! NSRegularExpression(pattern: "^[0-9]+", options: Disallowed characters: whitespace, mathematical symbols, arrows, private-use and invalid Unicode points, line- and boxdrawing characters Special rules: Can't begin with a number */ -struct SwiftIdentifier : CustomStringConvertible, Hashable { +struct SwiftIdentifier : CustomStringConvertible { let description: String init(name: String, lowercaseFirstCharacter: Bool = true) { @@ -36,6 +36,12 @@ struct SwiftIdentifier : CustomStringConvertible, Hashable { } } + init(rawValue: String) { + description = rawValue + } +} + +extension SwiftIdentifier : Hashable { var hashValue: Int { return description.hashValue } @@ -45,22 +51,27 @@ func ==(lhs: SwiftIdentifier, rhs: SwiftIdentifier) -> Bool { return lhs.description == rhs.description } -func sanitizedSwiftName(name: String, lowercaseFirstCharacter: Bool = true) -> String { - var nameComponents = name.componentsSeparatedByCharactersInSet(BlacklistedCharacters) +extension SwiftIdentifier : StringLiteralConvertible { + typealias StringLiteralType = String + typealias UnicodeScalarLiteralType = String + typealias ExtendedGraphemeClusterLiteralType = String - let firstComponent = nameComponents.removeAtIndex(0) - let cleanedSwiftName = nameComponents.reduce(firstComponent) { $0 + $1.uppercaseFirstCharacter } + init(stringLiteral value: StringLiteralType) { + description = value - let regex = try! NSRegularExpression(pattern: "^[0-9]+", options: .CaseInsensitive) - let fullRange = NSRange(location: 0, length: cleanedSwiftName.characters.count) - let sanitizedSwiftName = regex.stringByReplacingMatchesInString(cleanedSwiftName, options: NSMatchingOptions(rawValue: 0), range: fullRange, withTemplate: "") + if self != SwiftIdentifier(name: value, lowercaseFirstCharacter: false) { + assertionFailure("'\(value)' not a correct SwiftIdentifier") + } + } + + init(unicodeScalarLiteral value: StringLiteralType) { + description = value + } - let capitalizedSwiftName = lowercaseFirstCharacter ? sanitizedSwiftName.lowercaseFirstCharacter : sanitizedSwiftName - if SwiftKeywords.contains(capitalizedSwiftName) { - return "`\(capitalizedSwiftName)`" + init(extendedGraphemeClusterLiteral value: StringLiteralType) { + description = value } - return capitalizedSwiftName // .isEmpty ? nil : capitalizedSwiftName } struct SwiftNameGroups { diff --git a/R.swiftTests/MainTests.swift b/R.swiftTests/MainTests.swift index 33a19e2e..4df3075f 100644 --- a/R.swiftTests/MainTests.swift +++ b/R.swiftTests/MainTests.swift @@ -41,7 +41,7 @@ class MainTests: XCTestCase { // Use XCTAssert and related functions to verify your tests produce the correct results. swiftNameData.forEach { - let sanitizedResult = sanitizedSwiftName($0.0, lowercaseFirstCharacter: true) + let sanitizedResult = SwiftIdentifier(name: $0.0, lowercaseFirstCharacter: true) XCTAssertEqual(sanitizedResult, $0.1) } } @@ -50,7 +50,7 @@ class MainTests: XCTestCase { // This is an example of a performance test case. self.measureBlock { (0...1000).forEach { _ in - sanitizedSwiftName("(looks) easy, but it's not reallY that easy!", lowercaseFirstCharacter: true) + SwiftIdentifier(name: "(looks) easy, but it's not reallY that easy!", lowercaseFirstCharacter: true) } } } From 719d738d14a274310cfb81e0f40156fa4cd6c94d Mon Sep 17 00:00:00 2001 From: Tom Lokhorst Date: Sat, 30 Jul 2016 20:11:17 +0200 Subject: [PATCH 3/5] Move duplicate warnings to separate function --- R.swift/Generators/ColorGenerator.swift | 12 +--------- R.swift/Generators/ImageGenerator.swift | 12 +--------- R.swift/Generators/NibGenerator.swift | 12 +--------- .../Generators/ResourceFileGenerator.swift | 12 +--------- .../Generators/ReuseIdentifierGenerator.swift | 12 +--------- R.swift/Generators/SegueGenerator.swift | 12 +--------- R.swift/Generators/StoryboardGenerator.swift | 12 +--------- R.swift/Generators/StringsGenerator.swift | 24 ++----------------- R.swift/Util/SwiftIdentifier.swift | 20 ++++++++++++++++ .../ResourceAppTests/ResourceAppTests.swift | 6 ++--- 10 files changed, 32 insertions(+), 102 deletions(-) diff --git a/R.swift/Generators/ColorGenerator.swift b/R.swift/Generators/ColorGenerator.swift index 26d42aa1..9d85921e 100644 --- a/R.swift/Generators/ColorGenerator.swift +++ b/R.swift/Generators/ColorGenerator.swift @@ -31,17 +31,7 @@ struct ColorGenerator: Generator { let name = SwiftIdentifier(name: palette.filename) let groupedColors = palette.colors.groupBySwiftIdentifiers { $0.0 } - for (sanitizedName, duplicates) in groupedColors.duplicates { - warn("Skipping \(duplicates.count) colors in palette '\(palette.filename)' because symbol '\(sanitizedName)' would be generated for all of these colors: \(duplicates.joinWithSeparator(", "))") - } - - let empties = groupedColors.empties - if let empty = empties.first where empties.count == 1 { - warn("Skipping 1 color in palette '\(palette.filename)' because no swift identifier can be generated for image: \(empty)") - } - else if empties.count > 1 { - warn("Skipping \(empties.count) images in palette '\(palette.filename)' because no swift identifier can be generated for all of these images: \(empties.joinWithSeparator(", "))") - } + groupedColors.printWarningsForDuplicatesAndEmpties(source: "color", container: "in palette '\(palette.filename)'", result: "color") return Struct( comments: ["This `R.color.\(name)` struct is generated, and contains static references to \(groupedColors.uniques.count) colors."], diff --git a/R.swift/Generators/ImageGenerator.swift b/R.swift/Generators/ImageGenerator.swift index 45bbaeba..a0f1c9d9 100644 --- a/R.swift/Generators/ImageGenerator.swift +++ b/R.swift/Generators/ImageGenerator.swift @@ -24,17 +24,7 @@ struct ImageGenerator: Generator { let allFunctions = assetFolderImageNames + imagesNames let groupedFunctions = allFunctions.groupBySwiftIdentifiers { $0 } - for (sanitizedName, duplicates) in groupedFunctions.duplicates { - warn("Skipping \(duplicates.count) images because symbol '\(sanitizedName)' would be generated for all of these images: \(duplicates.joinWithSeparator(", "))") - } - - let empties = groupedFunctions.empties - if let empty = empties.first where empties.count == 1 { - warn("Skipping 1 image because no swift identifier can be generated for image: \(empty)") - } - else if empties.count > 1 { - warn("Skipping \(empties.count) images because no swift identifier can be generated for all of these images: \(empties.joinWithSeparator(", "))") - } + groupedFunctions.printWarningsForDuplicatesAndEmpties(source: "image", result: "image") let imageLets = groupedFunctions .uniques diff --git a/R.swift/Generators/NibGenerator.swift b/R.swift/Generators/NibGenerator.swift index 4e6728d1..842b08c7 100644 --- a/R.swift/Generators/NibGenerator.swift +++ b/R.swift/Generators/NibGenerator.swift @@ -38,17 +38,7 @@ struct NibGenerator: Generator { init(nibs: [Nib]) { let groupedNibs = nibs.groupBySwiftIdentifiers { $0.name } - for (name, duplicates) in groupedNibs.duplicates { - warn("Skipping \(duplicates.count) xibs because symbol '\(name)' would be generated for all of these xibs: \(duplicates.joinWithSeparator(", "))") - } - - let empties = groupedNibs.empties - if let empty = empties.first where empties.count == 1 { - warn("Skipping 1 xib because no swift identifier can be generated for xib: \(empty)") - } - else if empties.count > 1 { - warn("Skipping \(empties.count) xibs because no swift identifier can be generated for all of these xibs: \(empties.joinWithSeparator(", "))") - } + groupedNibs.printWarningsForDuplicatesAndEmpties(source: "xib", result: "xib") internalStruct = Struct( type: Type(module: .Host, name: "nib"), diff --git a/R.swift/Generators/ResourceFileGenerator.swift b/R.swift/Generators/ResourceFileGenerator.swift index 7e21f9e2..9aca4146 100644 --- a/R.swift/Generators/ResourceFileGenerator.swift +++ b/R.swift/Generators/ResourceFileGenerator.swift @@ -15,17 +15,7 @@ struct ResourceFileGenerator: Generator { init(resourceFiles: [ResourceFile]) { let groupedResourceFiles = resourceFiles.groupBySwiftIdentifiers { $0.fullname } - for (name, duplicates) in groupedResourceFiles.duplicates { - warn("Skipping \(duplicates.count) resource files because symbol '\(name)' would be generated for all of these files: \(duplicates.joinWithSeparator(", "))") - } - - let empties = groupedResourceFiles.empties - if let empty = empties.first where empties.count == 1 { - warn("Skipping 1 resource file because no swift identifier can be generated for file: \(empty)") - } - else if empties.count > 1 { - warn("Skipping \(empties.count) resource files because no swift identifier can be generated for all of these files: \(empties.joinWithSeparator(", "))") - } + groupedResourceFiles.printWarningsForDuplicatesAndEmpties(source: "resource file", result: "file") let resourceFileProperties: [Property] = groupedResourceFiles .uniques diff --git a/R.swift/Generators/ReuseIdentifierGenerator.swift b/R.swift/Generators/ReuseIdentifierGenerator.swift index 1d8b9714..c09d33ab 100644 --- a/R.swift/Generators/ReuseIdentifierGenerator.swift +++ b/R.swift/Generators/ReuseIdentifierGenerator.swift @@ -20,17 +20,7 @@ struct ReuseIdentifierGenerator: Generator { let groupedReusables = deduplicatedReusables.groupBySwiftIdentifiers { $0.identifier } - for (name, duplicates) in groupedReusables.duplicates { - warn("Skipping \(duplicates.count) reuseIdentifiers because symbol '\(name)' would be generated for all of these reuseIdentifiers: \(duplicates.joinWithSeparator(", "))") - } - - let empties = groupedReusables.empties - if let empty = empties.first where empties.count == 1 { - warn("Skipping 1 reuseIdentifier because no swift identifier can be generated for reuseIdentifier: \(empty)") - } - else if empties.count > 1 { - warn("Skipping \(empties.count) reuseIdentifiers because no swift identifier can be generated for all of these reuseIdentifiers: \(empties.joinWithSeparator(", "))") - } + groupedReusables.printWarningsForDuplicatesAndEmpties(source: "reuseIdentifier", result: "reuseIdentifier") let reuseIdentifierProperties = groupedReusables .uniques diff --git a/R.swift/Generators/SegueGenerator.swift b/R.swift/Generators/SegueGenerator.swift index 2b85fb8e..44107f5b 100644 --- a/R.swift/Generators/SegueGenerator.swift +++ b/R.swift/Generators/SegueGenerator.swift @@ -46,17 +46,7 @@ struct SegueGenerator: Generator { for (sourceType, seguesBySourceType) in deduplicatedSeguesWithInfo.groupBy({ $0.sourceType }) { let groupedSeguesWithInfo = seguesBySourceType.groupBySwiftIdentifiers { $0.segue.identifier } - for (name, duplicates) in groupedSeguesWithInfo.duplicates { - warn("Skipping \(duplicates.count) segues for '\(sourceType)' because symbol '\(name)' would be generated for all of these segues, but with a different destination or segue type: \(duplicates.joinWithSeparator(", "))") - } - - let empties = groupedSeguesWithInfo.empties - if let empty = empties.first where empties.count == 1 { - warn("Skipping 1 segue for '\(sourceType)' because no swift identifier can be generated for segue: \(empty)") - } - else if empties.count > 1 { - warn("Skipping \(empties.count) segues for '\(sourceType)' because no swift identifier can be generated for all of these segues: \(empties.joinWithSeparator(", "))") - } + groupedSeguesWithInfo.printWarningsForDuplicatesAndEmpties(source: "segue", container: "for '\(sourceType)'", result: "segue") let sts = groupedSeguesWithInfo .uniques diff --git a/R.swift/Generators/StoryboardGenerator.swift b/R.swift/Generators/StoryboardGenerator.swift index d930021c..0e069211 100644 --- a/R.swift/Generators/StoryboardGenerator.swift +++ b/R.swift/Generators/StoryboardGenerator.swift @@ -15,17 +15,7 @@ struct StoryboardGenerator: Generator { init(storyboards: [Storyboard]) { let groupedStoryboards = storyboards.groupBySwiftIdentifiers { $0.name } - for (name, duplicates) in groupedStoryboards.duplicates { - warn("Skipping \(duplicates.count) storyboards because symbol '\(name)' would be generated for all of these storyboards: \(duplicates.joinWithSeparator(", "))") - } - - let empties = groupedStoryboards.empties - if let empty = empties.first where empties.count == 1 { - warn("Skipping 1 storyboard because no swift identifier can be generated for storyboard: \(empty)") - } - else if empties.count > 1 { - warn("Skipping \(empties.count) storyboards because no swift identifier can be generated for all of these storyboards: \(empties.joinWithSeparator(", "))") - } + groupedStoryboards.printWarningsForDuplicatesAndEmpties(source: "storyboard", result: "storyboard") let storyboardStructs = groupedStoryboards .uniques diff --git a/R.swift/Generators/StringsGenerator.swift b/R.swift/Generators/StringsGenerator.swift index 33cea31c..bc4611e3 100644 --- a/R.swift/Generators/StringsGenerator.swift +++ b/R.swift/Generators/StringsGenerator.swift @@ -17,17 +17,7 @@ struct StringsGenerator: Generator { let localized = localizableStrings.groupBy { $0.filename } let groupedLocalized = localized.groupBySwiftIdentifiers { $0.0 } - for (sanitizedName, duplicates) in groupedLocalized.duplicates { - warn("Skipping \(duplicates.count) strings files because symbol '\(sanitizedName)' would be generated for all of these filenames: \(duplicates.joinWithSeparator(", "))") - } - - let empties = groupedLocalized.empties - if let empty = empties.first where empties.count == 1 { - warn("Skipping 1 strings file because no swift identifier can be generated for filename: \(empty)") - } - else if empties.count > 1 { - warn("Skipping \(empties.count) strings files because no swift identifier can be generated for all of these filenames: \(empties.joinWithSeparator(", "))") - } + groupedLocalized.printWarningsForDuplicatesAndEmpties(source: "strings file", result: "file") externalStruct = Struct( comments: ["This `R.string` struct is generated, and contains static references to \(groupedLocalized.uniques.count) localization tables."], @@ -75,17 +65,7 @@ struct StringsGenerator: Generator { let filenameLocale = ls.locale.withFilename(filename) let groupedKeys = ls.dictionary.keys.groupBySwiftIdentifiers { $0 } - for (sanitizedName, duplicates) in groupedKeys.duplicates { - warn("Skipping \(duplicates.count) strings in \(filenameLocale) because symbol '\(sanitizedName)' would be generated for all of these keys: \(duplicates.map { "'\($0)'" }.joinWithSeparator(", "))") - } - - let empties = groupedKeys.empties - if let empty = empties.first where empties.count == 1 { - warn("Skipping 1 string in \(filenameLocale) because no swift identifier can be generated for key: \(empty)") - } - else if empties.count > 1 { - warn("Skipping \(empties.count) strings in \(filenameLocale) because no swift identifier can be generated for all of these keys: \(empties.joinWithSeparator(", "))") - } + groupedKeys.printWarningsForDuplicatesAndEmpties(source: "string", container: "in \(filenameLocale)", result: "key") // Save uniques for key in groupedKeys.uniques { diff --git a/R.swift/Util/SwiftIdentifier.swift b/R.swift/Util/SwiftIdentifier.swift index 42b7de7a..b34d37ae 100644 --- a/R.swift/Util/SwiftIdentifier.swift +++ b/R.swift/Util/SwiftIdentifier.swift @@ -78,6 +78,26 @@ struct SwiftNameGroups { let uniques: [T] let duplicates: [(SwiftIdentifier, [String])] // Identifiers that result in duplicate Swift names let empties: [String] // Identifiers (wrapped in quotes) that result in empty swift names + + func printWarningsForDuplicatesAndEmpties(source source: String, container: String? = nil, result: String) { + + let sourceSingular = [source, container].flatMap { $0 }.joinWithSeparator(" ") + let sourcePlural = ["\(source)s", container].flatMap { $0 }.joinWithSeparator(" ") + + let resultSingular = result + let resultPlural = "\(result)s" + + for (sanitizedName, dups) in duplicates { + warn("Skipping \(dups.count) \(sourcePlural) because symbol '\(sanitizedName)' would be generated for all of these \(resultPlural): \(dups.joinWithSeparator(", "))") + } + + if let empty = empties.first where empties.count == 1 { + warn("Skipping 1 \(sourceSingular) because no swift identifier can be generated for \(resultSingular): \(empty)") + } + else if empties.count > 1 { + warn("Skipping \(empties.count) \(sourcePlural) because no swift identifier can be generated for all of these \(resultPlural): \(empties.joinWithSeparator(", "))") + } + } } extension SequenceType { diff --git a/ResourceApp/ResourceAppTests/ResourceAppTests.swift b/ResourceApp/ResourceAppTests/ResourceAppTests.swift index 1fb2a64f..a8fe883f 100644 --- a/ResourceApp/ResourceAppTests/ResourceAppTests.swift +++ b/ResourceApp/ResourceAppTests/ResourceAppTests.swift @@ -17,7 +17,7 @@ class ResourceAppTests: XCTestCase { "warning: [R.swift] Skipping 2 xibs because symbol 'duplicate' would be generated for all of these xibs: Duplicate, duplicate", "warning: [R.swift] Skipping 2 storyboards because symbol 'duplicate' would be generated for all of these storyboards: Duplicate, duplicate", "warning: [R.swift] Skipping 2 reuseIdentifiers because symbol 'duplicateCellView' would be generated for all of these reuseIdentifiers: DuplicateCellView, duplicateCellView", - "warning: [R.swift] Skipping 2 segues for 'SecondViewController' because symbol 'toFirst' would be generated for all of these segues, but with a different destination or segue type: ToFirst, toFirst", + "warning: [R.swift] Skipping 2 segues for 'SecondViewController' because symbol 'toFirst' would be generated for all of these segues: ToFirst, toFirst", "warning: [R.swift] Skipping 2 images because symbol 'theAppIcon' would be generated for all of these images: The App Icon, TheAppIcon", "warning: [R.swift] Skipping 2 images because symbol 'second' would be generated for all of these images: Second, second", "warning: [R.swift] Skipping 2 resource files because symbol 'duplicateJson' would be generated for all of these files: Duplicate.json, duplicateJson", @@ -25,8 +25,8 @@ class ResourceAppTests: XCTestCase { "warning: [R.swift] Skipping 1 reuseIdentifier because no swift identifier can be generated for reuseIdentifier: ' '", "warning: [R.swift] Skipping 2 colors in palette 'My R.swift colors' because symbol 'black' would be generated for all of these colors: Black, Black?", - "warning: [R.swift] Skipping 2 strings files because symbol 'duplicate' would be generated for all of these filenames: Duplicate, Duplicate#", - "warning: [R.swift] Skipping 1 strings file because no swift identifier can be generated for filename: '@@'", + "warning: [R.swift] Skipping 2 strings files because symbol 'duplicate' would be generated for all of these files: Duplicate, Duplicate#", + "warning: [R.swift] Skipping 1 strings file because no swift identifier can be generated for file: '@@'", "warning: [R.swift] Skipping 1 string in 'Generic' because no swift identifier can be generated for key: '#'", "warning: [R.swift] Strings file 'Localizable' (en) is missing translations for keys: 'japanese only'", "warning: [R.swift] Strings file 'Localizable' (es) is missing translations for keys: 'japanese only'", From b340ad4f82a70ed858e98c7569fdb0ef8360d065 Mon Sep 17 00:00:00 2001 From: Tom Lokhorst Date: Sat, 30 Jul 2016 20:23:52 +0200 Subject: [PATCH 4/5] Show warning for files --- R.swift/Generators/ColorGenerator.swift | 5 ++++- R.swift/Generators/FontGenerator.swift | 6 ++++-- R.swift/Generators/NibGenerator.swift | 3 +-- R.swift/Generators/ResourceFileGenerator.swift | 1 - R.swift/Generators/ReuseIdentifierGenerator.swift | 1 - R.swift/Generators/StoryboardGenerator.swift | 3 +-- ResourceApp/ResourceAppTests/ResourceAppTests.swift | 4 ++-- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/R.swift/Generators/ColorGenerator.swift b/R.swift/Generators/ColorGenerator.swift index 9d85921e..ac030857 100644 --- a/R.swift/Generators/ColorGenerator.swift +++ b/R.swift/Generators/ColorGenerator.swift @@ -14,6 +14,9 @@ struct ColorGenerator: Generator { let internalStruct: Struct? = nil init(colorPalettes palettes: [ColorPalette]) { + let groupedPalettes = palettes.groupBySwiftIdentifiers { $0.filename } + groupedPalettes.printWarningsForDuplicatesAndEmpties(source: "color palette", result: "file") + externalStruct = Struct( comments: ["This `R.color` struct is generated, and contains static references to \(palettes.count) color palettes."], type: Type(module: .Host, name: "color"), @@ -21,7 +24,7 @@ struct ColorGenerator: Generator { typealiasses: [], properties: [], functions: [], - structs: palettes.flatMap(ColorGenerator.colorStructFromPalette) + structs: groupedPalettes.uniques.flatMap(ColorGenerator.colorStructFromPalette) ) } diff --git a/R.swift/Generators/FontGenerator.swift b/R.swift/Generators/FontGenerator.swift index a1f0f49e..a28f1b9b 100644 --- a/R.swift/Generators/FontGenerator.swift +++ b/R.swift/Generators/FontGenerator.swift @@ -13,8 +13,10 @@ struct FontGenerator: Generator { let internalStruct: Struct? = nil init(fonts: [Font]) { + let groupedFonts = fonts.groupBySwiftIdentifiers { $0.name } + groupedFonts.printWarningsForDuplicatesAndEmpties(source: "font resource", result: "file") - let fontProperties: [Property] = fonts.map { + let fontProperties: [Property] = groupedFonts.uniques.map { Let( comments: ["Font `\($0.name)`."], isStatic: true, @@ -30,7 +32,7 @@ struct FontGenerator: Generator { implements: [], typealiasses: [], properties: fontProperties, - functions: fonts.map(FontGenerator.fontFunctionFromFont), + functions: groupedFonts.uniques.map(FontGenerator.fontFunctionFromFont), structs: [] ) } diff --git a/R.swift/Generators/NibGenerator.swift b/R.swift/Generators/NibGenerator.swift index 842b08c7..aeca8456 100644 --- a/R.swift/Generators/NibGenerator.swift +++ b/R.swift/Generators/NibGenerator.swift @@ -37,8 +37,7 @@ struct NibGenerator: Generator { init(nibs: [Nib]) { let groupedNibs = nibs.groupBySwiftIdentifiers { $0.name } - - groupedNibs.printWarningsForDuplicatesAndEmpties(source: "xib", result: "xib") + groupedNibs.printWarningsForDuplicatesAndEmpties(source: "xib", result: "file") internalStruct = Struct( type: Type(module: .Host, name: "nib"), diff --git a/R.swift/Generators/ResourceFileGenerator.swift b/R.swift/Generators/ResourceFileGenerator.swift index 9aca4146..109e6fdd 100644 --- a/R.swift/Generators/ResourceFileGenerator.swift +++ b/R.swift/Generators/ResourceFileGenerator.swift @@ -14,7 +14,6 @@ struct ResourceFileGenerator: Generator { init(resourceFiles: [ResourceFile]) { let groupedResourceFiles = resourceFiles.groupBySwiftIdentifiers { $0.fullname } - groupedResourceFiles.printWarningsForDuplicatesAndEmpties(source: "resource file", result: "file") let resourceFileProperties: [Property] = groupedResourceFiles diff --git a/R.swift/Generators/ReuseIdentifierGenerator.swift b/R.swift/Generators/ReuseIdentifierGenerator.swift index c09d33ab..f9af9198 100644 --- a/R.swift/Generators/ReuseIdentifierGenerator.swift +++ b/R.swift/Generators/ReuseIdentifierGenerator.swift @@ -19,7 +19,6 @@ struct ReuseIdentifierGenerator: Generator { .flatMap { $0.first } let groupedReusables = deduplicatedReusables.groupBySwiftIdentifiers { $0.identifier } - groupedReusables.printWarningsForDuplicatesAndEmpties(source: "reuseIdentifier", result: "reuseIdentifier") let reuseIdentifierProperties = groupedReusables diff --git a/R.swift/Generators/StoryboardGenerator.swift b/R.swift/Generators/StoryboardGenerator.swift index 0e069211..1efb4675 100644 --- a/R.swift/Generators/StoryboardGenerator.swift +++ b/R.swift/Generators/StoryboardGenerator.swift @@ -14,8 +14,7 @@ struct StoryboardGenerator: Generator { init(storyboards: [Storyboard]) { let groupedStoryboards = storyboards.groupBySwiftIdentifiers { $0.name } - - groupedStoryboards.printWarningsForDuplicatesAndEmpties(source: "storyboard", result: "storyboard") + groupedStoryboards.printWarningsForDuplicatesAndEmpties(source: "storyboard", result: "file") let storyboardStructs = groupedStoryboards .uniques diff --git a/ResourceApp/ResourceAppTests/ResourceAppTests.swift b/ResourceApp/ResourceAppTests/ResourceAppTests.swift index a8fe883f..194a4876 100644 --- a/ResourceApp/ResourceAppTests/ResourceAppTests.swift +++ b/ResourceApp/ResourceAppTests/ResourceAppTests.swift @@ -14,8 +14,8 @@ class ResourceAppTests: XCTestCase { let expectedWarnings = [ "warning: [R.swift] Skipping 2 images because symbol 'second' would be generated for all of these images: Second, second", - "warning: [R.swift] Skipping 2 xibs because symbol 'duplicate' would be generated for all of these xibs: Duplicate, duplicate", - "warning: [R.swift] Skipping 2 storyboards because symbol 'duplicate' would be generated for all of these storyboards: Duplicate, duplicate", + "warning: [R.swift] Skipping 2 xibs because symbol 'duplicate' would be generated for all of these files: Duplicate, duplicate", + "warning: [R.swift] Skipping 2 storyboards because symbol 'duplicate' would be generated for all of these files: Duplicate, duplicate", "warning: [R.swift] Skipping 2 reuseIdentifiers because symbol 'duplicateCellView' would be generated for all of these reuseIdentifiers: DuplicateCellView, duplicateCellView", "warning: [R.swift] Skipping 2 segues for 'SecondViewController' because symbol 'toFirst' would be generated for all of these segues: ToFirst, toFirst", "warning: [R.swift] Skipping 2 images because symbol 'theAppIcon' would be generated for all of these images: The App Icon, TheAppIcon", From a3ec094a4aae0ba94d326dc47c60c3fa6a803ee4 Mon Sep 17 00:00:00 2001 From: Tom Lokhorst Date: Sat, 30 Jul 2016 21:02:52 +0200 Subject: [PATCH 5/5] Fix broken test --- R.swiftTests/MainTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R.swiftTests/MainTests.swift b/R.swiftTests/MainTests.swift index 4df3075f..c0ab5784 100644 --- a/R.swiftTests/MainTests.swift +++ b/R.swiftTests/MainTests.swift @@ -41,7 +41,7 @@ class MainTests: XCTestCase { // Use XCTAssert and related functions to verify your tests produce the correct results. swiftNameData.forEach { - let sanitizedResult = SwiftIdentifier(name: $0.0, lowercaseFirstCharacter: true) + let sanitizedResult = SwiftIdentifier(name: $0.0, lowercaseFirstCharacter: true).description XCTAssertEqual(sanitizedResult, $0.1) } }