111 lines
2.5 KiB
Swift
111 lines
2.5 KiB
Swift
@resultBuilder
|
|
public enum NodeBuilder {
|
|
|
|
public static func buildPartialBlock<N: NodeRepresentable>(first: N) -> N {
|
|
first
|
|
}
|
|
|
|
public static func buildPartialBlock<N0: NodeRepresentable, N1: NodeRepresentable>(
|
|
accumulated: N0,
|
|
next: N1
|
|
) -> _ManyNode {
|
|
.init([accumulated, next], separator: .empty())
|
|
}
|
|
|
|
public static func buildArray<N: NodeRepresentable>(_ components: [N]) -> _ManyNode {
|
|
.init(components, separator: .empty())
|
|
}
|
|
|
|
public static func buildEither<N: NodeRepresentable>(
|
|
first component: N
|
|
) -> N {
|
|
component
|
|
}
|
|
|
|
public static func buildEither<N: NodeRepresentable>(
|
|
second component: N
|
|
) -> N {
|
|
component
|
|
}
|
|
|
|
public static func buildBlock<N: NodeRepresentable>(_ components: N...) -> _ManyNode {
|
|
.init(components)
|
|
}
|
|
|
|
// This breaks things ??
|
|
// public static func buildExpression<N: NodeRepresentable>(_ expression: N) -> AnyNode {
|
|
// expression.eraseToAnyNode()
|
|
// }
|
|
|
|
public static func buildOptional<N: NodeRepresentable>(_ component: N?) -> _ConditionalNode<N, Text> {
|
|
switch component {
|
|
case let .some(node):
|
|
return .first(node)
|
|
case .none:
|
|
return .second(.empty())
|
|
}
|
|
}
|
|
|
|
public static func buildFinalResult<N: NodeRepresentable>(_ component: N) -> N {
|
|
component
|
|
}
|
|
|
|
public static func buildLimitedAvailability<N: NodeRepresentable>(_ component: N) -> N {
|
|
component
|
|
}
|
|
|
|
}
|
|
|
|
// These are nodes that are only used by the `NodeBuilder` / internally.
|
|
|
|
// swiftlint:disable type_name
|
|
public enum _ConditionalNode<
|
|
TrueNode: NodeRepresentable,
|
|
FalseNode: NodeRepresentable
|
|
>: NodeRepresentable {
|
|
case first(TrueNode)
|
|
case second(FalseNode)
|
|
|
|
public func render() -> String {
|
|
switch self {
|
|
case let .first(node): return node.render()
|
|
case let .second(node): return node.render()
|
|
}
|
|
}
|
|
}
|
|
|
|
public struct _ManyNode: NodeRepresentable {
|
|
@usableFromInline
|
|
let nodes: [any NodeRepresentable]
|
|
|
|
@usableFromInline
|
|
let separator: any NodeRepresentable
|
|
|
|
@usableFromInline
|
|
init(
|
|
_ nodes: [any NodeRepresentable],
|
|
separator: any NodeRepresentable = "\n" as any NodeRepresentable
|
|
) {
|
|
// Flatten the nodes.
|
|
var allNodes = [any NodeRepresentable]()
|
|
for node in nodes {
|
|
if let many = node as? Self {
|
|
allNodes += many.nodes
|
|
} else {
|
|
allNodes.append(node)
|
|
}
|
|
}
|
|
self.nodes = allNodes
|
|
self.separator = separator
|
|
}
|
|
|
|
@inlinable
|
|
public func render() -> String {
|
|
nodes.map { $0.render() }
|
|
.joined(separator: separator.render())
|
|
}
|
|
|
|
}
|
|
|
|
// swiftlint:enable type_name
|