Squashed commit of the following:
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit

commit aa59ef28ea56315eb421ba044ddaf0c4066bfff8
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Mon Nov 7 10:26:28 2022 +0100

    Add trailing carrier at the end of generated extension files

commit e985950aa1e39d81d4938e15f8724c0f7723b003
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Fri Nov 4 16:37:34 2022 +0100

    Replace installation script by script that install completion file
    Setup a Makefile to install resgen

commit d574384c151259610a4c2f837b14068bb7716e44
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Fri Nov 4 14:33:39 2022 +0100

    Refactor
    Improve testability
    Add tests on SwiftUI generated code
    Add tests on  command

commit d9e76632c3037da0ed9e1dd37056685416579da9
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Thu Nov 3 15:43:47 2022 +0100

    Fixing bad merge on FontOptions

commit 76b5ebfcd1cde7a7d4c83f516a4fc937841e7715
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Thu Nov 3 15:37:28 2022 +0100

    Squashed commit of the following:

    commit 085f1ffc33
    Author: Thibaut Schmitt <t.schmitt@openium.fr>
    Date:   Thu Nov 3 15:00:27 2022 +0100

        Refactor SwiftUI extension generation and generation SwiftUI extension for images

    commit 4f7d7e18b1
    Author: Thibaut Schmitt <t.schmitt@openium.fr>
    Date:   Mon Oct 31 16:21:32 2022 +0100

        Génération de composant SwiftUI: Color et Image

    commit 0797667b25
    Author: Thibaut Schmitt <t.schmitt@openium.fr>
    Date:   Mon Oct 31 16:21:12 2022 +0100

        Génération de composant SwiftUI: Color et Image

commit 417a2630925841dd486ae1d684d28ab7dca240e0
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Wed Oct 19 17:13:03 2022 +0200

    Update Info.plist UIAppFonts key when generating fonts (if plist path if defined)
This commit is contained in:
2022-11-07 10:32:17 +01:00
parent 6203700b0c
commit 41733d2680
75 changed files with 1487 additions and 933 deletions

View File

@ -22,6 +22,7 @@ struct Colors: ParsableCommand {
static let toolName = "Color"
static let defaultExtensionName = "UIColor"
static let defaultExtensionNameSUI = "Color"
static let assetsColorsFolderName = "Colors"
// MARK: - Command options
@ -43,7 +44,7 @@ struct Colors: ParsableCommand {
// Get colors to generate
let parsedColors = ColorFileParser.parse(options.inputFile,
colorStyle: options.colorStyle)
colorStyle: options.style)
// -> Time: 0.0020350217819213867 seconds
// Generate all colors in xcassets
@ -55,9 +56,16 @@ struct Colors: ParsableCommand {
ColorExtensionGenerator.writeExtensionFile(colors: parsedColors,
staticVar: options.staticMembers,
extensionName: options.extensionName,
extensionFilePath: options.extensionFilePath)
// -> Time: 0.0010340213775634766 seconds
extensionFilePath: options.extensionFilePath,
isSwiftUI: false)
// Generate extension
ColorExtensionGenerator.writeExtensionFile(colors: parsedColors,
staticVar: options.staticMembers,
extensionName: options.extensionNameSwiftUI,
extensionFilePath: options.extensionFilePathSwiftUI,
isSwiftUI: true)
print("[\(Self.toolName)] Colors generated")
}
@ -80,6 +88,13 @@ struct Colors: ParsableCommand {
Colors.exit(withError: error)
}
// Extension for UIKit and SwiftUI should have different name
guard options.extensionName != options.extensionNameSwiftUI else {
let error = ColorsToolError.extensionNamesCollision(options.extensionName)
print(error.localizedDescription)
Colors.exit(withError: error)
}
// Check if needed to regenerate
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
inputFilePath: options.inputFile,

View File

