@@ -10,8 +10,8 @@ class NodeTreeRenderer {
10
10
val sceneNodes = scenes.map { renderScene(it) }.joinLines(spacing = 2 )
11
11
val types = renderTypes()
12
12
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 " )
15
15
}
16
16
17
17
private fun renderHeader (packageName : String? ): String {
@@ -39,35 +39,25 @@ class NodeTreeRenderer {
39
39
private fun renderScene (scene : Scene ): String {
40
40
val nodePath = " \$ path/${scene.root.name} "
41
41
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} ")
45
52
""" .trimMargin()
46
- }
47
53
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()
67
57
}
68
58
}
69
59
70
- private fun renderNode (node : Node , parentPath : String ): String {
60
+ private fun renderNode (node : Node , parentPath : String ): RenderNodeResult {
71
61
val nodePath = " $parentPath /${node.name} "
72
62
val symbolName = node.name
73
63
.split(" \\ s+" .toRegex())
@@ -76,37 +66,70 @@ class NodeTreeRenderer {
76
66
77
67
Log .renderingNode(node, nodePath)
78
68
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)"
102
106
}
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()
103
126
}
104
127
105
128
private fun renderTypes (): String {
106
129
return """
107
130
|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,
110
133
|) {
111
134
| operator fun getValue(thisRef: Node, property: KProperty<*>): T {
112
135
| val node = thisRef.getNode(NodePath(path)) ?: throw NodeNotFoundException(path)
@@ -126,3 +149,7 @@ class NodeTreeRenderer {
126
149
private fun Iterable<String>.joinLines (spacing : Int = 1): String = joinToString(" \n " .repeat(spacing))
127
150
128
151
private 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