templates

package
v0.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package templates owns the embedded forge template tree and renders it into scaffolded code.

The behavioural seam exposed by the package is the Service interface: callers (codegen, generator, packs, docs) hold a Service handle and ask it to render a template by category + name. The data carriers (TemplateCategory, TemplateEngine, *TemplateData structs) are utility types kept on the package surface for backward compatibility with scaffolders that walk individual category trees.

Code generated by forge. DO NOT EDIT. forge:hash=69d6efa4fa00677c778cdc4f91980492ae4e077344705c1959a78ee71faa2f41 forge-owned: regenerated every run — do not edit (forge disown to take ownership) Source: contract.go in this package.

To customize: edit contract.go (the interface IS the public surface) and re-run "forge generate". This file is regenerated unconditionally.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FuncMap

func FuncMap() template.FuncMap

FuncMap returns the shared template function map used across all templates.

func ListInternalPackageKindTemplates

func ListInternalPackageKindTemplates(kind string) ([]string, error)

ListInternalPackageKindTemplates lists template files for a specific internal-package kind subdirectory (e.g. "client", "eventbus").

func RenderFromFS

func RenderFromFS(fsys fs.FS, basePath, name string, data interface{}) ([]byte, error)

RenderFromFS renders a template from an arbitrary fs.FS. It reads the file at basePath/name, and if the name has a .tmpl suffix it parses and executes it with the shared FuncMap. Non-.tmpl files are returned as-is. Any //go:build ignore directives are stripped from the output.

This is the canonical template-rendering function used by both the built-in template helpers and the pack system.

func RenderInternalPackageKindTemplate

func RenderInternalPackageKindTemplate(kind, name string, data interface{}) ([]byte, error)

RenderInternalPackageKindTemplate renders a template from a kind subdirectory of the internal-package templates.

func RenderInternalPackageTemplate

func RenderInternalPackageTemplate(name string, data interface{}) ([]byte, error)

RenderInternalPackageTemplate renders a base internal-package template.

Types

type BuildImagesWorkflowData

type BuildImagesWorkflowData struct {
	ProjectName  string
	Registry     string // "ghcr", "gar"
	HasFrontends bool
	VulnDocker   bool // trivy scanning
}

BuildImagesWorkflowData holds data for the build-images workflow template.

type CIExtraJob

type CIExtraJob struct {
	Name   string
	Needs  []string
	RunsOn string
	Steps  []CIExtraStep
}

CIExtraJob defines an additional user-specified CI job.

type CIExtraStep

type CIExtraStep struct {
	Name string
	Run  string
	Uses string
	With map[string]string
}

CIExtraStep is a single step inside an extra CI job.

type CIWorkflowData

type CIWorkflowData struct {
	ProjectName  string
	GoVersion    string // e.g. "1.26"
	HasFrontends bool
	Frontends    []FrontendCIConfig // from project config
	HasServices  bool

	// Lint
	LintGolangci        bool
	LintBuf             bool
	LintBufBreaking     bool
	LintFrontend        bool
	LintFrontendStyles  bool
	LintMigrationSafety bool

	// Test
	TestRace     bool
	TestCoverage bool

	// Vuln scan
	VulnGo     bool // govulncheck
	VulnDocker bool // trivy
	VulnNPM    bool // npm audit

	// License compliance
	LicenseCheck bool // go-licenses

	// E2E
	E2EEnabled bool
	E2ERuntime string // "docker-compose" or "k3d"

	// Permissions
	PermContents string // default "read"

	// Extra jobs
	ExtraJobs []CIExtraJob

	// Deploy-related
	HasKCL    bool // validate KCL manifests
	HasDocker bool // emit docker-build job (project has a Dockerfile)
	// VerifyGenerated controls whether the verify-generated job is emitted.
	// Service projects always emit it (forge regenerates handlers/middleware
	// and we want CI to flag drift). CLI/library projects have very little
	// generated output worth verifying, so the job is suppressed.
	VerifyGenerated bool

	// Environments (for KCL validation)
	Environments []string

	// Legacy fields used by other CI templates (build-images, deploy, dependabot)
	Module       string
	Registry     string // "ghcr", "gar", "ecr"
	GithubOrg    string
	FrontendName string // first frontend name for dependabot

	// GitHubOwner is the inferred GitHub owner for default CODEOWNERS entries.
	// Empty when we couldn't confidently infer one (e.g. non-github module
	// path), in which case the CODEOWNERS template emits no file contents and
	// the generator drops the file. Populated by the generator from the
	// project's module path (e.g. "github.com/example/demo" -> "example").
	GitHubOwner string

	// ForgeVersion is the version of the forge CLI that produced the scaffold.
	// Used to pin `go install` in the verify-generated CI job so the
	// regeneration step is reproducible across runs. Empty or "dev" falls
	// back to ForgeGitCommit (when known), then to the pinned default.
	ForgeVersion string

	// ForgeGitCommit is the git commit SHA the forge binary was built from.
	// Used as a fallback for `go install` pinning when ForgeVersion is "dev"
	// (local builds). A full SHA is a valid `go install ...@<ref>` target,
	// so dev-built scaffolds remain reproducible.
	ForgeGitCommit string
}

