render

package
v0.30.0 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: AGPL-3.0 Imports: 7 Imported by: 0

Documentation

Overview

Package render parses awf section markers and renders templates with per-project overlays via text/template.

Index

Constants

View Source
const SectionDefaultSentinel = "\x00awf:section-default\x00"

SectionDefaultSentinel is the brace-free, NUL-delimited token the project layer substitutes for the {{=awf:sectionDefault}} placeholder (ADR-0072). Assemble splits a part body at each occurrence and splices the section's raw default source between the verbatim fragments, so Execute renders the default in place. Brace-free (inert to the template parser) and NUL-delimited (cannot collide with template or markdown text).

Variables

This section is empty.

Functions

func Assemble

func Assemble(segs []Segment, plan map[string]SectionPlan, style CommentStyle) (string, map[string]string)

Assemble applies the per-section plan to the parsed segments and returns the template skeleton plus a sentinel→raw-body map. Literal segments pass through verbatim; each non-dropped section is prefixed with its awf:edit pointer, then either a sentinel standing in for its part body (restored after Execute) or the template default. Section markers are consumed here and never written. touches-state: rendering/render-engine:no-section-marker-leak - section markers consumed, never written; proof in render_test.go

func CheckResidualMarkers added in v0.10.0

func CheckResidualMarkers(assembled string) error

CheckResidualMarkers hard-errors when an assembled skeleton still contains a marker-shaped awf:section/awf:end token - a malformed marker (unknown attribute, missing name) that ParseSections could not consume and that would otherwise leak verbatim into rendered output. It runs pre-Execute: part bodies are NUL sentinels and data is uninterpolated, so parts and data that quote the full comment form stay out of scope. touches-state: rendering/render-engine:no-residual-section-marker - hard error on surviving marker residue; proof in section_test.go

func CheckSectionDefaultStubs added in v0.11.0

func CheckSectionDefaultStubs(segs []Segment, plan map[string]SectionPlan) error

CheckSectionDefaultStubs hard-errors when a part re-injects the default of a stub-attributed section (ADR-0072 Decision 4): a stub default is an authoring prompt, not shippable prose, so there is nothing valid to re-inject and the section must stay in must-author state. Runs pre-Assemble on the same segs+plan StubSections consumes; it scans the substituted part body for the render-layer sentinel, since planSections has already replaced the {{=awf:sectionDefault}} token.

func Execute

func Execute(assembled string, data map[string]any, parts map[string]string, name string) (string, error)

Execute runs text/template over the awf-owned skeleton (part bodies stood in by sentinels) under missingkey=zero, then restores each raw part body verbatim - so a convention part is never parsed or executed as a template. name labels parse and execute errors with the target rather than a hardcoded literal. touches-state: rendering/render-engine:parts-raw-except-authoring-comments - part bodies restored verbatim post-strip, never templated; proof in render_test.go

func ExpandIncludes added in v0.6.2

func ExpandIncludes(src string, partialFS fs.FS) (string, error)

ExpandIncludes replaces each `<!-- awf:include NAME -->` directive line in src with the verbatim body of the awf-owned partial `partials/NAME.md`, read from partialFS. Expansion runs before section parsing, so spliced content is thereafter indistinguishable from inline template text. Three conditions are hard errors: a missing partial, a partial that itself contains an awf:include (nested includes are unsupported), and a partial that contains an awf:section/awf:end marker (overlay across a splice boundary is unspecified). touches-state: rendering/render-engine:include-splice - include-directive splice site; proof in include_test.go touches-state: rendering/render-engine:include-missing-fails - missing-partial hard error; proof in include_test.go touches-state: rendering/render-engine:include-no-nested - nested-include rejection; proof in include_test.go touches-state: rendering/render-engine:include-no-sections - section-marker-in-partial rejection; proof in include_test.go

func HasMarkerLine added in v0.12.0

func HasMarkerLine(body string) bool

HasMarkerLine reports whether body contains a line that, after trimming, begins with a marker-shaped `awf:section`/`awf:end` comment opener - the ADR-0083 whole-line detection behind the part-marker advisory. The prefix anchor covers the exact closed marker, an unclosed opener, and a marker with trailing text: none has a legitimate quoter, since prose quoting the form always precedes it on the line. Inline quoting never fires; the awf:stub part marker is out of scope by construction (the pattern names only section/end). Callers exclude fenced code before the scan. touches-state: rendering/render-engine:part-marker-advisory - whole-line section-marker residue detection; proof in section_test.go

