Skip to content

Commit

Permalink
Support Level 3 Variable Lists
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdeem committed May 1, 2018
1 parent 2f1efdc commit 4062b66
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 20 deletions.
27 changes: 18 additions & 9 deletions Source/Internal/Components.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,34 @@ internal struct LiteralPercentEncodedTripletComponent : Component {

internal struct ExpressionComponent : Component {
let expressionOperator: ExpressionOperator
let variable: Substring
let variableList: [Substring]
let templatePosition: String.Index

init (expressionOperator: ExpressionOperator, variable: Substring, templatePosition: String.Index) {
init (expressionOperator: ExpressionOperator, variableList: [Substring], templatePosition: String.Index) {
self.expressionOperator = expressionOperator
self.variable = variable
self.variableList = variableList
self.templatePosition = templatePosition
}

func expand(variables: [String:String]) throws -> String {
let configuration = expressionOperator.expansionConfiguration()
let variableName = String(variable)
let expansion = variables[variableName] ?? ""
guard let encodedExpansion = expansion.addingPercentEncoding(withAllowedCharacters: configuration.percentEncodingAllowedCharacterSet) else {
throw URITemplate.Error.expansionFailure(position: templatePosition, reason: "Failed expanding variable \"\(variableName)\": Percent Encoding Failed")
let expansions = try variableList.compactMap { variableName -> String? in
guard let value = variables[String(variableName)] else {
return nil;
}
guard let encodedValue = value.addingPercentEncoding(withAllowedCharacters: configuration.percentEncodingAllowedCharacterSet) else {
throw URITemplate.Error.expansionFailure(position: templatePosition, reason: "Failed expanding variable \"\(variableName)\": Percent Encoding Failed")
}
return encodedValue
}
if (expansions.count == 0) {
return ""
}

let joinedExpansions = expansions.joined(separator:configuration.separator)
if let prefix = configuration.prefix {
return prefix + encodedExpansion
return prefix + joinedExpansions
}
return encodedExpansion;
return joinedExpansions;
}
}
1 change: 1 addition & 0 deletions Source/Internal/ExpansionConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ import Foundation
internal struct ExpansionConfiguration {
let percentEncodingAllowedCharacterSet: CharacterSet
let prefix: String?
let separator: String
}
9 changes: 6 additions & 3 deletions Source/Internal/ExpressionOperator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ internal enum ExpressionOperator : Unicode.Scalar {
switch self {
case .simple:
return ExpansionConfiguration(percentEncodingAllowedCharacterSet:unreservedCharacterSet,
prefix:nil)
prefix:nil,
separator:",")
case .reserved:
return ExpansionConfiguration(percentEncodingAllowedCharacterSet:reservedAndUnreservedCharacterSet,
prefix:nil)
prefix:nil,
separator:",")
case .fragment:
return ExpansionConfiguration(percentEncodingAllowedCharacterSet:reservedAndUnreservedCharacterSet,
prefix:"#")
prefix:"#",
separator:",")
}
}
}
37 changes: 29 additions & 8 deletions Source/Internal/Scanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,9 @@ internal struct Scanner {
currentIndex = unicodeScalars.index(after:currentIndex)

let expressionOperator = try scanExpressionOperator()
let variableName = try scanVariableName()
let variableList = try scanVariableList()

if (currentIndex == unicodeScalars.endIndex) {
throw URITemplate.Error.malformedTemplate(position: currentIndex, reason: "Unterminated Expression")
} else if (unicodeScalars[currentIndex] != "}") {
throw URITemplate.Error.malformedTemplate(position: currentIndex, reason: "Unexpected Character in Expression")
}
currentIndex = unicodeScalars.index(after:currentIndex)
return ExpressionComponent(expressionOperator: expressionOperator, variable: variableName, templatePosition: expressionStartIndex)
return ExpressionComponent(expressionOperator: expressionOperator, variableList: variableList, templatePosition: expressionStartIndex)
}

private mutating func scanExpressionOperator() throws -> ExpressionOperator {
Expand All @@ -81,6 +75,33 @@ internal struct Scanner {
return expressionOperator
}

private mutating func scanVariableList() throws -> [Substring] {
var variableList: [Substring] = []

var complete = false
while (!complete) {
let variableName = try scanVariableName()

if (currentIndex == unicodeScalars.endIndex) {
throw URITemplate.Error.malformedTemplate(position: currentIndex, reason: "Unterminated Expression")
}

variableList.append(variableName)

switch unicodeScalars[currentIndex] {
case ",":
currentIndex = unicodeScalars.index(after: currentIndex)
case "}":
currentIndex = unicodeScalars.index(after: currentIndex)
complete = true
default:
throw URITemplate.Error.malformedTemplate(position: currentIndex, reason: "Unexpected Character in Expression")
}
}

return variableList
}

private mutating func scanVariableName() throws -> Substring {
let endIndex = scanUpTo(characterSet: invertedVarnameCharacterSet)
let variableName = string[currentIndex..<endIndex]
Expand Down

0 comments on commit 4062b66

Please sign in to comment.