@resultBuilder public enum NodeBuilder { public static func buildPartialBlock(first: N) -> N { first } public static func buildPartialBlock( accumulated: N0, next: N1 ) -> _ManyNode { .init([accumulated, next], separator: .empty()) } public static func buildArray(_ components: [N]) -> _ManyNode { .init(components, separator: .empty()) } public static func buildEither( first component: N ) -> N { component } public static func buildEither( second component: N ) -> N { component } public static func buildBlock(_ components: N...) -> _ManyNode { .init(components) } // This breaks things ?? // public static func buildExpression(_ expression: N) -> AnyNode { // expression.eraseToAnyNode() // } public static func buildOptional(_ component: N?) -> _ConditionalNode { switch component { case let .some(node): return .first(node) case .none: return .second(.empty()) } } public static func buildFinalResult(_ component: N) -> N { component } public static func buildLimitedAvailability(_ 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