diff --git a/Sources/ResgenSwift/Colors/Colors.swift b/Sources/ResgenSwift/Colors/Colors.swift index b0cc2c8..64d8957 100644 --- a/Sources/ResgenSwift/Colors/Colors.swift +++ b/Sources/ResgenSwift/Colors/Colors.swift @@ -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 @@ -56,6 +57,13 @@ struct Colors: ParsableCommand { staticVar: options.staticMembers, extensionName: options.extensionName, extensionFilePath: options.extensionFilePath) + + // Generate extension + ColorExtensionGenerator.writeSUIExtensionFile(colors: parsedColors, + staticVar: options.staticMembers, + extensionName: options.extensionNameSwiftUI, + extensionFilePath: options.extensionFilePathSwiftUI) + // -> Time: 0.0010340213775634766 seconds 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, diff --git a/Sources/ResgenSwift/Colors/ColorsToolError.swift b/Sources/ResgenSwift/Colors/ColorsToolError.swift index a4310e5..0397fa7 100644 --- a/Sources/ResgenSwift/Colors/ColorsToolError.swift +++ b/Sources/ResgenSwift/Colors/ColorsToolError.swift @@ -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\"" diff --git a/Sources/ResgenSwift/Colors/ColorsToolOptions.swift b/Sources/ResgenSwift/Colors/ColorsToolOptions.swift index 9f5ae80..00b1ca7 100644 --- a/Sources/ResgenSwift/Colors/ColorsToolOptions.swift +++ b/Sources/ResgenSwift/Colors/ColorsToolOptions.swift @@ -30,6 +30,9 @@ struct ColorsToolOptions: ParsableArguments { @Option(help: "Extension name. If not specified, it will generate an UIColor extension. Using default extension name will generate static property.") var extensionName: String = Colors.defaultExtensionName + @Option(help: "SwiftUI Extension name. If not specified, it will generate an Color extension. Using default extension name will generate static property.") + var extensionNameSwiftUI: String = Colors.defaultExtensionNameSUI + @Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift") var extensionSuffix: String? } @@ -41,6 +44,8 @@ extension ColorsToolOptions { ColorStyle(rawValue: style) ?? .all } + // MARK: - UIKit + var extensionFileName: String { if let extensionSuffix = extensionSuffix { return "\(extensionName)+\(extensionSuffix).swift" @@ -51,4 +56,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)" + } } diff --git a/Sources/ResgenSwift/Colors/Generator/ColorExtensionGenerator.swift b/Sources/ResgenSwift/Colors/Generator/ColorExtensionGenerator.swift index 6221896..da936b2 100644 --- a/Sources/ResgenSwift/Colors/Generator/ColorExtensionGenerator.swift +++ b/Sources/ResgenSwift/Colors/Generator/ColorExtensionGenerator.swift @@ -13,6 +13,8 @@ struct ColorExtensionGenerator { let colors: [ParsedColor] let extensionClassname: String + // MARK: - UIKit + static func writeExtensionFile(colors: [ParsedColor], staticVar: Bool, extensionName: String, extensionFilePath: String) { // Create extension content let extensionContent = Self.getExtensionContent(colors: colors, @@ -64,4 +66,58 @@ struct ColorExtensionGenerator { } .joined(separator: "\n\n") } + + // MARK: - SwiftUI + + static func writeSUIExtensionFile(colors: [ParsedColor], staticVar: Bool, extensionName: String, extensionFilePath: String) { + // Create extension content + let extensionContent = Self.getSUIExtensionContent(colors: colors, + staticVar: staticVar, + extensionName: extensionName) + + // Write content + let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath) + do { + try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8) + } catch (let error) { + let error = ColorsToolError.writeExtension(extensionFilePath, error.localizedDescription) + print(error.localizedDescription) + Colors.exit(withError: error) + } + } + + static func getSUIExtensionContent(colors: [ParsedColor], staticVar: Bool, extensionName: String) -> String { + [ + Self.getSUIHeader(extensionClassname: extensionName), + Self.getSUIProperties(for: colors, withStaticVar: staticVar), + Self.getSUIFooter() + ] + .joined(separator: "\n") + } + + private static func getSUIHeader(extensionClassname: String) -> String { + """ + // Generated by ResgenSwift.\(Colors.toolName) \(ResgenSwiftVersion) + + import SwiftUI + + extension \(extensionClassname) {\n + """ + } + + private static func getSUIFooter() -> String { + """ + } + """ + } + + private static func getSUIProperties(for colors: [ParsedColor], withStaticVar staticVar: Bool) -> String { + colors.map { + if staticVar { + return $0.getSUIColorStaticProperty() + } + return $0.getSUIColorProperty() + } + .joined(separator: "\n\n") + } } diff --git a/Sources/ResgenSwift/Colors/Model/ParsedColor.swift b/Sources/ResgenSwift/Colors/Model/ParsedColor.swift index 2bfe56c..2a8d2ee 100644 --- a/Sources/ResgenSwift/Colors/Model/ParsedColor.swift +++ b/Sources/ResgenSwift/Colors/Model/ParsedColor.swift @@ -72,6 +72,8 @@ struct ParsedColor { """ } + // MARK: - UIKit + func getColorProperty() -> String { """ /// Color \(name) is \(light) (light) or \(dark) (dark)" @@ -89,4 +91,24 @@ struct ParsedColor { } """ } + + // MARK: - SwiftUI + + func getSUIColorProperty() -> String { + """ + /// Color \(name) is \(light) (light) or \(dark) (dark)" + var \(name): Color { + Color("\(name)") + } + """ + } + + func getSUIColorStaticProperty() -> String { + """ + /// Color \(name) is \(light) (light) or \(dark) (dark)" + static var \(name): Color { + Color("\(name)")! + } + """ + } } diff --git a/Sources/ResgenSwift/Fonts/FontOptions.swift b/Sources/ResgenSwift/Fonts/FontOptions.swift index 983f00d..7ce99d5 100644 --- a/Sources/ResgenSwift/Fonts/FontOptions.swift +++ b/Sources/ResgenSwift/Fonts/FontOptions.swift @@ -24,6 +24,9 @@ struct FontsOptions: ParsableArguments { @Option(help: "Extension name. If not specified, it will generate an UIFont extension. Using default extension name will generate static property.") var extensionName: String = Fonts.defaultExtensionName + @Option(help: "Extension name. If not specified, it will generate an Font extension. Using default extension name will generate static property.") + var extensionNameSwiftUI: String = Fonts.defaultExtensionNameSUI + @Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+FontsMyApp.swift") var extensionSuffix: String = "" } @@ -31,6 +34,9 @@ struct FontsOptions: ParsableArguments { // MARK: - Computed var extension FontsOptions { + + // MARK: - UIKit + var extensionFileName: String { if extensionSuffix.isEmpty == false { return "\(extensionName)+\(extensionSuffix).swift" @@ -41,4 +47,17 @@ 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)" + } } diff --git a/Sources/ResgenSwift/Fonts/Fonts.swift b/Sources/ResgenSwift/Fonts/Fonts.swift index 3fa963d..0ac79a4 100644 --- a/Sources/ResgenSwift/Fonts/Fonts.swift +++ b/Sources/ResgenSwift/Fonts/Fonts.swift @@ -22,6 +22,7 @@ struct Fonts: ParsableCommand { static let toolName = "Fonts" static let defaultExtensionName = "UIFont" + static let defaultExtensionNameSUI = "Font" // MARK: - Command Options @@ -52,6 +53,11 @@ struct Fonts: ParsableCommand { extensionName: options.extensionName, extensionFilePath: options.extensionFilePath) + FontExtensionGenerator.writeSUIExtensionFile(fontsNames: fontsNames, + staticVar: options.staticMembers, + extensionName: options.extensionNameSwiftUI, + extensionFilePath: options.extensionFilePathSwiftUI) + print("Info.plist information:") print("\(FontPlistGenerator.generatePlistUIAppsFontContent(for: fontsNames))") @@ -70,6 +76,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, diff --git a/Sources/ResgenSwift/Fonts/FontsToolError.swift b/Sources/ResgenSwift/Fonts/FontsToolError.swift index e979ca6..30a8a22 100644 --- a/Sources/ResgenSwift/Fonts/FontsToolError.swift +++ b/Sources/ResgenSwift/Fonts/FontsToolError.swift @@ -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")" diff --git a/Sources/ResgenSwift/Fonts/Generator/FontToolContentGenerator.swift b/Sources/ResgenSwift/Fonts/Generator/FontToolContentGenerator.swift index 992e55d..b716d22 100644 --- a/Sources/ResgenSwift/Fonts/Generator/FontToolContentGenerator.swift +++ b/Sources/ResgenSwift/Fonts/Generator/FontToolContentGenerator.swift @@ -9,6 +9,19 @@ 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 + } + + // MARK: - UIKit static func writeExtensionFile(fontsNames: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) { // Create extension content @@ -47,17 +60,6 @@ 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 - } - private static func getFontMethods(fontsNames: [FontName], staticVar: Bool) -> String { let pragma = " // MARK: - Getter" @@ -80,4 +82,66 @@ class FontExtensionGenerator { } """ } + + // MARK: - SwiftUI + + static func writeSUIExtensionFile(fontsNames: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) { + // Create extension content + let extensionContent = Self.getSUIExtensionContent(fontsNames: fontsNames, + staticVar: staticVar, + extensionName: extensionName) + + // Write content + let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath) + do { + try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8) + } catch (let error) { + let error = FontsToolError.writeExtension(extensionFilePath, error.localizedDescription) + print(error.localizedDescription) + Fonts.exit(withError: error) + } + } + + static func getSUIExtensionContent(fontsNames: [String], staticVar: Bool, extensionName: String) -> String { + [ + Self.getSUIHeader(extensionClassname: extensionName), + Self.getFontNameEnum(fontsNames: fontsNames), + Self.getSUIFontMethods(fontsNames: fontsNames, staticVar: staticVar), + Self.getSUIFooter() + ] + .joined(separator: "\n") + } + + private static func getSUIHeader(extensionClassname: String) -> String { + """ + // Generated by ResgenSwift.\(Fonts.toolName) \(ResgenSwiftVersion) + + import SwiftUI + + extension \(extensionClassname) {\n + """ + } + + private static func getSUIFontMethods(fontsNames: [FontName], staticVar: Bool) -> String { + let pragma = " // MARK: - Getter" + + var propertiesOrMethods: [String] = fontsNames + .unique() + .map { + if staticVar { + return $0.suiStaticProperty + } else { + return $0.suiMethod + } + } + + propertiesOrMethods.insert(pragma, at: 0) + return propertiesOrMethods.joined(separator: "\n\n") + } + + private static func getSUIFooter() -> String { + """ + } + """ + } } diff --git a/Sources/ResgenSwift/Fonts/Model/FontName.swift b/Sources/ResgenSwift/Fonts/Model/FontName.swift index 7667a07..22ac1da 100644 --- a/Sources/ResgenSwift/Fonts/Model/FontName.swift +++ b/Sources/ResgenSwift/Fonts/Model/FontName.swift @@ -29,4 +29,20 @@ extension FontName { } """ } + + var suiMethod: String { + """ + func \(fontNameSanitize)(withSize size: CGFloat) -> Font { + Font.custom(FontName.\(fontNameSanitize).rawValue, size: size) + } + """ + } + + var suiStaticProperty: String { + """ + static let \(fontNameSanitize): ((_ size: CGFloat) -> Font) = { size in + Font.custom(FontName.\(fontNameSanitize).rawValue, size: size) + } + """ + } } diff --git a/Sources/ResgenSwift/Generate/Model/ConfigurationFile.swift b/Sources/ResgenSwift/Generate/Model/ConfigurationFile.swift index 7ba457f..0601b14 100644 --- a/Sources/ResgenSwift/Generate/Model/ConfigurationFile.swift +++ b/Sources/ResgenSwift/Generate/Model/ConfigurationFile.swift @@ -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? @@ -63,6 +64,7 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible { - Xcassets path: \(xcassetsPath) - Extension output path: \(extensionOutputPath) - Extension name: \(extensionName ?? "-") + - Extension name SwiftUI: \(extensionNameSwiftUI ?? "-") - Extension suffix: \(extensionSuffix ?? "-") """ } @@ -72,6 +74,7 @@ struct FontsConfiguration: Codable, CustomDebugStringConvertible { let inputFile: String let extensionOutputPath: String let extensionName: String? + let extensionNameSwiftUI: String? let extensionSuffix: String? private let staticMembers: Bool? @@ -88,6 +91,7 @@ struct FontsConfiguration: Codable, CustomDebugStringConvertible { - Input file: \(inputFile) - Extension output path: \(extensionOutputPath) - Extension name: \(extensionName ?? "-") + - Extension name SwiftUI: \(extensionNameSwiftUI ?? "-") - Extension suffix: \(extensionSuffix ?? "-") """ } diff --git a/Sources/ResgenSwift/Generate/Runnable/ColorsConfiguration+ShellCommandable.swift b/Sources/ResgenSwift/Generate/Runnable/ColorsConfiguration+ShellCommandable.swift index 49639b0..9f810de 100644 --- a/Sources/ResgenSwift/Generate/Runnable/ColorsConfiguration+ShellCommandable.swift +++ b/Sources/ResgenSwift/Generate/Runnable/ColorsConfiguration+ShellCommandable.swift @@ -33,6 +33,12 @@ extension ColorsConfiguration: Runnable { extensionName ] } + if let extensionNameSwiftUI = extensionNameSwiftUI { + args += [ + "--extension-name-swift-ui", + extensionNameSwiftUI + ] + } if let extensionSuffix = extensionSuffix { args += [ "--extension-suffix", diff --git a/Sources/ResgenSwift/Generate/Runnable/FontsConfiguration+ShellCommandable.swift b/Sources/ResgenSwift/Generate/Runnable/FontsConfiguration+ShellCommandable.swift index 4ef8aa2..d39d222 100644 --- a/Sources/ResgenSwift/Generate/Runnable/FontsConfiguration+ShellCommandable.swift +++ b/Sources/ResgenSwift/Generate/Runnable/FontsConfiguration+ShellCommandable.swift @@ -29,6 +29,12 @@ extension FontsConfiguration: Runnable { extensionName ] } + if let extensionNameSwiftUI = extensionNameSwiftUI { + args += [ + "--extension-name-swift-ui", + extensionNameSwiftUI + ] + } if let extensionSuffix = extensionSuffix { args += [