CIWorkflowData holds data for the spec-driven CI workflow template.

type DeployEnv

type DeployEnv struct {
	Name       string // "staging", "preprod", "prod"
	Auto       bool   // auto-deploy after image build
	Protection bool   // GitHub environment protection
	URL        string // environment URL
}

DeployEnv represents a single deploy environment (e.g. staging, prod).

type DeployWorkflowData

type DeployWorkflowData struct {
	ProjectName      string
	Environments     []DeployEnv // ordered: staging, preprod, prod
	Registry         string      // "ghcr", "gar", "ecr"
	HasFrontends     bool
	FrontendDeploy   string // "firebase", "vercel", "none"
	MigrationTest    bool   // test migrations before deploy
	Concurrency      bool   // per-env concurrency groups
	CancelInProgress bool
}

DeployWorkflowData holds data for the deploy workflow template.

type Deps

type Deps struct{}

Deps is the dependency set for the templates Service. Empty today; the package owns its embedded FS and has no external collaborators.

type E2EWorkflowData

type E2EWorkflowData struct {
	ProjectName  string
	GoVersion    string
	Runtime      string // "docker-compose" (default) or "k3d"
	HasFrontends bool
	// FrontendPath points the setup-node `node-version-file` input at a
	// package.json whose `engines.node` is honored by setup-node@v4. Empty
	// when there are no frontends — the template then falls back to a
	// fixed node-version.
	FrontendPath string
}

E2EWorkflowData holds data for the standalone E2E test workflow template.

type FrontendCIConfig

type FrontendCIConfig struct {
	Name string
	Path string
}

FrontendCIConfig is a minimal frontend descriptor for CI templates.

type FrontendTemplateData

type FrontendTemplateData struct {
	FrontendName string
	ProjectName  string
	// ApiUrl / ApiPort / ApiPackage are exposed to text/template files
	// under internal/templates/frontend/. Renaming to APIUrl / APIPort /
	// APIPackage would force a coordinated rename of dozens of .tmpl
	// files (vite, react-native, nextjs scaffolds) and break any
	// downstream project that references {{.ApiUrl}} in a customized
	// template. Keep the mixed-case field names; the revive var-naming
	// rule is suppressed on each line.
	ApiUrl  string //nolint:revive // template field name; see comment above
	ApiPort string //nolint:revive // template field name; see comment above
	Module  string
	Pages   []NavPageData
	// NavHookImports is the per-module aggregation of the list hooks the
	// dashboard tiles consume. Derived from Pages by the nav generator.
	NavHookImports []NavHookImport
	// Workspaces reports whether the project opted into the pnpm-
	// workspaces layout. When true, frontend templates emit imports
	// of ApiPackage / HooksPackage instead of relative @/gen and
	// @/hooks paths, and the per-frontend package.json declares
	// "workspace:*" deps on those packages.
	//
	// When false (the default), templates produce the historic
	// single-frontend output — byte-identical to projects scaffolded
	// before workspaces landed. Snapshot tests rely on this.
	Workspaces bool
	// ApiPackage is the npm package name for the shared Connect TS
	// clients workspace, e.g. "@myapp/api". Empty when Workspaces is
	// false.
	ApiPackage string //nolint:revive // template field name; matches ApiUrl above
	// HooksPackage is the npm package name for the shared React Query
	// hooks workspace, e.g. "@myapp/hooks". Empty when Workspaces is
	// false.
	HooksPackage string
	// UIWebPackage is the npm package name for the shared web UI
	// component workspace, e.g. "@myapp/ui-web". Empty when Workspaces
	// is false. Frontend package.json templates declare a
	// "workspace:*" dep on this, and tsconfig templates redirect
	// `@/components/*` paths into the package via path mapping.
	UIWebPackage string
	// UINativePackage is the npm package name for the shared React
	// Native primitives workspace, e.g. "@myapp/ui-native". Empty
	// when Workspaces is false OR the project has no RN frontend.
	// React Native templates reference this in their package.json
	// workspace deps and example screens.
	UINativePackage string
	// Output selects the Next.js build/runtime shape. Mirrors
	// config.FrontendConfig.Output. Only the nextjs templates read it
	// (`next.config.ts.tmpl`); other template trees ignore it.
	//
	// Valid values rendered by templates:
	//   - "standalone" (default): emit `output: "standalone"`
	//     unconditionally — pairs with the shipped Dockerfile and
	//     supports the generated dynamic `[id]` CRUD routes.
	//   - "static":     emit `output: "export"` gated on
	//     NODE_ENV=production. Dev server stays unchanged. Opt-in
	//     only: static export fails `next build` on dynamic route
	//     segments without generateStaticParams, which the generated
	//     CRUD detail/edit pages cannot provide.
	//   - "server":     omit `output` entirely (full Next.js dev+prod).
	//
	// Empty string is treated as "standalone" by the template — callers
	// that don't thread this field get the scaffold default.
	Output string
	// BasePath mirrors config.FrontendConfig.BasePath — the URL prefix
	// the frontend is mounted under (e.g. "/admin"), or "" for root.
	// Read by the nextjs templates only:
	//
	//   - next.config.ts.tmpl renders it as the build-time default for
	//     `basePath` + `assetPrefix` (overridable via the single
	//     canonical env var NEXT_PUBLIC_BASE_PATH).
	//   - src/lib/basepath_gen.ts.tmpl bakes it as the fallback for
	//     BASE_PATH / joinBasePath().
	//
	// Already validated by config.LoadStrict (leading "/", no trailing
	// "/", [A-Za-z0-9._-] segments) — templates splice it verbatim into
	// TypeScript string literals.
	BasePath string
}