func HasStubMarker added in v0.10.0

func HasStubMarker(body string) bool

HasStubMarker reports whether a part body contains a line that is exactly the awf:stub marker (modulo surrounding whitespace). Detection never mutates the body - parts render byte-for-byte verbatim, marker included (ADR-0034, ADR-0070). touches-state: rendering/render-engine:stub-part-verbatim - stub-marker detection without mutation; proof in section_test.go

func PlaceholderVarRefs added in v0.13.0

func PlaceholderVarRefs(body string) []string

PlaceholderVarRefs returns the config vars a raw convention-part body consumes through {{=awf:key}} placeholders - gateCmd and checkCmd are the only registry keys that read vars (see project.placeholderRegistry). Scanned on the on-disk bytes: substitution has already replaced the tokens in the assembled output, so this is the one consumption channel the assembled-source scan cannot see (ADR-0086 Decision 3). A backslash-escaped token (ADR-0058) renders literally and reads no var, so it is stripped before matching.

func PointerLinePrefixes added in v0.18.0

func PointerLinePrefixes(name string, style CommentStyle) []string

PointerLinePrefixes returns the awf:edit-family pointer line prefixes (the awf:edit and awf:edit-in-place variants) for a section named `name` in the given comment style, up to and including the `: ` separator. Every editPointer variant emits `<open>awf:edit[-in-place] <name>: ...`, so a trimmed output line is that section's pointer iff it begins with one of these prefixes. Read-back matches a region boundary by these exact per-section strings, never a generic pointer shape, so adopter text resembling a pointer for a non-registered name cannot bound a region (ADR-0100 Decision 2 / in-place-readback).

func ReferencedDataKeys added in v0.13.0

func ReferencedDataKeys(src string) []string

ReferencedDataKeys returns the sorted, de-duplicated list of top-level sidecar data keys referenced via {{ .data.K }} patterns in src (ADR-0086). Nested access (.data.a.b) claims its top-level key.

func ReferencedVars

func ReferencedVars(src string) []string

ReferencedVars returns the sorted, de-duplicated list of variable names referenced via {{ .vars.X }} patterns in src.

func ReferencesBareData added in v0.13.0

func ReferencesBareData(src string) bool

ReferencesBareData reports whether src reads .data without a key selector (range/with/index or a whole-map reference). Key-level extraction cannot see through such access, so it conservatively marks every data key consumed (ADR-0086 Decision 4). No shipped template uses the form; this is the future-proofing escape.

func ReferencesBareVars added in v0.13.0

func ReferencesBareVars(src string) bool

ReferencesBareVars mirrors ReferencesBareData for the vars namespace (ADR-0086 Decision 3).

func ReferencesCommitPolicy added in v0.30.0

func ReferencesCommitPolicy(src string) bool

ReferencesCommitPolicy reports whether a non-comment template action reads the typed commit-policy render context.

func ReferencesScopePlaceholder added in v0.8.0

func ReferencesScopePlaceholder(body string) bool

ReferencesScopePlaceholder reports whether a raw convention-part body uses a {{=awf:commitScope*}} sandbox placeholder (ADR-0057), so the artifact folds the resolved scope list into its config hash and reflags on a scopes edit.

func ReferencesScopes added in v0.6.0

func ReferencesScopes(src string) bool

ReferencesScopes reports whether src reads the resolved commit-scope render context (any {{ ... .commitScopes ... }} action) - such templates fold the resolved scope list into their config hash (ADR-0051, mirroring ADR-0046's ReferencesSkills).

func ReferencesSkills added in v0.6.0

func ReferencesSkills(src string) bool

ReferencesSkills reports whether src reads the enabled-skills render context (any {{ ... .skills... }} action) - such templates fold the effective skills set into their config hash (ADR-0046).

func StripAuthoringComments added in v0.18.0

func StripAuthoringComments(src string) (string, error)

StripAuthoringComments removes whole-line awf:comment authoring directives from src: a line whose trimmed form opens with the exact commentOpen literal at a token boundary (followed by a space, a tab, "-->", or the end of the line) and ends with "-->" is removed together with its trailing newline. Fenced code blocks are preserved verbatim, so a part or template can demonstrate the syntax. A whole line outside a fence that opens at the boundary but does not end with "-->" - a missing close, the bare opener, or text trailing the close - is a hard error; the input is returned unchanged alongside it. Mid-line occurrences and prefix-sharing tokens (awf:commentary) never fire.

func StubSections added in v0.10.0

func StubSections(segs []Segment, plan map[string]SectionPlan) (defaults, parts []string)

StubSections reports a parsed template's unauthored stub content under a plan (ADR-0070): defaults = stub-attributed sections rendering their template default; parts = sections whose convention part carries the awf:stub marker. Dropped sections report nothing.

Types

type CommentStyle added in v0.18.0

type CommentStyle int

CommentStyle is the comment syntax a rendered target uses for the surviving awf:edit-family provenance pointers. Because the pointers survive into output as comments, they must be valid comments in the target's language (ADR-0100 Decision 7): a `#`-line comment for a `#!`-shebang target such as a shell script, an HTML comment otherwise. The zero value is HTMLComment, the historical default.

const (
	HTMLComment  CommentStyle = iota // <!-- <text> -->
	HashComment                      // # <text>
	SlashComment                     // // <text>
)

func CommentStyleForSource added in v0.18.0

func CommentStyleForSource(src string) CommentStyle

CommentStyleForSource picks the pointer comment style for a target from its (expanded) template source, by the same `#!`-shebang sniff injectBanner uses so the pointer emitter and the read-back matcher derive the style identically and cannot diverge (ADR-0100 Decision 7).

type SectionPlan

type SectionPlan struct {
	Drop     bool
	HasPart  bool
	PartBody string
	// PartStub marks a part body carrying the whole-line awf:stub marker -
	// declared-unauthored starter content (ADR-0070). Set by the project layer,
	// which reads part bodies; consumed by StubSections.
	PartStub bool
	// PartMarker marks a part whose raw, fence-excluded body carries a
	// whole-line section-marker residue (ADR-0083). Set by the project layer
	// over the on-disk bytes - pre placeholder substitution, whose multi-line
	// values must never create or mask a match; consumed part-keyed by the
	// marker advisory.
	PartMarker bool
	// PartVarRefs lists the config vars the raw part body consumes via
	// {{=awf:key}} placeholders (ADR-0086). Set by the project layer over
	// the on-disk bytes; consumed by the unused-var union, which cannot see
	// part bodies in the assembled source (they are sentinel-substituted raw).
	PartVarRefs []string
	EditPath    string
	// InPlace marks a section whose body the adopter edits directly in the
	// rendered output, preserved across syncs (ADR-0100). Mutually exclusive
	// with HasPart. InPlaceFound reports whether the section's region was located
	// in the existing output (its pointer was present); InPlaceBody is that
	// region's read-back content (possibly empty - an adopter may empty the
	// region). When InPlaceFound is false (first render / deleted pointer) the
	// template default renders instead; a found-but-empty region stays empty, so
	// emptying a region is not silently reverted to the default (ADR-0100 Decision 2).
	InPlace      bool
	InPlaceFound bool
	InPlaceBody  string
}

SectionPlan is the project layer's per-section resolution handed to Assemble. Exactly one of Drop / HasPart / (neither) holds: Drop omits the section, HasPart substitutes PartBody, neither renders the template default. EditPath is the project-relative convention part path named by the awf:edit pointer.

type Segment

type Segment struct {
	IsSection bool
	Name      string
	Text      string
	// Stub marks a section whose template default is a must-replace authoring
	// prompt, declared by the `stub` marker attribute (ADR-0070).
	Stub bool
	// InPlace marks a section declared by the `inplace` marker attribute
	// (ADR-0100); its body is read back from the rendered output rather than a
	// convention part, and preserved across syncs. Mutually exclusive with Stub.
	InPlace bool
}

func ParseSections

func ParseSections(src string) []Segment

ParseSections splits src into ordered literal and section segments. Marker lines are consumed; a section segment's Text is the inner body.

Jump to

Keyboard shortcuts

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