= Component Template Specification

== Compiled Component Template Code

The following code represents a typical (transpiled) component template:

[source, groovy]
----
package com.jessebrault.website

import groowt.view.component.ComponentTemplate
import groowt.view.component.context.ComponentContext
import groowt.view.component.runtime.*
import groowt.view.web.WebViewComponent
import groowt.view.web.lib.*
import groowt.view.web.runtime.*

class MyComponentTemplate implements ComponentTemplate {

    Closure getRenderer() {
        return { WebViewComponentContext componentContext, ComponentWriter writer -> // <1>
            def renderContext = new DefaultWebViewComponentRenderContext(componentContext, writer) // <2>
            componentContext.setRenderContext(renderContext)
            writer.setRenderContext(renderContext)
            writer.setComponentContext(renderContext)

            writer << 'Hello from simple text!' // <3>
            writer << someProp // <3>
            writer << someMethod() // <3>

            // <4>
            def c0Resolved // <5>
            try {
                c0Resolved = renderContext.resolve('MySubComponent', MySubComponent) // <6>
            } catch (ComponentResolveException c0ResolveException) { // <7>
                c0ResolveException.template = this
                c0ResolveException.line = 1
                c0ResolveException.column = 1
                throw c0ResolveException
            }

            def c0 // <8>
            try {
                c0 = renderContext.create( // <9>
                        c0Resolved, // <10>
                        [greeting: 'Hello, World!'], // <11>
                        ["Some constructor arg"] // <12>
                ) { c0childList -> // <13>
                    c0childList << 'string child.' // <14>

                    def c1Resolved
                    try {
                        c1Resolved = renderContext.resolve('h1') // <15>
                    } catch (ComponentResolveException c1ResolveException) {
                        c1ResolveException.template = this
                        c1ResolveException.line = 1
                        c1ResolveException.column = 10
                        throw c1ResolveException
                    }

                    def c1
                    try {
                        c1 = renderContext.create(c1_resolved) { c1cc ->
                            c1cc << greeting
                        }
                    } catch (ComponentCreateException c1CreateException) {
                        c1CreateException.template = this
                        c1CreateException.line = 1
                        c1CreateException.column = 1
                    }

                    c0childList << c1
                }
            } catch (ComponentCreateException c0CreateException) {
                c0CreateException.template = this
                c0CreateException.line = 1
                c0CreateException.column = 1
                throw c0CreateException
            }

            writer << c0
        }
    }
}
----
<1> The render `Closure` receives a `ComponentContext` and a `ComponentWriter`.
<2> A `RenderContext` is created which is then initialized with the values that the render `Closure` received.
<3> Strings and expressions of every type (except components) are simply left-shifted into the `ComponentWriter`.
<4> Now begins a component 'block', where a component is resolved, created, and eventually left-shifted into either a `ComponentWriter` or a children `List` (see below).
<5> First, we define the `resolved` variable, of the type `ComponentContext.Resolved<WebViewComponent>`.
<6> Resolve it from the context.
<7> If the context cannot resolve the component, it should throw a `ComponentResolveException`. We catch it
    here in order to set the template (`this`), line, and column information for debugging purposes.
<8> Now we can start to create the component by first defining a variable for it.
<9> The create function takes up to four parameters.
<10> The relevant instance of `ComponentContext.Resolved` (required).
<11> Attributes from the component, passed as a `Map` (required; if there are no attributes, an empty `Map` is passed).
<12> Any arguments from the component constructor, passed as a `List` (required; if there are no arguments, an empty `List` is passed).
<13> A `Closure` (optional), which receives an argument of `List` and simply collects the children of the component.
<14> For children, we add the value of the child to the children `List`, rather than appending it directly to `out`.
<15> Here, a string type is passed, since all lowercase type names are treated as string types in web view components.

== Items requiring Groovy ASTNode position adjustment

The following items all need to have their transpiled Groovy ASTNodes' positions adjusted to match the original source
file, in case there is a Groovy compilation error involved.

* JStrings
* GStrings
* Component types (Class and String expressions)
* Attribute keys and values
* Component constructor args
