From fb9dd25d57d0b34ddaf22eabf3cc185d4588bb80 Mon Sep 17 00:00:00 2001 From: David Jennes Date: Tue, 30 May 2017 22:52:51 +0200 Subject: [PATCH] Add support for multiple color palettes --- Sources/Parsers/ColorsFileParser.swift | 15 +++-- .../ColorsCLRFileParser.swift | 5 +- .../ColorsJSONFileParser.swift | 5 +- .../ColorsTXTFileParser.swift | 5 +- .../ColorsXMLFileParser.swift | 5 +- Sources/Stencil/ColorsContext.swift | 55 ++++++++++++------- Tests/Resources | 2 +- .../SwiftGenKitTests/ColorsCLRFileTests.swift | 2 +- .../ColorsJSONFileTests.swift | 2 +- Tests/SwiftGenKitTests/ColorsTests.swift | 15 +++-- .../ColorsTextFileTests.swift | 2 +- .../SwiftGenKitTests/ColorsXMLFileTests.swift | 2 +- 12 files changed, 68 insertions(+), 47 deletions(-) diff --git a/Sources/Parsers/ColorsFileParser.swift b/Sources/Parsers/ColorsFileParser.swift index 4965975..f4bd808 100644 --- a/Sources/Parsers/ColorsFileParser.swift +++ b/Sources/Parsers/ColorsFileParser.swift @@ -29,16 +29,21 @@ public enum ColorsParserError: Error, CustomStringConvertible { } } +struct Palette { + let name: String + let colors: [String: UInt32] +} + protocol ColorsFileTypeParser: class { static var extensions: [String] { get } init() - func parseFile(at path: Path) throws -> [String: UInt32] + func parseFile(at path: Path) throws -> Palette } public final class ColorsFileParser { private var parsers = [String: ColorsFileTypeParser.Type]() - var colors = [String: UInt32]() + var palettes = [Palette]() public init() throws { try register(parser: ColorsCLRFileParser.self) @@ -53,11 +58,9 @@ public final class ColorsFileParser { } let parser = parserType.init() - let colors = try parser.parseFile(at: path) + let palette = try parser.parseFile(at: path) - for (name, value) in colors { - self.colors[name] = value - } + palettes += [palette] } func register(parser: ColorsFileTypeParser.Type) throws { diff --git a/Sources/Parsers/ColorsFileParsers/ColorsCLRFileParser.swift b/Sources/Parsers/ColorsFileParsers/ColorsCLRFileParser.swift index f73def0..6bcdef4 100644 --- a/Sources/Parsers/ColorsFileParsers/ColorsCLRFileParser.swift +++ b/Sources/Parsers/ColorsFileParsers/ColorsCLRFileParser.swift @@ -14,7 +14,7 @@ final class ColorsCLRFileParser: ColorsFileTypeParser { static let userColors = "UserColors" } - func parseFile(at path: Path) throws -> [String: UInt32] { + func parseFile(at path: Path) throws -> Palette { if let colorsList = NSColorList(name: Keys.userColors, fromFile: path.string) { var colors = [String: UInt32]() @@ -22,7 +22,8 @@ final class ColorsCLRFileParser: ColorsFileTypeParser { colors[colorName] = colorsList.color(withKey: colorName)?.hexValue } - return colors + let name = path.lastComponentWithoutExtension + return Palette(name: name, colors: colors) } else { throw ColorsParserError.invalidFile(path: path, reason: "Invalid color list") } diff --git a/Sources/Parsers/ColorsFileParsers/ColorsJSONFileParser.swift b/Sources/Parsers/ColorsFileParsers/ColorsJSONFileParser.swift index 8c05172..15002bc 100644 --- a/Sources/Parsers/ColorsFileParsers/ColorsJSONFileParser.swift +++ b/Sources/Parsers/ColorsFileParsers/ColorsJSONFileParser.swift @@ -10,7 +10,7 @@ import PathKit final class ColorsJSONFileParser: ColorsFileTypeParser { static let extensions = ["json"] - func parseFile(at path: Path) throws -> [String: UInt32] { + func parseFile(at path: Path) throws -> Palette { do { let json = try JSONSerialization.jsonObject(with: try path.read(), options: []) guard let dict = json as? [String: String] else { @@ -23,7 +23,8 @@ final class ColorsJSONFileParser: ColorsFileTypeParser { colors[key] = try parse(hex: value, key: key) } - return colors + let name = path.lastComponentWithoutExtension + return Palette(name: name, colors: colors) } catch let error as ColorsParserError { throw error } catch let error { diff --git a/Sources/Parsers/ColorsFileParsers/ColorsTXTFileParser.swift b/Sources/Parsers/ColorsFileParsers/ColorsTXTFileParser.swift index 0348cb0..c97958b 100644 --- a/Sources/Parsers/ColorsFileParsers/ColorsTXTFileParser.swift +++ b/Sources/Parsers/ColorsFileParsers/ColorsTXTFileParser.swift @@ -65,7 +65,7 @@ final class ColorsTextFileParser: ColorsFileTypeParser { // - One line per entry // - Each line composed by the color name, then ":", then the color hex representation // - Extra spaces will be skipped - func parseFile(at path: Path) throws -> [String: UInt32] { + func parseFile(at path: Path) throws -> Palette { do { let dict = try keyValueDict(from: path, withSeperator: ":") for key in dict.keys { @@ -77,6 +77,7 @@ final class ColorsTextFileParser: ColorsFileTypeParser { throw ColorsParserError.invalidFile(path: path, reason: error.localizedDescription) } - return colors + let name = path.lastComponentWithoutExtension + return Palette(name: name, colors: colors) } } diff --git a/Sources/Parsers/ColorsFileParsers/ColorsXMLFileParser.swift b/Sources/Parsers/ColorsFileParsers/ColorsXMLFileParser.swift index 1a84c61..14c2cae 100644 --- a/Sources/Parsers/ColorsFileParsers/ColorsXMLFileParser.swift +++ b/Sources/Parsers/ColorsFileParsers/ColorsXMLFileParser.swift @@ -16,7 +16,7 @@ final class ColorsXMLFileParser: ColorsFileTypeParser { static let nameAttribute = "name" } - func parseFile(at path: Path) throws -> [String: UInt32] { + func parseFile(at path: Path) throws -> Palette { guard let document = Kanna.XML(xml: try path.read(), encoding: .utf8) else { throw ColorsParserError.invalidFile(path: path, reason: "Unknown XML parser error.") } @@ -34,6 +34,7 @@ final class ColorsXMLFileParser: ColorsFileTypeParser { colors[name] = try parse(hex: value, key: name) } - return colors + let name = path.lastComponentWithoutExtension + return Palette(name: name, colors: colors) } } diff --git a/Sources/Stencil/ColorsContext.swift b/Sources/Stencil/ColorsContext.swift index dbc0a52..870e0fe 100644 --- a/Sources/Stencil/ColorsContext.swift +++ b/Sources/Stencil/ColorsContext.swift @@ -7,32 +7,47 @@ import Foundation /* - - `colors`: `Array` of: - - `name` : `String` — name of each color - - `red` : `String` — hex value of the red component - - `green`: `String` — hex value of the green component - - `blue` : `String` — hex value of the blue component - - `alpha`: `String` — hex value of the alpha component + - `palettes`: `Array` of: + - `name`: `String` — name of the palette + - `colors`: `Array` of: + - `name` : `String` — name of each color + - `red` : `String` — hex value of the red component + - `green`: `String` — hex value of the green component + - `blue` : `String` — hex value of the blue component + - `alpha`: `String` — hex value of the alpha component */ extension ColorsFileParser { public func stencilContext() -> [String: Any] { - let colorMap = colors.map({ (color: (name: String, value: UInt32)) -> [String:String] in - let name = color.name.trimmingCharacters(in: CharacterSet.whitespaces) - let hex = "00000000" + String(color.value, radix: 16) - let hexChars = Array(hex.characters.suffix(8)) - let comps = (0..<4).map { idx in String(hexChars[idx*2...idx*2+1]) } + let palettes: [[String: Any]] = self.palettes + .sorted(by: { $0.name < $1.name }) + .map { palette in + let colors = palette.colors + .sorted { $0.key < $1.key } + .map(map(color:value:)) - return [ - "name": name, - "red": comps[0], - "green": comps[1], - "blue": comps[2], - "alpha": comps[3] - ] - }).sorted { $0["name"] ?? "" < $1["name"] ?? "" } + return [ + "name": palette.name, + "colors": colors + ] + } return [ - "colors": colorMap + "palettes": palettes + ] + } + + private func map(color name: String, value: UInt32) -> [String: String] { + let name = name.trimmingCharacters(in: .whitespaces) + let hex = "00000000" + String(value, radix: 16) + let hexChars = Array(hex.characters.suffix(8)) + let comps = (0..<4).map { idx in String(hexChars[idx*2...idx*2+1]) } + + return [ + "name": name, + "red": comps[0], + "green": comps[1], + "blue": comps[2], + "alpha": comps[3] ] } } diff --git a/Tests/Resources b/Tests/Resources index 913f3d3..199c9b3 160000 --- a/Tests/Resources +++ b/Tests/Resources @@ -1 +1 @@ -Subproject commit 913f3d3095bc83786d607a65f04d43243b57827b +Subproject commit 199c9b3eddbf182727e24c5b822f1645c4ed589b diff --git a/Tests/SwiftGenKitTests/ColorsCLRFileTests.swift b/Tests/SwiftGenKitTests/ColorsCLRFileTests.swift index 1607913..2da5104 100644 --- a/Tests/SwiftGenKitTests/ColorsCLRFileTests.swift +++ b/Tests/SwiftGenKitTests/ColorsCLRFileTests.swift @@ -11,7 +11,7 @@ import PathKit class ColorsCLRFileTests: XCTestCase { func testFileWithDefaults() throws { let parser = try ColorsFileParser() - parser.colors = try ColorsCLRFileParser().parseFile(at: Fixtures.path(for: "colors.clr", sub: .colors)) + parser.palettes = [try ColorsCLRFileParser().parseFile(at: Fixtures.path(for: "colors.clr", sub: .colors))] let result = parser.stencilContext() XCTDiffContexts(result, expected: "defaults.plist", sub: .colors) diff --git a/Tests/SwiftGenKitTests/ColorsJSONFileTests.swift b/Tests/SwiftGenKitTests/ColorsJSONFileTests.swift index 3285394..ae6a484 100644 --- a/Tests/SwiftGenKitTests/ColorsJSONFileTests.swift +++ b/Tests/SwiftGenKitTests/ColorsJSONFileTests.swift @@ -11,7 +11,7 @@ import PathKit class ColorsJSONFileTests: XCTestCase { func testFileWithDefaults() throws { let parser = try ColorsFileParser() - parser.colors = try ColorsJSONFileParser().parseFile(at: Fixtures.path(for: "colors.json", sub: .colors)) + parser.palettes = [try ColorsJSONFileParser().parseFile(at: Fixtures.path(for: "colors.json", sub: .colors))] let result = parser.stencilContext() XCTDiffContexts(result, expected: "defaults.plist", sub: .colors) diff --git a/Tests/SwiftGenKitTests/ColorsTests.swift b/Tests/SwiftGenKitTests/ColorsTests.swift index 726c5d7..e2414ea 100644 --- a/Tests/SwiftGenKitTests/ColorsTests.swift +++ b/Tests/SwiftGenKitTests/ColorsTests.swift @@ -10,22 +10,22 @@ import XCTest final class TestFileParser1: ColorsFileTypeParser { static let extensions = ["test1"] - func parseFile(at path: Path) throws -> [String: UInt32] { - return ["test1": 1] + func parseFile(at path: Path) throws -> Palette { + return Palette(name: "test1", colors: [:]) } } final class TestFileParser2: ColorsFileTypeParser { static let extensions = ["test2"] - func parseFile(at path: Path) throws -> [String: UInt32] { - return ["test2": 1] + func parseFile(at path: Path) throws -> Palette { + return Palette(name: "test2", colors: [:]) } } final class TestFileParser3: ColorsFileTypeParser { static let extensions = ["test1"] - func parseFile(at path: Path) throws -> [String: UInt32] { - return [:] + func parseFile(at path: Path) throws -> Palette { + return Palette(name: "test3", colors: [:]) } } @@ -45,8 +45,7 @@ class ColorParserTests: XCTestCase { try parser.register(parser: TestFileParser2.self) try parser.parseFile(at: "someFile.test1") - XCTAssertEqual(parser.colors["test1"], 1) - XCTAssertNil(parser.colors["test2"]) + XCTAssertEqual(parser.palettes.first?.name, "test1") } func testDispatchUnknownExtension() throws { diff --git a/Tests/SwiftGenKitTests/ColorsTextFileTests.swift b/Tests/SwiftGenKitTests/ColorsTextFileTests.swift index 1e67b2b..539bb97 100644 --- a/Tests/SwiftGenKitTests/ColorsTextFileTests.swift +++ b/Tests/SwiftGenKitTests/ColorsTextFileTests.swift @@ -11,7 +11,7 @@ import PathKit class ColorsTextFileTests: XCTestCase { func testFileWithDefaults() throws { let parser = try ColorsFileParser() - parser.colors = try ColorsTextFileParser().parseFile(at: Fixtures.path(for: "colors.txt", sub: .colors)) + parser.palettes = [try ColorsTextFileParser().parseFile(at: Fixtures.path(for: "colors.txt", sub: .colors))] let result = parser.stencilContext() XCTDiffContexts(result, expected: "text-defaults.plist", sub: .colors) diff --git a/Tests/SwiftGenKitTests/ColorsXMLFileTests.swift b/Tests/SwiftGenKitTests/ColorsXMLFileTests.swift index 8af2056..37a939c 100644 --- a/Tests/SwiftGenKitTests/ColorsXMLFileTests.swift +++ b/Tests/SwiftGenKitTests/ColorsXMLFileTests.swift @@ -11,7 +11,7 @@ import PathKit class ColorsXMLFileTests: XCTestCase { func testFileWithDefaults() throws { let parser = try ColorsFileParser() - parser.colors = try ColorsXMLFileParser().parseFile(at: Fixtures.path(for: "colors.xml", sub: .colors)) + parser.palettes = [try ColorsXMLFileParser().parseFile(at: Fixtures.path(for: "colors.xml", sub: .colors))] let result = parser.stencilContext() XCTDiffContexts(result, expected: "defaults.plist", sub: .colors)