Files
swift-hpa/Sources/CliDoc/NodeBuilder.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