Skip to main content

structpages-lint

structpages-lint is a static analyzer for structpages projects. It is the primary guard behind the rule of thumb: never write an in-app URL as a string literal — resolve it by page type so renames break CI instead of drifting.

Install and run

go install github.com/jackielii/structpages/tools/lint/cmd/structpages-lint@latest
structpages-lint ./...

Wire it into CI alongside go test. If your project uses build tags, pass them through with -tags.

What it checks

CategoryWhat it flags
urlforstructpages.URLFor chain/composition errors — unknown child type, fragment-before-step, ambiguous bare lookups.
refstructpages.Ref(...) strings that don't resolve to a page-tree node — including refs stored in struct fields and vars (e.g. a nav table).
id, idtargetstructpages.ID / IDTarget method expressions whose receiver is not mounted as a page.
paramsURLFor params that don't appear in the route pattern.
url-attrURL-bearing HTML attributes in .templ files (href, action, formaction, hx-{get,post,put,patch,delete}, hx-{push,replace}-url) whose values are hard-coded internal paths, string concats, or fmt.Sprint* calls. Allows https://, mailto:, #, and protocol-relative //… externals.
route-literal.go string literals whose value exactly equals a mounted route — e.g. return "/admin/queues" — where you should resolve by page type via URLFor. Deliberately narrow: exact concrete-route matches only; comparisons (==/switch) and Ref(...) args are skipped; _test.go and generated files are skipped.

Suppressing a diagnostic

Place the directive on the same line or the line above. Prefer //-style in both .go and .templ — Go-style comments are stripped from generated HTML, while <!-- … --> HTML comments render into every response:

//structpages:lint:ignore route-literal
return "/legacy-path"
// structpages:lint:ignore url-attr
<a href="/legacy">…</a>

Multiple categories are comma-separated; a bare structpages:lint:ignore suppresses every category on the targeted line.

What lint can't see

Static analysis can't follow URLs assembled from runtime data or refs behind dynamic dispatch. For those, add a boot-time validation inventory — see URLFor & ID → Validation.