TEMPLATE · STATIC RENDER PROOF

Template execution lab

The shared source is parsed before this page is built. AST mode executes the committed nodes; generated mode lowers those same nodes into host-language renderers. Both modes use the same assign, define and output contract.

Cross-language proofPASS
AST modeIMPLEMENTED
Generated mode5 LANGUAGES
Page validationHTML

03 · NATIVE VALUES

Assign keeps the host instance

A class instance passed through assign stays that instance. The template reads a public field, calls the instance method and calls a separately registered logical class function.

template
<article><h1>{= order.label}</h1><p>{= order.status_label("ready")}</p><p>{= Order::suffix("!")}</p></article>
host assign
class Order { public label = 'Order 12'; public status_label(prefix) { return prefix + ':12'; } }
const assign = { order: new Order() };

Rendered output · 64 bytes · 5f94e0e9fe74…

<article><h1>Order 12</h1><p>ready:12</p><p>done!</p></article>

01 · EVIDENCE

Same bytes from AST mode

Source parsing occurs during the build. Runtime checks load the committed artifacts, apply assign and define, and compare UTF-8 output bytes. Generated mode must produce the same bytes before it can be enabled for a language.

ScenarioBytesSHA-256tsgorustphppython
compiler-coverage351f9e5af2122de…PASSPASSPASSPASSPASS
empty-state78d98cc268d4c4…PASSPASSPASSPASSPASS
html-slot111b1fc22f8d29c…PASSPASSPASSPASSPASS
react-boundary1244c247742a44e…PASSPASSPASSPASSPASS
scope-precedence1777b160d439d3d…PASSPASSPASSPASSPASS

02 · INPUT AND OUTPUT

Small SSR situations

Each card shows the exact assign data, define map, every template file, compiled artifact manifest and final HTML.

Generated compiler coverage

One readable page executes every canonical statement and expression family through AST and generated modes.

expressionsloops and loop metadatainclude scopedefine and block scope

Inputs

assign
{
  "flag": true,
  "dangerous": "&<>\"'",
  "empty_list": [],
  "empty_map": {},
  "page": {
    "title": "Guide"
  },
  "numbers": [
    10,
    20
  ],
  "lookup": {
    "x": "X"
  },
  "rows": [
    {
      "name": "A"
    },
    {
      "name": "B"
    }
  ]
}
define
{
  "layout": "layout.tpl",
  "content": {
    "template": "card.tpl",
    "data": {
      "label": "define"
    }
  }
}
templates · parser ranges
--- card.tpl
<p class="card">{= label}</p>


--- layout.tpl
{: values = [0, ...numbers]}
{: merged = [...lookup, 'z' => 'Z']}
<section>
<h1>{= page.title}</h1>
<p class="escaped">{= dangerous}</p>
<p class="logical">{= flag && 'x'}|{= false || 2}</p>
<p class="empty-truthiness">{= empty_list && flag}|{= empty_map && flag}</p>
<p>{= values[1]}|{= merged['z']}</p>
{? flag && page.title == 'Guide'}<strong>matched</strong>{:}<strong>missed</strong>{/}
<p>{= flag ? 'yes' : 'no'}|{= -1 + 3}|{= '' | default('fallback')}</p>
<ul>
{@ row = rows}
<li>{= row.index_}/{= row.size_}:{= row.name}:{= row.first_}:{= row.last_}</li>
{:}
<li>empty</li>
{/}
</ul>
{+ partial.tpl}
{?# content}<p>defined</p>{:}<p>missing</p>{/}
{# content label:page.title}
</section>


--- partial.tpl
<p class="included">{= values[2]}</p>
compiled artifacts
ast/manifest.json
{
  "schema": 3,
  "mode": "ast",
  "target": "canonical",
  "entry": "layout.tpl",
  "delimiters": null,
  "sourceDigest": "936a20a5f3b77bc8a454a40c57b55de1118203b69a39aedda5acb0455f495625",
  "typeDigest": "30c0b093d1694670ec7117cc02b36e0031780485e6218be94afbdf1be6524db7",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "fb8049870573426dd093e2af0cf544e3592477ef1af415453fafcf71f0389901",
  "files": {
    "card.tpl": {
      "path": "card.tpl.ast.json",
      "sourceDigest": "d299dda7918a928780ca472de4e9ae7a7e4f75367f9086362e90b17f358318bc",
      "artifactDigest": "b7d21b8c69cb2d1792c64260271e4822970a4a5c816966d3a0c8d5d074851579",
      "lines": [
        0,
        30
      ]
    },
    "layout.tpl": {
      "path": "layout.tpl.ast.json",
      "sourceDigest": "1ba56a9e17866570e7f4c48301edecc53a4151e0659a2bf2820db0c014c1836b",
      "artifactDigest": "2405af019355de6872b618c0264321380cab02c6fc5e80224c5ed80c15fd4b83",
      "lines": [
        0,
        29,
        66,
        76,
        100,
        137,
        191,
        268,
        305,
        392,
        463,
        468,
        483,
        563,
        567,
        582,
        586,
        592,
        608,
        655,
        684,
        695
      ]
    },
    "partial.tpl": {
      "path": "partial.tpl.ast.json",
      "sourceDigest": "12756a90a2a53d5fe389cce876f6ce983af348dc3353acfe1ec92174feec491b",
      "artifactDigest": "5a4d52cc6b5d74cc6afc476f64a71acb907c53262895e145b325ee35799c3743",
      "lines": [
        0,
        38
      ]
    }
  }
}

ast/card.tpl.ast.json · card.tpl
{
  "type": "Template",
  "name": "card.tpl",
  "body": [
    {
      "type": "Text",
      "value": "<p class=\"card\">",
      "span": [
        0,
        16
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Var",
        "name": "label",
        "span": [
          19,
          24
        ]
      },
      "span": [
        16,
        25
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n",
      "span": [
        25,
        30
      ]
    }
  ],
  "comments": []
}


ast/layout.tpl.ast.json · layout.tpl
{
  "type": "Template",
  "name": "layout.tpl",
  "body": [
    {
      "type": "Set",
      "name": "values",
      "expr": {
        "type": "List",
        "items": [
          {
            "type": "Literal",
            "kind": "number",
            "value": 0,
            "span": [
              13,
              14
            ]
          },
          {
            "type": "Spread",
            "expr": {
              "type": "Var",
              "name": "numbers",
              "span": [
                19,
                26
              ]
            },
            "span": [
              16,
              26
            ]
          }
        ],
        "span": [
          12,
          27
        ]
      },
      "span": [
        0,
        28
      ]
    },
    {
      "type": "Set",
      "name": "merged",
      "expr": {
        "type": "Map",
        "entries": [
          {
            "type": "Spread",
            "expr": {
              "type": "Var",
              "name": "lookup",
              "span": [
                45,
                51
              ]
            },
            "span": [
              42,
              51
            ]
          },
          {
            "key": {
              "type": "Literal",
              "kind": "string",
              "value": "z",
              "span": [
                53,
                56
              ]
            },
            "value": {
              "type": "Literal",
              "kind": "string",
              "value": "Z",
              "span": [
                60,
                63
              ]
            }
          }
        ],
        "span": [
          41,
          64
        ]
      },
      "span": [
        29,
        65
      ]
    },
    {
      "type": "Text",
      "value": "<section>\n<h1>",
      "span": [
        66,
        80
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Member",
        "object": {
          "type": "Var",
          "name": "page",
          "span": [
            83,
            87
          ]
        },
        "key": "title",
        "span": [
          83,
          93
        ]
      },
      "span": [
        80,
        94
      ]
    },
    {
      "type": "Text",
      "value": "</h1>\n<p class=\"escaped\">",
      "span": [
        94,
        119
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Var",
        "name": "dangerous",
        "span": [
          122,
          131
        ]
      },
      "span": [
        119,
        132
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n<p class=\"logical\">",
      "span": [
        132,
        156
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Binary",
        "op": "&&",
        "left": {
          "type": "Var",
          "name": "flag",
          "span": [
            159,
            163
          ]
        },
        "right": {
          "type": "Literal",
          "kind": "string",
          "value": "x",
          "span": [
            167,
            170
          ]
        },
        "span": [
          159,
          170
        ]
      },
      "span": [
        156,
        171
      ]
    },
    {
      "type": "Text",
      "value": "|",
      "span": [
        171,
        172
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Binary",
        "op": "||",
        "left": {
          "type": "Literal",
          "kind": "bool",
          "value": false,
          "span": [
            175,
            180
          ]
        },
        "right": {
          "type": "Literal",
          "kind": "number",
          "value": 2,
          "span": [
            184,
            185
          ]
        },
        "span": [
          175,
          185
        ]
      },
      "span": [
        172,
        186
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n<p class=\"empty-truthiness\">",
      "span": [
        186,
        219
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Binary",
        "op": "&&",
        "left": {
          "type": "Var",
          "name": "empty_list",
          "span": [
            222,
            232
          ]
        },
        "right": {
          "type": "Var",
          "name": "flag",
          "span": [
            236,
            240
          ]
        },
        "span": [
          222,
          240
        ]
      },
      "span": [
        219,
        241
      ]
    },
    {
      "type": "Text",
      "value": "|",
      "span": [
        241,
        242
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Binary",
        "op": "&&",
        "left": {
          "type": "Var",
          "name": "empty_map",
          "span": [
            245,
            254
          ]
        },
        "right": {
          "type": "Var",
          "name": "flag",
          "span": [
            258,
            262
          ]
        },
        "span": [
          245,
          262
        ]
      },
      "span": [
        242,
        263
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n<p>",
      "span": [
        263,
        271
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Index",
        "object": {
          "type": "Var",
          "name": "values",
          "span": [
            274,
            280
          ]
        },
        "index": {
          "type": "Literal",
          "kind": "number",
          "value": 1,
          "span": [
            281,
            282
          ]
        },
        "span": [
          274,
          283
        ]
      },
      "span": [
        271,
        284
      ]
    },
    {
      "type": "Text",
      "value": "|",
      "span": [
        284,
        285
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Index",
        "object": {
          "type": "Var",
          "name": "merged",
          "span": [
            288,
            294
          ]
        },
        "index": {
          "type": "Literal",
          "kind": "string",
          "value": "z",
          "span": [
            295,
            298
          ]
        },
        "span": [
          288,
          299
        ]
      },
      "span": [
        285,
        300
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n",
      "span": [
        300,
        305
      ]
    },
    {
      "type": "If",
      "branches": [
        {
          "test": {
            "type": "Binary",
            "op": "&&",
            "left": {
              "type": "Var",
              "name": "flag",
              "span": [
                308,
                312
              ]
            },
            "right": {
              "type": "Binary",
              "op": "==",
              "left": {
                "type": "Member",
                "object": {
                  "type": "Var",
                  "name": "page",
                  "span": [
                    316,
                    320
                  ]
                },
                "key": "title",
                "span": [
                  316,
                  326
                ]
              },
              "right": {
                "type": "Literal",
                "kind": "string",
                "value": "Guide",
                "span": [
                  330,
                  337
                ]
              },
              "span": [
                316,
                337
              ]
            },
            "span": [
              308,
              337
            ]
          },
          "body": [
            {
              "type": "Text",
              "value": "<strong>matched</strong>",
              "span": [
                338,
                362
              ]
            }
          ],
          "span": [
            305,
            338
          ]
        }
      ],
      "else": [
        {
          "type": "Text",
          "value": "<strong>missed</strong>",
          "span": [
            365,
            388
          ]
        }
      ],
      "span": [
        305,
        391
      ]
    },
    {
      "type": "Text",
      "value": "\n<p>",
      "span": [
        391,
        395
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Ternary",
        "test": {
          "type": "Var",
          "name": "flag",
          "span": [
            398,
            402
          ]
        },
        "then": {
          "type": "Literal",
          "kind": "string",
          "value": "yes",
          "span": [
            405,
            410
          ]
        },
        "else": {
          "type": "Literal",
          "kind": "string",
          "value": "no",
          "span": [
            413,
            417
          ]
        },
        "span": [
          398,
          417
        ]
      },
      "span": [
        395,
        418
      ]
    },
    {
      "type": "Text",
      "value": "|",
      "span": [
        418,
        419
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Binary",
        "op": "+",
        "left": {
          "type": "Unary",
          "op": "-",
          "operand": {
            "type": "Literal",
            "kind": "number",
            "value": 1,
            "span": [
              423,
              424
            ]
          },
          "span": [
            422,
            424
          ]
        },
        "right": {
          "type": "Literal",
          "kind": "number",
          "value": 3,
          "span": [
            427,
            428
          ]
        },
        "span": [
          422,
          428
        ]
      },
      "span": [
        419,
        429
      ]
    },
    {
      "type": "Text",
      "value": "|",
      "span": [
        429,
        430
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Call",
        "name": "default",
        "args": [
          {
            "type": "Literal",
            "kind": "string",
            "value": "",
            "span": [
              433,
              435
            ]
          },
          {
            "type": "Literal",
            "kind": "string",
            "value": "fallback",
            "span": [
              446,
              456
            ]
          }
        ],
        "span": [
          433,
          457
        ]
      },
      "span": [
        430,
        458
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n<ul>\n",
      "span": [
        458,
        468
      ]
    },
    {
      "type": "For",
      "name": "row",
      "iter": {
        "type": "Var",
        "name": "rows",
        "span": [
          477,
          481
        ]
      },
      "body": [
        {
          "type": "Text",
          "value": "<li>",
          "span": [
            483,
            487
          ]
        },
        {
          "type": "Echo",
          "expr": {
            "type": "LoopMeta",
            "loop": "row",
            "field": "index_",
            "span": [
              490,
              500
            ]
          },
          "span": [
            487,
            501
          ]
        },
        {
          "type": "Text",
          "value": "/",
          "span": [
            501,
            502
          ]
        },
        {
          "type": "Echo",
          "expr": {
            "type": "LoopMeta",
            "loop": "row",
            "field": "size_",
            "span": [
              505,
              514
            ]
          },
          "span": [
            502,
            515
          ]
        },
        {
          "type": "Text",
          "value": ":",
          "span": [
            515,
            516
          ]
        },
        {
          "type": "Echo",
          "expr": {
            "type": "Member",
            "object": {
              "type": "Var",
              "name": "row",
              "span": [
                519,
                522
              ]
            },
            "key": "name",
            "span": [
              519,
              527
            ]
          },
          "span": [
            516,
            528
          ]
        },
        {
          "type": "Text",
          "value": ":",
          "span": [
            528,
            529
          ]
        },
        {
          "type": "Echo",
          "expr": {
            "type": "LoopMeta",
            "loop": "row",
            "field": "first_",
            "span": [
              532,
              542
            ]
          },
          "span": [
            529,
            543
          ]
        },
        {
          "type": "Text",
          "value": ":",
          "span": [
            543,
            544
          ]
        },
        {
          "type": "Echo",
          "expr": {
            "type": "LoopMeta",
            "loop": "row",
            "field": "last_",
            "span": [
              547,
              556
            ]
          },
          "span": [
            544,
            557
          ]
        },
        {
          "type": "Text",
          "value": "</li>\n",
          "span": [
            557,
            563
          ]
        }
      ],
      "empty": [
        {
          "type": "Text",
          "value": "<li>empty</li>\n",
          "span": [
            567,
            582
          ]
        }
      ],
      "span": [
        468,
        585
      ]
    },
    {
      "type": "Text",
      "value": "</ul>\n",
      "span": [
        586,
        592
      ]
    },
    {
      "type": "Include",
      "path": "partial.tpl",
      "span": [
        592,
        607
      ]
    },
    {
      "type": "IfBlock",
      "id": "content",
      "body": [
        {
          "type": "Text",
          "value": "<p>defined</p>",
          "span": [
            620,
            634
          ]
        }
      ],
      "else": [
        {
          "type": "Text",
          "value": "<p>missing</p>",
          "span": [
            637,
            651
          ]
        }
      ],
      "span": [
        608,
        654
      ]
    },
    {
      "type": "Text",
      "value": "\n",
      "span": [
        654,
        655
      ]
    },
    {
      "type": "Block",
      "id": "content",
      "path": null,
      "scope": [
        {
          "name": "label",
          "expr": {
            "type": "Member",
            "object": {
              "type": "Var",
              "name": "page",
              "span": [
                672,
                676
              ]
            },
            "key": "title",
            "span": [
              672,
              682
            ]
          }
        }
      ],
      "span": [
        655,
        683
      ]
    },
    {
      "type": "Text",
      "value": "</section>\n",
      "span": [
        684,
        695
      ]
    }
  ],
  "comments": []
}


ast/partial.tpl.ast.json · partial.tpl
{
  "type": "Template",
  "name": "partial.tpl",
  "body": [
    {
      "type": "Text",
      "value": "<p class=\"included\">",
      "span": [
        0,
        20
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Index",
        "object": {
          "type": "Var",
          "name": "values",
          "span": [
            23,
            29
          ]
        },
        "index": {
          "type": "Literal",
          "kind": "number",
          "value": 2,
          "span": [
            30,
            31
          ]
        },
        "span": [
          23,
          32
        ]
      },
      "span": [
        20,
        33
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n",
      "span": [
        33,
        38
      ]
    }
  ],
  "comments": []
}
generated renderers
typescript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "ts",
  "entry": "layout.tpl",
  "sourceDigest": "936a20a5f3b77bc8a454a40c57b55de1118203b69a39aedda5acb0455f495625",
  "typeDigest": "30c0b093d1694670ec7117cc02b36e0031780485e6218be94afbdf1be6524db7",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "a81f5f0f977b099b35dd1267160848c835a8aaf7c6865ac99d066a351070cbb0",
  "files": {
    "compiler-coverage.ts": {
      "path": "compiler-coverage.ts",
      "artifactDigest": "da324a1e34bb870912a374e84d431ff54ca44354eed16a85e02e4dc0632dcbac"
    }
  }
}

// Generated.
import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary, type MapValue, type PreparedRender, type Program, type RenderOptions, type Span, type Template, type Value } from '@polyspec/template';
export interface Page {
  title: string;
}
export interface Row {
  name: string;
}
export interface Slot {
  template: string | null;
  html: string | null;
}
export interface Assign {
  flag: boolean;
  dangerous: string;
  empty_list: Array<string>;
  empty_map: Map<string, string>;
  page: Page;
  numbers: Array<number>;
  lookup: Map<string, string>;
  rows: Array<Row>;
}
export interface Input_card_tpl { label: string; }
export interface Input_layout_tpl {  }
export interface Input_partial_tpl { values: Array<number>; }
export type DefinitionData<T> = Partial<T>;
export interface Definition<T> { template?: string; html?: string; data?: DefinitionData<T>; }
export interface Definitions { content?: Definition<Input_card_tpl>; layout?: Definition<Input_layout_tpl>; }
export interface ArtifactManifest { schema: number; mode: 'gen'; target: 'ts'; entry: string; sourceDigest: string; typeDigest: string; contractDigest: string; files: Record<string, string>; }
type GeneratedDecoder<T> = (value: Value | undefined, path: string) => T;
function generatedTypeError(value: Value | undefined, path: string, expected: string): Error { return new Error(value === null || value === undefined ? path + ' is required' : path + ' is not ' + expected); }
function generatedChecked<T>(decode: GeneratedDecoder<T>, value: Value, path: string, runtime: RuntimeBindings, frame: Frame, span: Span): T { try { return decode(value, path); } catch (error) { if (error instanceof Error) throw runtime.error(frame, span, 'E_RUNTIME_TYPE', error.message); throw error; } }
function generatedDataObject(value: Value, path: string): MapValue { if (value instanceof Map) return value; throw new Error(path + ' is not an object'); }
function generatedPlain(value: unknown): value is object { if (typeof value !== 'object' || value === null) return false; const prototype = Reflect.getPrototypeOf(value); return prototype === Object.prototype || prototype === null; }
function generatedObject(value: Value | undefined, path: string): MapValue { if (value instanceof Map) return value; throw generatedTypeError(value, path, 'an object'); }
function generatedString(value: Value | undefined, path: string): string { if (typeof value === 'string') return value; throw generatedTypeError(value, path, 'a string'); }
function generatedNumber(value: Value | undefined, path: string): number { if (typeof value === 'number') return value; throw generatedTypeError(value, path, 'a number'); }
function generatedBoolean(value: Value | undefined, path: string): boolean { if (typeof value === 'boolean') return value; throw generatedTypeError(value, path, 'a boolean'); }
function generatedOptional<T>(decode: GeneratedDecoder<T>): GeneratedDecoder<T | null> { return (value, path) => value === null || value === undefined ? null : decode(value, path); }
function generatedListOf<T>(item: GeneratedDecoder<T>): GeneratedDecoder<T[]> { return (value, path) => { if (Array.isArray(value)) return value.map((element, index) => item(element, path + '[' + index + ']')); throw generatedTypeError(value, path, 'a list'); }; }
function generatedMapOf<T>(item: GeneratedDecoder<T>): GeneratedDecoder<Map<string, T>> { return (value, path) => new Map([...generatedObject(value, path)].map(([key, element]): [string, T] => [key, item(element, path + '.' + key)])); }
function generatedEntries<T>(value: T[] | Map<string, T> | null): [Value, T][] { if (value === null) return []; if (Array.isArray(value)) return value.map((item, index): [Value, T] => [index, item]); return [...value]; }
function generatedDecode_Page(value: Value | undefined, path: string): Page { const object = generatedObject(value, path); return { title: generatedString(object.get("title"), path + ".title") }; }
function generatedDecode_Row(value: Value | undefined, path: string): Row { const object = generatedObject(value, path); return { name: generatedString(object.get("name"), path + ".name") }; }
function generatedEncode_Row(value: Row): Value { return new Map<string, Value>([["name", value.name]]); }
function generatedDecodeAssign(value: Value | undefined, path: string): Assign { const object = generatedObject(value, path); return { flag: generatedBoolean(object.get("flag"), path + ".flag"), dangerous: generatedString(object.get("dangerous"), path + ".dangerous"), empty_list: generatedListOf(generatedString)(object.get("empty_list"), path + ".empty_list"), empty_map: generatedMapOf(generatedString)(object.get("empty_map"), path + ".empty_map"), page: generatedDecode_Page(object.get("page"), path + ".page"), numbers: generatedListOf(generatedNumber)(object.get("numbers"), path + ".numbers"), lookup: generatedMapOf(generatedString)(object.get("lookup"), path + ".lookup"), rows: generatedListOf(generatedDecode_Row)(object.get("rows"), path + ".rows") }; }
function generatedDecodeData_Input_card_tpl(value: Value, path: string): DefinitionData<Input_card_tpl> { const object = generatedDataObject(value, path); const data: DefinitionData<Input_card_tpl> = {}; if (object.has("label")) data.label = generatedString(object.get("label"), path + ".label"); return data; }
function generatedDecodeData_Input_layout_tpl(value: Value, path: string): DefinitionData<Input_layout_tpl> { generatedDataObject(value, path); return {}; }
function generatedBindAssign(value: unknown): { assign: Assign; root: MapValue } { const root = bindMap(value); return { assign: generatedDecodeAssign(root, 'assign'), root }; }
type GeneratedTarget = { target: string | null; html?: string };
type GeneratedBoundDefinitions = { definitions: Definitions; targets: Map<string, GeneratedTarget> };
function generatedBindDefinitions(input: unknown): GeneratedBoundDefinitions {
  const definitions: Definitions = {};
  const targets = new Map<string, GeneratedTarget>();
  if (input === undefined || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error('define is not an object');
  const entries: [string, unknown][] = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
    case "content": {
      if (typeof raw === 'string') {
        if (raw !== "card.tpl") throw new Error("define.content has an invalid template");
        definitions.content = { template: "card.tpl" }; targets.set("content", { target: "card.tpl" }); break;
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.content is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        if (template !== undefined || data !== undefined) throw new Error("define.content has an invalid html entry");
        definitions.content = { html }; targets.set("content", { target: null, html }); break;
      }
      if (template !== "card.tpl") throw new Error("define.content has an invalid template");
      definitions.content = { template: "card.tpl", data: data === undefined ? {} : generatedDecodeData_Input_card_tpl(data, "define.content.data") }; targets.set("content", { target: "card.tpl" }); break;
    }
    case "layout": {
      if (typeof raw === 'string') {
        if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl" }; targets.set("layout", { target: "layout.tpl" }); break;
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.layout is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        throw new Error("define.layout has an invalid html entry");
      }
      if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
      definitions.layout = { template: "layout.tpl", data: data === undefined ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") }; targets.set("layout", { target: "layout.tpl" }); break;
    }
    default: throw new Error('define.' + id + ' is not declared');
    }
  }
  return { definitions, targets };
}
function render_card_tpl(_assign: Assign, _definitions: Definitions, input: Input_card_tpl, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  const frame = new Frame("card.tpl", [0,30], rootData);
  scope.locals.set("label", input.label);
    context.at(frame, [0,16]); context.output.write("<p class=\"card\">");
    context.at(frame, [16,25]); context.output.write(runtime.escape(input.label, frame, [19,24]));
    context.at(frame, [25,30]); context.output.write("</p>\n");
}
function render_layout_tpl(assign: Assign, definitions: Definitions, input: Input_layout_tpl, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  const frame = new Frame("layout.tpl", [0,29,66,76,100,137,191,268,305,392,463,468,483,563,567,582,586,592,608,655,684,695], rootData);

    const local_values_1: Array<number> = generatedChecked(generatedListOf(generatedNumber), runtime.depth([0, ...runtime.listSpread(assign.numbers, frame, [16,26])], frame, [12,27]), "[0, ...numbers]", runtime, frame, [12,27]);
    scope.locals.set("values", local_values_1);
    const local_merged_2: Map<string, string> = generatedChecked(generatedMapOf(generatedString), runtime.depth(new Map<string, Value>([...runtime.mapSpread(assign.lookup, frame, [42,51]), [runtime.stringify("z", frame, [53,56]), "Z"]]), frame, [41,64]), "[...lookup, \"z\" => \"Z\"]", runtime, frame, [41,64]);
    scope.locals.set("merged", local_merged_2);
    context.at(frame, [66,80]); context.output.write("<section>\n<h1>");
    context.at(frame, [80,94]); context.output.write(runtime.escape((assign.page).title, frame, [83,93]));
    context.at(frame, [94,119]); context.output.write("</h1>\n<p class=\"escaped\">");
    context.at(frame, [119,132]); context.output.write(runtime.escape(assign.dangerous, frame, [122,131]));
    context.at(frame, [132,156]); context.output.write("</p>\n<p class=\"logical\">");
    context.at(frame, [156,171]); context.output.write(runtime.escape((() => { const left = assign.flag; return runtime.truthy(left) ? runtime.truthy("x") : false; })(), frame, [159,170]));
    context.at(frame, [171,172]); context.output.write("|");
    context.at(frame, [172,186]); context.output.write(runtime.escape((() => { const left = false; return runtime.truthy(left) ? true : runtime.truthy(2); })(), frame, [175,185]));
    context.at(frame, [186,219]); context.output.write("</p>\n<p class=\"empty-truthiness\">");
    context.at(frame, [219,241]); context.output.write(runtime.escape((() => { const left = assign.empty_list; return runtime.truthy(left) ? runtime.truthy(assign.flag) : false; })(), frame, [222,240]));
    context.at(frame, [241,242]); context.output.write("|");
    context.at(frame, [242,263]); context.output.write(runtime.escape((() => { const left = assign.empty_map; return runtime.truthy(left) ? runtime.truthy(assign.flag) : false; })(), frame, [245,262]));
    context.at(frame, [263,271]); context.output.write("</p>\n<p>");
    context.at(frame, [271,284]); context.output.write(runtime.escape(generatedChecked(generatedOptional(generatedNumber), runtime.index(local_values_1, 1, frame, [274,283]), "values[1]", runtime, frame, [274,283]), frame, [274,283]));
    context.at(frame, [284,285]); context.output.write("|");
    context.at(frame, [285,300]); context.output.write(runtime.escape(generatedChecked(generatedOptional(generatedString), runtime.index(local_merged_2, "z", frame, [288,299]), "merged[\"z\"]", runtime, frame, [288,299]), frame, [288,299]));
    context.at(frame, [300,305]); context.output.write("</p>\n");
    if (runtime.truthy((() => { const left = assign.flag; return runtime.truthy(left) ? runtime.truthy(generatedChecked(generatedBoolean, runtime.binary("==", (assign.page).title, "Guide", frame, [316,337]), "page.title == \"Guide\"", runtime, frame, [316,337])) : false; })())) {
        context.at(frame, [338,362]); context.output.write("<strong>matched</strong>");
    } else {
        context.at(frame, [365,388]); context.output.write("<strong>missed</strong>");
    }
    context.at(frame, [391,395]); context.output.write("\n<p>");
    context.at(frame, [395,418]); context.output.write(runtime.escape((runtime.truthy(assign.flag) ? "yes" : "no"), frame, [398,417]));
    context.at(frame, [418,419]); context.output.write("|");
    context.at(frame, [419,429]); context.output.write(runtime.escape(generatedChecked(generatedNumber, runtime.binary("+", generatedChecked(generatedNumber, runtime.unary("-", 1, frame, [422,424]), "-1", runtime, frame, [422,424]), 3, frame, [422,428]), "-1 + 3", runtime, frame, [422,428]), frame, [422,428]));
    context.at(frame, [429,430]); context.output.write("|");
    context.at(frame, [430,458]); context.output.write(runtime.escape(generatedChecked(generatedString, runtime.call("default", ["", "fallback"], frame, [433,457]), "default(\"\", \"fallback\")", runtime, frame, [433,457]), frame, [433,457]));
    context.at(frame, [458,468]); context.output.write("</p>\n<ul>\n");
    { const row_entries = generatedEntries(assign.rows);
    const row_size = row_entries.length; const row_last_index = row_size - 1;
    const row_previous = scope.locals.get("row");
    try {
    for (const [row_index, [, local_row_3]] of row_entries.entries()) {
        scope.locals.set("row", generatedEncode_Row(local_row_3));
        const row_first = row_index === 0;
        const row_last = row_index === row_last_index;
        context.iterations += 1;
        runtime.limit('iteration', context.iterations, frame, [468,585]);
            context.at(frame, [483,487]); context.output.write("<li>");
            context.at(frame, [487,501]); context.output.write(runtime.escape(row_index, frame, [490,500]));
            context.at(frame, [501,502]); context.output.write("/");
            context.at(frame, [502,515]); context.output.write(runtime.escape(row_size, frame, [505,514]));
            context.at(frame, [515,516]); context.output.write(":");
            context.at(frame, [516,528]); context.output.write(runtime.escape((local_row_3).name, frame, [519,527]));
            context.at(frame, [528,529]); context.output.write(":");
            context.at(frame, [529,543]); context.output.write(runtime.escape(row_first, frame, [532,542]));
            context.at(frame, [543,544]); context.output.write(":");
            context.at(frame, [544,557]); context.output.write(runtime.escape(row_last, frame, [547,556]));
            context.at(frame, [557,563]); context.output.write("</li>\n");
    }
    } finally { if (row_previous !== undefined) scope.locals.set("row", row_previous); else scope.locals.delete("row"); }
    if (row_size === 0) {
            context.at(frame, [567,582]); context.output.write("<li>empty</li>\n");
    }
    }
    context.at(frame, [586,592]); context.output.write("</ul>\n");
    context.enter("partial.tpl", frame, [592,607]);
    try { render_partial_tpl(assign, definitions, { values: local_values_1 }, context, runtime, rootData, scope); } finally { context.leave(); }
    if (definitions.content !== undefined) {
        context.at(frame, [620,634]); context.output.write("<p>defined</p>");
    } else {
        context.at(frame, [637,651]); context.output.write("<p>missing</p>");
    }
    context.at(frame, [654,655]); context.output.write("\n");
    { let definition = definitions.content;
    if (definition === undefined) throw runtime.error(frame, [655,683], 'E_RUNTIME_BLOCK_UNDEFINED', "define content is not registered");
    if (definition?.html !== undefined) { context.at(frame, [655,683]); context.output.write(definition.html); }
    else { const input: Input_card_tpl = { label: (assign.page).title }; const blockScope = new Scope(); context.enter("card.tpl", frame, [655,683]); try { render_card_tpl(assign, definitions, input, context, runtime, rootData, blockScope); } finally { context.leave(); } }
    }
    context.at(frame, [684,695]); context.output.write("</section>\n");
}
function render_partial_tpl(_assign: Assign, _definitions: Definitions, input: Input_partial_tpl, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  const frame = new Frame("partial.tpl", [0,38], rootData);
  scope.locals.set("values", input.values);
    context.at(frame, [0,20]); context.output.write("<p class=\"included\">");
    context.at(frame, [20,33]); context.output.write(runtime.escape(generatedChecked(generatedOptional(generatedNumber), runtime.index(input.values, 2, frame, [23,32]), "values[2]", runtime, frame, [23,32]), frame, [23,32]));
    context.at(frame, [33,38]); context.output.write("</p>\n");
}
function renderTemplate(target: string, assign: Assign, definitions: Definitions, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  switch (target) {
    case "layout.tpl": render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope); return;
    default: throw context.fail('E_LOAD_NOT_FOUND', null, null, 'template ' + target + ' does not exist');
  }
}
function generatedEnv(input: unknown): { timezone: string; now: number } { if (input === undefined || input === null) return { timezone: 'Z', now: Math.floor(Date.now() / 1000) }; if (!generatedPlain(input)) throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env is not an object'); const timezone = ('timezone' in input ? input.timezone : undefined) ?? 'Z'; const now = ('now' in input ? input.now : undefined) ?? Math.floor(Date.now() / 1000); if (typeof timezone !== 'string') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.timezone is not a string'); if (typeof now !== 'number') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.now is not a number'); return { timezone, now }; }
class GeneratedPreparedRender implements PreparedRender { private readonly name: string; private readonly execute: () => string; constructor(name: string, execute: () => string) { this.name = name; this.execute = execute; } render(): string { return internalBoundary(this.name, this.execute); } }
export class GeneratedProgram implements Program {
  readonly runtime: RuntimeEnvironment;
  constructor(runtime: RuntimeEnvironment = new RuntimeEnvironment()) { this.runtime = runtime; }
  prepare(target: string | Template, assign: unknown, options: RenderOptions = {}): PreparedRender { if (typeof target !== 'string') throw new Error('generated target must be a template name'); return internalBoundary(target, () => this.prepareBound(target, assign, options)); }
  private prepareBound(target: string, assign: unknown, options: RenderOptions): PreparedRender { let boundAssign: { assign: Assign; root: MapValue }; let bound: GeneratedBoundDefinitions; let env: { timezone: string; now: number }; try { boundAssign = generatedBindAssign(assign); bound = generatedBindDefinitions(options.define); env = generatedEnv(options.env); } catch (error) { if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message }); throw error; } const registered = bound.targets.get(target); const html = registered?.html; if (html !== undefined) return new GeneratedPreparedRender(target, () => html); const targetName = registered?.target ?? target; return new GeneratedPreparedRender(target, () => { const context = new RenderContext(this.runtime, boundAssign.root, env, targetName); const runtime = new RuntimeBindings(context); const scope = new Scope(); context.enter(targetName, null, null); try { renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope); return context.output.toString(); } finally { context.leave(); } }); }
  render(target: string | Template, assign: unknown, options: RenderOptions = {}): string { return this.prepare(target, assign, options).render(); }
}


javascript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "js",
  "entry": "layout.tpl",
  "sourceDigest": "936a20a5f3b77bc8a454a40c57b55de1118203b69a39aedda5acb0455f495625",
  "typeDigest": "30c0b093d1694670ec7117cc02b36e0031780485e6218be94afbdf1be6524db7",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "7a758948ae54e846b8c9cb16fa604ebf4a8aa94725dd3cd63ae77c94b2fe1e05",
  "files": {
    "compiler-coverage.js": {
      "path": "compiler-coverage.js",
      "artifactDigest": "5d473ea122af5e8999d768919f4a3da38de3072735e95aee12a2f31496925442"
    }
  }
}

import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary } from "@polyspec/template";
function generatedTypeError(value, path, expected) {
  return new Error(value === null || value === void 0 ? path + " is required" : path + " is not " + expected);
}
function generatedChecked(decode, value, path, runtime, frame, span) {
  try {
    return decode(value, path);
  } catch (error) {
    if (error instanceof Error) throw runtime.error(frame, span, "E_RUNTIME_TYPE", error.message);
    throw error;
  }
}
function generatedDataObject(value, path) {
  if (value instanceof Map) return value;
  throw new Error(path + " is not an object");
}
function generatedPlain(value) {
  if (typeof value !== "object" || value === null) return false;
  const prototype = Reflect.getPrototypeOf(value);
  return prototype === Object.prototype || prototype === null;
}
function generatedObject(value, path) {
  if (value instanceof Map) return value;
  throw generatedTypeError(value, path, "an object");
}
function generatedString(value, path) {
  if (typeof value === "string") return value;
  throw generatedTypeError(value, path, "a string");
}
function generatedNumber(value, path) {
  if (typeof value === "number") return value;
  throw generatedTypeError(value, path, "a number");
}
function generatedBoolean(value, path) {
  if (typeof value === "boolean") return value;
  throw generatedTypeError(value, path, "a boolean");
}
function generatedOptional(decode) {
  return (value, path) => value === null || value === void 0 ? null : decode(value, path);
}
function generatedListOf(item) {
  return (value, path) => {
    if (Array.isArray(value)) return value.map((element, index) => item(element, path + "[" + index + "]"));
    throw generatedTypeError(value, path, "a list");
  };
}
function generatedMapOf(item) {
  return (value, path) => new Map([...generatedObject(value, path)].map(([key, element]) => [key, item(element, path + "." + key)]));
}
function generatedEntries(value) {
  if (value === null) return [];
  if (Array.isArray(value)) return value.map((item, index) => [index, item]);
  return [...value];
}
function generatedDecode_Page(value, path) {
  const object = generatedObject(value, path);
  return { title: generatedString(object.get("title"), path + ".title") };
}
function generatedDecode_Row(value, path) {
  const object = generatedObject(value, path);
  return { name: generatedString(object.get("name"), path + ".name") };
}
function generatedEncode_Row(value) {
  return /* @__PURE__ */ new Map([["name", value.name]]);
}
function generatedDecodeAssign(value, path) {
  const object = generatedObject(value, path);
  return { flag: generatedBoolean(object.get("flag"), path + ".flag"), dangerous: generatedString(object.get("dangerous"), path + ".dangerous"), empty_list: generatedListOf(generatedString)(object.get("empty_list"), path + ".empty_list"), empty_map: generatedMapOf(generatedString)(object.get("empty_map"), path + ".empty_map"), page: generatedDecode_Page(object.get("page"), path + ".page"), numbers: generatedListOf(generatedNumber)(object.get("numbers"), path + ".numbers"), lookup: generatedMapOf(generatedString)(object.get("lookup"), path + ".lookup"), rows: generatedListOf(generatedDecode_Row)(object.get("rows"), path + ".rows") };
}
function generatedDecodeData_Input_card_tpl(value, path) {
  const object = generatedDataObject(value, path);
  const data = {};
  if (object.has("label")) data.label = generatedString(object.get("label"), path + ".label");
  return data;
}
function generatedDecodeData_Input_layout_tpl(value, path) {
  generatedDataObject(value, path);
  return {};
}
function generatedBindAssign(value) {
  const root = bindMap(value);
  return { assign: generatedDecodeAssign(root, "assign"), root };
}
function generatedBindDefinitions(input) {
  const definitions = {};
  const targets = /* @__PURE__ */ new Map();
  if (input === void 0 || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error("define is not an object");
  const entries = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
      case "content": {
        if (typeof raw === "string") {
          if (raw !== "card.tpl") throw new Error("define.content has an invalid template");
          definitions.content = { template: "card.tpl" };
          targets.set("content", { target: "card.tpl" });
          break;
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.content is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          if (template !== void 0 || data !== void 0) throw new Error("define.content has an invalid html entry");
          definitions.content = { html };
          targets.set("content", { target: null, html });
          break;
        }
        if (template !== "card.tpl") throw new Error("define.content has an invalid template");
        definitions.content = { template: "card.tpl", data: data === void 0 ? {} : generatedDecodeData_Input_card_tpl(data, "define.content.data") };
        targets.set("content", { target: "card.tpl" });
        break;
      }
      case "layout": {
        if (typeof raw === "string") {
          if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
          definitions.layout = { template: "layout.tpl" };
          targets.set("layout", { target: "layout.tpl" });
          break;
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.layout is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          throw new Error("define.layout has an invalid html entry");
        }
        if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl", data: data === void 0 ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") };
        targets.set("layout", { target: "layout.tpl" });
        break;
      }
      default:
        throw new Error("define." + id + " is not declared");
    }
  }
  return { definitions, targets };
}
function render_card_tpl(_assign, _definitions, input, context, runtime, rootData, scope) {
  const frame = new Frame("card.tpl", [0, 30], rootData);
  scope.locals.set("label", input.label);
  context.at(frame, [0, 16]);
  context.output.write('<p class="card">');
  context.at(frame, [16, 25]);
  context.output.write(runtime.escape(input.label, frame, [19, 24]));
  context.at(frame, [25, 30]);
  context.output.write("</p>\n");
}
function render_layout_tpl(assign, definitions, input, context, runtime, rootData, scope) {
  const frame = new Frame("layout.tpl", [0, 29, 66, 76, 100, 137, 191, 268, 305, 392, 463, 468, 483, 563, 567, 582, 586, 592, 608, 655, 684, 695], rootData);
  const local_values_1 = generatedChecked(generatedListOf(generatedNumber), runtime.depth([0, ...runtime.listSpread(assign.numbers, frame, [16, 26])], frame, [12, 27]), "[0, ...numbers]", runtime, frame, [12, 27]);
  scope.locals.set("values", local_values_1);
  const local_merged_2 = generatedChecked(generatedMapOf(generatedString), runtime.depth(new Map([...runtime.mapSpread(assign.lookup, frame, [42, 51]), [runtime.stringify("z", frame, [53, 56]), "Z"]]), frame, [41, 64]), '[...lookup, "z" => "Z"]', runtime, frame, [41, 64]);
  scope.locals.set("merged", local_merged_2);
  context.at(frame, [66, 80]);
  context.output.write("<section>\n<h1>");
  context.at(frame, [80, 94]);
  context.output.write(runtime.escape(assign.page.title, frame, [83, 93]));
  context.at(frame, [94, 119]);
  context.output.write('</h1>\n<p class="escaped">');
  context.at(frame, [119, 132]);
  context.output.write(runtime.escape(assign.dangerous, frame, [122, 131]));
  context.at(frame, [132, 156]);
  context.output.write('</p>\n<p class="logical">');
  context.at(frame, [156, 171]);
  context.output.write(runtime.escape((() => {
    const left = assign.flag;
    return runtime.truthy(left) ? runtime.truthy("x") : false;
  })(), frame, [159, 170]));
  context.at(frame, [171, 172]);
  context.output.write("|");
  context.at(frame, [172, 186]);
  context.output.write(runtime.escape((() => {
    const left = false;
    return runtime.truthy(left) ? true : runtime.truthy(2);
  })(), frame, [175, 185]));
  context.at(frame, [186, 219]);
  context.output.write('</p>\n<p class="empty-truthiness">');
  context.at(frame, [219, 241]);
  context.output.write(runtime.escape((() => {
    const left = assign.empty_list;
    return runtime.truthy(left) ? runtime.truthy(assign.flag) : false;
  })(), frame, [222, 240]));
  context.at(frame, [241, 242]);
  context.output.write("|");
  context.at(frame, [242, 263]);
  context.output.write(runtime.escape((() => {
    const left = assign.empty_map;
    return runtime.truthy(left) ? runtime.truthy(assign.flag) : false;
  })(), frame, [245, 262]));
  context.at(frame, [263, 271]);
  context.output.write("</p>\n<p>");
  context.at(frame, [271, 284]);
  context.output.write(runtime.escape(generatedChecked(generatedOptional(generatedNumber), runtime.index(local_values_1, 1, frame, [274, 283]), "values[1]", runtime, frame, [274, 283]), frame, [274, 283]));
  context.at(frame, [284, 285]);
  context.output.write("|");
  context.at(frame, [285, 300]);
  context.output.write(runtime.escape(generatedChecked(generatedOptional(generatedString), runtime.index(local_merged_2, "z", frame, [288, 299]), 'merged["z"]', runtime, frame, [288, 299]), frame, [288, 299]));
  context.at(frame, [300, 305]);
  context.output.write("</p>\n");
  if (runtime.truthy((() => {
    const left = assign.flag;
    return runtime.truthy(left) ? runtime.truthy(generatedChecked(generatedBoolean, runtime.binary("==", assign.page.title, "Guide", frame, [316, 337]), 'page.title == "Guide"', runtime, frame, [316, 337])) : false;
  })())) {
    context.at(frame, [338, 362]);
    context.output.write("<strong>matched</strong>");
  } else {
    context.at(frame, [365, 388]);
    context.output.write("<strong>missed</strong>");
  }
  context.at(frame, [391, 395]);
  context.output.write("\n<p>");
  context.at(frame, [395, 418]);
  context.output.write(runtime.escape(runtime.truthy(assign.flag) ? "yes" : "no", frame, [398, 417]));
  context.at(frame, [418, 419]);
  context.output.write("|");
  context.at(frame, [419, 429]);
  context.output.write(runtime.escape(generatedChecked(generatedNumber, runtime.binary("+", generatedChecked(generatedNumber, runtime.unary("-", 1, frame, [422, 424]), "-1", runtime, frame, [422, 424]), 3, frame, [422, 428]), "-1 + 3", runtime, frame, [422, 428]), frame, [422, 428]));
  context.at(frame, [429, 430]);
  context.output.write("|");
  context.at(frame, [430, 458]);
  context.output.write(runtime.escape(generatedChecked(generatedString, runtime.call("default", ["", "fallback"], frame, [433, 457]), 'default("", "fallback")', runtime, frame, [433, 457]), frame, [433, 457]));
  context.at(frame, [458, 468]);
  context.output.write("</p>\n<ul>\n");
  {
    const row_entries = generatedEntries(assign.rows);
    const row_size = row_entries.length;
    const row_last_index = row_size - 1;
    const row_previous = scope.locals.get("row");
    try {
      for (const [row_index, [, local_row_3]] of row_entries.entries()) {
        scope.locals.set("row", generatedEncode_Row(local_row_3));
        const row_first = row_index === 0;
        const row_last = row_index === row_last_index;
        context.iterations += 1;
        runtime.limit("iteration", context.iterations, frame, [468, 585]);
        context.at(frame, [483, 487]);
        context.output.write("<li>");
        context.at(frame, [487, 501]);
        context.output.write(runtime.escape(row_index, frame, [490, 500]));
        context.at(frame, [501, 502]);
        context.output.write("/");
        context.at(frame, [502, 515]);
        context.output.write(runtime.escape(row_size, frame, [505, 514]));
        context.at(frame, [515, 516]);
        context.output.write(":");
        context.at(frame, [516, 528]);
        context.output.write(runtime.escape(local_row_3.name, frame, [519, 527]));
        context.at(frame, [528, 529]);
        context.output.write(":");
        context.at(frame, [529, 543]);
        context.output.write(runtime.escape(row_first, frame, [532, 542]));
        context.at(frame, [543, 544]);
        context.output.write(":");
        context.at(frame, [544, 557]);
        context.output.write(runtime.escape(row_last, frame, [547, 556]));
        context.at(frame, [557, 563]);
        context.output.write("</li>\n");
      }
    } finally {
      if (row_previous !== void 0) scope.locals.set("row", row_previous);
      else scope.locals.delete("row");
    }
    if (row_size === 0) {
      context.at(frame, [567, 582]);
      context.output.write("<li>empty</li>\n");
    }
  }
  context.at(frame, [586, 592]);
  context.output.write("</ul>\n");
  context.enter("partial.tpl", frame, [592, 607]);
  try {
    render_partial_tpl(assign, definitions, { values: local_values_1 }, context, runtime, rootData, scope);
  } finally {
    context.leave();
  }
  if (definitions.content !== void 0) {
    context.at(frame, [620, 634]);
    context.output.write("<p>defined</p>");
  } else {
    context.at(frame, [637, 651]);
    context.output.write("<p>missing</p>");
  }
  context.at(frame, [654, 655]);
  context.output.write("\n");
  {
    let definition = definitions.content;
    if (definition === void 0) throw runtime.error(frame, [655, 683], "E_RUNTIME_BLOCK_UNDEFINED", "define content is not registered");
    if (definition?.html !== void 0) {
      context.at(frame, [655, 683]);
      context.output.write(definition.html);
    } else {
      const input2 = { label: assign.page.title };
      const blockScope = new Scope();
      context.enter("card.tpl", frame, [655, 683]);
      try {
        render_card_tpl(assign, definitions, input2, context, runtime, rootData, blockScope);
      } finally {
        context.leave();
      }
    }
  }
  context.at(frame, [684, 695]);
  context.output.write("</section>\n");
}
function render_partial_tpl(_assign, _definitions, input, context, runtime, rootData, scope) {
  const frame = new Frame("partial.tpl", [0, 38], rootData);
  scope.locals.set("values", input.values);
  context.at(frame, [0, 20]);
  context.output.write('<p class="included">');
  context.at(frame, [20, 33]);
  context.output.write(runtime.escape(generatedChecked(generatedOptional(generatedNumber), runtime.index(input.values, 2, frame, [23, 32]), "values[2]", runtime, frame, [23, 32]), frame, [23, 32]));
  context.at(frame, [33, 38]);
  context.output.write("</p>\n");
}
function renderTemplate(target, assign, definitions, context, runtime, rootData, scope) {
  switch (target) {
    case "layout.tpl":
      render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope);
      return;
    default:
      throw context.fail("E_LOAD_NOT_FOUND", null, null, "template " + target + " does not exist");
  }
}
function generatedEnv(input) {
  if (input === void 0 || input === null) return { timezone: "Z", now: Math.floor(Date.now() / 1e3) };
  if (!generatedPlain(input)) throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env is not an object");
  const timezone = ("timezone" in input ? input.timezone : void 0) ?? "Z";
  const now = ("now" in input ? input.now : void 0) ?? Math.floor(Date.now() / 1e3);
  if (typeof timezone !== "string") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.timezone is not a string");
  if (typeof now !== "number") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.now is not a number");
  return { timezone, now };
}
class GeneratedPreparedRender {
  name;
  execute;
  constructor(name, execute) {
    this.name = name;
    this.execute = execute;
  }
  render() {
    return internalBoundary(this.name, this.execute);
  }
}
export class GeneratedProgram {
  runtime;
  constructor(runtime = new RuntimeEnvironment()) {
    this.runtime = runtime;
  }
  prepare(target, assign, options = {}) {
    if (typeof target !== "string") throw new Error("generated target must be a template name");
    return internalBoundary(target, () => this.prepareBound(target, assign, options));
  }
  prepareBound(target, assign, options) {
    let boundAssign;
    let bound;
    let env;
    try {
      boundAssign = generatedBindAssign(assign);
      bound = generatedBindDefinitions(options.define);
      env = generatedEnv(options.env);
    } catch (error) {
      if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message });
      throw error;
    }
    const registered = bound.targets.get(target);
    const html = registered?.html;
    if (html !== void 0) return new GeneratedPreparedRender(target, () => html);
    const targetName = registered?.target ?? target;
    return new GeneratedPreparedRender(target, () => {
      const context = new RenderContext(this.runtime, boundAssign.root, env, targetName);
      const runtime = new RuntimeBindings(context);
      const scope = new Scope();
      context.enter(targetName, null, null);
      try {
        renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope);
        return context.output.toString();
      } finally {
        context.leave();
      }
    });
  }
  render(target, assign, options = {}) {
    return this.prepare(target, assign, options).render();
  }
}


go · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "go",
  "entry": "layout.tpl",
  "sourceDigest": "936a20a5f3b77bc8a454a40c57b55de1118203b69a39aedda5acb0455f495625",
  "typeDigest": "30c0b093d1694670ec7117cc02b36e0031780485e6218be94afbdf1be6524db7",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "45312e93dc75fa9cac0af4448f4b43508dff97b90f52d7c3d1407e5852dbc284",
  "files": {
    "generated.go": {
      "path": "generated.go",
      "artifactDigest": "3e46e99df34537416e9f7a268f6ff88b7b01369b786988c096d7ee3f433f988d"
    }
  }
}

// Code generated by @polyspec/template-compiler. DO NOT EDIT.

package generated

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	template "github.com/polyspec/template/packages/go"
	"github.com/polyspec/template/packages/go/ast"
	"github.com/polyspec/template/packages/go/errs"
	"github.com/polyspec/template/packages/go/functions"
	"github.com/polyspec/template/packages/go/render"
	"github.com/polyspec/template/packages/go/value"
	"time"
	"unicode/utf8"
)

type Page struct {
	Title string `json:"title"`
}

func (r Page) TemplateValue() value.Value {
	result := value.NewOrderedMap()
	result.Set("title", generatedValue(r.Title))
	return result
}

type Row struct {
	Name string `json:"name"`
}

func (r Row) TemplateValue() value.Value {
	result := value.NewOrderedMap()
	result.Set("name", generatedValue(r.Name))
	return result
}

type Slot struct {
	Template *string `json:"template"`
	Html     *string `json:"html"`
}

func (r Slot) TemplateValue() value.Value {
	result := value.NewOrderedMap()
	result.Set("template", generatedValue(r.Template))
	result.Set("html", generatedValue(r.Html))
	return result
}

type Assign struct {
	Flag       bool                       `json:"flag"`
	Dangerous  string                     `json:"dangerous"`
	Empty_list []string                   `json:"empty_list"`
	Empty_map  OrderedMap[string, string] `json:"empty_map"`
	Page       Page                       `json:"page"`
	Numbers    []float64                  `json:"numbers"`
	Lookup     OrderedMap[string, string] `json:"lookup"`
	Rows       []Row                      `json:"rows"`
}

type Input_card_tpl struct {
	Label string `json:"label"`
}

type Input_layout_tpl struct{}

type Input_partial_tpl struct {
	Values []float64 `json:"values"`
}

type DefinitionData_card_tpl struct {
	Label *string `json:"label"`
}

type DefinitionData_layout_tpl struct{}

type DefinitionData_partial_tpl struct {
	Values *[]float64 `json:"values"`
}

type Definition[T any] struct {
	Template string  `json:"template"`
	HTML     *string `json:"html"`
	Data     *T      `json:"data"`
}

type Definitions struct {
	Content *Definition[DefinitionData_card_tpl]   `json:"content"`
	Layout  *Definition[DefinitionData_layout_tpl] `json:"layout"`
}

type ArtifactManifest struct {
	Schema         int
	Mode           string
	Target         string
	Entry          string
	SourceDigest   string
	TypeDigest     string
	ContractDigest string
	Files          map[string]string
}

var generatedRecordFields = map[string][]generatedField{"Page": []generatedField{{Name: "title", Type: generatedType{Kind: "string"}}}, "Row": []generatedField{{Name: "name", Type: generatedType{Kind: "string"}}}, "Slot": []generatedField{{Name: "template", Type: generatedType{Kind: "string", Optional: true}}, {Name: "html", Type: generatedType{Kind: "string", Optional: true}}}}

type OrderedEntry[K comparable, V any] struct {
	Key   K
	Value V
}

type OrderedMap[K comparable, V any] struct {
	entries []OrderedEntry[K, V]
}

func NewOrderedMap[K comparable, V any]() OrderedMap[K, V] {
	return OrderedMap[K, V]{}
}

func (m *OrderedMap[K, V]) Set(key K, item V) {
	for index := range m.entries {
		if m.entries[index].Key == key {
			m.entries[index].Value = item
			return
		}
	}
	m.entries = append(m.entries, OrderedEntry[K, V]{key, item})
}

func (m OrderedMap[K, V]) Entries() []OrderedEntry[K, V] {
	return m.entries
}

func (m OrderedMap[K, V]) TemplateValue() value.Value {
	result := value.NewOrderedMap()
	for _, entry := range m.entries {
		result.Set(fmt.Sprint(entry.Key), generatedValue(entry.Value))
	}
	return result
}

func (m *OrderedMap[K, V]) UnmarshalJSON(data []byte) error {
	decoder := json.NewDecoder(bytes.NewReader(data))
	token, err := decoder.Token()
	if err != nil {
		return err
	}
	if token != json.Delim('{') {
		return fmt.Errorf("generated ordered map must be an object")
	}
	m.entries = nil
	for decoder.More() {
		rawKey, err := decoder.Token()
		if err != nil {
			return err
		}
		keyText, ok := rawKey.(string)
		if !ok {
			return fmt.Errorf("generated ordered map key is not text")
		}
		keyJSON, err := json.Marshal(keyText)
		if err != nil {
			return err
		}
		var key K
		if err := json.Unmarshal(keyJSON, &key); err != nil {
			return err
		}
		var item V
		if err := decoder.Decode(&item); err != nil {
			return err
		}
		m.Set(key, item)
	}
	_, err = decoder.Token()
	return err
}

func generatedPanic(err error) {
	if err != nil {
		panic(err)
	}
}

func generatedValue(input any) value.Value {
	switch item := input.(type) {
	case nil:
		return nil
	case bool:
		return item
	case float64:
		return item
	case string:
		return item
	case value.SafeString:
		return item
	case value.List:
		result := make(value.List, len(item))
		for index, element := range item {
			result[index] = generatedValue(element)
		}
		return result
	case *value.OrderedMap:
		return item
	}
	result, err := value.Convert(input)
	generatedPanic(err)
	return result
}

func generatedResult[T any](input value.Value) T {
	result, err := generatedAs[T](input)
	generatedPanic(err)
	return result
}

func generatedAs[T any](input value.Value) (T, error) {
	if result, ok := input.(T); ok {
		return result, nil
	}
	var result T
	err := generatedDecode(input, &result)
	return result, err
}

func generatedTruthy(runtime *render.RuntimeBindings, input any) bool {
	return runtime.Truthy(generatedValue(input))
}

func generatedUnary[T any](runtime *render.RuntimeBindings, operator string, input any, frame *render.Frame, span ast.Span) T {
	result, err := runtime.Unary(operator, generatedValue(input), frame, span)
	generatedPanic(err)
	return generatedResult[T](result)
}

func generatedBinary[T any](runtime *render.RuntimeBindings, operator string, left, right any, frame *render.Frame, span ast.Span) T {
	result, err := runtime.Binary(operator, generatedValue(left), generatedValue(right), frame, span)
	generatedPanic(err)
	return generatedResult[T](result)
}

func generatedIndex[T any](runtime *render.RuntimeBindings, input, key any, frame *render.Frame, span ast.Span) T {
	result, err := runtime.Index(generatedValue(input), generatedValue(key), frame, span)
	generatedPanic(err)
	return generatedResult[T](result)
}

func generatedDepth[T any](runtime *render.RuntimeBindings, input T, frame *render.Frame, span ast.Span) T {
	_, err := runtime.Depth(generatedValue(input), frame, span)
	generatedPanic(err)
	return input
}

func generatedCall[T any](runtime *render.RuntimeBindings, name string, args []value.Value, frame *render.Frame, span ast.Span) T {
	result, err := runtime.Call(name, args, frame, span)
	generatedPanic(err)
	return generatedResult[T](result)
}

func generatedEscape(runtime *render.RuntimeBindings, input any, frame *render.Frame, span ast.Span) string {
	result, err := runtime.Escape(generatedValue(input), frame, span)
	generatedPanic(err)
	return result
}

type generatedEntry[T any] struct {
	Key   value.Value
	Value T
}

func generatedListEntries[T any](items []T) []generatedEntry[T] {
	result := make([]generatedEntry[T], len(items))
	for index, item := range items {
		result[index] = generatedEntry[T]{float64(index), item}
	}
	return result
}

func generatedListSpread[T any](runtime *render.RuntimeBindings, input any, frame *render.Frame, span ast.Span) []T {
	source, err := runtime.ListSpread(generatedValue(input), frame, span)
	generatedPanic(err)
	result := make([]T, len(source))
	for index, item := range source {
		result[index] = generatedResult[T](item)
	}
	return result
}

func generatedMapSpread[K comparable, V any](runtime *render.RuntimeBindings, input any, frame *render.Frame, span ast.Span) OrderedMap[K, V] {
	source, err := runtime.MapSpread(generatedValue(input), frame, span)
	generatedPanic(err)
	result := NewOrderedMap[K, V]()
	for _, key := range source.Keys() {
		result.Set(generatedResult[K](key), generatedResult[V](source.MustGet(key)))
	}
	return result
}

func generatedLoopMeta(scope *render.Scope, name string) *render.LoopMeta {
	result := scope.LoopMeta(name)
	if result == nil {
		panic("generated loop metadata is missing")
	}
	return result
}

func generatedWrite(context *render.Context, text string, frame *render.Frame, span ast.Span) {
	generatedPanic(context.Write(text, frame, &span))
}

func generatedEnter(context *render.Context, name string, frame *render.Frame, span ast.Span) {
	generatedPanic(context.Enter(name, frame, &span))
}

func generatedLimit(runtime *render.RuntimeBindings, kind string, count int, frame *render.Frame, span ast.Span) {
	generatedPanic(runtime.Limit(kind, count, frame, span))
}

func generatedPlain(input any) any {
	switch item := input.(type) {
	case *value.OrderedMap:
		result := map[string]any{}
		for _, key := range item.Keys() {
			entry, _ := item.Get(key)
			result[key] = generatedPlain(entry)
		}
		return result
	case value.List:
		result := make([]any, len(item))
		for index, entry := range item {
			result[index] = generatedPlain(entry)
		}
		return result
	default:
		return input
	}
}

type generatedType struct {
	Kind     string
	Optional bool
	Name     string
	Item     *generatedType
	Key      *generatedType
	Value    *generatedType
}

type generatedField struct {
	Name string
	Type generatedType
}

func generatedCheck(input value.Value, kind generatedType, records map[string][]generatedField, path string) error {
	if input == nil {
		if kind.Optional || kind.Kind == "any" {
			return nil
		}
		return fmt.Errorf("%s is required", path)
	}
	actual := value.TypeOf(input)
	switch kind.Kind {
	case "any":
		return nil
	case "string":
		if actual != value.TypeString {
			return fmt.Errorf("%s is not a string", path)
		}
	case "number":
		if actual != value.TypeNumber {
			return fmt.Errorf("%s is not a number", path)
		}
	case "boolean":
		if actual != value.TypeBool {
			return fmt.Errorf("%s is not a boolean", path)
		}
	case "list":
		items, ok := input.(value.List)
		if !ok {
			return fmt.Errorf("%s is not a list", path)
		}
		for index, item := range items {
			if err := generatedCheck(item, *kind.Item, records, fmt.Sprintf("%s[%d]", path, index)); err != nil {
				return err
			}
		}
	case "map":
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		for _, key := range entries.Keys() {
			item, _ := entries.Get(key)
			if err := generatedCheck(item, *kind.Value, records, path+"."+key); err != nil {
				return err
			}
		}
	default:
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		return generatedCheckFields(entries, records[kind.Name], records, path)
	}
	return nil
}

func generatedCheckFields(input *value.OrderedMap, fields []generatedField, records map[string][]generatedField, path string) error {
	for _, field := range fields {
		item, _ := input.Get(field.Name)
		if err := generatedCheck(item, field.Type, records, path+"."+field.Name); err != nil {
			return err
		}
	}
	return nil
}

func generatedDecode(input any, output any) error {
	data, err := json.Marshal(generatedPlain(input))
	if err != nil {
		return err
	}
	return json.Unmarshal(data, output)
}

func generatedEnv(options template.RenderOptions) functions.Env {
	env := functions.Env{Timezone: "Z", Now: float64(time.Now().Unix())}
	if options.Env != nil {
		if options.Env.Timezone != "" {
			env.Timezone = options.Env.Timezone
		}
		env.Now = options.Env.Now
	}
	return env
}

func render_card_tpl(assign Assign, definitions *Definitions, input Input_card_tpl, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	frame := render.NewFrame("card.tpl", errs.LineIndex{0, 30}, rootData)
	scope.Locals["label"] = generatedValue(input.Label)
	generatedWrite(context, "<p class=\"card\">", frame, ast.Span{0, 16})
	generatedWrite(context, generatedEscape(runtime, input.Label, frame, ast.Span{19, 24}), frame, ast.Span{16, 25})
	generatedWrite(context, "</p>\u000a", frame, ast.Span{25, 30})
}

func render_layout_tpl(assign Assign, definitions *Definitions, input Input_layout_tpl, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	frame := render.NewFrame("layout.tpl", errs.LineIndex{0, 29, 66, 76, 100, 137, 191, 268, 305, 392, 463, 468, 483, 563, 567, 582, 586, 592, 608, 655, 684, 695}, rootData)
	var local_values_1 []float64 = generatedDepth(runtime, func() []float64 {
		result := []float64{}
		result = append(result, float64(0))
		result = append(result, generatedListSpread[float64](runtime, assign.Numbers, frame, ast.Span{16, 26})...)
		return result
	}(), frame, ast.Span{12, 27})
	scope.Locals["values"] = generatedValue(local_values_1)
	var local_merged_2 OrderedMap[string, string] = generatedDepth(runtime, func() OrderedMap[string, string] {
		result := NewOrderedMap[string, string]()
		for _, entry := range generatedMapSpread[string, string](runtime, assign.Lookup, frame, ast.Span{42, 51}).Entries() {
			result.Set(entry.Key, entry.Value)
		}
		result.Set("z", "Z")
		return result
	}(), frame, ast.Span{41, 64})
	scope.Locals["merged"] = generatedValue(local_merged_2)
	generatedWrite(context, "<section>\u000a<h1>", frame, ast.Span{66, 80})
	generatedWrite(context, generatedEscape(runtime, assign.Page.Title, frame, ast.Span{83, 93}), frame, ast.Span{80, 94})
	generatedWrite(context, "</h1>\u000a<p class=\"escaped\">", frame, ast.Span{94, 119})
	generatedWrite(context, generatedEscape(runtime, assign.Dangerous, frame, ast.Span{122, 131}), frame, ast.Span{119, 132})
	generatedWrite(context, "</p>\u000a<p class=\"logical\">", frame, ast.Span{132, 156})
	generatedWrite(context, generatedEscape(runtime, func() bool {
		left := assign.Flag
		if !generatedTruthy(runtime, left) {
			return false
		}
		return generatedTruthy(runtime, "x")
	}(), frame, ast.Span{159, 170}), frame, ast.Span{156, 171})
	generatedWrite(context, "|", frame, ast.Span{171, 172})
	generatedWrite(context, generatedEscape(runtime, func() bool {
		left := false
		if generatedTruthy(runtime, left) {
			return true
		}
		return generatedTruthy(runtime, float64(2))
	}(), frame, ast.Span{175, 185}), frame, ast.Span{172, 186})
	generatedWrite(context, "</p>\u000a<p class=\"empty-truthiness\">", frame, ast.Span{186, 219})
	generatedWrite(context, generatedEscape(runtime, func() bool {
		left := assign.Empty_list
		if !generatedTruthy(runtime, left) {
			return false
		}
		return generatedTruthy(runtime, assign.Flag)
	}(), frame, ast.Span{222, 240}), frame, ast.Span{219, 241})
	generatedWrite(context, "|", frame, ast.Span{241, 242})
	generatedWrite(context, generatedEscape(runtime, func() bool {
		left := assign.Empty_map
		if !generatedTruthy(runtime, left) {
			return false
		}
		return generatedTruthy(runtime, assign.Flag)
	}(), frame, ast.Span{245, 262}), frame, ast.Span{242, 263})
	generatedWrite(context, "</p>\u000a<p>", frame, ast.Span{263, 271})
	generatedWrite(context, generatedEscape(runtime, generatedIndex[*float64](runtime, local_values_1, float64(1), frame, ast.Span{274, 283}), frame, ast.Span{274, 283}), frame, ast.Span{271, 284})
	generatedWrite(context, "|", frame, ast.Span{284, 285})
	generatedWrite(context, generatedEscape(runtime, generatedIndex[*string](runtime, local_merged_2, "z", frame, ast.Span{288, 299}), frame, ast.Span{288, 299}), frame, ast.Span{285, 300})
	generatedWrite(context, "</p>\u000a", frame, ast.Span{300, 305})
	if generatedTruthy(runtime, func() bool {
		left := assign.Flag
		if !generatedTruthy(runtime, left) {
			return false
		}
		return generatedTruthy(runtime, generatedBinary[bool](runtime, "==", assign.Page.Title, "Guide", frame, ast.Span{316, 337}))
	}()) {
		generatedWrite(context, "<strong>matched</strong>", frame, ast.Span{338, 362})
	} else {
		generatedWrite(context, "<strong>missed</strong>", frame, ast.Span{365, 388})
	}
	generatedWrite(context, "\u000a<p>", frame, ast.Span{391, 395})
	generatedWrite(context, generatedEscape(runtime, func() string {
		if generatedTruthy(runtime, assign.Flag) {
			return "yes"
		}
		return "no"
	}(), frame, ast.Span{398, 417}), frame, ast.Span{395, 418})
	generatedWrite(context, "|", frame, ast.Span{418, 419})
	generatedWrite(context, generatedEscape(runtime, generatedBinary[float64](runtime, "+", generatedUnary[float64](runtime, "-", float64(1), frame, ast.Span{422, 424}), float64(3), frame, ast.Span{422, 428}), frame, ast.Span{422, 428}), frame, ast.Span{419, 429})
	generatedWrite(context, "|", frame, ast.Span{429, 430})
	generatedWrite(context, generatedEscape(runtime, generatedCall[string](runtime, "default", []value.Value{generatedValue(""), generatedValue("fallback")}, frame, ast.Span{433, 457}), frame, ast.Span{433, 457}), frame, ast.Span{430, 458})
	generatedWrite(context, "</p>\u000a<ul>\u000a", frame, ast.Span{458, 468})
	{
		entries := generatedListEntries(assign.Rows)
		entriesSize := len(entries)
		lastIndex := entriesSize - 1
		previous, hadPrevious := scope.Locals["row"]
		for row_index, entry := range entries {
			row_key, local_row_3 := entry.Key, entry.Value
			row_value := generatedValue(local_row_3)
			scope.Locals["row"] = row_value
			scope.Loops["row"] = append(scope.Loops["row"], &render.LoopMeta{Index: row_index, Key: row_key, Value: row_value, Size: entriesSize, First: row_index == 0, Last: row_index == lastIndex})
			context.Iterations++
			generatedLimit(runtime, "iteration", context.Iterations, frame, ast.Span{468, 585})
			generatedWrite(context, "<li>", frame, ast.Span{483, 487})
			generatedWrite(context, generatedEscape(runtime, generatedLoopMeta(scope, "row").Index, frame, ast.Span{490, 500}), frame, ast.Span{487, 501})
			generatedWrite(context, "/", frame, ast.Span{501, 502})
			generatedWrite(context, generatedEscape(runtime, generatedLoopMeta(scope, "row").Size, frame, ast.Span{505, 514}), frame, ast.Span{502, 515})
			generatedWrite(context, ":", frame, ast.Span{515, 516})
			generatedWrite(context, generatedEscape(runtime, local_row_3.Name, frame, ast.Span{519, 527}), frame, ast.Span{516, 528})
			generatedWrite(context, ":", frame, ast.Span{528, 529})
			generatedWrite(context, generatedEscape(runtime, generatedLoopMeta(scope, "row").First, frame, ast.Span{532, 542}), frame, ast.Span{529, 543})
			generatedWrite(context, ":", frame, ast.Span{543, 544})
			generatedWrite(context, generatedEscape(runtime, generatedLoopMeta(scope, "row").Last, frame, ast.Span{547, 556}), frame, ast.Span{544, 557})
			generatedWrite(context, "</li>\u000a", frame, ast.Span{557, 563})
			scope.Loops["row"] = scope.Loops["row"][:len(scope.Loops["row"])-1]
		}
		if hadPrevious {
			scope.Locals["row"] = previous
		} else {
			delete(scope.Locals, "row")
		}
		if entriesSize == 0 {
			generatedWrite(context, "<li>empty</li>\u000a", frame, ast.Span{567, 582})
		}
	}
	generatedWrite(context, "</ul>\u000a", frame, ast.Span{586, 592})
	generatedEnter(context, "partial.tpl", frame, ast.Span{592, 607})
	func() {
		defer context.Leave()
		render_partial_tpl(assign, definitions, Input_partial_tpl{Values: local_values_1}, context, runtime, rootData, scope)
	}()
	if definitions.Content != nil {
		generatedWrite(context, "<p>defined</p>", frame, ast.Span{620, 634})
	} else {
		generatedWrite(context, "<p>missing</p>", frame, ast.Span{637, 651})
	}
	generatedWrite(context, "\u000a", frame, ast.Span{654, 655})
	{
		definition := definitions.Content
		if definition == nil {
			panic(runtime.Error(frame, ast.Span{655, 683}, errs.RuntimeBlockUndefined, "define content is not registered"))
		}
		if definition != nil && definition.HTML != nil {
			generatedWrite(context, *definition.HTML, frame, ast.Span{655, 683})
		} else {
			input := Input_card_tpl{}
			if definition != nil && definition.Data != nil {
				if definition.Data.Label != nil {
					input.Label = *definition.Data.Label
				}
			}
			input.Label = assign.Page.Title
			blockScope := render.NewScope()
			generatedEnter(context, "card.tpl", frame, ast.Span{655, 683})
			func() {
				defer context.Leave()
				render_card_tpl(assign, definitions, input, context, runtime, rootData, blockScope)
			}()
		}
	}
	generatedWrite(context, "</section>\u000a", frame, ast.Span{684, 695})
}

func render_partial_tpl(assign Assign, definitions *Definitions, input Input_partial_tpl, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	frame := render.NewFrame("partial.tpl", errs.LineIndex{0, 38}, rootData)
	scope.Locals["values"] = generatedValue(input.Values)
	generatedWrite(context, "<p class=\"included\">", frame, ast.Span{0, 20})
	generatedWrite(context, generatedEscape(runtime, generatedIndex[*float64](runtime, input.Values, float64(2), frame, ast.Span{23, 32}), frame, ast.Span{23, 32}), frame, ast.Span{20, 33})
	generatedWrite(context, "</p>\u000a", frame, ast.Span{33, 38})
}

func renderTemplate(target string, assign Assign, definitions *Definitions, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	switch target {
	case "layout.tpl":
		render_layout_tpl(assign, definitions, Input_layout_tpl{}, context, runtime, rootData, scope)
		return
	default:
		panic(context.Fail(errs.LoadNotFound, nil, nil, "template "+target+" does not exist"))
	}
}

type generatedTarget struct {
	target string
	html   *string
}

func generatedBindDefinitions(input map[string]template.DefineInput) (*Definitions, map[string]generatedTarget, error) {
	definitions := &Definitions{}
	targets := map[string]generatedTarget{}
	for id, input := range input {
		if !utf8.ValidString(id) {
			return nil, nil, &value.BindError{Code: errs.DataInvalidUTF8, Message: "a define id is not valid UTF-8"}
		}
		switch id {
		case "content":
			if input.HTML != nil {
				if input.Template != "" || input.Data != nil {
					return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
				}
				definitions.Content = &Definition[DefinitionData_card_tpl]{HTML: input.HTML}
				targets[id] = generatedTarget{html: input.HTML}
				continue
			}
			if input.Template != "card.tpl" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[DefinitionData_card_tpl]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				data, ok := bound.(*value.OrderedMap)
				if !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := DefinitionData_card_tpl{}
				if raw, found := data.Get("label"); found {
					if err := generatedCheck(raw, generatedType{Kind: "string"}, generatedRecordFields, "define."+id+".data."+"label"); err != nil {
						return nil, nil, err
					}
					converted, err := generatedAs[string](raw)
					if err != nil {
						return nil, nil, fmt.Errorf("define.%s.data.%s: %w", id, "label", err)
					}
					definitionData.Label = &converted
				}
				entry.Data = &definitionData
			}
			definitions.Content = entry
			targets[id] = generatedTarget{target: "card.tpl"}
		case "layout":
			if input.HTML != nil {
				return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
			}
			if input.Template != "layout.tpl" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[DefinitionData_layout_tpl]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				if _, ok := bound.(*value.OrderedMap); !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := DefinitionData_layout_tpl{}
				entry.Data = &definitionData
			}
			definitions.Layout = entry
			targets[id] = generatedTarget{target: "layout.tpl"}
		default:
			return nil, nil, fmt.Errorf("define.%s is not declared", id)
		}
	}
	return definitions, targets, nil
}

type GeneratedProgram struct {
	Runtime *template.RuntimeEnvironment
}

func NewGeneratedProgram(options template.Options) (*GeneratedProgram, error) {
	runtime, err := template.NewRuntimeEnvironment(options.Limits, options.Functions)
	if err != nil {
		return nil, err
	}
	return &GeneratedProgram{Runtime: runtime}, nil
}

type generatedPrepared struct {
	name        string
	target      string
	assign      Assign
	definitions *Definitions
	rootData    *value.OrderedMap
	env         functions.Env
	runtime     *template.RuntimeEnvironment
	html        *string
}

func (p *generatedPrepared) Render() (string, error) {
	return render.Guard(p.name, p.render)
}

func (p *generatedPrepared) render() (string, error) {
	context := render.NewContext(p.runtime, p.rootData, p.env, p.target)
	runtime := render.NewRuntimeBindings(context)
	scope := render.NewScope()
	if err := context.Enter(p.target, nil, nil); err != nil {
		return "", err
	}
	defer context.Leave()
	if p.html != nil {
		if err := context.Write(*p.html, nil, nil); err != nil {
			return "", err
		}
	} else {
		renderTemplate(p.target, p.assign, p.definitions, context, runtime, p.rootData, scope)
	}
	return context.Output(), nil
}

func (p *GeneratedProgram) Prepare(target any, assign any, options template.RenderOptions) (template.Prepared, error) {
	name, ok := target.(string)
	if !ok {
		return nil, fmt.Errorf("generated target must be a template name")
	}
	return render.Guard(name, func() (template.Prepared, error) {
		return p.prepare(name, assign, options)
	})
}

func generatedBindFailure(name string, err error) error {
	var bindError *value.BindError
	if errors.As(err, &bindError) {
		return errs.WithoutPosition(bindError.Code, name, bindError.Message)
	}
	return err
}

func (p *GeneratedProgram) prepare(name string, assign any, options template.RenderOptions) (template.Prepared, error) {
	rootData, err := value.BindMap(assign)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	var typedAssign Assign
	if err := generatedCheckFields(rootData, []generatedField{{Name: "flag", Type: generatedType{Kind: "boolean"}}, {Name: "dangerous", Type: generatedType{Kind: "string"}}, {Name: "empty_list", Type: generatedType{Kind: "list", Item: &generatedType{Kind: "string"}}}, {Name: "empty_map", Type: generatedType{Kind: "map", Key: &generatedType{Kind: "string"}, Value: &generatedType{Kind: "string"}}}, {Name: "page", Type: generatedType{Kind: "record", Name: "Page"}}, {Name: "numbers", Type: generatedType{Kind: "list", Item: &generatedType{Kind: "number"}}}, {Name: "lookup", Type: generatedType{Kind: "map", Key: &generatedType{Kind: "string"}, Value: &generatedType{Kind: "string"}}}, {Name: "rows", Type: generatedType{Kind: "list", Item: &generatedType{Kind: "record", Name: "Row"}}}}, generatedRecordFields, "assign"); err != nil {
		return nil, err
	}
	if err := generatedDecode(rootData, &typedAssign); err != nil {
		return nil, err
	}
	definitions, targets, err := generatedBindDefinitions(options.Define)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	resolved := targets[name]
	targetName := name
	if resolved.target != "" {
		targetName = resolved.target
	}
	return &generatedPrepared{name: name, target: targetName, assign: typedAssign, definitions: definitions, rootData: rootData, env: generatedEnv(options), runtime: p.Runtime, html: resolved.html}, nil
}

func (p *GeneratedProgram) Render(target any, assign any, options template.RenderOptions) (string, error) {
	prepared, err := p.Prepare(target, assign, options)
	if err != nil {
		return "", err
	}
	return prepared.Render()
}

var _ template.Program = (*GeneratedProgram)(nil)


rust · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "rust",
  "entry": "layout.tpl",
  "sourceDigest": "936a20a5f3b77bc8a454a40c57b55de1118203b69a39aedda5acb0455f495625",
  "typeDigest": "30c0b093d1694670ec7117cc02b36e0031780485e6218be94afbdf1be6524db7",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "88d74f055ec030758070b516d0cd35473b90e243ae8571128c3187ba0162631f",
  "files": {
    "compiler-coverage.rust": {
      "path": "compiler-coverage.rust",
      "artifactDigest": "02a59e563c9a631b45a902749a27d20611407108b112fb622ddc077c92eb4e6f"
    }
  }
}

// Generated.
use polyspec_template::{ArgumentError, ErrorCode, OrderedMap as RuntimeOrderedMap, PreparedRender, Program, RenderOptions, RenderTarget, RequestError, RuntimeEnvironment, TemplateError, Value, internal_boundary};
use polyspec_template::error::LineIndex;
use polyspec_template::render::context::{Frame, RenderContext, Scope};
use polyspec_template::render::runtime_bindings::RuntimeBindings;
use serde_json::Value as JsonValue;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Clone, Default)] pub struct Assign {
    pub flag: bool,
    pub dangerous: String,
    pub empty_list: Vec<String>,
    pub empty_map: OrderedMap<String, String>,
    pub page: Page,
    pub numbers: Vec<f64>,
    pub lookup: OrderedMap<String, String>,
    pub rows: Vec<Row>,
}
impl GeneratedConvert for Assign { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; let _ = (&map, path); let flag = generated_field(map, path, "flag")?; let dangerous = generated_field(map, path, "dangerous")?; let empty_list = generated_field(map, path, "empty_list")?; let empty_map = generated_field(map, path, "empty_map")?; let page = generated_field(map, path, "page")?; let numbers = generated_field(map, path, "numbers")?; let lookup = generated_field(map, path, "lookup")?; let rows = generated_field(map, path, "rows")?; Ok(Assign { flag, dangerous, empty_list, empty_map, page, numbers, lookup, rows }) } fn to_value(&self) -> Value { let mut map = RuntimeOrderedMap::new(); map.insert("flag".to_string(), self.flag.to_value()); map.insert("dangerous".to_string(), self.dangerous.to_value()); map.insert("empty_list".to_string(), self.empty_list.to_value()); map.insert("empty_map".to_string(), self.empty_map.to_value()); map.insert("page".to_string(), self.page.to_value()); map.insert("numbers".to_string(), self.numbers.to_value()); map.insert("lookup".to_string(), self.lookup.to_value()); map.insert("rows".to_string(), self.rows.to_value()); Value::map(map) } }
#[derive(Clone, Default)] pub struct InputCardTpl { pub label: String }
#[derive(Clone, Default)] pub struct InputLayoutTpl {  }
#[derive(Clone, Default)] pub struct InputPartialTpl { pub values: Vec<f64> }
#[derive(Clone, Default)] pub struct DefinitionDataCardTpl { pub label: Option<String> }
#[derive(Clone, Default)] pub struct DefinitionDataLayoutTpl {  }
#[derive(Clone, Default)] pub struct Definition<T> { pub html: Option<String>, pub data: Option<T> }
#[derive(Clone, Default)] pub struct Definitions { pub content: Option<Definition<DefinitionDataCardTpl>>, pub layout: Option<Definition<DefinitionDataLayoutTpl>> }
#[derive(Clone, Default)] pub struct Page { pub title: String }
impl GeneratedConvert for Page { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; let _ = (&map, path); let title = generated_field(map, path, "title")?; Ok(Page { title }) } fn to_value(&self) -> Value { let mut map = RuntimeOrderedMap::new(); map.insert("title".to_string(), self.title.to_value()); Value::map(map) } }
#[derive(Clone, Default)] pub struct Row { pub name: String }
impl GeneratedConvert for Row { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; let _ = (&map, path); let name = generated_field(map, path, "name")?; Ok(Row { name }) } fn to_value(&self) -> Value { let mut map = RuntimeOrderedMap::new(); map.insert("name".to_string(), self.name.to_value()); Value::map(map) } }
#[derive(Clone)] struct OrderedEntry<K, V> { key: K, value: V }
#[derive(Clone, Default)] pub struct OrderedMap<K, V> { entries: Vec<OrderedEntry<K, V>> }
impl<K: PartialEq, V> OrderedMap<K, V> { fn new() -> Self { Self { entries: Vec::new() } } fn set(&mut self, key: K, value: V) { if let Some(entry) = self.entries.iter_mut().find(|entry| entry.key == key) { entry.value = value; } else { self.entries.push(OrderedEntry { key, value }); } } }
impl<K: GeneratedConvert + PartialEq, V: GeneratedConvert> GeneratedConvert for OrderedMap<K, V> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; let mut result = OrderedMap::new(); for (key, value) in map.iter() { result.set(K::from_value(&Value::text(key.clone()), path)?, V::from_value(value, &format!("{path}.{key}"))?); } Ok(result) } fn to_value(&self) -> Value { let mut map = RuntimeOrderedMap::new(); for entry in &self.entries { map.insert(entry.key.to_value().as_text().unwrap_or_default().to_string(), entry.value.to_value()); } Value::map(map) } }
fn generated_conversion_error(message: impl Into<String>) -> TemplateError { TemplateError::without_position(ErrorCode::E_RUNTIME_TYPE, "generated", message) }
pub trait GeneratedConvert: Sized { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError>; fn to_value(&self) -> Value; }
impl GeneratedConvert for Value { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let _ = path; Ok(input.clone()) } fn to_value(&self) -> Value { self.clone() } }
impl GeneratedConvert for String { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { input.as_text().map(str::to_string).ok_or_else(|| generated_type_error(input, path, "a string")) } fn to_value(&self) -> Value { Value::text(self.clone()) } }
impl GeneratedConvert for f64 { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Number(number) => Ok(*number), _ => Err(generated_type_error(input, path, "a number")) } } fn to_value(&self) -> Value { Value::Number(*self) } }
impl GeneratedConvert for bool { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Bool(value) => Ok(*value), _ => Err(generated_type_error(input, path, "a boolean")) } } fn to_value(&self) -> Value { Value::Bool(*self) } }
impl<T: GeneratedConvert> GeneratedConvert for Option<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Null => Ok(None), other => T::from_value(other, path).map(Some) } } fn to_value(&self) -> Value { self.as_ref().map_or(Value::Null, T::to_value) } }
impl<T: GeneratedConvert> GeneratedConvert for Vec<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::List(items) => items.iter().enumerate().map(|(index, item)| T::from_value(item, &format!("{path}[{index}]"))).collect(), _ => Err(generated_type_error(input, path, "a list")) } } fn to_value(&self) -> Value { Value::list(self.iter().map(T::to_value).collect()) } }
fn generated_type_error(input: &Value, path: &str, expected: &str) -> TemplateError { generated_conversion_error(if matches!(input, Value::Null) { format!("{path} is required") } else { format!("{path} is not {expected}") }) }
fn generated_field<T: GeneratedConvert>(map: &RuntimeOrderedMap, path: &str, name: &str) -> Result<T, TemplateError> { T::from_value(map.get(name).unwrap_or(&Value::Null), &format!("{path}.{name}")) }
fn generated_value<T: GeneratedConvert>(input: &T) -> Result<Value, TemplateError> { Ok(input.to_value()) }
fn generated_result<T: GeneratedConvert>(input: &Value, path: &str) -> Result<T, TemplateError> { T::from_value(input, path) }
fn generated_loop_meta(runtime: &RuntimeBindings, context: &RenderContext<'_>, scope: &Scope, frame: &Frame, span: polyspec_template::error::Span, name: &str, field: &str) -> Result<Value, TemplateError> { let meta = scope.loop_meta(name).ok_or_else(|| runtime.error(context, frame, span, ErrorCode::E_RUNTIME_UNKNOWN_LOOP, format!("loop {name} is not active")))?; Ok(match field { "index_" => Value::Number(meta.index as f64), "size_" => Value::Number(meta.size as f64), "first_" => Value::Bool(meta.first), "last_" => Value::Bool(meta.last), "key_" => meta.key.clone(), "value_" => meta.value.clone(), _ => return Err(runtime.error(context, frame, span, ErrorCode::E_RUNTIME_UNKNOWN_LOOP, format!("loop {name} has no metadata {field}"))) }) }
fn render_card_tpl(assign: &Assign, definitions: &mut Definitions, input: InputCardTpl, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { let _ = (&assign, &definitions, &input, &runtime, &scope); let frame = Frame { name: "card.tpl".to_string(), lines: Some(LineIndex::from_starts(vec![0, 30])), context: Rc::clone(root_data) };
scope.locals.insert("label".to_string(), generated_value(&input.label)?);
    context.write("<p class=\"card\">", &frame, [0, 16])?;
    let escaped = runtime.escape(context, &scope.lookup(&frame, "label"), &frame, [19, 24])?; context.write(&escaped, &frame, [16, 25])?;
    context.write("</p>\u{a}", &frame, [25, 30])?;
 Ok(()) }
fn render_layout_tpl(assign: &Assign, definitions: &mut Definitions, input: InputLayoutTpl, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { let _ = (&assign, &definitions, &input, &runtime, &scope); let frame = Frame { name: "layout.tpl".to_string(), lines: Some(LineIndex::from_starts(vec![0, 29, 66, 76, 100, 137, 191, 268, 305, 392, 463, 468, 483, 563, 567, 582, 586, 592, 608, 655, 684, 695])), context: Rc::clone(root_data) };

    scope.locals.insert("values".to_string(), { let mut result = Vec::new(); result.push(Value::Number(0f64)); result.extend(runtime.list_spread(context, &generated_value(&assign.numbers)?, &frame, [16, 26])?); runtime.depth(context, Value::list(result), &frame, [12, 27])? });
    scope.locals.insert("merged".to_string(), { let mut result = RuntimeOrderedMap::new(); for (key, value) in runtime.map_spread(context, &generated_value(&assign.lookup)?, &frame, [42, 51])?.iter() { result.insert(key.clone(), value.clone()); } result.insert(runtime.stringify(context, &Value::text("z"), &frame, [53, 56])?, Value::text("Z")); runtime.depth(context, Value::map(result), &frame, [41, 64])? });
    context.write("<section>\u{a}<h1>", &frame, [66, 80])?;
    let escaped = runtime.escape(context, &runtime.member(context, &generated_value(&assign.page)?, "title", &frame, [83, 93])?, &frame, [83, 93])?; context.write(&escaped, &frame, [80, 94])?;
    context.write("</h1>\u{a}<p class=\"escaped\">", &frame, [94, 119])?;
    let escaped = runtime.escape(context, &generated_value(&assign.dangerous)?, &frame, [122, 131])?; context.write(&escaped, &frame, [119, 132])?;
    context.write("</p>\u{a}<p class=\"logical\">", &frame, [132, 156])?;
    let escaped = runtime.escape(context, &{ let left = generated_value(&assign.flag)?; Value::Bool(if !runtime.truthy(&left) { false } else { runtime.truthy(&Value::text("x")) }) }, &frame, [159, 170])?; context.write(&escaped, &frame, [156, 171])?;
    context.write("|", &frame, [171, 172])?;
    let escaped = runtime.escape(context, &{ let left = Value::Bool(false); Value::Bool(if runtime.truthy(&left) { true } else { runtime.truthy(&Value::Number(2f64)) }) }, &frame, [175, 185])?; context.write(&escaped, &frame, [172, 186])?;
    context.write("</p>\u{a}<p class=\"empty-truthiness\">", &frame, [186, 219])?;
    let escaped = runtime.escape(context, &{ let left = generated_value(&assign.empty_list)?; Value::Bool(if !runtime.truthy(&left) { false } else { runtime.truthy(&generated_value(&assign.flag)?) }) }, &frame, [222, 240])?; context.write(&escaped, &frame, [219, 241])?;
    context.write("|", &frame, [241, 242])?;
    let escaped = runtime.escape(context, &{ let left = generated_value(&assign.empty_map)?; Value::Bool(if !runtime.truthy(&left) { false } else { runtime.truthy(&generated_value(&assign.flag)?) }) }, &frame, [245, 262])?; context.write(&escaped, &frame, [242, 263])?;
    context.write("</p>\u{a}<p>", &frame, [263, 271])?;
    let escaped = runtime.escape(context, &runtime.index(context, &scope.lookup(&frame, "values"), &Value::Number(1f64), &frame, [274, 283])?, &frame, [274, 283])?; context.write(&escaped, &frame, [271, 284])?;
    context.write("|", &frame, [284, 285])?;
    let escaped = runtime.escape(context, &runtime.index(context, &scope.lookup(&frame, "merged"), &Value::text("z"), &frame, [288, 299])?, &frame, [288, 299])?; context.write(&escaped, &frame, [285, 300])?;
    context.write("</p>\u{a}", &frame, [300, 305])?;
    if runtime.truthy(&{ let left = generated_value(&assign.flag)?; Value::Bool(if !runtime.truthy(&left) { false } else { runtime.truthy(&runtime.binary(context, polyspec_template::ast::BinaryOp::Equal, &runtime.member(context, &generated_value(&assign.page)?, "title", &frame, [316, 326])?, &Value::text("Guide"), &frame, [316, 337])?) }) }) {
        context.write("<strong>matched</strong>", &frame, [338, 362])?;    } else {
        context.write("<strong>missed</strong>", &frame, [365, 388])?;
    }
    context.write("\u{a}<p>", &frame, [391, 395])?;
    let escaped = runtime.escape(context, &if runtime.truthy(&generated_value(&assign.flag)?) { Value::text("yes") } else { Value::text("no") }, &frame, [398, 417])?; context.write(&escaped, &frame, [395, 418])?;
    context.write("|", &frame, [418, 419])?;
    let escaped = runtime.escape(context, &runtime.binary(context, polyspec_template::ast::BinaryOp::Add, &runtime.unary(context, polyspec_template::ast::UnaryOp::Negate, &Value::Number(1f64), &frame, [422, 424])?, &Value::Number(3f64), &frame, [422, 428])?, &frame, [422, 428])?; context.write(&escaped, &frame, [419, 429])?;
    context.write("|", &frame, [429, 430])?;
    let escaped = runtime.escape(context, &runtime.call(context, "default", vec![Value::text(""), Value::text("fallback")], &frame, [433, 457])?, &frame, [433, 457])?; context.write(&escaped, &frame, [430, 458])?;
    context.write("</p>\u{a}<ul>\u{a}", &frame, [458, 468])?;
    { let entries = runtime.entries(context, &generated_value(&assign.rows)?, &frame, [468, 585])?;
    let row_size = entries.len();
    let row_last_index = entries.len().saturating_sub(1);
    let row_previous = scope.locals.get("row").cloned();
    for (row_index_raw, (row_key, row_value)) in entries.iter().cloned().enumerate() {
        scope.locals.insert("row".to_string(), row_value.clone());
        scope.loops.entry("row".to_string()).or_default().push(polyspec_template::render::context::LoopMeta { index: row_index_raw, key: row_key, value: row_value, first: row_index_raw == 0, last: row_index_raw == row_last_index, size: row_size });
        context.iterations += 1;
        runtime.limit(context, "iteration", context.iterations, &frame, [468, 585])?;
            context.write("<li>", &frame, [483, 487])?;
            let escaped = runtime.escape(context, &generated_loop_meta(runtime, context, scope, &frame, [490, 500], "row", "index_")?, &frame, [490, 500])?; context.write(&escaped, &frame, [487, 501])?;
            context.write("/", &frame, [501, 502])?;
            let escaped = runtime.escape(context, &generated_loop_meta(runtime, context, scope, &frame, [505, 514], "row", "size_")?, &frame, [505, 514])?; context.write(&escaped, &frame, [502, 515])?;
            context.write(":", &frame, [515, 516])?;
            let escaped = runtime.escape(context, &runtime.member(context, &scope.lookup(&frame, "row"), "name", &frame, [519, 527])?, &frame, [519, 527])?; context.write(&escaped, &frame, [516, 528])?;
            context.write(":", &frame, [528, 529])?;
            let escaped = runtime.escape(context, &generated_loop_meta(runtime, context, scope, &frame, [532, 542], "row", "first_")?, &frame, [532, 542])?; context.write(&escaped, &frame, [529, 543])?;
            context.write(":", &frame, [543, 544])?;
            let escaped = runtime.escape(context, &generated_loop_meta(runtime, context, scope, &frame, [547, 556], "row", "last_")?, &frame, [547, 556])?; context.write(&escaped, &frame, [544, 557])?;
            context.write("</li>\u{a}", &frame, [557, 563])?;
        scope.loops.get_mut("row").expect("generated loop stack").pop();
    }
    if scope.loops.get("row").is_some_and(Vec::is_empty) { scope.loops.remove("row"); }
    if let Some(previous) = row_previous { scope.locals.insert("row".to_string(), previous); } else { scope.locals.remove("row"); }
    if entries.is_empty() {
            context.write("<li>empty</li>\u{a}", &frame, [567, 582])?;
    }
    }
    context.write("</ul>\u{a}", &frame, [586, 592])?;
    context.enter("partial.tpl", Some(&frame), Some([592, 607]))?;
    let rendered = render_partial_tpl(assign, definitions, InputPartialTpl { values: generated_result::<Vec<f64>>(&scope.lookup(&frame, "values"), "values")? }, context, runtime, root_data, scope);
    context.leave();
    rendered?;
    if definitions.content.is_some() {
            context.write("<p>defined</p>", &frame, [620, 634])?;
    } else {
            context.write("<p>missing</p>", &frame, [637, 651])?;
    }
    context.write("\u{a}", &frame, [654, 655])?;
    { if definitions.content.is_none() { return Err(runtime.error(context, &frame, [655, 683], ErrorCode::E_RUNTIME_BLOCK_UNDEFINED, "define content is not registered")); }
    let definition = definitions.content.clone();
    if let Some(html) = definition.as_ref().and_then(|value| value.html.as_ref()) { context.write(html, &frame, [655, 683])?; } else {
        let mut input = InputCardTpl::default();
        if let Some(data) = definition.as_ref().and_then(|value| value.data.as_ref()) && let Some(value) = data.label.clone() { input.label = value; }
        input.label = generated_result::<String>(&runtime.member(context, &generated_value(&assign.page)?, "title", &frame, [672, 682])?, "label")?;
        let mut block_scope = Scope::default();
        context.enter("card.tpl", Some(&frame), Some([655, 683]))?;
        let rendered = render_card_tpl(assign, definitions, input, context, runtime, root_data, &mut block_scope);
        context.leave();
        rendered?;
    }
    }
    context.write("</section>\u{a}", &frame, [684, 695])?;
 Ok(()) }
fn render_partial_tpl(assign: &Assign, definitions: &mut Definitions, input: InputPartialTpl, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { let _ = (&assign, &definitions, &input, &runtime, &scope); let frame = Frame { name: "partial.tpl".to_string(), lines: Some(LineIndex::from_starts(vec![0, 38])), context: Rc::clone(root_data) };
scope.locals.insert("values".to_string(), generated_value(&input.values)?);
    context.write("<p class=\"included\">", &frame, [0, 20])?;
    let escaped = runtime.escape(context, &runtime.index(context, &scope.lookup(&frame, "values"), &Value::Number(2f64), &frame, [23, 32])?, &frame, [23, 32])?; context.write(&escaped, &frame, [20, 33])?;
    context.write("</p>\u{a}", &frame, [33, 38])?;
 Ok(()) }
fn render_template(target: &str, assign: &Assign, definitions: &mut Definitions, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { match target {
        "layout.tpl" => render_layout_tpl(assign, definitions, InputLayoutTpl::default(), context, runtime, root_data, scope),
        _ => Err(context.fail(ErrorCode::E_LOAD_NOT_FOUND, None, None, format!("template {target} does not exist"))),
} }
fn generated_error(message: String) -> RequestError { RequestError::Argument(ArgumentError { message }) }
struct GeneratedTarget { target: Option<String>, html: Option<String> }
fn generated_bind_definitions(name: &str, input: &HashMap<String, polyspec_template::DefineInput>) -> Result<(Definitions, HashMap<String, GeneratedTarget>), RequestError> { let mut definitions = Definitions::default(); let mut targets = HashMap::new(); for (id, input) in input { match id.as_str() {
            "content" => { if let Some(html) = &input.html { if false || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.content = Some(Definition { html: Some(html.clone()), ..Default::default() }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("card.tpl") { return Err(generated_error(format!("define.{id} has an invalid template"))); }
let data = match &input.data { None => None, Some(data) => match polyspec_template::bind_data(data).map_err(|error| TemplateError::without_position(error.code, name, error.message))? { Value::Map(map) => { let _ = &map; Some(DefinitionDataCardTpl { label: map.get("label").map(|value| GeneratedConvert::from_value(value, &format!("define.{id}.data.label"))).transpose().map_err(|error| generated_error(error.message))? }) }, _ => return Err(generated_error(format!("define.{id}.data is not an object"))) } };
definitions.content = Some(Definition { data, ..Default::default() }); targets.insert(id.clone(), GeneratedTarget { target: Some("card.tpl".to_string()), html: None }); } },
            "layout" => { if let Some(html) = &input.html { if true || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.layout = Some(Definition { html: Some(html.clone()), ..Default::default() }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("layout.tpl") { return Err(generated_error(format!("define.{id} has an invalid template"))); }
let data = match &input.data { None => None, Some(data) => match polyspec_template::bind_data(data).map_err(|error| TemplateError::without_position(error.code, name, error.message))? { Value::Map(map) => { let _ = &map; Some(DefinitionDataLayoutTpl {  }) }, _ => return Err(generated_error(format!("define.{id}.data is not an object"))) } };
definitions.layout = Some(Definition { data, ..Default::default() }); targets.insert(id.clone(), GeneratedTarget { target: Some("layout.tpl".to_string()), html: None }); } },
            _ => return Err(generated_error(format!("define.{id} is not declared"))),
        } } Ok((definitions, targets)) }
pub struct GeneratedProgram { pub runtime: RuntimeEnvironment }
impl GeneratedProgram { pub fn new(runtime: RuntimeEnvironment) -> GeneratedProgram { GeneratedProgram { runtime } }  }
impl Program for GeneratedProgram { fn prepare(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || { let root_data = Rc::new(polyspec_template::value::bind::bind_map(assign).map_err(|error| TemplateError::without_position(error.code, name, error.message))?); self.prepare_root(name, root_data, options) }) } fn render(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare(target, assign, options)?.render()?) } fn prepare_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || self.prepare_root(name, polyspec_template::bound_root(assign), options)) } fn render_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare_bound(target, assign, options)?.render()?) } }
impl GeneratedProgram { fn prepare_root<'e>(&'e self, name: &str, root_data: Rc<RuntimeOrderedMap>, options: &RenderOptions) -> Result<PreparedRender<'e>, RequestError> { let typed_assign: Assign = Assign::from_value(&Value::Map(Rc::clone(&root_data)), "assign").map_err(|error| generated_error(error.message))?; let (definitions, targets) = generated_bind_definitions(name, &options.define)?; let resolved = targets.get(name); let target_name = resolved.and_then(|value| value.target.clone()).unwrap_or_else(|| name.to_string()); let html = resolved.and_then(|value| value.html.clone()); let env = options.env.clone().unwrap_or_else(|| polyspec_template::Env { timezone: "Z".to_string(), now: std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|duration| duration.as_secs() as f64).unwrap_or(0.0) }); Ok(PreparedRender::new(name, move || { let mut context = RenderContext::new(&self.runtime, Rc::clone(&root_data), env.clone(), &target_name); let runtime = RuntimeBindings::new(); let mut scope = Scope::default(); let mut render_definitions = definitions.clone(); context.enter(&target_name, None, None)?; let result = if let Some(html) = &html { let frame = Frame { name: target_name.clone(), lines: None, context: Rc::clone(&root_data) }; context.write(html, &frame, [0, 0]) } else { render_template(&target_name, &typed_assign, &mut render_definitions, &mut context, &runtime, &root_data, &mut scope) }; context.leave(); result?; Ok(context.output) })) } }


php · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "php",
  "entry": "layout.tpl",
  "sourceDigest": "936a20a5f3b77bc8a454a40c57b55de1118203b69a39aedda5acb0455f495625",
  "typeDigest": "30c0b093d1694670ec7117cc02b36e0031780485e6218be94afbdf1be6524db7",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "ba7f0bfd4d8024e26cbef4e9ddf0cd1e011489480f00daebb75a11ecfa8e218f",
  "files": {
    "Page.php": {
      "path": "Page.php",
      "artifactDigest": "cbffa5fc40d8cf9bc4f774d00647df3d4b3409b6a28c964e2c088cdaf4fa5b47"
    },
    "Row.php": {
      "path": "Row.php",
      "artifactDigest": "81c3d16d492639958c7fe3dfd592a98ae751d527785faafdc0a1a98f3a15c80b"
    },
    "Slot.php": {
      "path": "Slot.php",
      "artifactDigest": "039e1da3e55bda3debc78b45a39c5c0833b66d4635929b4e965311bb5bf637bc"
    },
    "Assign.php": {
      "path": "Assign.php",
      "artifactDigest": "7a46d541770077c3a43366552024d33fafffc44f260007682f528b2bfdb206fd"
    },
    "InputCardTpl.php": {
      "path": "InputCardTpl.php",
      "artifactDigest": "99c1740bed0945efc344b5d64f5997ad3d06a2a22891378a5ac753dc5267fa1b"
    },
    "InputLayoutTpl.php": {
      "path": "InputLayoutTpl.php",
      "artifactDigest": "90a8c10ab520b9a4b4331b9059a08e8e96a61fa275accbcadd45a2ca636d9647"
    },
    "InputPartialTpl.php": {
      "path": "InputPartialTpl.php",
      "artifactDigest": "0dc6c9bd0951fc713a2fdcb139edfb033b5bcfdd068946d8ed28a797750b1d71"
    },
    "DefinitionDataCardTpl.php": {
      "path": "DefinitionDataCardTpl.php",
      "artifactDigest": "571578dcca2072e25c17010c571b3a06d79698ddfbc1fb584d66b1dbc2d105a8"
    },
    "DefinitionDataLayoutTpl.php": {
      "path": "DefinitionDataLayoutTpl.php",
      "artifactDigest": "3678921062097582186777e14817310de4126a2c27212fc0f4119dc802d4fcab"
    },
    "DefinitionDataPartialTpl.php": {
      "path": "DefinitionDataPartialTpl.php",
      "artifactDigest": "e7189ec40151b92aeef12855c79edf8d4f8b25e3360156fc83fe9635f4f23dff"
    },
    "Definition.php": {
      "path": "Definition.php",
      "artifactDigest": "329d06a2941db3c464c437163ad1e21ab20b10533dafb463ae1febff303a22fa"
    },
    "Definitions.php": {
      "path": "Definitions.php",
      "artifactDigest": "2a01e1bd496f4da05fb3a864650e1378601c1db61380d76eb39161fd3fb58c20"
    },
    "ArtifactManifest.php": {
      "path": "ArtifactManifest.php",
      "artifactDigest": "ef8947a09ffc0b7fccd351f03e499115649587919a224b008af92d17ddeff03a"
    },
    "GeneratedRuntime.php": {
      "path": "GeneratedRuntime.php",
      "artifactDigest": "f47c6e4c65c0c9968475b5f8212649b3ffe52c1a1b6df1bd6403248c6a257d3b"
    },
    "GeneratedTemplates.php": {
      "path": "GeneratedTemplates.php",
      "artifactDigest": "8cef0a6b9e6140dd4fd3cd1b419910af458674c7f81bd3988b41923512464dd2"
    },
    "GeneratedExecution.php": {
      "path": "GeneratedExecution.php",
      "artifactDigest": "ba79633119f4765a2ea980fd34f53bfa8de88108ce74cf48864eb21409de290b"
    },
    "GeneratedProgram.php": {
      "path": "GeneratedProgram.php",
      "artifactDigest": "cc53ad4abb1dc4503fe6a743efb927db39ab6ab608f6abbcc392b84c11462d90"
    }
  }
}

<?php

declare(strict_types=1);

namespace Polyspec\Showcase\Generated\CompilerCoverage;

use Polyspec\Template\Render\Context;
use Polyspec\Template\Render\Frame;
use Polyspec\Template\Render\RuntimeBindings;
use Polyspec\Template\Render\Scope;
use Polyspec\Template\Value\MapValue;

final class GeneratedTemplates
{
    public static function render(
        string $target,
        Assign $assign,
        Definitions $definitions,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        switch ($target) {
            case 'layout.tpl':
                self::renderLayoutTpl(
                    $assign,
                    $definitions,
                    new InputLayoutTpl(),
                    $context,
                    $runtime,
                    $rootData,
                    $scope,
                );
                return;
            default:
                throw $context->fail('E_LOAD_NOT_FOUND', null, null, 'template ' . $target . ' does not exist');
        }
    }

    private static function renderCardTpl(
        Assign $assign,
        Definitions $definitions,
        InputCardTpl $input,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        $frame = new Frame('card.tpl', [0, 30], $rootData);
        $scope->locals->set('label', $input->label);
        $context->at($frame, [0, 16]);
        $context->write('<p class="card">');
        $context->at($frame, [16, 25]);
        $context->write($runtime->escape($scope->lookup($frame, 'label'), $frame, [19, 24]));
        $context->at($frame, [25, 30]);
        $context->write(('</p>' . "\n"));
    }

    private static function renderLayoutTpl(
        Assign $assign,
        Definitions $definitions,
        InputLayoutTpl $input,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        $frame = new Frame(
            'layout.tpl',
            [0, 29, 66, 76, 100, 137, 191, 268, 305, 392, 463, 468, 483, 563, 567, 582, 586, 592, 608, 655, 684, 695],
            $rootData,
        );
        $scope->locals->set(
            'values',
            $runtime->depth(
                GeneratedRuntime::list(
                    [
                        ['spread' => false, 'value' => 0],
                        ['spread' => true, 'value' => $runtime->listSpread($assign->numbers, $frame, [16, 26])],
                    ],
                ),
                $frame,
                [12, 27],
            ),
        );
        $scope->locals->set(
            'merged',
            $runtime->depth(
                GeneratedRuntime::map(
                    [
                        ['spread' => true, 'value' => $runtime->mapSpread($assign->lookup, $frame, [42, 51])],
                        ['spread' => false, 'key' => 'z', 'value' => 'Z'],
                    ],
                ),
                $frame,
                [41, 64],
            ),
        );
        $context->at($frame, [66, 80]);
        $context->write(('<section>' . "\n" . '<h1>'));
        $context->at($frame, [80, 94]);
        $context->write($runtime->escape($assign->page?->title, $frame, [83, 93]));
        $context->at($frame, [94, 119]);
        $context->write(('</h1>' . "\n" . '<p class="escaped">'));
        $context->at($frame, [119, 132]);
        $context->write($runtime->escape($assign->dangerous, $frame, [122, 131]));
        $context->at($frame, [132, 156]);
        $context->write(('</p>' . "\n" . '<p class="logical">'));
        $context->at($frame, [156, 171]);
        $context->write(
            $runtime->escape(($runtime->truthy($assign->flag) && $runtime->truthy('x')), $frame, [159, 170]),
        );
        $context->at($frame, [171, 172]);
        $context->write('|');
        $context->at($frame, [172, 186]);
        $context->write($runtime->escape(($runtime->truthy(false) || $runtime->truthy(2)), $frame, [175, 185]));
        $context->at($frame, [186, 219]);
        $context->write(('</p>' . "\n" . '<p class="empty-truthiness">'));
        $context->at($frame, [219, 241]);
        $context->write(
            $runtime->escape(
                ($runtime->truthy($assign->empty_list) && $runtime->truthy($assign->flag)),
                $frame,
                [222, 240],
            ),
        );
        $context->at($frame, [241, 242]);
        $context->write('|');
        $context->at($frame, [242, 263]);
        $context->write(
            $runtime->escape(
                ($runtime->truthy($assign->empty_map) && $runtime->truthy($assign->flag)),
                $frame,
                [245, 262],
            ),
        );
        $context->at($frame, [263, 271]);
        $context->write(('</p>' . "\n" . '<p>'));
        $context->at($frame, [271, 284]);
        $context->write(
            $runtime->escape(
                $runtime->index($scope->lookup($frame, 'values'), 1, $frame, [274, 283]),
                $frame,
                [274, 283],
            ),
        );
        $context->at($frame, [284, 285]);
        $context->write('|');
        $context->at($frame, [285, 300]);
        $context->write(
            $runtime->escape(
                $runtime->index($scope->lookup($frame, 'merged'), 'z', $frame, [288, 299]),
                $frame,
                [288, 299],
            ),
        );
        $context->at($frame, [300, 305]);
        $context->write(('</p>' . "\n"));
        if (
            $runtime->truthy(
                ($runtime->truthy($assign->flag)
                    && $runtime->truthy($runtime->binary('==', $assign->page?->title, 'Guide', $frame, [316, 337]))),
            )
        ) {
            $context->at($frame, [338, 362]);
            $context->write('<strong>matched</strong>');
        } else {
            $context->at($frame, [365, 388]);
            $context->write('<strong>missed</strong>');
        }
        $context->at($frame, [391, 395]);
        $context->write(("\n" . '<p>'));
        $context->at($frame, [395, 418]);
        $context->write($runtime->escape(($runtime->truthy($assign->flag) ? 'yes' : 'no'), $frame, [398, 417]));
        $context->at($frame, [418, 419]);
        $context->write('|');
        $context->at($frame, [419, 429]);
        $context->write(
            $runtime->escape(
                $runtime->binary('+', $runtime->unary('-', 1, $frame, [422, 424]), 3, $frame, [422, 428]),
                $frame,
                [422, 428],
            ),
        );
        $context->at($frame, [429, 430]);
        $context->write('|');
        $context->at($frame, [430, 458]);
        $context->write(
            $runtime->escape($runtime->call('default', ['', 'fallback'], $frame, [433, 457]), $frame, [433, 457]),
        );
        $context->at($frame, [458, 468]);
        $context->write(('</p>' . "\n" . '<ul>' . "\n"));
        $row_entries = $runtime->entries($assign->rows, $frame, [468, 585]);
        $row_size = count($row_entries);
        $row_last_index = $row_size - 1;
        $row_had = $scope->locals->has('row');
        $row_previous = $scope->locals->get('row');
        foreach ($row_entries as $row_index => [$row_key, $row_value]) {
            $scope->locals->set('row', $row_value);
            $row_stack = $scope->loops['row'] ?? [];
            $row_stack[] = [
                'index_' => (float) $row_index,
                'size_' => (float) $row_size,
                'first_' => $row_index === 0,
                'last_' => $row_index === $row_last_index,
                'key_' => $row_key,
                'value_' => $row_value,
            ];
            $scope->loops['row'] = $row_stack;
            $context->iterations++;
            $runtime->limit('iteration', $context->iterations, $frame, [468, 585]);
            $context->at($frame, [483, 487]);
            $context->write('<li>');
            $context->at($frame, [487, 501]);
            $context->write($runtime->escape($scope->loopMeta('row')['index_'], $frame, [490, 500]));
            $context->at($frame, [501, 502]);
            $context->write('/');
            $context->at($frame, [502, 515]);
            $context->write($runtime->escape($scope->loopMeta('row')['size_'], $frame, [505, 514]));
            $context->at($frame, [515, 516]);
            $context->write(':');
            $context->at($frame, [516, 528]);
            $context->write($runtime->escape($scope->lookup($frame, 'row')?->name, $frame, [519, 527]));
            $context->at($frame, [528, 529]);
            $context->write(':');
            $context->at($frame, [529, 543]);
            $context->write($runtime->escape($scope->loopMeta('row')['first_'], $frame, [532, 542]));
            $context->at($frame, [543, 544]);
            $context->write(':');
            $context->at($frame, [544, 557]);
            $context->write($runtime->escape($scope->loopMeta('row')['last_'], $frame, [547, 556]));
            $context->at($frame, [557, 563]);
            $context->write(('</li>' . "\n"));
            $row_stack = $scope->loops['row'];
            array_pop($row_stack);
            if ($row_stack === []) {
                unset($scope->loops['row']);
            } else {
                $scope->loops['row'] = $row_stack;
            }
        }
        if ($row_had) {
            $scope->locals->set('row', $row_previous);
        } else {
            $scope->locals->remove('row');
        }
        if ($row_size === 0) {
            $context->at($frame, [567, 582]);
            $context->write(('<li>empty</li>' . "\n"));
        }
        $context->at($frame, [586, 592]);
        $context->write(('</ul>' . "\n"));
        $context->enter('partial.tpl', $frame, [592, 607]);
        try {
            self::renderPartialTpl(
                $assign,
                $definitions,
                new InputPartialTpl(values: $scope->lookup($frame, 'values')),
                $context,
                $runtime,
                $rootData,
                $scope,
            );
        } finally {
            $context->leave();
        }
        if ($definitions->content !== null) {
            $context->at($frame, [620, 634]);
            $context->write('<p>defined</p>');
        } else {
            $context->at($frame, [637, 651]);
            $context->write('<p>missing</p>');
        }
        $context->at($frame, [654, 655]);
        $context->write("\n");
        $definition = $definitions->content;
        if ($definition === null) {
            throw $runtime->error($frame, [655, 683], 'E_RUNTIME_BLOCK_UNDEFINED', 'define content is not registered');
        }
        if ($definition?->html !== null) {
            $context->at($frame, [655, 683]);
            $context->write($definition->html);
        } else {
            if ($definition?->data !== null && !($definition->data instanceof DefinitionDataCardTpl)) {
                throw $runtime->error(
                    $frame,
                    [655, 683],
                    'E_RUNTIME_TYPE',
                    'generated definition content data has an invalid type',
                );
            }
            $scoped_label = $assign->page?->title;
            $input = new InputCardTpl(label: $scoped_label);
            if ($definition?->data !== null) {
                if ($definition->data->has_label) {
                    $input->label = $definition->data->label;
                }
            }
            $input->label = $scoped_label;
            $blockScope = new Scope();
            $context->enter('card.tpl', $frame, [655, 683]);
            try {
                self::renderCardTpl($assign, $definitions, $input, $context, $runtime, $rootData, $blockScope);
            } finally {
                $context->leave();
            }
        }
        $context->at($frame, [684, 695]);
        $context->write(('</section>' . "\n"));
    }

    private static function renderPartialTpl(
        Assign $assign,
        Definitions $definitions,
        InputPartialTpl $input,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        $frame = new Frame('partial.tpl', [0, 38], $rootData);
        $scope->locals->set('values', $input->values);
        $context->at($frame, [0, 20]);
        $context->write('<p class="included">');
        $context->at($frame, [20, 33]);
        $context->write(
            $runtime->escape($runtime->index($scope->lookup($frame, 'values'), 2, $frame, [23, 32]), $frame, [23, 32]),
        );
        $context->at($frame, [33, 38]);
        $context->write(('</p>' . "\n"));
    }
}

Output · 351 bytes · f9e5af2122de…

<section>
<h1>Guide</h1>
<p class="escaped">&amp;&lt;&gt;&quot;&#39;</p>
<p class="logical">true|true</p>
<p class="empty-truthiness">false|false</p>
<p>10|Z</p>
<strong>matched</strong>
<p>yes|2|fallback</p>
<ul>
<li>0/2:A:true:false</li>
<li>1/2:B:false:true</li>
</ul>
<p class="included">20</p>
<p>defined</p>
<p class="card">Guide</p>
</section>
Implementationtsgorustphppython
artifact renderPASSPASSPASSPASSPASS

Empty definition branch

An if-block checks whether a contents definition exists and renders a stable empty state when it does not.

layout targetmissing definitionempty state

Inputs

assign
{
  "page": "empty"
}
define
{
  "layout": "layout.tpl"
}
templates · parser ranges
--- layout.tpl
<main class="empty-page">
{?# content}
{# content}
{:}
<p class="empty">No content definition.</p>
{/}
</main>
compiled artifacts
ast/manifest.json
{
  "schema": 3,
  "mode": "ast",
  "target": "canonical",
  "entry": "layout.tpl",
  "delimiters": null,
  "sourceDigest": "b35ff56c22d316b47ee800072a43ac824e2a635029c6d44d79dea93631ed3e78",
  "typeDigest": "5b636e35624f3d01bf615d9b970af6434b57be8080120f7da054104556517597",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "fb8049870573426dd093e2af0cf544e3592477ef1af415453fafcf71f0389901",
  "files": {
    "layout.tpl": {
      "path": "layout.tpl.ast.json",
      "sourceDigest": "8c95f1682dd85b85cd8c18e4e37e651b8285bb45d1af72ff1e8305fc92db03f9",
      "artifactDigest": "0b3c0693679ac4dce1fa3861764cd8af85ca089e1d106bfee52c7f70aa04cea7",
      "lines": [
        0,
        26,
        39,
        51,
        55,
        99,
        103,
        111
      ]
    }
  }
}

ast/layout.tpl.ast.json · layout.tpl
{
  "type": "Template",
  "name": "layout.tpl",
  "body": [
    {
      "type": "Text",
      "value": "<main class=\"empty-page\">\n",
      "span": [
        0,
        26
      ]
    },
    {
      "type": "IfBlock",
      "id": "content",
      "body": [
        {
          "type": "Block",
          "id": "content",
          "path": null,
          "scope": [],
          "span": [
            39,
            50
          ]
        }
      ],
      "else": [
        {
          "type": "Text",
          "value": "<p class=\"empty\">No content definition.</p>\n",
          "span": [
            55,
            99
          ]
        }
      ],
      "span": [
        26,
        102
      ]
    },
    {
      "type": "Text",
      "value": "</main>\n",
      "span": [
        103,
        111
      ]
    }
  ],
  "comments": []
}
generated renderers
typescript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "ts",
  "entry": "layout.tpl",
  "sourceDigest": "b35ff56c22d316b47ee800072a43ac824e2a635029c6d44d79dea93631ed3e78",
  "typeDigest": "5b636e35624f3d01bf615d9b970af6434b57be8080120f7da054104556517597",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "a81f5f0f977b099b35dd1267160848c835a8aaf7c6865ac99d066a351070cbb0",
  "files": {
    "empty-state.ts": {
      "path": "empty-state.ts",
      "artifactDigest": "e003f0c6ed34e25c452c17d2aa575af7c81ac1c911f08be726947e0b2924aab0"
    }
  }
}

// Generated.
import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary, type MapValue, type PreparedRender, type Program, type RenderOptions, type Template, type Value } from '@polyspec/template';

export interface Assign {
  page: string;
}
export interface Input_layout_tpl {  }
export type DefinitionData<T> = Partial<T>;
export interface Definition<T> { template?: string; html?: string; data?: DefinitionData<T>; }
export interface Definitions { content?: Definition<Record<never, never>>; layout?: Definition<Input_layout_tpl>; }
export interface ArtifactManifest { schema: number; mode: 'gen'; target: 'ts'; entry: string; sourceDigest: string; typeDigest: string; contractDigest: string; files: Record<string, string>; }
function generatedTypeError(value: Value | undefined, path: string, expected: string): Error { return new Error(value === null || value === undefined ? path + ' is required' : path + ' is not ' + expected); }
function generatedDataObject(value: Value, path: string): MapValue { if (value instanceof Map) return value; throw new Error(path + ' is not an object'); }
function generatedPlain(value: unknown): value is object { if (typeof value !== 'object' || value === null) return false; const prototype = Reflect.getPrototypeOf(value); return prototype === Object.prototype || prototype === null; }
function generatedObject(value: Value | undefined, path: string): MapValue { if (value instanceof Map) return value; throw generatedTypeError(value, path, 'an object'); }
function generatedString(value: Value | undefined, path: string): string { if (typeof value === 'string') return value; throw generatedTypeError(value, path, 'a string'); }
function generatedDecodeAssign(value: Value | undefined, path: string): Assign { const object = generatedObject(value, path); return { page: generatedString(object.get("page"), path + ".page") }; }
function generatedDecodeData_Input_layout_tpl(value: Value, path: string): DefinitionData<Input_layout_tpl> { generatedDataObject(value, path); return {}; }
function generatedBindAssign(value: unknown): { assign: Assign; root: MapValue } { const root = bindMap(value); return { assign: generatedDecodeAssign(root, 'assign'), root }; }
type GeneratedTarget = { target: string | null; html?: string };
type GeneratedBoundDefinitions = { definitions: Definitions; targets: Map<string, GeneratedTarget> };
function generatedBindDefinitions(input: unknown): GeneratedBoundDefinitions {
  const definitions: Definitions = {};
  const targets = new Map<string, GeneratedTarget>();
  if (input === undefined || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error('define is not an object');
  const entries: [string, unknown][] = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
    case "content": {
      if (typeof raw === 'string') {
        throw new Error("define.content has an invalid template");
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.content is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        if (template !== undefined || data !== undefined) throw new Error("define.content has an invalid html entry");
        definitions.content = { html }; targets.set("content", { target: null, html }); break;
      }
      throw new Error("define.content has an invalid template");
    }
    case "layout": {
      if (typeof raw === 'string') {
        if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl" }; targets.set("layout", { target: "layout.tpl" }); break;
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.layout is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        throw new Error("define.layout has an invalid html entry");
      }
      if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
      definitions.layout = { template: "layout.tpl", data: data === undefined ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") }; targets.set("layout", { target: "layout.tpl" }); break;
    }
    default: throw new Error('define.' + id + ' is not declared');
    }
  }
  return { definitions, targets };
}
function render_layout_tpl(_assign: Assign, definitions: Definitions, _input: Input_layout_tpl, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, _scope: Scope): void {
  const frame = new Frame("layout.tpl", [0,26,39,51,55,99,103,111], rootData);

    context.at(frame, [0,26]); context.output.write("<main class=\"empty-page\">\n");
    if (definitions.content !== undefined) {
        { const definition = definitions.content;
        if (definition?.html === undefined) throw runtime.error(frame, [39,50], 'E_RUNTIME_BLOCK_UNDEFINED', "define content is not registered");
        context.at(frame, [39,50]); context.output.write(definition.html);
        }
    } else {
        context.at(frame, [55,99]); context.output.write("<p class=\"empty\">No content definition.</p>\n");
    }
    context.at(frame, [103,111]); context.output.write("</main>\n");
}
function renderTemplate(target: string, assign: Assign, definitions: Definitions, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  switch (target) {
    case "layout.tpl": render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope); return;
    default: throw context.fail('E_LOAD_NOT_FOUND', null, null, 'template ' + target + ' does not exist');
  }
}
function generatedEnv(input: unknown): { timezone: string; now: number } { if (input === undefined || input === null) return { timezone: 'Z', now: Math.floor(Date.now() / 1000) }; if (!generatedPlain(input)) throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env is not an object'); const timezone = ('timezone' in input ? input.timezone : undefined) ?? 'Z'; const now = ('now' in input ? input.now : undefined) ?? Math.floor(Date.now() / 1000); if (typeof timezone !== 'string') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.timezone is not a string'); if (typeof now !== 'number') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.now is not a number'); return { timezone, now }; }
class GeneratedPreparedRender implements PreparedRender { private readonly name: string; private readonly execute: () => string; constructor(name: string, execute: () => string) { this.name = name; this.execute = execute; } render(): string { return internalBoundary(this.name, this.execute); } }
export class GeneratedProgram implements Program {
  readonly runtime: RuntimeEnvironment;
  constructor(runtime: RuntimeEnvironment = new RuntimeEnvironment()) { this.runtime = runtime; }
  prepare(target: string | Template, assign: unknown, options: RenderOptions = {}): PreparedRender { if (typeof target !== 'string') throw new Error('generated target must be a template name'); return internalBoundary(target, () => this.prepareBound(target, assign, options)); }
  private prepareBound(target: string, assign: unknown, options: RenderOptions): PreparedRender { let boundAssign: { assign: Assign; root: MapValue }; let bound: GeneratedBoundDefinitions; let env: { timezone: string; now: number }; try { boundAssign = generatedBindAssign(assign); bound = generatedBindDefinitions(options.define); env = generatedEnv(options.env); } catch (error) { if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message }); throw error; } const registered = bound.targets.get(target); const html = registered?.html; if (html !== undefined) return new GeneratedPreparedRender(target, () => html); const targetName = registered?.target ?? target; return new GeneratedPreparedRender(target, () => { const context = new RenderContext(this.runtime, boundAssign.root, env, targetName); const runtime = new RuntimeBindings(context); const scope = new Scope(); context.enter(targetName, null, null); try { renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope); return context.output.toString(); } finally { context.leave(); } }); }
  render(target: string | Template, assign: unknown, options: RenderOptions = {}): string { return this.prepare(target, assign, options).render(); }
}


javascript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "js",
  "entry": "layout.tpl",
  "sourceDigest": "b35ff56c22d316b47ee800072a43ac824e2a635029c6d44d79dea93631ed3e78",
  "typeDigest": "5b636e35624f3d01bf615d9b970af6434b57be8080120f7da054104556517597",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "7a758948ae54e846b8c9cb16fa604ebf4a8aa94725dd3cd63ae77c94b2fe1e05",
  "files": {
    "empty-state.js": {
      "path": "empty-state.js",
      "artifactDigest": "8fab434118f459ba3e314b479de5dcb1f1b929b1592ca417d20785bd701ddcc2"
    }
  }
}

import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary } from "@polyspec/template";
function generatedTypeError(value, path, expected) {
  return new Error(value === null || value === void 0 ? path + " is required" : path + " is not " + expected);
}
function generatedDataObject(value, path) {
  if (value instanceof Map) return value;
  throw new Error(path + " is not an object");
}
function generatedPlain(value) {
  if (typeof value !== "object" || value === null) return false;
  const prototype = Reflect.getPrototypeOf(value);
  return prototype === Object.prototype || prototype === null;
}
function generatedObject(value, path) {
  if (value instanceof Map) return value;
  throw generatedTypeError(value, path, "an object");
}
function generatedString(value, path) {
  if (typeof value === "string") return value;
  throw generatedTypeError(value, path, "a string");
}
function generatedDecodeAssign(value, path) {
  const object = generatedObject(value, path);
  return { page: generatedString(object.get("page"), path + ".page") };
}
function generatedDecodeData_Input_layout_tpl(value, path) {
  generatedDataObject(value, path);
  return {};
}
function generatedBindAssign(value) {
  const root = bindMap(value);
  return { assign: generatedDecodeAssign(root, "assign"), root };
}
function generatedBindDefinitions(input) {
  const definitions = {};
  const targets = /* @__PURE__ */ new Map();
  if (input === void 0 || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error("define is not an object");
  const entries = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
      case "content": {
        if (typeof raw === "string") {
          throw new Error("define.content has an invalid template");
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.content is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          if (template !== void 0 || data !== void 0) throw new Error("define.content has an invalid html entry");
          definitions.content = { html };
          targets.set("content", { target: null, html });
          break;
        }
        throw new Error("define.content has an invalid template");
      }
      case "layout": {
        if (typeof raw === "string") {
          if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
          definitions.layout = { template: "layout.tpl" };
          targets.set("layout", { target: "layout.tpl" });
          break;
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.layout is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          throw new Error("define.layout has an invalid html entry");
        }
        if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl", data: data === void 0 ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") };
        targets.set("layout", { target: "layout.tpl" });
        break;
      }
      default:
        throw new Error("define." + id + " is not declared");
    }
  }
  return { definitions, targets };
}
function render_layout_tpl(_assign, definitions, _input, context, runtime, rootData, _scope) {
  const frame = new Frame("layout.tpl", [0, 26, 39, 51, 55, 99, 103, 111], rootData);
  context.at(frame, [0, 26]);
  context.output.write('<main class="empty-page">\n');
  if (definitions.content !== void 0) {
    {
      const definition = definitions.content;
      if (definition?.html === void 0) throw runtime.error(frame, [39, 50], "E_RUNTIME_BLOCK_UNDEFINED", "define content is not registered");
      context.at(frame, [39, 50]);
      context.output.write(definition.html);
    }
  } else {
    context.at(frame, [55, 99]);
    context.output.write('<p class="empty">No content definition.</p>\n');
  }
  context.at(frame, [103, 111]);
  context.output.write("</main>\n");
}
function renderTemplate(target, assign, definitions, context, runtime, rootData, scope) {
  switch (target) {
    case "layout.tpl":
      render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope);
      return;
    default:
      throw context.fail("E_LOAD_NOT_FOUND", null, null, "template " + target + " does not exist");
  }
}
function generatedEnv(input) {
  if (input === void 0 || input === null) return { timezone: "Z", now: Math.floor(Date.now() / 1e3) };
  if (!generatedPlain(input)) throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env is not an object");
  const timezone = ("timezone" in input ? input.timezone : void 0) ?? "Z";
  const now = ("now" in input ? input.now : void 0) ?? Math.floor(Date.now() / 1e3);
  if (typeof timezone !== "string") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.timezone is not a string");
  if (typeof now !== "number") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.now is not a number");
  return { timezone, now };
}
class GeneratedPreparedRender {
  name;
  execute;
  constructor(name, execute) {
    this.name = name;
    this.execute = execute;
  }
  render() {
    return internalBoundary(this.name, this.execute);
  }
}
export class GeneratedProgram {
  runtime;
  constructor(runtime = new RuntimeEnvironment()) {
    this.runtime = runtime;
  }
  prepare(target, assign, options = {}) {
    if (typeof target !== "string") throw new Error("generated target must be a template name");
    return internalBoundary(target, () => this.prepareBound(target, assign, options));
  }
  prepareBound(target, assign, options) {
    let boundAssign;
    let bound;
    let env;
    try {
      boundAssign = generatedBindAssign(assign);
      bound = generatedBindDefinitions(options.define);
      env = generatedEnv(options.env);
    } catch (error) {
      if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message });
      throw error;
    }
    const registered = bound.targets.get(target);
    const html = registered?.html;
    if (html !== void 0) return new GeneratedPreparedRender(target, () => html);
    const targetName = registered?.target ?? target;
    return new GeneratedPreparedRender(target, () => {
      const context = new RenderContext(this.runtime, boundAssign.root, env, targetName);
      const runtime = new RuntimeBindings(context);
      const scope = new Scope();
      context.enter(targetName, null, null);
      try {
        renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope);
        return context.output.toString();
      } finally {
        context.leave();
      }
    });
  }
  render(target, assign, options = {}) {
    return this.prepare(target, assign, options).render();
  }
}


go · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "go",
  "entry": "layout.tpl",
  "sourceDigest": "b35ff56c22d316b47ee800072a43ac824e2a635029c6d44d79dea93631ed3e78",
  "typeDigest": "5b636e35624f3d01bf615d9b970af6434b57be8080120f7da054104556517597",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "45312e93dc75fa9cac0af4448f4b43508dff97b90f52d7c3d1407e5852dbc284",
  "files": {
    "generated.go": {
      "path": "generated.go",
      "artifactDigest": "1ad27bd79c1dab5d79046f65e54d2d5492513d9820f54f429183457e23dceb94"
    }
  }
}

// Code generated by @polyspec/template-compiler. DO NOT EDIT.

package generated

import (
	"encoding/json"
	"errors"
	"fmt"
	template "github.com/polyspec/template/packages/go"
	"github.com/polyspec/template/packages/go/ast"
	"github.com/polyspec/template/packages/go/errs"
	"github.com/polyspec/template/packages/go/functions"
	"github.com/polyspec/template/packages/go/render"
	"github.com/polyspec/template/packages/go/value"
	"time"
	"unicode/utf8"
)

type Assign struct {
	Page string `json:"page"`
}

type Input_layout_tpl struct{}

type DefinitionData_layout_tpl struct{}

type Definition[T any] struct {
	Template string  `json:"template"`
	HTML     *string `json:"html"`
	Data     *T      `json:"data"`
}

type Definitions struct {
	Content *Definition[struct{}]                  `json:"content"`
	Layout  *Definition[DefinitionData_layout_tpl] `json:"layout"`
}

type ArtifactManifest struct {
	Schema         int
	Mode           string
	Target         string
	Entry          string
	SourceDigest   string
	TypeDigest     string
	ContractDigest string
	Files          map[string]string
}

var generatedRecordFields = map[string][]generatedField{}

func generatedPanic(err error) {
	if err != nil {
		panic(err)
	}
}

func generatedWrite(context *render.Context, text string, frame *render.Frame, span ast.Span) {
	generatedPanic(context.Write(text, frame, &span))
}

func generatedPlain(input any) any {
	switch item := input.(type) {
	case *value.OrderedMap:
		result := map[string]any{}
		for _, key := range item.Keys() {
			entry, _ := item.Get(key)
			result[key] = generatedPlain(entry)
		}
		return result
	case value.List:
		result := make([]any, len(item))
		for index, entry := range item {
			result[index] = generatedPlain(entry)
		}
		return result
	default:
		return input
	}
}

type generatedType struct {
	Kind     string
	Optional bool
	Name     string
	Item     *generatedType
	Key      *generatedType
	Value    *generatedType
}

type generatedField struct {
	Name string
	Type generatedType
}

func generatedCheck(input value.Value, kind generatedType, records map[string][]generatedField, path string) error {
	if input == nil {
		if kind.Optional || kind.Kind == "any" {
			return nil
		}
		return fmt.Errorf("%s is required", path)
	}
	actual := value.TypeOf(input)
	switch kind.Kind {
	case "any":
		return nil
	case "string":
		if actual != value.TypeString {
			return fmt.Errorf("%s is not a string", path)
		}
	case "number":
		if actual != value.TypeNumber {
			return fmt.Errorf("%s is not a number", path)
		}
	case "boolean":
		if actual != value.TypeBool {
			return fmt.Errorf("%s is not a boolean", path)
		}
	case "list":
		items, ok := input.(value.List)
		if !ok {
			return fmt.Errorf("%s is not a list", path)
		}
		for index, item := range items {
			if err := generatedCheck(item, *kind.Item, records, fmt.Sprintf("%s[%d]", path, index)); err != nil {
				return err
			}
		}
	case "map":
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		for _, key := range entries.Keys() {
			item, _ := entries.Get(key)
			if err := generatedCheck(item, *kind.Value, records, path+"."+key); err != nil {
				return err
			}
		}
	default:
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		return generatedCheckFields(entries, records[kind.Name], records, path)
	}
	return nil
}

func generatedCheckFields(input *value.OrderedMap, fields []generatedField, records map[string][]generatedField, path string) error {
	for _, field := range fields {
		item, _ := input.Get(field.Name)
		if err := generatedCheck(item, field.Type, records, path+"."+field.Name); err != nil {
			return err
		}
	}
	return nil
}

func generatedDecode(input any, output any) error {
	data, err := json.Marshal(generatedPlain(input))
	if err != nil {
		return err
	}
	return json.Unmarshal(data, output)
}

func generatedEnv(options template.RenderOptions) functions.Env {
	env := functions.Env{Timezone: "Z", Now: float64(time.Now().Unix())}
	if options.Env != nil {
		if options.Env.Timezone != "" {
			env.Timezone = options.Env.Timezone
		}
		env.Now = options.Env.Now
	}
	return env
}

func render_layout_tpl(assign Assign, definitions *Definitions, input Input_layout_tpl, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	frame := render.NewFrame("layout.tpl", errs.LineIndex{0, 26, 39, 51, 55, 99, 103, 111}, rootData)
	generatedWrite(context, "<main class=\"empty-page\">\u000a", frame, ast.Span{0, 26})
	if definitions.Content != nil {
		{
			definition := definitions.Content
			if definition == nil || definition.HTML == nil {
				panic(runtime.Error(frame, ast.Span{39, 50}, errs.RuntimeBlockUndefined, "define content is not registered"))
			}
			generatedWrite(context, *definition.HTML, frame, ast.Span{39, 50})
		}
	} else {
		generatedWrite(context, "<p class=\"empty\">No content definition.</p>\u000a", frame, ast.Span{55, 99})
	}
	generatedWrite(context, "</main>\u000a", frame, ast.Span{103, 111})
}

func renderTemplate(target string, assign Assign, definitions *Definitions, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	switch target {
	case "layout.tpl":
		render_layout_tpl(assign, definitions, Input_layout_tpl{}, context, runtime, rootData, scope)
		return
	default:
		panic(context.Fail(errs.LoadNotFound, nil, nil, "template "+target+" does not exist"))
	}
}

type generatedTarget struct {
	target string
	html   *string
}

func generatedBindDefinitions(input map[string]template.DefineInput) (*Definitions, map[string]generatedTarget, error) {
	definitions := &Definitions{}
	targets := map[string]generatedTarget{}
	for id, input := range input {
		if !utf8.ValidString(id) {
			return nil, nil, &value.BindError{Code: errs.DataInvalidUTF8, Message: "a define id is not valid UTF-8"}
		}
		switch id {
		case "content":
			if input.HTML != nil {
				if input.Template != "" || input.Data != nil {
					return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
				}
				definitions.Content = &Definition[struct{}]{HTML: input.HTML}
				targets[id] = generatedTarget{html: input.HTML}
				continue
			}
			if input.Template != "" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[struct{}]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				if _, ok := bound.(*value.OrderedMap); !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := struct{}{}
				entry.Data = &definitionData
			}
			definitions.Content = entry
			targets[id] = generatedTarget{target: ""}
		case "layout":
			if input.HTML != nil {
				return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
			}
			if input.Template != "layout.tpl" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[DefinitionData_layout_tpl]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				if _, ok := bound.(*value.OrderedMap); !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := DefinitionData_layout_tpl{}
				entry.Data = &definitionData
			}
			definitions.Layout = entry
			targets[id] = generatedTarget{target: "layout.tpl"}
		default:
			return nil, nil, fmt.Errorf("define.%s is not declared", id)
		}
	}
	return definitions, targets, nil
}

type GeneratedProgram struct {
	Runtime *template.RuntimeEnvironment
}

func NewGeneratedProgram(options template.Options) (*GeneratedProgram, error) {
	runtime, err := template.NewRuntimeEnvironment(options.Limits, options.Functions)
	if err != nil {
		return nil, err
	}
	return &GeneratedProgram{Runtime: runtime}, nil
}

type generatedPrepared struct {
	name        string
	target      string
	assign      Assign
	definitions *Definitions
	rootData    *value.OrderedMap
	env         functions.Env
	runtime     *template.RuntimeEnvironment
	html        *string
}

func (p *generatedPrepared) Render() (string, error) {
	return render.Guard(p.name, p.render)
}

func (p *generatedPrepared) render() (string, error) {
	context := render.NewContext(p.runtime, p.rootData, p.env, p.target)
	runtime := render.NewRuntimeBindings(context)
	scope := render.NewScope()
	if err := context.Enter(p.target, nil, nil); err != nil {
		return "", err
	}
	defer context.Leave()
	if p.html != nil {
		if err := context.Write(*p.html, nil, nil); err != nil {
			return "", err
		}
	} else {
		renderTemplate(p.target, p.assign, p.definitions, context, runtime, p.rootData, scope)
	}
	return context.Output(), nil
}

func (p *GeneratedProgram) Prepare(target any, assign any, options template.RenderOptions) (template.Prepared, error) {
	name, ok := target.(string)
	if !ok {
		return nil, fmt.Errorf("generated target must be a template name")
	}
	return render.Guard(name, func() (template.Prepared, error) {
		return p.prepare(name, assign, options)
	})
}

func generatedBindFailure(name string, err error) error {
	var bindError *value.BindError
	if errors.As(err, &bindError) {
		return errs.WithoutPosition(bindError.Code, name, bindError.Message)
	}
	return err
}

func (p *GeneratedProgram) prepare(name string, assign any, options template.RenderOptions) (template.Prepared, error) {
	rootData, err := value.BindMap(assign)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	var typedAssign Assign
	if err := generatedCheckFields(rootData, []generatedField{{Name: "page", Type: generatedType{Kind: "string"}}}, generatedRecordFields, "assign"); err != nil {
		return nil, err
	}
	if err := generatedDecode(rootData, &typedAssign); err != nil {
		return nil, err
	}
	definitions, targets, err := generatedBindDefinitions(options.Define)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	resolved := targets[name]
	targetName := name
	if resolved.target != "" {
		targetName = resolved.target
	}
	return &generatedPrepared{name: name, target: targetName, assign: typedAssign, definitions: definitions, rootData: rootData, env: generatedEnv(options), runtime: p.Runtime, html: resolved.html}, nil
}

func (p *GeneratedProgram) Render(target any, assign any, options template.RenderOptions) (string, error) {
	prepared, err := p.Prepare(target, assign, options)
	if err != nil {
		return "", err
	}
	return prepared.Render()
}

var _ template.Program = (*GeneratedProgram)(nil)


rust · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "rust",
  "entry": "layout.tpl",
  "sourceDigest": "b35ff56c22d316b47ee800072a43ac824e2a635029c6d44d79dea93631ed3e78",
  "typeDigest": "5b636e35624f3d01bf615d9b970af6434b57be8080120f7da054104556517597",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "88d74f055ec030758070b516d0cd35473b90e243ae8571128c3187ba0162631f",
  "files": {
    "empty-state.rust": {
      "path": "empty-state.rust",
      "artifactDigest": "e83456aee19ca61515cbdde2e2c4551bcbb6cb6d4d75924b3947a2fa420ab7fb"
    }
  }
}

// Generated.
use polyspec_template::{ArgumentError, ErrorCode, OrderedMap as RuntimeOrderedMap, PreparedRender, Program, RenderOptions, RenderTarget, RequestError, RuntimeEnvironment, TemplateError, Value, internal_boundary};
use polyspec_template::error::LineIndex;
use polyspec_template::render::context::{Frame, RenderContext, Scope};
use polyspec_template::render::runtime_bindings::RuntimeBindings;
use serde_json::Value as JsonValue;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Clone, Default)] pub struct Assign {

}
impl GeneratedConvert for Assign { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; let _ = (&map, path); generated_check_field(map, path, "page", |value, path| <String as GeneratedConvert>::from_value(value, path).map(drop))?; Ok(Assign {  }) } }
#[derive(Clone, Default)] pub struct InputLayoutTpl {  }

#[derive(Clone, Default)] pub struct Definition { pub html: Option<String> }
#[derive(Clone, Default)] pub struct Definitions { pub content: Option<Definition>, pub layout: Option<Definition> }
fn generated_conversion_error(message: impl Into<String>) -> TemplateError { TemplateError::without_position(ErrorCode::E_RUNTIME_TYPE, "generated", message) }
pub trait GeneratedConvert: Sized { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError>; }
impl GeneratedConvert for Value { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let _ = path; Ok(input.clone()) } }
impl GeneratedConvert for String { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { input.as_text().map(str::to_string).ok_or_else(|| generated_type_error(input, path, "a string")) } }
impl GeneratedConvert for f64 { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Number(number) => Ok(*number), _ => Err(generated_type_error(input, path, "a number")) } } }
impl GeneratedConvert for bool { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Bool(value) => Ok(*value), _ => Err(generated_type_error(input, path, "a boolean")) } } }
impl<T: GeneratedConvert> GeneratedConvert for Option<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Null => Ok(None), other => T::from_value(other, path).map(Some) } } }
impl<T: GeneratedConvert> GeneratedConvert for Vec<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::List(items) => items.iter().enumerate().map(|(index, item)| T::from_value(item, &format!("{path}[{index}]"))).collect(), _ => Err(generated_type_error(input, path, "a list")) } } }
fn generated_type_error(input: &Value, path: &str, expected: &str) -> TemplateError { generated_conversion_error(if matches!(input, Value::Null) { format!("{path} is required") } else { format!("{path} is not {expected}") }) }
fn generated_check_field(map: &RuntimeOrderedMap, path: &str, name: &str, check: impl Fn(&Value, &str) -> Result<(), TemplateError>) -> Result<(), TemplateError> { check(map.get(name).unwrap_or(&Value::Null), &format!("{path}.{name}")) }
fn render_layout_tpl(assign: &Assign, definitions: &mut Definitions, input: InputLayoutTpl, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { let _ = (&assign, &definitions, &input, &runtime, &scope); let frame = Frame { name: "layout.tpl".to_string(), lines: Some(LineIndex::from_starts(vec![0, 26, 39, 51, 55, 99, 103, 111])), context: Rc::clone(root_data) };

    context.write("<main class=\"empty-page\">\u{a}", &frame, [0, 26])?;
    if definitions.content.is_some() {
            { let definition = definitions.content.as_ref();
            let Some(html) = definition.and_then(|value| value.html.as_ref()) else { return Err(runtime.error(context, &frame, [39, 50], ErrorCode::E_RUNTIME_BLOCK_UNDEFINED, "define content is not registered")); };
            context.write(html, &frame, [39, 50])?;
            }
    } else {
            context.write("<p class=\"empty\">No content definition.</p>\u{a}", &frame, [55, 99])?;
    }
    context.write("</main>\u{a}", &frame, [103, 111])?;
 Ok(()) }
fn render_template(target: &str, assign: &Assign, definitions: &mut Definitions, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { match target {
        "layout.tpl" => render_layout_tpl(assign, definitions, InputLayoutTpl::default(), context, runtime, root_data, scope),
        _ => Err(context.fail(ErrorCode::E_LOAD_NOT_FOUND, None, None, format!("template {target} does not exist"))),
} }
fn generated_error(message: String) -> RequestError { RequestError::Argument(ArgumentError { message }) }
struct GeneratedTarget { target: Option<String>, html: Option<String> }
fn generated_bind_definitions(name: &str, input: &HashMap<String, polyspec_template::DefineInput>) -> Result<(Definitions, HashMap<String, GeneratedTarget>), RequestError> { let mut definitions = Definitions::default(); let mut targets = HashMap::new(); for (id, input) in input { match id.as_str() {
            "content" => { if let Some(html) = &input.html { if false || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.content = Some(Definition { html: Some(html.clone()) }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("") { return Err(generated_error(format!("define.{id} has an invalid template"))); }

definitions.content = Some(Definition::default()); targets.insert(id.clone(), GeneratedTarget { target: Some("".to_string()), html: None }); } },
            "layout" => { if let Some(html) = &input.html { if true || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.layout = Some(Definition { html: Some(html.clone()) }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("layout.tpl") { return Err(generated_error(format!("define.{id} has an invalid template"))); }
if let Some(data) = &input.data { match polyspec_template::bind_data(data).map_err(|error| TemplateError::without_position(error.code, name, error.message))? { Value::Map(_) => {  }, _ => return Err(generated_error(format!("define.{id}.data is not an object"))) } }
definitions.layout = Some(Definition::default()); targets.insert(id.clone(), GeneratedTarget { target: Some("layout.tpl".to_string()), html: None }); } },
            _ => return Err(generated_error(format!("define.{id} is not declared"))),
        } } Ok((definitions, targets)) }
pub struct GeneratedProgram { pub runtime: RuntimeEnvironment }
impl GeneratedProgram { pub fn new(runtime: RuntimeEnvironment) -> GeneratedProgram { GeneratedProgram { runtime } }  }
impl Program for GeneratedProgram { fn prepare(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || { let root_data = Rc::new(polyspec_template::value::bind::bind_map(assign).map_err(|error| TemplateError::without_position(error.code, name, error.message))?); self.prepare_root(name, root_data, options) }) } fn render(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare(target, assign, options)?.render()?) } fn prepare_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || self.prepare_root(name, polyspec_template::bound_root(assign), options)) } fn render_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare_bound(target, assign, options)?.render()?) } }
impl GeneratedProgram { fn prepare_root<'e>(&'e self, name: &str, root_data: Rc<RuntimeOrderedMap>, options: &RenderOptions) -> Result<PreparedRender<'e>, RequestError> { let typed_assign: Assign = Assign::from_value(&Value::Map(Rc::clone(&root_data)), "assign").map_err(|error| generated_error(error.message))?; let (definitions, targets) = generated_bind_definitions(name, &options.define)?; let resolved = targets.get(name); let target_name = resolved.and_then(|value| value.target.clone()).unwrap_or_else(|| name.to_string()); let html = resolved.and_then(|value| value.html.clone()); let env = options.env.clone().unwrap_or_else(|| polyspec_template::Env { timezone: "Z".to_string(), now: std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|duration| duration.as_secs() as f64).unwrap_or(0.0) }); Ok(PreparedRender::new(name, move || { let mut context = RenderContext::new(&self.runtime, Rc::clone(&root_data), env.clone(), &target_name); let runtime = RuntimeBindings::new(); let mut scope = Scope::default(); let mut render_definitions = definitions.clone(); context.enter(&target_name, None, None)?; let result = if let Some(html) = &html { let frame = Frame { name: target_name.clone(), lines: None, context: Rc::clone(&root_data) }; context.write(html, &frame, [0, 0]) } else { render_template(&target_name, &typed_assign, &mut render_definitions, &mut context, &runtime, &root_data, &mut scope) }; context.leave(); result?; Ok(context.output) })) } }


php · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "php",
  "entry": "layout.tpl",
  "sourceDigest": "b35ff56c22d316b47ee800072a43ac824e2a635029c6d44d79dea93631ed3e78",
  "typeDigest": "5b636e35624f3d01bf615d9b970af6434b57be8080120f7da054104556517597",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "ba7f0bfd4d8024e26cbef4e9ddf0cd1e011489480f00daebb75a11ecfa8e218f",
  "files": {
    "Assign.php": {
      "path": "Assign.php",
      "artifactDigest": "33dd7be03cccfa8df884753b41aa87358a376f013446af017fd837fb8478829e"
    },
    "InputLayoutTpl.php": {
      "path": "InputLayoutTpl.php",
      "artifactDigest": "348fcbcbf8cf84bc3643787cf94a8f1eae4c23bc033437d7b21462fcdc643054"
    },
    "DefinitionDataLayoutTpl.php": {
      "path": "DefinitionDataLayoutTpl.php",
      "artifactDigest": "9eb0bca17b2c9bab2b5fc5c55c4e693ee30506e5bccbd90daca979f3af5eba65"
    },
    "Definition.php": {
      "path": "Definition.php",
      "artifactDigest": "a1093ec2b5227e20324d52a1482dc75d2f6b2b51e97ae9e07436329f90ffcb48"
    },
    "Definitions.php": {
      "path": "Definitions.php",
      "artifactDigest": "b8e7f758fcf26f1c251e8e7e9ea92b520d81f5935b795290b60b2337fb14a679"
    },
    "ArtifactManifest.php": {
      "path": "ArtifactManifest.php",
      "artifactDigest": "36fe6a4b728613284594e6dee1a568ec89f3fa6602fdcf1ef18f8318a7d2eb90"
    },
    "GeneratedRuntime.php": {
      "path": "GeneratedRuntime.php",
      "artifactDigest": "01187ceb3e740c6a11a40653b5023de290019d077c38c3fa3c76bcfe8e3e3046"
    },
    "GeneratedTemplates.php": {
      "path": "GeneratedTemplates.php",
      "artifactDigest": "d55948805e1fbb2cba152a4dab6c8bf0c66fd08a3b7580ef55223415d3666b84"
    },
    "GeneratedExecution.php": {
      "path": "GeneratedExecution.php",
      "artifactDigest": "6284308bda6da01266d53487c67dce52ebf5aa3569da9afa55f2c3fc2fa931df"
    },
    "GeneratedProgram.php": {
      "path": "GeneratedProgram.php",
      "artifactDigest": "037edcbc7e74a91d27320939790151e199b39d4fa7762ff28a9cabf324eee24a"
    }
  }
}

<?php

declare(strict_types=1);

namespace Polyspec\Showcase\Generated\EmptyState;

use Polyspec\Template\Render\Context;
use Polyspec\Template\Render\Frame;
use Polyspec\Template\Render\RuntimeBindings;
use Polyspec\Template\Render\Scope;
use Polyspec\Template\Value\MapValue;

final class GeneratedTemplates
{
    public static function render(
        string $target,
        Assign $assign,
        Definitions $definitions,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        switch ($target) {
            case 'layout.tpl':
                self::renderLayoutTpl(
                    $assign,
                    $definitions,
                    new InputLayoutTpl(),
                    $context,
                    $runtime,
                    $rootData,
                    $scope,
                );
                return;
            default:
                throw $context->fail('E_LOAD_NOT_FOUND', null, null, 'template ' . $target . ' does not exist');
        }
    }

    private static function renderLayoutTpl(
        Assign $assign,
        Definitions $definitions,
        InputLayoutTpl $input,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        $frame = new Frame('layout.tpl', [0, 26, 39, 51, 55, 99, 103, 111], $rootData);
        $context->at($frame, [0, 26]);
        $context->write(('<main class="empty-page">' . "\n"));
        if ($definitions->content !== null) {
            $definition = $definitions->content;
            if ($definition?->html === null) {
                throw $runtime->error(
                    $frame,
                    [39, 50],
                    'E_RUNTIME_BLOCK_UNDEFINED',
                    'define content is not registered',
                );
            }
            $context->at($frame, [39, 50]);
            $context->write($definition->html);
        } else {
            $context->at($frame, [55, 99]);
            $context->write(('<p class="empty">No content definition.</p>' . "\n"));
        }
        $context->at($frame, [103, 111]);
        $context->write(('</main>' . "\n"));
    }
}

Output · 78 bytes · d98cc268d4c4…

<main class="empty-page">
<p class="empty">No content definition.</p>
</main>
Implementationtsgorustphppython
artifact renderPASSPASSPASSPASSPASS

Pre-rendered HTML slot

The layout is selected by define while a server-produced HTML fragment is passed as a define entry.

layout targetassign dataHTML define

Inputs

assign
{
  "heading": "<server slot>"
}
define
{
  "layout": "layout.tpl",
  "content": {
    "html": "<p class=\"server\">pre-rendered &amp; safe</p>\n"
  }
}
templates · parser ranges
--- layout.tpl
<section class="notice">
<h1>{= heading}</h1>
{# content}
</section>
compiled artifacts
ast/manifest.json
{
  "schema": 3,
  "mode": "ast",
  "target": "canonical",
  "entry": "layout.tpl",
  "delimiters": null,
  "sourceDigest": "8161f4e59b4395fd598d60094d8d6f070b3ecab40be6821d47bd45cd4ee233a1",
  "typeDigest": "97e18db9ff8a29117f78c5ffb0a1fe590c00d89b20d04117721f2d64dab8e7dc",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "fb8049870573426dd093e2af0cf544e3592477ef1af415453fafcf71f0389901",
  "files": {
    "layout.tpl": {
      "path": "layout.tpl.ast.json",
      "sourceDigest": "43c54e2a5d18fbbc57a1ecdc73deb95dcaa74ffd9dc6732971be84d015d79263",
      "artifactDigest": "5625936f1194645ddc65b40d21c3bd5b35d443b2bb515465ae07d240318032f0",
      "lines": [
        0,
        25,
        46,
        58,
        69
      ]
    }
  }
}

ast/layout.tpl.ast.json · layout.tpl
{
  "type": "Template",
  "name": "layout.tpl",
  "body": [
    {
      "type": "Text",
      "value": "<section class=\"notice\">\n<h1>",
      "span": [
        0,
        29
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Var",
        "name": "heading",
        "span": [
          32,
          39
        ]
      },
      "span": [
        29,
        40
      ]
    },
    {
      "type": "Text",
      "value": "</h1>\n",
      "span": [
        40,
        46
      ]
    },
    {
      "type": "Block",
      "id": "content",
      "path": null,
      "scope": [],
      "span": [
        46,
        57
      ]
    },
    {
      "type": "Text",
      "value": "</section>\n",
      "span": [
        58,
        69
      ]
    }
  ],
  "comments": []
}
generated renderers
typescript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "ts",
  "entry": "layout.tpl",
  "sourceDigest": "8161f4e59b4395fd598d60094d8d6f070b3ecab40be6821d47bd45cd4ee233a1",
  "typeDigest": "97e18db9ff8a29117f78c5ffb0a1fe590c00d89b20d04117721f2d64dab8e7dc",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "a81f5f0f977b099b35dd1267160848c835a8aaf7c6865ac99d066a351070cbb0",
  "files": {
    "html-slot.ts": {
      "path": "html-slot.ts",
      "artifactDigest": "16210c1f7ef0a77cdfc9e4722236c6eaf60efd3902bd1dd14230a913971f19b2"
    }
  }
}

// Generated.
import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary, type MapValue, type PreparedRender, type Program, type RenderOptions, type Template, type Value } from '@polyspec/template';

export interface Assign {
  heading: string;
}
export interface Input_layout_tpl {  }
export type DefinitionData<T> = Partial<T>;
export interface Definition<T> { template?: string; html?: string; data?: DefinitionData<T>; }
export interface Definitions { content?: Definition<Record<never, never>>; layout?: Definition<Input_layout_tpl>; }
export interface ArtifactManifest { schema: number; mode: 'gen'; target: 'ts'; entry: string; sourceDigest: string; typeDigest: string; contractDigest: string; files: Record<string, string>; }
function generatedTypeError(value: Value | undefined, path: string, expected: string): Error { return new Error(value === null || value === undefined ? path + ' is required' : path + ' is not ' + expected); }
function generatedDataObject(value: Value, path: string): MapValue { if (value instanceof Map) return value; throw new Error(path + ' is not an object'); }
function generatedPlain(value: unknown): value is object { if (typeof value !== 'object' || value === null) return false; const prototype = Reflect.getPrototypeOf(value); return prototype === Object.prototype || prototype === null; }
function generatedObject(value: Value | undefined, path: string): MapValue { if (value instanceof Map) return value; throw generatedTypeError(value, path, 'an object'); }
function generatedString(value: Value | undefined, path: string): string { if (typeof value === 'string') return value; throw generatedTypeError(value, path, 'a string'); }
function generatedDecodeAssign(value: Value | undefined, path: string): Assign { const object = generatedObject(value, path); return { heading: generatedString(object.get("heading"), path + ".heading") }; }
function generatedDecodeData_Input_layout_tpl(value: Value, path: string): DefinitionData<Input_layout_tpl> { generatedDataObject(value, path); return {}; }
function generatedBindAssign(value: unknown): { assign: Assign; root: MapValue } { const root = bindMap(value); return { assign: generatedDecodeAssign(root, 'assign'), root }; }
type GeneratedTarget = { target: string | null; html?: string };
type GeneratedBoundDefinitions = { definitions: Definitions; targets: Map<string, GeneratedTarget> };
function generatedBindDefinitions(input: unknown): GeneratedBoundDefinitions {
  const definitions: Definitions = {};
  const targets = new Map<string, GeneratedTarget>();
  if (input === undefined || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error('define is not an object');
  const entries: [string, unknown][] = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
    case "content": {
      if (typeof raw === 'string') {
        throw new Error("define.content has an invalid template");
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.content is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        if (template !== undefined || data !== undefined) throw new Error("define.content has an invalid html entry");
        definitions.content = { html }; targets.set("content", { target: null, html }); break;
      }
      throw new Error("define.content has an invalid template");
    }
    case "layout": {
      if (typeof raw === 'string') {
        if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl" }; targets.set("layout", { target: "layout.tpl" }); break;
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.layout is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        throw new Error("define.layout has an invalid html entry");
      }
      if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
      definitions.layout = { template: "layout.tpl", data: data === undefined ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") }; targets.set("layout", { target: "layout.tpl" }); break;
    }
    default: throw new Error('define.' + id + ' is not declared');
    }
  }
  return { definitions, targets };
}
function render_layout_tpl(assign: Assign, definitions: Definitions, _input: Input_layout_tpl, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, _scope: Scope): void {
  const frame = new Frame("layout.tpl", [0,25,46,58,69], rootData);

    context.at(frame, [0,29]); context.output.write("<section class=\"notice\">\n<h1>");
    context.at(frame, [29,40]); context.output.write(runtime.escape(assign.heading, frame, [32,39]));
    context.at(frame, [40,46]); context.output.write("</h1>\n");
    { const definition = definitions.content;
    if (definition?.html === undefined) throw runtime.error(frame, [46,57], 'E_RUNTIME_BLOCK_UNDEFINED', "define content is not registered");
    context.at(frame, [46,57]); context.output.write(definition.html);
    }
    context.at(frame, [58,69]); context.output.write("</section>\n");
}
function renderTemplate(target: string, assign: Assign, definitions: Definitions, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  switch (target) {
    case "layout.tpl": render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope); return;
    default: throw context.fail('E_LOAD_NOT_FOUND', null, null, 'template ' + target + ' does not exist');
  }
}
function generatedEnv(input: unknown): { timezone: string; now: number } { if (input === undefined || input === null) return { timezone: 'Z', now: Math.floor(Date.now() / 1000) }; if (!generatedPlain(input)) throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env is not an object'); const timezone = ('timezone' in input ? input.timezone : undefined) ?? 'Z'; const now = ('now' in input ? input.now : undefined) ?? Math.floor(Date.now() / 1000); if (typeof timezone !== 'string') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.timezone is not a string'); if (typeof now !== 'number') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.now is not a number'); return { timezone, now }; }
class GeneratedPreparedRender implements PreparedRender { private readonly name: string; private readonly execute: () => string; constructor(name: string, execute: () => string) { this.name = name; this.execute = execute; } render(): string { return internalBoundary(this.name, this.execute); } }
export class GeneratedProgram implements Program {
  readonly runtime: RuntimeEnvironment;
  constructor(runtime: RuntimeEnvironment = new RuntimeEnvironment()) { this.runtime = runtime; }
  prepare(target: string | Template, assign: unknown, options: RenderOptions = {}): PreparedRender { if (typeof target !== 'string') throw new Error('generated target must be a template name'); return internalBoundary(target, () => this.prepareBound(target, assign, options)); }
  private prepareBound(target: string, assign: unknown, options: RenderOptions): PreparedRender { let boundAssign: { assign: Assign; root: MapValue }; let bound: GeneratedBoundDefinitions; let env: { timezone: string; now: number }; try { boundAssign = generatedBindAssign(assign); bound = generatedBindDefinitions(options.define); env = generatedEnv(options.env); } catch (error) { if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message }); throw error; } const registered = bound.targets.get(target); const html = registered?.html; if (html !== undefined) return new GeneratedPreparedRender(target, () => html); const targetName = registered?.target ?? target; return new GeneratedPreparedRender(target, () => { const context = new RenderContext(this.runtime, boundAssign.root, env, targetName); const runtime = new RuntimeBindings(context); const scope = new Scope(); context.enter(targetName, null, null); try { renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope); return context.output.toString(); } finally { context.leave(); } }); }
  render(target: string | Template, assign: unknown, options: RenderOptions = {}): string { return this.prepare(target, assign, options).render(); }
}


javascript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "js",
  "entry": "layout.tpl",
  "sourceDigest": "8161f4e59b4395fd598d60094d8d6f070b3ecab40be6821d47bd45cd4ee233a1",
  "typeDigest": "97e18db9ff8a29117f78c5ffb0a1fe590c00d89b20d04117721f2d64dab8e7dc",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "7a758948ae54e846b8c9cb16fa604ebf4a8aa94725dd3cd63ae77c94b2fe1e05",
  "files": {
    "html-slot.js": {
      "path": "html-slot.js",
      "artifactDigest": "930844a2f9dc18ef304548c5746620397c37ee593be334d1e1b17de48188466d"
    }
  }
}

import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary } from "@polyspec/template";
function generatedTypeError(value, path, expected) {
  return new Error(value === null || value === void 0 ? path + " is required" : path + " is not " + expected);
}
function generatedDataObject(value, path) {
  if (value instanceof Map) return value;
  throw new Error(path + " is not an object");
}
function generatedPlain(value) {
  if (typeof value !== "object" || value === null) return false;
  const prototype = Reflect.getPrototypeOf(value);
  return prototype === Object.prototype || prototype === null;
}
function generatedObject(value, path) {
  if (value instanceof Map) return value;
  throw generatedTypeError(value, path, "an object");
}
function generatedString(value, path) {
  if (typeof value === "string") return value;
  throw generatedTypeError(value, path, "a string");
}
function generatedDecodeAssign(value, path) {
  const object = generatedObject(value, path);
  return { heading: generatedString(object.get("heading"), path + ".heading") };
}
function generatedDecodeData_Input_layout_tpl(value, path) {
  generatedDataObject(value, path);
  return {};
}
function generatedBindAssign(value) {
  const root = bindMap(value);
  return { assign: generatedDecodeAssign(root, "assign"), root };
}
function generatedBindDefinitions(input) {
  const definitions = {};
  const targets = /* @__PURE__ */ new Map();
  if (input === void 0 || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error("define is not an object");
  const entries = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
      case "content": {
        if (typeof raw === "string") {
          throw new Error("define.content has an invalid template");
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.content is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          if (template !== void 0 || data !== void 0) throw new Error("define.content has an invalid html entry");
          definitions.content = { html };
          targets.set("content", { target: null, html });
          break;
        }
        throw new Error("define.content has an invalid template");
      }
      case "layout": {
        if (typeof raw === "string") {
          if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
          definitions.layout = { template: "layout.tpl" };
          targets.set("layout", { target: "layout.tpl" });
          break;
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.layout is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          throw new Error("define.layout has an invalid html entry");
        }
        if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl", data: data === void 0 ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") };
        targets.set("layout", { target: "layout.tpl" });
        break;
      }
      default:
        throw new Error("define." + id + " is not declared");
    }
  }
  return { definitions, targets };
}
function render_layout_tpl(assign, definitions, _input, context, runtime, rootData, _scope) {
  const frame = new Frame("layout.tpl", [0, 25, 46, 58, 69], rootData);
  context.at(frame, [0, 29]);
  context.output.write('<section class="notice">\n<h1>');
  context.at(frame, [29, 40]);
  context.output.write(runtime.escape(assign.heading, frame, [32, 39]));
  context.at(frame, [40, 46]);
  context.output.write("</h1>\n");
  {
    const definition = definitions.content;
    if (definition?.html === void 0) throw runtime.error(frame, [46, 57], "E_RUNTIME_BLOCK_UNDEFINED", "define content is not registered");
    context.at(frame, [46, 57]);
    context.output.write(definition.html);
  }
  context.at(frame, [58, 69]);
  context.output.write("</section>\n");
}
function renderTemplate(target, assign, definitions, context, runtime, rootData, scope) {
  switch (target) {
    case "layout.tpl":
      render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope);
      return;
    default:
      throw context.fail("E_LOAD_NOT_FOUND", null, null, "template " + target + " does not exist");
  }
}
function generatedEnv(input) {
  if (input === void 0 || input === null) return { timezone: "Z", now: Math.floor(Date.now() / 1e3) };
  if (!generatedPlain(input)) throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env is not an object");
  const timezone = ("timezone" in input ? input.timezone : void 0) ?? "Z";
  const now = ("now" in input ? input.now : void 0) ?? Math.floor(Date.now() / 1e3);
  if (typeof timezone !== "string") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.timezone is not a string");
  if (typeof now !== "number") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.now is not a number");
  return { timezone, now };
}
class GeneratedPreparedRender {
  name;
  execute;
  constructor(name, execute) {
    this.name = name;
    this.execute = execute;
  }
  render() {
    return internalBoundary(this.name, this.execute);
  }
}
export class GeneratedProgram {
  runtime;
  constructor(runtime = new RuntimeEnvironment()) {
    this.runtime = runtime;
  }
  prepare(target, assign, options = {}) {
    if (typeof target !== "string") throw new Error("generated target must be a template name");
    return internalBoundary(target, () => this.prepareBound(target, assign, options));
  }
  prepareBound(target, assign, options) {
    let boundAssign;
    let bound;
    let env;
    try {
      boundAssign = generatedBindAssign(assign);
      bound = generatedBindDefinitions(options.define);
      env = generatedEnv(options.env);
    } catch (error) {
      if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message });
      throw error;
    }
    const registered = bound.targets.get(target);
    const html = registered?.html;
    if (html !== void 0) return new GeneratedPreparedRender(target, () => html);
    const targetName = registered?.target ?? target;
    return new GeneratedPreparedRender(target, () => {
      const context = new RenderContext(this.runtime, boundAssign.root, env, targetName);
      const runtime = new RuntimeBindings(context);
      const scope = new Scope();
      context.enter(targetName, null, null);
      try {
        renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope);
        return context.output.toString();
      } finally {
        context.leave();
      }
    });
  }
  render(target, assign, options = {}) {
    return this.prepare(target, assign, options).render();
  }
}


go · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "go",
  "entry": "layout.tpl",
  "sourceDigest": "8161f4e59b4395fd598d60094d8d6f070b3ecab40be6821d47bd45cd4ee233a1",
  "typeDigest": "97e18db9ff8a29117f78c5ffb0a1fe590c00d89b20d04117721f2d64dab8e7dc",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "45312e93dc75fa9cac0af4448f4b43508dff97b90f52d7c3d1407e5852dbc284",
  "files": {
    "generated.go": {
      "path": "generated.go",
      "artifactDigest": "79a7460b4286e20a70d9821b0ab6cd4de3f47f181f88d36da828dd4827f74039"
    }
  }
}

// Code generated by @polyspec/template-compiler. DO NOT EDIT.

package generated

import (
	"encoding/json"
	"errors"
	"fmt"
	template "github.com/polyspec/template/packages/go"
	"github.com/polyspec/template/packages/go/ast"
	"github.com/polyspec/template/packages/go/errs"
	"github.com/polyspec/template/packages/go/functions"
	"github.com/polyspec/template/packages/go/render"
	"github.com/polyspec/template/packages/go/value"
	"time"
	"unicode/utf8"
)

type Assign struct {
	Heading string `json:"heading"`
}

type Input_layout_tpl struct{}

type DefinitionData_layout_tpl struct{}

type Definition[T any] struct {
	Template string  `json:"template"`
	HTML     *string `json:"html"`
	Data     *T      `json:"data"`
}

type Definitions struct {
	Content *Definition[struct{}]                  `json:"content"`
	Layout  *Definition[DefinitionData_layout_tpl] `json:"layout"`
}

type ArtifactManifest struct {
	Schema         int
	Mode           string
	Target         string
	Entry          string
	SourceDigest   string
	TypeDigest     string
	ContractDigest string
	Files          map[string]string
}

var generatedRecordFields = map[string][]generatedField{}

func generatedPanic(err error) {
	if err != nil {
		panic(err)
	}
}

func generatedValue(input any) value.Value {
	switch item := input.(type) {
	case nil:
		return nil
	case bool:
		return item
	case float64:
		return item
	case string:
		return item
	case value.SafeString:
		return item
	case value.List:
		result := make(value.List, len(item))
		for index, element := range item {
			result[index] = generatedValue(element)
		}
		return result
	case *value.OrderedMap:
		return item
	}
	result, err := value.Convert(input)
	generatedPanic(err)
	return result
}

func generatedEscape(runtime *render.RuntimeBindings, input any, frame *render.Frame, span ast.Span) string {
	result, err := runtime.Escape(generatedValue(input), frame, span)
	generatedPanic(err)
	return result
}

func generatedWrite(context *render.Context, text string, frame *render.Frame, span ast.Span) {
	generatedPanic(context.Write(text, frame, &span))
}

func generatedPlain(input any) any {
	switch item := input.(type) {
	case *value.OrderedMap:
		result := map[string]any{}
		for _, key := range item.Keys() {
			entry, _ := item.Get(key)
			result[key] = generatedPlain(entry)
		}
		return result
	case value.List:
		result := make([]any, len(item))
		for index, entry := range item {
			result[index] = generatedPlain(entry)
		}
		return result
	default:
		return input
	}
}

type generatedType struct {
	Kind     string
	Optional bool
	Name     string
	Item     *generatedType
	Key      *generatedType
	Value    *generatedType
}

type generatedField struct {
	Name string
	Type generatedType
}

func generatedCheck(input value.Value, kind generatedType, records map[string][]generatedField, path string) error {
	if input == nil {
		if kind.Optional || kind.Kind == "any" {
			return nil
		}
		return fmt.Errorf("%s is required", path)
	}
	actual := value.TypeOf(input)
	switch kind.Kind {
	case "any":
		return nil
	case "string":
		if actual != value.TypeString {
			return fmt.Errorf("%s is not a string", path)
		}
	case "number":
		if actual != value.TypeNumber {
			return fmt.Errorf("%s is not a number", path)
		}
	case "boolean":
		if actual != value.TypeBool {
			return fmt.Errorf("%s is not a boolean", path)
		}
	case "list":
		items, ok := input.(value.List)
		if !ok {
			return fmt.Errorf("%s is not a list", path)
		}
		for index, item := range items {
			if err := generatedCheck(item, *kind.Item, records, fmt.Sprintf("%s[%d]", path, index)); err != nil {
				return err
			}
		}
	case "map":
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		for _, key := range entries.Keys() {
			item, _ := entries.Get(key)
			if err := generatedCheck(item, *kind.Value, records, path+"."+key); err != nil {
				return err
			}
		}
	default:
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		return generatedCheckFields(entries, records[kind.Name], records, path)
	}
	return nil
}

func generatedCheckFields(input *value.OrderedMap, fields []generatedField, records map[string][]generatedField, path string) error {
	for _, field := range fields {
		item, _ := input.Get(field.Name)
		if err := generatedCheck(item, field.Type, records, path+"."+field.Name); err != nil {
			return err
		}
	}
	return nil
}

func generatedDecode(input any, output any) error {
	data, err := json.Marshal(generatedPlain(input))
	if err != nil {
		return err
	}
	return json.Unmarshal(data, output)
}

func generatedEnv(options template.RenderOptions) functions.Env {
	env := functions.Env{Timezone: "Z", Now: float64(time.Now().Unix())}
	if options.Env != nil {
		if options.Env.Timezone != "" {
			env.Timezone = options.Env.Timezone
		}
		env.Now = options.Env.Now
	}
	return env
}

func render_layout_tpl(assign Assign, definitions *Definitions, input Input_layout_tpl, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	frame := render.NewFrame("layout.tpl", errs.LineIndex{0, 25, 46, 58, 69}, rootData)
	generatedWrite(context, "<section class=\"notice\">\u000a<h1>", frame, ast.Span{0, 29})
	generatedWrite(context, generatedEscape(runtime, assign.Heading, frame, ast.Span{32, 39}), frame, ast.Span{29, 40})
	generatedWrite(context, "</h1>\u000a", frame, ast.Span{40, 46})
	{
		definition := definitions.Content
		if definition == nil || definition.HTML == nil {
			panic(runtime.Error(frame, ast.Span{46, 57}, errs.RuntimeBlockUndefined, "define content is not registered"))
		}
		generatedWrite(context, *definition.HTML, frame, ast.Span{46, 57})
	}
	generatedWrite(context, "</section>\u000a", frame, ast.Span{58, 69})
}

func renderTemplate(target string, assign Assign, definitions *Definitions, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	switch target {
	case "layout.tpl":
		render_layout_tpl(assign, definitions, Input_layout_tpl{}, context, runtime, rootData, scope)
		return
	default:
		panic(context.Fail(errs.LoadNotFound, nil, nil, "template "+target+" does not exist"))
	}
}

type generatedTarget struct {
	target string
	html   *string
}

func generatedBindDefinitions(input map[string]template.DefineInput) (*Definitions, map[string]generatedTarget, error) {
	definitions := &Definitions{}
	targets := map[string]generatedTarget{}
	for id, input := range input {
		if !utf8.ValidString(id) {
			return nil, nil, &value.BindError{Code: errs.DataInvalidUTF8, Message: "a define id is not valid UTF-8"}
		}
		switch id {
		case "content":
			if input.HTML != nil {
				if input.Template != "" || input.Data != nil {
					return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
				}
				definitions.Content = &Definition[struct{}]{HTML: input.HTML}
				targets[id] = generatedTarget{html: input.HTML}
				continue
			}
			if input.Template != "" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[struct{}]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				if _, ok := bound.(*value.OrderedMap); !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := struct{}{}
				entry.Data = &definitionData
			}
			definitions.Content = entry
			targets[id] = generatedTarget{target: ""}
		case "layout":
			if input.HTML != nil {
				return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
			}
			if input.Template != "layout.tpl" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[DefinitionData_layout_tpl]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				if _, ok := bound.(*value.OrderedMap); !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := DefinitionData_layout_tpl{}
				entry.Data = &definitionData
			}
			definitions.Layout = entry
			targets[id] = generatedTarget{target: "layout.tpl"}
		default:
			return nil, nil, fmt.Errorf("define.%s is not declared", id)
		}
	}
	return definitions, targets, nil
}

type GeneratedProgram struct {
	Runtime *template.RuntimeEnvironment
}

func NewGeneratedProgram(options template.Options) (*GeneratedProgram, error) {
	runtime, err := template.NewRuntimeEnvironment(options.Limits, options.Functions)
	if err != nil {
		return nil, err
	}
	return &GeneratedProgram{Runtime: runtime}, nil
}

type generatedPrepared struct {
	name        string
	target      string
	assign      Assign
	definitions *Definitions
	rootData    *value.OrderedMap
	env         functions.Env
	runtime     *template.RuntimeEnvironment
	html        *string
}

func (p *generatedPrepared) Render() (string, error) {
	return render.Guard(p.name, p.render)
}

func (p *generatedPrepared) render() (string, error) {
	context := render.NewContext(p.runtime, p.rootData, p.env, p.target)
	runtime := render.NewRuntimeBindings(context)
	scope := render.NewScope()
	if err := context.Enter(p.target, nil, nil); err != nil {
		return "", err
	}
	defer context.Leave()
	if p.html != nil {
		if err := context.Write(*p.html, nil, nil); err != nil {
			return "", err
		}
	} else {
		renderTemplate(p.target, p.assign, p.definitions, context, runtime, p.rootData, scope)
	}
	return context.Output(), nil
}

func (p *GeneratedProgram) Prepare(target any, assign any, options template.RenderOptions) (template.Prepared, error) {
	name, ok := target.(string)
	if !ok {
		return nil, fmt.Errorf("generated target must be a template name")
	}
	return render.Guard(name, func() (template.Prepared, error) {
		return p.prepare(name, assign, options)
	})
}

func generatedBindFailure(name string, err error) error {
	var bindError *value.BindError
	if errors.As(err, &bindError) {
		return errs.WithoutPosition(bindError.Code, name, bindError.Message)
	}
	return err
}

func (p *GeneratedProgram) prepare(name string, assign any, options template.RenderOptions) (template.Prepared, error) {
	rootData, err := value.BindMap(assign)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	var typedAssign Assign
	if err := generatedCheckFields(rootData, []generatedField{{Name: "heading", Type: generatedType{Kind: "string"}}}, generatedRecordFields, "assign"); err != nil {
		return nil, err
	}
	if err := generatedDecode(rootData, &typedAssign); err != nil {
		return nil, err
	}
	definitions, targets, err := generatedBindDefinitions(options.Define)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	resolved := targets[name]
	targetName := name
	if resolved.target != "" {
		targetName = resolved.target
	}
	return &generatedPrepared{name: name, target: targetName, assign: typedAssign, definitions: definitions, rootData: rootData, env: generatedEnv(options), runtime: p.Runtime, html: resolved.html}, nil
}

func (p *GeneratedProgram) Render(target any, assign any, options template.RenderOptions) (string, error) {
	prepared, err := p.Prepare(target, assign, options)
	if err != nil {
		return "", err
	}
	return prepared.Render()
}

var _ template.Program = (*GeneratedProgram)(nil)


rust · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "rust",
  "entry": "layout.tpl",
  "sourceDigest": "8161f4e59b4395fd598d60094d8d6f070b3ecab40be6821d47bd45cd4ee233a1",
  "typeDigest": "97e18db9ff8a29117f78c5ffb0a1fe590c00d89b20d04117721f2d64dab8e7dc",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "88d74f055ec030758070b516d0cd35473b90e243ae8571128c3187ba0162631f",
  "files": {
    "html-slot.rust": {
      "path": "html-slot.rust",
      "artifactDigest": "aaa175dc22ed5686ea376558912b42c69056545aa5be04519f7165333d7a1f49"
    }
  }
}

// Generated.
use polyspec_template::{ArgumentError, ErrorCode, OrderedMap as RuntimeOrderedMap, PreparedRender, Program, RenderOptions, RenderTarget, RequestError, RuntimeEnvironment, TemplateError, Value, internal_boundary};
use polyspec_template::error::LineIndex;
use polyspec_template::render::context::{Frame, RenderContext, Scope};
use polyspec_template::render::runtime_bindings::RuntimeBindings;
use serde_json::Value as JsonValue;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Clone, Default)] pub struct Assign {
    pub heading: String,
}
impl GeneratedConvert for Assign { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; let _ = (&map, path); let heading = generated_field(map, path, "heading")?; Ok(Assign { heading }) } fn to_value(&self) -> Value { let mut map = RuntimeOrderedMap::new(); map.insert("heading".to_string(), self.heading.to_value()); Value::map(map) } }
#[derive(Clone, Default)] pub struct InputLayoutTpl {  }

#[derive(Clone, Default)] pub struct Definition { pub html: Option<String> }
#[derive(Clone, Default)] pub struct Definitions { pub content: Option<Definition>, pub layout: Option<Definition> }
fn generated_conversion_error(message: impl Into<String>) -> TemplateError { TemplateError::without_position(ErrorCode::E_RUNTIME_TYPE, "generated", message) }
pub trait GeneratedConvert: Sized { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError>; fn to_value(&self) -> Value; }
impl GeneratedConvert for Value { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let _ = path; Ok(input.clone()) } fn to_value(&self) -> Value { self.clone() } }
impl GeneratedConvert for String { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { input.as_text().map(str::to_string).ok_or_else(|| generated_type_error(input, path, "a string")) } fn to_value(&self) -> Value { Value::text(self.clone()) } }
impl GeneratedConvert for f64 { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Number(number) => Ok(*number), _ => Err(generated_type_error(input, path, "a number")) } } fn to_value(&self) -> Value { Value::Number(*self) } }
impl GeneratedConvert for bool { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Bool(value) => Ok(*value), _ => Err(generated_type_error(input, path, "a boolean")) } } fn to_value(&self) -> Value { Value::Bool(*self) } }
impl<T: GeneratedConvert> GeneratedConvert for Option<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Null => Ok(None), other => T::from_value(other, path).map(Some) } } fn to_value(&self) -> Value { self.as_ref().map_or(Value::Null, T::to_value) } }
impl<T: GeneratedConvert> GeneratedConvert for Vec<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::List(items) => items.iter().enumerate().map(|(index, item)| T::from_value(item, &format!("{path}[{index}]"))).collect(), _ => Err(generated_type_error(input, path, "a list")) } } fn to_value(&self) -> Value { Value::list(self.iter().map(T::to_value).collect()) } }
fn generated_type_error(input: &Value, path: &str, expected: &str) -> TemplateError { generated_conversion_error(if matches!(input, Value::Null) { format!("{path} is required") } else { format!("{path} is not {expected}") }) }
fn generated_field<T: GeneratedConvert>(map: &RuntimeOrderedMap, path: &str, name: &str) -> Result<T, TemplateError> { T::from_value(map.get(name).unwrap_or(&Value::Null), &format!("{path}.{name}")) }
fn generated_value<T: GeneratedConvert>(input: &T) -> Result<Value, TemplateError> { Ok(input.to_value()) }
fn render_layout_tpl(assign: &Assign, definitions: &mut Definitions, input: InputLayoutTpl, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { let _ = (&assign, &definitions, &input, &runtime, &scope); let frame = Frame { name: "layout.tpl".to_string(), lines: Some(LineIndex::from_starts(vec![0, 25, 46, 58, 69])), context: Rc::clone(root_data) };

    context.write("<section class=\"notice\">\u{a}<h1>", &frame, [0, 29])?;
    let escaped = runtime.escape(context, &generated_value(&assign.heading)?, &frame, [32, 39])?; context.write(&escaped, &frame, [29, 40])?;
    context.write("</h1>\u{a}", &frame, [40, 46])?;
    { let definition = definitions.content.as_ref();
    let Some(html) = definition.and_then(|value| value.html.as_ref()) else { return Err(runtime.error(context, &frame, [46, 57], ErrorCode::E_RUNTIME_BLOCK_UNDEFINED, "define content is not registered")); };
    context.write(html, &frame, [46, 57])?;
    }
    context.write("</section>\u{a}", &frame, [58, 69])?;
 Ok(()) }
fn render_template(target: &str, assign: &Assign, definitions: &mut Definitions, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { match target {
        "layout.tpl" => render_layout_tpl(assign, definitions, InputLayoutTpl::default(), context, runtime, root_data, scope),
        _ => Err(context.fail(ErrorCode::E_LOAD_NOT_FOUND, None, None, format!("template {target} does not exist"))),
} }
fn generated_error(message: String) -> RequestError { RequestError::Argument(ArgumentError { message }) }
struct GeneratedTarget { target: Option<String>, html: Option<String> }
fn generated_bind_definitions(name: &str, input: &HashMap<String, polyspec_template::DefineInput>) -> Result<(Definitions, HashMap<String, GeneratedTarget>), RequestError> { let mut definitions = Definitions::default(); let mut targets = HashMap::new(); for (id, input) in input { match id.as_str() {
            "content" => { if let Some(html) = &input.html { if false || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.content = Some(Definition { html: Some(html.clone()) }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("") { return Err(generated_error(format!("define.{id} has an invalid template"))); }

definitions.content = Some(Definition::default()); targets.insert(id.clone(), GeneratedTarget { target: Some("".to_string()), html: None }); } },
            "layout" => { if let Some(html) = &input.html { if true || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.layout = Some(Definition { html: Some(html.clone()) }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("layout.tpl") { return Err(generated_error(format!("define.{id} has an invalid template"))); }
if let Some(data) = &input.data { match polyspec_template::bind_data(data).map_err(|error| TemplateError::without_position(error.code, name, error.message))? { Value::Map(_) => {  }, _ => return Err(generated_error(format!("define.{id}.data is not an object"))) } }
definitions.layout = Some(Definition::default()); targets.insert(id.clone(), GeneratedTarget { target: Some("layout.tpl".to_string()), html: None }); } },
            _ => return Err(generated_error(format!("define.{id} is not declared"))),
        } } Ok((definitions, targets)) }
pub struct GeneratedProgram { pub runtime: RuntimeEnvironment }
impl GeneratedProgram { pub fn new(runtime: RuntimeEnvironment) -> GeneratedProgram { GeneratedProgram { runtime } }  }
impl Program for GeneratedProgram { fn prepare(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || { let root_data = Rc::new(polyspec_template::value::bind::bind_map(assign).map_err(|error| TemplateError::without_position(error.code, name, error.message))?); self.prepare_root(name, root_data, options) }) } fn render(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare(target, assign, options)?.render()?) } fn prepare_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || self.prepare_root(name, polyspec_template::bound_root(assign), options)) } fn render_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare_bound(target, assign, options)?.render()?) } }
impl GeneratedProgram { fn prepare_root<'e>(&'e self, name: &str, root_data: Rc<RuntimeOrderedMap>, options: &RenderOptions) -> Result<PreparedRender<'e>, RequestError> { let typed_assign: Assign = Assign::from_value(&Value::Map(Rc::clone(&root_data)), "assign").map_err(|error| generated_error(error.message))?; let (definitions, targets) = generated_bind_definitions(name, &options.define)?; let resolved = targets.get(name); let target_name = resolved.and_then(|value| value.target.clone()).unwrap_or_else(|| name.to_string()); let html = resolved.and_then(|value| value.html.clone()); let env = options.env.clone().unwrap_or_else(|| polyspec_template::Env { timezone: "Z".to_string(), now: std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|duration| duration.as_secs() as f64).unwrap_or(0.0) }); Ok(PreparedRender::new(name, move || { let mut context = RenderContext::new(&self.runtime, Rc::clone(&root_data), env.clone(), &target_name); let runtime = RuntimeBindings::new(); let mut scope = Scope::default(); let mut render_definitions = definitions.clone(); context.enter(&target_name, None, None)?; let result = if let Some(html) = &html { let frame = Frame { name: target_name.clone(), lines: None, context: Rc::clone(&root_data) }; context.write(html, &frame, [0, 0]) } else { render_template(&target_name, &typed_assign, &mut render_definitions, &mut context, &runtime, &root_data, &mut scope) }; context.leave(); result?; Ok(context.output) })) } }


php · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "php",
  "entry": "layout.tpl",
  "sourceDigest": "8161f4e59b4395fd598d60094d8d6f070b3ecab40be6821d47bd45cd4ee233a1",
  "typeDigest": "97e18db9ff8a29117f78c5ffb0a1fe590c00d89b20d04117721f2d64dab8e7dc",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "ba7f0bfd4d8024e26cbef4e9ddf0cd1e011489480f00daebb75a11ecfa8e218f",
  "files": {
    "Assign.php": {
      "path": "Assign.php",
      "artifactDigest": "15379f830fd312141913ae9a5ca6a45320f18b8a8280fffc6aa791259c42ddb4"
    },
    "InputLayoutTpl.php": {
      "path": "InputLayoutTpl.php",
      "artifactDigest": "0f27a79be075d6276e941bedc20ec146f56aa37852c6f1d359fe30c552608ddb"
    },
    "DefinitionDataLayoutTpl.php": {
      "path": "DefinitionDataLayoutTpl.php",
      "artifactDigest": "69fb9932fd0bfeb28371da170224c988cf27ad89dbc1ad593327d82483cf6290"
    },
    "Definition.php": {
      "path": "Definition.php",
      "artifactDigest": "4faa951d5c080487435439c59eebe46bdecbd1baed1ce02b299abaffd490832d"
    },
    "Definitions.php": {
      "path": "Definitions.php",
      "artifactDigest": "cd13e6c727028d33f6afda010ab9ad967c035768663fe3e82f18b83c2edffe35"
    },
    "ArtifactManifest.php": {
      "path": "ArtifactManifest.php",
      "artifactDigest": "eac95162f15d7230173bbefdfb1c05045c0c24c99ee3f8b8d7cfc2dfdc9a2c97"
    },
    "GeneratedRuntime.php": {
      "path": "GeneratedRuntime.php",
      "artifactDigest": "ee0b8697bb7c8c1963f80bd3f545b78ebdb0e879e9a7393382efacc522de90ff"
    },
    "GeneratedTemplates.php": {
      "path": "GeneratedTemplates.php",
      "artifactDigest": "7e7441f44d39f6913a1bcbdac4fcf6842a8b5be83633af740bb302a8ff701320"
    },
    "GeneratedExecution.php": {
      "path": "GeneratedExecution.php",
      "artifactDigest": "165a8e4d16a40201b2070ee5601632540d373e82e718e9dd2c39ae69783f8998"
    },
    "GeneratedProgram.php": {
      "path": "GeneratedProgram.php",
      "artifactDigest": "0f1da614f2fd7e326d0a8c6831b0eeb69cab3b94c4c896e35525f152966db3e6"
    }
  }
}

<?php

declare(strict_types=1);

namespace Polyspec\Showcase\Generated\HtmlSlot;

use Polyspec\Template\Render\Context;
use Polyspec\Template\Render\Frame;
use Polyspec\Template\Render\RuntimeBindings;
use Polyspec\Template\Render\Scope;
use Polyspec\Template\Value\MapValue;

final class GeneratedTemplates
{
    public static function render(
        string $target,
        Assign $assign,
        Definitions $definitions,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        switch ($target) {
            case 'layout.tpl':
                self::renderLayoutTpl(
                    $assign,
                    $definitions,
                    new InputLayoutTpl(),
                    $context,
                    $runtime,
                    $rootData,
                    $scope,
                );
                return;
            default:
                throw $context->fail('E_LOAD_NOT_FOUND', null, null, 'template ' . $target . ' does not exist');
        }
    }

    private static function renderLayoutTpl(
        Assign $assign,
        Definitions $definitions,
        InputLayoutTpl $input,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        $frame = new Frame('layout.tpl', [0, 25, 46, 58, 69], $rootData);
        $context->at($frame, [0, 29]);
        $context->write(('<section class="notice">' . "\n" . '<h1>'));
        $context->at($frame, [29, 40]);
        $context->write($runtime->escape($assign->heading, $frame, [32, 39]));
        $context->at($frame, [40, 46]);
        $context->write(('</h1>' . "\n"));
        $definition = $definitions->content;
        if ($definition?->html === null) {
            throw $runtime->error($frame, [46, 57], 'E_RUNTIME_BLOCK_UNDEFINED', 'define content is not registered');
        }
        $context->at($frame, [46, 57]);
        $context->write($definition->html);
        $context->at($frame, [58, 69]);
        $context->write(('</section>' . "\n"));
    }
}

Output · 111 bytes · b1fc22f8d29c…

<section class="notice">
<h1>&lt;server slot&gt;</h1>
<p class="server">pre-rendered &amp; safe</p>
</section>
Implementationtsgorustphppython
artifact renderPASSPASSPASSPASSPASS

React island boundary

The template engine owns the server HTML shell; a React root owns a marked island after the page arrives.

SSR shellReact islandclient boundary

Inputs

assign
{
  "title": "Server rendered shell",
  "island_label": "Interactive island"
}
define
{
  "layout": "layout.tpl",
  "content": "content.tpl"
}
templates · parser ranges
--- content.tpl
<section data-react-island id="counter">
<p>{= island_label}</p>
</section>


--- layout.tpl
<main>
<h1>{= title}</h1>
{# content}
</main>
integration source
--- react-host.tsx
import { createRoot } from 'react-dom/client';

function Counter() {
  return <button onClick={() => alert('React owns this island')}>Interactive island</button>;
}

const island = document.getElementById('counter');
if (island === null) throw new Error('the page has no element #counter');
createRoot(island).render(<Counter />);
compiled artifacts
ast/manifest.json
{
  "schema": 3,
  "mode": "ast",
  "target": "canonical",
  "entry": "layout.tpl",
  "delimiters": null,
  "sourceDigest": "c688413e9bb0e846699f0df008a45824ea5c4ffec063bc8ae0355cbe4d300c47",
  "typeDigest": "2e7791f397b9a5dbd6610bc51eb4255149c45f1b7671c9d752ddd3e8b4067422",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "fb8049870573426dd093e2af0cf544e3592477ef1af415453fafcf71f0389901",
  "files": {
    "content.tpl": {
      "path": "content.tpl.ast.json",
      "sourceDigest": "abb0db9b6110b5ca0624d76013aa126c9e66a1486543f52492524c2ce2a52323",
      "artifactDigest": "3015220af570efb10db38900e9b9dbd79e58bb4d62004b30d98817bd94fa8d67",
      "lines": [
        0,
        41,
        65,
        76
      ]
    },
    "layout.tpl": {
      "path": "layout.tpl.ast.json",
      "sourceDigest": "2e71cffcf5f4701914b2c4f024251f6aa6a836a13ad1292948f3636d2272af4a",
      "artifactDigest": "fee2929c1a8a7066215e2ed719278e1330151cd4a8db4b0d1a47e332ac625eb3",
      "lines": [
        0,
        7,
        26,
        38,
        46
      ]
    }
  }
}

ast/content.tpl.ast.json · content.tpl
{
  "type": "Template",
  "name": "content.tpl",
  "body": [
    {
      "type": "Text",
      "value": "<section data-react-island id=\"counter\">\n<p>",
      "span": [
        0,
        44
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Var",
        "name": "island_label",
        "span": [
          47,
          59
        ]
      },
      "span": [
        44,
        60
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n</section>\n",
      "span": [
        60,
        76
      ]
    }
  ],
  "comments": []
}


ast/layout.tpl.ast.json · layout.tpl
{
  "type": "Template",
  "name": "layout.tpl",
  "body": [
    {
      "type": "Text",
      "value": "<main>\n<h1>",
      "span": [
        0,
        11
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Var",
        "name": "title",
        "span": [
          14,
          19
        ]
      },
      "span": [
        11,
        20
      ]
    },
    {
      "type": "Text",
      "value": "</h1>\n",
      "span": [
        20,
        26
      ]
    },
    {
      "type": "Block",
      "id": "content",
      "path": null,
      "scope": [],
      "span": [
        26,
        37
      ]
    },
    {
      "type": "Text",
      "value": "</main>\n",
      "span": [
        38,
        46
      ]
    }
  ],
  "comments": []
}
generated renderers
typescript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "ts",
  "entry": "layout.tpl",
  "sourceDigest": "c688413e9bb0e846699f0df008a45824ea5c4ffec063bc8ae0355cbe4d300c47",
  "typeDigest": "2e7791f397b9a5dbd6610bc51eb4255149c45f1b7671c9d752ddd3e8b4067422",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "a81f5f0f977b099b35dd1267160848c835a8aaf7c6865ac99d066a351070cbb0",
  "files": {
    "react-boundary.ts": {
      "path": "react-boundary.ts",
      "artifactDigest": "dca8aa420586683f288d95c4d475f8cd3eab537a803e361a15b6b50361a365df"
    }
  }
}

// Generated.
import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary, type MapValue, type PreparedRender, type Program, type RenderOptions, type Template, type Value } from '@polyspec/template';
export interface Page {
  title: string | null;
}
export interface Slot {
  template: string | null;
  html: string | null;
}
export interface Assign {
  title: string | null;
  heading: string | null;
  island_label: string | null;
  root_label: string | null;
  defined_label: string | null;
  page: Page | null;
}
export interface Input_content_tpl {  }
export interface Input_layout_tpl {  }
export type DefinitionData<T> = Partial<T>;
export interface Definition<T> { template?: string; html?: string; data?: DefinitionData<T>; }
export interface Definitions { content?: Definition<Input_content_tpl>; layout?: Definition<Input_layout_tpl>; }
export interface ArtifactManifest { schema: number; mode: 'gen'; target: 'ts'; entry: string; sourceDigest: string; typeDigest: string; contractDigest: string; files: Record<string, string>; }
type GeneratedDecoder<T> = (value: Value | undefined, path: string) => T;
function generatedTypeError(value: Value | undefined, path: string, expected: string): Error { return new Error(value === null || value === undefined ? path + ' is required' : path + ' is not ' + expected); }
function generatedDataObject(value: Value, path: string): MapValue { if (value instanceof Map) return value; throw new Error(path + ' is not an object'); }
function generatedPlain(value: unknown): value is object { if (typeof value !== 'object' || value === null) return false; const prototype = Reflect.getPrototypeOf(value); return prototype === Object.prototype || prototype === null; }
function generatedObject(value: Value | undefined, path: string): MapValue { if (value instanceof Map) return value; throw generatedTypeError(value, path, 'an object'); }
function generatedString(value: Value | undefined, path: string): string { if (typeof value === 'string') return value; throw generatedTypeError(value, path, 'a string'); }
function generatedOptional<T>(decode: GeneratedDecoder<T>): GeneratedDecoder<T | null> { return (value, path) => value === null || value === undefined ? null : decode(value, path); }
function generatedDecode_Page(value: Value | undefined, path: string): Page { const object = generatedObject(value, path); return { title: generatedOptional(generatedString)(object.get("title"), path + ".title") }; }
function generatedDecodeAssign(value: Value | undefined, path: string): Assign { const object = generatedObject(value, path); return { title: generatedOptional(generatedString)(object.get("title"), path + ".title"), heading: generatedOptional(generatedString)(object.get("heading"), path + ".heading"), island_label: generatedOptional(generatedString)(object.get("island_label"), path + ".island_label"), root_label: generatedOptional(generatedString)(object.get("root_label"), path + ".root_label"), defined_label: generatedOptional(generatedString)(object.get("defined_label"), path + ".defined_label"), page: generatedOptional(generatedDecode_Page)(object.get("page"), path + ".page") }; }
function generatedDecodeData_Input_content_tpl(value: Value, path: string): DefinitionData<Input_content_tpl> { generatedDataObject(value, path); return {}; }
function generatedDecodeData_Input_layout_tpl(value: Value, path: string): DefinitionData<Input_layout_tpl> { generatedDataObject(value, path); return {}; }
function generatedBindAssign(value: unknown): { assign: Assign; root: MapValue } { const root = bindMap(value); return { assign: generatedDecodeAssign(root, 'assign'), root }; }
type GeneratedTarget = { target: string | null; html?: string };
type GeneratedBoundDefinitions = { definitions: Definitions; targets: Map<string, GeneratedTarget> };
function generatedBindDefinitions(input: unknown): GeneratedBoundDefinitions {
  const definitions: Definitions = {};
  const targets = new Map<string, GeneratedTarget>();
  if (input === undefined || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error('define is not an object');
  const entries: [string, unknown][] = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
    case "content": {
      if (typeof raw === 'string') {
        if (raw !== "content.tpl") throw new Error("define.content has an invalid template");
        definitions.content = { template: "content.tpl" }; targets.set("content", { target: "content.tpl" }); break;
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.content is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        if (template !== undefined || data !== undefined) throw new Error("define.content has an invalid html entry");
        definitions.content = { html }; targets.set("content", { target: null, html }); break;
      }
      if (template !== "content.tpl") throw new Error("define.content has an invalid template");
      definitions.content = { template: "content.tpl", data: data === undefined ? {} : generatedDecodeData_Input_content_tpl(data, "define.content.data") }; targets.set("content", { target: "content.tpl" }); break;
    }
    case "layout": {
      if (typeof raw === 'string') {
        if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl" }; targets.set("layout", { target: "layout.tpl" }); break;
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.layout is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        throw new Error("define.layout has an invalid html entry");
      }
      if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
      definitions.layout = { template: "layout.tpl", data: data === undefined ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") }; targets.set("layout", { target: "layout.tpl" }); break;
    }
    default: throw new Error('define.' + id + ' is not declared');
    }
  }
  return { definitions, targets };
}
function render_content_tpl(assign: Assign, _definitions: Definitions, _input: Input_content_tpl, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, _scope: Scope): void {
  const frame = new Frame("content.tpl", [0,41,65,76], rootData);

    context.at(frame, [0,44]); context.output.write("<section data-react-island id=\"counter\">\n<p>");
    context.at(frame, [44,60]); context.output.write(runtime.escape(assign.island_label, frame, [47,59]));
    context.at(frame, [60,76]); context.output.write("</p>\n</section>\n");
}
function render_layout_tpl(assign: Assign, definitions: Definitions, input: Input_layout_tpl, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, _scope: Scope): void {
  const frame = new Frame("layout.tpl", [0,7,26,38,46], rootData);

    context.at(frame, [0,11]); context.output.write("<main>\n<h1>");
    context.at(frame, [11,20]); context.output.write(runtime.escape(assign.title, frame, [14,19]));
    context.at(frame, [20,26]); context.output.write("</h1>\n");
    { let definition = definitions.content;
    if (definition === undefined) throw runtime.error(frame, [26,37], 'E_RUNTIME_BLOCK_UNDEFINED', "define content is not registered");
    if (definition?.html !== undefined) { context.at(frame, [26,37]); context.output.write(definition.html); }
    else { const input: Input_content_tpl = {  }; const blockScope = new Scope(); context.enter("content.tpl", frame, [26,37]); try { render_content_tpl(assign, definitions, input, context, runtime, rootData, blockScope); } finally { context.leave(); } }
    }
    context.at(frame, [38,46]); context.output.write("</main>\n");
}
function renderTemplate(target: string, assign: Assign, definitions: Definitions, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  switch (target) {
    case "content.tpl": render_content_tpl(assign, definitions, {}, context, runtime, rootData, scope); return;
    case "layout.tpl": render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope); return;
    default: throw context.fail('E_LOAD_NOT_FOUND', null, null, 'template ' + target + ' does not exist');
  }
}
function generatedEnv(input: unknown): { timezone: string; now: number } { if (input === undefined || input === null) return { timezone: 'Z', now: Math.floor(Date.now() / 1000) }; if (!generatedPlain(input)) throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env is not an object'); const timezone = ('timezone' in input ? input.timezone : undefined) ?? 'Z'; const now = ('now' in input ? input.now : undefined) ?? Math.floor(Date.now() / 1000); if (typeof timezone !== 'string') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.timezone is not a string'); if (typeof now !== 'number') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.now is not a number'); return { timezone, now }; }
class GeneratedPreparedRender implements PreparedRender { private readonly name: string; private readonly execute: () => string; constructor(name: string, execute: () => string) { this.name = name; this.execute = execute; } render(): string { return internalBoundary(this.name, this.execute); } }
export class GeneratedProgram implements Program {
  readonly runtime: RuntimeEnvironment;
  constructor(runtime: RuntimeEnvironment = new RuntimeEnvironment()) { this.runtime = runtime; }
  prepare(target: string | Template, assign: unknown, options: RenderOptions = {}): PreparedRender { if (typeof target !== 'string') throw new Error('generated target must be a template name'); return internalBoundary(target, () => this.prepareBound(target, assign, options)); }
  private prepareBound(target: string, assign: unknown, options: RenderOptions): PreparedRender { let boundAssign: { assign: Assign; root: MapValue }; let bound: GeneratedBoundDefinitions; let env: { timezone: string; now: number }; try { boundAssign = generatedBindAssign(assign); bound = generatedBindDefinitions(options.define); env = generatedEnv(options.env); } catch (error) { if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message }); throw error; } const registered = bound.targets.get(target); const html = registered?.html; if (html !== undefined) return new GeneratedPreparedRender(target, () => html); const targetName = registered?.target ?? target; return new GeneratedPreparedRender(target, () => { const context = new RenderContext(this.runtime, boundAssign.root, env, targetName); const runtime = new RuntimeBindings(context); const scope = new Scope(); context.enter(targetName, null, null); try { renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope); return context.output.toString(); } finally { context.leave(); } }); }
  render(target: string | Template, assign: unknown, options: RenderOptions = {}): string { return this.prepare(target, assign, options).render(); }
}


javascript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "js",
  "entry": "layout.tpl",
  "sourceDigest": "c688413e9bb0e846699f0df008a45824ea5c4ffec063bc8ae0355cbe4d300c47",
  "typeDigest": "2e7791f397b9a5dbd6610bc51eb4255149c45f1b7671c9d752ddd3e8b4067422",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "7a758948ae54e846b8c9cb16fa604ebf4a8aa94725dd3cd63ae77c94b2fe1e05",
  "files": {
    "react-boundary.js": {
      "path": "react-boundary.js",
      "artifactDigest": "2353e20b17e79fb529708730f0858e173d2ac72dab953e4e36ee1c551f7c48c5"
    }
  }
}

import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary } from "@polyspec/template";
function generatedTypeError(value, path, expected) {
  return new Error(value === null || value === void 0 ? path + " is required" : path + " is not " + expected);
}
function generatedDataObject(value, path) {
  if (value instanceof Map) return value;
  throw new Error(path + " is not an object");
}
function generatedPlain(value) {
  if (typeof value !== "object" || value === null) return false;
  const prototype = Reflect.getPrototypeOf(value);
  return prototype === Object.prototype || prototype === null;
}
function generatedObject(value, path) {
  if (value instanceof Map) return value;
  throw generatedTypeError(value, path, "an object");
}
function generatedString(value, path) {
  if (typeof value === "string") return value;
  throw generatedTypeError(value, path, "a string");
}
function generatedOptional(decode) {
  return (value, path) => value === null || value === void 0 ? null : decode(value, path);
}
function generatedDecode_Page(value, path) {
  const object = generatedObject(value, path);
  return { title: generatedOptional(generatedString)(object.get("title"), path + ".title") };
}
function generatedDecodeAssign(value, path) {
  const object = generatedObject(value, path);
  return { title: generatedOptional(generatedString)(object.get("title"), path + ".title"), heading: generatedOptional(generatedString)(object.get("heading"), path + ".heading"), island_label: generatedOptional(generatedString)(object.get("island_label"), path + ".island_label"), root_label: generatedOptional(generatedString)(object.get("root_label"), path + ".root_label"), defined_label: generatedOptional(generatedString)(object.get("defined_label"), path + ".defined_label"), page: generatedOptional(generatedDecode_Page)(object.get("page"), path + ".page") };
}
function generatedDecodeData_Input_content_tpl(value, path) {
  generatedDataObject(value, path);
  return {};
}
function generatedDecodeData_Input_layout_tpl(value, path) {
  generatedDataObject(value, path);
  return {};
}
function generatedBindAssign(value) {
  const root = bindMap(value);
  return { assign: generatedDecodeAssign(root, "assign"), root };
}
function generatedBindDefinitions(input) {
  const definitions = {};
  const targets = /* @__PURE__ */ new Map();
  if (input === void 0 || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error("define is not an object");
  const entries = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
      case "content": {
        if (typeof raw === "string") {
          if (raw !== "content.tpl") throw new Error("define.content has an invalid template");
          definitions.content = { template: "content.tpl" };
          targets.set("content", { target: "content.tpl" });
          break;
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.content is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          if (template !== void 0 || data !== void 0) throw new Error("define.content has an invalid html entry");
          definitions.content = { html };
          targets.set("content", { target: null, html });
          break;
        }
        if (template !== "content.tpl") throw new Error("define.content has an invalid template");
        definitions.content = { template: "content.tpl", data: data === void 0 ? {} : generatedDecodeData_Input_content_tpl(data, "define.content.data") };
        targets.set("content", { target: "content.tpl" });
        break;
      }
      case "layout": {
        if (typeof raw === "string") {
          if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
          definitions.layout = { template: "layout.tpl" };
          targets.set("layout", { target: "layout.tpl" });
          break;
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.layout is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          throw new Error("define.layout has an invalid html entry");
        }
        if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl", data: data === void 0 ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") };
        targets.set("layout", { target: "layout.tpl" });
        break;
      }
      default:
        throw new Error("define." + id + " is not declared");
    }
  }
  return { definitions, targets };
}
function render_content_tpl(assign, _definitions, _input, context, runtime, rootData, _scope) {
  const frame = new Frame("content.tpl", [0, 41, 65, 76], rootData);
  context.at(frame, [0, 44]);
  context.output.write('<section data-react-island id="counter">\n<p>');
  context.at(frame, [44, 60]);
  context.output.write(runtime.escape(assign.island_label, frame, [47, 59]));
  context.at(frame, [60, 76]);
  context.output.write("</p>\n</section>\n");
}
function render_layout_tpl(assign, definitions, input, context, runtime, rootData, _scope) {
  const frame = new Frame("layout.tpl", [0, 7, 26, 38, 46], rootData);
  context.at(frame, [0, 11]);
  context.output.write("<main>\n<h1>");
  context.at(frame, [11, 20]);
  context.output.write(runtime.escape(assign.title, frame, [14, 19]));
  context.at(frame, [20, 26]);
  context.output.write("</h1>\n");
  {
    let definition = definitions.content;
    if (definition === void 0) throw runtime.error(frame, [26, 37], "E_RUNTIME_BLOCK_UNDEFINED", "define content is not registered");
    if (definition?.html !== void 0) {
      context.at(frame, [26, 37]);
      context.output.write(definition.html);
    } else {
      const input2 = {};
      const blockScope = new Scope();
      context.enter("content.tpl", frame, [26, 37]);
      try {
        render_content_tpl(assign, definitions, input2, context, runtime, rootData, blockScope);
      } finally {
        context.leave();
      }
    }
  }
  context.at(frame, [38, 46]);
  context.output.write("</main>\n");
}
function renderTemplate(target, assign, definitions, context, runtime, rootData, scope) {
  switch (target) {
    case "content.tpl":
      render_content_tpl(assign, definitions, {}, context, runtime, rootData, scope);
      return;
    case "layout.tpl":
      render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope);
      return;
    default:
      throw context.fail("E_LOAD_NOT_FOUND", null, null, "template " + target + " does not exist");
  }
}
function generatedEnv(input) {
  if (input === void 0 || input === null) return { timezone: "Z", now: Math.floor(Date.now() / 1e3) };
  if (!generatedPlain(input)) throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env is not an object");
  const timezone = ("timezone" in input ? input.timezone : void 0) ?? "Z";
  const now = ("now" in input ? input.now : void 0) ?? Math.floor(Date.now() / 1e3);
  if (typeof timezone !== "string") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.timezone is not a string");
  if (typeof now !== "number") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.now is not a number");
  return { timezone, now };
}
class GeneratedPreparedRender {
  name;
  execute;
  constructor(name, execute) {
    this.name = name;
    this.execute = execute;
  }
  render() {
    return internalBoundary(this.name, this.execute);
  }
}
export class GeneratedProgram {
  runtime;
  constructor(runtime = new RuntimeEnvironment()) {
    this.runtime = runtime;
  }
  prepare(target, assign, options = {}) {
    if (typeof target !== "string") throw new Error("generated target must be a template name");
    return internalBoundary(target, () => this.prepareBound(target, assign, options));
  }
  prepareBound(target, assign, options) {
    let boundAssign;
    let bound;
    let env;
    try {
      boundAssign = generatedBindAssign(assign);
      bound = generatedBindDefinitions(options.define);
      env = generatedEnv(options.env);
    } catch (error) {
      if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message });
      throw error;
    }
    const registered = bound.targets.get(target);
    const html = registered?.html;
    if (html !== void 0) return new GeneratedPreparedRender(target, () => html);
    const targetName = registered?.target ?? target;
    return new GeneratedPreparedRender(target, () => {
      const context = new RenderContext(this.runtime, boundAssign.root, env, targetName);
      const runtime = new RuntimeBindings(context);
      const scope = new Scope();
      context.enter(targetName, null, null);
      try {
        renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope);
        return context.output.toString();
      } finally {
        context.leave();
      }
    });
  }
  render(target, assign, options = {}) {
    return this.prepare(target, assign, options).render();
  }
}


go · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "go",
  "entry": "layout.tpl",
  "sourceDigest": "c688413e9bb0e846699f0df008a45824ea5c4ffec063bc8ae0355cbe4d300c47",
  "typeDigest": "2e7791f397b9a5dbd6610bc51eb4255149c45f1b7671c9d752ddd3e8b4067422",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "45312e93dc75fa9cac0af4448f4b43508dff97b90f52d7c3d1407e5852dbc284",
  "files": {
    "generated.go": {
      "path": "generated.go",
      "artifactDigest": "7574cf4a9d59b9b7f79385322f30e333636592f0451c69f8e6a50d8847ad6092"
    }
  }
}

// Code generated by @polyspec/template-compiler. DO NOT EDIT.

package generated

import (
	"encoding/json"
	"errors"
	"fmt"
	template "github.com/polyspec/template/packages/go"
	"github.com/polyspec/template/packages/go/ast"
	"github.com/polyspec/template/packages/go/errs"
	"github.com/polyspec/template/packages/go/functions"
	"github.com/polyspec/template/packages/go/render"
	"github.com/polyspec/template/packages/go/value"
	"time"
	"unicode/utf8"
)

type Page struct {
	Title *string `json:"title"`
}

func (r Page) TemplateValue() value.Value {
	result := value.NewOrderedMap()
	result.Set("title", generatedValue(r.Title))
	return result
}

type Slot struct {
	Template *string `json:"template"`
	Html     *string `json:"html"`
}

func (r Slot) TemplateValue() value.Value {
	result := value.NewOrderedMap()
	result.Set("template", generatedValue(r.Template))
	result.Set("html", generatedValue(r.Html))
	return result
}

type Assign struct {
	Title         *string `json:"title"`
	Heading       *string `json:"heading"`
	Island_label  *string `json:"island_label"`
	Root_label    *string `json:"root_label"`
	Defined_label *string `json:"defined_label"`
	Page          *Page   `json:"page"`
}

type Input_content_tpl struct{}

type Input_layout_tpl struct{}

type DefinitionData_content_tpl struct{}

type DefinitionData_layout_tpl struct{}

type Definition[T any] struct {
	Template string  `json:"template"`
	HTML     *string `json:"html"`
	Data     *T      `json:"data"`
}

type Definitions struct {
	Content *Definition[DefinitionData_content_tpl] `json:"content"`
	Layout  *Definition[DefinitionData_layout_tpl]  `json:"layout"`
}

type ArtifactManifest struct {
	Schema         int
	Mode           string
	Target         string
	Entry          string
	SourceDigest   string
	TypeDigest     string
	ContractDigest string
	Files          map[string]string
}

var generatedRecordFields = map[string][]generatedField{"Page": []generatedField{{Name: "title", Type: generatedType{Kind: "string", Optional: true}}}, "Slot": []generatedField{{Name: "template", Type: generatedType{Kind: "string", Optional: true}}, {Name: "html", Type: generatedType{Kind: "string", Optional: true}}}}

func generatedPanic(err error) {
	if err != nil {
		panic(err)
	}
}

func generatedValue(input any) value.Value {
	switch item := input.(type) {
	case nil:
		return nil
	case bool:
		return item
	case float64:
		return item
	case string:
		return item
	case value.SafeString:
		return item
	case value.List:
		result := make(value.List, len(item))
		for index, element := range item {
			result[index] = generatedValue(element)
		}
		return result
	case *value.OrderedMap:
		return item
	}
	result, err := value.Convert(input)
	generatedPanic(err)
	return result
}

func generatedEscape(runtime *render.RuntimeBindings, input any, frame *render.Frame, span ast.Span) string {
	result, err := runtime.Escape(generatedValue(input), frame, span)
	generatedPanic(err)
	return result
}

func generatedWrite(context *render.Context, text string, frame *render.Frame, span ast.Span) {
	generatedPanic(context.Write(text, frame, &span))
}

func generatedEnter(context *render.Context, name string, frame *render.Frame, span ast.Span) {
	generatedPanic(context.Enter(name, frame, &span))
}

func generatedPlain(input any) any {
	switch item := input.(type) {
	case *value.OrderedMap:
		result := map[string]any{}
		for _, key := range item.Keys() {
			entry, _ := item.Get(key)
			result[key] = generatedPlain(entry)
		}
		return result
	case value.List:
		result := make([]any, len(item))
		for index, entry := range item {
			result[index] = generatedPlain(entry)
		}
		return result
	default:
		return input
	}
}

type generatedType struct {
	Kind     string
	Optional bool
	Name     string
	Item     *generatedType
	Key      *generatedType
	Value    *generatedType
}

type generatedField struct {
	Name string
	Type generatedType
}

func generatedCheck(input value.Value, kind generatedType, records map[string][]generatedField, path string) error {
	if input == nil {
		if kind.Optional || kind.Kind == "any" {
			return nil
		}
		return fmt.Errorf("%s is required", path)
	}
	actual := value.TypeOf(input)
	switch kind.Kind {
	case "any":
		return nil
	case "string":
		if actual != value.TypeString {
			return fmt.Errorf("%s is not a string", path)
		}
	case "number":
		if actual != value.TypeNumber {
			return fmt.Errorf("%s is not a number", path)
		}
	case "boolean":
		if actual != value.TypeBool {
			return fmt.Errorf("%s is not a boolean", path)
		}
	case "list":
		items, ok := input.(value.List)
		if !ok {
			return fmt.Errorf("%s is not a list", path)
		}
		for index, item := range items {
			if err := generatedCheck(item, *kind.Item, records, fmt.Sprintf("%s[%d]", path, index)); err != nil {
				return err
			}
		}
	case "map":
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		for _, key := range entries.Keys() {
			item, _ := entries.Get(key)
			if err := generatedCheck(item, *kind.Value, records, path+"."+key); err != nil {
				return err
			}
		}
	default:
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		return generatedCheckFields(entries, records[kind.Name], records, path)
	}
	return nil
}

func generatedCheckFields(input *value.OrderedMap, fields []generatedField, records map[string][]generatedField, path string) error {
	for _, field := range fields {
		item, _ := input.Get(field.Name)
		if err := generatedCheck(item, field.Type, records, path+"."+field.Name); err != nil {
			return err
		}
	}
	return nil
}

func generatedDecode(input any, output any) error {
	data, err := json.Marshal(generatedPlain(input))
	if err != nil {
		return err
	}
	return json.Unmarshal(data, output)
}

func generatedEnv(options template.RenderOptions) functions.Env {
	env := functions.Env{Timezone: "Z", Now: float64(time.Now().Unix())}
	if options.Env != nil {
		if options.Env.Timezone != "" {
			env.Timezone = options.Env.Timezone
		}
		env.Now = options.Env.Now
	}
	return env
}

func render_content_tpl(assign Assign, definitions *Definitions, input Input_content_tpl, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	frame := render.NewFrame("content.tpl", errs.LineIndex{0, 41, 65, 76}, rootData)
	generatedWrite(context, "<section data-react-island id=\"counter\">\u000a<p>", frame, ast.Span{0, 44})
	generatedWrite(context, generatedEscape(runtime, assign.Island_label, frame, ast.Span{47, 59}), frame, ast.Span{44, 60})
	generatedWrite(context, "</p>\u000a</section>\u000a", frame, ast.Span{60, 76})
}

func render_layout_tpl(assign Assign, definitions *Definitions, input Input_layout_tpl, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	frame := render.NewFrame("layout.tpl", errs.LineIndex{0, 7, 26, 38, 46}, rootData)
	generatedWrite(context, "<main>\u000a<h1>", frame, ast.Span{0, 11})
	generatedWrite(context, generatedEscape(runtime, assign.Title, frame, ast.Span{14, 19}), frame, ast.Span{11, 20})
	generatedWrite(context, "</h1>\u000a", frame, ast.Span{20, 26})
	{
		definition := definitions.Content
		if definition == nil {
			panic(runtime.Error(frame, ast.Span{26, 37}, errs.RuntimeBlockUndefined, "define content is not registered"))
		}
		if definition != nil && definition.HTML != nil {
			generatedWrite(context, *definition.HTML, frame, ast.Span{26, 37})
		} else {
			input := Input_content_tpl{}
			blockScope := render.NewScope()
			generatedEnter(context, "content.tpl", frame, ast.Span{26, 37})
			func() {
				defer context.Leave()
				render_content_tpl(assign, definitions, input, context, runtime, rootData, blockScope)
			}()
		}
	}
	generatedWrite(context, "</main>\u000a", frame, ast.Span{38, 46})
}

func renderTemplate(target string, assign Assign, definitions *Definitions, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	switch target {
	case "content.tpl":
		render_content_tpl(assign, definitions, Input_content_tpl{}, context, runtime, rootData, scope)
		return
	case "layout.tpl":
		render_layout_tpl(assign, definitions, Input_layout_tpl{}, context, runtime, rootData, scope)
		return
	default:
		panic(context.Fail(errs.LoadNotFound, nil, nil, "template "+target+" does not exist"))
	}
}

type generatedTarget struct {
	target string
	html   *string
}

func generatedBindDefinitions(input map[string]template.DefineInput) (*Definitions, map[string]generatedTarget, error) {
	definitions := &Definitions{}
	targets := map[string]generatedTarget{}
	for id, input := range input {
		if !utf8.ValidString(id) {
			return nil, nil, &value.BindError{Code: errs.DataInvalidUTF8, Message: "a define id is not valid UTF-8"}
		}
		switch id {
		case "content":
			if input.HTML != nil {
				if input.Template != "" || input.Data != nil {
					return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
				}
				definitions.Content = &Definition[DefinitionData_content_tpl]{HTML: input.HTML}
				targets[id] = generatedTarget{html: input.HTML}
				continue
			}
			if input.Template != "content.tpl" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[DefinitionData_content_tpl]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				if _, ok := bound.(*value.OrderedMap); !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := DefinitionData_content_tpl{}
				entry.Data = &definitionData
			}
			definitions.Content = entry
			targets[id] = generatedTarget{target: "content.tpl"}
		case "layout":
			if input.HTML != nil {
				return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
			}
			if input.Template != "layout.tpl" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[DefinitionData_layout_tpl]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				if _, ok := bound.(*value.OrderedMap); !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := DefinitionData_layout_tpl{}
				entry.Data = &definitionData
			}
			definitions.Layout = entry
			targets[id] = generatedTarget{target: "layout.tpl"}
		default:
			return nil, nil, fmt.Errorf("define.%s is not declared", id)
		}
	}
	return definitions, targets, nil
}

type GeneratedProgram struct {
	Runtime *template.RuntimeEnvironment
}

func NewGeneratedProgram(options template.Options) (*GeneratedProgram, error) {
	runtime, err := template.NewRuntimeEnvironment(options.Limits, options.Functions)
	if err != nil {
		return nil, err
	}
	return &GeneratedProgram{Runtime: runtime}, nil
}

type generatedPrepared struct {
	name        string
	target      string
	assign      Assign
	definitions *Definitions
	rootData    *value.OrderedMap
	env         functions.Env
	runtime     *template.RuntimeEnvironment
	html        *string
}

func (p *generatedPrepared) Render() (string, error) {
	return render.Guard(p.name, p.render)
}

func (p *generatedPrepared) render() (string, error) {
	context := render.NewContext(p.runtime, p.rootData, p.env, p.target)
	runtime := render.NewRuntimeBindings(context)
	scope := render.NewScope()
	if err := context.Enter(p.target, nil, nil); err != nil {
		return "", err
	}
	defer context.Leave()
	if p.html != nil {
		if err := context.Write(*p.html, nil, nil); err != nil {
			return "", err
		}
	} else {
		renderTemplate(p.target, p.assign, p.definitions, context, runtime, p.rootData, scope)
	}
	return context.Output(), nil
}

func (p *GeneratedProgram) Prepare(target any, assign any, options template.RenderOptions) (template.Prepared, error) {
	name, ok := target.(string)
	if !ok {
		return nil, fmt.Errorf("generated target must be a template name")
	}
	return render.Guard(name, func() (template.Prepared, error) {
		return p.prepare(name, assign, options)
	})
}

func generatedBindFailure(name string, err error) error {
	var bindError *value.BindError
	if errors.As(err, &bindError) {
		return errs.WithoutPosition(bindError.Code, name, bindError.Message)
	}
	return err
}

func (p *GeneratedProgram) prepare(name string, assign any, options template.RenderOptions) (template.Prepared, error) {
	rootData, err := value.BindMap(assign)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	var typedAssign Assign
	if err := generatedCheckFields(rootData, []generatedField{{Name: "title", Type: generatedType{Kind: "string", Optional: true}}, {Name: "heading", Type: generatedType{Kind: "string", Optional: true}}, {Name: "island_label", Type: generatedType{Kind: "string", Optional: true}}, {Name: "root_label", Type: generatedType{Kind: "string", Optional: true}}, {Name: "defined_label", Type: generatedType{Kind: "string", Optional: true}}, {Name: "page", Type: generatedType{Kind: "record", Optional: true, Name: "Page"}}}, generatedRecordFields, "assign"); err != nil {
		return nil, err
	}
	if err := generatedDecode(rootData, &typedAssign); err != nil {
		return nil, err
	}
	definitions, targets, err := generatedBindDefinitions(options.Define)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	resolved := targets[name]
	targetName := name
	if resolved.target != "" {
		targetName = resolved.target
	}
	return &generatedPrepared{name: name, target: targetName, assign: typedAssign, definitions: definitions, rootData: rootData, env: generatedEnv(options), runtime: p.Runtime, html: resolved.html}, nil
}

func (p *GeneratedProgram) Render(target any, assign any, options template.RenderOptions) (string, error) {
	prepared, err := p.Prepare(target, assign, options)
	if err != nil {
		return "", err
	}
	return prepared.Render()
}

var _ template.Program = (*GeneratedProgram)(nil)


rust · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "rust",
  "entry": "layout.tpl",
  "sourceDigest": "c688413e9bb0e846699f0df008a45824ea5c4ffec063bc8ae0355cbe4d300c47",
  "typeDigest": "2e7791f397b9a5dbd6610bc51eb4255149c45f1b7671c9d752ddd3e8b4067422",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "88d74f055ec030758070b516d0cd35473b90e243ae8571128c3187ba0162631f",
  "files": {
    "react-boundary.rust": {
      "path": "react-boundary.rust",
      "artifactDigest": "3f4c6f4a5fd935f6be0dae52ba7cec7a41473094e79046ad66b101946f9ffa27"
    }
  }
}

// Generated.
use polyspec_template::{ArgumentError, ErrorCode, OrderedMap as RuntimeOrderedMap, PreparedRender, Program, RenderOptions, RenderTarget, RequestError, RuntimeEnvironment, TemplateError, Value, internal_boundary};
use polyspec_template::error::LineIndex;
use polyspec_template::render::context::{Frame, RenderContext, Scope};
use polyspec_template::render::runtime_bindings::RuntimeBindings;
use serde_json::Value as JsonValue;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Clone, Default)] pub struct Assign {
    pub title: Option<String>,
    pub island_label: Option<String>,
}
impl GeneratedConvert for Assign { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; let _ = (&map, path); let title = generated_field(map, path, "title")?; generated_check_field(map, path, "heading", |value, path| match value { Value::Null => Ok(()), other => <String as GeneratedConvert>::from_value(other, path).map(drop) })?; let island_label = generated_field(map, path, "island_label")?; generated_check_field(map, path, "root_label", |value, path| match value { Value::Null => Ok(()), other => <String as GeneratedConvert>::from_value(other, path).map(drop) })?; generated_check_field(map, path, "defined_label", |value, path| match value { Value::Null => Ok(()), other => <String as GeneratedConvert>::from_value(other, path).map(drop) })?; generated_check_field(map, path, "page", |value, path| match value { Value::Null => Ok(()), other => generated_check_page(other, path) })?; Ok(Assign { title, island_label }) } fn to_value(&self) -> Value { let mut map = RuntimeOrderedMap::new(); map.insert("title".to_string(), self.title.to_value()); map.insert("island_label".to_string(), self.island_label.to_value()); Value::map(map) } }
#[derive(Clone, Default)] pub struct InputContentTpl {  }
#[derive(Clone, Default)] pub struct InputLayoutTpl {  }

#[derive(Clone, Default)] pub struct Definition { pub html: Option<String> }
#[derive(Clone, Default)] pub struct Definitions { pub content: Option<Definition>, pub layout: Option<Definition> }
fn generated_conversion_error(message: impl Into<String>) -> TemplateError { TemplateError::without_position(ErrorCode::E_RUNTIME_TYPE, "generated", message) }
pub trait GeneratedConvert: Sized { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError>; fn to_value(&self) -> Value; }
impl GeneratedConvert for Value { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let _ = path; Ok(input.clone()) } fn to_value(&self) -> Value { self.clone() } }
impl GeneratedConvert for String { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { input.as_text().map(str::to_string).ok_or_else(|| generated_type_error(input, path, "a string")) } fn to_value(&self) -> Value { Value::text(self.clone()) } }
impl GeneratedConvert for f64 { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Number(number) => Ok(*number), _ => Err(generated_type_error(input, path, "a number")) } } fn to_value(&self) -> Value { Value::Number(*self) } }
impl GeneratedConvert for bool { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Bool(value) => Ok(*value), _ => Err(generated_type_error(input, path, "a boolean")) } } fn to_value(&self) -> Value { Value::Bool(*self) } }
impl<T: GeneratedConvert> GeneratedConvert for Option<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Null => Ok(None), other => T::from_value(other, path).map(Some) } } fn to_value(&self) -> Value { self.as_ref().map_or(Value::Null, T::to_value) } }
impl<T: GeneratedConvert> GeneratedConvert for Vec<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::List(items) => items.iter().enumerate().map(|(index, item)| T::from_value(item, &format!("{path}[{index}]"))).collect(), _ => Err(generated_type_error(input, path, "a list")) } } fn to_value(&self) -> Value { Value::list(self.iter().map(T::to_value).collect()) } }
fn generated_type_error(input: &Value, path: &str, expected: &str) -> TemplateError { generated_conversion_error(if matches!(input, Value::Null) { format!("{path} is required") } else { format!("{path} is not {expected}") }) }
fn generated_field<T: GeneratedConvert>(map: &RuntimeOrderedMap, path: &str, name: &str) -> Result<T, TemplateError> { T::from_value(map.get(name).unwrap_or(&Value::Null), &format!("{path}.{name}")) }
fn generated_check_field(map: &RuntimeOrderedMap, path: &str, name: &str, check: impl Fn(&Value, &str) -> Result<(), TemplateError>) -> Result<(), TemplateError> { check(map.get(name).unwrap_or(&Value::Null), &format!("{path}.{name}")) }
fn generated_check_page(input: &Value, path: &str) -> Result<(), TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; generated_check_field(map, path, "title", |value, path| match value { Value::Null => Ok(()), other => <String as GeneratedConvert>::from_value(other, path).map(drop) })?; Ok(()) }
fn generated_value<T: GeneratedConvert>(input: &T) -> Result<Value, TemplateError> { Ok(input.to_value()) }
fn render_content_tpl(assign: &Assign, definitions: &mut Definitions, input: InputContentTpl, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { let _ = (&assign, &definitions, &input, &runtime, &scope); let frame = Frame { name: "content.tpl".to_string(), lines: Some(LineIndex::from_starts(vec![0, 41, 65, 76])), context: Rc::clone(root_data) };

    context.write("<section data-react-island id=\"counter\">\u{a}<p>", &frame, [0, 44])?;
    let escaped = runtime.escape(context, &generated_value(&assign.island_label)?, &frame, [47, 59])?; context.write(&escaped, &frame, [44, 60])?;
    context.write("</p>\u{a}</section>\u{a}", &frame, [60, 76])?;
 Ok(()) }
fn render_layout_tpl(assign: &Assign, definitions: &mut Definitions, input: InputLayoutTpl, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { let _ = (&assign, &definitions, &input, &runtime, &scope); let frame = Frame { name: "layout.tpl".to_string(), lines: Some(LineIndex::from_starts(vec![0, 7, 26, 38, 46])), context: Rc::clone(root_data) };

    context.write("<main>\u{a}<h1>", &frame, [0, 11])?;
    let escaped = runtime.escape(context, &generated_value(&assign.title)?, &frame, [14, 19])?; context.write(&escaped, &frame, [11, 20])?;
    context.write("</h1>\u{a}", &frame, [20, 26])?;
    { if definitions.content.is_none() { return Err(runtime.error(context, &frame, [26, 37], ErrorCode::E_RUNTIME_BLOCK_UNDEFINED, "define content is not registered")); }
    let definition = definitions.content.clone();
    if let Some(html) = definition.as_ref().and_then(|value| value.html.as_ref()) { context.write(html, &frame, [26, 37])?; } else {
        let input = InputContentTpl::default();
        let mut block_scope = Scope::default();
        context.enter("content.tpl", Some(&frame), Some([26, 37]))?;
        let rendered = render_content_tpl(assign, definitions, input, context, runtime, root_data, &mut block_scope);
        context.leave();
        rendered?;
    }
    }
    context.write("</main>\u{a}", &frame, [38, 46])?;
 Ok(()) }
fn render_template(target: &str, assign: &Assign, definitions: &mut Definitions, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { match target {
        "content.tpl" => render_content_tpl(assign, definitions, InputContentTpl::default(), context, runtime, root_data, scope),
        "layout.tpl" => render_layout_tpl(assign, definitions, InputLayoutTpl::default(), context, runtime, root_data, scope),
        _ => Err(context.fail(ErrorCode::E_LOAD_NOT_FOUND, None, None, format!("template {target} does not exist"))),
} }
fn generated_error(message: String) -> RequestError { RequestError::Argument(ArgumentError { message }) }
struct GeneratedTarget { target: Option<String>, html: Option<String> }
fn generated_bind_definitions(name: &str, input: &HashMap<String, polyspec_template::DefineInput>) -> Result<(Definitions, HashMap<String, GeneratedTarget>), RequestError> { let mut definitions = Definitions::default(); let mut targets = HashMap::new(); for (id, input) in input { match id.as_str() {
            "content" => { if let Some(html) = &input.html { if false || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.content = Some(Definition { html: Some(html.clone()) }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("content.tpl") { return Err(generated_error(format!("define.{id} has an invalid template"))); }
if let Some(data) = &input.data { match polyspec_template::bind_data(data).map_err(|error| TemplateError::without_position(error.code, name, error.message))? { Value::Map(_) => {  }, _ => return Err(generated_error(format!("define.{id}.data is not an object"))) } }
definitions.content = Some(Definition::default()); targets.insert(id.clone(), GeneratedTarget { target: Some("content.tpl".to_string()), html: None }); } },
            "layout" => { if let Some(html) = &input.html { if true || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.layout = Some(Definition { html: Some(html.clone()) }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("layout.tpl") { return Err(generated_error(format!("define.{id} has an invalid template"))); }
if let Some(data) = &input.data { match polyspec_template::bind_data(data).map_err(|error| TemplateError::without_position(error.code, name, error.message))? { Value::Map(_) => {  }, _ => return Err(generated_error(format!("define.{id}.data is not an object"))) } }
definitions.layout = Some(Definition::default()); targets.insert(id.clone(), GeneratedTarget { target: Some("layout.tpl".to_string()), html: None }); } },
            _ => return Err(generated_error(format!("define.{id} is not declared"))),
        } } Ok((definitions, targets)) }
pub struct GeneratedProgram { pub runtime: RuntimeEnvironment }
impl GeneratedProgram { pub fn new(runtime: RuntimeEnvironment) -> GeneratedProgram { GeneratedProgram { runtime } }  }
impl Program for GeneratedProgram { fn prepare(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || { let root_data = Rc::new(polyspec_template::value::bind::bind_map(assign).map_err(|error| TemplateError::without_position(error.code, name, error.message))?); self.prepare_root(name, root_data, options) }) } fn render(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare(target, assign, options)?.render()?) } fn prepare_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || self.prepare_root(name, polyspec_template::bound_root(assign), options)) } fn render_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare_bound(target, assign, options)?.render()?) } }
impl GeneratedProgram { fn prepare_root<'e>(&'e self, name: &str, root_data: Rc<RuntimeOrderedMap>, options: &RenderOptions) -> Result<PreparedRender<'e>, RequestError> { let typed_assign: Assign = Assign::from_value(&Value::Map(Rc::clone(&root_data)), "assign").map_err(|error| generated_error(error.message))?; let (definitions, targets) = generated_bind_definitions(name, &options.define)?; let resolved = targets.get(name); let target_name = resolved.and_then(|value| value.target.clone()).unwrap_or_else(|| name.to_string()); let html = resolved.and_then(|value| value.html.clone()); let env = options.env.clone().unwrap_or_else(|| polyspec_template::Env { timezone: "Z".to_string(), now: std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|duration| duration.as_secs() as f64).unwrap_or(0.0) }); Ok(PreparedRender::new(name, move || { let mut context = RenderContext::new(&self.runtime, Rc::clone(&root_data), env.clone(), &target_name); let runtime = RuntimeBindings::new(); let mut scope = Scope::default(); let mut render_definitions = definitions.clone(); context.enter(&target_name, None, None)?; let result = if let Some(html) = &html { let frame = Frame { name: target_name.clone(), lines: None, context: Rc::clone(&root_data) }; context.write(html, &frame, [0, 0]) } else { render_template(&target_name, &typed_assign, &mut render_definitions, &mut context, &runtime, &root_data, &mut scope) }; context.leave(); result?; Ok(context.output) })) } }


php · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "php",
  "entry": "layout.tpl",
  "sourceDigest": "c688413e9bb0e846699f0df008a45824ea5c4ffec063bc8ae0355cbe4d300c47",
  "typeDigest": "2e7791f397b9a5dbd6610bc51eb4255149c45f1b7671c9d752ddd3e8b4067422",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "ba7f0bfd4d8024e26cbef4e9ddf0cd1e011489480f00daebb75a11ecfa8e218f",
  "files": {
    "Page.php": {
      "path": "Page.php",
      "artifactDigest": "4d2bda7b74f796c2eb7ef261ab8fe4bd8753e9e9171f4840629b1c793e8cf8cc"
    },
    "Slot.php": {
      "path": "Slot.php",
      "artifactDigest": "ae06f2af0cf18fecce49eafe2d229a2f921fec6a833bd62da065a6384e145d45"
    },
    "Assign.php": {
      "path": "Assign.php",
      "artifactDigest": "239bc7487915a6669494b1944d38accd4f6fc3cb6e97fc3bc3857b54c4cad66b"
    },
    "InputContentTpl.php": {
      "path": "InputContentTpl.php",
      "artifactDigest": "bf8e1e7f0dfa8e80f979ebd5a1d16d81b8c8883659769da9a6fa905d8cbdb506"
    },
    "InputLayoutTpl.php": {
      "path": "InputLayoutTpl.php",
      "artifactDigest": "86da6fa52d888c87ca265aa32b62fc0373f139ab8a1f4a6701dc5d5ccef33539"
    },
    "DefinitionDataContentTpl.php": {
      "path": "DefinitionDataContentTpl.php",
      "artifactDigest": "fa593de50bddcd3794e5a11c94647895839e249b14a2a82fcb582d6fe5060470"
    },
    "DefinitionDataLayoutTpl.php": {
      "path": "DefinitionDataLayoutTpl.php",
      "artifactDigest": "465646cf8f65395f7b82034ead01aa0dc317ca18f999f4b61ae3030a908835f3"
    },
    "Definition.php": {
      "path": "Definition.php",
      "artifactDigest": "63ac1e65f1641c6b6c98a38dfa28640eddf5572d9c54b1d657a8f9f149778147"
    },
    "Definitions.php": {
      "path": "Definitions.php",
      "artifactDigest": "52dc27d5daeaa57eab8924d99abfd93cf2bcd4f0a0d4545141a4a20af6b25910"
    },
    "ArtifactManifest.php": {
      "path": "ArtifactManifest.php",
      "artifactDigest": "ecf80842576705de834015a600ac81f757e1b555dcfbc1f82463fb66069b7450"
    },
    "GeneratedRuntime.php": {
      "path": "GeneratedRuntime.php",
      "artifactDigest": "9917bf51902f31c45cec1c6e2f420b8be4af44c32181763d442fdb3aef35e544"
    },
    "GeneratedTemplates.php": {
      "path": "GeneratedTemplates.php",
      "artifactDigest": "d3fcf6b6f38030ef5ba98d2710935cfb2d1c70960a35b8047643859e41e584f5"
    },
    "GeneratedExecution.php": {
      "path": "GeneratedExecution.php",
      "artifactDigest": "401921b189ca1d66e341a7fb78d53940b0816efb67edf969c48055a691f9c7b2"
    },
    "GeneratedProgram.php": {
      "path": "GeneratedProgram.php",
      "artifactDigest": "86171d1bf1e866796a1897eef3cf65fadf490786de2a21ab47165a02a8dafa76"
    }
  }
}

<?php

declare(strict_types=1);

namespace Polyspec\Showcase\Generated\ReactBoundary;

use Polyspec\Template\Render\Context;
use Polyspec\Template\Render\Frame;
use Polyspec\Template\Render\RuntimeBindings;
use Polyspec\Template\Render\Scope;
use Polyspec\Template\Value\MapValue;

final class GeneratedTemplates
{
    public static function render(
        string $target,
        Assign $assign,
        Definitions $definitions,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        switch ($target) {
            case 'content.tpl':
                self::renderContentTpl(
                    $assign,
                    $definitions,
                    new InputContentTpl(),
                    $context,
                    $runtime,
                    $rootData,
                    $scope,
                );
                return;
            case 'layout.tpl':
                self::renderLayoutTpl(
                    $assign,
                    $definitions,
                    new InputLayoutTpl(),
                    $context,
                    $runtime,
                    $rootData,
                    $scope,
                );
                return;
            default:
                throw $context->fail('E_LOAD_NOT_FOUND', null, null, 'template ' . $target . ' does not exist');
        }
    }

    private static function renderContentTpl(
        Assign $assign,
        Definitions $definitions,
        InputContentTpl $input,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        $frame = new Frame('content.tpl', [0, 41, 65, 76], $rootData);
        $context->at($frame, [0, 44]);
        $context->write(('<section data-react-island id="counter">' . "\n" . '<p>'));
        $context->at($frame, [44, 60]);
        $context->write($runtime->escape($assign->island_label, $frame, [47, 59]));
        $context->at($frame, [60, 76]);
        $context->write(('</p>' . "\n" . '</section>' . "\n"));
    }

    private static function renderLayoutTpl(
        Assign $assign,
        Definitions $definitions,
        InputLayoutTpl $input,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        $frame = new Frame('layout.tpl', [0, 7, 26, 38, 46], $rootData);
        $context->at($frame, [0, 11]);
        $context->write(('<main>' . "\n" . '<h1>'));
        $context->at($frame, [11, 20]);
        $context->write($runtime->escape($assign->title, $frame, [14, 19]));
        $context->at($frame, [20, 26]);
        $context->write(('</h1>' . "\n"));
        $definition = $definitions->content;
        if ($definition === null) {
            throw $runtime->error($frame, [26, 37], 'E_RUNTIME_BLOCK_UNDEFINED', 'define content is not registered');
        }
        if ($definition?->html !== null) {
            $context->at($frame, [26, 37]);
            $context->write($definition->html);
        } else {
            if ($definition?->data !== null && !($definition->data instanceof DefinitionDataContentTpl)) {
                throw $runtime->error(
                    $frame,
                    [26, 37],
                    'E_RUNTIME_TYPE',
                    'generated definition content data has an invalid type',
                );
            }
            $input = new InputContentTpl();
            $blockScope = new Scope();
            $context->enter('content.tpl', $frame, [26, 37]);
            try {
                self::renderContentTpl($assign, $definitions, $input, $context, $runtime, $rootData, $blockScope);
            } finally {
                $context->leave();
            }
        }
        $context->at($frame, [38, 46]);
        $context->write(('</main>' . "\n"));
    }
}

Output · 124 bytes · 4c247742a44e…

<main>
<h1>Server rendered shell</h1>
<section data-react-island id="counter">
<p>Interactive island</p>
</section>
</main>
Implementationtsgorustphppython
artifact renderPASSPASSPASSPASSPASS

Scope precedence

A template definition receives root assign data, definition data and a scope argument, while a layout local stays isolated.

assign datadefine datascope precedencelocal isolation

Inputs

assign
{
  "page": {
    "title": "from assign"
  },
  "root_label": "root assign",
  "defined_label": "root value that is replaced"
}
define
{
  "layout": "layout.tpl",
  "content": {
    "template": "content.tpl",
    "data": {
      "title": "from define data",
      "defined_label": "definition data"
    }
  }
}
templates · parser ranges
--- content.tpl
<article>
<h1>{= title}</h1>
<p class="root">{= root_label}</p>
<p class="defined">{= defined_label}</p>
<p class="local">{= layout_local | default('missing')}</p>
</article>


--- layout.tpl
{: layout_local = 'visible only in layout'}
<section class="scope">
{# content title:page.title}
</section>
compiled artifacts
ast/manifest.json
{
  "schema": 3,
  "mode": "ast",
  "target": "canonical",
  "entry": "layout.tpl",
  "delimiters": null,
  "sourceDigest": "112ab94718df18ed706f433c92ce33f65c71045800866aabe4fc052142d97028",
  "typeDigest": "3fec0fc166342c701a26f62cb935ae5fbb99d9f610b9fcefb50d105b79d59014",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "fb8049870573426dd093e2af0cf544e3592477ef1af415453fafcf71f0389901",
  "files": {
    "content.tpl": {
      "path": "content.tpl.ast.json",
      "sourceDigest": "c79abf1a243053bd7c145f39700c8d00b06a5d23eb222ae4d445e7e6102f6b7d",
      "artifactDigest": "2ebb456bc896d48a699d533525e2fa07abe52ca12618da6e6eb7bc91f7f591de",
      "lines": [
        0,
        10,
        29,
        64,
        105,
        164,
        175
      ]
    },
    "layout.tpl": {
      "path": "layout.tpl.ast.json",
      "sourceDigest": "8b9462afffb5aa9d81c6d17412eb9f828016bc33298cdb15eaa66eaa1d0b9431",
      "artifactDigest": "2a8277c99d6d0eeeafddecbcc0a8ce88e0cafef905e347b17d52fbb08bb3ce74",
      "lines": [
        0,
        44,
        68,
        97,
        108
      ]
    }
  }
}

ast/content.tpl.ast.json · content.tpl
{
  "type": "Template",
  "name": "content.tpl",
  "body": [
    {
      "type": "Text",
      "value": "<article>\n<h1>",
      "span": [
        0,
        14
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Var",
        "name": "title",
        "span": [
          17,
          22
        ]
      },
      "span": [
        14,
        23
      ]
    },
    {
      "type": "Text",
      "value": "</h1>\n<p class=\"root\">",
      "span": [
        23,
        45
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Var",
        "name": "root_label",
        "span": [
          48,
          58
        ]
      },
      "span": [
        45,
        59
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n<p class=\"defined\">",
      "span": [
        59,
        83
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Var",
        "name": "defined_label",
        "span": [
          86,
          99
        ]
      },
      "span": [
        83,
        100
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n<p class=\"local\">",
      "span": [
        100,
        122
      ]
    },
    {
      "type": "Echo",
      "expr": {
        "type": "Call",
        "name": "default",
        "args": [
          {
            "type": "Var",
            "name": "layout_local",
            "span": [
              125,
              137
            ]
          },
          {
            "type": "Literal",
            "kind": "string",
            "value": "missing",
            "span": [
              148,
              157
            ]
          }
        ],
        "span": [
          125,
          158
        ]
      },
      "span": [
        122,
        159
      ]
    },
    {
      "type": "Text",
      "value": "</p>\n</article>\n",
      "span": [
        159,
        175
      ]
    }
  ],
  "comments": []
}


ast/layout.tpl.ast.json · layout.tpl
{
  "type": "Template",
  "name": "layout.tpl",
  "body": [
    {
      "type": "Set",
      "name": "layout_local",
      "expr": {
        "type": "Literal",
        "kind": "string",
        "value": "visible only in layout",
        "span": [
          18,
          42
        ]
      },
      "span": [
        0,
        43
      ]
    },
    {
      "type": "Text",
      "value": "<section class=\"scope\">\n",
      "span": [
        44,
        68
      ]
    },
    {
      "type": "Block",
      "id": "content",
      "path": null,
      "scope": [
        {
          "name": "title",
          "expr": {
            "type": "Member",
            "object": {
              "type": "Var",
              "name": "page",
              "span": [
                85,
                89
              ]
            },
            "key": "title",
            "span": [
              85,
              95
            ]
          }
        }
      ],
      "span": [
        68,
        96
      ]
    },
    {
      "type": "Text",
      "value": "</section>\n",
      "span": [
        97,
        108
      ]
    }
  ],
  "comments": []
}
generated renderers
typescript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "ts",
  "entry": "layout.tpl",
  "sourceDigest": "112ab94718df18ed706f433c92ce33f65c71045800866aabe4fc052142d97028",
  "typeDigest": "3fec0fc166342c701a26f62cb935ae5fbb99d9f610b9fcefb50d105b79d59014",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "a81f5f0f977b099b35dd1267160848c835a8aaf7c6865ac99d066a351070cbb0",
  "files": {
    "scope-precedence.ts": {
      "path": "scope-precedence.ts",
      "artifactDigest": "e9db26dbc5e5cf7ede014505eab2a05ebcef155c109b6cf6777bc19ae25f1af4"
    }
  }
}

// Generated.
import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary, type MapValue, type PreparedRender, type Program, type RenderOptions, type Span, type Template, type Value } from '@polyspec/template';
export interface Page {
  title: string;
}
export interface Assign {
  page: Page;
  root_label: string;
  defined_label: string;
}
export interface Input_content_tpl { title: string; root_label: string; defined_label: string; layout_local: string | null; }
export interface Input_layout_tpl {  }
export type DefinitionData<T> = Partial<T>;
export interface Definition<T> { template?: string; html?: string; data?: DefinitionData<T>; }
export interface Definitions { content?: Definition<Input_content_tpl>; layout?: Definition<Input_layout_tpl>; }
export interface ArtifactManifest { schema: number; mode: 'gen'; target: 'ts'; entry: string; sourceDigest: string; typeDigest: string; contractDigest: string; files: Record<string, string>; }
type GeneratedDecoder<T> = (value: Value | undefined, path: string) => T;
function generatedTypeError(value: Value | undefined, path: string, expected: string): Error { return new Error(value === null || value === undefined ? path + ' is required' : path + ' is not ' + expected); }
function generatedChecked<T>(decode: GeneratedDecoder<T>, value: Value, path: string, runtime: RuntimeBindings, frame: Frame, span: Span): T { try { return decode(value, path); } catch (error) { if (error instanceof Error) throw runtime.error(frame, span, 'E_RUNTIME_TYPE', error.message); throw error; } }
function generatedDataObject(value: Value, path: string): MapValue { if (value instanceof Map) return value; throw new Error(path + ' is not an object'); }
function generatedPlain(value: unknown): value is object { if (typeof value !== 'object' || value === null) return false; const prototype = Reflect.getPrototypeOf(value); return prototype === Object.prototype || prototype === null; }
function generatedObject(value: Value | undefined, path: string): MapValue { if (value instanceof Map) return value; throw generatedTypeError(value, path, 'an object'); }
function generatedString(value: Value | undefined, path: string): string { if (typeof value === 'string') return value; throw generatedTypeError(value, path, 'a string'); }
function generatedOptional<T>(decode: GeneratedDecoder<T>): GeneratedDecoder<T | null> { return (value, path) => value === null || value === undefined ? null : decode(value, path); }
function generatedDecode_Page(value: Value | undefined, path: string): Page { const object = generatedObject(value, path); return { title: generatedString(object.get("title"), path + ".title") }; }
function generatedDecodeAssign(value: Value | undefined, path: string): Assign { const object = generatedObject(value, path); return { page: generatedDecode_Page(object.get("page"), path + ".page"), root_label: generatedString(object.get("root_label"), path + ".root_label"), defined_label: generatedString(object.get("defined_label"), path + ".defined_label") }; }
function generatedDecodeData_Input_content_tpl(value: Value, path: string): DefinitionData<Input_content_tpl> { const object = generatedDataObject(value, path); const data: DefinitionData<Input_content_tpl> = {}; if (object.has("title")) data.title = generatedString(object.get("title"), path + ".title"); if (object.has("root_label")) data.root_label = generatedString(object.get("root_label"), path + ".root_label"); if (object.has("defined_label")) data.defined_label = generatedString(object.get("defined_label"), path + ".defined_label"); if (object.has("layout_local")) data.layout_local = generatedOptional(generatedString)(object.get("layout_local"), path + ".layout_local"); return data; }
function generatedDecodeData_Input_layout_tpl(value: Value, path: string): DefinitionData<Input_layout_tpl> { generatedDataObject(value, path); return {}; }
function generatedBindAssign(value: unknown): { assign: Assign; root: MapValue } { const root = bindMap(value); return { assign: generatedDecodeAssign(root, 'assign'), root }; }
type GeneratedTarget = { target: string | null; html?: string };
type GeneratedBoundDefinitions = { definitions: Definitions; targets: Map<string, GeneratedTarget> };
function generatedBindDefinitions(input: unknown): GeneratedBoundDefinitions {
  const definitions: Definitions = {};
  const targets = new Map<string, GeneratedTarget>();
  if (input === undefined || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error('define is not an object');
  const entries: [string, unknown][] = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
    case "content": {
      if (typeof raw === 'string') {
        if (raw !== "content.tpl") throw new Error("define.content has an invalid template");
        definitions.content = { template: "content.tpl" }; targets.set("content", { target: "content.tpl" }); break;
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.content is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        if (template !== undefined || data !== undefined) throw new Error("define.content has an invalid html entry");
        definitions.content = { html }; targets.set("content", { target: null, html }); break;
      }
      if (template !== "content.tpl") throw new Error("define.content has an invalid template");
      definitions.content = { template: "content.tpl", data: data === undefined ? {} : generatedDecodeData_Input_content_tpl(data, "define.content.data") }; targets.set("content", { target: "content.tpl" }); break;
    }
    case "layout": {
      if (typeof raw === 'string') {
        if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl" }; targets.set("layout", { target: "layout.tpl" }); break;
      }
      if (typeof raw !== 'object' || raw === null) throw new Error("define.layout is not an object");
      const template = 'template' in raw ? raw.template : undefined;
      const html = 'html' in raw ? raw.html : undefined;
      const data = 'data' in raw && raw.data !== undefined ? bindData(raw.data) : undefined;
      if (typeof html === 'string') {
        throw new Error("define.layout has an invalid html entry");
      }
      if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
      definitions.layout = { template: "layout.tpl", data: data === undefined ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") }; targets.set("layout", { target: "layout.tpl" }); break;
    }
    default: throw new Error('define.' + id + ' is not declared');
    }
  }
  return { definitions, targets };
}
function render_content_tpl(_assign: Assign, _definitions: Definitions, input: Input_content_tpl, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  const frame = new Frame("content.tpl", [0,10,29,64,105,164,175], rootData);
  scope.locals.set("title", input.title);
  scope.locals.set("root_label", input.root_label);
  scope.locals.set("defined_label", input.defined_label);
  scope.locals.set("layout_local", input.layout_local);
    context.at(frame, [0,14]); context.output.write("<article>\n<h1>");
    context.at(frame, [14,23]); context.output.write(runtime.escape(input.title, frame, [17,22]));
    context.at(frame, [23,45]); context.output.write("</h1>\n<p class=\"root\">");
    context.at(frame, [45,59]); context.output.write(runtime.escape(input.root_label, frame, [48,58]));
    context.at(frame, [59,83]); context.output.write("</p>\n<p class=\"defined\">");
    context.at(frame, [83,100]); context.output.write(runtime.escape(input.defined_label, frame, [86,99]));
    context.at(frame, [100,122]); context.output.write("</p>\n<p class=\"local\">");
    context.at(frame, [122,159]); context.output.write(runtime.escape(generatedChecked(generatedString, runtime.call("default", [input.layout_local, "missing"], frame, [125,158]), "default(layout_local, \"missing\")", runtime, frame, [125,158]), frame, [125,158]));
    context.at(frame, [159,175]); context.output.write("</p>\n</article>\n");
}
function render_layout_tpl(assign: Assign, definitions: Definitions, input: Input_layout_tpl, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  const frame = new Frame("layout.tpl", [0,44,68,97,108], rootData);

    const local_layout_local_1: string = "visible only in layout";
    scope.locals.set("layout_local", local_layout_local_1);
    context.at(frame, [44,68]); context.output.write("<section class=\"scope\">\n");
    { let definition = definitions.content;
    if (definition === undefined) throw runtime.error(frame, [68,96], 'E_RUNTIME_BLOCK_UNDEFINED', "define content is not registered");
    if (definition?.html !== undefined) { context.at(frame, [68,96]); context.output.write(definition.html); }
    else { const input: Input_content_tpl = { title: (assign.page).title, root_label: definition?.data?.root_label !== undefined ? definition.data.root_label : assign.root_label, defined_label: definition?.data?.defined_label !== undefined ? definition.data.defined_label : assign.defined_label, layout_local: definition?.data?.layout_local !== undefined ? definition.data.layout_local : null }; const blockScope = new Scope(); context.enter("content.tpl", frame, [68,96]); try { render_content_tpl(assign, definitions, input, context, runtime, rootData, blockScope); } finally { context.leave(); } }
    }
    context.at(frame, [97,108]); context.output.write("</section>\n");
}
function renderTemplate(target: string, assign: Assign, definitions: Definitions, context: RenderContext, runtime: RuntimeBindings, rootData: MapValue, scope: Scope): void {
  switch (target) {
    case "layout.tpl": render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope); return;
    default: throw context.fail('E_LOAD_NOT_FOUND', null, null, 'template ' + target + ' does not exist');
  }
}
function generatedEnv(input: unknown): { timezone: string; now: number } { if (input === undefined || input === null) return { timezone: 'Z', now: Math.floor(Date.now() / 1000) }; if (!generatedPlain(input)) throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env is not an object'); const timezone = ('timezone' in input ? input.timezone : undefined) ?? 'Z'; const now = ('now' in input ? input.now : undefined) ?? Math.floor(Date.now() / 1000); if (typeof timezone !== 'string') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.timezone is not a string'); if (typeof now !== 'number') throw new BindError('E_DATA_UNSUPPORTED_TYPE', 'env.now is not a number'); return { timezone, now }; }
class GeneratedPreparedRender implements PreparedRender { private readonly name: string; private readonly execute: () => string; constructor(name: string, execute: () => string) { this.name = name; this.execute = execute; } render(): string { return internalBoundary(this.name, this.execute); } }
export class GeneratedProgram implements Program {
  readonly runtime: RuntimeEnvironment;
  constructor(runtime: RuntimeEnvironment = new RuntimeEnvironment()) { this.runtime = runtime; }
  prepare(target: string | Template, assign: unknown, options: RenderOptions = {}): PreparedRender { if (typeof target !== 'string') throw new Error('generated target must be a template name'); return internalBoundary(target, () => this.prepareBound(target, assign, options)); }
  private prepareBound(target: string, assign: unknown, options: RenderOptions): PreparedRender { let boundAssign: { assign: Assign; root: MapValue }; let bound: GeneratedBoundDefinitions; let env: { timezone: string; now: number }; try { boundAssign = generatedBindAssign(assign); bound = generatedBindDefinitions(options.define); env = generatedEnv(options.env); } catch (error) { if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message }); throw error; } const registered = bound.targets.get(target); const html = registered?.html; if (html !== undefined) return new GeneratedPreparedRender(target, () => html); const targetName = registered?.target ?? target; return new GeneratedPreparedRender(target, () => { const context = new RenderContext(this.runtime, boundAssign.root, env, targetName); const runtime = new RuntimeBindings(context); const scope = new Scope(); context.enter(targetName, null, null); try { renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope); return context.output.toString(); } finally { context.leave(); } }); }
  render(target: string | Template, assign: unknown, options: RenderOptions = {}): string { return this.prepare(target, assign, options).render(); }
}


javascript · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "js",
  "entry": "layout.tpl",
  "sourceDigest": "112ab94718df18ed706f433c92ce33f65c71045800866aabe4fc052142d97028",
  "typeDigest": "3fec0fc166342c701a26f62cb935ae5fbb99d9f610b9fcefb50d105b79d59014",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "7a758948ae54e846b8c9cb16fa604ebf4a8aa94725dd3cd63ae77c94b2fe1e05",
  "files": {
    "scope-precedence.js": {
      "path": "scope-precedence.js",
      "artifactDigest": "2cf584f48faefd0a4765dcac2abc207aa17e42bbbfb96ecdb41cc9f914c21813"
    }
  }
}

import { BindError, Frame, RenderContext, RuntimeBindings, RuntimeEnvironment, Scope, TemplateError, bindData, bindMap, checkText, internalBoundary } from "@polyspec/template";
function generatedTypeError(value, path, expected) {
  return new Error(value === null || value === void 0 ? path + " is required" : path + " is not " + expected);
}
function generatedChecked(decode, value, path, runtime, frame, span) {
  try {
    return decode(value, path);
  } catch (error) {
    if (error instanceof Error) throw runtime.error(frame, span, "E_RUNTIME_TYPE", error.message);
    throw error;
  }
}
function generatedDataObject(value, path) {
  if (value instanceof Map) return value;
  throw new Error(path + " is not an object");
}
function generatedPlain(value) {
  if (typeof value !== "object" || value === null) return false;
  const prototype = Reflect.getPrototypeOf(value);
  return prototype === Object.prototype || prototype === null;
}
function generatedObject(value, path) {
  if (value instanceof Map) return value;
  throw generatedTypeError(value, path, "an object");
}
function generatedString(value, path) {
  if (typeof value === "string") return value;
  throw generatedTypeError(value, path, "a string");
}
function generatedOptional(decode) {
  return (value, path) => value === null || value === void 0 ? null : decode(value, path);
}
function generatedDecode_Page(value, path) {
  const object = generatedObject(value, path);
  return { title: generatedString(object.get("title"), path + ".title") };
}
function generatedDecodeAssign(value, path) {
  const object = generatedObject(value, path);
  return { page: generatedDecode_Page(object.get("page"), path + ".page"), root_label: generatedString(object.get("root_label"), path + ".root_label"), defined_label: generatedString(object.get("defined_label"), path + ".defined_label") };
}
function generatedDecodeData_Input_content_tpl(value, path) {
  const object = generatedDataObject(value, path);
  const data = {};
  if (object.has("title")) data.title = generatedString(object.get("title"), path + ".title");
  if (object.has("root_label")) data.root_label = generatedString(object.get("root_label"), path + ".root_label");
  if (object.has("defined_label")) data.defined_label = generatedString(object.get("defined_label"), path + ".defined_label");
  if (object.has("layout_local")) data.layout_local = generatedOptional(generatedString)(object.get("layout_local"), path + ".layout_local");
  return data;
}
function generatedDecodeData_Input_layout_tpl(value, path) {
  generatedDataObject(value, path);
  return {};
}
function generatedBindAssign(value) {
  const root = bindMap(value);
  return { assign: generatedDecodeAssign(root, "assign"), root };
}
function generatedBindDefinitions(input) {
  const definitions = {};
  const targets = /* @__PURE__ */ new Map();
  if (input === void 0 || input === null) return { definitions, targets };
  if (!generatedPlain(input)) throw new Error("define is not an object");
  const entries = Object.entries(input);
  for (const [id, raw] of entries) {
    checkText(id);
    switch (id) {
      case "content": {
        if (typeof raw === "string") {
          if (raw !== "content.tpl") throw new Error("define.content has an invalid template");
          definitions.content = { template: "content.tpl" };
          targets.set("content", { target: "content.tpl" });
          break;
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.content is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          if (template !== void 0 || data !== void 0) throw new Error("define.content has an invalid html entry");
          definitions.content = { html };
          targets.set("content", { target: null, html });
          break;
        }
        if (template !== "content.tpl") throw new Error("define.content has an invalid template");
        definitions.content = { template: "content.tpl", data: data === void 0 ? {} : generatedDecodeData_Input_content_tpl(data, "define.content.data") };
        targets.set("content", { target: "content.tpl" });
        break;
      }
      case "layout": {
        if (typeof raw === "string") {
          if (raw !== "layout.tpl") throw new Error("define.layout has an invalid template");
          definitions.layout = { template: "layout.tpl" };
          targets.set("layout", { target: "layout.tpl" });
          break;
        }
        if (typeof raw !== "object" || raw === null) throw new Error("define.layout is not an object");
        const template = "template" in raw ? raw.template : void 0;
        const html = "html" in raw ? raw.html : void 0;
        const data = "data" in raw && raw.data !== void 0 ? bindData(raw.data) : void 0;
        if (typeof html === "string") {
          throw new Error("define.layout has an invalid html entry");
        }
        if (template !== "layout.tpl") throw new Error("define.layout has an invalid template");
        definitions.layout = { template: "layout.tpl", data: data === void 0 ? {} : generatedDecodeData_Input_layout_tpl(data, "define.layout.data") };
        targets.set("layout", { target: "layout.tpl" });
        break;
      }
      default:
        throw new Error("define." + id + " is not declared");
    }
  }
  return { definitions, targets };
}
function render_content_tpl(_assign, _definitions, input, context, runtime, rootData, scope) {
  const frame = new Frame("content.tpl", [0, 10, 29, 64, 105, 164, 175], rootData);
  scope.locals.set("title", input.title);
  scope.locals.set("root_label", input.root_label);
  scope.locals.set("defined_label", input.defined_label);
  scope.locals.set("layout_local", input.layout_local);
  context.at(frame, [0, 14]);
  context.output.write("<article>\n<h1>");
  context.at(frame, [14, 23]);
  context.output.write(runtime.escape(input.title, frame, [17, 22]));
  context.at(frame, [23, 45]);
  context.output.write('</h1>\n<p class="root">');
  context.at(frame, [45, 59]);
  context.output.write(runtime.escape(input.root_label, frame, [48, 58]));
  context.at(frame, [59, 83]);
  context.output.write('</p>\n<p class="defined">');
  context.at(frame, [83, 100]);
  context.output.write(runtime.escape(input.defined_label, frame, [86, 99]));
  context.at(frame, [100, 122]);
  context.output.write('</p>\n<p class="local">');
  context.at(frame, [122, 159]);
  context.output.write(runtime.escape(generatedChecked(generatedString, runtime.call("default", [input.layout_local, "missing"], frame, [125, 158]), 'default(layout_local, "missing")', runtime, frame, [125, 158]), frame, [125, 158]));
  context.at(frame, [159, 175]);
  context.output.write("</p>\n</article>\n");
}
function render_layout_tpl(assign, definitions, input, context, runtime, rootData, scope) {
  const frame = new Frame("layout.tpl", [0, 44, 68, 97, 108], rootData);
  const local_layout_local_1 = "visible only in layout";
  scope.locals.set("layout_local", local_layout_local_1);
  context.at(frame, [44, 68]);
  context.output.write('<section class="scope">\n');
  {
    let definition = definitions.content;
    if (definition === void 0) throw runtime.error(frame, [68, 96], "E_RUNTIME_BLOCK_UNDEFINED", "define content is not registered");
    if (definition?.html !== void 0) {
      context.at(frame, [68, 96]);
      context.output.write(definition.html);
    } else {
      const input2 = { title: assign.page.title, root_label: definition?.data?.root_label !== void 0 ? definition.data.root_label : assign.root_label, defined_label: definition?.data?.defined_label !== void 0 ? definition.data.defined_label : assign.defined_label, layout_local: definition?.data?.layout_local !== void 0 ? definition.data.layout_local : null };
      const blockScope = new Scope();
      context.enter("content.tpl", frame, [68, 96]);
      try {
        render_content_tpl(assign, definitions, input2, context, runtime, rootData, blockScope);
      } finally {
        context.leave();
      }
    }
  }
  context.at(frame, [97, 108]);
  context.output.write("</section>\n");
}
function renderTemplate(target, assign, definitions, context, runtime, rootData, scope) {
  switch (target) {
    case "layout.tpl":
      render_layout_tpl(assign, definitions, {}, context, runtime, rootData, scope);
      return;
    default:
      throw context.fail("E_LOAD_NOT_FOUND", null, null, "template " + target + " does not exist");
  }
}
function generatedEnv(input) {
  if (input === void 0 || input === null) return { timezone: "Z", now: Math.floor(Date.now() / 1e3) };
  if (!generatedPlain(input)) throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env is not an object");
  const timezone = ("timezone" in input ? input.timezone : void 0) ?? "Z";
  const now = ("now" in input ? input.now : void 0) ?? Math.floor(Date.now() / 1e3);
  if (typeof timezone !== "string") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.timezone is not a string");
  if (typeof now !== "number") throw new BindError("E_DATA_UNSUPPORTED_TYPE", "env.now is not a number");
  return { timezone, now };
}
class GeneratedPreparedRender {
  name;
  execute;
  constructor(name, execute) {
    this.name = name;
    this.execute = execute;
  }
  render() {
    return internalBoundary(this.name, this.execute);
  }
}
export class GeneratedProgram {
  runtime;
  constructor(runtime = new RuntimeEnvironment()) {
    this.runtime = runtime;
  }
  prepare(target, assign, options = {}) {
    if (typeof target !== "string") throw new Error("generated target must be a template name");
    return internalBoundary(target, () => this.prepareBound(target, assign, options));
  }
  prepareBound(target, assign, options) {
    let boundAssign;
    let bound;
    let env;
    try {
      boundAssign = generatedBindAssign(assign);
      bound = generatedBindDefinitions(options.define);
      env = generatedEnv(options.env);
    } catch (error) {
      if (error instanceof BindError) throw new TemplateError({ code: error.code, template: target, line: 0, col: 0, offset: 0, end: 0, message: error.message });
      throw error;
    }
    const registered = bound.targets.get(target);
    const html = registered?.html;
    if (html !== void 0) return new GeneratedPreparedRender(target, () => html);
    const targetName = registered?.target ?? target;
    return new GeneratedPreparedRender(target, () => {
      const context = new RenderContext(this.runtime, boundAssign.root, env, targetName);
      const runtime = new RuntimeBindings(context);
      const scope = new Scope();
      context.enter(targetName, null, null);
      try {
        renderTemplate(targetName, boundAssign.assign, bound.definitions, context, runtime, boundAssign.root, scope);
        return context.output.toString();
      } finally {
        context.leave();
      }
    });
  }
  render(target, assign, options = {}) {
    return this.prepare(target, assign, options).render();
  }
}


go · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "go",
  "entry": "layout.tpl",
  "sourceDigest": "112ab94718df18ed706f433c92ce33f65c71045800866aabe4fc052142d97028",
  "typeDigest": "3fec0fc166342c701a26f62cb935ae5fbb99d9f610b9fcefb50d105b79d59014",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "45312e93dc75fa9cac0af4448f4b43508dff97b90f52d7c3d1407e5852dbc284",
  "files": {
    "generated.go": {
      "path": "generated.go",
      "artifactDigest": "b89f993bc70d1de383402bddcada4cf1d08b55275e2f0e367770c5e7007567f3"
    }
  }
}

// Code generated by @polyspec/template-compiler. DO NOT EDIT.

package generated

import (
	"encoding/json"
	"errors"
	"fmt"
	template "github.com/polyspec/template/packages/go"
	"github.com/polyspec/template/packages/go/ast"
	"github.com/polyspec/template/packages/go/errs"
	"github.com/polyspec/template/packages/go/functions"
	"github.com/polyspec/template/packages/go/render"
	"github.com/polyspec/template/packages/go/value"
	"time"
	"unicode/utf8"
)

type Page struct {
	Title string `json:"title"`
}

func (r Page) TemplateValue() value.Value {
	result := value.NewOrderedMap()
	result.Set("title", generatedValue(r.Title))
	return result
}

type Assign struct {
	Page          Page   `json:"page"`
	Root_label    string `json:"root_label"`
	Defined_label string `json:"defined_label"`
}

type Input_content_tpl struct {
	Title         string  `json:"title"`
	Root_label    string  `json:"root_label"`
	Defined_label string  `json:"defined_label"`
	Layout_local  *string `json:"layout_local"`
}

type Input_layout_tpl struct{}

type DefinitionData_content_tpl struct {
	Title         *string  `json:"title"`
	Root_label    *string  `json:"root_label"`
	Defined_label *string  `json:"defined_label"`
	Layout_local  **string `json:"layout_local"`
}

type DefinitionData_layout_tpl struct{}

type Definition[T any] struct {
	Template string  `json:"template"`
	HTML     *string `json:"html"`
	Data     *T      `json:"data"`
}

type Definitions struct {
	Content *Definition[DefinitionData_content_tpl] `json:"content"`
	Layout  *Definition[DefinitionData_layout_tpl]  `json:"layout"`
}

type ArtifactManifest struct {
	Schema         int
	Mode           string
	Target         string
	Entry          string
	SourceDigest   string
	TypeDigest     string
	ContractDigest string
	Files          map[string]string
}

var generatedRecordFields = map[string][]generatedField{"Page": []generatedField{{Name: "title", Type: generatedType{Kind: "string"}}}}

func generatedPanic(err error) {
	if err != nil {
		panic(err)
	}
}

func generatedValue(input any) value.Value {
	switch item := input.(type) {
	case nil:
		return nil
	case bool:
		return item
	case float64:
		return item
	case string:
		return item
	case value.SafeString:
		return item
	case value.List:
		result := make(value.List, len(item))
		for index, element := range item {
			result[index] = generatedValue(element)
		}
		return result
	case *value.OrderedMap:
		return item
	}
	result, err := value.Convert(input)
	generatedPanic(err)
	return result
}

func generatedResult[T any](input value.Value) T {
	result, err := generatedAs[T](input)
	generatedPanic(err)
	return result
}

func generatedAs[T any](input value.Value) (T, error) {
	if result, ok := input.(T); ok {
		return result, nil
	}
	var result T
	err := generatedDecode(input, &result)
	return result, err
}

func generatedCall[T any](runtime *render.RuntimeBindings, name string, args []value.Value, frame *render.Frame, span ast.Span) T {
	result, err := runtime.Call(name, args, frame, span)
	generatedPanic(err)
	return generatedResult[T](result)
}

func generatedEscape(runtime *render.RuntimeBindings, input any, frame *render.Frame, span ast.Span) string {
	result, err := runtime.Escape(generatedValue(input), frame, span)
	generatedPanic(err)
	return result
}

func generatedWrite(context *render.Context, text string, frame *render.Frame, span ast.Span) {
	generatedPanic(context.Write(text, frame, &span))
}

func generatedEnter(context *render.Context, name string, frame *render.Frame, span ast.Span) {
	generatedPanic(context.Enter(name, frame, &span))
}

func generatedPlain(input any) any {
	switch item := input.(type) {
	case *value.OrderedMap:
		result := map[string]any{}
		for _, key := range item.Keys() {
			entry, _ := item.Get(key)
			result[key] = generatedPlain(entry)
		}
		return result
	case value.List:
		result := make([]any, len(item))
		for index, entry := range item {
			result[index] = generatedPlain(entry)
		}
		return result
	default:
		return input
	}
}

type generatedType struct {
	Kind     string
	Optional bool
	Name     string
	Item     *generatedType
	Key      *generatedType
	Value    *generatedType
}

type generatedField struct {
	Name string
	Type generatedType
}

func generatedCheck(input value.Value, kind generatedType, records map[string][]generatedField, path string) error {
	if input == nil {
		if kind.Optional || kind.Kind == "any" {
			return nil
		}
		return fmt.Errorf("%s is required", path)
	}
	actual := value.TypeOf(input)
	switch kind.Kind {
	case "any":
		return nil
	case "string":
		if actual != value.TypeString {
			return fmt.Errorf("%s is not a string", path)
		}
	case "number":
		if actual != value.TypeNumber {
			return fmt.Errorf("%s is not a number", path)
		}
	case "boolean":
		if actual != value.TypeBool {
			return fmt.Errorf("%s is not a boolean", path)
		}
	case "list":
		items, ok := input.(value.List)
		if !ok {
			return fmt.Errorf("%s is not a list", path)
		}
		for index, item := range items {
			if err := generatedCheck(item, *kind.Item, records, fmt.Sprintf("%s[%d]", path, index)); err != nil {
				return err
			}
		}
	case "map":
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		for _, key := range entries.Keys() {
			item, _ := entries.Get(key)
			if err := generatedCheck(item, *kind.Value, records, path+"."+key); err != nil {
				return err
			}
		}
	default:
		entries, ok := input.(*value.OrderedMap)
		if !ok {
			return fmt.Errorf("%s is not an object", path)
		}
		return generatedCheckFields(entries, records[kind.Name], records, path)
	}
	return nil
}

func generatedCheckFields(input *value.OrderedMap, fields []generatedField, records map[string][]generatedField, path string) error {
	for _, field := range fields {
		item, _ := input.Get(field.Name)
		if err := generatedCheck(item, field.Type, records, path+"."+field.Name); err != nil {
			return err
		}
	}
	return nil
}

func generatedDecode(input any, output any) error {
	data, err := json.Marshal(generatedPlain(input))
	if err != nil {
		return err
	}
	return json.Unmarshal(data, output)
}

func generatedEnv(options template.RenderOptions) functions.Env {
	env := functions.Env{Timezone: "Z", Now: float64(time.Now().Unix())}
	if options.Env != nil {
		if options.Env.Timezone != "" {
			env.Timezone = options.Env.Timezone
		}
		env.Now = options.Env.Now
	}
	return env
}

func render_content_tpl(assign Assign, definitions *Definitions, input Input_content_tpl, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	frame := render.NewFrame("content.tpl", errs.LineIndex{0, 10, 29, 64, 105, 164, 175}, rootData)
	scope.Locals["title"] = generatedValue(input.Title)
	scope.Locals["root_label"] = generatedValue(input.Root_label)
	scope.Locals["defined_label"] = generatedValue(input.Defined_label)
	scope.Locals["layout_local"] = generatedValue(input.Layout_local)
	generatedWrite(context, "<article>\u000a<h1>", frame, ast.Span{0, 14})
	generatedWrite(context, generatedEscape(runtime, input.Title, frame, ast.Span{17, 22}), frame, ast.Span{14, 23})
	generatedWrite(context, "</h1>\u000a<p class=\"root\">", frame, ast.Span{23, 45})
	generatedWrite(context, generatedEscape(runtime, input.Root_label, frame, ast.Span{48, 58}), frame, ast.Span{45, 59})
	generatedWrite(context, "</p>\u000a<p class=\"defined\">", frame, ast.Span{59, 83})
	generatedWrite(context, generatedEscape(runtime, input.Defined_label, frame, ast.Span{86, 99}), frame, ast.Span{83, 100})
	generatedWrite(context, "</p>\u000a<p class=\"local\">", frame, ast.Span{100, 122})
	generatedWrite(context, generatedEscape(runtime, generatedCall[string](runtime, "default", []value.Value{generatedValue(input.Layout_local), generatedValue("missing")}, frame, ast.Span{125, 158}), frame, ast.Span{125, 158}), frame, ast.Span{122, 159})
	generatedWrite(context, "</p>\u000a</article>\u000a", frame, ast.Span{159, 175})
}

func render_layout_tpl(assign Assign, definitions *Definitions, input Input_layout_tpl, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	frame := render.NewFrame("layout.tpl", errs.LineIndex{0, 44, 68, 97, 108}, rootData)
	var local_layout_local_1 string = "visible only in layout"
	scope.Locals["layout_local"] = generatedValue(local_layout_local_1)
	generatedWrite(context, "<section class=\"scope\">\u000a", frame, ast.Span{44, 68})
	{
		definition := definitions.Content
		if definition == nil {
			panic(runtime.Error(frame, ast.Span{68, 96}, errs.RuntimeBlockUndefined, "define content is not registered"))
		}
		if definition != nil && definition.HTML != nil {
			generatedWrite(context, *definition.HTML, frame, ast.Span{68, 96})
		} else {
			input := Input_content_tpl{Root_label: assign.Root_label, Defined_label: assign.Defined_label}
			if definition != nil && definition.Data != nil {
				if definition.Data.Title != nil {
					input.Title = *definition.Data.Title
				}
				if definition.Data.Root_label != nil {
					input.Root_label = *definition.Data.Root_label
				}
				if definition.Data.Defined_label != nil {
					input.Defined_label = *definition.Data.Defined_label
				}
				if definition.Data.Layout_local != nil {
					input.Layout_local = *definition.Data.Layout_local
				}
			}
			input.Title = assign.Page.Title
			blockScope := render.NewScope()
			generatedEnter(context, "content.tpl", frame, ast.Span{68, 96})
			func() {
				defer context.Leave()
				render_content_tpl(assign, definitions, input, context, runtime, rootData, blockScope)
			}()
		}
	}
	generatedWrite(context, "</section>\u000a", frame, ast.Span{97, 108})
}

func renderTemplate(target string, assign Assign, definitions *Definitions, context *render.Context, runtime *render.RuntimeBindings, rootData *value.OrderedMap, scope *render.Scope) {
	switch target {
	case "layout.tpl":
		render_layout_tpl(assign, definitions, Input_layout_tpl{}, context, runtime, rootData, scope)
		return
	default:
		panic(context.Fail(errs.LoadNotFound, nil, nil, "template "+target+" does not exist"))
	}
}

type generatedTarget struct {
	target string
	html   *string
}

func generatedBindDefinitions(input map[string]template.DefineInput) (*Definitions, map[string]generatedTarget, error) {
	definitions := &Definitions{}
	targets := map[string]generatedTarget{}
	for id, input := range input {
		if !utf8.ValidString(id) {
			return nil, nil, &value.BindError{Code: errs.DataInvalidUTF8, Message: "a define id is not valid UTF-8"}
		}
		switch id {
		case "content":
			if input.HTML != nil {
				if input.Template != "" || input.Data != nil {
					return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
				}
				definitions.Content = &Definition[DefinitionData_content_tpl]{HTML: input.HTML}
				targets[id] = generatedTarget{html: input.HTML}
				continue
			}
			if input.Template != "content.tpl" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[DefinitionData_content_tpl]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				data, ok := bound.(*value.OrderedMap)
				if !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := DefinitionData_content_tpl{}
				if raw, found := data.Get("title"); found {
					if err := generatedCheck(raw, generatedType{Kind: "string"}, generatedRecordFields, "define."+id+".data."+"title"); err != nil {
						return nil, nil, err
					}
					converted, err := generatedAs[string](raw)
					if err != nil {
						return nil, nil, fmt.Errorf("define.%s.data.%s: %w", id, "title", err)
					}
					definitionData.Title = &converted
				}
				if raw, found := data.Get("root_label"); found {
					if err := generatedCheck(raw, generatedType{Kind: "string"}, generatedRecordFields, "define."+id+".data."+"root_label"); err != nil {
						return nil, nil, err
					}
					converted, err := generatedAs[string](raw)
					if err != nil {
						return nil, nil, fmt.Errorf("define.%s.data.%s: %w", id, "root_label", err)
					}
					definitionData.Root_label = &converted
				}
				if raw, found := data.Get("defined_label"); found {
					if err := generatedCheck(raw, generatedType{Kind: "string"}, generatedRecordFields, "define."+id+".data."+"defined_label"); err != nil {
						return nil, nil, err
					}
					converted, err := generatedAs[string](raw)
					if err != nil {
						return nil, nil, fmt.Errorf("define.%s.data.%s: %w", id, "defined_label", err)
					}
					definitionData.Defined_label = &converted
				}
				if raw, found := data.Get("layout_local"); found {
					if err := generatedCheck(raw, generatedType{Kind: "string", Optional: true}, generatedRecordFields, "define."+id+".data."+"layout_local"); err != nil {
						return nil, nil, err
					}
					converted, err := generatedAs[*string](raw)
					if err != nil {
						return nil, nil, fmt.Errorf("define.%s.data.%s: %w", id, "layout_local", err)
					}
					definitionData.Layout_local = &converted
				}
				entry.Data = &definitionData
			}
			definitions.Content = entry
			targets[id] = generatedTarget{target: "content.tpl"}
		case "layout":
			if input.HTML != nil {
				return nil, nil, fmt.Errorf("define.%s has an invalid html entry", id)
			}
			if input.Template != "layout.tpl" {
				return nil, nil, fmt.Errorf("define.%s has an invalid template", id)
			}
			entry := &Definition[DefinitionData_layout_tpl]{Template: input.Template}
			if input.Data != nil {
				bound, err := value.BindData(input.Data)
				if err != nil {
					return nil, nil, err
				}
				if _, ok := bound.(*value.OrderedMap); !ok {
					return nil, nil, fmt.Errorf("define.%s.data is not an object", id)
				}
				definitionData := DefinitionData_layout_tpl{}
				entry.Data = &definitionData
			}
			definitions.Layout = entry
			targets[id] = generatedTarget{target: "layout.tpl"}
		default:
			return nil, nil, fmt.Errorf("define.%s is not declared", id)
		}
	}
	return definitions, targets, nil
}

type GeneratedProgram struct {
	Runtime *template.RuntimeEnvironment
}

func NewGeneratedProgram(options template.Options) (*GeneratedProgram, error) {
	runtime, err := template.NewRuntimeEnvironment(options.Limits, options.Functions)
	if err != nil {
		return nil, err
	}
	return &GeneratedProgram{Runtime: runtime}, nil
}

type generatedPrepared struct {
	name        string
	target      string
	assign      Assign
	definitions *Definitions
	rootData    *value.OrderedMap
	env         functions.Env
	runtime     *template.RuntimeEnvironment
	html        *string
}

func (p *generatedPrepared) Render() (string, error) {
	return render.Guard(p.name, p.render)
}

func (p *generatedPrepared) render() (string, error) {
	context := render.NewContext(p.runtime, p.rootData, p.env, p.target)
	runtime := render.NewRuntimeBindings(context)
	scope := render.NewScope()
	if err := context.Enter(p.target, nil, nil); err != nil {
		return "", err
	}
	defer context.Leave()
	if p.html != nil {
		if err := context.Write(*p.html, nil, nil); err != nil {
			return "", err
		}
	} else {
		renderTemplate(p.target, p.assign, p.definitions, context, runtime, p.rootData, scope)
	}
	return context.Output(), nil
}

func (p *GeneratedProgram) Prepare(target any, assign any, options template.RenderOptions) (template.Prepared, error) {
	name, ok := target.(string)
	if !ok {
		return nil, fmt.Errorf("generated target must be a template name")
	}
	return render.Guard(name, func() (template.Prepared, error) {
		return p.prepare(name, assign, options)
	})
}

func generatedBindFailure(name string, err error) error {
	var bindError *value.BindError
	if errors.As(err, &bindError) {
		return errs.WithoutPosition(bindError.Code, name, bindError.Message)
	}
	return err
}

func (p *GeneratedProgram) prepare(name string, assign any, options template.RenderOptions) (template.Prepared, error) {
	rootData, err := value.BindMap(assign)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	var typedAssign Assign
	if err := generatedCheckFields(rootData, []generatedField{{Name: "page", Type: generatedType{Kind: "record", Name: "Page"}}, {Name: "root_label", Type: generatedType{Kind: "string"}}, {Name: "defined_label", Type: generatedType{Kind: "string"}}}, generatedRecordFields, "assign"); err != nil {
		return nil, err
	}
	if err := generatedDecode(rootData, &typedAssign); err != nil {
		return nil, err
	}
	definitions, targets, err := generatedBindDefinitions(options.Define)
	if err != nil {
		return nil, generatedBindFailure(name, err)
	}
	resolved := targets[name]
	targetName := name
	if resolved.target != "" {
		targetName = resolved.target
	}
	return &generatedPrepared{name: name, target: targetName, assign: typedAssign, definitions: definitions, rootData: rootData, env: generatedEnv(options), runtime: p.Runtime, html: resolved.html}, nil
}

func (p *GeneratedProgram) Render(target any, assign any, options template.RenderOptions) (string, error) {
	prepared, err := p.Prepare(target, assign, options)
	if err != nil {
		return "", err
	}
	return prepared.Render()
}

var _ template.Program = (*GeneratedProgram)(nil)


rust · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "rust",
  "entry": "layout.tpl",
  "sourceDigest": "112ab94718df18ed706f433c92ce33f65c71045800866aabe4fc052142d97028",
  "typeDigest": "3fec0fc166342c701a26f62cb935ae5fbb99d9f610b9fcefb50d105b79d59014",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "88d74f055ec030758070b516d0cd35473b90e243ae8571128c3187ba0162631f",
  "files": {
    "scope-precedence.rust": {
      "path": "scope-precedence.rust",
      "artifactDigest": "737850319f43527240e008fd5f6c62166573c36794a839eeaa6091b8b7d32c67"
    }
  }
}

// Generated.
use polyspec_template::{ArgumentError, ErrorCode, OrderedMap as RuntimeOrderedMap, PreparedRender, Program, RenderOptions, RenderTarget, RequestError, RuntimeEnvironment, TemplateError, Value, internal_boundary};
use polyspec_template::error::LineIndex;
use polyspec_template::render::context::{Frame, RenderContext, Scope};
use polyspec_template::render::runtime_bindings::RuntimeBindings;
use serde_json::Value as JsonValue;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Clone, Default)] pub struct Assign {
    pub page: Page,
    pub root_label: String,
    pub defined_label: String,
}
impl GeneratedConvert for Assign { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; let _ = (&map, path); let page = generated_field(map, path, "page")?; let root_label = generated_field(map, path, "root_label")?; let defined_label = generated_field(map, path, "defined_label")?; Ok(Assign { page, root_label, defined_label }) } fn to_value(&self) -> Value { let mut map = RuntimeOrderedMap::new(); map.insert("page".to_string(), self.page.to_value()); map.insert("root_label".to_string(), self.root_label.to_value()); map.insert("defined_label".to_string(), self.defined_label.to_value()); Value::map(map) } }
#[derive(Clone, Default)] pub struct InputContentTpl { pub title: String, pub root_label: String, pub defined_label: String, pub layout_local: Option<String> }
#[derive(Clone, Default)] pub struct InputLayoutTpl {  }
#[derive(Clone, Default)] pub struct DefinitionDataContentTpl { pub title: Option<String>, pub root_label: Option<String>, pub defined_label: Option<String>, pub layout_local: Option<Option<String>> }
#[derive(Clone, Default)] pub struct DefinitionDataLayoutTpl {  }
#[derive(Clone, Default)] pub struct Definition<T> { pub html: Option<String>, pub data: Option<T> }
#[derive(Clone, Default)] pub struct Definitions { pub content: Option<Definition<DefinitionDataContentTpl>>, pub layout: Option<Definition<DefinitionDataLayoutTpl>> }
#[derive(Clone, Default)] pub struct Page { pub title: String }
impl GeneratedConvert for Page { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let Value::Map(map) = input else { return Err(generated_type_error(input, path, "an object")); }; let _ = (&map, path); let title = generated_field(map, path, "title")?; Ok(Page { title }) } fn to_value(&self) -> Value { let mut map = RuntimeOrderedMap::new(); map.insert("title".to_string(), self.title.to_value()); Value::map(map) } }
fn generated_conversion_error(message: impl Into<String>) -> TemplateError { TemplateError::without_position(ErrorCode::E_RUNTIME_TYPE, "generated", message) }
pub trait GeneratedConvert: Sized { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError>; fn to_value(&self) -> Value; }
impl GeneratedConvert for Value { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { let _ = path; Ok(input.clone()) } fn to_value(&self) -> Value { self.clone() } }
impl GeneratedConvert for String { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { input.as_text().map(str::to_string).ok_or_else(|| generated_type_error(input, path, "a string")) } fn to_value(&self) -> Value { Value::text(self.clone()) } }
impl GeneratedConvert for f64 { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Number(number) => Ok(*number), _ => Err(generated_type_error(input, path, "a number")) } } fn to_value(&self) -> Value { Value::Number(*self) } }
impl GeneratedConvert for bool { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Bool(value) => Ok(*value), _ => Err(generated_type_error(input, path, "a boolean")) } } fn to_value(&self) -> Value { Value::Bool(*self) } }
impl<T: GeneratedConvert> GeneratedConvert for Option<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::Null => Ok(None), other => T::from_value(other, path).map(Some) } } fn to_value(&self) -> Value { self.as_ref().map_or(Value::Null, T::to_value) } }
impl<T: GeneratedConvert> GeneratedConvert for Vec<T> { fn from_value(input: &Value, path: &str) -> Result<Self, TemplateError> { match input { Value::List(items) => items.iter().enumerate().map(|(index, item)| T::from_value(item, &format!("{path}[{index}]"))).collect(), _ => Err(generated_type_error(input, path, "a list")) } } fn to_value(&self) -> Value { Value::list(self.iter().map(T::to_value).collect()) } }
fn generated_type_error(input: &Value, path: &str, expected: &str) -> TemplateError { generated_conversion_error(if matches!(input, Value::Null) { format!("{path} is required") } else { format!("{path} is not {expected}") }) }
fn generated_field<T: GeneratedConvert>(map: &RuntimeOrderedMap, path: &str, name: &str) -> Result<T, TemplateError> { T::from_value(map.get(name).unwrap_or(&Value::Null), &format!("{path}.{name}")) }
fn generated_value<T: GeneratedConvert>(input: &T) -> Result<Value, TemplateError> { Ok(input.to_value()) }
fn generated_result<T: GeneratedConvert>(input: &Value, path: &str) -> Result<T, TemplateError> { T::from_value(input, path) }
fn render_content_tpl(assign: &Assign, definitions: &mut Definitions, input: InputContentTpl, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { let _ = (&assign, &definitions, &input, &runtime, &scope); let frame = Frame { name: "content.tpl".to_string(), lines: Some(LineIndex::from_starts(vec![0, 10, 29, 64, 105, 164, 175])), context: Rc::clone(root_data) };
scope.locals.insert("title".to_string(), generated_value(&input.title)?);
scope.locals.insert("root_label".to_string(), generated_value(&input.root_label)?);
scope.locals.insert("defined_label".to_string(), generated_value(&input.defined_label)?);
scope.locals.insert("layout_local".to_string(), generated_value(&input.layout_local)?);
    context.write("<article>\u{a}<h1>", &frame, [0, 14])?;
    let escaped = runtime.escape(context, &scope.lookup(&frame, "title"), &frame, [17, 22])?; context.write(&escaped, &frame, [14, 23])?;
    context.write("</h1>\u{a}<p class=\"root\">", &frame, [23, 45])?;
    let escaped = runtime.escape(context, &scope.lookup(&frame, "root_label"), &frame, [48, 58])?; context.write(&escaped, &frame, [45, 59])?;
    context.write("</p>\u{a}<p class=\"defined\">", &frame, [59, 83])?;
    let escaped = runtime.escape(context, &scope.lookup(&frame, "defined_label"), &frame, [86, 99])?; context.write(&escaped, &frame, [83, 100])?;
    context.write("</p>\u{a}<p class=\"local\">", &frame, [100, 122])?;
    let escaped = runtime.escape(context, &runtime.call(context, "default", vec![scope.lookup(&frame, "layout_local"), Value::text("missing")], &frame, [125, 158])?, &frame, [125, 158])?; context.write(&escaped, &frame, [122, 159])?;
    context.write("</p>\u{a}</article>\u{a}", &frame, [159, 175])?;
 Ok(()) }
fn render_layout_tpl(assign: &Assign, definitions: &mut Definitions, input: InputLayoutTpl, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { let _ = (&assign, &definitions, &input, &runtime, &scope); let frame = Frame { name: "layout.tpl".to_string(), lines: Some(LineIndex::from_starts(vec![0, 44, 68, 97, 108])), context: Rc::clone(root_data) };

    scope.locals.insert("layout_local".to_string(), Value::text("visible only in layout"));
    context.write("<section class=\"scope\">\u{a}", &frame, [44, 68])?;
    { if definitions.content.is_none() { return Err(runtime.error(context, &frame, [68, 96], ErrorCode::E_RUNTIME_BLOCK_UNDEFINED, "define content is not registered")); }
    let definition = definitions.content.clone();
    if let Some(html) = definition.as_ref().and_then(|value| value.html.as_ref()) { context.write(html, &frame, [68, 96])?; } else {
        let mut input = InputContentTpl { root_label: generated_result::<String>(&generated_value(&assign.root_label)?, "root_label")?, defined_label: generated_result::<String>(&generated_value(&assign.defined_label)?, "defined_label")?, ..Default::default() };
        if let Some(data) = definition.as_ref().and_then(|value| value.data.as_ref()) && let Some(value) = data.title.clone() { input.title = value; }
        if let Some(data) = definition.as_ref().and_then(|value| value.data.as_ref()) && let Some(value) = data.root_label.clone() { input.root_label = value; }
        if let Some(data) = definition.as_ref().and_then(|value| value.data.as_ref()) && let Some(value) = data.defined_label.clone() { input.defined_label = value; }
        if let Some(data) = definition.as_ref().and_then(|value| value.data.as_ref()) && let Some(value) = data.layout_local.clone() { input.layout_local = value; }
        input.title = generated_result::<String>(&runtime.member(context, &generated_value(&assign.page)?, "title", &frame, [85, 95])?, "title")?;
        let mut block_scope = Scope::default();
        context.enter("content.tpl", Some(&frame), Some([68, 96]))?;
        let rendered = render_content_tpl(assign, definitions, input, context, runtime, root_data, &mut block_scope);
        context.leave();
        rendered?;
    }
    }
    context.write("</section>\u{a}", &frame, [97, 108])?;
 Ok(()) }
fn render_template(target: &str, assign: &Assign, definitions: &mut Definitions, context: &mut RenderContext<'_>, runtime: &RuntimeBindings, root_data: &Rc<RuntimeOrderedMap>, scope: &mut Scope) -> Result<(), TemplateError> { match target {
        "layout.tpl" => render_layout_tpl(assign, definitions, InputLayoutTpl::default(), context, runtime, root_data, scope),
        _ => Err(context.fail(ErrorCode::E_LOAD_NOT_FOUND, None, None, format!("template {target} does not exist"))),
} }
fn generated_error(message: String) -> RequestError { RequestError::Argument(ArgumentError { message }) }
struct GeneratedTarget { target: Option<String>, html: Option<String> }
fn generated_bind_definitions(name: &str, input: &HashMap<String, polyspec_template::DefineInput>) -> Result<(Definitions, HashMap<String, GeneratedTarget>), RequestError> { let mut definitions = Definitions::default(); let mut targets = HashMap::new(); for (id, input) in input { match id.as_str() {
            "content" => { if let Some(html) = &input.html { if false || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.content = Some(Definition { html: Some(html.clone()), ..Default::default() }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("content.tpl") { return Err(generated_error(format!("define.{id} has an invalid template"))); }
let data = match &input.data { None => None, Some(data) => match polyspec_template::bind_data(data).map_err(|error| TemplateError::without_position(error.code, name, error.message))? { Value::Map(map) => { let _ = &map; Some(DefinitionDataContentTpl { title: map.get("title").map(|value| GeneratedConvert::from_value(value, &format!("define.{id}.data.title"))).transpose().map_err(|error| generated_error(error.message))?, root_label: map.get("root_label").map(|value| GeneratedConvert::from_value(value, &format!("define.{id}.data.root_label"))).transpose().map_err(|error| generated_error(error.message))?, defined_label: map.get("defined_label").map(|value| GeneratedConvert::from_value(value, &format!("define.{id}.data.defined_label"))).transpose().map_err(|error| generated_error(error.message))?, layout_local: map.get("layout_local").map(|value| GeneratedConvert::from_value(value, &format!("define.{id}.data.layout_local"))).transpose().map_err(|error| generated_error(error.message))? }) }, _ => return Err(generated_error(format!("define.{id}.data is not an object"))) } };
definitions.content = Some(Definition { data, ..Default::default() }); targets.insert(id.clone(), GeneratedTarget { target: Some("content.tpl".to_string()), html: None }); } },
            "layout" => { if let Some(html) = &input.html { if true || input.template.is_some() || input.data.is_some() { return Err(generated_error(format!("define.{id} has an invalid html entry"))); } definitions.layout = Some(Definition { html: Some(html.clone()), ..Default::default() }); targets.insert(id.clone(), GeneratedTarget { target: None, html: Some(html.clone()) }); } else { if input.template.as_deref() != Some("layout.tpl") { return Err(generated_error(format!("define.{id} has an invalid template"))); }
let data = match &input.data { None => None, Some(data) => match polyspec_template::bind_data(data).map_err(|error| TemplateError::without_position(error.code, name, error.message))? { Value::Map(map) => { let _ = &map; Some(DefinitionDataLayoutTpl {  }) }, _ => return Err(generated_error(format!("define.{id}.data is not an object"))) } };
definitions.layout = Some(Definition { data, ..Default::default() }); targets.insert(id.clone(), GeneratedTarget { target: Some("layout.tpl".to_string()), html: None }); } },
            _ => return Err(generated_error(format!("define.{id} is not declared"))),
        } } Ok((definitions, targets)) }
pub struct GeneratedProgram { pub runtime: RuntimeEnvironment }
impl GeneratedProgram { pub fn new(runtime: RuntimeEnvironment) -> GeneratedProgram { GeneratedProgram { runtime } }  }
impl Program for GeneratedProgram { fn prepare(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || { let root_data = Rc::new(polyspec_template::value::bind::bind_map(assign).map_err(|error| TemplateError::without_position(error.code, name, error.message))?); self.prepare_root(name, root_data, options) }) } fn render(&self, target: RenderTarget<'_>, assign: &JsonValue, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare(target, assign, options)?.render()?) } fn prepare_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<PreparedRender<'_>, RequestError> { let RenderTarget::Name(name) = target else { return Err(generated_error("generated target must be a template name".to_string())); }; internal_boundary(name, || self.prepare_root(name, polyspec_template::bound_root(assign), options)) } fn render_bound(&self, target: RenderTarget<'_>, assign: &polyspec_template::BoundMap, options: &RenderOptions) -> Result<String, RequestError> { Ok(self.prepare_bound(target, assign, options)?.render()?) } }
impl GeneratedProgram { fn prepare_root<'e>(&'e self, name: &str, root_data: Rc<RuntimeOrderedMap>, options: &RenderOptions) -> Result<PreparedRender<'e>, RequestError> { let typed_assign: Assign = Assign::from_value(&Value::Map(Rc::clone(&root_data)), "assign").map_err(|error| generated_error(error.message))?; let (definitions, targets) = generated_bind_definitions(name, &options.define)?; let resolved = targets.get(name); let target_name = resolved.and_then(|value| value.target.clone()).unwrap_or_else(|| name.to_string()); let html = resolved.and_then(|value| value.html.clone()); let env = options.env.clone().unwrap_or_else(|| polyspec_template::Env { timezone: "Z".to_string(), now: std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|duration| duration.as_secs() as f64).unwrap_or(0.0) }); Ok(PreparedRender::new(name, move || { let mut context = RenderContext::new(&self.runtime, Rc::clone(&root_data), env.clone(), &target_name); let runtime = RuntimeBindings::new(); let mut scope = Scope::default(); let mut render_definitions = definitions.clone(); context.enter(&target_name, None, None)?; let result = if let Some(html) = &html { let frame = Frame { name: target_name.clone(), lines: None, context: Rc::clone(&root_data) }; context.write(html, &frame, [0, 0]) } else { render_template(&target_name, &typed_assign, &mut render_definitions, &mut context, &runtime, &root_data, &mut scope) }; context.leave(); result?; Ok(context.output) })) } }


php · product generated program
{
  "schema": 3,
  "mode": "gen",
  "target": "php",
  "entry": "layout.tpl",
  "sourceDigest": "112ab94718df18ed706f433c92ce33f65c71045800866aabe4fc052142d97028",
  "typeDigest": "3fec0fc166342c701a26f62cb935ae5fbb99d9f610b9fcefb50d105b79d59014",
  "contractDigest": "b3a300448cfa0263a9e4fb6888adb359317b6f8e0e9e7f40edc29e8c8671bf2d",
  "compilerDigest": "ba7f0bfd4d8024e26cbef4e9ddf0cd1e011489480f00daebb75a11ecfa8e218f",
  "files": {
    "Page.php": {
      "path": "Page.php",
      "artifactDigest": "b74a64385368068ae4eff959d5cb14c237e72166308d66dae0ddce028edaebb2"
    },
    "Assign.php": {
      "path": "Assign.php",
      "artifactDigest": "b0e4413b0d3be056e19dd2d5c914ece84f0339ad7590a2cd63c7160daa45a246"
    },
    "InputContentTpl.php": {
      "path": "InputContentTpl.php",
      "artifactDigest": "83e6727dd9c8ec97e454e7b90018d8a302f36c7220eed52951bc75d6452bd209"
    },
    "InputLayoutTpl.php": {
      "path": "InputLayoutTpl.php",
      "artifactDigest": "79e4964e3b80b00ae36d281da2106949431465862ea3ccecacddd8495c33ebda"
    },
    "DefinitionDataContentTpl.php": {
      "path": "DefinitionDataContentTpl.php",
      "artifactDigest": "007f373121b52b056610c423738120f328008978a2db9ab79c99332db1b07756"
    },
    "DefinitionDataLayoutTpl.php": {
      "path": "DefinitionDataLayoutTpl.php",
      "artifactDigest": "249cf2081e72236926cf75dd16e786ab359d8b50f884ab5a58f0d784d1dea4e6"
    },
    "Definition.php": {
      "path": "Definition.php",
      "artifactDigest": "f8af91f48a9173ad58775e2e26aa7632f9340bfc8953c18ca921f374259c617e"
    },
    "Definitions.php": {
      "path": "Definitions.php",
      "artifactDigest": "d474ff0a142bf279f94069ed4716a0c8d394204d3ae8ae86cbc3e8399327ae63"
    },
    "ArtifactManifest.php": {
      "path": "ArtifactManifest.php",
      "artifactDigest": "665cbba9f9afc5805374e5cf203033449fb50e5a3f1fe8c404f72eeda0881795"
    },
    "GeneratedRuntime.php": {
      "path": "GeneratedRuntime.php",
      "artifactDigest": "ba4ca2a90aa8daa7d2c0fba6b4c3282350f4e8c075bae07b49ea4116b179e0a4"
    },
    "GeneratedTemplates.php": {
      "path": "GeneratedTemplates.php",
      "artifactDigest": "62d9ae34e8e38f30573bd842d2717cba507a19e6223df4bfc6dc43e0e3c84eba"
    },
    "GeneratedExecution.php": {
      "path": "GeneratedExecution.php",
      "artifactDigest": "dd5b697c02acd7c5035bd39aee273698f379cef83c186fe8d4f1fb165387e8fe"
    },
    "GeneratedProgram.php": {
      "path": "GeneratedProgram.php",
      "artifactDigest": "54f92593a57e937528c9645e965ceb8d5cf1312ed816f680736c306d575fa291"
    }
  }
}

<?php

declare(strict_types=1);

namespace Polyspec\Showcase\Generated\ScopePrecedence;

use Polyspec\Template\Render\Context;
use Polyspec\Template\Render\Frame;
use Polyspec\Template\Render\RuntimeBindings;
use Polyspec\Template\Render\Scope;
use Polyspec\Template\Value\MapValue;

final class GeneratedTemplates
{
    public static function render(
        string $target,
        Assign $assign,
        Definitions $definitions,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        switch ($target) {
            case 'layout.tpl':
                self::renderLayoutTpl(
                    $assign,
                    $definitions,
                    new InputLayoutTpl(),
                    $context,
                    $runtime,
                    $rootData,
                    $scope,
                );
                return;
            default:
                throw $context->fail('E_LOAD_NOT_FOUND', null, null, 'template ' . $target . ' does not exist');
        }
    }

    private static function renderContentTpl(
        Assign $assign,
        Definitions $definitions,
        InputContentTpl $input,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        $frame = new Frame('content.tpl', [0, 10, 29, 64, 105, 164, 175], $rootData);
        $scope->locals->set('title', $input->title);
        $scope->locals->set('root_label', $input->root_label);
        $scope->locals->set('defined_label', $input->defined_label);
        $scope->locals->set('layout_local', $input->layout_local);
        $context->at($frame, [0, 14]);
        $context->write(('<article>' . "\n" . '<h1>'));
        $context->at($frame, [14, 23]);
        $context->write($runtime->escape($scope->lookup($frame, 'title'), $frame, [17, 22]));
        $context->at($frame, [23, 45]);
        $context->write(('</h1>' . "\n" . '<p class="root">'));
        $context->at($frame, [45, 59]);
        $context->write($runtime->escape($scope->lookup($frame, 'root_label'), $frame, [48, 58]));
        $context->at($frame, [59, 83]);
        $context->write(('</p>' . "\n" . '<p class="defined">'));
        $context->at($frame, [83, 100]);
        $context->write($runtime->escape($scope->lookup($frame, 'defined_label'), $frame, [86, 99]));
        $context->at($frame, [100, 122]);
        $context->write(('</p>' . "\n" . '<p class="local">'));
        $context->at($frame, [122, 159]);
        $context->write(
            $runtime->escape(
                $runtime->call('default', [$scope->lookup($frame, 'layout_local'), 'missing'], $frame, [125, 158]),
                $frame,
                [125, 158],
            ),
        );
        $context->at($frame, [159, 175]);
        $context->write(('</p>' . "\n" . '</article>' . "\n"));
    }

    private static function renderLayoutTpl(
        Assign $assign,
        Definitions $definitions,
        InputLayoutTpl $input,
        Context $context,
        RuntimeBindings $runtime,
        MapValue $rootData,
        Scope $scope,
    ): void {
        $frame = new Frame('layout.tpl', [0, 44, 68, 97, 108], $rootData);
        $scope->locals->set('layout_local', 'visible only in layout');
        $context->at($frame, [44, 68]);
        $context->write(('<section class="scope">' . "\n"));
        $definition = $definitions->content;
        if ($definition === null) {
            throw $runtime->error($frame, [68, 96], 'E_RUNTIME_BLOCK_UNDEFINED', 'define content is not registered');
        }
        if ($definition?->html !== null) {
            $context->at($frame, [68, 96]);
            $context->write($definition->html);
        } else {
            if ($definition?->data !== null && !($definition->data instanceof DefinitionDataContentTpl)) {
                throw $runtime->error(
                    $frame,
                    [68, 96],
                    'E_RUNTIME_TYPE',
                    'generated definition content data has an invalid type',
                );
            }
            $scoped_title = $assign->page?->title;
            $input = new InputContentTpl(
                title: $scoped_title,
                root_label: $assign->root_label,
                defined_label: $assign->defined_label,
                layout_local: null,
            );
            if ($definition?->data !== null) {
                if ($definition->data->has_title) {
                    $input->title = $definition->data->title;
                }
                if ($definition->data->has_root_label) {
                    $input->root_label = $definition->data->root_label;
                }
                if ($definition->data->has_defined_label) {
                    $input->defined_label = $definition->data->defined_label;
                }
                if ($definition->data->has_layout_local) {
                    $input->layout_local = $definition->data->layout_local;
                }
            }
            $input->title = $scoped_title;
            $blockScope = new Scope();
            $context->enter('content.tpl', $frame, [68, 96]);
            try {
                self::renderContentTpl($assign, $definitions, $input, $context, $runtime, $rootData, $blockScope);
            } finally {
                $context->leave();
            }
        }
        $context->at($frame, [97, 108]);
        $context->write(('</section>' . "\n"));
    }
}

Output · 177 bytes · 7b160d439d3d…

<section class="scope">
<article>
<h1>from assign</h1>
<p class="root">root assign</p>
<p class="defined">definition data</p>
<p class="local">missing</p>
</article>
</section>
Implementationtsgorustphppython
artifact renderPASSPASSPASSPASSPASS

04 · PERFORMANCE

Same request, two execution modes

Independent samples use production artifacts with the page cache disabled. Cold includes process startup and loading. Full render includes request binding; prepared render reuses one normalized request. Every row must match the same UTF-8 bytes before it is recorded.

LanguageModeCold medianFull renderPrepared renderRSS medianBytesOutput
typescriptast137.41 ms0.0080 ms0.0020 ms94.25 MiB1777b160d439d3d…
typescriptgenerated131.65 ms0.0073 ms0.0010 ms92.97 MiB1777b160d439d3d…
goast7.11 ms0.0030 ms0.0016 ms11.34 MiB1777b160d439d3d…
gogenerated8.60 ms0.0038 ms0.0008 ms10.70 MiB1777b160d439d3d…
rustast9.64 ms0.0051 ms0.0024 ms2.80 MiB1777b160d439d3d…
rustgenerated5.81 ms0.0043 ms0.0017 ms2.53 MiB1777b160d439d3d…
phpast70.12 ms0.0178 ms0.0106 ms28.08 MiB1777b160d439d3d…
phpgenerated81.61 ms0.0130 ms0.0045 ms28.22 MiB1777b160d439d3d…
Package throughput samples
FixtureImplementationIterationsOutput
empty-statets20d98cc268d4c4…
empty-statego20d98cc268d4c4…
empty-staterust20d98cc268d4c4…
empty-statephp20d98cc268d4c4…
empty-statets20d98cc268d4c4…
empty-statego20d98cc268d4c4…
empty-staterust20d98cc268d4c4…
empty-statephp20d98cc268d4c4…
empty-statets20d98cc268d4c4…
empty-statego20d98cc268d4c4…
empty-staterust20d98cc268d4c4…
empty-statephp20d98cc268d4c4…
empty-statets20d98cc268d4c4…
empty-statego20d98cc268d4c4…
empty-staterust20d98cc268d4c4…
empty-statephp20d98cc268d4c4…
empty-statets20d98cc268d4c4…
empty-statego20d98cc268d4c4…
empty-staterust20d98cc268d4c4…
empty-statephp20d98cc268d4c4…
html-slotts20b1fc22f8d29c…
html-slotgo20b1fc22f8d29c…
html-slotrust20b1fc22f8d29c…
html-slotphp20b1fc22f8d29c…
html-slotts20b1fc22f8d29c…
html-slotgo20b1fc22f8d29c…
html-slotrust20b1fc22f8d29c…
html-slotphp20b1fc22f8d29c…
html-slotts20b1fc22f8d29c…
html-slotgo20b1fc22f8d29c…
html-slotrust20b1fc22f8d29c…
html-slotphp20b1fc22f8d29c…
html-slotts20b1fc22f8d29c…
html-slotgo20b1fc22f8d29c…
html-slotrust20b1fc22f8d29c…
html-slotphp20b1fc22f8d29c…
html-slotts20b1fc22f8d29c…
html-slotgo20b1fc22f8d29c…
html-slotrust20b1fc22f8d29c…
html-slotphp20b1fc22f8d29c…
scope-precedencets207b160d439d3d…
scope-precedencego207b160d439d3d…
scope-precedencerust207b160d439d3d…
scope-precedencephp207b160d439d3d…
scope-precedencets207b160d439d3d…
scope-precedencego207b160d439d3d…
scope-precedencerust207b160d439d3d…
scope-precedencephp207b160d439d3d…
scope-precedencets207b160d439d3d…
scope-precedencego207b160d439d3d…
scope-precedencerust207b160d439d3d…
scope-precedencephp207b160d439d3d…
scope-precedencets207b160d439d3d…
scope-precedencego207b160d439d3d…
scope-precedencerust207b160d439d3d…
scope-precedencephp207b160d439d3d…
scope-precedencets207b160d439d3d…
scope-precedencego207b160d439d3d…
scope-precedencerust207b160d439d3d…
scope-precedencephp207b160d439d3d…