This is the current .gwdk language contract for the experimental 0.x line. It
describes implemented and partial syntax only as far as the compiler supports
it today. Planned syntax is listed so unsupported source can fail clearly
instead of becoming accidental behavior.
Detailed behavior stays in the feature pages linked from GOWDK Language.
Status Terms
- Implemented: accepted by the current compiler and covered by tests or a documented verification command.
- Partial: accepted for a narrower slice than the final contract.
- Planned: accepted direction, but not stable source behavior.
- Unsupported: intentionally rejected or not accepted by the current parser.
File Model
.gwdk files are package-peer source files. They live beside normal .go
files and declare the same Go package name:
package pages
The package declaration must be the first non-comment declaration. GOWDK source files do not derive route identity from folders.
Current file kinds:
- Page files declare
@routeandview {}.@guardis optional but a page is not public by default (see below). They may declare@pagewhen they need an explicit stable page ID. - Component files declare
@componentand usuallyview {}. - Layout files take their identity from the file name (
root.layout.gwdkdeclares the layoutroot) and declareview {}with exactly one<slot />. They may declare@layoutto name the parent layout(s) they nest within.
Planned or partial file kinds:
- API-only files are planned separately. Current pages still own a page
GETroute and must declareview {}. - Island-only and plugin-adjacent files are not separate stable file kinds yet.
Comments
Line comments start with //. Empty lines and line comments are ignored by the
metadata parser outside block bodies.
Annotations
Annotations start with @ at the beginning of the trimmed line.
Implemented or partial annotations:
@page <id>@route "<path>"@title "<text>"@description "<text>"@canonical "<url>"@image "<url>"@layout <id>[, <id>...]@cache "<policy>"@revalidate <seconds|duration>@error "<path.html>"@guard <id>[, <id>...]@component <Name>
Unknown annotations are errors. Malformed @ lines are errors.
@guard is optional on page sources, but a page is not public by default. A
guardless page builds with a missing_page_guard warning and its route is
denied (403) at request time until access is stated. Use @guard public to
serve a page on purpose, or custom/RBAC guard IDs such as role:admin when the
page is protected. The full access contract — default-deny enforcement,
paths {} and SSR coverage, and the backend-endpoint rule — lives in
guards.md.
@page is optional for file-backed page sources. When omitted, the compiler
derives the page ID from the source filename by removing .page.gwdk or
.gwdk. For example, src/pages/blog-post.page.gwdk derives page ID
blog-post. Add @page blog.post when a route, filename, or file location
change must not change page identity.
Imports And Uses
Go imports bind normal Go packages for build data, component props/state, and handler references:
import interop "github.com/acme/app/interop"
import "github.com/acme/app/ui"
GOWDK use declarations bind discovered .gwdk source packages for
cross-package component calls:
use ui "components"
Go imports do not import .gwdk files. use values are package names from
discovered GOWDK sources, not Go import paths.
Routes
Routes are explicit:
@route "/patients/{id:int}"
Current route rules:
- Routes must start with
/. /is the only route that may end with/.- Query strings, fragments, backslashes, whitespace, control characters, empty
segments,
., and..are invalid. - Dynamic params are whole segments such as
{slug}or{id:int}. - Param names use Go-like identifier spelling.
- Supported param types are
string,int,int64,uint,uint64,bool, andfloat64. - Duplicate params in one route are invalid.
- Duplicate route patterns are invalid.
Dynamic SPA routes require paths {} unless the page selects request-time
rendering with load {} or go ssr {}.
Blocks
Implemented or partial top-level blocks:
paths {}: build-time dynamic SPA path declarations.build {}: build-time page data.load {}: request-time page data; requires the SSR addon.view {}: page, component, or layout markup.style {}: component/page-local CSS body capture.go {}: optional same-package Go extraction.go ssr {}: optional request-time load-handler extraction.go client {}: optional browser-side Go WASM mount extraction.go addon.<name> {}: addon-owned Go block validation and emission.js "<relative-file.js|.mjs|.ts>": scoped browser module asset.js {}: inline scoped browser module asset for small cases.
Unsupported top-level block declarations that look like name ... { are
rejected until their feature slice is implemented.
Build-Time Data
paths {} supports the first literal record subset:
paths {
=> { slug: "hello-gowdk" }
}
build {} supports literal records, references to earlier fields, route
params, and no-argument Go function calls from imported or same-package Go:
build {
=> { title: "Hello", count: 2 }
=> FeaturedCopyForBuild()
=> interop.FeaturedCopyForBuild()
}
Arbitrary build-time Go statements are not stable source behavior.
Request-Time Data
load {} selects the request-time page lane and requires SSR to be enabled.
Generated SSR supports declared field placeholders and same-package Go load
functions through ssr.LoadContext for the current slice.
go ssr {} can provide generated SSR load handlers when request-time rendering
is enabled.
Endpoints
Actions and APIs are top-level endpoint declarations:
act Submit POST "/signup"
api Health GET "/api/health"
Endpoint-local error pages are supported:
act Submit POST "/signup" @error "/errors/signup.html"
Current rules:
- Action methods are currently
POST. - API methods support
GET,POST,PUT,PATCH, andDELETE. - Declarations name exact exported Go handler symbols.
- Behavior lives in normal same-package Go handlers or supported extracted Go blocks.
- Old
act name { ... }andapi name { ... }blocks are rejected with migration diagnostics.
View Markup
view {} supports the current GOWDK markup subset:
- Lowercase HTML elements.
- Text and quoted attribute interpolation.
- Escaped text and attributes by default.
- Self-closing component calls.
- Same-package component calls by bare component name.
- Cross-package component calls through
usealiases. - Shorthand class and id attributes on HTML elements.
- Boolean attributes and first-slice expression attributes.
<slot />in layouts and components.- First-slice form enhancement directives such as
g:post,g:target, andg:swap. - First-slice local island directives such as
g:on:*andg:island. - The explicit
g:html={Expr}raw HTML directive on non-void elements.
view {} expands only through GOWDK-owned AST nodes and g: directives. The
current parser does not implement arbitrary external template semantics.
Unsupported template tags and unknown g: directives must fail with
diagnostics (unsupported_markup_syntax and unsupported_markup_directive
message families) rather than being treated as raw HTML or silently ignored.
Components
Components use @component <Name>. They can define props and state contracts
through imported Go types and can render same-package or use-qualified child
components.
Current component support is partial:
- String-like props and first typed Go prop/state contracts are supported.
- Component CSS and assets can be scoped and emitted.
- Component-level
@wasmcan emit browser WASM island assets. - Rich non-string props, broad lifecycle behavior, child-to-parent events, and a full reactive graph are planned.
Scoped JavaScript
Scoped browser modules are explicit source declarations:
js "./dashboard.ts"
js {
console.log("loaded")
}
Path-based modules are preferred. Script declarations are page- or component-scoped. TypeScript is transform-only; GOWDK does not type-check it. Bundling, minification, import-graph following, and JavaScript tree shaking are not implemented.
Generated JavaScript is enhancement only. It must not own routing truth, auth, trusted validation, server state, business rules, or cache policy.
Raw HTML Policy
Generated HTML escapes text and attributes by default; that default is
unchanged. The one explicit, stable escape hatch is the GOWDK-owned
g:html={Expr} element directive: the element's attributes stay escaped and
the expression's resolved string is written as the element content without
escaping. Only trusted or sanitized HTML may be fed to g:html; see
markup.md for the full contract and restrictions. Raw HTML syntax
from other template languages, such as {@html ...}, remains unsupported and
fails loudly with guidance toward g:html.
Diagnostics Policy
Compiler failures should include a diagnostic code, source position, source range when known, severity, message, and short suggestion when useful. Current public diagnostics are listed in diagnostics.md and Diagnostics Reference.
Parser recovery is still partial. parse_error remains the broad parser code
until more specific parser diagnostics are stabilized.
Compatibility Policy
During 0.x, public contracts can still change. Compatibility rules for language work:
- Implemented syntax should keep tests or documented verification.
- Partial syntax must stay labeled partial in docs.
- Planned syntax must not be silently accepted as generated behavior.
- Deprecated syntax should fail with migration diagnostics before removal.
- Unsupported syntax should fail before generated output is accepted.
- Docs must change in the same commit as behavior changes.