@@ -161,6 +161,253 @@ types:
161161
162162## Generated renderer for a specific type which interprets templates at runtime
163163
164+ Mustachio's first set of generated renderers render objects into
165+ runtime-interpreted Mustache template blocks. Each template block may be the
166+ content of a Mustache template file, a Mustache partial file, or a Mustache
167+ section. The design for a tool which can generate such a renderer is included
168+ after the design for the renderer.
169+
170+ The mechanics of the tool which generates these renderers is a separate concern
171+ from the mechanics of the renderers themselves. This section is primarily
172+ concerned with documenting how the renderers work. At the end, a higher level
173+ description of the code generator can be found.
174+
175+ ### Example types
176+
177+ Any examples in this section will use the following types:
178+
179+ ``` dart
180+ abstract class User {
181+ String get name;
182+ UserProfile get profile;
183+ List<Post>? get posts;
184+ }
185+
186+ abstract class UserProfile {
187+ String get avatarUrl;
188+ String get biography;
189+ }
190+
191+ abstract class Post {
192+ String get title;
193+ String get content;
194+ bool? get isPublished;
195+ }
196+ ```
197+
198+ A User object can be rendered into the following Mustache template:
199+
200+ ``` dart
201+ <h1>{{ name }}</h1>
202+ {{ #profile }}
203+ <img src=”{{ avatarUrl }}” />
204+ <p>{{ biography }}</p>
205+ {{ /profile }}
206+ {{ #posts }}
207+ {{ #isPublished }}
208+ <div>
209+ <h2>{{ title }}</h2>
210+ <p>{{ content }}</h2>
211+ </div>
212+ {{ /isPublished }}
213+ {{ /posts }}
214+ ```
215+
216+ ### Renderer outline
217+
218+ In order to support repeated sections and value sections, a renderer for a type
219+ _ T_ requires renderers for other types:
220+
221+ * If _ T_ has a getter of type _ S_ , then a renderer for type _ T_ may be called
222+ upon to render a [ value section] [ ] for that getter, which requires a renderer
223+ for type _ S_ .
224+ * If _ T_ has a getter of type _ Iterable< ; S>_ for some type _ S_ , then a
225+ renderer for type _ T_ may be called upon to render a repeated section for that
226+ getter, which requires a renderer for type _ S_ .
227+
228+ An instance of a renderer needs four things in order to render an object using a
229+ Mustache syntax tree (a _ template block_ ):
230+
231+ * the context object,
232+ * the Mustache template block (a list of nodes),
233+ * the path to the directory in which the Mustache template is located, in order
234+ to locate partials,
235+ * optionally, a parent renderer
236+
237+ Additionally, a renderer needs various functions in order to render each getter
238+ for the renderer's context type. It may need to render each getter (1) as a
239+ variable, (2) possibly as a conditional section, (3) possibly as a repeated
240+ section, and (4) possibly as a value section).
241+
242+ Here are all of the elements of such a renderer for the User class:
243+
244+ ``` dart
245+ class Renderer_User extends RendererBase<User> {
246+ static final Map<String, Property<CT_>> propertyMap<CT_ extends User>() => ...;
247+
248+ Renderer_User(User context, RendererBase<Object> parent, Template template)
249+ : super(context, parent, template);
250+
251+ @override
252+ Property<User> getProperty(String key) {
253+ if (propertyMap<User>().containsKey(key)) {
254+ return propertyMap<User>()[key];
255+ } else {
256+ return null;
257+ }
258+ }
259+ }
260+ ```
261+
262+ * The base class, ** RendererBase** , provides functionality common to all
263+ renderers, for example a buffer to which output may be written; each of the
264+ methods discussed in [ Rendering a block] [ ] below.
265+ * The map of properties forms the bulk of each individual renderer. The Property
266+ class is described just below.
267+ * The renderer instance may be asked to render multiple blocks; while rendering
268+ a list of nodes, the children of certain nodes are rendered without changing
269+ context, and so can use the same renderer. In particular:
270+ * when rendering a conditional section,
271+ * when rendering an inverted repeated section or inverted value section,
272+ * when rendering a partial.
273+
274+ #### Map of properties
275+
276+ The core functionality of accessing getters on an object by name (as a String)
277+ is a static map of properties for each type which may be used as a context
278+ object during the rendering process. Each getter names is mapped to a Property
279+ object which holds functions that allow performing certain rendering actions
280+ using the given property.
281+
282+ The property map is actually a function because it needs to be type
283+ parameterized on ` CT_ ` , a type variable bounded to the type of the context
284+ object. This is an unfortunate complication which arises from the design of
285+ Property being a collection of functions. Since a renderer can be used to
286+ render _ subtypes_ of the context type, we cannot type all of the functions in
287+ the Properties with the context type; they must each be typed with the runtime
288+ type of the context object.
289+
290+ Here is the Property interface:
291+
292+ ``` dart
293+ class Property<T> {
294+ final Object Function(T context) getValue;
295+ final String Function(T, Property<T>, List<String>) renderVariable;
296+ final bool Function(T context) getBool;
297+ final Iterable<String> Function(T, RendererBase<T>, List<MustachioNode>)
298+ renderIterable;
299+ final bool Function(T) isNullValue;
300+ final String Function(T, RendererBase<T>, List<MustachioNode>) renderValue;
301+ }
302+ ```
303+
304+ For each valid getter on a type, the renderer will map out a Property object
305+ with non-` null ` values for the appropriate functions, and ` null ` values for
306+ inappropriate functions.
307+
308+ ##### The ` getValue ` function
309+
310+ For every valid getter, the Property object will contain a function named
311+ ` getValue ` which calls the getter and returns the result. This function is used
312+ to render a property in a [ variable node] [ ] . For example, the Property for
313+ ` name ` on the User renderer has the following ` getValue ` function:
314+
315+ ``` dart
316+ (CT_ c) => c.name
317+ ```
318+
319+ ##### The ` renderVariable ` function
320+
321+ TODO(srawlins): Write.
322+
323+ ##### The ` getBool ` function
324+
325+ For every valid getter with a ` bool? ` or ` bool ` return type, the Property object
326+ contains a function named ` getBool ` which returns the non-` null ` ` bool ` value of
327+ the getter (` null ` is converted to ` false ` ). This function is used to render a
328+ property in a conditional section node (or an inverted one). For example, the
329+ Property for ` isPublished ` on the Post renderer has the following ` getBool `
330+ function:
331+
332+ ``` dart
333+ (CT_ c) => c.isPublished == true
334+ ```
335+
336+ ##### The ` renderIterable ` function
337+
338+ For every valid getter with a return type assignable to ` Iterable<Object?>? ` ,
339+ the Property object contains a function named ` renderIterable ` which requires
340+ some parameters: the context object, the current renderer, and the AST to
341+ render. This function is used to render a property in a repeated section node
342+ (or an inverted one). For example, the Property for ` posts ` on the User renderer
343+ has the following ` renderIterable ` function:
344+
345+ ``` dart
346+ (CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
347+ return c.posts.map(
348+ (e) => _render_Post(e, ast, r.template, parent: r));
349+ }
350+ ```
351+
352+ This function needs the three arguments so that it can iterate over the ` posts `
353+ of the context object, and then create new instances of the Post renderer, which
354+ requires the AST to render, and the parent context.
355+
356+ ##### The ` isNullValue ` and ` renderValue ` functions
357+
358+ For each valid getter which has neither a ` bool ` return type nor an ` Iterable `
359+ return type, the Property object contains a function named ` isNullValue ` which
360+ returns whether the value of the getter is ` null ` or not. It also contains a
361+ function named ` renderValue ` which requires more parameters: the context object,
362+ the current renderer, and the AST to render. These functions are used to render
363+ a property in a value section node (or an inverted one). For example, the
364+ Property for ` profile ` on the User renderer has the following ` isNullValue `
365+ function:
366+
367+ ``` dart
368+ (CT_ c) => c.profile == null
369+ ```
370+
371+ and ` renderValue ` function:
372+
373+ ``` dart
374+ (CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
375+ return _render_UserProfile(c.profile, ast, r.template, parent: r);
376+ }
377+ ```
378+
379+ The ` renderValue ` function needs the three arguments so that it can render the
380+ property value using a new ` UserProfile ` renderer, which requires the AST to
381+ render, and the parent context.
382+
383+ #### Rendering a block
384+
385+ TODO(srawlins): Write.
386+
387+ #### Resolving a variable key
388+
389+ TODO(srawlins): Write.
390+
391+ #### Rendering a section
392+
393+ TODO(srawlins): Write.
394+
395+ ##### Conditional section
396+
397+ ##### Repeated section
398+
399+ ##### Value section
400+
401+ #### Rendering a partial
402+
403+ TODO(srawlins): Write.
404+
405+ [ value section ] : https://mustache.github.io/mustache.5.html#Sections
406+ [ Rendering a block ] : #rendering-a-block
407+ [ variable node ] : https://mustache.github.io/mustache.5.html#Variables
408+
409+ ### High level design for generating renderers
410+
164411TODO(srawlins): Write.
165412
166413## Generated renderer for a specific type and a static template which pre-compiles the templates
0 commit comments