2026-02-19 17:42:08 +00:00
# CLAUDE.md
2026-03-13 13:38:01 +00:00
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
2026-03-22 01:28:30 +00:00
Agent instructions for `go-html` . Module path: `dappco.re/go/core/html`
2026-02-19 17:42:08 +00:00
## Commands
```bash
2026-02-20 15:01:55 +00:00
go test ./... # Run all tests
go test -run TestName ./... # Single test
go test -short ./... # Skip slow WASM build test
go test -bench . ./... # Benchmarks
2026-03-13 13:38:01 +00:00
go test -bench . -benchmem ./... # Benchmarks with alloc stats
2026-02-20 15:01:55 +00:00
go vet ./... # Static analysis
GOOS=js GOARCH=wasm go build -ldflags="-s -w" -o gohtml.wasm ./cmd/wasm/ # WASM build
2026-03-13 13:38:01 +00:00
make wasm # WASM build with size gate
2026-02-20 15:01:55 +00:00
echo '{"H":"nav-bar","C":"main-content"}' | go run ./cmd/codegen/ # Codegen CLI
2026-02-19 17:42:08 +00:00
```
## Architecture
2026-02-20 15:01:55 +00:00
See `docs/architecture.md` for full detail. Summary:
2026-03-13 13:38:01 +00:00
- **Node interface**: `Render(ctx *Context) string` — El, Text, Raw, If, Unless, Each[T], EachSeq[T], Switch, Entitled
- **HLCRF Layout**: Header/Left/Content/Right/Footer compositor with ARIA roles and deterministic `data-block` IDs. Variant string (e.g. "HCF", "HLCRF", "C") controls which slots render. Layouts nest via clone-on-render (thread-safe).
- **Responsive**: Multi-variant breakpoint wrapper (`data-variant` attributes), renders all variants in insertion order
2026-02-20 15:01:55 +00:00
- **Pipeline**: Render → StripTags → go-i18n/reversal Tokenise → GrammarImprint (server-side only)
- **Codegen**: Web Component classes with closed Shadow DOM, generated at build time by `cmd/codegen/`
2026-03-17 08:21:15 +00:00
- **WASM**: `cmd/wasm/` exports `renderToString()` only — size gate: < 3.5 MB raw , < 1 MB gzip
2026-02-20 08:29:54 +00:00
## Server/Client Split
2026-02-20 15:01:55 +00:00
Files guarded with `//go:build !js` are excluded from WASM:
- `pipeline.go` — Imprint/CompareVariants use `go-i18n/reversal` (server-side only)
2026-02-20 08:29:54 +00:00
- `cmd/wasm/register.go` — encoding/json + codegen (replaced by `cmd/codegen/` CLI)
2026-03-13 13:38:01 +00:00
**Critical WASM constraint**: Never import `encoding/json` , `text/template` , or `fmt` in WASM-linked code (files without a `!js` build tag). Use string concatenation instead of `fmt.Sprintf` in `layout.go` , `node.go` , `responsive.go` , `render.go` , `path.go` , and `context.go` . The `fmt` package alone adds ~500 KB to the WASM binary.
2026-02-19 17:42:08 +00:00
## Dependencies
2026-03-22 01:28:30 +00:00
- `dappco.re/go/core/i18n` (replace directive → local go-i18n)
- `forge.lthn.ai/core/go-inference` (indirect, via go-i18n; not yet migrated)
- `forge.lthn.ai/core/go-log` (indirect, via go-i18n; not yet migrated)
2026-03-13 13:38:01 +00:00
- Both `go-i18n` and `go-inference` must be cloned alongside this repo for builds
- Go 1.26+ required (uses `range` over integers, `iter.Seq` , `maps.Keys` , `slices.Collect` )
2026-02-19 17:42:08 +00:00
## Coding Standards
2026-03-13 13:38:01 +00:00
- UK English (colour, organisation, centre, behaviour, licence, serialise)
- All types annotated; use `any` not `interface{}`
2026-02-19 17:42:08 +00:00
- Tests use `testify` assert/require
2026-02-20 15:01:55 +00:00
- Licence: EUPL-1.2 — add `// SPDX-Licence-Identifier: EUPL-1.2` to new files
2026-03-13 13:38:01 +00:00
- Safe-by-default: HTML escaping via `html.EscapeString()` on Text nodes and attribute values, void element handling, entitlement deny-by-default
- Deterministic output: sorted attributes on El nodes, reproducible block ID paths
2026-03-17 08:21:15 +00:00
- Errors: use `log.E("scope", "message", err)` from `go-log` , never `fmt.Errorf`
- File I/O: use `coreio.Local` from `go-io` , never `os.ReadFile` /`os.WriteFile`
2026-02-20 15:01:55 +00:00
- Commits: conventional commits + `Co-Authored-By: Virgil <virgil@lethean.io>`
2026-02-19 17:42:08 +00:00
## Test Conventions
2026-03-13 13:38:01 +00:00
Use table-driven subtests with `t.Run()` . Integration tests that use `Text` nodes must initialise i18n before rendering:
```go
svc, _ := i18n.New()
i18n.SetDefault(svc)
```