feat(RES-34): Fix plist font filename (#14)
All checks were successful
gitea-openium/resgen.swift/pipeline/head This commit looks good
All checks were successful
gitea-openium/resgen.swift/pipeline/head This commit looks good
Reviewed-on: #14
This commit is contained in:
@ -1,124 +1,134 @@
|
||||
//
|
||||
// main.swift
|
||||
//
|
||||
//
|
||||
//
|
||||
// Created by Thibaut Schmitt on 20/12/2021.
|
||||
//
|
||||
|
||||
import ToolCore
|
||||
@preconcurrency import ArgumentParser
|
||||
import Foundation
|
||||
import ArgumentParser
|
||||
import ToolCore
|
||||
|
||||
struct Colors: ParsableCommand {
|
||||
|
||||
|
||||
// MARK: - CommandConfiguration
|
||||
|
||||
static var configuration = CommandConfiguration(
|
||||
|
||||
static let configuration = CommandConfiguration(
|
||||
abstract: "A utility for generate colors assets and their getters.",
|
||||
version: ResgenSwiftVersion
|
||||
)
|
||||
|
||||
|
||||
// MARK: - Static
|
||||
|
||||
|
||||
static let toolName = "Color"
|
||||
static let defaultExtensionName = "Color"
|
||||
static let defaultExtensionNameUIKit = "UIColor"
|
||||
static let assetsColorsFolderName = "Colors"
|
||||
|
||||
|
||||
// MARK: - Command options
|
||||
|
||||
|
||||
@OptionGroup var options: ColorsToolOptions
|
||||
|
||||
|
||||
// MARK: - Run
|
||||
|
||||
public func run() throws {
|
||||
|
||||
func run() throws {
|
||||
print("[\(Self.toolName)] Starting colors generation")
|
||||
|
||||
|
||||
// Check requirements
|
||||
guard checkRequirements() else { return }
|
||||
|
||||
|
||||
print("[\(Self.toolName)] Will generate colors")
|
||||
|
||||
|
||||
// Delete current colors
|
||||
deleteCurrentColors()
|
||||
|
||||
// Get colors to generate
|
||||
let parsedColors = ColorFileParser.parse(options.inputFile,
|
||||
colorStyle: options.style)
|
||||
let parsedColors = ColorFileParser.parse(
|
||||
options.inputFile,
|
||||
colorStyle: options.style
|
||||
)
|
||||
// -> Time: 0.0020350217819213867 seconds
|
||||
|
||||
// Generate all colors in xcassets
|
||||
ColorXcassetHelper.generateXcassetColors(colors: parsedColors,
|
||||
to: options.xcassetsPath)
|
||||
ColorXcassetHelper.generateXcassetColors(
|
||||
colors: parsedColors,
|
||||
to: options.xcassetsPath
|
||||
)
|
||||
// -> Time: 3.4505380392074585 seconds
|
||||
|
||||
// Generate extension
|
||||
ColorExtensionGenerator.writeExtensionFile(colors: parsedColors,
|
||||
staticVar: options.staticMembers,
|
||||
extensionName: options.extensionName,
|
||||
extensionFilePath: options.extensionFilePath,
|
||||
isSwiftUI: true)
|
||||
|
||||
ColorExtensionGenerator.writeExtensionFile(
|
||||
colors: parsedColors,
|
||||
staticVar: options.staticMembers,
|
||||
extensionName: options.extensionName,
|
||||
extensionFilePath: options.extensionFilePath,
|
||||
isSwiftUI: true
|
||||
)
|
||||
|
||||
// Generate extension
|
||||
ColorExtensionGenerator.writeExtensionFile(colors: parsedColors,
|
||||
staticVar: options.staticMembers,
|
||||
extensionName: options.extensionNameUIKit,
|
||||
extensionFilePath: options.extensionFilePathUIKit,
|
||||
isSwiftUI: false)
|
||||
|
||||
ColorExtensionGenerator.writeExtensionFile(
|
||||
colors: parsedColors,
|
||||
staticVar: options.staticMembers,
|
||||
extensionName: options.extensionNameUIKit,
|
||||
extensionFilePath: options.extensionFilePathUIKit,
|
||||
isSwiftUI: false
|
||||
)
|
||||
|
||||
print("[\(Self.toolName)] Colors generated")
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Requirements
|
||||
|
||||
|
||||
private func checkRequirements() -> Bool {
|
||||
let fileManager = FileManager()
|
||||
|
||||
|
||||
// Check if input file exists
|
||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
||||
let error = ColorsToolError.fileNotExists(options.inputFile)
|
||||
print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
Self.exit(withError: error)
|
||||
}
|
||||
|
||||
|
||||
// Check if xcassets file exists
|
||||
guard fileManager.fileExists(atPath: options.xcassetsPath) else {
|
||||
let error = ColorsToolError.fileNotExists(options.xcassetsPath)
|
||||
print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
Self.exit(withError: error)
|
||||
}
|
||||
|
||||
|
||||
// Extension for UIKit and SwiftUI should have different name
|
||||
guard options.extensionName != options.extensionNameUIKit else {
|
||||
let error = ColorsToolError.extensionNamesCollision(options.extensionName)
|
||||
print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
Self.exit(withError: error)
|
||||
}
|
||||
|
||||
|
||||
// Check if needed to regenerate
|
||||
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
|
||||
inputFilePath: options.inputFile,
|
||||
extensionFilePath: options.extensionFilePath) else {
|
||||
guard GeneratorChecker.shouldGenerate(
|
||||
force: options.forceGeneration,
|
||||
inputFilePath: options.inputFile,
|
||||
extensionFilePath: options.extensionFilePath
|
||||
) else {
|
||||
print("[\(Self.toolName)] Colors are already up to date :) ")
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
|
||||
private func deleteCurrentColors() {
|
||||
let fileManager = FileManager()
|
||||
let assetsColorPath = "\(options.xcassetsPath)/Colors"
|
||||
|
||||
|
||||
if fileManager.fileExists(atPath: assetsColorPath) {
|
||||
do {
|
||||
try fileManager.removeItem(atPath: assetsColorPath)
|
||||
} catch {
|
||||
let error = ColorsToolError.deleteExistingColors("\(options.xcassetsPath)/Colors")
|
||||
print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
Self.exit(withError: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
import Foundation
|
||||
|
||||
enum ColorsToolError: Error {
|
||||
|
||||
case extensionNamesCollision(String)
|
||||
case badFormat(String)
|
||||
case writeAsset(String)
|
||||
@ -16,30 +17,30 @@ enum ColorsToolError: Error {
|
||||
case fileNotExists(String)
|
||||
case badColorDefinition(String, String)
|
||||
case deleteExistingColors(String)
|
||||
|
||||
|
||||
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\""
|
||||
|
||||
|
||||
case .writeAsset(let info):
|
||||
return "error: [\(Colors.toolName)] An error occured while writing color in Xcasset: \(info)"
|
||||
|
||||
|
||||
case .createAssetFolder(let assetsFolder):
|
||||
return "error: [\(Colors.toolName)] An error occured while creating colors folder `\(assetsFolder)`"
|
||||
|
||||
case .writeExtension(let filename, let info):
|
||||
|
||||
case let .writeExtension(filename, info):
|
||||
return "error: [\(Colors.toolName)] An error occured while writing extension in \(filename): \(info)"
|
||||
|
||||
|
||||
case .fileNotExists(let filename):
|
||||
return "error: [\(Colors.toolName)] File \(filename) does not exists"
|
||||
|
||||
case .badColorDefinition(let lightColor, let darkColor):
|
||||
|
||||
case let .badColorDefinition(lightColor, darkColor):
|
||||
return "error: [\(Colors.toolName)] One of these two colors has invalid synthax: -\(lightColor)- or -\(darkColor)-"
|
||||
|
||||
|
||||
case .deleteExistingColors(let assetsFolder):
|
||||
return "error: [\(Colors.toolName)] An error occured while deleting colors folder `\(assetsFolder)`"
|
||||
}
|
||||
|
@ -1,38 +1,41 @@
|
||||
//
|
||||
// ColorsToolOptions.swift
|
||||
//
|
||||
//
|
||||
//
|
||||
// Created by Thibaut Schmitt on 17/01/2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ArgumentParser
|
||||
import Foundation
|
||||
|
||||
// swiftlint:disable no_grouping_extension
|
||||
|
||||
struct ColorsToolOptions: ParsableArguments {
|
||||
|
||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||
var forceGeneration = false
|
||||
|
||||
|
||||
@Argument(help: "Input files where colors ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||
var inputFile: String
|
||||
|
||||
|
||||
@Option(help: "Color style to generate: light for light colors only, or all for dark and light colors")
|
||||
var style: ColorStyle
|
||||
|
||||
|
||||
@Option(help: "Path of xcassets where to generate colors", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||
var xcassetsPath: String
|
||||
|
||||
|
||||
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||
var extensionOutputPath: String
|
||||
|
||||
|
||||
@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 Color extension.")
|
||||
var extensionName: String = Colors.defaultExtensionName
|
||||
|
||||
|
||||
@Option(help: "SwiftUI Extension name. If not specified, it will generate an UIColor extension.")
|
||||
var extensionNameUIKit: String = Colors.defaultExtensionNameUIKit
|
||||
|
||||
|
||||
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift")
|
||||
var extensionSuffix: String?
|
||||
}
|
||||
@ -40,29 +43,29 @@ struct ColorsToolOptions: ParsableArguments {
|
||||
// MARK: - Computed var
|
||||
|
||||
extension ColorsToolOptions {
|
||||
|
||||
|
||||
// MARK: - SwiftUI
|
||||
|
||||
|
||||
var extensionFileName: String {
|
||||
if let extensionSuffix = extensionSuffix {
|
||||
if let extensionSuffix {
|
||||
return "\(extensionName)+\(extensionSuffix).swift"
|
||||
}
|
||||
return "\(extensionName).swift"
|
||||
}
|
||||
|
||||
|
||||
var extensionFilePath: String {
|
||||
"\(extensionOutputPath)/\(extensionFileName)"
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UIKit
|
||||
|
||||
|
||||
var extensionFileNameUIKit: String {
|
||||
if let extensionSuffix = extensionSuffix {
|
||||
if let extensionSuffix {
|
||||
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
||||
}
|
||||
return "\(extensionNameUIKit).swift"
|
||||
}
|
||||
|
||||
|
||||
var extensionFilePathUIKit: String {
|
||||
"\(extensionOutputPath)/\(extensionFileNameUIKit)"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
//
|
||||
// ColorExtensionGenerator.swift
|
||||
//
|
||||
//
|
||||
//
|
||||
// Created by Thibaut Schmitt on 20/12/2021.
|
||||
//
|
||||
@ -9,38 +9,44 @@ import Foundation
|
||||
import ToolCore
|
||||
|
||||
struct ColorExtensionGenerator {
|
||||
|
||||
|
||||
let colors: [ParsedColor]
|
||||
let extensionClassname: String
|
||||
|
||||
|
||||
// MARK: - UIKit
|
||||
|
||||
static func writeExtensionFile(colors: [ParsedColor],
|
||||
staticVar: Bool,
|
||||
extensionName: String,
|
||||
extensionFilePath: String,
|
||||
isSwiftUI: Bool) {
|
||||
|
||||
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,
|
||||
isSwiftUI: isSwiftUI)
|
||||
|
||||
let extensionContent = Self.getExtensionContent(
|
||||
colors: colors,
|
||||
staticVar: staticVar,
|
||||
extensionName: extensionName,
|
||||
isSwiftUI: isSwiftUI
|
||||
)
|
||||
|
||||
// Write content
|
||||
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
||||
do {
|
||||
try extensionContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||
} catch let error {
|
||||
} catch {
|
||||
let error = ColorsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
||||
print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
}
|
||||
}
|
||||
|
||||
static func getExtensionContent(colors: [ParsedColor],
|
||||
staticVar: Bool,
|
||||
extensionName: String,
|
||||
isSwiftUI: Bool) -> String {
|
||||
|
||||
static func getExtensionContent(
|
||||
colors: [ParsedColor],
|
||||
staticVar: Bool,
|
||||
extensionName: String,
|
||||
isSwiftUI: Bool
|
||||
) -> String {
|
||||
[
|
||||
Self.getHeader(extensionClassname: extensionName, isSwiftUI: isSwiftUI),
|
||||
Self.getProperties(for: colors, withStaticVar: staticVar, isSwiftUI: isSwiftUI),
|
||||
@ -48,7 +54,7 @@ struct ColorExtensionGenerator {
|
||||
]
|
||||
.joined(separator: "\n")
|
||||
}
|
||||
|
||||
|
||||
private static func getHeader(extensionClassname: String, isSwiftUI: Bool) -> String {
|
||||
"""
|
||||
// Generated by ResgenSwift.\(Colors.toolName) \(ResgenSwiftVersion)
|
||||
@ -58,17 +64,19 @@ struct ColorExtensionGenerator {
|
||||
extension \(extensionClassname) {\n
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
private static func getFooter() -> String {
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
}
|
||||
|
||||
private static func getProperties(for colors: [ParsedColor],
|
||||
withStaticVar staticVar: Bool,
|
||||
isSwiftUI: Bool) -> String {
|
||||
|
||||
private static func getProperties(
|
||||
for colors: [ParsedColor],
|
||||
withStaticVar staticVar: Bool,
|
||||
isSwiftUI: Bool
|
||||
) -> String {
|
||||
colors.map {
|
||||
$0.getColorProperty(isStatic: staticVar, isSwiftUI: isSwiftUI)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
//
|
||||
// ColorXcassetHelper.swift
|
||||
//
|
||||
//
|
||||
//
|
||||
// Created by Thibaut Schmitt on 20/12/2021.
|
||||
//
|
||||
@ -8,37 +8,39 @@
|
||||
import Foundation
|
||||
import ToolCore
|
||||
|
||||
struct ColorXcassetHelper {
|
||||
|
||||
enum ColorXcassetHelper {
|
||||
|
||||
static func generateXcassetColors(colors: [ParsedColor], to xcassetsPath: String) {
|
||||
colors.forEach {
|
||||
Self.generateColorSetAssets(from: $0, to: xcassetsPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Generate ColorSet in XCAssets file
|
||||
private static func generateColorSetAssets(from color: ParsedColor, to xcassetsPath: String) {
|
||||
// Create ColorSet
|
||||
let colorSetPath = "\(xcassetsPath)/Colors/\(color.name).colorset"
|
||||
let contentsJsonPath = "\(colorSetPath)/Contents.json"
|
||||
|
||||
|
||||
let fileManager = FileManager()
|
||||
if fileManager.fileExists(atPath: colorSetPath) == false {
|
||||
do {
|
||||
try fileManager.createDirectory(atPath: colorSetPath,
|
||||
withIntermediateDirectories: true)
|
||||
try fileManager.createDirectory(
|
||||
atPath: colorSetPath,
|
||||
withIntermediateDirectories: true
|
||||
)
|
||||
} catch {
|
||||
let error = ColorsToolError.createAssetFolder(colorSetPath)
|
||||
print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write content in Contents.json
|
||||
let contentsJsonPathURL = URL(fileURLWithPath: contentsJsonPath)
|
||||
do {
|
||||
try color.contentsJSON().write(to: contentsJsonPathURL, atomically: false, encoding: .utf8)
|
||||
} catch let error {
|
||||
} catch {
|
||||
let error = ColorsToolError.writeAsset(error.localizedDescription)
|
||||
print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
|
@ -5,13 +5,14 @@
|
||||
// Created by Thibaut Schmitt on 29/08/2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ArgumentParser
|
||||
import Foundation
|
||||
|
||||
enum ColorStyle: String, Decodable, ExpressibleByArgument {
|
||||
|
||||
case light
|
||||
case all
|
||||
|
||||
|
||||
static var allValueStrings: [String] {
|
||||
[
|
||||
Self.light.rawValue,
|
||||
|
@ -8,28 +8,29 @@
|
||||
import Foundation
|
||||
|
||||
struct ParsedColor {
|
||||
|
||||
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 {
|
||||
let error = ColorsToolError.badColorDefinition(light, dark)
|
||||
print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
}
|
||||
|
||||
|
||||
return """
|
||||
{
|
||||
"colors": [
|
||||
@ -71,9 +72,9 @@ struct ParsedColor {
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UIKit
|
||||
|
||||
|
||||
func getColorProperty(isStatic: Bool, isSwiftUI: Bool) -> String {
|
||||
if isSwiftUI {
|
||||
return """
|
||||
|
@ -7,44 +7,45 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class ColorFileParser {
|
||||
enum ColorFileParser {
|
||||
|
||||
static func parse(_ inputFile: String, colorStyle: ColorStyle) -> [ParsedColor] {
|
||||
// Get content of input file
|
||||
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8)
|
||||
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8) // swiftlint:disable:this force_try
|
||||
let colorsByLines = inputFileContent.components(separatedBy: CharacterSet.newlines)
|
||||
|
||||
|
||||
// Iterate on each line of input file
|
||||
return parseLines(lines: colorsByLines, colorStyle: colorStyle)
|
||||
}
|
||||
|
||||
|
||||
static func parseLines(lines: [String], colorStyle: ColorStyle) -> [ParsedColor] {
|
||||
lines
|
||||
.enumerated()
|
||||
.compactMap { lineNumber, colorLine in
|
||||
// Required format:
|
||||
// colorName = "#RGB/#ARGB", colorName "#RGB/#ARGB", colorName "#RGB/#ARGB" "#RGB/#ARGB"
|
||||
.compactMap { _, colorLine in // swiftlint:disable:this unused_enumerated
|
||||
// Required format:
|
||||
// colorName = "#RGB/#ARGB", colorName "#RGB/#ARGB", colorName "#RGB/#ARGB" "#RGB/#ARGB"
|
||||
let colorLineCleanedUp = colorLine
|
||||
.removeLeadingWhitespace()
|
||||
.removeTrailingWhitespace()
|
||||
.replacingOccurrences(of: "=", with: "") // Keep compat with current file format
|
||||
|
||||
|
||||
guard colorLineCleanedUp.hasPrefix("#") == false, colorLineCleanedUp.isEmpty == false else {
|
||||
// debugPrint("[\(Colors.toolName)] ⚠️ BadFormat or empty line (line number: \(lineNumber + 1)). Skip this line")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
let colorContent = colorLineCleanedUp.split(separator: " ")
|
||||
|
||||
|
||||
guard colorContent.count >= 2 else {
|
||||
let error = ColorsToolError.badFormat(colorLine)
|
||||
print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
}
|
||||
|
||||
|
||||
switch colorStyle {
|
||||
case .light:
|
||||
return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[1]))
|
||||
|
||||
|
||||
case .all:
|
||||
if colorContent.count == 3 {
|
||||
return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[2]))
|
||||
|
Reference in New Issue
Block a user