Skip to content

feat(examples): file-tree recursive-template recipe; adopt livetemplate v0.19.0 + lvt v0.2.0 - #114

Merged
adnaan merged 1 commit into
mainfrom
feat/recursive-template-example
Jul 18, 2026
Merged

feat(examples): file-tree recursive-template recipe; adopt livetemplate v0.19.0 + lvt v0.2.0#114
adnaan merged 1 commit into
mainfrom
feat/recursive-template-example

Conversation

@adnaan

@adnaan adnaan commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Adopts the newly released toolchain and adds the recipe for the feature it unlocks.

Pin Before After
livetemplate v0.18.0 v0.19.0
lvt v0.1.6 v0.2.0
lvt/components v0.1.2 v0.1.8

The recipe

examples/file-tree renders a directory tree from one self-referential block:

{{define "node"}}
  ...
  {{range .Children}}{{template "node" .}}{{end}}
  ...
{{end}}

That is the shape {{template}} inlining cannot express — expanding node yields another node, forever — which is why recursion was rejected at parse time before livetemplate v0.19.0. Starring a file four levels down now scopes the update to that leaf rather than re-sending the branch.

Tier 1 throughout: every control is a plain <button name="..."> inside a form. No lvt-* attributes, no hand-written JavaScript. data-key is the node path, not its name, because sibling names repeat across directories (two README.md files are different nodes).

Tests

  • 7 white-box tests over the tree walk and actions.
  • TestHandler_RendersRecursiveDepth — the version gate. Asserts the deepest leaf reaches the first render, which cannot happen before v0.19.0, and asserts a collapsed directory does not render its children so the test can't pass by rendering everything unconditionally.
  • TestFileTreeE2E — real browser, all four observability channels (console, server logs, WS frames, rendered HTML).

The e2e's load-bearing assertion is the absence of livetemplate's falling back to HTML structure-based tree warning. This is the point of the test: a recursive full-HTML document whose {{define}} blocks fail to resolve still renders and still updates via HTML-string diffing — so every visible assertion passes while the reactive path is dead. It also marks a sibling node from the browser and checks the marker survives, proving the update patched one leaf rather than rebuilding the branch.

A non-vacuity guard asserts server logs were captured at all, so the fallback check cannot pass merely because log capture broke.

Verification

Run with GOWORK=off throughout — a bare go run resolves livetemplate to the local workspace checkout at HEAD rather than the pin, which would hide exactly the version mismatch this PR is about.

  • GOWORK=off go build ./...
  • GOWORK=off go test ./examples/... — full suite, browser tests included, all green
  • tinkerdown validate content/ — 96/96

./e2e is untouched and not run here; it targets a deployed site (make test-e2e-local drives a locally served one).

Noted separately, not in this PR

A cmd/sync dry-run against core reports all 20 mirrored reference pages are stalecontent/reference/template-support-matrix.md is still pinned at source_ref: v0.16.0 and tells readers circular template references "would cause infinite loop". That's machine-synced content and a pre-existing drift, so it doesn't belong in this diff.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ui2cwpeGkrUfRt8rh2FgGG

…lvt v0.2.0

Bumps the pinned toolchain and adds the recipe for the feature it unlocks:
- livetemplate v0.18.0 -> v0.19.0 (recursive {{template}}, per-leaf range diff)
- lvt v0.1.6 -> v0.2.0, lvt/components v0.1.2 -> v0.1.8

examples/file-tree renders a directory tree from a single self-referential
{{define "node"}} block — the shape {{template}} inlining cannot express, and
the reason recursion was rejected before v0.19.0. Starring a file four levels
down scopes the update to that leaf instead of re-sending the branch.

Tier 1 throughout: every control is a plain <button name="..."> in a form, no
lvt-* attributes and no hand-written JavaScript. data-key is the node path,
not its name, because sibling names repeat across directories.

Tests:
- seven white-box tests over the tree walk and actions
- TestHandler_RendersRecursiveDepth is the version gate — it asserts the
  deepest leaf reaches the first render, which cannot happen before v0.19.0
- TestFileTreeE2E drives a real browser with all four observability channels.
  Its load-bearing assertion is the ABSENCE of livetemplate's "falling back to
  HTML structure-based tree" warning: a recursive full-HTML document that fails
  to resolve still renders and still updates via HTML-string diffing, so every
  visible assertion can pass while the reactive path is dead. A non-vacuity
  guard asserts server logs were captured at all, so the check cannot pass
  because capture silently broke.

Verified with GOWORK=off (a bare go run resolves livetemplate to the local
workspace checkout at HEAD, not the pin, and would hide a version mismatch):
go build ./..., the full ./examples/... suite including browser tests, and
tinkerdown validate content/ (96/96).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@adnaan
adnaan merged commit a8a443a into main Jul 18, 2026
3 checks passed
adnaan added a commit to livetemplate/livetemplate that referenced this pull request Jul 19, 2026
Two documentation points from claude-review on #503.

The cachedBodyContent field comment still described it as the result of
ExtractTemplateBodyContent(templateStr), which this PR made false: the
computation now calls ExtractTemplateBodyContentSliced and conditionally appends
recursionDefines. Drift I introduced.

The proposal's full-document registry-drop entry describes the rescan mechanism
this PR removes. It is a completed-phase log so the claim was true when written;
rather than rewrite history, it now carries a superseded note pointing at #496,
so someone grepping for how re-attachment works is not sent to a mechanism that
no longer exists.

Also ticked the release-gated docs checkbox, which the review did not raise but
which is stale in the same way: that work landed today. The support matrix row
is ✅ with a Recursion depth section and CONFIGURATION.md documents
LVT_MAX_TEMPLATE_DEPTH (#498), and the file-tree recipe shipped in
livetemplate/docs#114. Verified current-limitations.md needed no change — it
never claimed recursion was unsupported.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant