feat(examples): file-tree recursive-template recipe; adopt livetemplate v0.19.0 + lvt v0.2.0 - #114
Merged
Merged
Conversation
…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
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adopts the newly released toolchain and adds the recipe for the feature it unlocks.
livetemplatelvtlvt/componentsThe recipe
examples/file-treerenders a directory tree from one self-referential block:{{define "node"}} ... {{range .Children}}{{template "node" .}}{{end}} ... {{end}}That is the shape
{{template}}inlining cannot express — expandingnodeyields anothernode, 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. Nolvt-*attributes, no hand-written JavaScript.data-keyis the node path, not its name, because sibling names repeat across directories (twoREADME.mdfiles are different nodes).Tests
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 treewarning. 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=offthroughout — a barego runresolveslivetemplateto 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 greentinkerdown validate content/— 96/96./e2eis untouched and not run here; it targets a deployed site (make test-e2e-localdrives a locally served one).Noted separately, not in this PR
A
cmd/syncdry-run against core reports all 20 mirrored reference pages are stale —content/reference/template-support-matrix.mdis still pinned atsource_ref: v0.16.0and 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