Skip to content

Instantly share code, notes, and snippets.

@lukas1
Last active October 17, 2022 05:44
Show Gist options
  • Save lukas1/867f9300b457a4d2bd45283d24a1d6b1 to your computer and use it in GitHub Desktop.
Save lukas1/867f9300b457a4d2bd45283d24a1d6b1 to your computer and use it in GitHub Desktop.
A swift script that generates Color Assets and a Swift file containing enum of colors based on input json

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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment