Skip to content

Commit c067a24

Browse files
committed
Add map APIs to variant collection types
Adds map APIs to variant collection types to facilitate transforming the value contained in variant collections.
1 parent 20c2894 commit c067a24

File tree

6 files changed

+162
-20
lines changed

6 files changed

+162
-20
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2022 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See https://swift.org/LICENSE.txt for license information
8+
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import Foundation
12+
13+
public extension VariantCollection {
14+
/// A variant for a render node value.
15+
struct Variant<Value: Codable> {
16+
/// The traits associated with the override.
17+
public var traits: [RenderNode.Variant.Trait]
18+
19+
/// The patch to apply as part of the override.
20+
public var patch: [VariantPatchOperation<Value>]
21+
22+
/// Creates an override value for the given traits.
23+
///
24+
/// - Parameters:
25+
/// - traits: The traits associated with this override value.
26+
/// - patch: The patch to apply as part of the override.
27+
public init(traits: [RenderNode.Variant.Trait], patch: [VariantPatchOperation<Value>]) {
28+
self.traits = traits
29+
self.patch = patch
30+
}
31+
32+
/// Returns a new variant collection containing the traits of this variant collection with the values transformed by the given closure.
33+
public func mapPatch<TransformedValue>(
34+
_ transform: (Value) -> TransformedValue
35+
) -> VariantCollection<TransformedValue>.Variant<TransformedValue> {
36+
VariantCollection<TransformedValue>.Variant<TransformedValue>(
37+
traits: traits,
38+
patch: patch.map { patchOperation in patchOperation.map(transform) }
39+
)
40+
}
41+
}
42+
}

Sources/SwiftDocC/Model/Rendering/Variants/VariantCollection.swift

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,16 @@ public struct VariantCollection<Value: Codable>: Codable {
9191

9292
encoder.userInfoVariantOverrides?.add(contentsOf: overrides)
9393
}
94-
}
95-
96-
public extension VariantCollection {
97-
/// A variant for a render node value.
98-
struct Variant<Value: Codable> {
99-
/// The traits associated with the override.
100-
public var traits: [RenderNode.Variant.Trait]
101-
102-
/// The patch to apply as part of the override.
103-
public var patch: [VariantPatchOperation<Value>]
104-
105-
/// Creates an override value for the given traits.
106-
///
107-
/// - Parameters:
108-
/// - traits: The traits associated with this override value.
109-
/// - patch: The patch to apply as part of the override.
110-
public init(traits: [RenderNode.Variant.Trait], patch: [VariantPatchOperation<Value>]) {
111-
self.traits = traits
112-
self.patch = patch
113-
}
94+
95+
/// Returns a variant collection containing the results of calling the given transformation with each value of this variant collection.
96+
public func mapValues<TransformedValue>(
97+
_ transform: (Value) -> TransformedValue
98+
) -> VariantCollection<TransformedValue> {
99+
VariantCollection<TransformedValue>(
100+
defaultValue: transform(defaultValue),
101+
variants: variants.map { variant in
102+
variant.mapPatch(transform)
103+
}
104+
)
114105
}
115106
}

Sources/SwiftDocC/Model/Rendering/Variants/VariantPatchOperation.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ public enum VariantPatchOperation<Value: Codable> {
1717
/// - Parameter value: The value to use in the replacement.
1818
case replace(value: Value)
1919

20+
/// An addition operation.
21+
///
22+
/// - Parameter value: The value to use in the addition.
2023
case add(value: Value)
2124

2225
/// A removal operation.
@@ -33,6 +36,24 @@ public enum VariantPatchOperation<Value: Codable> {
3336
return .remove
3437
}
3538
}
39+
40+
/// Returns a new patch operation with its value transformed using the given closure.
41+
///
42+
/// If the patch operation doesn't have a value—for example, if it's a removal operation—the operation is returned unmodified.
43+
func map<TransformedValue>(
44+
_ transform: (Value) -> TransformedValue
45+
) -> VariantPatchOperation<TransformedValue> {
46+
switch self {
47+
case .replace(let value):
48+
return VariantPatchOperation<TransformedValue>.replace(value: transform(value))
49+
50+
case .add(let value):
51+
return VariantPatchOperation<TransformedValue>.add(value: transform(value))
52+
53+
case .remove:
54+
return .remove
55+
}
56+
}
3657
}
3758

3859
extension VariantCollection.Variant where Value: RangeReplaceableCollection {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2022 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See https://swift.org/LICENSE.txt for license information
8+
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import Foundation
12+
import XCTest
13+
@testable import SwiftDocC
14+
15+
class VariantCollection_VariantTests: XCTestCase {
16+
let testVariant = VariantCollection<String>.Variant<String>(
17+
traits: [.interfaceLanguage("a")],
18+
patch: [
19+
.replace(value: "replace"),
20+
.add(value: "add"),
21+
.remove,
22+
]
23+
)
24+
25+
func testMapPatch() throws {
26+
XCTAssertEqual(
27+
testVariant.mapPatch { "\($0) transformed" }.patch.map(\.value),
28+
["replace transformed", "add transformed", nil]
29+
)
30+
}
31+
}
32+
33+
private extension VariantPatchOperation {
34+
var value: Value? {
35+
switch self {
36+
case let .replace(value):
37+
return value
38+
case let .add(value):
39+
return value
40+
case .remove:
41+
return nil
42+
}
43+
}
44+
}

Tests/SwiftDocCTests/Rendering/Variants/VariantCollectionTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,23 @@ class VariantCollectionTests: XCTestCase {
7474
XCTAssertEqual(value.value as! String, expectedValue)
7575
}
7676
}
77+
78+
func testMapValues() {
79+
let testCollection = testCollection.mapValues { value -> String? in
80+
if value == "default value" {
81+
return "default value transformed"
82+
}
83+
84+
return nil
85+
}
86+
87+
XCTAssertEqual(testCollection.defaultValue, "default value transformed")
88+
89+
guard case .replace(let value)? = testCollection.variants.first?.patch.first else {
90+
XCTFail()
91+
return
92+
}
93+
94+
XCTAssertNil(value)
95+
}
7796
}

Tests/SwiftDocCTests/Rendering/Variants/VariantPatchOperationTests.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,29 @@ class VariantPatchOperationTests: XCTestCase {
6666
XCTAssertEqual(stringVariant.applyingPatchTo("A"), expectedValue)
6767
}
6868
}
69+
70+
func testMap() throws {
71+
let transform: (String) -> String = { "\($0) transformed" }
72+
let replace = VariantPatchOperation<String>.replace(value: "replace")
73+
guard case .replace(let value) = replace.map(transform) else {
74+
XCTFail("Expected replace operation")
75+
return
76+
}
77+
78+
XCTAssertEqual(value, "replace transformed")
79+
80+
let add = VariantPatchOperation<String>.add(value: "add")
81+
guard case .add(let value) = add.map(transform) else {
82+
XCTFail("Expected add operation")
83+
return
84+
}
85+
86+
XCTAssertEqual(value, "add transformed")
87+
88+
let remove = VariantPatchOperation<String>.remove.map(transform)
89+
guard case .remove = remove else {
90+
XCTFail("Expected remove operation")
91+
return
92+
}
93+
}
6994
}

0 commit comments

Comments
 (0)