fix: update golden files for corrected $index resolution in range#208
fix: update golden files for corrected $index resolution in range#208
Conversation
The core library (livetemplate/livetemplate#179) fixed a bug where range variables in executeRangeBodyWithVars were stored with the $ prefix, causing buildExecData to construct "$$index" patterns that never matched {{$index}} in templates. The fix strips the $ prefix so that pipe expressions like {{$index | printf "#%d"}} now correctly resolve to "#0", "#1", etc. instead of empty strings. Updates all affected golden files: - update_01: Initial range items now have "#0", "#1", "#2" for field 2 - update_02: Adds ["u", "todo-3", {"2": "#1"}] after remove (index shift) - update_03: Adds index updates for completed/reordered items - update_05a: Adds index updates for existing items when prepending - update_05b: Adds index updates for existing items when inserting middle - update_06: Adds index updates for multi-operation scenario Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates the E2E “todos” golden update fixtures to reflect updated wire-format output for the numbered list index rendered as #<n> in each todo row.
Changes:
- Populate the todo “index label” field (node key
"2") with#0,#1, etc. instead of an empty string in relevant updates. - Add range
"u"operations where needed so existing items’ index labels are updated when list membership changes (remove/insert/multi-op cases). - Refresh expected update payloads for the affected scenarios (add, remove, complete, insert-at-start, insert-in-middle, multiple-ops).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| e2e/testdata/e2e/todos/update_01_add_todos.golden.json | Golden update now includes #<n> index labels for initially added todos. |
| e2e/testdata/e2e/todos/update_02_remove_todo.golden.json | Golden update now includes a follow-up "u" to adjust remaining item index labels after removal. |
| e2e/testdata/e2e/todos/update_03_complete_todo.golden.json | Golden update now includes index label updates alongside completion + reorder ops. |
| e2e/testdata/e2e/todos/update_05a_insert_single_start.golden.json | Golden update now includes "u" ops shifting existing items’ index labels after a prepend. |
| e2e/testdata/e2e/todos/update_05b_insert_single_middle.golden.json | Golden update now includes "u" ops shifting index labels plus an "i" insert op for the middle insertion case. |
| e2e/testdata/e2e/todos/update_06_multiple_ops.golden.json | Golden update now reflects index label updates in a mixed remove/update/append scenario. |
Points to squash-merged PR #179 on livetemplate/livetemplate main branch which fixes $index resolution in pipe expressions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
PR Review posted separately |
ChangelogAll notable changes to the LVT CLI will be documented in this file. The format is based on Keep a Changelog, [v0.1.0] - 2025-11-03Initial release of LVT CLI as a standalone package extracted from the LiveTemplate monorepo. Features
Infrastructure
Documentation
Related Versions
Version SynchronizationLVT follows the LiveTemplate core library's major.minor version (X.Y):
|
|
module github.com/livetemplate/lvt go 1.26.0 require github.com/livetemplate/livetemplate v0.8.4-0.20260312224234-855c13e80cdf replace github.com/livetemplate/lvt/components => ./components require ( require ( |
|
test inline body |
LiveTemplate CLI Generator (
|
| AI Assistant | Installation | Best For |
|---|---|---|
| Claude Code | lvt install-agent --llm claude |
Full workflows with 20+ skills |
| GitHub Copilot | lvt install-agent --llm copilot |
In-editor suggestions |
| Cursor | lvt install-agent --llm cursor |
Rule-based development |
| Aider | lvt install-agent --llm aider |
CLI-driven development |
| Generic/Other | lvt install-agent --llm generic |
Custom LLMs via MCP |
Claude Code (Recommended)
Full-featured agent with skills and workflows:
# Install
lvt install-agent --llm claude
# Upgrade
lvt install-agent --upgrade
# Start Claude Code
claudeFeatures:
- 20+ skills for lvt commands
- Project management agent
- Guided workflows
- Best practices enforcement
Try asking:
- "Add a posts resource with title and content"
- "Generate authentication system"
- "Create a quickstart blog app"
GitHub Copilot
Instructions-based integration:
# Install
lvt install-agent --llm copilot
# Open in VS Code - Copilot automatically understands LiveTemplateCursor
Rule-based development patterns:
# Install
lvt install-agent --llm cursor
# Open project in Cursor - rules apply to *.go files automaticallyAider
CLI configuration:
# Install
lvt install-agent --llm aider
# Start Aider - configuration loads automatically
aiderUpgrading Agents
# Upgrade any agent type
lvt install-agent --llm <type> --upgradeThis preserves your custom settings while updating the agent files.
Complete Setup Guide
For detailed setup instructions for each AI assistant, see:
- docs/AGENT_SETUP.md - Complete setup guide for all AI assistants
- docs/MCP_TOOLS.md - MCP server tools reference
- docs/WORKFLOWS.md - Common development workflows
- docs/AGENT_USAGE_GUIDE.md - Claude Code usage examples
Global AI Access via MCP Server
lvt also provides a Model Context Protocol (MCP) server that works with Claude Desktop, Claude Code, and other MCP-compatible AI applications. This gives you global access to lvt commands from anywhere.
Setup for Claude Desktop
-
Install lvt globally:
go install github.com/livetemplate/lvt@latest
-
Configure Claude Desktop by editing
claude_desktop_config.json:macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.jsonAdd:
{ "mcpServers": { "lvt": { "command": "lvt", "args": ["mcp-server"] } } } -
Restart Claude Desktop
Available MCP Tools
Once configured, Claude has access to these 16 tools:
Project & Resource Generation:
- lvt_new - Create new apps with kit/CSS/module options
- lvt_gen_resource - Generate CRUD resources with fields
- lvt_gen_view - Generate view-only handlers
- lvt_gen_auth - Generate authentication systems
- lvt_gen_schema - Generate database schema only
Database Migrations:
- lvt_migration_up - Run pending migrations
- lvt_migration_down - Rollback last migration
- lvt_migration_status - Check migration status
- lvt_migration_create - Create new migration files
Data & Inspection:
- lvt_seed - Generate test data for resources
- lvt_resource_list - List all available resources
- lvt_resource_describe - Show detailed schema for a resource
Validation & Configuration:
- lvt_validate_template - Validate and analyze template files
- lvt_env_generate - Generate .env.example with detected config
- lvt_kits_list - List available CSS framework kits
- lvt_kits_info - Show detailed kit information
Usage Example
In Claude Desktop, simply ask:
"Create a new LiveTemplate app called 'blog' with the multi kit"
Claude will use the MCP tools to create your app, even before you have a project directory!
MCP vs Embedded Agent
- MCP Server: Global access, works with Claude Desktop, great for project creation
- Embedded Agent: Project-specific, richer workflows, 20+ skills with detailed guidance
Use both for the best experience!
Quick Start
You can use lvt in two modes: Interactive (TUI wizards) or Direct (CLI arguments).
Important: Create apps outside of existing Go module directories. If you create an app inside another Go module (e.g., for testing), you'll need to use GOWORK=off when running commands:
GOWORK=off go run cmd/myapp/main.goInteractive Mode (Recommended for New Users)
# Launch interactive app creator
lvt new
# Launch interactive resource builder
lvt gen
# Launch interactive view creator
lvt gen viewDirect Mode
1. Create a New App
lvt new myapp
cd myappThis generates:
- Complete Go project structure
- Database layer with sqlc integration
- go.mod with Go 1.24+ tools directive
- README with next steps
2. Generate a CRUD Resource
# With explicit types
lvt gen users name:string email:string age:int
# With inferred types (NEW!)
lvt gen products name price quantity enabled created_at
# → Infers: name:string price:float quantity:int enabled:bool created_at:timeThis generates:
app/users/users.go- Full CRUD handlerapp/users/users.tmpl- Tailwind CSS UIapp/users/users_ws_test.go- WebSocket testsapp/users/users_test.go- Chromedp E2E tests- Database schema and queries (appended)
3. Run Migrations
lvt migration up # Runs pending migrations and auto-generates database codeThis automatically:
- Applies pending database migrations
- Runs
sqlc generateto create Go database code - Updates your query interfaces
4. Wire Up Routes
Add to cmd/myapp/main.go:
import "myapp/app/users"
// In main():
http.Handle("/users", users.Handler(queries))5. Run the App
go run cmd/myapp/main.goOpen http://localhost:8080/users
Tutorial: Building a Blog System
Let's build a complete blog system with posts, comments, and categories to demonstrate lvt's capabilities.
Step 1: Create the Blog App
lvt new myblog
cd myblogThis creates your project structure with database setup, main.go, and configuration. Dependencies are automatically installed via go get ./....
Step 2: Generate Resources
lvt gen posts title content:string published:bool
lvt gen categories name description
lvt gen comments post_id:references:posts author textThis generates for each resource:
- ✅
app/{resource}/{resource}.go- CRUD handler with LiveTemplate integration - ✅
app/{resource}/{resource}.tmpl- Component-based template with Tailwind CSS - ✅
app/{resource}/{resource}_test.go- E2E tests with chromedp - ✅ Database migration file with unique timestamps
- ✅ SQL queries appended to
database/queries.sql
For the comments resource with post_id:references:posts:
- ✅ Creates
post_idfield as TEXT (matching posts.id type) - ✅ Adds foreign key constraint:
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE - ✅ Creates index on
post_idfor query performance - ✅ No manual migration needed!
Step 3: Run Migrations
lvt migration upThis command:
- ✅ Runs all pending database migrations
- ✅ Automatically generates Go database code with sqlc
- ✅ Creates type-safe query interfaces
You'll see output like:
Running pending migrations...
OK 20240315120000_create_posts.sql
OK 20240315120001_create_categories.sql
OK 20240315120002_create_comments.sql
Generating database code with sqlc...
✅ Database code generated successfully!
✅ Migrations complete!
Step 4: Resolve Dependencies
go mod tidyThis resolves all internal package imports created by the generated code. Required before running the app.
Step 5: Wire Up Routes
The routes are auto-injected, but verify in cmd/myblog/main.go:
import (
"myblog/app/posts"
"myblog/app/categories"
"myblog/app/comments"
)
func main() {
// ... database setup ...
// Routes (auto-injected)
http.Handle("/posts", posts.Handler(queries))
http.Handle("/categories", categories.Handler(queries))
http.Handle("/comments", comments.Handler(queries))
// Start server
http.ListenAndServe(":8080", nil)
}Step 6: Run the Blog
go run cmd/myblog/main.goVisit:
- http://localhost:8080/posts - Create and manage blog posts
- http://localhost:8080/categories - Organize posts by category
- http://localhost:8080/comments - View all comments
Note: Visiting http://localhost:8080/ will show a 404 since no root handler exists. You can add a homepage next.
Step 7: Add a Custom View for the Homepage (Optional)
lvt gen view home
go mod tidy
go run cmd/myblog/main.goThis creates a view-only handler (no database operations). Edit app/home/home.tmpl to create your landing page, then visit http://localhost:8080/home.
Step 8: Test the Application
# Run all tests (E2E + WebSocket)
go test ./...
# Run specific resource tests
go test ./app/posts -vCustomization Ideas
1. Generate resources (CSS framework determined by kit):
# Resources use the CSS framework from your chosen kit
# Multi and single kits use Tailwind CSS
# Simple kit uses no CSS framework (semantic HTML)
lvt gen tags name
# To use a different CSS framework, create your app with a different kit
lvt new myapp --kit simple # Uses no CSS (semantic HTML)
cd myapp
lvt gen authors name bio # Will use semantic HTML2. Use Type Inference:
# Field types are inferred from names
lvt gen articles title content published_at author email price
# Infers: title=string, content=string, published_at=time,
# author=string, email=string, price=float3. Create Custom Templates:
# Copy templates to customize
lvt template copy all
# Edit templates in .lvt/templates/
# Your customizations apply to all new resources4. Define Relationships with references:
# Basic reference (ON DELETE CASCADE - default)
lvt gen comments post_id:references:posts author text
# Custom ON DELETE behavior
lvt gen audit_logs user_id:references:users:set_null action:string
# Makes user_id nullable, sets NULL when user deleted
# Multiple references
lvt gen likes user_id:references:users post_id:references:posts
# Restrict deletion (prevent deleting parent if children exist)
lvt gen invoices customer_id:references:customers:restrict amount:float5. Add More Features:
# Tags for posts
lvt gen tags name color:string
# Post-tag relationship (many-to-many with references)
lvt gen post_tags post_id:references:posts tag_id:references:tags
# User accounts
lvt gen users username email password_hash:string
# Post reactions with proper relationships
lvt gen reactions post_id:references:posts user_id:references:users type:stringProject Structure
After completing the tutorial, your project looks like:
myblog/
├── cmd/myblog/main.go
├── internal/
│ ├── app/
│ │ ├── posts/
│ │ │ ├── posts.go
│ │ │ ├── posts.tmpl
│ │ │ ├── posts_test.go
│ │ │ └── posts_ws_test.go
│ │ ├── categories/
│ │ ├── comments/
│ │ └── home/
│ └── database/
│ ├── db.go
│ ├── migrations/
│ │ ├── 20240315120000_create_posts.sql
│ │ ├── 20240315120001_create_categories.sql
│ │ └── ...
│ ├── queries.sql
│ └── models/ # Generated by sqlc
│ ├── db.go
│ ├── models.go
│ └── queries.sql.go
└── go.mod
Next Steps
- Add Authentication - Integrate session management
- Rich Text Editor - Add markdown or WYSIWYG editor to post content
- Image Uploads - Add image upload functionality
- Search - Implement full-text search across posts
- RSS Feed - Generate RSS feed from posts
- Admin Dashboard - Create
lvt gen view admin - API Endpoints - Add JSON API alongside HTML views
Tips
- Start simple - Begin with core resources, add features incrementally
- Use migrations - Always use
lvt migration createfor schema changes - Test continuously - Run
go test ./...after each change - Customize templates - Copy and modify templates to match your design
- Component mode - Use
--mode singlefor SPA-style applications
Commands
lvt new <app-name>
Creates a new LiveTemplate application with:
myapp/
├── cmd/myapp/main.go # Application entry point
├── go.mod # With //go:tool directive
├── internal/
│ ├── app/ # Handlers and templates
│ ├── database/
│ │ ├── db.go # Connection & migrations
│ │ ├── schema.sql # Database schema
│ │ ├── queries.sql # SQL queries (sqlc)
│ │ ├── sqlc.yaml # sqlc configuration
│ │ └── models/ # Generated code
│ └── shared/ # Shared utilities
├── web/assets/ # Static assets
└── README.md
lvt gen <resource> <field:type>...
Generates a full CRUD resource with database integration.
Example:
lvt gen posts title:string content:string published:bool views:intGenerated Files:
- Handler with State struct, Change() method, Init() method
- Bulma CSS template with:
- Create form with validation
- List view with search, sort, pagination
- Delete functionality
- Real-time WebSocket updates
- WebSocket unit tests
- Chromedp E2E tests
- Database schema and queries
Features:
- ✅ CRUD operations (Create, Read, Update, Delete)
- ✅ Search across string fields
- ✅ Sorting by fields
- ✅ Pagination
- ✅ Real-time updates via WebSocket
- ✅ Form validation
- ✅ Statistics/counts
- ✅ Bulma CSS styling
- ✅ Comprehensive tests
- ✅ Auto-injected routes - Automatically adds route and import to
main.go
lvt gen view <name>
Generates a view-only handler without database integration (like the counter example).
Example:
lvt gen view dashboardGenerates:
app/dashboard/dashboard.go- View handler with state managementapp/dashboard/dashboard.tmpl- Bulma CSS templateapp/dashboard/dashboard_ws_test.go- WebSocket testsapp/dashboard/dashboard_test.go- Chromedp E2E tests
Features:
- ✅ State management
- ✅ Real-time updates via WebSocket
- ✅ Bulma CSS styling
- ✅ Comprehensive tests
- ✅ No database dependencies
- ✅ Auto-injected routes - Automatically adds route and import to
main.go
lvt gen auth
Generates a complete authentication system similar to Phoenix's mix phx.gen.auth.
Example:
# Generate with default settings (password + magic-link auth)
lvt gen auth
# Generate with only password authentication
lvt gen auth --no-magic-link
# Generate with only magic-link authentication
lvt gen auth --no-password
# Disable email confirmation
lvt gen auth --no-email-confirm
# Disable CSRF protection
lvt gen auth --no-csrfFlags:
--no-password- Disable password authentication--no-magic-link- Disable magic-link authentication--no-email-confirm- Disable email confirmation flow--no-password-reset- Disable password reset functionality--no-sessions-ui- Disable session management UI--no-csrf- Disable CSRF protection middleware
Note: At least one authentication method (password or magic-link) must be enabled.
Generates:
shared/password/password.go- Password hashing utilities (bcrypt)shared/email/email.go- Email sender interface with console loggerdatabase/migrations/YYYYMMDDHHMMSS_create_auth_tables.sql- Auth tables migration- Auth queries appended to
database/queries.sql
Features:
- ✅ Password authentication with bcrypt hashing
- ✅ Magic-link email authentication
- ✅ Email confirmation flow
- ✅ Password reset functionality
- ✅ Session management
- ✅ CSRF protection with gorilla/csrf
- ✅ Auto-updates
go.moddependencies - ✅ EmailSender interface (console logger + SMTP/Mailgun examples)
- ✅ Case-insensitive email matching
- ✅ Configurable features via flags
Database Tables:
users- User accounts with email and optional hashed passworduser_tokens- Tokens for magic links, email confirmation, password reset
Next Steps After Generation:
# 1. Run migrations
lvt migration up
# 2. Generate sqlc code
sqlc generate
# 3. Update main.go to register auth handler
# (Implementation in Phase 2)Router Auto-Update
When you generate a resource or view, lvt automatically:
-
Adds the import to your
cmd/*/main.go:import ( "yourapp/app/users" // ← Auto-added )
-
Injects the route after the TODO comment:
// TODO: Add routes here http.Handle("/users", users.Handler(queries)) // ← Auto-added
-
Maintains idempotency - Running the same command twice won't duplicate routes
This eliminates the manual step of wiring up routes, making the development workflow smoother. Routes are inserted in the order you generate them, right after the TODO marker.
Type Mappings
| CLI Type | Go Type | SQL Type |
|---|---|---|
| string | string | TEXT |
| int | int64 | INTEGER |
| bool | bool | BOOLEAN |
| float | float64 | REAL |
| time | time.Time | DATETIME |
Aliases:
str,text→stringinteger→intboolean→boolfloat64,decimal→floatdatetime,timestamp→time
Smart Type Inference (🆕 Phase 1)
The CLI includes an intelligent type inference system that automatically suggests types based on field names:
How It Works
When using the type inference system, you can omit explicit types and let the system infer them:
// In ui.InferType("email") → returns "string"
// In ui.InferType("age") → returns "int"
// In ui.InferType("price") → returns "float"
// In ui.InferType("enabled") → returns "bool"
// In ui.InferType("created_at") → returns "time"Inference Rules
String fields (default for unknown):
- Exact:
name,title,description,email,username,url,slug,address, etc. - Contains:
*email*,*url*
Integer fields:
- Exact:
age,count,quantity,views,likes,score,rank,year - Suffix:
*_count,*_number,*_index
Float fields:
- Exact:
price,amount,rating,latitude,longitude - Suffix/Contains:
*_price,*_amount,*_rate,*price*,*amount*
Boolean fields:
- Exact:
enabled,active,published,verified,approved,deleted - Prefix:
is_*,has_*,can_*
Time fields:
- Exact:
created_at,updated_at,deleted_at,published_at - Suffix:
*_at,*_date,*_time
Usage
The inference system is available via the ui package:
import "github.com/livetemplate/lvt/internal/ui"
// Infer type from field name
fieldType := ui.InferType("email") // → "string"
// Parse field input (with or without type)
name, typ := ui.ParseFieldInput("email") // → "email", "string" (inferred)
name, typ := ui.ParseFieldInput("age:float") // → "age", "float" (explicit override)Future Enhancement
In upcoming phases, this will power:
- Interactive field builders that suggest types as you type
- Direct mode support:
lvt gen users name email age(without explicit types) - Smart defaults that reduce typing
Project Layout
The generated app follows idiomatic Go conventions:
cmd/- Application entry pointsapp/- Handlers and templates (co-located!)database/- Database layer with sqlcshared/- Shared utilitiesweb/assets/- Static assets
Key Design Decision: Templates live next to their handlers for easy discovery.
Generated Handler Structure
package users
type State struct {
Queries *models.Queries
Users []User
SearchQuery string
SortBy string
CurrentPage int
PageSize int
TotalPages int
// ...
}
// Action methods - automatically dispatched based on action name
func (s *State) Add(ctx *livetemplate.ActionContext) error {
// Create user
return nil
}
func (s *State) Update(ctx *livetemplate.ActionContext) error {
// Update user
return nil
}
func (s *State) Delete(ctx *livetemplate.ActionContext) error {
// Delete user
return nil
}
func (s *State) Search(ctx *livetemplate.ActionContext) error {
// Search users
return nil
}
func (s *State) Init() error {
// Load initial data
return nil
}
func Handler(queries *models.Queries) http.Handler {
tmpl := livetemplate.New("users")
state := &State{Queries: queries, PageSize: 10}
return tmpl.Handle(state)
}Testing
The project includes comprehensive testing infrastructure at multiple levels.
Make Targets (Recommended)
Use these convenient make targets for different testing workflows:
make test-fast # Unit tests only (~30s)
make test-commit # Before committing (~3-4min)
make test-all # Full suite (~5-6min)
make test-clean # Clean Docker resourcesSee Testing Guide for detailed documentation on test optimization and architecture.
Quick Start
# Run all tests (fast mode - skips deployment tests)
go test ./... -short
# Run all tests (including slower e2e tests)
go test ./...
# Run specific package tests
go test ./internal/generator -v
# Run tests with coverage
go test ./... -coverTest Types
1. Unit Tests
Fast tests for individual packages and functions:
# Internal packages
go test ./internal/config ./internal/generator ./internal/parser -v
# Commands package
go test ./commands -vDuration: <5 seconds
2. WebSocket Tests (*_ws_test.go)
Fast unit tests for WebSocket protocol and state changes in generated resources:
go test ./app/users -run WebSocketFeatures:
- Test server startup with dynamic ports
- WebSocket connection testing
- CRUD action testing
- Server log capture for debugging
Duration: 2-5 seconds per resource
3. E2E Browser Tests (*_test.go)
Full browser testing with real user interactions for generated resources:
go test ./app/users -run E2EFeatures:
- Docker Chrome container
- Real browser interactions (clicks, typing, forms)
- Visual verification
- Screenshot capture
- Console log access
Duration: 20-60 seconds per resource
4. Deployment Tests (Advanced)
Comprehensive deployment testing infrastructure for testing real deployments:
# Mock deployment tests (fast, no credentials needed)
go test ./e2e -run TestDeploymentInfrastructure_Mock -v
# Docker deployment tests (requires Docker)
RUN_DOCKER_DEPLOYMENT_TESTS=true go test ./e2e -run TestDockerDeployment -v
# Fly.io deployment tests (requires credentials)
export FLY_API_TOKEN="your_token"
RUN_FLY_DEPLOYMENT_TESTS=true go test ./e2e -run TestRealFlyDeployment -vFeatures:
- Mock, Docker, and Fly.io deployment testing
- Automatic cleanup and resource management
- Smoke tests (HTTP, health, WebSocket, templates)
- Credential-based access control
Duration: 2 minutes (mock) to 15 minutes (real deployments)
Test Environment Variables
| Variable | Purpose | Default |
|---|---|---|
RUN_DOCKER_DEPLOYMENT_TESTS |
Enable Docker deployment tests | false |
RUN_FLY_DEPLOYMENT_TESTS |
Enable Fly.io deployment tests | false |
FLY_API_TOKEN |
Fly.io API token for real deployments | - |
Continuous Integration
Tests run automatically on every pull request via GitHub Actions:
- ✅ Code formatting validation
- ✅ Unit tests (all internal packages)
- ✅ Commands tests
- ✅ E2E tests (short mode)
- ✅ Mock deployment tests
On-demand/scheduled deployment testing available via manual workflow dispatch or weekly schedule.
For detailed CI/CD documentation, see:
Skip Slow Tests
Use -short flag to skip slow tests (deployment tests, long-running e2e tests):
go test -short ./...Test Documentation
For comprehensive testing documentation, see:
- Deployment Testing - Complete deployment testing guide
- CI/CD Testing - CI/CD workflows and setup
- Deployment Plan - Implementation progress and status
Go 1.24+ Tools Support
Generated go.mod includes:
//go:tool github.com/sqlc-dev/sqlc/cmd/sqlcRun migrations (automatically runs sqlc):
lvt migration upCSS Framework
All generated templates use Bulma CSS by default:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.4/css/bulma.min.css">Components used:
.section,.container- Layout.box- Content containers.table- Data tables.button,.input,.select- Form controls.pagination- Pagination controls
Development Workflow
- Create app:
lvt new myapp - Generate resources:
lvt gen users name:string email:string - Run migrations:
lvt migration up(auto-generates DB code) - Wire routes in
main.go - Run tests:
go test ./... - Run app:
go run cmd/myapp/main.go
Examples
Blog App
lvt new myblog
cd myblog
# Generate posts resource
lvt gen posts title:string content:string published:bool
# Generate comments resource
lvt gen comments post_id:string author:string text:string
# Run migrations (auto-generates DB code)
lvt migration up
# Run
go run cmd/myblog/main.goE-commerce
lvt new mystore
cd mystore
lvt gen products name:string price:float stock:int
lvt gen customers name:string email:string
lvt gen orders customer_id:string total:float
lvt migration up # Runs migrations and generates DB code
go run cmd/mystore/main.goArchitecture
Template System
The generator uses custom delimiters ([[, ]]) to avoid conflicts with Go template syntax:
- Generator templates:
[[.ResourceName]]- Replaced during generation - Output templates:
{{.Title}}- Used at runtime by LiveTemplate
Embedded Templates
All templates are embedded using embed.FS for easy distribution.
Code Generation Strategy
- Parse field definitions (
name:type) - Map types to Go and SQL types
- Render templates with resource data
- Generate handler, template, tests
- Append to database files
Testing the Generator
Run All Tests
go test ./cmd/lvt -vTest Layers
-
Parser Tests (
cmd/lvt/internal/parser/fields_test.go)- Field parsing and validation
- Type mapping correctness
- 13 comprehensive tests
-
Golden File Tests (
cmd/lvt/golden_test.go)- Regression testing for generated code
- Validates handler and template output
- Update with:
UPDATE_GOLDEN=1 go test ./cmd/lvt -run Golden
-
Integration Tests (
cmd/lvt/integration_test.go)- Go syntax validation
- File structure validation
- Generation pipeline testing
-
Smoke Test (
scripts/test_cli_smoke.sh)- End-to-end CLI workflow
- App creation and resource generation
- File structure verification
Roadmap
-
✅ Completelvt gen view- View-only handlers -
Router auto-update✅ Complete -
Bubbletea interactive UI✅ Complete (Phase 1-3)- Dependencies & infrastructure
- Smart type inference system (50+ patterns)
- UI styling framework (Lipgloss)
- Interactive app creation wizard
- Interactive resource builder
- Interactive view builder
- Mode detection (auto-switch based on args)
- Type inference in direct mode
-
Enhanced validation & help system (Phase 4)✅ Complete- Real-time Go identifier validation
- SQL reserved word warnings (25+ keywords)
- Help overlay with
?key in all wizards - Color-coded feedback (✓✗⚠)
- All 3 wizards enhanced
-
Migration commands✅ Complete- Goose integration with minimal wrapper (~410 lines)
- Auto-generate migrations from
lvt gen resource - Commands:
up,down,status,create <name> - Timestamped migration files with Up/Down sections
- Schema versioning and rollback support
-
Custom template support✅ Complete- Cascading template lookup (project → user → embedded)
-
lvt template copycommand for easy customization - Project templates in
.lvt/templates/(version-controlled) - User-wide templates in
~/.config/lvt/templates/ - Selective override (only customize what you need)
- Zero breaking changes (~250 lines total)
-
Multiple CSS frameworks✅ Complete- Tailwind CSS v4 (default)
- Bulma 1.0.4
- Pico CSS v2
- None (pure HTML)
- CSS framework determined by kit (multi/single use Tailwind, simple uses Pico)
- 57 CSS helper functions for framework abstraction
- Conditional template rendering (single source of truth)
- Semantic HTML support for Pico CSS (, )
- Zero breaking changes (~550 lines total)
-
✅ Phase 1 Completelvt gen auth- Authentication system- Password authentication (bcrypt)
- Magic-link email authentication
- Email confirmation flow
- Password reset functionality
- Session management tables
- CSRF protection (gorilla/csrf)
- Auto-dependency updates (go.mod)
- EmailSender interface with examples
- Configurable via flags
- Auth handlers (Phase 2)
- Custom authenticator (Phase 3)
- Middleware templates (Phase 4)
- GraphQL support
Contributing
See the main LiveTemplate CLAUDE.md for development guidelines.
License
Same as LiveTemplate project.
PR Review: fix: update golden files for corrected index resolution in range |
Contributing to LVT CLIThank you for your interest in contributing to the LVT CLI! Development SetupPrerequisites
Getting Started# Clone the repository
git clone https://github.com/livetemplate/lvt.git
cd lvt
# Install dependencies
go mod download
# Install git hooks
./scripts/install-hooks.sh
# Run tests
go test ./...
# Build
go build -o lvt .Development Workflow1. Create a Branchgit checkout -b feature/your-feature-name
# or
git checkout -b fix/your-bug-fix2. Make Changes
3. Local Development with Core LibraryIf you're making changes that depend on unreleased core library changes, you have two options: Recommended: Go Workspace (Automatic)The easiest way - Go automatically uses local modules without any # From parent directory containing all repos
cd ..
./setup-workspace.sh
# Now test with local core library
cd lvt
go test ./... # Automatically uses ../livetemplateThe workspace setup is done once and affects all repositories. See the core library CONTRIBUTING.md for details. Alternative: Manual Replace DirectivesIf you prefer manual control: # Enable local development mode
./scripts/setup-local-dev.sh
# Test with local core
go test ./...
# Revert to published version
./scripts/setup-local-dev.sh --undoDirectory structure for both methods: 4. Test Your Changes# Run all tests
go test ./...
# Run with timeout
go test ./... -timeout=120s
# Run specific package
go test ./internal/generator -v
# Build to verify
go build -o lvt .5. Commit Your ChangesThe repository has a pre-commit hook that will:
git add .
git commit -m "feat: add new feature"Commit Message FormatFollow Conventional Commits:
6. Push and Create PRgit push origin feature/your-feature-nameThen create a Pull Request on GitHub. Code StyleGo Conventions
Project StructureTesting GuidelinesTest Categories
Writing Testsfunc TestGenerateResource(t *testing.T) {
// Arrange
gen := generator.New()
// Act
err := gen.GenerateResource("Post", fields)
// Assert
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}Test Coverage
Adding New Features1. GeneratorsAdd to // internal/generator/myfeature.go
func (g *Generator) GenerateMyFeature(name string) error {
// Implementation
}2. CommandsAdd to // commands/mycommand.go
var myCmd = &cobra.Command{
Use: "my",
Short: "Description",
Run: runMy,
}
func runMy(cmd *cobra.Command, args []string) {
// Implementation
}3. KitsKits are located in To add a new kit:
VersioningLVT follows the core library's major.minor version:
Release ProcessReleases are automated via # Dry run
./scripts/release.sh --dry-run
# Actual release (maintainers only)
./scripts/release.shThe script will:
Core Library CoordinationWhen the core library changes:
DocumentationREADME.mdUpdate for:
Code Comments
Getting Help
LicenseBy contributing, you agree that your contributions will be licensed under the MIT License. |
|
The fix is well-targeted and the golden file updates correctly capture the new behavior. A few observations. What looks good: rendering from empty string to index numbers matches the template; the index-shift propagation in update_02 through update_06 correctly reflects that remaining items need updated indices when the list changes; go.mod/go.sum properly bumped to v0.8.4-0.20260312224234-855c13e80cdf. Issues/Questions: (1) Missing trailing newlines - four of the six updated golden files now lack a trailing newline: update_03_complete_todo.golden.json, update_05a_insert_single_start.golden.json, update_05b_insert_single_middle.golden.json, and update_06_multiple_ops.golden.json. update_01 and update_02 retain their trailing newlines. Worth fixing for consistency. (2) update_04_sort_todos.golden.json is not updated - intentional? This file only contains an reorder operation but no index-update ops for index changes. After the reorder, the two remaining items switch positions. This seems inconsistent with insert/remove cases that do emit index-shift ops. Either the framework intentionally does not emit index updates for pure reorders (worth noting), or the sort case should also emit index-update ops but does not yet. Worth clarifying before merge. (3) Dependency on unmerged upstream PR - CI will not be green until the upstream livetemplate/livetemplate PR 179 is merged. Worth ensuring this does not land on main before the upstream is released. Summary: The core change is correct and the index-shift propagation in the golden files looks right. The main open question is whether the sort/reorder case (update_04) intentionally omits index-shift operations or if that is an oversight. |
Get GitHub PR Comments for Current BranchFetch and display GitHub Pull Request review comments for the current branch. This skill will:
UsageInvoke this skill when you need to:
Implementation# Get current branch
BRANCH=$(git branch --show-current)
echo "Current branch: $BRANCH"
# Get PR number for current branch
PR_NUMBER=$(gh pr list --state all --head "$BRANCH" --json number --jq '.[0].number')
if [ -z "$PR_NUMBER" ]; then
echo "No PR found for branch $BRANCH"
exit 1
fi
echo "Found PR #$PR_NUMBER for branch $BRANCH"
echo ""
echo "Fetching review comments..."
echo ""
# Fetch PR review comments using GitHub API
gh api "/repos/{owner}/{repo}/pulls/$PR_NUMBER/comments" \
--jq '.[] | "File: \(.path):\(.line // .original_line)\nComment: \(.body)\nAuthor: \(.user.login)\n---"'Output FormatThe skill outputs comments in this format: |
|
Review posted - please see the full review below. |
|
test with newline |
|
Cleaning up test comments - the actual review was posted as comment #208 (comment) |
|
module github.com/livetemplate/lvt go 1.26.0 require github.com/livetemplate/livetemplate v0.8.4-0.20260312224234-855c13e80cdf replace github.com/livetemplate/lvt/components => ./components require ( require ( |
|
.PHONY: test-fast test-commit test-all test-e2e test-unit test-http test-browser test-clean install upgrade-skills =============================================================================TIERED TESTING STRATEGY=============================================================================Tier 0: Client JS tests (Jest + jsdom) - run separately via npmTier 1: HTTP tests (no browser) - fast server-side validationTier 2: Browser rendering tests - validates rendering libraryTier 3: Application tests - HTTP for most, browser for UI-critical=============================================================================Fast feedback - unit tests only (~30 seconds)test-fast: Before commit - unit + HTTP tests, NO browser (~75 seconds)This is the recommended pre-push target - no laptop freezing!test-commit: HTTP tests only - Tier 1 + Tier 3 HTTP teststest-http: Browser rendering tests only - Tier 2 (~45 seconds)Run weekly or before releases to validate rendering librarytest-browser: Full validation - all tiers including browser (~3-5 minutes)test-all: Legacy e2e target - runs all e2e tests (browser-based)test-e2e: Unit tests onlytest-unit: Clean up Docker resourcestest-clean: Install lvt CLI to GOPATH/bininstall: Install lvt and upgrade Claude Code skills (for local testing)upgrade-skills: install |
LiveTemplate Assistant for GitHub CopilotYou are an AI assistant helping developers build full-stack Go web applications with LiveTemplate. Use the Available MCP ToolsThe Core Generation (5 tools)
Database (4 tools)
Development (7 tools)
Common WorkflowsCreating a New AppAdding Features to Existing AppDatabase ManagementBest Practices
Field TypesWhen using lvt_gen_resource, these field types are available: Example SessionsBlog with Auth// 1. Create app
{"tool": "lvt_new", "input": {"name": "myblog", "kit": "multi"}}
// 2. Add authentication
{"tool": "lvt_gen_auth", "input": {}}
// 3. Add posts
{"tool": "lvt_gen_resource", "input": {
"name": "posts",
"fields": {
"title": "string",
"content": "text",
"user_id": "references:users",
"published": "bool"
}
}}
// 4. Add comments
{"tool": "lvt_gen_resource", "input": {
"name": "comments",
"fields": {
"content": "text",
"post_id": "references:posts",
"user_id": "references:users"
}
}}
// 5. Apply migrations
{"tool": "lvt_migration_up", "input": {}}
// 6. Seed data
{"tool": "lvt_seed", "input": {"resource": "posts", "count": 10}}
{"tool": "lvt_seed", "input": {"resource": "comments", "count": 30}}Task Manager// 1. Create app
{"tool": "lvt_new", "input": {"name": "tasks", "kit": "single"}}
// 2. Add auth
{"tool": "lvt_gen_auth", "input": {}}
// 3. Add tasks resource
{"tool": "lvt_gen_resource", "input": {
"name": "tasks",
"fields": {
"title": "string",
"description": "text",
"completed": "bool",
"user_id": "references:users",
"due_date": "time",
"priority": "int"
}
}}
// 4. Migrate & seed
{"tool": "lvt_migration_up", "input": {}}
{"tool": "lvt_seed", "input": {"resource": "tasks", "count": 20}}TroubleshootingMigration IssuesTemplate ErrorsStarting FreshQuick ReferenceCreate new app:
Add CRUD resource:
Add auth:
Manage migrations:
Development data:
File StructureAfter generation, you'll find: Integration Tips
Documentation Links
MCP Server SetupTo enable these tools in GitHub Copilot, the Installation: go install github.com/livetemplate/lvt@latestStart MCP server: lvt mcp-serverOnce running, all 16 tools become available for use in LiveTemplate projects. |
|
PR Review: fix: update golden files for corrected index resolution in range The fix is well-targeted and the golden file updates correctly capture the new behavior. What looks good
Issues / Questions 1. Missing trailing newlines Four of the six updated golden files lack a trailing newline: update_03_complete_todo.golden.json, update_05a_insert_single_start.golden.json, update_05b_insert_single_middle.golden.json, and update_06_multiple_ops.golden.json. update_01 and update_02 retain their trailing newlines. Worth fixing for consistency. 2. update_04_sort_todos.golden.json is not updated -- intentional? This file only contains a reorder op but no u ops for index changes. After the reorder, the two remaining items switch positions. This seems inconsistent with insert/remove cases that do emit index-shift ops. Either the framework does not emit index updates for pure reorders (worth noting), or the sort case needs a follow-up fix. Worth clarifying before merge. 3. Dependency on unmerged upstream PR CI will not be green until the upstream livetemplate/livetemplate PR 179 is merged. Ensure this does not land on main before the upstream is released. Summary The core change is correct. The main open question is whether update_04 intentionally omits index-shift operations or if that is an oversight. Resolving the trailing newline inconsistency would also improve diff hygiene. |
PR Review: fix: update golden files for corrected index resolution in rangeThe fix is well-targeted and the golden file updates correctly capture the new behavior. |
PR Review: fix: update golden files for corrected index resolution in rangeThe fix is well-targeted and the golden file updates correctly capture the new behavior. A few observations: What looks good
Issues / Questions 1. Missing trailing newlines (minor but inconsistent) Four of the six updated golden files now lack a trailing newline: update_03_complete_todo.golden.json, update_05a_insert_single_start.golden.json, update_05b_insert_single_middle.golden.json, and update_06_multiple_ops.golden.json. update_01 and update_02 retain their trailing newlines. Worth fixing for consistency. 2. update_04_sort_todos.golden.json is not updated -- intentional? This file only contains a reorder operation but no index-update ops. After the reorder, the two remaining items switch positions. This seems inconsistent with insert/remove cases that do emit index-shift ops. Either the framework intentionally does not emit index updates for pure reorders (worth noting), or this is a gap needing a follow-up fix. Worth clarifying before merge. 3. Dependency on unmerged upstream PR Already called out in the description -- CI will not be green until the upstream livetemplate/livetemplate PR 179 is merged. Worth ensuring this does not land on main before the upstream is released. Summary The core change is correct and the index-shift propagation in the golden files looks right. The main open question is whether the sort/reorder case (update_04) intentionally omits index-shift operations or if that is an oversight. Resolving the trailing newline inconsistency would also improve diff hygiene for future changes. |
name: lvt-validate-templates
|
PR Review SummaryWhat looks good:
Issue 1 - Missing trailing newlines: Four updated files lack a trailing newline (update_03, update_05a, update_05b, update_06) while update_01 and update_02 do not. If regenerated via -update-golden, the tooling may not be normalizing newlines consistently. Issue 2 - update_04_sort_todos.golden.json not updated: After the reorder operation, todo-1 and todo-3 switch positions (todo-3 was at index 0, todo-1 at index 1 after step 03). Post-sort order puts todo-1 at index 0 and todo-3 at index 1 — both indices change. Yet unlike insert/remove cases, no u ops are emitted for index shifts. Is this intentional (client re-evaluates position on reorder) or an oversight needing a follow-up fix in the core library? Issue 3 - Pre-release upstream dependency: CI will not pass until livetemplate/livetemplate PR 179 merges. Ensure this does not land on main before the upstream is released to avoid mismatching the published library version. Overall the core fix is correct. The main question is whether the sort/reorder case intentionally omits index-shift operations. |
Summary
$indexvariable resolution in range loopsexecuteRangeBodyWithVarsstored range variables with the$prefix, causingbuildExecDatato construct"$$index"patterns that never matched{{$index}}in templates{{$index | printf "#%d"}}now correctly resolves to"#0","#1", etc. instead of empty strings""Test plan
-update-goldenflag against the fixed core libraryTestTemplate_E2E_CompleteRenderingSequencesubtests pass with updated goldens🤖 Generated with Claude Code