diff --git a/CHANGELOG.md b/CHANGELOG.md index f8e9e1a..20363c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ _None_ * XCAssets: Added support for named colors. [David Jennes](https://github.com/djbe) [#68](https://github.com/SwiftGen/templates/pull/68) +* Fonts: the path to fonts will now default to just the font filename, but you can disable this behaviour by enabling the `preservePath` parameter. + [David Jennes](https://github.com/djbe) + [#71](https://github.com/SwiftGen/templates/pull/71) ### Internal Changes diff --git a/Contexts/Fonts/defaults.plist b/Contexts/Fonts/defaults.plist index 8b560a9..5d23288 100644 --- a/Contexts/Fonts/defaults.plist +++ b/Contexts/Fonts/defaults.plist @@ -11,7 +11,7 @@ name .SFNSDisplay-Black path - SFNSDisplay-Black.otf + Fonts/SFNSDisplay-Black.otf style Black @@ -19,7 +19,7 @@ name .SFNSDisplay-Bold path - SFNSDisplay-Bold.otf + Fonts/SFNSDisplay-Bold.otf style Bold @@ -27,7 +27,7 @@ name .SFNSDisplay-Heavy path - SFNSDisplay-Heavy.otf + Fonts/SFNSDisplay-Heavy.otf style Heavy @@ -35,7 +35,7 @@ name .SFNSDisplay-Regular path - SFNSDisplay-Regular.otf + Fonts/SFNSDisplay-Regular.otf style Regular @@ -50,7 +50,7 @@ name .SFNSText-Bold path - SFNSText-Bold.otf + Fonts/SFNSText-Bold.otf style Bold @@ -58,7 +58,7 @@ name .SFNSText-Heavy path - SFNSText-Heavy.otf + Fonts/SFNSText-Heavy.otf style Heavy @@ -66,7 +66,7 @@ name .SFNSText-Regular path - SFNSText-Regular.otf + Fonts/SFNSText-Regular.otf style Regular @@ -81,7 +81,7 @@ name Avenir-Black path - Avenir.ttc + Fonts/Avenir.ttc style Black @@ -89,7 +89,7 @@ name Avenir-BlackOblique path - Avenir.ttc + Fonts/Avenir.ttc style Black Oblique @@ -97,7 +97,7 @@ name Avenir-Book path - Avenir.ttc + Fonts/Avenir.ttc style Book @@ -105,7 +105,7 @@ name Avenir-BookOblique path - Avenir.ttc + Fonts/Avenir.ttc style Book Oblique @@ -113,7 +113,7 @@ name Avenir-Heavy path - Avenir.ttc + Fonts/Avenir.ttc style Heavy @@ -121,7 +121,7 @@ name Avenir-HeavyOblique path - Avenir.ttc + Fonts/Avenir.ttc style Heavy Oblique @@ -129,7 +129,7 @@ name Avenir-Light path - Avenir.ttc + Fonts/Avenir.ttc style Light @@ -137,7 +137,7 @@ name Avenir-LightOblique path - Avenir.ttc + Fonts/Avenir.ttc style Light Oblique @@ -145,7 +145,7 @@ name Avenir-Medium path - Avenir.ttc + Fonts/Avenir.ttc style Medium @@ -153,7 +153,7 @@ name Avenir-MediumOblique path - Avenir.ttc + Fonts/Avenir.ttc style Medium Oblique @@ -161,7 +161,7 @@ name Avenir-Oblique path - Avenir.ttc + Fonts/Avenir.ttc style Oblique @@ -169,7 +169,7 @@ name Avenir-Roman path - Avenir.ttc + Fonts/Avenir.ttc style Roman @@ -184,7 +184,7 @@ name ZapfDingbatsITC path - ZapfDingbats.ttf + Fonts/ZapfDingbats.ttf style Regular @@ -199,7 +199,7 @@ name private path - class.ttf + Fonts/class.ttf style internal diff --git a/Documentation/fonts/swift2.md b/Documentation/fonts/swift2.md index 011e22c..e915d94 100644 --- a/Documentation/fonts/swift2.md +++ b/Documentation/fonts/swift2.md @@ -19,6 +19,7 @@ You can customize some elements of this template by overriding the following par | Parameter Name | Default Value | Description | | -------------- | ------------- | ----------- | | `enumName` | `FontFamily` | Allows you to change the name of the generated `enum` containing all font families. | +| `preservePath` | N/A | Setting this parameter will disable the basename filter applied to all font paths. Use this if you added your font folder as a "folder reference" in your Xcode project, making that folder hierarchy preserved once copied in the build app bundle. The path will be relative to the folder you provided to SwiftGen. | ## Generated Code diff --git a/Documentation/fonts/swift3.md b/Documentation/fonts/swift3.md index 7971d51..bb4fb8d 100644 --- a/Documentation/fonts/swift3.md +++ b/Documentation/fonts/swift3.md @@ -18,6 +18,7 @@ You can customize some elements of this template by overriding the following par | Parameter Name | Default Value | Description | | -------------- | ------------- | ----------- | | `enumName` | `FontFamily` | Allows you to change the name of the generated `enum` containing all font families. | +| `preservePath` | N/A | Setting this parameter will disable the basename filter applied to all font paths. Use this if you added your font folder as a "folder reference" in your Xcode project, making that folder hierarchy preserved once copied in the build app bundle. The path will be relative to the folder you provided to SwiftGen. | ## Generated Code diff --git a/Documentation/fonts/swift4.md b/Documentation/fonts/swift4.md index 496454e..7756c54 100644 --- a/Documentation/fonts/swift4.md +++ b/Documentation/fonts/swift4.md @@ -18,6 +18,7 @@ You can customize some elements of this template by overriding the following par | Parameter Name | Default Value | Description | | -------------- | ------------- | ----------- | | `enumName` | `FontFamily` | Allows you to change the name of the generated `enum` containing all font families. | +| `preservePath` | N/A | Setting this parameter will disable the basename filter applied to all font paths. Use this if you added your font folder as a "folder reference" in your Xcode project, making that folder hierarchy preserved once copied in the build app bundle. The path will be relative to the folder you provided to SwiftGen. | ## Generated Code diff --git a/Podfile.lock b/Podfile.lock index ff08fe4..5b0715a 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -15,7 +15,7 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: StencilSwiftKit: - :commit: 695b6bfd3f0f54cec5b96d65783f98c3edd9a81c + :commit: 3ba083dea79a953156a3f128dcad0452f62a8132 :git: https://github.com/SwiftGen/StencilSwiftKit SPEC CHECKSUMS: diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock index ff08fe4..5b0715a 100644 --- a/Pods/Manifest.lock +++ b/Pods/Manifest.lock @@ -15,7 +15,7 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: StencilSwiftKit: - :commit: 695b6bfd3f0f54cec5b96d65783f98c3edd9a81c + :commit: 3ba083dea79a953156a3f128dcad0452f62a8132 :git: https://github.com/SwiftGen/StencilSwiftKit SPEC CHECKSUMS: diff --git a/Pods/StencilSwiftKit/README.md b/Pods/StencilSwiftKit/README.md index 9dce049..32d78fc 100644 --- a/Pods/StencilSwiftKit/README.md +++ b/Pods/StencilSwiftKit/README.md @@ -25,13 +25,19 @@ ## Filters * [String filters](Documentation/filters-strings.md): + * `basename`: Get the filename from a path. * `camelToSnakeCase`: Transforms text from camelCase to snake_case. By default it converts to lower case, unless a single optional argument is set to "false", "no" or "0". + * `contains`: Check if a string contains a specific substring. + * `dirname`: Get the path to the parent folder from a path. * `escapeReservedKeywords`: Escape keywords reserved in the Swift language, by wrapping them inside backticks so that the can be used as regular escape keywords in Swift code. + * `hasPrefix` / `hasSuffix`: Check if a string starts/ends with a specific substring. + * `lowerFirstLetter`: Lowercases only the first letter of a string. * `lowerFirstWord`: Lowercases only the first word of a string. * `removeNewlines`: Removes newlines and other whitespace characters, depending on the mode ("all" or "leading"). + * `replace`: Replaces instances of a substring with a new string. * `snakeToCamelCase`: Transforms text from snake_case to camelCase. By default it keeps leading underscores, unless a single optional argument is set to "true", "yes" or "1". * `swiftIdentifier`: Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference) - * `titlecase`: Uppercases only the first character + * `upperFirstLetter`: Uppercases only the first character * [Number filters](Documentation/filters-numbers.md): * `int255toFloat` * `hexToInt` diff --git a/Pods/StencilSwiftKit/Sources/Environment.swift b/Pods/StencilSwiftKit/Sources/Environment.swift index 5348e00..2df9258 100644 --- a/Pods/StencilSwiftKit/Sources/Environment.swift +++ b/Pods/StencilSwiftKit/Sources/Environment.swift @@ -13,13 +13,21 @@ public extension Extension { registerTag("call", parser: CallNode.parse) registerTag("map", parser: MapNode.parse) + registerFilter("basename", filter: Filters.Strings.basename) registerFilter("camelToSnakeCase", filter: Filters.Strings.camelToSnakeCase) + registerFilter("contains", filter: Filters.Strings.contains) + registerFilter("dirname", filter: Filters.Strings.dirname) registerFilter("escapeReservedKeywords", filter: Filters.Strings.escapeReservedKeywords) + registerFilter("hasPrefix", filter: Filters.Strings.hasPrefix) + registerFilter("hasSuffix", filter: Filters.Strings.hasSuffix) + registerFilter("lowerFirstLetter", filter: Filters.Strings.lowerFirstLetter) registerFilter("lowerFirstWord", filter: Filters.Strings.lowerFirstWord) registerFilter("removeNewlines", filter: Filters.Strings.removeNewlines) + registerFilter("replace", filter: Filters.Strings.replace) registerFilter("snakeToCamelCase", filter: Filters.Strings.snakeToCamelCase) registerFilter("swiftIdentifier", filter: Filters.Strings.swiftIdentifier) - registerFilter("titlecase", filter: Filters.Strings.titlecase) + registerFilter("titlecase", filter: Filters.Strings.upperFirstLetter) + registerFilter("upperFirstLetter", filter: Filters.Strings.upperFirstLetter) registerFilter("hexToInt", filter: Filters.Numbers.hexToInt) registerFilter("int255toFloat", filter: Filters.Numbers.int255toFloat) diff --git a/Pods/StencilSwiftKit/Sources/Filters+Strings.swift b/Pods/StencilSwiftKit/Sources/Filters+Strings.swift index 4bbbb86..a6133db 100644 --- a/Pods/StencilSwiftKit/Sources/Filters+Strings.swift +++ b/Pods/StencilSwiftKit/Sources/Filters+Strings.swift @@ -32,17 +32,43 @@ extension Filters { "right", "set", "Type", "unowned", "weak", "willSet" ] + /// Replaces in the given string the given substring with the replacement + /// "people picker", replacing "picker" with "life" gives "people life" + /// + /// - Parameters: + /// - value: the value to be processed + /// - arguments: the arguments to the function; expecting two arguments: substring, replacement + /// - Returns: the results string + /// - Throws: FilterError.invalidInputType if the value parameter or argunemts aren't string + static func replace(_ value: Any?, arguments: [Any?]) throws -> Any? { + guard let source = value as? String, + arguments.count == 2, + let substring = arguments[0] as? String, + let replacement = arguments[1] as? String else { + throw Filters.Error.invalidInputType + } + return source.replacingOccurrences(of: substring, with: replacement) + } + static func swiftIdentifier(_ value: Any?) throws -> Any? { guard let value = value as? String else { throw Filters.Error.invalidInputType } return StencilSwiftKit.swiftIdentifier(from: value, replaceWithUnderscores: true) } - /* - If the string starts with only one uppercase letter, lowercase that first letter - * - If the string starts with multiple uppercase letters, lowercase those first letters - * up to the one before the last uppercase one, but only if the last one is followed by - * a lowercase character. - * e.g. "PeoplePicker" gives "peoplePicker" but "URLChooser" gives "urlChooser" - */ + /// Lowers the first letter of the string + /// e.g. "People picker" gives "people picker", "Sports Stats" gives "sports Stats" + static func lowerFirstLetter(_ value: Any?) throws -> Any? { + guard let string = value as? String else { throw Filters.Error.invalidInputType } + let first = String(string.characters.prefix(1)).lowercased() + let other = String(string.characters.dropFirst(1)) + return first + other + } + + /// If the string starts with only one uppercase letter, lowercase that first letter + /// If the string starts with multiple uppercase letters, lowercase those first letters + /// up to the one before the last uppercase one, but only if the last one is followed by + /// a lowercase character. + /// e.g. "PeoplePicker" gives "peoplePicker" but "URLChooser" gives "urlChooser" static func lowerFirstWord(_ value: Any?) throws -> Any? { guard let string = value as? String else { throw Filters.Error.invalidInputType } let cs = CharacterSet.uppercaseLetters @@ -61,7 +87,15 @@ extension Filters { return transformed } - static func titlecase(_ value: Any?) throws -> Any? { + /// Lowers the first letter of the string + /// e.g. "People picker" gives "people picker", "Sports Stats" gives "sports Stats" + /// + /// - Parameters: + /// - value: the value to uppercase first letter of + /// - arguments: the arguments to the function; expecting zero + /// - Returns: the string with first letter being uppercased + /// - Throws: FilterError.invalidInputType if the value parameter isn't a string + static func upperFirstLetter(_ value: Any?) throws -> Any? { guard let string = value as? String else { throw Filters.Error.invalidInputType } return titlecase(string) } @@ -150,6 +184,68 @@ extension Filters { } } + /// Checks if the given string contains given substring + /// + /// - Parameters: + /// - value: the string value to check if it contains substring + /// - arguments: the arguments to the function; expecting one string argument - substring + /// - Returns: the result whether true or not + /// - Throws: FilterError.invalidInputType if the value parameter isn't a string or + /// if number of arguments is not one or if the given argument isn't a string + static func contains(_ value: Any?, arguments: [Any?]) throws -> Bool { + guard let string = value as? String else { throw Filters.Error.invalidInputType } + guard let substring = arguments.first as? String else { throw Filters.Error.invalidInputType } + return string.contains(substring) + } + + /// Checks if the given string has given prefix + /// + /// - Parameters: + /// - value: the string value to check if it has prefix + /// - arguments: the arguments to the function; expecting one string argument - prefix + /// - Returns: the result whether true or not + /// - Throws: FilterError.invalidInputType if the value parameter isn't a string or + /// if number of arguments is not one or if the given argument isn't a string + static func hasPrefix(_ value: Any?, arguments: [Any?]) throws -> Bool { + guard let string = value as? String else { throw Filters.Error.invalidInputType } + guard let prefix = arguments.first as? String else { throw Filters.Error.invalidInputType } + return string.hasPrefix(prefix) + } + + /// Checks if the given string has given suffix + /// + /// - Parameters: + /// - value: the string value to check if it has prefix + /// - arguments: the arguments to the function; expecting one string argument - suffix + /// - Returns: the result whether true or not + /// - Throws: FilterError.invalidInputType if the value parameter isn't a string or + /// if number of arguments is not one or if the given argument isn't a string + static func hasSuffix(_ value: Any?, arguments: [Any?]) throws -> Bool { + guard let string = value as? String else { throw Filters.Error.invalidInputType } + guard let suffix = arguments.first as? String else { throw Filters.Error.invalidInputType } + return string.hasSuffix(suffix) + } + + /// Converts a file path to just the filename, stripping any path components before it. + /// + /// - Parameter value: the value to be processed + /// - Returns: the basename of the path + /// - Throws: FilterError.invalidInputType if the value parameter isn't a string + static func basename(_ value: Any?) throws -> Any? { + guard let string = value as? String else { throw Filters.Error.invalidInputType } + return (string as NSString).lastPathComponent + } + + /// Converts a file path to just the path without the filename. + /// + /// - Parameter value: the value to be processed + /// - Returns: the dirname of the path + /// - Throws: FilterError.invalidInputType if the value parameter isn't a string + static func dirname(_ value: Any?) throws -> Any? { + guard let string = value as? String else { throw Filters.Error.invalidInputType } + return (string as NSString).deletingLastPathComponent + } + // MARK: - Private methods private static func removeLeadingWhitespaces(from string: String) -> String { diff --git a/Tests/Expected/Fonts/swift2-context-defaults-preservepath.swift b/Tests/Expected/Fonts/swift2-context-defaults-preservepath.swift new file mode 100644 index 0000000..37d1354 --- /dev/null +++ b/Tests/Expected/Fonts/swift2-context-defaults-preservepath.swift @@ -0,0 +1,86 @@ +// Generated using SwiftGen, by O.Halligon — https://github.com/SwiftGen/SwiftGen + +#if os(OSX) + import AppKit.NSFont + typealias Font = NSFont +#elseif os(iOS) || os(tvOS) || os(watchOS) + import UIKit.UIFont + typealias Font = UIFont +#endif + +// swiftlint:disable file_length + +struct FontConvertible { + let name: String + let family: String + let path: String + + func font(size: CGFloat) -> Font! { + return Font(font: self, size: size) + } + + func register() { + let bundle = NSBundle(forClass: BundleToken.self) + + guard let url = bundle.URLForResource(path, withExtension: nil) else { + return + } + + var errorRef: Unmanaged? + CTFontManagerRegisterFontsForURL(url as CFURL, .Process, &errorRef) + } +} + +extension Font { + convenience init!(font: FontConvertible, size: CGFloat) { + #if os(iOS) || os(tvOS) || os(watchOS) + if UIFont.fontNamesForFamilyName(font.family).isEmpty { + font.register() + } + #elseif os(OSX) + if NSFontManager.sharedFontManager().availableMembersOfFontFamily(font.family) == nil { + font.register() + } + #endif + + self.init(name: font.name, size: size) + } +} + +// swiftlint:disable identifier_name line_length type_body_length +enum FontFamily { + enum SFNSDisplay { + static let Black = FontConvertible(".SFNSDisplay-Black", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Black.otf") + static let Bold = FontConvertible(".SFNSDisplay-Bold", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Bold.otf") + static let Heavy = FontConvertible(".SFNSDisplay-Heavy", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Heavy.otf") + static let Regular = FontConvertible(".SFNSDisplay-Regular", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Regular.otf") + } + enum SFNSText { + static let Bold = FontConvertible(".SFNSText-Bold", family: ".SF NS Text", path: "Fonts/SFNSText-Bold.otf") + static let Heavy = FontConvertible(".SFNSText-Heavy", family: ".SF NS Text", path: "Fonts/SFNSText-Heavy.otf") + static let Regular = FontConvertible(".SFNSText-Regular", family: ".SF NS Text", path: "Fonts/SFNSText-Regular.otf") + } + enum Avenir { + static let Black = FontConvertible("Avenir-Black", family: "Avenir", path: "Fonts/Avenir.ttc") + static let BlackOblique = FontConvertible("Avenir-BlackOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let Book = FontConvertible("Avenir-Book", family: "Avenir", path: "Fonts/Avenir.ttc") + static let BookOblique = FontConvertible("Avenir-BookOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let Heavy = FontConvertible("Avenir-Heavy", family: "Avenir", path: "Fonts/Avenir.ttc") + static let HeavyOblique = FontConvertible("Avenir-HeavyOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let Light = FontConvertible("Avenir-Light", family: "Avenir", path: "Fonts/Avenir.ttc") + static let LightOblique = FontConvertible("Avenir-LightOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let Medium = FontConvertible("Avenir-Medium", family: "Avenir", path: "Fonts/Avenir.ttc") + static let MediumOblique = FontConvertible("Avenir-MediumOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let Oblique = FontConvertible("Avenir-Oblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let Roman = FontConvertible("Avenir-Roman", family: "Avenir", path: "Fonts/Avenir.ttc") + } + enum ZapfDingbats { + static let Regular = FontConvertible("ZapfDingbatsITC", family: "Zapf Dingbats", path: "Fonts/ZapfDingbats.ttf") + } + enum Public { + static let Internal = FontConvertible("private", family: "public", path: "Fonts/class.ttf") + } +} +// swiftlint:enable identifier_name line_length type_body_length + +private final class BundleToken {} diff --git a/Tests/Expected/Fonts/swift3-context-defaults-preservepath.swift b/Tests/Expected/Fonts/swift3-context-defaults-preservepath.swift new file mode 100644 index 0000000..8358f78 --- /dev/null +++ b/Tests/Expected/Fonts/swift3-context-defaults-preservepath.swift @@ -0,0 +1,86 @@ +// Generated using SwiftGen, by O.Halligon — https://github.com/SwiftGen/SwiftGen + +#if os(OSX) + import AppKit.NSFont + typealias Font = NSFont +#elseif os(iOS) || os(tvOS) || os(watchOS) + import UIKit.UIFont + typealias Font = UIFont +#endif + +// swiftlint:disable file_length + +struct FontConvertible { + let name: String + let family: String + let path: String + + func font(size: CGFloat) -> Font! { + return Font(font: self, size: size) + } + + func register() { + let bundle = Bundle(for: BundleToken.self) + + guard let url = bundle.url(forResource: path, withExtension: nil) else { + return + } + + var errorRef: Unmanaged? + CTFontManagerRegisterFontsForURL(url as CFURL, .process, &errorRef) + } +} + +extension Font { + convenience init!(font: FontConvertible, size: CGFloat) { + #if os(iOS) || os(tvOS) || os(watchOS) + if UIFont.fontNames(forFamilyName: font.family).isEmpty { + font.register() + } + #elseif os(OSX) + if NSFontManager.shared().availableMembers(ofFontFamily: font.family) == nil { + font.register() + } + #endif + + self.init(name: font.name, size: size) + } +} + +// swiftlint:disable identifier_name line_length type_body_length +enum FontFamily { + enum SFNSDisplay { + static let black = FontConvertible(name: ".SFNSDisplay-Black", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Black.otf") + static let bold = FontConvertible(name: ".SFNSDisplay-Bold", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Bold.otf") + static let heavy = FontConvertible(name: ".SFNSDisplay-Heavy", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Heavy.otf") + static let regular = FontConvertible(name: ".SFNSDisplay-Regular", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Regular.otf") + } + enum SFNSText { + static let bold = FontConvertible(name: ".SFNSText-Bold", family: ".SF NS Text", path: "Fonts/SFNSText-Bold.otf") + static let heavy = FontConvertible(name: ".SFNSText-Heavy", family: ".SF NS Text", path: "Fonts/SFNSText-Heavy.otf") + static let regular = FontConvertible(name: ".SFNSText-Regular", family: ".SF NS Text", path: "Fonts/SFNSText-Regular.otf") + } + enum Avenir { + static let black = FontConvertible(name: "Avenir-Black", family: "Avenir", path: "Fonts/Avenir.ttc") + static let blackOblique = FontConvertible(name: "Avenir-BlackOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let book = FontConvertible(name: "Avenir-Book", family: "Avenir", path: "Fonts/Avenir.ttc") + static let bookOblique = FontConvertible(name: "Avenir-BookOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let heavy = FontConvertible(name: "Avenir-Heavy", family: "Avenir", path: "Fonts/Avenir.ttc") + static let heavyOblique = FontConvertible(name: "Avenir-HeavyOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let light = FontConvertible(name: "Avenir-Light", family: "Avenir", path: "Fonts/Avenir.ttc") + static let lightOblique = FontConvertible(name: "Avenir-LightOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let medium = FontConvertible(name: "Avenir-Medium", family: "Avenir", path: "Fonts/Avenir.ttc") + static let mediumOblique = FontConvertible(name: "Avenir-MediumOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let oblique = FontConvertible(name: "Avenir-Oblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let roman = FontConvertible(name: "Avenir-Roman", family: "Avenir", path: "Fonts/Avenir.ttc") + } + enum ZapfDingbats { + static let regular = FontConvertible(name: "ZapfDingbatsITC", family: "Zapf Dingbats", path: "Fonts/ZapfDingbats.ttf") + } + enum Public { + static let `internal` = FontConvertible(name: "private", family: "public", path: "Fonts/class.ttf") + } +} +// swiftlint:enable identifier_name line_length type_body_length + +private final class BundleToken {} diff --git a/Tests/Expected/Fonts/swift4-context-defaults-preservepath.swift b/Tests/Expected/Fonts/swift4-context-defaults-preservepath.swift new file mode 100644 index 0000000..58a3b9e --- /dev/null +++ b/Tests/Expected/Fonts/swift4-context-defaults-preservepath.swift @@ -0,0 +1,86 @@ +// Generated using SwiftGen, by O.Halligon — https://github.com/SwiftGen/SwiftGen + +#if os(OSX) + import AppKit.NSFont + typealias Font = NSFont +#elseif os(iOS) || os(tvOS) || os(watchOS) + import UIKit.UIFont + typealias Font = UIFont +#endif + +// swiftlint:disable file_length + +struct FontConvertible { + let name: String + let family: String + let path: String + + func font(size: CGFloat) -> Font! { + return Font(font: self, size: size) + } + + func register() { + let bundle = Bundle(for: BundleToken.self) + + guard let url = bundle.url(forResource: path, withExtension: nil) else { + return + } + + var errorRef: Unmanaged? + CTFontManagerRegisterFontsForURL(url as CFURL, .process, &errorRef) + } +} + +extension Font { + convenience init!(font: FontConvertible, size: CGFloat) { + #if os(iOS) || os(tvOS) || os(watchOS) + if UIFont.fontNames(forFamilyName: font.family).isEmpty { + font.register() + } + #elseif os(OSX) + if NSFontManager.shared.availableMembers(ofFontFamily: font.family) == nil { + font.register() + } + #endif + + self.init(name: font.name, size: size) + } +} + +// swiftlint:disable identifier_name line_length type_body_length +enum FontFamily { + enum SFNSDisplay { + static let black = FontConvertible(name: ".SFNSDisplay-Black", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Black.otf") + static let bold = FontConvertible(name: ".SFNSDisplay-Bold", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Bold.otf") + static let heavy = FontConvertible(name: ".SFNSDisplay-Heavy", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Heavy.otf") + static let regular = FontConvertible(name: ".SFNSDisplay-Regular", family: ".SF NS Display", path: "Fonts/SFNSDisplay-Regular.otf") + } + enum SFNSText { + static let bold = FontConvertible(name: ".SFNSText-Bold", family: ".SF NS Text", path: "Fonts/SFNSText-Bold.otf") + static let heavy = FontConvertible(name: ".SFNSText-Heavy", family: ".SF NS Text", path: "Fonts/SFNSText-Heavy.otf") + static let regular = FontConvertible(name: ".SFNSText-Regular", family: ".SF NS Text", path: "Fonts/SFNSText-Regular.otf") + } + enum Avenir { + static let black = FontConvertible(name: "Avenir-Black", family: "Avenir", path: "Fonts/Avenir.ttc") + static let blackOblique = FontConvertible(name: "Avenir-BlackOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let book = FontConvertible(name: "Avenir-Book", family: "Avenir", path: "Fonts/Avenir.ttc") + static let bookOblique = FontConvertible(name: "Avenir-BookOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let heavy = FontConvertible(name: "Avenir-Heavy", family: "Avenir", path: "Fonts/Avenir.ttc") + static let heavyOblique = FontConvertible(name: "Avenir-HeavyOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let light = FontConvertible(name: "Avenir-Light", family: "Avenir", path: "Fonts/Avenir.ttc") + static let lightOblique = FontConvertible(name: "Avenir-LightOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let medium = FontConvertible(name: "Avenir-Medium", family: "Avenir", path: "Fonts/Avenir.ttc") + static let mediumOblique = FontConvertible(name: "Avenir-MediumOblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let oblique = FontConvertible(name: "Avenir-Oblique", family: "Avenir", path: "Fonts/Avenir.ttc") + static let roman = FontConvertible(name: "Avenir-Roman", family: "Avenir", path: "Fonts/Avenir.ttc") + } + enum ZapfDingbats { + static let regular = FontConvertible(name: "ZapfDingbatsITC", family: "Zapf Dingbats", path: "Fonts/ZapfDingbats.ttf") + } + enum Public { + static let `internal` = FontConvertible(name: "private", family: "public", path: "Fonts/class.ttf") + } +} +// swiftlint:enable identifier_name line_length type_body_length + +private final class BundleToken {} diff --git a/Tests/TemplatesTests/FontsTests.swift b/Tests/TemplatesTests/FontsTests.swift index 47aa19a..9858a36 100644 --- a/Tests/TemplatesTests/FontsTests.swift +++ b/Tests/TemplatesTests/FontsTests.swift @@ -23,7 +23,10 @@ class FontsTests: XCTestCase { suffix: ""), (context: try StencilContext.enrich(context: context, parameters: ["enumName=CustomFamily"]), - suffix: "-customname") + suffix: "-customname"), + (context: try StencilContext.enrich(context: context, + parameters: ["preservePath"]), + suffix: "-preservepath") ] } diff --git a/templates/fonts/swift2.stencil b/templates/fonts/swift2.stencil index ed101c2..d45478e 100644 --- a/templates/fonts/swift2.stencil +++ b/templates/fonts/swift2.stencil @@ -49,11 +49,18 @@ extension Font { } // swiftlint:disable identifier_name line_length type_body_length +{% macro transformPath path %}{% filter removeNewlines %} + {% if param.preservePath %} + {{path}} + {% else %} + {{path|basename}} + {% endif %} +{% endfilter %}{% endmacro %} enum {{param.enumName|default:"FontFamily"}} { {% for family in families %} enum {{family.name|swiftIdentifier|snakeToCamelCase:"true"|escapeReservedKeywords}} { {% for font in family.fonts %} - static let {{font.style|swiftIdentifier|snakeToCamelCase:"true"|escapeReservedKeywords}} = FontConvertible("{{font.name}}", family: "{{family.name}}", path: "{{font.path}}") + static let {{font.style|swiftIdentifier|snakeToCamelCase:"true"|escapeReservedKeywords}} = FontConvertible("{{font.name}}", family: "{{family.name}}", path: "{% call transformPath font.path %}") {% endfor %} } {% endfor %} diff --git a/templates/fonts/swift3.stencil b/templates/fonts/swift3.stencil index 9d20ef1..09f5b88 100644 --- a/templates/fonts/swift3.stencil +++ b/templates/fonts/swift3.stencil @@ -49,11 +49,18 @@ extension Font { } // swiftlint:disable identifier_name line_length type_body_length +{% macro transformPath path %}{% filter removeNewlines %} + {% if param.preservePath %} + {{path}} + {% else %} + {{path|basename}} + {% endif %} +{% endfilter %}{% endmacro %} enum {{param.enumName|default:"FontFamily"}} { {% for family in families %} enum {{family.name|swiftIdentifier|snakeToCamelCase:"true"|escapeReservedKeywords}} { {% for font in family.fonts %} - static let {{font.style|swiftIdentifier|snakeToCamelCase:"true"|lowerFirstWord|escapeReservedKeywords}} = FontConvertible(name: "{{font.name}}", family: "{{family.name}}", path: "{{font.path}}") + static let {{font.style|swiftIdentifier|snakeToCamelCase:"true"|lowerFirstWord|escapeReservedKeywords}} = FontConvertible(name: "{{font.name}}", family: "{{family.name}}", path: "{% call transformPath font.path %}") {% endfor %} } {% endfor %} diff --git a/templates/fonts/swift4.stencil b/templates/fonts/swift4.stencil index 517e1cb..53886e1 100644 --- a/templates/fonts/swift4.stencil +++ b/templates/fonts/swift4.stencil @@ -49,11 +49,18 @@ extension Font { } // swiftlint:disable identifier_name line_length type_body_length +{% macro transformPath path %}{% filter removeNewlines %} + {% if param.preservePath %} + {{path}} + {% else %} + {{path|basename}} + {% endif %} +{% endfilter %}{% endmacro %} enum {{param.enumName|default:"FontFamily"}} { {% for family in families %} enum {{family.name|swiftIdentifier|snakeToCamelCase:"true"|escapeReservedKeywords}} { {% for font in family.fonts %} - static let {{font.style|swiftIdentifier|snakeToCamelCase:"true"|lowerFirstWord|escapeReservedKeywords}} = FontConvertible(name: "{{font.name}}", family: "{{family.name}}", path: "{{font.path}}") + static let {{font.style|swiftIdentifier|snakeToCamelCase:"true"|lowerFirstWord|escapeReservedKeywords}} = FontConvertible(name: "{{font.name}}", family: "{{family.name}}", path: "{% call transformPath font.path %}") {% endfor %} } {% endfor %}