FrontendTemplateData holds data for frontend template rendering.

type MockService

type MockService struct {
	contractkit.Recorder
	RenderCategoryFunc            func(string, string, any) ([]byte, error)
	ListCategoryFunc              func(string, string) ([]string, error)
	RenderInternalPackageKindFunc func(string, string, any) ([]byte, error)
}

MockService is a test mock for the Service interface.

The embedded contractkit.Recorder records every call so tests can assert call counts and captured arguments. Set XxxFunc fields to override per-method behaviour; unset methods return the canonical "MockService.<Method>Func not set" error.

func (*MockService) ListCategory

func (m *MockService) ListCategory(category string, subdir string) ([]string, error)

func (*MockService) RenderCategory

func (m *MockService) RenderCategory(category string, name string, data any) ([]byte, error)

func (*MockService) RenderInternalPackageKind

func (m *MockService) RenderInternalPackageKind(kind string, name string, data any) ([]byte, error)
type NavHookImport struct {
	Module  string   // "@/hooks/task-service-hooks"
	Symbols []string // ["useListTasks", "useListProjects"] — sorted
}

NavHookImport is one merged import statement the dashboard template emits for list hooks: all hook symbols whose generated hooks file is the same module. Pre-grouped in Go so two entities served by one service don't produce duplicate import statements (import/no-duplicates).

type NavPageData struct {
	Label      string // display name, e.g. "Tasks"
	LabelLower string // lowercase for descriptions, e.g. "tasks"
	Slug       string // URL path segment, e.g. "tasks"
	// LabelSingular is the singular display name ("Task") — used by
	// "Create X" buttons. Derived from the proto entity name, not a
	// strip-the-trailing-s guess ("Categories" → "Category", not
	// "Categorie").
	LabelSingular string
	// HasCreate reports whether the page generator emitted a create page
	// (<slug>/new) for this entity. The dashboard's QuickActions grid
	// gates its "Create X" buttons on this — advertising a create route
	// the page generator never wrote is a guaranteed 404.
	HasCreate bool
	// ListHook is the generated React Query list hook name
	// ("useListTasks"); the dashboard tile uses it to render a real
	// entity count instead of a placeholder.
	ListHook string
	// HooksModule is the import path of the generated hooks file, e.g.
	// "@/hooks/task-service-hooks".
	HooksModule string
	// ItemsField is the camelCase repeated field on the list response
	// holding the entities ("tasks").
	ItemsField string
	// ComponentIdent is a valid TS identifier for per-entity generated
	// components ("Tasks" → TasksTile).
	ComponentIdent string
}

NavPageData describes a single page entry for the frontend navigation.

type Service

type Service interface {
	// RenderCategory renders the named template within the given category
	// (e.g. category="project", name="bootstrap.go.tmpl") with data and
	// returns the post-processed bytes.
	RenderCategory(category, name string, data any) ([]byte, error)

	// ListCategory returns all template paths under the named category,
	// optionally restricted to a sub-directory. Recursive walk.
	ListCategory(category, subdir string) ([]string, error)

	// RenderInternalPackageKind renders a template from an internal-package
	// kind sub-directory (e.g. kind="client", name="client.go.tmpl").
	RenderInternalPackageKind(kind, name string, data any) ([]byte, error)
}

Service is the behavioural surface of the templates package.

Operations are intentionally narrow: callers pick a category by name and ask for either a list of templates or a rendered template body. More specialised entry points (TemplateEngine, RenderFromFS) remain as package-level helpers because their inputs (pre-parsed template, custom fs.FS) make a uniform interface awkward.

func New

func New(_ Deps) Service

