feat: Working on node builder
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,3 +4,10 @@ extension String: NodeRepresentable {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension String: Node {
|
||||||
|
|
||||||
|
public var body: some NodeRepresentable {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user