diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ColorToolCore.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ColorToolCore.xcscheme
new file mode 100644
index 0000000..2149977
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/ColorToolCore.xcscheme
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/FontToolCore.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/FontToolCore.xcscheme
new file mode 100644
index 0000000..cb899de
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/FontToolCore.xcscheme
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ResgenSwift-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ResgenSwift-Package.xcscheme
new file mode 100644
index 0000000..b573efc
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/ResgenSwift-Package.xcscheme
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ResgenSwift.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ResgenSwift.xcscheme
new file mode 100644
index 0000000..c25849f
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/ResgenSwift.xcscheme
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Package.swift b/Package.swift
index e0aef1c..14cab04 100644
--- a/Package.swift
+++ b/Package.swift
@@ -14,13 +14,22 @@ let package = Package(
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "ResgenSwift",
- dependencies: ["FontToolCore"]),
+ dependencies: ["FontToolCore", "ColorToolCore"]
+ ),
.target(
name: "FontToolCore",
dependencies: [
"CLIToolCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
- ]),
+ ]
+ ),
+ .target(
+ name: "ColorToolCore",
+ dependencies: [
+ "CLIToolCore",
+ .product(name: "ArgumentParser", package: "swift-argument-parser")
+ ]
+ ),
// Helper targets
.target(name: "CLIToolCore"),
// Test targets
diff --git a/SampleFiles/Colors/Generated/R2Color+Font.swift b/SampleFiles/Colors/Generated/R2Color+Font.swift
new file mode 100644
index 0000000..516ec44
--- /dev/null
+++ b/SampleFiles/Colors/Generated/R2Color+Font.swift
@@ -0,0 +1,21 @@
+// Generated from ColorToolCore at 2021-12-20 15:27:15 +0000
+
+import UIKit
+
+extension R2Color {
+
+ /// Color red is #FF0000 (light) or #FF0000 (dark)"
+ @objc var red: UIColor {
+ UIColor(named: "red")!
+ }
+
+ /// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
+ @objc var green_alpha_50: UIColor {
+ UIColor(named: "green_alpha_50")!
+ }
+
+ /// Color blue_light_dark is #0000FF (light) or #0000FF (dark)"
+ @objc var blue_light_dark: UIColor {
+ UIColor(named: "blue_light_dark")!
+ }
+}
\ No newline at end of file
diff --git a/SampleFiles/Colors/Generated/UIColor+Font.swift b/SampleFiles/Colors/Generated/UIColor+Font.swift
new file mode 100644
index 0000000..76d0ed0
--- /dev/null
+++ b/SampleFiles/Colors/Generated/UIColor+Font.swift
@@ -0,0 +1,21 @@
+// Generated from ColorToolCore at 2021-12-20 15:16:18 +0000
+
+import UIKit
+
+extension UIColor {
+
+ /// Color red is #FF0000 (light) or #FF0000 (dark)"
+ static var red: UIColor {
+ UIColor(named: "red")!
+ }
+
+ /// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
+ static var green_alpha_50: UIColor {
+ UIColor(named: "green_alpha_50")!
+ }
+
+ /// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
+ static var blue_light_dark: UIColor {
+ UIColor(named: "blue_light_dark")!
+ }
+}
\ No newline at end of file
diff --git a/SampleFiles/Colors/Generated/UIColor+FontSampleApp.swift b/SampleFiles/Colors/Generated/UIColor+FontSampleApp.swift
new file mode 100644
index 0000000..473f1c9
--- /dev/null
+++ b/SampleFiles/Colors/Generated/UIColor+FontSampleApp.swift
@@ -0,0 +1,21 @@
+// Generated from ColorToolCore at 2021-12-20 15:17:10 +0000
+
+import UIKit
+
+extension UIColor {
+
+ /// Color red is #FF0000 (light) or #FF0000 (dark)"
+ static var red: UIColor {
+ UIColor(named: "red")!
+ }
+
+ /// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
+ static var green_alpha_50: UIColor {
+ UIColor(named: "green_alpha_50")!
+ }
+
+ /// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
+ static var blue_light_dark: UIColor {
+ UIColor(named: "blue_light_dark")!
+ }
+}
\ No newline at end of file
diff --git a/SampleFiles/Colors/colors.xcassets/Colors/blue_light_dark.colorset/Contents.json b/SampleFiles/Colors/colors.xcassets/Colors/blue_light_dark.colorset/Contents.json
new file mode 100644
index 0000000..830f655
--- /dev/null
+++ b/SampleFiles/Colors/colors.xcassets/Colors/blue_light_dark.colorset/Contents.json
@@ -0,0 +1,38 @@
+{
+ "colors": [
+ {
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "alpha": "0xFF",
+ "blue": "0xFF",
+ "green": "0x00",
+ "red": "0x00",
+ }
+ },
+ "idiom": "universal"
+ },
+ {
+ "appearances": [
+ {
+ "appearance": "luminosity",
+ "value": "dark"
+ }
+ ],
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "alpha": "0xFF",
+ "blue": "0xFF",
+ "green": "0x00",
+ "red": "0x00",
+ }
+ },
+ "idiom": "universal"
+ }
+ ],
+ "info": {
+ "author": "xcode",
+ "version": 1
+ }
+}
\ No newline at end of file
diff --git a/SampleFiles/Colors/colors.xcassets/Colors/green_alpha_50.colorset/Contents.json b/SampleFiles/Colors/colors.xcassets/Colors/green_alpha_50.colorset/Contents.json
new file mode 100644
index 0000000..dcc7598
--- /dev/null
+++ b/SampleFiles/Colors/colors.xcassets/Colors/green_alpha_50.colorset/Contents.json
@@ -0,0 +1,38 @@
+{
+ "colors": [
+ {
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "alpha": "0xA0",
+ "blue": "0x00",
+ "green": "0xFF",
+ "red": "0x00",
+ }
+ },
+ "idiom": "universal"
+ },
+ {
+ "appearances": [
+ {
+ "appearance": "luminosity",
+ "value": "dark"
+ }
+ ],
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "alpha": "0xA0",
+ "blue": "0x00",
+ "green": "0xFF",
+ "red": "0x00",
+ }
+ },
+ "idiom": "universal"
+ }
+ ],
+ "info": {
+ "author": "xcode",
+ "version": 1
+ }
+}
\ No newline at end of file
diff --git a/SampleFiles/Colors/colors.xcassets/Colors/red.colorset/Contents.json b/SampleFiles/Colors/colors.xcassets/Colors/red.colorset/Contents.json
new file mode 100644
index 0000000..7e5dbe2
--- /dev/null
+++ b/SampleFiles/Colors/colors.xcassets/Colors/red.colorset/Contents.json
@@ -0,0 +1,38 @@
+{
+ "colors": [
+ {
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "alpha": "0xFF",
+ "blue": "0x00",
+ "green": "0x00",
+ "red": "0xFF",
+ }
+ },
+ "idiom": "universal"
+ },
+ {
+ "appearances": [
+ {
+ "appearance": "luminosity",
+ "value": "dark"
+ }
+ ],
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "alpha": "0xFF",
+ "blue": "0x00",
+ "green": "0x00",
+ "red": "0xFF",
+ }
+ },
+ "idiom": "universal"
+ }
+ ],
+ "info": {
+ "author": "xcode",
+ "version": 1
+ }
+}
\ No newline at end of file
diff --git a/SampleFiles/Colors/sampleColors1.txt b/SampleFiles/Colors/sampleColors1.txt
new file mode 100644
index 0000000..d5b4260
--- /dev/null
+++ b/SampleFiles/Colors/sampleColors1.txt
@@ -0,0 +1,9 @@
+# Available format:
+# colorName=#RGB/#ARGB
+# colorName #RGB/#ARGB
+# colorName #RGB/#ARGB #RGB/#ARGB
+
+# Comment line and empty line will be ingored
+red = #FF0000
+green_alpha_50 = #A000FF00
+blue_light_dark = #0000FF #0000AA
diff --git a/Sources/CLIToolCore/CLIToolCore.swift b/Sources/CLIToolCore/CLIToolCore.swift
index 66d50f7..ab5f5c3 100644
--- a/Sources/CLIToolCore/CLIToolCore.swift
+++ b/Sources/CLIToolCore/CLIToolCore.swift
@@ -29,3 +29,35 @@ public class Shell {
return (terminationStatus: task.terminationStatus, output: output)
}
}
+
+public class GeneratorChecker {
+
+ /// Return `true` if inputFile is newer than extensionFile, otherwise `false`
+ public static func shouldGenerate(force: Bool, inputFilePath: String, extensionFilePath: String) -> Bool {
+ guard force == false else {
+ return true
+ }
+
+ // If inputFile is newer that generated extension -> Regenerate
+ let extensionFileURL = URL(fileURLWithPath: extensionFilePath)
+ let inputFileURL = URL(fileURLWithPath: inputFilePath)
+
+ let extensionRessourceValues = try? extensionFileURL.resourceValues(forKeys: [URLResourceKey.contentModificationDateKey])
+ let inputFileRessourceValues = try? inputFileURL.resourceValues(forKeys: [URLResourceKey.contentModificationDateKey])
+
+ if let extensionModificationDate = extensionRessourceValues?.contentModificationDate,
+ let inputFileModificationDate = inputFileRessourceValues?.contentModificationDate {
+ if inputFileModificationDate >= extensionModificationDate {
+ print("Input file is newer that generated extension.")
+ return true
+ } else {
+ return false
+ }
+ }
+
+ // ModificationDate not available for both file
+ print("⚠️ Could not compare file modication date. ⚠️")
+ return true
+ }
+
+}
diff --git a/Sources/CLIToolCore/Extensions.swift b/Sources/CLIToolCore/Extensions.swift
new file mode 100644
index 0000000..bbe4a58
--- /dev/null
+++ b/Sources/CLIToolCore/Extensions.swift
@@ -0,0 +1,64 @@
+//
+// Extensions.swift
+//
+//
+// Created by Thibaut Schmitt on 13/12/2021.
+//
+
+import Foundation
+
+// MARK: - String
+
+public extension String {
+ func removeCharacters(from forbiddenChars: CharacterSet) -> String {
+ let passed = self.unicodeScalars.filter { !forbiddenChars.contains($0) }
+ return String(String.UnicodeScalarView(passed))
+ }
+
+ func removeCharacters(from: String) -> String {
+ return removeCharacters(from: CharacterSet(charactersIn: from))
+ }
+
+ func removeTrailingWhitespace() -> String {
+ var newString = self
+
+ while newString.last?.isWhitespace == true {
+ newString = String(newString.dropLast())
+ }
+
+ return newString
+ }
+
+ func colorComponent() -> (alpha: String, red: String, green: String, blue: String) {
+ var alpha: String = "FF"
+ var red: String
+ var green: String
+ var blue: String
+
+ var colorClean = self
+ .replacingOccurrences(of: "#", with: "")
+ .replacingOccurrences(of: "0x", with: "")
+
+ if colorClean.count == 8 {
+ alpha = String(colorClean.prefix(2))
+ colorClean = String(colorClean.dropFirst(2))
+ }
+
+ red = String(colorClean.prefix(2))
+ colorClean = String(colorClean.dropFirst(2))
+ green = String(colorClean.prefix(2))
+ colorClean = String(colorClean.dropFirst(2))
+ blue = String(colorClean.prefix(2))
+ return (alpha: alpha, red: red, green: green, blue: blue)
+ }
+}
+
+// MARK: - Sequence
+
+extension Sequence where Iterator.Element: Hashable {
+ public func unique() -> [Iterator.Element] {
+ var seen: [Iterator.Element: Bool] = [:]
+ return self.filter { seen.updateValue(true, forKey: $0) == nil }
+ }
+}
+
diff --git a/Sources/ColorToolCore/ColorExtensionGenerator.swift b/Sources/ColorToolCore/ColorExtensionGenerator.swift
new file mode 100644
index 0000000..ba2e1c3
--- /dev/null
+++ b/Sources/ColorToolCore/ColorExtensionGenerator.swift
@@ -0,0 +1,41 @@
+//
+// ColorExtensionGenerator.swift
+//
+//
+// Created by Thibaut Schmitt on 20/12/2021.
+//
+
+import Foundation
+
+struct ColorExtensionGenerator {
+
+ let colors: [GenColor]
+ let extensionClassname: String
+ let isUIColorExtension: Bool
+
+ func getHeader() -> String {
+ """
+ // Generated from ColorToolCore at \(Date())
+
+ import UIKit
+
+ extension \(extensionClassname) {\n
+ """
+ }
+
+ func getFooter() -> String {
+ """
+ }
+ """
+ }
+
+ func getProperties() -> String {
+ colors.map {
+ if extensionClassname == ColorTool.defaultExtensionName {
+ return $0.getColorStaticProperty()
+ }
+ return $0.getColorProperty()
+ }
+ .joined(separator: "\n\n")
+ }
+}
diff --git a/Sources/ColorToolCore/ColorToolError.swift b/Sources/ColorToolCore/ColorToolError.swift
new file mode 100644
index 0000000..b5a0f73
--- /dev/null
+++ b/Sources/ColorToolCore/ColorToolError.swift
@@ -0,0 +1,53 @@
+//
+// ColorToolError.swift
+//
+//
+// Created by Thibaut Schmitt on 20/12/2021.
+//
+
+import Foundation
+
+enum ColorToolError: Error {
+ case badFormat(String)
+ case writeAsset(String)
+ case writeExtension(String, String)
+ case fileNotExists(String)
+ case badColorDefinition(String, String)
+
+ var description: String {
+ switch self {
+ case .badFormat(let info):
+ return """
+ [ColorTool]
+ Bad line format: \(info). Accepted format are:
+ - colorName="#RGB/#ARGB"
+ - colorName "#RGB/#ARGB"
+ - colorName "#RGB/#ARGB" "#RGB/#ARGB"
+ """
+
+ case .writeAsset(let info):
+ return """
+ [ColorTool]
+ An error occured while writing color in Xcasset: \(info)
+ """
+
+ case .writeExtension(let filename, let info):
+ return """
+ [ColorTool]
+ An error occured while writing extension in \(filename): \(info)
+ """
+
+ case .fileNotExists(let filename):
+ return """
+ [ColorTool]
+ File \(filename) does not exists
+ """
+
+ case .badColorDefinition(let lightColor, let darkColor):
+ return """
+ [ColorTool]
+ One of these two colors has invalid synthax: -\(lightColor)- or -\(darkColor)-
+ """
+ }
+ }
+}
diff --git a/Sources/ColorToolCore/ColorXcassetHelper.swift b/Sources/ColorToolCore/ColorXcassetHelper.swift
new file mode 100644
index 0000000..d909e65
--- /dev/null
+++ b/Sources/ColorToolCore/ColorXcassetHelper.swift
@@ -0,0 +1,40 @@
+//
+// ColorXcassetHelper.swift
+//
+//
+// Created by Thibaut Schmitt on 20/12/2021.
+//
+
+import Foundation
+import CLIToolCore
+
+struct ColorXcassetHelper {
+
+ let xcassetsPath: String
+ let colors: [GenColor]
+
+ func generateXcassetColors() {
+ colors.forEach {
+ generateColorSetAssets(from: $0)
+ }
+ }
+
+ // Generate ColorSet in XCAssets file
+ private func generateColorSetAssets(from color: GenColor) {
+ // Create ColorSet
+ let colorSetPath = "\(xcassetsPath)/Colors/\(color.name).colorset"
+ Shell.shell("mkdir", "-p", "\(colorSetPath)")
+
+ // Create Contents.json in ColorSet
+ let contentsJsonPath = "\(colorSetPath)/Contents.json"
+ Shell.shell("touch", "\(contentsJsonPath)")
+
+ // Write content in Contents.json
+ let contentsJsonPathURL = URL(fileURLWithPath: contentsJsonPath)
+ do {
+ try color.contentsJSON().write(to: contentsJsonPathURL, atomically: true, encoding: .utf8)
+ } catch (let error) {
+ ColorTool.exit(withError: ColorToolError.writeAsset(error.localizedDescription))
+ }
+ }
+}
diff --git a/Sources/ColorToolCore/GenColor.swift b/Sources/ColorToolCore/GenColor.swift
new file mode 100644
index 0000000..10526f3
--- /dev/null
+++ b/Sources/ColorToolCore/GenColor.swift
@@ -0,0 +1,90 @@
+//
+// GenColor.swift
+//
+//
+// Created by Thibaut Schmitt on 20/12/2021.
+//
+
+import Foundation
+
+struct GenColor {
+ let name: String
+ let light: String
+ let dark: String
+
+ // Generate Contents.json content
+ func contentsJSON() -> String {
+ let lightARGB = light.colorComponent()
+ let darkARGB = dark.colorComponent()
+
+ let allComponents = [
+ lightARGB.alpha, lightARGB.red, lightARGB.green, lightARGB.blue,
+ darkARGB.alpha, darkARGB.red, darkARGB.green, darkARGB.blue
+ ].map {
+ $0.isEmpty
+ }
+
+ guard allComponents.contains(true) == false else {
+ ColorTool.exit(withError: ColorToolError.badColorDefinition(light, dark))
+ }
+
+ return """
+ {
+ "colors": [
+ {
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "alpha": "0x\(lightARGB.alpha)",
+ "blue": "0x\(lightARGB.blue)",
+ "green": "0x\(lightARGB.green)",
+ "red": "0x\(lightARGB.red)",
+ }
+ },
+ "idiom": "universal"
+ },
+ {
+ "appearances": [
+ {
+ "appearance": "luminosity",
+ "value": "dark"
+ }
+ ],
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "alpha": "0x\(darkARGB.alpha)",
+ "blue": "0x\(darkARGB.blue)",
+ "green": "0x\(darkARGB.green)",
+ "red": "0x\(darkARGB.red)",
+ }
+ },
+ "idiom": "universal"
+ }
+ ],
+ "info": {
+ "author": "xcode",
+ "version": 1
+ }
+ }
+ """
+ }
+
+ func getColorProperty() -> String {
+ """
+ /// 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 {
+ UIColor(named: "\(name)")!
+ }
+ """
+ }
+}
diff --git a/Sources/ColorToolCore/main.swift b/Sources/ColorToolCore/main.swift
new file mode 100644
index 0000000..624b3e6
--- /dev/null
+++ b/Sources/ColorToolCore/main.swift
@@ -0,0 +1,165 @@
+//
+// main.swift
+//
+//
+// Created by Thibaut Schmitt on 20/12/2021.
+//
+
+import Foundation
+import CLIToolCore
+import ArgumentParser
+
+enum ColorStyle: String, Decodable {
+ case light
+ case all
+}
+
+struct ColorTool: ParsableCommand {
+ static let defaultExtensionName = "UIColor"
+ static let assetsColorsFolderName = "Colors"
+
+ @Flag(name: .customShort("f"), help: "Should force generation")
+ var forceGeneration = false
+
+ @Argument(help: "Input files where colors ared defined.")
+ var inputFile: String
+
+ @Option(help: "Color style to generate: light for light colors only, or all for dark and light colors")
+ var style: String
+
+ @Option(help: "Path of xcassets where to generate colors")
+ var xcassetsPath: String
+
+ @Option(help: "Path where to generate the extension.")
+ var extensionOutputPath: String
+
+ @Option(help: "Extension name. If not specified, it will generate an UIFont extension")
+ var extensionName: String = Self.defaultExtensionName
+
+ @Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift")
+ var extensionSuffix: String = ""
+
+ var colorStyle: ColorStyle { ColorStyle(rawValue: style) ?? .all }
+ var extensionFileName: String { "\(extensionName)+Font\(extensionSuffix).swift" }
+ var extensionFilePath: String { "\(extensionOutputPath)/\(extensionFileName)" }
+
+ public func run() throws {
+ print("[ColorTool] Starting colors generation")
+
+ print("[ColorTool] Will use inputFile \(inputFile) to generate \(colorStyle) colors in xcassets \(xcassetsPath)")
+ print("[ColorTool] Extension will be \(extensionFilePath)")
+
+
+ // Check if needed to regenerate
+ guard GeneratorChecker.shouldGenerate(force: forceGeneration, inputFilePath: inputFile, extensionFilePath: extensionFilePath) else {
+ print("[ColorTool] Colors are already up to date :) ")
+ return
+ }
+ print("[ColorTool] Will generate colors")
+
+ // Check if Xcasset exists
+ let fileManager = FileManager()
+ guard fileManager.fileExists(atPath: xcassetsPath) else {
+ ColorTool.exit(withError: ColorToolError.fileNotExists(xcassetsPath))
+ }
+
+ // Delete current colors
+ Shell.shell("rm", "-rf", "\(xcassetsPath)/Colors/*")
+
+ // Get colors
+ let colorsToGen = getColorsGen()
+
+ // Generate all colors in xcassets
+ let colorAssetHelper = ColorXcassetHelper(xcassetsPath: xcassetsPath, colors: colorsToGen)
+ colorAssetHelper.generateXcassetColors()
+
+ // Generate extension
+ let extensionGenerator = ColorExtensionGenerator(colors: colorsToGen,
+ extensionClassname: extensionName,
+ isUIColorExtension: isUIColorExtension())
+ let extensionHeader = extensionGenerator.getHeader()
+ let extensionProperties = extensionGenerator.getProperties()
+ let extensionFooter = extensionGenerator.getFooter()
+
+ generateExtensionFile(extensionHeader, extensionProperties, extensionFooter)
+
+ print("[ColorTool] Colors generated")
+ }
+
+ private func generateExtensionFile(_ args: String...) {
+ // Create file if not exists
+ let fileManager = FileManager()
+ if fileManager.fileExists(atPath: extensionFilePath) == false {
+ Shell.shell("touch", "\(extensionFilePath)")
+ }
+
+ // Create extension content
+ let extensionContent = args.joined(separator: "\n")
+
+ // Write content
+ let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
+ do {
+ try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8)
+ } catch (let error) {
+ ColorTool.exit(withError: ColorToolError.writeExtension(extensionFilePath, error.localizedDescription))
+ }
+ }
+
+ private func getColorsGen() -> [GenColor] {
+ // Get content of input file
+ let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8)
+ let colorsByLines = inputFileContent.components(separatedBy: .newlines)
+
+ // Iterate on each line of input file
+ return colorsByLines.enumerated().compactMap { lineNumber, colorLine in
+ // Required format:
+ // colorName="#RGB/#ARGB", colorName "#RGB/#ARGB", colorName "#RGB/#ARGB" "#RGB/#ARGB"
+ let colorLineCleanedUp = colorLine
+ .removeTrailingWhitespace()
+ .replacingOccurrences(of: "=", with: "") // Keep compat with current file format
+
+ guard colorLineCleanedUp.hasPrefix("#") == false, colorLineCleanedUp.isEmpty == false else {
+ print("[ColorTool] ⚠️ BadFormat or empty line (line number: \(lineNumber + 1)). Skip this line")
+ return nil
+ }
+
+ let colorContent = colorLineCleanedUp.split(separator: " ")
+
+ guard colorContent.count >= 2 else {
+ ColorTool.exit(withError: ColorToolError.badFormat(colorLine))
+ }
+
+ switch colorStyle {
+ case .light:
+ return GenColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[1]))
+
+ case .all:
+ if colorContent.count == 3 {
+ return GenColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[2]))
+ }
+ return GenColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[1]))
+ }
+ }
+ }
+
+ // MARK: - Helpers
+
+ private func isUIColorExtension() -> Bool {
+ extensionName == Self.defaultExtensionName
+ }
+}
+
+ColorTool.main()
+
+/*
+ Command samples:
+
+ 1. UIColor extension without suffix
+ swift run -c release ColorToolCore -f ./SampleFiles/Colors/sampleColors1.txt --style all --xcassets-path "./SampleFiles/Colors/colors.xcassets" --extension-output-path "./SampleFiles/Colors/Generated/" --extension-name "UIColor"
+
+ 2. UIColor extension with custom suffix
+ swift run -c release ColorToolCore -f ./SampleFiles/Colors/sampleColors1.txt --style all --xcassets-path "./SampleFiles/Colors/colors.xcassets" --extension-output-path "./SampleFiles/Colors/Generated/" --extension-name "UIColor" --extension-suffix "SampleApp"
+
+ 3. Custom extension with only light theme colors (R2Color)
+ swift run -c release ColorToolCore -f ./SampleFiles/Colors/sampleColors1.txt --style light --xcassets-path "./SampleFiles/Colors/colors.xcassets" --extension-output-path "./SampleFiles/Colors/Generated/" --extension-name "R2Color"
+ */
diff --git a/Sources/FontToolCore/Extensions.swift b/Sources/FontToolCore/Extensions.swift
deleted file mode 100644
index 88e3713..0000000
--- a/Sources/FontToolCore/Extensions.swift
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// File.swift
-//
-//
-// Created by Thibaut Schmitt on 13/12/2021.
-//
-
-import Foundation
-
-extension String {
- func removeCharacters(from forbiddenChars: CharacterSet) -> String {
- let passed = self.unicodeScalars.filter { !forbiddenChars.contains($0) }
- return String(String.UnicodeScalarView(passed))
- }
-
- func removeCharacters(from: String) -> String {
- return removeCharacters(from: CharacterSet(charactersIn: from))
- }
-}
-
-extension Sequence where Iterator.Element: Hashable {
- func unique() -> [Iterator.Element] {
- var seen: [Iterator.Element: Bool] = [:]
- return self.filter { seen.updateValue(true, forKey: $0) == nil }
- }
-}
diff --git a/Sources/FontToolCore/FontToolError.swift b/Sources/FontToolCore/FontToolError.swift
index c3a0860..9967f29 100644
--- a/Sources/FontToolCore/FontToolError.swift
+++ b/Sources/FontToolCore/FontToolError.swift
@@ -16,12 +16,16 @@ enum FontToolError: Error {
switch self {
case .fcScan(let path, let code, let output):
return """
+ [FontTool]
Error while getting fontName (fc-scan --format %{postscriptname} \(path).
fc-scan exit with \(code) and output is: \(output ?? "no output")
"""
case .inputFolderNotFound(let inputFolder):
- return "Input folder not found: \(inputFolder)"
+ return """
+ [ColorTool]
+ Input folder not found: \(inputFolder)
+ """
}
}
}
diff --git a/Sources/FontToolCore/main.swift b/Sources/FontToolCore/main.swift
index a1a5fb2..eedaf85 100644
--- a/Sources/FontToolCore/main.swift
+++ b/Sources/FontToolCore/main.swift
@@ -9,6 +9,11 @@ import Foundation
import CLIToolCore
import ArgumentParser
+/*
+ Lire l'infoPlist et check si les fonts dedans sont les memes que celles à générer
+ */
+
+//swift run -c release FontToolCore ./SampleFiles/Fonts --extension-output-path ~/Desktop --extension-name R2Font
struct FontTool: ParsableCommand {
static let defaultExtensionName = "UIFont"
@@ -22,7 +27,7 @@ struct FontTool: ParsableCommand {
var extensionName: String = Self.defaultExtensionName
public func run() throws {
- print("[FontTool] Starting font generation")
+ print("[FontTool] Starting fonts generation")
let fontsData = FontToolHelper.getFontsData(fromInputFolder: inputFolder)
@@ -41,7 +46,7 @@ struct FontTool: ParsableCommand {
print("Info.plist information:")
print("\(generatePlistUIAppFonts(fontsNames: fontsData.fontsNames))")
- print("[FontTool] Font generated")
+ print("[FontTool] Fonts generated")
}
private func generateExtensionFile(_ args: String...) {