Call the script like this:
./palette-generator.swift example-input.json
It will create a folder Colors
in the folder where this script is executed, containing output.
{ | |
"paletteColors": { | |
"blue": "#0000FF", | |
"red": "#FF0000" | |
}, | |
"projectColorReferences": { | |
"title": "blue", | |
"subtitle": "red" | |
} | |
} |
#!/usr/bin/swift | |
import Foundation | |
struct PaletteInput: Decodable, Encodable { | |
let paletteColors: [String: String] | |
let projectColorReferences: [String: String] | |
} | |
func hexStringToUInt32(_ hex: String) -> UInt32 { | |
var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() | |
if (cString.hasPrefix("#")) { | |
cString.remove(at: cString.startIndex) | |
} | |
if ((cString.count) != 6) { | |
return 0 | |
} | |
var rgbValue:UInt32 = 0 | |
Scanner(string: cString).scanHexInt32(&rgbValue) | |
return rgbValue | |
} | |
func redFromHex(_ hexColor: String) -> CGFloat { | |
return CGFloat((hexStringToUInt32(hexColor) & 0xFF0000) >> 16) / 255.0 | |
} | |
func greenFromHex(_ hexColor: String) -> CGFloat { | |
return CGFloat((hexStringToUInt32(hexColor) & 0x00FF00) >> 8) / 255.0 | |
} | |
func blueFromHex(_ hexColor: String) -> CGFloat { | |
return CGFloat(hexStringToUInt32(hexColor) & 0x0000FF) / 255.0 | |
} | |
func createColorAssetJson(hexColor: String) -> String { | |
return """ | |
{ | |
"info" : { | |
"version" : 1, | |
"author" : "xcode" | |
}, | |
"colors" : [ | |
{ | |
"idiom" : "universal", | |
"color" : { | |
"color-space" : "srgb", | |
"components" : { | |
"red" : "\(redFromHex(hexColor))", | |
"alpha" : "1.0", | |
"blue" : "\(blueFromHex(hexColor))", | |
"green" : "\(greenFromHex(hexColor))" | |
} | |
} | |
} | |
] | |
} | |
""" | |
} | |
func createPaletteEnum(paletteColors: [String: String]) -> String { | |
let colorLines = paletteColors.map { arg -> (String) in | |
let (name, hex) = arg | |
return "\t\tstatic let \(name): UIColor = UIColor(red: \(redFromHex(hex)), green: \(greenFromHex(hex)), blue: \(blueFromHex(hex)), alpha: 1.0)" | |
}.joined(separator: "\n") | |
return """ | |
\tenum Palette { | |
\(colorLines) | |
\t} | |
""" | |
} | |
func createColorsEnum(paletteInput: PaletteInput) -> String { | |
let colorLines = paletteInput.projectColorReferences.map { arg -> (String) in | |
let (name, paletteRef) = arg | |
return "\tstatic let \(name): UIColor = Palette.\(paletteRef)" | |
}.joined(separator: "\n") | |
return """ | |
import UIKit | |
enum Colors { | |
\(createPaletteEnum(paletteColors: paletteInput.paletteColors)) | |
\(colorLines) | |
} | |
""" | |
} | |
func printHelp() { | |
print("Script should be called like this: ./palette-generator path-to-palette-file") | |
} | |
func exitWithMessage(_ message: String = "") -> Never { | |
print(message) | |
printHelp() | |
return exit(1) | |
} | |
if CommandLine.arguments.count < 2 { | |
exitWithMessage() | |
} | |
let paletteFilePath = CommandLine.arguments[1] | |
guard let paletteData = FileManager.default.contents(atPath: paletteFilePath) | |
else { | |
exitWithMessage("File at path '\(paletteFilePath)' not found") | |
} | |
guard let paletteInput = try? JSONDecoder().decode(PaletteInput.self, from: paletteData) | |
else { | |
exitWithMessage("Palette Input has wrong format") | |
} | |
// Color Asset Files | |
let paletteColors = paletteInput.paletteColors.map { arg -> (String, String) in | |
let (name, hexColor) = arg | |
return (name.capitalized(with: nil), createColorAssetJson(hexColor: hexColor)) | |
} | |
let projectColors = paletteInput.projectColorReferences.map { arg -> (String, String) in | |
let (name, paletteRef) = arg | |
let hexColor = paletteInput.paletteColors[paletteRef] | |
return (name.capitalized(with: nil), createColorAssetJson(hexColor: hexColor!)) | |
} | |
var hadError = false | |
let colorsDir = "./Colors" | |
(paletteColors + projectColors).forEach { (name, json) in | |
do { | |
let colorDir = colorsDir + "/\(name).colorset" | |
try FileManager.default.createDirectory( | |
atPath: colorDir, withIntermediateDirectories: true, attributes: nil | |
) | |
FileManager.default.createFile( | |
atPath: "\(colorDir)/Contents.json", | |
contents: json.data(using: .utf8), | |
attributes: nil | |
) | |
} catch { | |
print(error.localizedDescription) | |
hadError = true | |
} | |
} | |
if hadError { | |
print("Some colors were not created") | |
exit(1) | |
} | |
FileManager.default.createFile( | |
atPath: "\(colorsDir)/Colors.swift", | |
contents: createColorsEnum(paletteInput: paletteInput).data(using: .utf8), | |
attributes: nil | |
) | |
print("SUCCESS!") | |
exit(0) |