@ -8,6 +8,7 @@
import Foundation
enum ColorsToolError: Error {
case extensionNamesCollision(String)
case badFormat(String)
case writeAsset(String)
case createAssetFolder(String)
@ -18,6 +19,9 @@ enum ColorsToolError: Error {
var description: String {
switch self {
case .extensionNamesCollision(let extensionName):
return "error:[\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
case .badFormat(let info):
return "error:[\(Colors.toolName)] Bad line format: \(info). Accepted format are: colorName=\"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\" \"#RGB/#ARGB\""

View File

@ -16,7 +16,7 @@ struct ColorsToolOptions: ParsableArguments {
var inputFile: String
@Option(help: "Color style to generate: light for light colors only, or all for dark and light colors")
fileprivate var style: String
var style: ColorStyle
@Option(help: "Path of xcassets where to generate colors", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var xcassetsPath: String
@ -27,9 +27,12 @@ struct ColorsToolOptions: ParsableArguments {
@Option(help: "Tell if it will generate static properties or not")
var staticMembers: Bool = false
@Option(help: "Extension name. If not specified, it will generate an UIColor extension. Using default extension name will generate static property.")
@Option(help: "Extension name. If not specified, it will generate an UIColor extension.")
var extensionName: String = Colors.defaultExtensionName
@Option(help: "SwiftUI Extension name. If not specified, it will generate an Color extension.")
var extensionNameSwiftUI: String = Colors.defaultExtensionNameSUI
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift")
var extensionSuffix: String?
}
@ -37,9 +40,8 @@ struct ColorsToolOptions: ParsableArguments {
// MARK: - Computed var
extension ColorsToolOptions {
var colorStyle: ColorStyle {
ColorStyle(rawValue: style) ?? .all
}
// MARK: - UIKit
var extensionFileName: String {
if let extensionSuffix = extensionSuffix {
@ -51,4 +53,17 @@ extension ColorsToolOptions {
var extensionFilePath: String {
"\(extensionOutputPath)/\(extensionFileName)"
}
// MARK: - SwiftUI
var extensionFileNameSwiftUI: String {
if let extensionSuffix = extensionSuffix {
return "\(extensionNameSwiftUI)+\(extensionSuffix).swift"
}
return "\(extensionNameSwiftUI).swift"
}
var extensionFilePathSwiftUI: String {
"\(extensionOutputPath)/\(extensionFileNameSwiftUI)"
}
}

View File

@ -13,11 +13,18 @@ struct ColorExtensionGenerator {
let colors: [ParsedColor]
let extensionClassname: String
static func writeExtensionFile(colors: [ParsedColor], staticVar: Bool, extensionName: String, extensionFilePath: String) {
// MARK: - UIKit
static func writeExtensionFile(colors: [ParsedColor],
staticVar: Bool,
extensionName: String,
extensionFilePath: String,
isSwiftUI: Bool) {
// Create extension content
let extensionContent = Self.getExtensionContent(colors: colors,
staticVar: staticVar,
extensionName: extensionName)
extensionName: extensionName,
isSwiftUI: isSwiftUI)
// Write content
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
@ -30,20 +37,23 @@ struct ColorExtensionGenerator {
}
}
static func getExtensionContent(colors: [ParsedColor], staticVar: Bool, extensionName: String) -> String {
static func getExtensionContent(colors: [ParsedColor],
staticVar: Bool,
extensionName: String,
isSwiftUI: Bool) -> String {
[
Self.getHeader(extensionClassname: extensionName),
Self.getProperties(for: colors, withStaticVar: staticVar),
Self.getHeader(extensionClassname: extensionName, isSwiftUI: isSwiftUI),
Self.getProperties(for: colors, withStaticVar: staticVar, isSwiftUI: isSwiftUI),
Self.getFooter()
]
.joined(separator: "\n")
}
private static func getHeader(extensionClassname: String) -> String {
private static func getHeader(extensionClassname: String, isSwiftUI: Bool) -> String {
"""
// Generated by ResgenSwift.\(Colors.toolName) \(ResgenSwiftVersion)
import UIKit
import \(isSwiftUI ? "SwiftUI" : "UIKit")
extension \(extensionClassname) {\n
"""
@ -52,15 +62,15 @@ struct ColorExtensionGenerator {
private static func getFooter() -> String {
"""
}
"""
}
private static func getProperties(for colors: [ParsedColor], withStaticVar staticVar: Bool) -> String {
private static func getProperties(for colors: [ParsedColor],
withStaticVar staticVar: Bool,
isSwiftUI: Bool) -> String {
colors.map {
if staticVar {
return $0.getColorStaticProperty()
}
return $0.getColorProperty()
$0.getColorProperty(isStatic: staticVar, isSwiftUI: isSwiftUI)
}
.joined(separator: "\n\n")
}

View File

@ -6,8 +6,16 @@
//
import Foundation
import ArgumentParser
enum ColorStyle: String, Decodable {
enum ColorStyle: String, Decodable, ExpressibleByArgument {
case light
case all
static var allValueStrings: [String] {
[
Self.light.rawValue,
Self.all.rawValue
]
}
}

View File

@ -72,19 +72,20 @@ struct ParsedColor {
"""
}
func getColorProperty() -> String {
"""
// MARK: - UIKit
func getColorProperty(isStatic: Bool, isSwiftUI: Bool) -> String {
if isSwiftUI {
return """
/// Color \(name) is \(light) (light) or \(dark) (dark)"
\(isStatic ? "static " : "")var \(name): Color {
Color("\(name)")
}
"""
}
return """
/// Color \(name) is \(light) (light) or \(dark) (dark)"
@objc var \(name): UIColor {
UIColor(named: "\(name)")!
}
"""
}
func getColorStaticProperty() -> String {
"""
/// Color \(name) is \(light) (light) or \(dark) (dark)"
static var \(name): UIColor {
\(isStatic ? "static " : "@objc ")var \(name): UIColor {
UIColor(named: "\(name)")!
}
"""

View File

@ -21,16 +21,25 @@ struct FontsOptions: ParsableArguments {
@Option(help: "Tell if it will generate static properties or methods")
var staticMembers: Bool = false
@Option(help: "Extension name. If not specified, it will generate an UIFont extension. Using default extension name will generate static property.")
@Option(help: "Extension name. If not specified, it will generate an UIFont extension.")
var extensionName: String = Fonts.defaultExtensionName
@Option(help: "Extension name. If not specified, it will generate an Font extension.")
var extensionNameSwiftUI: String = Fonts.defaultExtensionNameSUI
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+FontsMyApp.swift")
var extensionSuffix: String = ""
@Option(name: .customLong("info-plist-paths"), help: "Info.plist paths (array). Will be used to update UIAppFonts content")
fileprivate var infoPlistPathsRaw: String = ""
}
// MARK: - Computed var
extension FontsOptions {
// MARK: - UIKit
var extensionFileName: String {
if extensionSuffix.isEmpty == false {
return "\(extensionName)+\(extensionSuffix).swift"
@ -41,4 +50,25 @@ extension FontsOptions {
var extensionFilePath: String {
"\(extensionOutputPath)/\(extensionFileName)"
}
// MARK: - SwiftUI
var extensionFileNameSwiftUI: String {
if extensionSuffix.isEmpty == false {
return "\(extensionNameSwiftUI)+\(extensionSuffix).swift"
}
return "\(extensionNameSwiftUI).swift"
}
var extensionFilePathSwiftUI: String {
"\(extensionOutputPath)/\(extensionFileNameSwiftUI)"
}
// MARK: -
var infoPlistPaths: [String] {
infoPlistPathsRaw
.split(separator: " ")
.map { String($0) }
}
}

View File

@ -22,6 +22,7 @@ struct Fonts: ParsableCommand {
static let toolName = "Fonts"
static let defaultExtensionName = "UIFont"
static let defaultExtensionNameSUI = "Font"
// MARK: - Command Options
@ -50,10 +51,17 @@ struct Fonts: ParsableCommand {
FontExtensionGenerator.writeExtensionFile(fontsNames: fontsNames,
staticVar: options.staticMembers,
extensionName: options.extensionName,
extensionFilePath: options.extensionFilePath)
extensionFilePath: options.extensionFilePath,
isSwiftUI: false)
print("Info.plist information:")
print("\(FontPlistGenerator.generatePlistUIAppsFontContent(for: fontsNames))")
FontExtensionGenerator.writeExtensionFile(fontsNames: fontsNames,
staticVar: options.staticMembers,
extensionName: options.extensionNameSwiftUI,
extensionFilePath: options.extensionFilePathSwiftUI,
isSwiftUI: true)
print("Info.plist has been updated with:")
print("\(FontPlistGenerator.generatePlistUIAppsFontContent(for: fontsNames, infoPlistPaths: options.infoPlistPaths))")
print("[\(Self.toolName)] Fonts generated")
}
@ -70,6 +78,13 @@ struct Fonts: ParsableCommand {
Fonts.exit(withError: error)
}
// Extension for UIKit and SwiftUI should have different name
guard options.extensionName != options.extensionNameSwiftUI else {
let error = FontsToolError.extensionNamesCollision(options.extensionName)
print(error.localizedDescription)
Fonts.exit(withError: error)
}
// Check if needed to regenerate
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
inputFilePath: options.inputFile,

View File

@ -8,6 +8,7 @@
import Foundation
enum FontsToolError: Error {
case extensionNamesCollision(String)
case fcScan(String, Int32, String?)
case inputFolderNotFound(String)
case fileNotExists(String)
@ -15,6 +16,9 @@ enum FontsToolError: Error {
var localizedDescription: String {
switch self {
case .extensionNamesCollision(let extensionName):
return "error:[\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
case .fcScan(let path, let code, let output):
return "error:[\(Fonts.toolName)] Error while getting fontName (fc-scan --format %{postscriptname} \(path). fc-scan exit with \(code) and output is: \(output ?? "no output")"

View File

@ -6,12 +6,34 @@
//
import Foundation
import ToolCore
class FontPlistGenerator {
static func generatePlistUIAppsFontContent(for fonts: [FontName]) -> String {
var plistData = "<key>UIAppFonts</key>\n\t<array>\n"
fonts
static func generatePlistUIAppsFontContent(for fonts: [FontName], infoPlistPaths: [String]) -> String {
let fontsToAddToPlist = fonts
.compactMap { $0 }
// Update each plist
infoPlistPaths.forEach { infoPlist in
// Remove UIAppFonts value
Shell.shell(launchPath: "/usr/libexec/PlistBuddy",
["-c", "delete :UIAppFonts", infoPlist])
// Add UIAppFonts empty array
debugPrint("Will PlistBuddy -c add :UIAppFonts array \(infoPlist)")
Shell.shell(launchPath: "/usr/libexec/PlistBuddy",
["-c", "add :UIAppFonts array", infoPlist])
// Fill array with fonts
fontsToAddToPlist
.forEach {
Shell.shell(launchPath: "/usr/libexec/PlistBuddy",
["-c", "add :UIAppFonts: string \($0)", infoPlist])
}
}
var plistData = "<key>UIAppFonts</key>\n\t<array>\n"
fontsToAddToPlist
.forEach {
plistData += "\t\t<string>\($0)</string>\n"
}

View File

@ -9,12 +9,28 @@ import Foundation
import ToolCore
class FontExtensionGenerator {
private static func getFontNameEnum(fontsNames: [String]) -> String {
var enumDefinition = " enum FontName: String {\n"
fontsNames.forEach {
enumDefinition += " case \($0.fontNameSanitize) = \"\($0)\"\n"
}
enumDefinition += " }\n"
return enumDefinition
}
static func writeExtensionFile(fontsNames: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) {
static func writeExtensionFile(fontsNames: [String],
staticVar: Bool,
extensionName: String,
extensionFilePath: String,
isSwiftUI: Bool) {
// Create extension content
let extensionContent = Self.getExtensionContent(fontsNames: fontsNames,
staticVar: staticVar,
extensionName: extensionName)
extensionName: extensionName,
isSwiftUI: isSwiftUI)
// Write content
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
@ -27,48 +43,36 @@ class FontExtensionGenerator {
}
}
static func getExtensionContent(fontsNames: [String], staticVar: Bool, extensionName: String) -> String {
static func getExtensionContent(fontsNames: [String],
staticVar: Bool,
extensionName: String,
isSwiftUI: Bool) -> String {
[
Self.getHeader(extensionClassname: extensionName),
Self.getHeader(extensionClassname: extensionName, isSwiftUI: isSwiftUI),
Self.getFontNameEnum(fontsNames: fontsNames),
Self.getFontMethods(fontsNames: fontsNames, staticVar: staticVar),
Self.getFontMethods(fontsNames: fontsNames, staticVar: staticVar, isSwiftUI: isSwiftUI),
Self.getFooter()
]
.joined(separator: "\n")
}
private static func getHeader(extensionClassname: String) -> String {
private static func getHeader(extensionClassname: String, isSwiftUI: Bool) -> String {
"""
// Generated by ResgenSwift.\(Fonts.toolName) \(ResgenSwiftVersion)
import UIKit
import \(isSwiftUI ? "SwiftUI" : "UIKit")
extension \(extensionClassname) {\n
"""
}
private static func getFontNameEnum(fontsNames: [String]) -> String {
var enumDefinition = " enum FontName: String {\n"
fontsNames.forEach {
enumDefinition += " case \($0.fontNameSanitize) = \"\($0)\"\n"
}
enumDefinition += " }\n"
return enumDefinition
}
private static func getFontMethods(fontsNames: [FontName], staticVar: Bool) -> String {
private static func getFontMethods(fontsNames: [FontName], staticVar: Bool, isSwiftUI: Bool) -> String {
let pragma = " // MARK: - Getter"
var propertiesOrMethods: [String] = fontsNames
.unique()
.map {
if staticVar {
return $0.staticProperty
} else {
return $0.method
}
$0.getProperty(isStatic: staticVar, isSwiftUI: isSwiftUI)
}
propertiesOrMethods.insert(pragma, at: 0)
@ -78,6 +82,7 @@ class FontExtensionGenerator {
private static func getFooter() -> String {
"""
}
"""
}
}

View File

@ -14,19 +14,33 @@ extension FontName {
self.removeCharacters(from: "[]+-_")
}
var method: String {
"""
func getProperty(isStatic: Bool, isSwiftUI: Bool) -> String {
if isSwiftUI {
if isStatic {
return """
static let \(fontNameSanitize): ((_ size: CGFloat) -> Font) = { size in
Font.custom(FontName.\(fontNameSanitize).rawValue, size: size)
}
"""
}
return """
func \(fontNameSanitize)(withSize size: CGFloat) -> Font {
Font.custom(FontName.\(fontNameSanitize).rawValue, size: size)
}
"""
}
// UIKit
if isStatic {
return """
static let \(fontNameSanitize): ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.\(fontNameSanitize).rawValue, size: size)!
}
"""
}
return """
func \(fontNameSanitize)(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.\(fontNameSanitize).rawValue, size: size)!
}
"""
}
var staticProperty: String {
"""
static let \(fontNameSanitize): ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.\(fontNameSanitize).rawValue, size: size)!
}
"""
}
}

View File

@ -10,6 +10,7 @@ import Foundation
extension String {
func prependIfRelativePath(_ prependPath: String) -> String {
// If path starts with "/", it's an absolute path
if self.hasPrefix("/") {
return self
}

View File

@ -34,11 +34,11 @@ struct Generate: ParsableCommand {
// Parse
let configuration = ConfigurationFileParser.parse(options.configurationFile)
print("Found configurations :")
print(" - \(configuration.colors.count) colors configuration")
print(" - \(configuration.fonts.count) fonts configuration")
print(" - \(configuration.images.count) images configuration")
print(" - \(configuration.strings.count) strings configuration")
print(" - \(configuration.tags.count) tags configuration")
print(" - \(configuration.colors.count) colors configuration(s)")
print(" - \(configuration.fonts.count) fonts configuration(s)")
print(" - \(configuration.images.count) images configuration(s)")
print(" - \(configuration.strings.count) strings configuration(s)")
print(" - \(configuration.tags.count) tags configuration(s)")
print()
print("Input file: \(configuration.colors.first?.inputFile ?? "no input file")")

View File

@ -45,6 +45,7 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
let xcassetsPath: String
let extensionOutputPath: String
let extensionName: String?
let extensionNameSwiftUI: String?
let extensionSuffix: String?
private let staticMembers: Bool?
@ -55,6 +56,24 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
return false
}
internal init(inputFile: String,
style: String,
xcassetsPath: String,
extensionOutputPath: String,
extensionName: String?,
extensionNameSwiftUI: String?,
extensionSuffix: String?,
staticMembers: Bool?) {
self.inputFile = inputFile
self.style = style
self.xcassetsPath = xcassetsPath
self.extensionOutputPath = extensionOutputPath
self.extensionName = extensionName
self.extensionNameSwiftUI = extensionNameSwiftUI
self.extensionSuffix = extensionSuffix
self.staticMembers = staticMembers
}
var debugDescription: String {
"""
Colors configuration:
@ -63,6 +82,7 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
- Xcassets path: \(xcassetsPath)
- Extension output path: \(extensionOutputPath)
- Extension name: \(extensionName ?? "-")
- Extension name SwiftUI: \(extensionNameSwiftUI ?? "-")
- Extension suffix: \(extensionSuffix ?? "-")
"""
}
@ -72,7 +92,9 @@ struct FontsConfiguration: Codable, CustomDebugStringConvertible {
let inputFile: String
let extensionOutputPath: String
let extensionName: String?
let extensionNameSwiftUI: String?
let extensionSuffix: String?
let infoPlistPaths: String?
private let staticMembers: Bool?
var staticMembersOptions: Bool {
@ -82,13 +104,31 @@ struct FontsConfiguration: Codable, CustomDebugStringConvertible {
return false
}
internal init(inputFile: String,
extensionOutputPath: String,
extensionName: String?,
extensionNameSwiftUI: String?,
extensionSuffix: String?,
infoPlistPaths: String?,
staticMembers: Bool?) {
self.inputFile = inputFile
self.extensionOutputPath = extensionOutputPath
self.extensionName = extensionName
self.extensionNameSwiftUI = extensionNameSwiftUI
self.extensionSuffix = extensionSuffix
self.infoPlistPaths = infoPlistPaths
self.staticMembers = staticMembers
}
var debugDescription: String {
"""
Fonts configuration:
- Input file: \(inputFile)
- Extension output path: \(extensionOutputPath)
- Extension name: \(extensionName ?? "-")
- Extension name SwiftUI: \(extensionNameSwiftUI ?? "-")
- Extension suffix: \(extensionSuffix ?? "-")
- InfoPlistPaths: \(infoPlistPaths ?? "-")
"""
}
}
@ -98,6 +138,7 @@ struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
let xcassetsPath: String
let extensionOutputPath: String
let extensionName: String?
let extensionNameSwiftUI: String?
let extensionSuffix: String?
private let staticMembers: Bool?
@ -108,6 +149,22 @@ struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
return false
}
internal init(inputFile: String,
xcassetsPath: String,
extensionOutputPath: String,
extensionName: String?,
extensionNameSwiftUI: String?,
extensionSuffix: String?,
staticMembers: Bool?) {
self.inputFile = inputFile
self.xcassetsPath = xcassetsPath
self.extensionOutputPath = extensionOutputPath
self.extensionName = extensionName
self.extensionNameSwiftUI = extensionNameSwiftUI
self.extensionSuffix = extensionSuffix
self.staticMembers = staticMembers
}
var debugDescription: String {
"""
Images configuration:
@ -115,6 +172,7 @@ struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
- Xcassets path: \(xcassetsPath)
- Extension output path: \(extensionOutputPath)
- Extension name: \(extensionName ?? "-")
- Extension name SwiftUI: \(extensionNameSwiftUI ?? "-")
- Extension suffix: \(extensionSuffix ?? "-")
"""
}
@ -137,6 +195,24 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
return false
}
internal init(inputFile: String,
outputPath: String,
langs: String,
defaultLang: String,
extensionOutputPath: String,
extensionName: String?,
extensionSuffix: String?,
staticMembers: Bool?) {
self.inputFile = inputFile
self.outputPath = outputPath
self.langs = langs
self.defaultLang = defaultLang
self.extensionOutputPath = extensionOutputPath
self.extensionName = extensionName
self.extensionSuffix = extensionSuffix
self.staticMembers = staticMembers
}
var debugDescription: String {
"""
Strings configuration:
@ -166,6 +242,20 @@ struct TagsConfiguration: Codable, CustomDebugStringConvertible {
return false
}
internal init(inputFile: String,
lang: String,
extensionOutputPath: String,
extensionName: String?,
extensionSuffix: String?,
staticMembers: Bool?) {
self.inputFile = inputFile
self.lang = lang
self.extensionOutputPath = extensionOutputPath
self.extensionName = extensionName
self.extensionSuffix = extensionSuffix
self.staticMembers = staticMembers
}
var debugDescription: String {
"""
Tags configuration:

View File

@ -9,6 +9,11 @@ import Foundation
extension ColorsConfiguration: Runnable {
func run(projectDirectory: String, force: Bool) {
let args = getArguments(projectDirectory: projectDirectory, force: force)
Colors.main(args)
}
func getArguments(projectDirectory: String, force: Bool) -> [String] {
var args = [String]()
if force {
@ -33,6 +38,12 @@ extension ColorsConfiguration: Runnable {
extensionName
]
}
if let extensionNameSwiftUI = extensionNameSwiftUI {
args += [
"--extension-name-swift-ui",
extensionNameSwiftUI
]
}
if let extensionSuffix = extensionSuffix {
args += [
"--extension-suffix",
@ -40,6 +51,6 @@ extension ColorsConfiguration: Runnable {
]
}
Colors.main(args)
return args
}
}

View File

@ -9,6 +9,11 @@ import Foundation
extension FontsConfiguration: Runnable {
func run(projectDirectory: String, force: Bool) {
let args = getArguments(projectDirectory: projectDirectory, force: force)
Fonts.main(args)
}
func getArguments(projectDirectory: String, force: Bool) -> [String] {
var args = [String]()
if force {
@ -29,6 +34,12 @@ extension FontsConfiguration: Runnable {
extensionName
]
}
if let extensionNameSwiftUI = extensionNameSwiftUI {
args += [
"--extension-name-swift-ui",
extensionNameSwiftUI
]
}
if let extensionSuffix = extensionSuffix {
args += [
@ -37,6 +48,18 @@ extension FontsConfiguration: Runnable {
]
}
Fonts.main(args)
if let infoPlistPaths = infoPlistPaths {
let adjustedPlistPaths = infoPlistPaths
.split(separator: " ")
.map { String($0).prependIfRelativePath(projectDirectory) }
.joined(separator: " ")
args += [
"--info-plist-paths",
adjustedPlistPaths
]
}
return args
}
}

View File

@ -9,6 +9,11 @@ import Foundation
extension ImagesConfiguration: Runnable {
func run(projectDirectory: String, force: Bool) {
let args = getArguments(projectDirectory: projectDirectory, force: force)
Images.main(args)
}
func getArguments(projectDirectory: String, force: Bool) -> [String] {
var args = [String]()
if force {
@ -31,6 +36,12 @@ extension ImagesConfiguration: Runnable {
extensionName
]
}
if let extensionNameSwiftUI = extensionNameSwiftUI {
args += [
"--extension-name-swift-ui",
extensionNameSwiftUI
]
}
if let extensionSuffix = extensionSuffix {
args += [
"--extension-suffix",
@ -38,6 +49,6 @@ extension ImagesConfiguration: Runnable {
]
}
Images.main(args)
return args
}
}

View File

@ -10,18 +10,20 @@ import Foundation
class ImageExtensionGenerator {
// MARK: - pragm
// MARK: - UIKit
static func generateExtensionFile(images: [ParsedImage],
staticVar: Bool,
inputFilename: String,
extensionName: String,
extensionFilePath: String) {
extensionFilePath: String,
isSwiftUI: Bool) {
// Create extension conten1t
let extensionContent = Self.getExtensionContent(images: images,
staticVar: staticVar,
extensionName: extensionName,
inputFilename: inputFilename)
inputFilename: inputFilename,
isSwiftUI: isSwiftUI)
// Write content
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
@ -34,44 +36,42 @@ class ImageExtensionGenerator {
}
}
// MARK: - Extension content
static func getExtensionContent(images: [ParsedImage], staticVar: Bool, extensionName: String, inputFilename: String) -> String {
static func getExtensionContent(images: [ParsedImage],
staticVar: Bool,
extensionName: String,
inputFilename: String,
isSwiftUI: Bool) -> String {
[
Self.getHeader(inputFilename: inputFilename, extensionClassname: extensionName),
Self.getProperties(images: images, staticVar: staticVar),
Self.getHeader(inputFilename: inputFilename, extensionClassname: extensionName, isSwiftUI: isSwiftUI),
Self.getProperties(images: images, staticVar: staticVar, isSwiftUI: isSwiftUI),
Self.getFooter()
]
.joined(separator: "\n")
}
// MARK: - Extension part
private static func getHeader(inputFilename: String, extensionClassname: String) -> String {
private static func getHeader(inputFilename: String,
extensionClassname: String,
isSwiftUI: Bool) -> String {
"""
// Generated by ResgenSwift.\(Images.toolName) \(ResgenSwiftVersion)
// Images from \(inputFilename)
import UIKit
import \(isSwiftUI ? "SwiftUI" : "UIKit")
extension \(extensionClassname) {
"""
}
private static func getProperties(images: [ParsedImage], staticVar: Bool) -> String {
if staticVar {
return images
.map { "\n\($0.getStaticImageProperty())" }
.joined(separator: "\n")
}
return images
.map { "\n\($0.getImageProperty())" }
private static func getProperties(images: [ParsedImage], staticVar: Bool, isSwiftUI: Bool) -> String {
images
.map { "\n\($0.getImageProperty(isStatic: staticVar, isSwiftUI: isSwiftUI))" }
.joined(separator: "\n")
}
private static func getFooter() -> String {
"""
}
"""
}
}

View File

@ -22,6 +22,7 @@ struct Images: ParsableCommand {
static let toolName = "Images"
static let defaultExtensionName = "UIImage"
static let defaultExtensionNameSUI = "Image"
// MARK: - Command Options
@ -56,8 +57,15 @@ struct Images: ParsableCommand {
staticVar: options.staticMembers,
inputFilename: options.inputFilenameWithoutExt,
extensionName: options.extensionName,
extensionFilePath: options.extensionFilePath)
extensionFilePath: options.extensionFilePath,
isSwiftUI: false)
ImageExtensionGenerator.generateExtensionFile(images: imagesToGenerate,
staticVar: options.staticMembers,
inputFilename: options.inputFilenameWithoutExt,
extensionName: options.extensionNameSwiftUI,
extensionFilePath: options.extensionFilePathSwiftUI,
isSwiftUI: true)
print("[\(Self.toolName)] Images generated")
}
@ -81,6 +89,13 @@ struct Images: ParsableCommand {
// RSVG-Converter
_ = Images.getSvgConverterPath()
// Extension for UIKit and SwiftUI should have different name
guard options.extensionName != options.extensionNameSwiftUI else {
let error = ImagesError.extensionNamesCollision(options.extensionName)
print(error.localizedDescription)
Images.exit(withError: error)
}
// Check if needed to regenerate
guard GeneratorChecker.shouldGenerate(force: options.forceExecution,
inputFilePath: options.inputFile,

View File

@ -8,6 +8,7 @@
import Foundation
enum ImagesError: Error {
case extensionNamesCollision(String)
case inputFolderNotFound(String)
case fileNotExists(String)
case unknownImageExtension(String)
@ -19,6 +20,9 @@ enum ImagesError: Error {
var localizedDescription: String {
switch self {
case .extensionNamesCollision(let extensionName):
return "error:[\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
case .inputFolderNotFound(let inputFolder):
return " error:[\(Images.toolName)] Input folder not found: \(inputFolder)"

View File

@ -27,9 +27,12 @@ struct ImagesOptions: ParsableArguments {
@Option(help: "Tell if it will generate static properties or not")
var staticMembers: Bool = false
@Option(help: "Extension name. If not specified, it will generate an UIImage extension. Using default extension name will generate static property.")
@Option(help: "Extension name. If not specified, it will generate an UIImage extension.")
var extensionName: String = Images.defaultExtensionName
@Option(help: "Extension name. If not specified, it will generate an Image extension.")
var extensionNameSwiftUI: String = Images.defaultExtensionNameSUI
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Image{extensionSuffix}.swift")
var extensionSuffix: String?
}
@ -37,6 +40,9 @@ struct ImagesOptions: ParsableArguments {
// MARK: - Computed var
extension ImagesOptions {
// MARK: - UIKit
var extensionFileName: String {
if let extensionSuffix = extensionSuffix {
return "\(extensionName)+\(extensionSuffix).swift"
@ -48,6 +54,21 @@ extension ImagesOptions {
"\(extensionOutputPath)/\(extensionFileName)"
}
// MARK: - SwiftUI
var extensionFileNameSwiftUI: String {
if let extensionSuffix = extensionSuffix {
return "\(extensionNameSwiftUI)+\(extensionSuffix).swift"
}
return "\(extensionNameSwiftUI).swift"
}
var extensionFilePathSwiftUI: String {
"\(extensionOutputPath)/\(extensionFileNameSwiftUI)"
}
// MARK: -
var inputFilenameWithoutExt: String {
URL(fileURLWithPath: inputFile)
.deletingPathExtension()

View File

@ -72,17 +72,16 @@ struct ParsedImage {
// MARK: - Extension property
func getImageProperty() -> String {
"""
var \(name): UIImage {
UIImage(named: "\(name)")!
}
"""
}
func getStaticImageProperty() -> String {
"""
static var \(name): UIImage {
func getImageProperty(isStatic: Bool, isSwiftUI: Bool) -> String {
if isSwiftUI {
return """
\(isStatic ? "static ": "")var \(name): Image {
Image("\(name)")
}
"""
}
return """
\(isStatic ? "static ": "")var \(name): UIImage {
UIImage(named: "\(name)")!
}
"""

View File

@ -158,6 +158,7 @@ class StringsFileGenerator {
private static func getFooter() -> String {
"""
}
"""
}
}

View File

@ -80,6 +80,7 @@ class TagsGenerator {
private static func getFooter() -> String {
"""
}
"""
}
}

View File

@ -33,7 +33,7 @@ struct StringiumOptions: ParsableArguments {
@Option(help: "Tell if it will generate static properties or not")
var staticMembers: Bool = false
@Option(help: "Extension name. If not specified, it will generate an String extension. Using default extension name will generate static property.")
@Option(help: "Extension name. If not specified, it will generate an String extension.")
var extensionName: String = Stringium.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+{extensionSuffix}.swift")

View File

@ -24,7 +24,7 @@ struct TagsOptions: ParsableArguments {
@Option(help: "Tell if it will generate static properties or not")
var staticMembers: Bool = false
@Option(help: "Extension name. If not specified, it will generate a Tag extension. Using default extension name will generate static property.")
@Option(help: "Extension name. If not specified, it will generate a Tag extension.")
var extensionName: String = Tags.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Tag{extensionSuffix}.swift")