From c40686d07d350f835a1c10d0d440d924e8d605a5 Mon Sep 17 00:00:00 2001 From: Alex Deem Date: Mon, 10 Jun 2024 22:07:58 +1000 Subject: [PATCH] Refactor variable expansion This change eliminates a swiftlint cyclomatic_complexity issue --- .../Internal/Components.swift | 24 +------------ .../Internal/ValueFormatting.swift | 35 ++++++++++++++++--- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/Sources/ScreamURITemplate/Internal/Components.swift b/Sources/ScreamURITemplate/Internal/Components.swift index ccd66fb..9e63fbc 100644 --- a/Sources/ScreamURITemplate/Internal/Components.swift +++ b/Sources/ScreamURITemplate/Internal/Components.swift @@ -64,7 +64,6 @@ struct ExpressionComponent: Component { self.templatePosition = templatePosition } - // swiftlint:disable:next cyclomatic_complexity func expand(variables: VariableProvider) throws -> String { let configuration = expressionOperator.expansionConfiguration() let expansions = try variableList.compactMap { variableSpec -> String? in @@ -72,28 +71,7 @@ struct ExpressionComponent: Component { return nil } do { - switch value { - case let .string(plainValue): - return try plainValue.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) - case let .list(arrayValue): - switch variableSpec.modifier { - case .prefix: - throw FormatError.failure(reason: "Prefix operator can only be applied to string") - case .explode: - return try arrayValue.explodeForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) - case .none: - return try arrayValue.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) - } - case let .associativeArray(associativeArrayValue): - switch variableSpec.modifier { - case .prefix: - throw FormatError.failure(reason: "Prefix operator can only be applied to string") - case .explode: - return try associativeArrayValue.explodeForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) - case .none: - return try associativeArrayValue.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) - } - } + return try value.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) } catch let FormatError.failure(reason) { throw URITemplate.Error.expansionFailure(position: templatePosition, reason: "Failed expanding variable \"\(variableSpec.name)\": \(reason)") } diff --git a/Sources/ScreamURITemplate/Internal/ValueFormatting.swift b/Sources/ScreamURITemplate/Internal/ValueFormatting.swift index 1915440..6619176 100644 --- a/Sources/ScreamURITemplate/Internal/ValueFormatting.swift +++ b/Sources/ScreamURITemplate/Internal/ValueFormatting.swift @@ -18,7 +18,34 @@ enum FormatError: Error { case failure(reason: String) } -func percentEncode(string: String, withAllowedCharacters allowedCharacterSet: CharacterSet, allowPercentEncodedTriplets: Bool) throws -> String { +extension TypedVariableValue { + func formatForTemplateExpansion(variableSpec: VariableSpec, expansionConfiguration configuration: ExpansionConfiguration) throws -> String? { + switch self { + case let .string(plainValue): + return try plainValue.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) + case let .list(arrayValue): + switch variableSpec.modifier { + case .prefix: + throw FormatError.failure(reason: "Prefix operator can only be applied to string") + case .explode: + return try arrayValue.explodeForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) + case .none: + return try arrayValue.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) + } + case let .associativeArray(associativeArrayValue): + switch variableSpec.modifier { + case .prefix: + throw FormatError.failure(reason: "Prefix operator can only be applied to string") + case .explode: + return try associativeArrayValue.explodeForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) + case .none: + return try associativeArrayValue.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration) + } + } + } +} + +private func percentEncode(string: String, withAllowedCharacters allowedCharacterSet: CharacterSet, allowPercentEncodedTriplets: Bool) throws -> String { guard var encoded = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) else { throw FormatError.failure(reason: "Percent Encoding Failed") } @@ -45,7 +72,7 @@ func percentEncode(string: String, withAllowedCharacters allowedCharacterSet: Ch return encoded } -extension StringProtocol { +private extension StringProtocol { func formatForTemplateExpansion(variableSpec: VariableSpec, expansionConfiguration: ExpansionConfiguration) throws -> String { let modifiedValue = if let prefixLength = variableSpec.prefixLength() { String(prefix(prefixLength)) @@ -63,7 +90,7 @@ extension StringProtocol { } } -extension Array where Element: StringProtocol { +private extension Array where Element: StringProtocol { func formatForTemplateExpansion(variableSpec: VariableSpec, expansionConfiguration: ExpansionConfiguration) throws -> String? { let separator = "," let encodedExpansions = try map { element -> String in @@ -101,7 +128,7 @@ extension Array where Element: StringProtocol { } } -extension [TypedVariableValue.AssociativeArrayElement] { +private extension [TypedVariableValue.AssociativeArrayElement] { func formatForTemplateExpansion(variableSpec: VariableSpec, expansionConfiguration: ExpansionConfiguration) throws -> String? { let encodedExpansions = try map { key, value -> String in let encodedKey = try percentEncode(string: String(key), withAllowedCharacters: expansionConfiguration.percentEncodingAllowedCharacterSet, allowPercentEncodedTriplets: expansionConfiguration.allowPercentEncodedTriplets)