feat: Working on node builder

This commit is contained in:
2024-12-01 17:47:27 -05:00
parent 96a1fac07b
commit 857177032c
6 changed files with 128 additions and 26 deletions

View File

@@ -1,21 +1,34 @@
// TODO: This doesn't seem correct, maybe remove this type.
public struct AnyNode: NodeRepresentable { public struct AnyNode: NodeRepresentable {
@usableFromInline @usableFromInline
let node: any NodeRepresentable let makeBody: @Sendable () -> String
// @usableFromInline
// let node: Value
@inlinable @inlinable
public init<N: NodeRepresentable>(@NodeBuilder _ build: () -> N) { public init<N: NodeRepresentable>(@NodeBuilder _ build: () -> N) {
self.node = build() self.makeBody = build().render
} }
@inlinable @inlinable
public init<N: NodeRepresentable>(_ node: N) { public init<N: NodeRepresentable>(_ node: N) {
self.node = node self.makeBody = node.render
} }
@inlinable
public func render() -> String { public func render() -> String {
node.render() makeBody()
} }
//
// public var body: some NodeRepresentable {
// node
// }
// @inlinable
// public func render() -> String {
// node.render()
// }
} }
public extension NodeRepresentable { public extension NodeRepresentable {

View File

@@ -2,36 +2,62 @@ public struct Group: NodeRepresentable {
@usableFromInline @usableFromInline
let node: any NodeRepresentable let node: any NodeRepresentable
@usableFromInline @inlinable
init( public init(
separator: AnyNode, separator: any NodeRepresentable = " ",
node: any NodeRepresentable @NodeBuilder node: () -> any NodeRepresentable
) { ) {
if let many = node as? _ManyNode { if let many = node as? _ManyNode {
self.node = _ManyNode(many.nodes, separator: separator) self.node = _ManyNode(many.nodes, separator: separator)
} else { } else {
self.node = node self.node = node()
} }
} }
@inlinable // @inlinable
public init( // public init(
separator: any NodeRepresentable, // separator: any NodeRepresentable,
@NodeBuilder _ build: () -> any NodeRepresentable // @NodeBuilder _ build: () -> any NodeRepresentable
) { // ) {
self.init(separator: separator.eraseToAnyNode(), node: build()) // self.init(separator: separator.eraseToAnyNode(), node: build())
} // }
@inlinable // @inlinable
public init( // public init(
separator: String = " ", // separator: String = " ",
@NodeBuilder _ build: () -> any NodeRepresentable // @NodeBuilder _ build: () -> any NodeRepresentable
) { // ) {
self.init(separator: separator.eraseToAnyNode(), node: build()) // self.init(separator: separator.eraseToAnyNode(), node: build())
} // }
@inlinable @inlinable
public func render() -> String { public func render() -> String {
node.render() node.render()
} }
} }
public struct Group2<Content: NodeRepresentable>: Node {
@usableFromInline
let content: Content
@usableFromInline
let separator: any NodeRepresentable
@inlinable
public init(
separator: any NodeRepresentable = " ",
@NodeBuilder _ content: () -> Content
) {
self.content = content()
self.separator = separator
}
@inlinable
public var body: some NodeRepresentable {
guard let content = content as? _ManyNode else {
return content.eraseToAnyNode()
}
return _ManyNode(content.nodes, separator: separator).eraseToAnyNode()
}
}

View File

@@ -44,3 +44,32 @@ public extension LabeledContent {
} }
} }
} }
public struct LabeledContent2<Label: Node, Content: Node>: Node {
@usableFromInline
let separator: any NodeRepresentable
@usableFromInline
let label: Label
@usableFromInline
let content: Content
public init(
separator: any NodeRepresentable = " ",
@NodeBuilder label: () -> Label,
@NodeBuilder content: () -> Content
) {
self.separator = separator
self.label = label()
self.content = content()
}
public var body: some NodeRepresentable {
Group2(separator: separator) {
label
content
}
}
}

View File

@@ -4,3 +4,10 @@ extension String: NodeRepresentable {
self self
} }
} }
extension String: Node {
public var body: some NodeRepresentable {
self
}
}

View File

@@ -1,6 +1,6 @@
@preconcurrency import Rainbow @preconcurrency import Rainbow
public struct Text: NodeRepresentable { public struct Text: Node {
@usableFromInline @usableFromInline
let text: String let text: String
@@ -10,7 +10,7 @@ public struct Text: NodeRepresentable {
} }
@inlinable @inlinable
public func render() -> String { public var body: some NodeRepresentable {
text text
} }
} }

View File

@@ -96,6 +96,23 @@ final class CliDocTests: XCTestCase {
XCTAssert(node.render() == expected) XCTAssert(node.render() == expected)
} }
func testLabeledContent2() {
let node = LabeledContent2 {
"Foo"
} content: {
Text("Bar")
}
// .labelStyle(.green)
// .labelStyle(.bold)
let expected = """
Foo Bar
"""
XCTAssert(node.render() == expected)
print(type(of: node.body))
XCTAssertNotNil(node.body as? _ManyNode)
}
func testShellCommand() { func testShellCommand() {
let node = ShellCommand { let node = ShellCommand {
"ls -lah" "ls -lah"
@@ -126,4 +143,14 @@ final class CliDocTests: XCTestCase {
let foo = Foo() let foo = Foo()
XCTAssertNotNil(foo.body as? LabeledContent) XCTAssertNotNil(foo.body as? LabeledContent)
} }
func testGroup2() {
let node = Group2 {
Text("foo")
Text("bar")
}
print(node.render())
XCTAssertNotNil(node.body as? _ManyNode)
// XCTAssert(false)
}
} }