Skip to content

Commit

Permalink
Support processing by directly providing TypedVariableValue
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdeem committed Jun 12, 2024
1 parent 28f4c81 commit f038ca2
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 6 deletions.
10 changes: 5 additions & 5 deletions Sources/ScreamURITemplate/Internal/Components.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Foundation
typealias ComponentBase = Sendable

protocol Component: ComponentBase {
func expand(variables: VariableProvider) throws -> String
func expand(variables: TypedVariableProvider) throws -> String
var variableNames: [String] { get }
}

Expand All @@ -33,7 +33,7 @@ struct LiteralComponent: Component {
literal = string
}

func expand(variables _: VariableProvider) throws -> String {
func expand(variables _: TypedVariableProvider) throws -> String {
let expansion = String(literal)
guard let encodedExpansion = expansion.addingPercentEncoding(withAllowedCharacters: reservedAndUnreservedCharacterSet) else {
throw URITemplate.Error.expansionFailure(position: literal.startIndex, reason: "Percent Encoding Failed")
Expand All @@ -48,7 +48,7 @@ struct LiteralPercentEncodedTripletComponent: Component {
literal = string
}

func expand(variables _: VariableProvider) throws -> String {
func expand(variables _: TypedVariableProvider) throws -> String {
return String(literal)
}
}
Expand All @@ -64,10 +64,10 @@ struct ExpressionComponent: Component {
self.templatePosition = templatePosition
}

func expand(variables: VariableProvider) throws -> String {
func expand(variables: TypedVariableProvider) throws -> String {
let configuration = expressionOperator.expansionConfiguration()
let expansions = try variableList.compactMap { variableSpec -> String? in
guard let value = variables[String(variableSpec.name)]?.asTypedVariableValue() else {
guard let value = variables[String(variableSpec.name)] else {
return nil
}
do {
Expand Down
14 changes: 13 additions & 1 deletion Sources/ScreamURITemplate/URITemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,26 @@ public struct URITemplate {
self.components = components
}

public func process(variables: VariableProvider) throws -> String {
public func process(variables: TypedVariableProvider) throws -> String {
var result = ""
for component in components {
result += try component.expand(variables: variables)
}
return result
}

public func process(variables: VariableProvider) throws -> String {
struct TypedVariableProviderWrapper: TypedVariableProvider {
let variables: VariableProvider

subscript(_ key: String) -> TypedVariableValue? {
return variables[key]?.asTypedVariableValue()
}
}

return try process(variables: TypedVariableProviderWrapper(variables: variables))
}

public func process(variables: [String: String]) throws -> String {
return try process(variables: variables as VariableDictionary)
}
Expand Down
8 changes: 8 additions & 0 deletions Sources/ScreamURITemplate/VariableProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@ public protocol VariableProvider {
subscript(_: String) -> VariableValue? { get }
}

public protocol TypedVariableProvider {
subscript(_: String) -> TypedVariableValue? { get }
}

public typealias VariableDictionary = [String: VariableValue]

extension VariableDictionary: VariableProvider {}

public typealias TypedVariableDictionary = [String: TypedVariableValue]

extension TypedVariableDictionary: TypedVariableProvider {}

public struct SequenceVariableProvider: VariableProvider, ExpressibleByArrayLiteral {
let sequence: any Sequence<VariableProvider>

Expand Down
39 changes: 39 additions & 0 deletions Tests/ScreamURITemplateTests/Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,45 @@ class Tests: XCTestCase {
XCTAssertEqual(urlString, "https://api.example.com/1740A1A9-B3AD-4AE9-954B-918CEDE95285")
}

func testVariableDictionaryVariousTypes() throws {
let template: URITemplate = "https://api.example.com{/string,int,bool,list}{?unordered*,ordered*}"
let variables: VariableDictionary = [
"string": "SwiftScream",
"int": 42,
"bool": true,
"list": ["SwiftScream", 42, true],
"unordered": [
"b": 42,
"a": "A",
"c": true,
],
"ordered": [
"b2": 42,
"a2": "A",
"c2": true,
] as KeyValuePairs,
]
let urlString = try template.process(variables: variables)
XCTAssertEqual("https://api.example.com/SwiftScream/42/true/SwiftScream,42,true?a=A&b=42&c=true&b2=42&a2=A&c2=true", urlString)
}

func testTypedVariableDictionaryVariousTypes() throws {
let template: URITemplate = "https://api.example.com{/string,int,bool,list}{?unordered*,ordered*}"
let variables: TypedVariableDictionary = [
"string": .string("SwiftScream"),
"int": .string("42"),
"bool": .string("true"),
"list": .list(["SwiftScream", "42", "true"]),
"ordered": .associativeArray([
("b", "42"),
("a", "A"),
("c", "true"),
]),
]
let urlString = try template.process(variables: variables)
XCTAssertEqual("https://api.example.com/SwiftScream/42/true/SwiftScream,42,true?b=42&a=A&c=true", urlString)
}

func testSendable() {
let template: URITemplate = "https://api.github.com/repos/{owner}/{repo}/collaborators/{username}"
let sendable = template as Sendable
Expand Down

0 comments on commit f038ca2

Please sign in to comment.