@@ -10,8 +10,8 @@ class NodeTreeRenderer {
1010 val sceneNodes = scenes.map { renderScene(it) }.joinLines(spacing = 2 )
1111 val types = renderTypes()
1212
13- return listOfNotNull (header, nodeTree, sceneNodes, types)
14- .joinLines(spacing = 2 ).plus(" \n " )
13+ return listOf (header, nodeTree, sceneNodes, types)
14+ .joinLines(spacing = 2 ).trimBlankLines(). plus(" \n " )
1515 }
1616
1717 private fun renderHeader (packageName : String? ): String {
@@ -39,35 +39,25 @@ class NodeTreeRenderer {
3939 private fun renderScene (scene : Scene ): String {
4040 val nodePath = " \$ path/${scene.root.name} "
4141
42- val renderNodeHeader = { type: String ->
43- """
44- |class ${scene.name} Scene(private val path: String) : NodeRef<${type} >("$nodePath ", "$type ")
42+ return when (val root = scene.root) {
43+ is ParentNode -> renderParentNode(
44+ node = root,
45+ nodePath = nodePath,
46+ className = " ${scene.name} Scene" ,
47+ nestedClass = false ,
48+ )
49+
50+ is LeafNode -> """
51+ |class ${scene.name} Scene(private val path: String) : NodeRef<${root.type} >("$nodePath ", "${root.type} ")
4552 """ .trimMargin()
46- }
4753
48- return when (val root = scene.root) {
49- is ParentNode -> {
50- val header = renderNodeHeader(root.type)
51- val children = root.children.map { renderNode(it, nodePath) }.joinLines().indentLine()
52-
53- """
54- |$header {
55- | $children
56- |}
57- """ .trimMargin()
58- }
59-
60- is LeafNode -> renderNodeHeader(root.type)
61-
62- is NestedScene -> {
63- """
64- |class ${scene.name} Scene(private val path: String) : ${root.scene} Scene(path)
65- """ .trimMargin()
66- }
54+ is NestedScene -> """
55+ |class ${scene.name} Scene(private val path: String) : ${root.scene} Scene(path)
56+ """ .trimMargin()
6757 }
6858 }
6959
70- private fun renderNode (node : Node , parentPath : String ): String {
60+ private fun renderNode (node : Node , parentPath : String ): RenderNodeResult {
7161 val nodePath = " $parentPath /${node.name} "
7262 val symbolName = node.name
7363 .split(" \\ s+" .toRegex())
@@ -76,37 +66,70 @@ class NodeTreeRenderer {
7666
7767 Log .renderingNode(node, nodePath)
7868
79- return when (node) {
80- is ParentNode -> {
81- val children = node.children.map { renderNode(it, nodePath) }.joinLines().indentLine()
82-
83- """
84- |val $symbolName = ${symbolName} Tree()
85- |inner class ${symbolName} Tree : NodeRef<${node.type} >("$nodePath ", "${node.type} ") {
86- | $children
87- |}
88- """ .trimMargin()
89- }
90-
91- is LeafNode -> {
92- """
93- |val $symbolName = NodeRef<${node.type} >("$nodePath ", "${node.type} ")
94- """ .trimMargin()
95- }
96-
97- is NestedScene -> {
98- """
99- |val $symbolName = ${node.scene} Scene("$nodePath ")
100- """ .trimMargin()
101- }
69+ val field = when (node) {
70+ is ParentNode -> """
71+ |val $symbolName = ${symbolName} Tree()
72+ """ .trimMargin()
73+
74+ is LeafNode -> """
75+ |val $symbolName = NodeRef<${node.type} >("$nodePath ", "${node.type} ")
76+ """ .trimMargin()
77+
78+ is NestedScene -> """
79+ |val $symbolName = ${node.scene} Scene("$nodePath ")
80+ """ .trimMargin()
81+ }
82+
83+ val nestedClass = when (node) {
84+ is ParentNode -> renderParentNode(
85+ node = node,
86+ nodePath = " $parentPath /${node.name} " ,
87+ className = " ${symbolName} Tree" ,
88+ nestedClass = true ,
89+ )
90+
91+ else -> null
92+ }
93+
94+ return RenderNodeResult (field, nestedClass)
95+ }
96+
97+ private fun renderParentNode (
98+ node : ParentNode ,
99+ nodePath : String ,
100+ className : String ,
101+ nestedClass : Boolean ,
102+ ): String {
103+ val (classType, constructor ) = when (nestedClass) {
104+ true -> " inner class" to " "
105+ false -> " class" to " (private val path: String)"
102106 }
107+ val header = """
108+ |$classType $className$constructor : NodeRef<${node.type} >("$nodePath ", "${node.type} ")
109+ """ .trimMargin()
110+
111+ val children = node.children.map { child -> renderNode(child, nodePath) }
112+ val fields = children.map { it.field }.joinLines().indentLine()
113+ val nestedClasses = children.mapNotNull { it.nestedClass }.joinLines(spacing = 2 ).indentLine()
114+
115+ val body = """
116+ | $fields
117+ |
118+ | $nestedClasses
119+ """ .trimMargin().trimEnd()
120+
121+ return """
122+ |$header {
123+ |$body
124+ |}
125+ """ .trimMargin()
103126 }
104127
105128 private fun renderTypes (): String {
106129 return """
107130 |open class NodeRef<T : Node>(
108- | private val path: String,
109- | private val type: String,
131+ | private val path: String,
132+ | private val type: String,
110133 |) {
111134 | operator fun getValue(thisRef: Node, property: KProperty<*>): T {
112135 | val node = thisRef.getNode(NodePath(path)) ?: throw NodeNotFoundException(path)
@@ -126,3 +149,7 @@ class NodeTreeRenderer {
126149private fun Iterable<String>.joinLines (spacing : Int = 1): String = joinToString(" \n " .repeat(spacing))
127150
128151private fun String.indentLine (times : Int = 1): String = lineSequence().joinToString(" \n " + " " .repeat(times))
152+
153+ private fun String.trimBlankLines (): String = lineSequence().joinToString(" \n " ) { it.ifBlank { " " } }
154+
155+ private data class RenderNodeResult (val field : String , val nestedClass : String? )
0 commit comments