Skip to content

Commit d696be7

Browse files
committed
Release 0.6.0 (#17)
* Refactor Platform type to Framework which is more aligned with the concept of what we are representing, default Framework is now SwiftUI, Update README file * Move all file generation logic to new FileGenerator class, Add unit test for header method, header method update to validate struct file name is Capitalized. * Update help info for some parameters
1 parent ac14c8a commit d696be7

File tree

10 files changed

+362
-219
lines changed

10 files changed

+362
-219
lines changed

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
# Chroma
22

3-
A command line tool to auto generate .swift extensions or structs files from .xcassets on your iOS, macOS & SwiftUI projects.
3+
A command line tool to generate .swift extensions or structs files from .xcassets on your UIKit, AppKIt or SwiftUI projects.
44

55
### Usage
66

77
```
88
$ Chroma --help
99
10-
USAGE: chroma --asset <asset> --path <path> [--type <type>] [--platform <platform>]
10+
USAGE: chroma --asset <asset> --path <path> [--type <type>] [--framework <framework>]
1111
1212
OPTIONS:
13-
-a, --asset <asset> The path of .xcasset file.
14-
-p, --path <path> The path of the generated .swift file.
15-
-t, --type <type> Specifies generated file type.
16-
Supported values: "extension","struct". (default:
13+
-a, --asset <asset> The path of .xcasset file.
14+
-p, --path <path> The path of the generated .swift file.
15+
-t, --type <type> The output type of generated .swift file.
16+
Supported values: extension, struct. (default:
1717
extension)
18-
--platform <platform> Specifies the platform compatibility of the exported
19-
file.
20-
iOS, macOS, swiftUI (default: iOS)
18+
--framework <framework> The framework compatibility of generated .swift file.
19+
Supported values: AppKit, SwiftUI, UIKit. (default:
20+
SwiftUI)
2121
-h, --help Show help information.
2222
2323
```
@@ -53,6 +53,6 @@ Select your project target on Xcode > go to `Build Phases` tab > Press on `+` >
5353
Copy & paste below command on your new script phase and update paths & platform parameters according to your needs.
5454

5555
```
56-
chroma --asset MyProject/Assets.xcassets --path MyProject/Extensions/Colors.swift --platform swiftUI
56+
chroma --asset MyProject/Assets.xcassets --path MyProject/Extensions/Colors.swift --framework SwiftUI
5757
```
5858
Optionally you can rename your new `Run Script` to `Chroma`.

Sources/Chroma/App/Chroma.swift

Lines changed: 11 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
//
88

99
import ArgumentParser
10-
import Files
1110
import Foundation
1211

1312
public struct Chroma: ParsableCommand {
@@ -20,48 +19,25 @@ public struct Chroma: ParsableCommand {
2019
@Option(name: .shortAndLong, help: OutputType.help)
2120
private var type: OutputType = .extension
2221

23-
@Option(name: .long, help: "Specifies the platform compatibility of the exported file.\niOS, macOS, swiftUI")
24-
private var platform: Platform = .iOS
22+
@Option(name: .long, help: Framework.help)
23+
private var framework: Framework = .SwiftUI
2524

2625
public init() {}
2726

2827
public func run() throws {
29-
let outputFile = try createOutputFile()
30-
let content = try getContentFromAssetsFile(outputFile: outputFile)
31-
try outputFile.write(content)
28+
let generator = FileGenerator(
29+
asset: asset,
30+
path: path,
31+
type: type,
32+
framework: framework
33+
)
34+
let file = try generator.generate()
3235
print(
3336
"""
34-
\(outputFile.name) was generated successfully.
35-
Can be found at \(outputFile.path)
37+
\(file.name) was generated successfully.
38+
Can be found at \(file.path)
3639
"""
3740
)
3841
}
3942

4043
}
41-
42-
extension Chroma {
43-
private func createOutputFile() throws -> File {
44-
// Check if path param is a valid swift file path
45-
guard let pathURL = URL(string: path), !pathURL.hasDirectoryPath, pathURL.pathExtension == "swift" else {
46-
throw ChromaError.invalidPath(path: path)
47-
}
48-
49-
let folder = try Folder(path: pathURL.deletingLastPathComponent().path)
50-
return try File(named: pathURL.lastPathComponent, at: folder)
51-
}
52-
53-
private func getContentFromAssetsFile(outputFile: File) throws -> String {
54-
let assetFolder = try Folder(path: asset)
55-
let body = platform.fileBody(asset: assetFolder).joined(separator: "\n")
56-
return platform.fileContent(header: header(file: outputFile), body: body)
57-
}
58-
59-
private func header(file: File) -> String {
60-
switch type {
61-
case .extension:
62-
return "\(type.rawValue) \(platform.variableType)"
63-
case .struct:
64-
return "\(type.rawValue) \(file.nameExcludingExtension)"
65-
}
66-
}
67-
}
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,44 @@
11
//
2-
// Platform.swift
2+
// FileGenerator.swift
33
// Chroma
44
//
5-
// Created by Oscar De Moya on 7/06/20.
6-
// Copyright © 2020 Jota Uribe. All rights reserved.
5+
// Created by Jota Uribe on 16/10/23.
76
//
87

9-
import Foundation
10-
import ArgumentParser
118
import Files
9+
import Foundation
1210

13-
enum Platform: String, ExpressibleByArgument {
14-
case iOS
15-
case macOS
16-
case swiftUI
17-
}
18-
19-
extension Platform {
11+
struct FileGenerator {
2012
private static let colorAssetExtension = "colorset"
2113

22-
var framework: String {
23-
switch self {
24-
case .iOS: return "UIKit"
25-
case .macOS: return "AppKit"
26-
case .swiftUI: return "SwiftUI"
27-
}
28-
}
14+
let asset: String
15+
let path: String
16+
let type: OutputType
17+
let framework: Framework
2918

30-
var defaultValue: String {
31-
switch self {
32-
case .iOS, .macOS:
33-
return "?? .clear "
34-
case .swiftUI:
35-
return ""
36-
}
19+
func generate() throws -> File {
20+
let outputFile = try createOutputFile()
21+
let content = try getContentFromAssetsFile(outputFile: outputFile)
22+
try outputFile.write(content)
23+
return outputFile
3724
}
3825

39-
var parameterName: String {
40-
switch self {
41-
case .iOS, .macOS:
42-
return "named: "
43-
case .swiftUI:
44-
return ""
45-
}
46-
}
26+
// MARK: Helper Methods
4727

48-
var variableType: String {
49-
switch self {
50-
case .iOS: return "UIColor"
51-
case .macOS: return "NSColor"
52-
case .swiftUI: return "Color"
28+
private func createOutputFile() throws -> File {
29+
// Check if path param is a valid swift file path
30+
guard let pathURL = URL(string: path), !pathURL.hasDirectoryPath, pathURL.pathExtension == "swift" else {
31+
throw ChromaError.invalidPath(path: path)
5332
}
33+
34+
let folder = try Folder(path: pathURL.deletingLastPathComponent().path)
35+
return try File(named: pathURL.lastPathComponent, at: folder)
5436
}
5537

56-
var systemReservedVariableNames: [String] {
57-
switch self {
58-
case .iOS, .macOS:
59-
return []
60-
case .swiftUI:
61-
return ["accentColor"]
62-
}
38+
private func getContentFromAssetsFile(outputFile: File) throws -> String {
39+
let assetFolder = try Folder(path: asset)
40+
let body = fileBody(asset: assetFolder).joined(separator: "\n")
41+
return fileContent(header: header(fileName: outputFile.nameExcludingExtension), body: body)
6342
}
6443

6544
func fileContent(header: String, body: String) -> String {
@@ -70,8 +49,8 @@ extension Platform {
7049
//
7150
// This file was auto generated please do not modify it directly.
7251
//
73-
74-
import \(framework)
52+
53+
import \(framework.rawValue)
7554
7655
\(header) {
7756
@@ -81,6 +60,15 @@ extension Platform {
8160
"""
8261
}
8362

63+
func header(fileName: String) -> String {
64+
switch type {
65+
case .extension:
66+
return "\(type.rawValue) \(framework.variableType)"
67+
case .struct:
68+
return "\(type.rawValue) \(fileName.capitalized)"
69+
}
70+
}
71+
8472
func fileBody(asset: Folder) -> Array<String> {
8573
let assetKey = asset.nameExcludingExtension
8674
// Get subfolders with valid extension
@@ -107,13 +95,7 @@ extension Platform {
10795
private func colorVariableNames(folders: [Folder]) -> [String] {
10896
// We filter out duplicated variable names
10997
Set(folders.compactMap { colorFolder in
110-
return colorVariable(name: colorFolder.nameExcludingExtension)
98+
return framework.colorVariable(name: colorFolder.nameExcludingExtension)
11199
}).sorted()
112100
}
113-
114-
func colorVariable(name: String) -> String? {
115-
let formattedName = name.camelCased().removing(.punctuationCharacters.union(.symbols))
116-
guard !systemReservedVariableNames.contains(formattedName) else { return nil }
117-
return " static var \(formattedName): \(variableType) { return \(variableType)(\(parameterName)\"\(name)\") \(defaultValue)}"
118-
}
119101
}

Sources/Chroma/App/Framework.swift

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
// Framework.swift
3+
// Chroma
4+
//
5+
// Created by Jota Uribe on 16/10/23.
6+
//
7+
8+
import Foundation
9+
import ArgumentParser
10+
11+
enum Framework: String, CaseIterable, ExpressibleByArgument {
12+
case AppKit
13+
case SwiftUI
14+
case UIKit
15+
}
16+
17+
extension Framework {
18+
static var help: ArgumentHelp {
19+
"""
20+
The framework compatibility of generated .swift file.
21+
Supported values: \(formattedValues).
22+
"""
23+
}
24+
}
25+
26+
extension Framework {
27+
var defaultValue: String {
28+
switch self {
29+
case .UIKit, .AppKit:
30+
return "?? .clear "
31+
case .SwiftUI:
32+
return ""
33+
}
34+
}
35+
36+
var parameterName: String {
37+
switch self {
38+
case .UIKit, .AppKit:
39+
return "named: "
40+
case .SwiftUI:
41+
return ""
42+
}
43+
}
44+
45+
var variableType: String {
46+
switch self {
47+
case .UIKit: return "UIColor"
48+
case .AppKit: return "NSColor"
49+
case .SwiftUI: return "Color"
50+
}
51+
}
52+
53+
var systemReservedVariableNames: [String] {
54+
switch self {
55+
case .UIKit, .AppKit:
56+
return []
57+
case .SwiftUI:
58+
return ["accentColor"]
59+
}
60+
}
61+
62+
func colorVariable(name: String) -> String? {
63+
let formattedName = name.camelCased().removing(.punctuationCharacters.union(.symbols))
64+
guard !systemReservedVariableNames.contains(formattedName) else { return nil }
65+
return " static var \(formattedName): \(variableType) { return \(variableType)(\(parameterName)\"\(name)\") \(defaultValue)}"
66+
}
67+
}

Sources/Chroma/App/OutputType.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,9 @@ enum OutputType: String, CaseIterable, ExpressibleByArgument {
1515
}
1616

1717
extension OutputType {
18-
19-
private static var formattedValues: String {
20-
return OutputType.allCases.map { "\"\($0.rawValue)\"" }.joined(separator: ",")
21-
}
22-
2318
static var help: ArgumentHelp {
2419
"""
25-
Specifies generated file type.
20+
The output type of generated .swift file.
2621
Supported values: \(formattedValues).
2722
"""
2823
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// CaseIterable+Formatters.swift
3+
// Chroma
4+
//
5+
// Created by Jota Uribe on 17/10/23.
6+
//
7+
8+
import Foundation
9+
10+
extension CaseIterable where Self: RawRepresentable {
11+
static var formattedValues: String {
12+
return Self.allCases.map { "\($0.rawValue)" }.joined(separator: ", ")
13+
}
14+
}

0 commit comments

Comments
 (0)