diff --git a/.swiftlint.yml b/.swiftlint.yml
new file mode 100644
index 0000000..ff4d15b
--- /dev/null
+++ b/.swiftlint.yml
@@ -0,0 +1,193 @@
+excluded:
+ - .build
+
+disabled_rules:
+ - opening_brace
+ - trailing_comma
+
+nesting:
+ type_level:
+ warning: 3
+ error: 6
+
+opt_in_rules:
+ - array_init
+ - attributes
+ - block_based_kvo
+ - class_delegate_protocol
+ - closing_brace
+ - closure_body_length
+ - closure_end_indentation
+ - closure_parameter_position
+ - closure_spacing
+ - collection_alignment
+ - colon
+ - comma
+ - comment_spacing
+ - compiler_protocol_init
+ - computed_accessors_order
+ - contains_over_filter_count
+ - contains_over_filter_is_empty
+ - contains_over_first_not_nil
+ - contains_over_range_nil_comparison
+ - control_statement
+ - convenience_type
+ - custom_rules
+ - cyclomatic_complexity
+ - deployment_target
+ - discarded_notification_center_observer
+ - discouraged_direct_init
+ - discouraged_object_literal
+ - discouraged_optional_boolean
+ - discouraged_optional_collection
+ - duplicate_enum_cases
+ - duplicate_imports
+ - dynamic_inline
+ - empty_collection_literal
+ - empty_count
+ - empty_enum_arguments
+ - empty_parameters
+ - empty_parentheses_with_trailing_closure
+ - empty_string
+ - empty_xctest_method
+ - enum_case_associated_values_count
+ - expiring_todo
+ - explicit_init
+ - explicit_self
+ - extension_access_modifier
+ - fallthrough
+ - fatal_error_message
+ - file_header
+ - file_length
+ - file_name
+ - file_name_no_space
+ - first_where
+ - flatmap_over_map_reduce
+ - for_where
+ - force_cast
+ - force_try
+ - force_unwrapping
+ - function_body_length
+ - function_default_parameter_at_end
+ - function_parameter_count
+ - generic_type_name
+ - identical_operands
+ - identifier_name
+ - implicit_getter
+ - implicit_return
+ - implicitly_unwrapped_optional
+ - inclusive_language
+ - inert_defer
+ - is_disjoint
+ - joined_default_parameter
+ - large_tuple
+ - last_where
+ - leading_whitespace
+ - legacy_cggeometry_functions
+ - legacy_constant
+ - legacy_constructor
+ - legacy_hashing
+ - legacy_multiple
+ - legacy_nsgeometry_functions
+ - legacy_random
+# - let_var_whitespace # We actually want this, but it currently gets confused with property wrappers.
+ - line_length
+ - literal_expression_end_indentation
+ - lower_acl_than_parent
+ - mark
+ - missing_docs
+ - modifier_order
+ - multiline_arguments
+ - multiline_arguments_brackets
+ - multiline_function_chains
+ - multiline_literal_brackets
+ - multiline_parameters
+ - multiline_parameters_brackets
+ - multiple_closures_with_trailing_closure
+ - nesting
+ - no_fallthrough_only
+ - no_grouping_extension
+ - no_space_in_method_call
+ - notification_center_detachment
+ - nslocalizedstring_key
+ - nslocalizedstring_require_bundle
+ - nsobject_prefer_isequal
+ - number_separator
+ - object_literal
+ - operator_usage_whitespace
+ - operator_whitespace
+ - optional_enum_case_matching
+ - orphaned_doc_comment
+ - overridden_super_call
+ - override_in_extension
+ - pattern_matching_keywords
+ - prefer_self_type_over_type_of_self
+ - prefer_zero_over_explicit_init
+ - private_action
+ - private_outlet
+ - private_over_fileprivate
+ - private_unit_test
+ - prohibited_super_call
+ - protocol_property_accessors_order
+ - quick_discouraged_call
+ - quick_discouraged_focused_test
+ - quick_discouraged_pending_test
+ - raw_value_for_camel_cased_codable_enum
+ - reduce_boolean
+ - reduce_into
+ - redundant_discardable_let
+ - redundant_nil_coalescing
+ - redundant_objc_attribute
+ - redundant_optional_initialization
+ - redundant_set_access_control
+ - redundant_string_enum_value
+ - redundant_type_annotation
+ - redundant_void_return
+ - required_enum_case
+ - return_arrow_whitespace
+ - shorthand_operator
+ - single_test_class
+ - sorted_first_last
+ - sorted_imports
+ - statement_position
+ - static_operator
+ - strict_fileprivate
+ - strong_iboutlet
+ - superfluous_disable_command
+ - switch_case_alignment
+ - switch_case_on_newline
+ - syntactic_sugar
+ - test_case_accessibility
+ - todo
+ - toggle_bool
+ - trailing_closure
+ - trailing_newline
+ - trailing_semicolon
+ - trailing_whitespace
+ - type_body_length
+ - type_name
+ - unavailable_function
+ - unneeded_break_in_switch
+ - unneeded_parentheses_in_closure_argument
+ - unowned_variable_capture
+ - untyped_error_in_catch
+ - unused_capture_list
+ - unused_closure_parameter
+ - unused_control_flow_label
+ - unused_declaration
+ - unused_enumerated
+ - unused_import
+ - unused_optional_binding
+ - unused_setter_value
+ - valid_ibinspectable
+ - vertical_parameter_alignment
+ - vertical_parameter_alignment_on_call
+ - vertical_whitespace
+ - vertical_whitespace_between_cases
+ - vertical_whitespace_closing_braces
+ - vertical_whitespace_opening_braces
+ - void_return
+ - weak_delegate
+ - xct_specific_matcher
+ - xctfail_message
+ - yoda_condition
diff --git a/Sources/LibMakeColors/Extensions/String+Extensions.swift b/Sources/LibMakeColors/Extensions/StringProtocol+Extensions.swift
similarity index 100%
rename from Sources/LibMakeColors/Extensions/String+Extensions.swift
rename to Sources/LibMakeColors/Extensions/StringProtocol+Extensions.swift
diff --git a/Sources/LibMakeColors/Generators/AndroidGenerator.swift b/Sources/LibMakeColors/Generators/AndroidGenerator.swift
index e9c309f..cf80010 100644
--- a/Sources/LibMakeColors/Generators/AndroidGenerator.swift
+++ b/Sources/LibMakeColors/Generators/AndroidGenerator.swift
@@ -23,8 +23,11 @@ final class AndroidGenerator: Generator {
let value: String
switch color {
- case let .color(colorValue): value = colorValue.description
- case let .reference(ref): value = "@color/\(prefix)\(ref.camelCasePathToSnakeCase())"
+ case let .color(colorValue):
+ value = colorValue.description
+
+ case let .reference(ref):
+ value = "@color/\(prefix)\(ref.camelCasePathToSnakeCase())"
}
xml += """
diff --git a/Sources/LibMakeColors/Generators/AssetCatalogGenerator.swift b/Sources/LibMakeColors/Generators/AssetCatalogGenerator.swift
index ee277ce..3be34f9 100644
--- a/Sources/LibMakeColors/Generators/AssetCatalogGenerator.swift
+++ b/Sources/LibMakeColors/Generators/AssetCatalogGenerator.swift
@@ -60,10 +60,10 @@ private extension Color {
"color" : {
"color-space" : "srgb",
"components" : {
- "alpha" : "\(Float(a) / 256)",
- "blue" : "0x\(String(b, radix: 16))",
- "green" : "0x\(String(g, radix: 16))",
- "red" : "0x\(String(r, radix: 16))"
+ "alpha" : "\(Float(alpha) / 256)",
+ "blue" : "0x\(String(blue, radix: 16))",
+ "green" : "0x\(String(green, radix: 16))",
+ "red" : "0x\(String(red, radix: 16))"
}
},
"idiom" : "universal"
diff --git a/Sources/LibMakeColors/Generators/HTMLGenerator.swift b/Sources/LibMakeColors/Generators/HTMLGenerator.swift
index 9900f3e..393900c 100644
--- a/Sources/LibMakeColors/Generators/HTMLGenerator.swift
+++ b/Sources/LibMakeColors/Generators/HTMLGenerator.swift
@@ -2,6 +2,45 @@ import Foundation
final class HTMLGenerator: Generator {
static let defaultExtension = "html"
+
+ static let head = """
+
+
+
+
+
+
+
+ |
+ Name |
+ Value |
+
+
+
+
+ """
+
let context: Context
init(context: Context) {
@@ -9,52 +48,27 @@ final class HTMLGenerator: Generator {
}
func generate(data: [String: ColorDef]) throws -> FileWrapper {
- var html = """
-
-
-
-
-
-
-
- |
- Name |
- Value |
-
-
-
-
- """
+ var html = Self.head
for (key, color) in data.sorted() {
let actualColor = try data.resolve(key)
let value: String
switch color {
- case let .reference(name): value = """
+ case let .reference(name):
+ value = """
\(name.insertCamelCaseSeparators())
\(actualColor)
"""
- case .color: value = actualColor.description
+
+ case .color:
+ value = actualColor.description
}
html += """
- |
+
+
+ |
\(key.insertCamelCaseSeparators()) |
\(value) |
diff --git a/Sources/LibMakeColors/MakeColors.swift b/Sources/LibMakeColors/MakeColors.swift
index 00bceb1..b125ec4 100644
--- a/Sources/LibMakeColors/MakeColors.swift
+++ b/Sources/LibMakeColors/MakeColors.swift
@@ -2,18 +2,18 @@ import ArgumentParser
import Foundation
private struct GeneratorOption: EnumerableFlag, CustomStringConvertible {
- let type: Generator.Type
-
- var description: String {
- type.option
- }
-
static let allCases: [GeneratorOption] = [
.init(type: AssetCatalogGenerator.self),
.init(type: AndroidGenerator.self),
.init(type: HTMLGenerator.self),
]
+ let type: Generator.Type
+
+ var description: String {
+ type.option
+ }
+
static func == (lhs: GeneratorOption, rhs: GeneratorOption) -> Bool {
lhs.type == rhs.type
}
@@ -53,9 +53,12 @@ public final class MakeColors: ParsableCommand, Context {
for (key, color) in data.sorted() {
let resolved = try data.resolve(key)
switch color {
- case .color: print(key.insertCamelCaseSeparators(), resolved, separator: ": ")
- case let .reference(r): print(
- "\(key.insertCamelCaseSeparators()) (@\(r.insertCamelCaseSeparators()))",
+ case .color:
+ print(key.insertCamelCaseSeparators(), resolved, separator: ": ")
+
+ case let .reference(referenced):
+ print(
+ "\(key.insertCamelCaseSeparators()) (@\(referenced.insertCamelCaseSeparators()))",
resolved,
separator: ": "
)
diff --git a/Sources/LibMakeColors/Model/Color.swift b/Sources/LibMakeColors/Model/Color.swift
index ee08acf..ef2030e 100644
--- a/Sources/LibMakeColors/Model/Color.swift
+++ b/Sources/LibMakeColors/Model/Color.swift
@@ -1,23 +1,27 @@
struct Color: CustomStringConvertible, Equatable {
- let r, g, b, a: UInt8
+ let red: UInt8
+ let green: UInt8
+ let blue: UInt8
+ let alpha: UInt8
- init(r: UInt8, g: UInt8, b: UInt8, a: UInt8 = 0xFF) {
- self.r = r
- self.g = g
- self.b = b
- self.a = a
+ init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8 = 0xFF) {
+ self.red = red
+ self.green = green
+ self.blue = blue
+ self.alpha = alpha
}
- init?(_ array: [UInt8]) {
- guard array.count >= 3 else { return nil }
- r = array[0]
- g = array[1]
- b = array[2]
- a = array.count >= 4 ? array[3] : 0xFF
+ init(_ array: [UInt8]) {
+ precondition(array.count == 3 || array.count == 4)
+ red = array[0]
+ green = array[1]
+ blue = array[2]
+ alpha = array.count == 4 ? array[3] : 0xFF
}
var description: String {
- a != 0xFF ? String(format: "#%02X%02X%02X%02X", r, g, b, a) : String(format: "#%02X%02X%02X", r, g, b)
+ let alphaSuffix = alpha != 0xFF ? String(format: "%02X", alpha) : ""
+ return String(format: "#%02X%02X%02X%@", red, green, blue, alphaSuffix)
}
}
@@ -49,11 +53,16 @@ extension Dictionary where Key == String, Value == ColorDef {
sorted(by: Self.compare)
}
- static func compare(_ a: (String, ColorDef), _ b: (String, ColorDef)) -> Bool {
- switch (a, b) {
- case ((_, .color), (_, .reference)): return true
- case ((_, .reference), (_, .color)): return false
- case let ((left, _), (right, _)): return left.localizedStandardCompare(right) == .orderedAscending
+ static func compare(_ lhs: (String, ColorDef), _ rhs: (String, ColorDef)) -> Bool {
+ switch (lhs, rhs) {
+ case ((_, .color), (_, .reference)):
+ return true
+
+ case ((_, .reference), (_, .color)):
+ return false
+
+ case let ((left, _), (right, _)):
+ return left.localizedStandardCompare(right) == .orderedAscending
}
}
}
diff --git a/Sources/LibMakeColors/Model/Parser.swift b/Sources/LibMakeColors/Model/Scanner+ColorParser.swift
similarity index 93%
rename from Sources/LibMakeColors/Model/Parser.swift
rename to Sources/LibMakeColors/Model/Scanner+ColorParser.swift
index ae1e86e..3d56246 100644
--- a/Sources/LibMakeColors/Model/Parser.swift
+++ b/Sources/LibMakeColors/Model/Scanner+ColorParser.swift
@@ -1,26 +1,6 @@
import Foundation
-private extension CharacterSet {
- static let hex = CharacterSet(charactersIn: "0123456789abcdef")
- static let name = alphanumerics.union(CharacterSet(charactersIn: "_/"))
-}
-
-private extension Collection {
- func chunks(size: Int) -> UnfoldSequence {
- sequence(state: startIndex) { state -> SubSequence? in
- guard state != endIndex else { return nil }
- let next = index(state, offsetBy: size, limitedBy: endIndex) ?? endIndex
- defer { state = next }
- return self[state.. Bool {
- scanString(s) != nil
- }
-
func color() -> Color? {
if string("#"), let digits = scanCharacters(from: .hex) {
switch digits.count {
@@ -34,7 +14,8 @@ extension Scanner {
let digits = digits.chunks(size: 2).compactMap { UInt8($0, radix: 16) }
return Color(digits)
- default: return nil
+ default:
+ return nil
}
}
@@ -110,6 +91,7 @@ extension Scanner {
return result
}
+ // swiftlint:disable:next discouraged_optional_collection
func commaSeparated() -> [UInt8]? {
var result: [UInt8] = []
repeat {
@@ -121,3 +103,25 @@ extension Scanner {
return result
}
}
+
+private extension Scanner {
+ func string(_ string: String) -> Bool {
+ scanString(string) != nil
+ }
+}
+
+private extension CharacterSet {
+ static let hex = CharacterSet(charactersIn: "0123456789abcdef")
+ static let name = alphanumerics.union(CharacterSet(charactersIn: "_/"))
+}
+
+private extension Collection {
+ func chunks(size: Int) -> UnfoldSequence {
+ sequence(state: startIndex) { state -> SubSequence? in
+ guard state != endIndex else { return nil }
+ let next = index(state, offsetBy: size, limitedBy: endIndex) ?? endIndex
+ defer { state = next }
+ return self[state..