New constructs a templates.Service.

type TemplateCategory

type TemplateCategory struct {
	// contains filtered or unexported fields
}

TemplateCategory provides Get, Render, and List operations for a specific template directory within the embedded filesystem.

func CITemplates

func CITemplates(provider string) TemplateCategory

CITemplates returns a TemplateCategory for a specific CI provider.

func DeployTemplates

func DeployTemplates() TemplateCategory

DeployTemplates returns the category for deploy-scaffold templates.

func FrontendTemplates

func FrontendTemplates() TemplateCategory

FrontendTemplates returns the category for frontend-scaffold templates.

func IngressTemplates

func IngressTemplates() TemplateCategory

IngressTemplates returns the embedded Gateway API install assets (the Envoy Gateway VERSION pins + the vendored `eg` GatewayClass) keyed under `internal/templates/ingress/<provider>/`. The Envoy Gateway controller is installed via `helm` from the pinned gateway-helm chart, and the Gateway API CRDs are fetched from the upstream GitHub release at `forge cluster up` time and cached under ~/.cache/forge/ — see internal/cli/dev_cluster_ingress.go.

func InternalPkgKindTemplates

func InternalPkgKindTemplates(kind string) TemplateCategory

InternalPkgKindTemplates returns a TemplateCategory for a specific internal-package kind subdirectory.

func InternalPkgTemplates

func InternalPkgTemplates() TemplateCategory

InternalPkgTemplates returns the category for shared internal-package templates.

func MiddlewareTemplates

func MiddlewareTemplates() TemplateCategory

MiddlewareTemplates returns the category for middleware-scaffold templates.

func OperatorTemplates

func OperatorTemplates() TemplateCategory

OperatorTemplates returns the category for operator-scaffold templates.

func ProjectTemplates

func ProjectTemplates() TemplateCategory

ProjectTemplates returns the category for project-scaffold templates.

func ServiceTemplates

func ServiceTemplates() TemplateCategory

ServiceTemplates returns the category for service-scaffold templates.

func TestTemplates

func TestTemplates() TemplateCategory

TestTemplates returns the category for test-scaffold templates.

func WebhookTemplates

func WebhookTemplates() TemplateCategory

WebhookTemplates returns the category for webhook-scaffold templates.

func WorkerCronTemplates

func WorkerCronTemplates() TemplateCategory

WorkerCronTemplates returns the category for worker-cron-scaffold templates.

func WorkerTemplates

func WorkerTemplates() TemplateCategory

WorkerTemplates returns the category for worker-scaffold templates.

func (TemplateCategory) Get

func (c TemplateCategory) Get(name string) ([]byte, error)

Get returns the raw bytes of a template file. Any //go:build ignore directives are stripped from the output.

func (TemplateCategory) List

func (c TemplateCategory) List(subdir string) ([]string, error)

List returns all template names in the category (recursive).

func (TemplateCategory) ListFlat

func (c TemplateCategory) ListFlat(subdir string) ([]string, error)

ListFlat returns only direct children (non-recursive).

func (TemplateCategory) Render

func (c TemplateCategory) Render(name string, data interface{}) ([]byte, error)

Render executes a template with the given data and returns the result.

type TemplateEngine

type TemplateEngine struct {
	// contains filtered or unexported fields
}

TemplateEngine handles code generation from service/middleware templates. NOTE: TemplateEngine pre-parses templates for reuse via a singleton (see generator/project.go), while the TemplateCategory.Render method parses on each call. Both share FuncMap(). Consider consolidating if this becomes a maintenance burden.

func NewTemplateEngine

func NewTemplateEngine() (*TemplateEngine, error)

NewTemplateEngine creates a new template engine with all service and middleware templates pre-loaded.

func (*TemplateEngine) RenderTemplate

func (e *TemplateEngine) RenderTemplate(name string, data interface{}) (string, error)

RenderTemplate renders a template with the given data.

type WebhookRouteEntryData

type WebhookRouteEntryData struct {
	Name       string // kebab-case name for the URL path (e.g. "stripe")
	PascalName string // PascalCase name for the handler method (e.g. "Stripe")
}

WebhookRouteEntryData holds per-webhook data for route generation.

type WebhookRoutesTemplateData

type WebhookRoutesTemplateData struct {
	Package  string                  // Go package name (e.g. "billing")
	Webhooks []WebhookRouteEntryData // all webhooks for this service
}

WebhookRoutesTemplateData holds data for the webhook_routes_gen.go template.

type WebhookTemplateData

type WebhookTemplateData struct {
	Name           string // webhook name (e.g. "stripe", "github")
	ServiceName    string // target service display name (may contain hyphens)
	ServicePackage string // Go-package-safe form of ServiceName (snake_case)
	Module         string // Go module path
}

WebhookTemplateData holds data for webhook template rendering.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL