diff --git a/docs/engineering/decisions/0002-compile-first-render-model.md b/docs/engineering/decisions/0002-compile-first-render-model.md index 8ed6997c..4efe9c34 100644 --- a/docs/engineering/decisions/0002-compile-first-render-model.md +++ b/docs/engineering/decisions/0002-compile-first-render-model.md @@ -15,7 +15,6 @@ Core GOWDK renders at build time by default. SSR is an optional addon and a per- Render modes: - `spa`: build-time HTML. -- `action`: SPA page plus backend actions/API behavior. - `hybrid`: SPA by default with selected request-time behavior. - `ssr`: request-time full-page rendering through the SSR addon. @@ -34,7 +33,7 @@ Compiler rules: - Dynamic SPA routes require `paths {}`; action endpoints inherit generated concrete page paths. - `server {}` and `go server {}` require `ssr.Addon()`. -- `server {}` is rejected on SPA/action pages. +- `server {}` is rejected on SPA pages. - Actions can exist without SSR. - Partial updates are server fragments, not full-page SSR. diff --git a/docs/engineering/testing.md b/docs/engineering/testing.md index 84d5c341..5c34078c 100644 --- a/docs/engineering/testing.md +++ b/docs/engineering/testing.md @@ -58,7 +58,7 @@ must pass `--config `. | Runtime race detector | `scripts/test-runtime-race.sh` | Shared-state runtime packages, lifecycle, contracts, SSE, rate limiting, trace, or testkit changes. | | VS Code extension syntax | `node --check editors/vscode/extension.js` | Editor extension changes and broad verification. | | VS Code extension behavior | `node --test editors/vscode/*.test.js` | Editor extension pure helper changes and broad verification. | -| SPA/action examples | `go run ./cmd/gowdk check examples/pages/home.page.gwdk examples/actions/newsletter.page.gwdk` | Language/tooling changes. | +| SPA and action endpoint examples | `go run ./cmd/gowdk check examples/pages/home.page.gwdk examples/actions/newsletter.page.gwdk` | Language/tooling changes. | | Init project smoke | `go build -o /tmp/gowdk-cli ./cmd/gowdk && rm -rf /tmp/gowdk-init && /tmp/gowdk-cli init /tmp/gowdk-init && (cd /tmp/gowdk-init && /tmp/gowdk-cli build)` | CLI scaffold changes. | | Init project tests | `go build -o /tmp/gowdk-cli ./cmd/gowdk && rm -rf /tmp/gowdk-init-tested && /tmp/gowdk-cli init --tests /tmp/gowdk-init-tested && (cd /tmp/gowdk-init-tested && /tmp/gowdk-cli test --count=1 --timeout=2m)` | CLI scaffold or `gowdk test` changes. | | SSR example | `go run ./cmd/gowdk check --ssr examples/ssr/dashboard.page.gwdk` | SSR validation or example changes. | diff --git a/docs/language/api.md b/docs/language/api.md index dd04cca1..782c6251 100644 --- a/docs/language/api.md +++ b/docs/language/api.md @@ -179,4 +179,4 @@ Future API behavior must define: `func(context.Context, *http.Request) (response.Response, error)`. - Per-route body/query/result contracts and route-param accessors. - Per-endpoint CORS policy syntax and richer content negotiation. -- Interaction with SPA/action pages without full-page SSR. +- Interaction with SPA pages that declare backend endpoints without full-page SSR. diff --git a/docs/language/blocks.md b/docs/language/blocks.md index b1120ba2..189e89a3 100644 --- a/docs/language/blocks.md +++ b/docs/language/blocks.md @@ -17,7 +17,7 @@ The parser records whether these top-level blocks are present: statement forms are rejected with a `parse_error` diagnostic; arbitrary build-time statements remain planned. - `server {}`: request-time data block. Presence and raw body text are recorded, - then rejected on SPA/action pages. + then rejected on SPA pages. - `go {}` and `go target {}`: optional inline Go authoring blocks. Presence, target, raw body text, and source span are recorded. Default `go {}` can provide build-data functions called by @@ -68,7 +68,7 @@ api Health GET "/api/health" - `act` and `api` endpoint declarations describe request handlers that should work without full-page SSR. Normal Go handlers own behavior and return `runtime/response.Response`. -- `view {}` renders markup for spa, action, partial, and SSR output. +- `view {}` renders markup for SPA, partial, and SSR output. ## Style Blocks diff --git a/docs/language/partials.md b/docs/language/partials.md index 13e21e16..0cc68657 100644 --- a/docs/language/partials.md +++ b/docs/language/partials.md @@ -1,8 +1,8 @@ # Partials Partial updates use server fragments, not full-page SSR. The generated slice -supports action-driven fragment responses for SPA/action pages and standalone -concrete or dynamic fragment routes. +supports action-driven fragment responses for SPA pages and standalone concrete +or dynamic fragment routes. Current support: diff --git a/docs/product/requirements.md b/docs/product/requirements.md index 896a42e0..3ffc46b8 100644 --- a/docs/product/requirements.md +++ b/docs/product/requirements.md @@ -28,7 +28,7 @@ language references, compiler docs, and examples. | --- | --- | --- | --- | --- | | PRD-001 | Compile portable package-peer `.gwdk` files that declare `package`, optional `page`, `route`, `guard`, `layout`, blocks, and endpoints. | High | Partial | Discovery, package parsing, metadata parsing, parser syntax validation, filename-derived page IDs, default build discovery, route shape/conflict validation, required page-view and page-guard validation, explicit component-file build input, typed GOWDK AST, AST analyzer, versioned compiler IR, endpoint comment discovery, and endpoint conflict diagnostics are implemented; full downstream migration to the IR remains planned. | | PRD-002 | Default render mode must be `spa`. | High | Implemented | Root `RenderConfig.DefaultMode()` defaults to `gowdk.SPA`. | -| PRD-003 | Support render modes `spa`, `action`, `hybrid`, and `ssr`. | High | Implemented | Root `RenderMode` constants exist. | +| PRD-003 | Support render modes `spa`, `hybrid`, and `ssr`. | High | Implemented | Root `RenderMode` constants exist. Actions are endpoint capability, not a render mode. | | PRD-004 | Reject request-time page behavior unless the SSR feature is enabled in config or CLI options. | High | Implemented | `internal/compiler.ValidatePage` emits `missing_ssr_addon`. | | PRD-005 | Require `paths {}` for dynamic SPA routes. | High | Implemented | Dynamic SPA routes without paths are rejected; action endpoints on those pages inherit generated concrete page paths. Malformed routes, duplicate route params, duplicate page route patterns, and route-method conflicts are rejected; the first literal string `paths {}` subset can prerender dynamic SPA routes. | | PRD-006 | Keep typed actions available without SSR. | High | Partial | SPA pages with exported `act Name POST "/path"` endpoint declarations validate without SSR. Generated apps can serve POST action handlers with generated typed decoders, unexpected-field rejection, generated validation for direct literal `required`, `minlength`, `maxlength`, and supported anchored `pattern` form controls, bounded multipart action forms with explicit file count/size/MIME policy, generated validation fragments for partial requests, partial fragment responses, same-package action handlers using no-input, typed value, typed pointer, `form.Values`, or `form.Data` signatures returning `response.Response`, and generated CSRF token injection/validation by default unless `Build.CSRF.Disabled` is set. Upload storage/scanning/persistence and user-defined domain validation patterns remain in normal Go handlers. | diff --git a/docs/reference/config.md b/docs/reference/config.md index ef3ed352..5136d30e 100644 --- a/docs/reference/config.md +++ b/docs/reference/config.md @@ -348,7 +348,9 @@ artifacts from another module selection cannot be copied into the next binary. ## Render -`RenderConfig.Default` controls the default render mode. When omitted, default mode is `spa`. +`RenderConfig.Default` controls the default render mode. When omitted, default +mode is `spa`. Supported render modes are `spa`, `hybrid`, and `ssr`; actions +are endpoint declarations, not render modes. ## Env diff --git a/docs/reference/hooks.md b/docs/reference/hooks.md index 1132baac..ebf64a6e 100644 --- a/docs/reference/hooks.md +++ b/docs/reference/hooks.md @@ -183,7 +183,7 @@ contract): `fragment` endpoints, where it is a build error. - `guard public` marks intentional public access and cannot be combined with protected guard IDs. -- Non-public page guards on build-time SPA/action page routes fail validation; +- Non-public page guards on build-time SPA page routes fail validation; add `server {}` or `go server {}` with the SSR addon when the page itself is protected. - Guards run in declaration order. diff --git a/docs/reference/manifest.md b/docs/reference/manifest.md index b47510f2..817136d5 100644 --- a/docs/reference/manifest.md +++ b/docs/reference/manifest.md @@ -39,7 +39,7 @@ Current JSON shape: "source": "examples/actions/signup.page.gwdk", "kind": "page", "route": "/signup", - "render": "action", + "render": "spa", "artifacts": [ {"kind": "html", "path": "signup/index.html"} ], @@ -137,8 +137,8 @@ Fields: - `cssClasses`: optional sorted class names directly visible in literal `class` attributes. - `styleAttributes`: optional sorted literal inline `style` attribute values. -- `artifacts`: optional generated artifact path metadata. SPA and action - pages list the generated HTML path pattern relative to the build output +- `artifacts`: optional generated artifact path metadata. SPA pages list the + generated HTML path pattern relative to the build output directory, such as `index.html`, `newsletter/index.html`, or `blog/{slug}/index.html`. SSR-only pages omit app-shell HTML artifacts. - `components`: component declarations known to the manifest. diff --git a/docs/reference/seo.md b/docs/reference/seo.md index 97a76ed8..de66f295 100644 --- a/docs/reference/seo.md +++ b/docs/reference/seo.md @@ -50,7 +50,7 @@ are joined onto it. If `BaseURL` includes a path such as `sitemap.xml` includes build-time-enumerable page routes: -- public static SPA/action pages; +- public static SPA pages; - public dynamic SPA routes expanded from literal `paths {}` declarations; - optional `ExtraURLs`, which may be absolute URLs or root-relative paths. diff --git a/editors/vscode/extension-core.js b/editors/vscode/extension-core.js index c2692aeb..4465fb16 100644 --- a/editors/vscode/extension-core.js +++ b/editors/vscode/extension-core.js @@ -1746,7 +1746,7 @@ function semanticTokens(source) { collectPatternTokens(tokens, line, text, /\b(package|import|use|paths|build|load|act|api|fragment|view|script|go|style|props|state|exports|client|emits)\b/g, 'keyword'); collectPatternTokens(tokens, line, text, /\b(async|fn|computed|on|mount|destroy|effect|when|ref|let|return|await|if|else|in|emit)\b/g, 'keyword'); collectPatternTokens(tokens, line, text, /\b(GET|POST|PUT|PATCH|DELETE)\b/g, 'enumMember'); - collectPatternTokens(tokens, line, text, /\b(spa|action|hybrid|ssr)\b/g, 'enumMember'); + collectPatternTokens(tokens, line, text, /\b(spa|hybrid|ssr)\b/g, 'enumMember'); collectPatternTokens(tokens, line, text, /\b(string|int|float|bool)\b/g, 'enumMember'); collectPatternTokens(tokens, line, text, /\bg:(post|target|swap|ref|if|else-if|else|for|key|bind:(?:value|checked)|island)\b/g, 'property'); collectPatternTokens(tokens, line, text, /\bg:on:[A-Za-z][A-Za-z0-9_-]*(?:\.(?:prevent|stop|once|capture|debounce\([^)]+\)|throttle\([^)]+\)))*/g, 'property'); diff --git a/editors/vscode/syntaxes/gwdk.tmLanguage.json b/editors/vscode/syntaxes/gwdk.tmLanguage.json index 1aa972cf..e6f8faee 100644 --- a/editors/vscode/syntaxes/gwdk.tmLanguage.json +++ b/editors/vscode/syntaxes/gwdk.tmLanguage.json @@ -49,7 +49,7 @@ }, { "name": "support.type.render-mode.gwdk", - "match": "\\b(?:spa|action|hybrid|ssr)\\b" + "match": "\\b(?:spa|hybrid|ssr)\\b" }, { "name": "constant.language.http-method.gwdk", diff --git a/gowdk.go b/gowdk.go index 3a3d9ead..3de5f6d1 100644 --- a/gowdk.go +++ b/gowdk.go @@ -704,8 +704,6 @@ type RenderMode string const ( // SPA emits a non-SSR app shell and client-side route experience. SPA RenderMode = "spa" - // Action emits a non-SSR app shell while allowing backend actions. - Action RenderMode = "action" // Hybrid allows a route to combine app output and request-time behavior. Hybrid RenderMode = "hybrid" // SSR renders full pages at request time through the SSR addon. @@ -716,7 +714,7 @@ const ( func ParseRenderMode(value string) (RenderMode, error) { mode := RenderMode(value) switch mode { - case SPA, Action, Hybrid, SSR: + case SPA, Hybrid, SSR: return mode, nil default: return "", fmt.Errorf("unknown render mode %q", value) @@ -732,7 +730,7 @@ func (mode RenderMode) RequiresSSR() bool { // IsBuildTime reports whether this mode is always build-time. Hybrid defaults // to build-time unless explicit request-time capabilities are declared. func (mode RenderMode) IsBuildTime() bool { - return mode == SPA || mode == Action + return mode == SPA } // Feature names the capabilities that addons make available to the compiler. diff --git a/internal/buildgen/actions_partials_test.go b/internal/buildgen/actions_partials_test.go index 3d98dee2..38ec0c61 100644 --- a/internal/buildgen/actions_partials_test.go +++ b/internal/buildgen/actions_partials_test.go @@ -12,12 +12,12 @@ import ( "github.com/cssbruno/gowdk/internal/source" ) -func TestBuildLowersGPostDirectiveForActionPage(t *testing.T) { +func TestBuildLowersGPostDirectiveForSPAPage(t *testing.T) { outputDir := t.TempDir() app := gwdkanalysis.Sources{Pages: []gwdkir.Page{{ ID: "signup", Route: "/signup", - Render: gowdk.Action, + Render: gowdk.SPA, Guards: []string{"public"}, Blocks: gwdkir.Blocks{ View: true, @@ -48,7 +48,7 @@ func TestBuildSynthesizesActionInputAttrsFromBindingFields(t *testing.T) { ir := gwdkir.Program{Pages: []gwdkir.Page{{ ID: "signup", Route: "/signup", - Render: gowdk.Action, + Render: gowdk.SPA, Guards: []string{"public"}, Blocks: gwdkir.Blocks{ View: true, @@ -94,7 +94,7 @@ func TestBuildProductionRequiresBoundBackendHandlers(t *testing.T) { Package: "app", Source: filepath.Join(t.TempDir(), "signup.page.gwdk"), Route: "/signup", - Render: gowdk.Action, + Render: gowdk.SPA, Guards: []string{"public"}, Blocks: gwdkir.Blocks{ View: true, @@ -119,7 +119,7 @@ func TestBuildProductionAllowsExplicitMissingBackendStubs(t *testing.T) { Package: "app", Source: filepath.Join(t.TempDir(), "signup.page.gwdk"), Route: "/signup", - Render: gowdk.Action, + Render: gowdk.SPA, Guards: []string{"public"}, Blocks: gwdkir.Blocks{ View: true, @@ -145,7 +145,7 @@ func TestBuildAllowsGPostWithLocalValueBinding(t *testing.T) { Pages: []gwdkir.Page{{ ID: "search", Route: "/search", - Render: gowdk.Action, + Render: gowdk.SPA, Guards: []string{"public"}, Blocks: gwdkir.Blocks{ View: true, diff --git a/internal/buildgen/build_data_routes_test.go b/internal/buildgen/build_data_routes_test.go index 3457394e..9d5d1f2e 100644 --- a/internal/buildgen/build_data_routes_test.go +++ b/internal/buildgen/build_data_routes_test.go @@ -987,7 +987,7 @@ func TestBuildExpandsTypedDynamicSPAPathsAndInheritedActionRoutes(t *testing.T) app := gwdkanalysis.Sources{Pages: []gwdkir.Page{{ ID: "patients.show", Route: "/patients/{id:int}", - Render: gowdk.Action, + Render: gowdk.SPA, Guards: []string{"public"}, Blocks: gwdkir.Blocks{ Paths: true, @@ -1028,7 +1028,7 @@ func TestBuildLocalizesInheritedActionRoutes(t *testing.T) { app := gwdkanalysis.Sources{Pages: []gwdkir.Page{{ ID: "contact", Route: "/contact", - Render: gowdk.Action, + Render: gowdk.SPA, Guards: []string{"public"}, Blocks: gwdkir.Blocks{ View: true, diff --git a/internal/buildgen/render.go b/internal/buildgen/render.go index 8db408ad..57e81df8 100644 --- a/internal/buildgen/render.go +++ b/internal/buildgen/render.go @@ -27,7 +27,7 @@ const ( func renderPage(config gowdk.Config, page gwdkir.Page, route string, components map[string]view.Component, layouts map[string]gwdkir.Layout, stylesheets []gowdk.Stylesheet, actionFields map[string][]view.ActionInputField, data map[string]string, locale string, realtimeEventTypeNames map[string]string, queryTypeNames map[string]string, policy renderModePolicy) (string, ssrRegions, error) { mode := page.RenderMode(config.Render.DefaultMode()) - if policy == renderModeSPA && mode != gowdk.SPA && mode != gowdk.Action { + if policy == renderModeSPA && mode != gowdk.SPA { return "", ssrRegions{}, fmt.Errorf("%s: SPA build cannot emit request-time %s pages yet", page.ID, mode) } if policy == renderModeRequestTime && mode != gowdk.SSR && mode != gowdk.Hybrid { @@ -466,7 +466,7 @@ func viewHasInvalidatedQuery(source string, nodes []view.Node, queryTypeNames ma func pageUsesSPANavigationRuntime(config gowdk.Config, page gwdkir.Page, viewSource string, viewNodes []view.Node, components map[string]view.Component) (bool, error) { mode := page.RenderMode(config.Render.DefaultMode()) - if mode != gowdk.SPA && mode != gowdk.Action { + if mode != gowdk.SPA { return false, nil } if viewHasInternalLink(viewSource, viewNodes) { diff --git a/internal/compiler/validate_page.go b/internal/compiler/validate_page.go index dd44ffa3..9e40862c 100644 --- a/internal/compiler/validate_page.go +++ b/internal/compiler/validate_page.go @@ -297,7 +297,7 @@ func requiresSSRFeature(mode gowdk.RenderMode, page gwdkir.Page) bool { func isBuildTimeRoute(mode gowdk.RenderMode, page gwdkir.Page) bool { switch mode { - case gowdk.SPA, gowdk.Action: + case gowdk.SPA: return true default: return false diff --git a/internal/gwdkir/page_methods_test.go b/internal/gwdkir/page_methods_test.go index 4a90395b..21145d07 100644 --- a/internal/gwdkir/page_methods_test.go +++ b/internal/gwdkir/page_methods_test.go @@ -19,7 +19,7 @@ func TestPageRenderModeResolvesRequestTime(t *testing.T) { {"load_block", Page{Blocks: Blocks{Server: true}}, gowdk.SPA, gowdk.SSR}, {"go_ssr_block", Page{Blocks: Blocks{GoBlocks: []GoBlock{{Target: "server"}}}}, gowdk.SPA, gowdk.SSR}, {"default_spa", Page{}, "", gowdk.SPA}, - {"default_passthrough", Page{}, gowdk.Action, gowdk.Action}, + {"default_passthrough", Page{}, gowdk.Hybrid, gowdk.Hybrid}, } for _, tc := range cases { if got := tc.page.RenderMode(tc.def); got != tc.want { diff --git a/internal/lang/manifest_json.go b/internal/lang/manifest_json.go index af024e93..f5dad919 100644 --- a/internal/lang/manifest_json.go +++ b/internal/lang/manifest_json.go @@ -470,7 +470,7 @@ func fragmentEndpointsJSON(fragments []gwdkir.FragmentEndpoint) []fragmentEndpoi func artifactsJSON(page gwdkir.Page) []artifactJSON { switch page.RenderMode(gowdk.SPA) { - case gowdk.SPA, gowdk.Action: + case gowdk.SPA: default: return nil } diff --git a/internal/lang/tools_test.go b/internal/lang/tools_test.go index 907e5ece..175eb88c 100644 --- a/internal/lang/tools_test.go +++ b/internal/lang/tools_test.go @@ -341,12 +341,15 @@ view { } `) - payload, diagnostics := ManifestJSON(gowdk.Config{Render: gowdk.RenderConfig{Default: gowdk.Action}}, []string{path}) + payload, diagnostics := ManifestJSON(gowdk.Config{ + Render: gowdk.RenderConfig{Default: gowdk.SSR}, + Addons: []gowdk.Addon{ssr.Addon()}, + }, []string{path}) if diagnostics.HasErrors() { t.Fatal(diagnostics) } - if !strings.Contains(string(payload), `"render": "action"`) { - t.Fatalf("expected action render mode in manifest JSON: %s", payload) + if !strings.Contains(string(payload), `"render": "ssr"`) { + t.Fatalf("expected ssr render mode in manifest JSON: %s", payload) } } diff --git a/internal/project/config.go b/internal/project/config.go index 448c0fec..dd4c052f 100644 --- a/internal/project/config.go +++ b/internal/project/config.go @@ -165,7 +165,11 @@ func parseConfigLiteral(expression ast.Expr, imports map[string]string) (gowdk.C needsExecutableLoad = true continue } - config.Render = parseRenderConfig(field.Value) + render, err := parseRenderConfig(field.Value) + if err != nil { + return gowdk.Config{}, false, false, err + } + config.Render = render case "I18N": if needsConfigExpressionEvaluation(field.Value) { needsExecutableLoad = true @@ -352,19 +356,23 @@ func parseModuleConfig(expression ast.Expr) gowdk.ModuleConfig { return module } -func parseRenderConfig(expression ast.Expr) gowdk.RenderConfig { +func parseRenderConfig(expression ast.Expr) (gowdk.RenderConfig, error) { fields, ok := configLiteralFields(expression) if !ok { - return gowdk.RenderConfig{} + return gowdk.RenderConfig{}, nil } var render gowdk.RenderConfig for _, field := range fields { if field.Name == "Default" { - render.Default = parseRenderMode(field.Value) + mode, err := parseRenderMode(field.Value) + if err != nil { + return gowdk.RenderConfig{}, err + } + render.Default = mode } } - return render + return render, nil } func parseI18NConfig(expression ast.Expr) gowdk.I18NConfig { @@ -425,13 +433,13 @@ func parseLocaleConfig(expression ast.Expr) (gowdk.LocaleConfig, bool) { return locale, true } -func parseRenderMode(expression ast.Expr) gowdk.RenderMode { +func parseRenderMode(expression ast.Expr) (gowdk.RenderMode, error) { if value := parseString(expression); value != "" { mode, err := gowdk.ParseRenderMode(value) if err == nil { - return mode + return mode, nil } - return "" + return "", err } switch typed := expression.(type) { case *ast.SelectorExpr: @@ -439,22 +447,20 @@ func parseRenderMode(expression ast.Expr) gowdk.RenderMode { case *ast.Ident: return renderModeByName(typed.Name) default: - return "" + return "", fmt.Errorf("unsupported render mode expression") } } -func renderModeByName(name string) gowdk.RenderMode { +func renderModeByName(name string) (gowdk.RenderMode, error) { switch name { case "SPA": - return gowdk.SPA - case "Action": - return gowdk.Action + return gowdk.SPA, nil case "Hybrid": - return gowdk.Hybrid + return gowdk.Hybrid, nil case "SSR": - return gowdk.SSR + return gowdk.SSR, nil default: - return "" + return "", fmt.Errorf("unknown render mode %q", name) } } diff --git a/internal/project/config_test.go b/internal/project/config_test.go index 050def86..1b41f832 100644 --- a/internal/project/config_test.go +++ b/internal/project/config_test.go @@ -134,7 +134,7 @@ var Config = gowdk.Config{ }, }, Render: gowdk.RenderConfig{ - Default: gowdk.Action, + Default: gowdk.SSR, }, I18N: gowdk.I18NConfig{ DefaultLocale: "en", @@ -253,7 +253,7 @@ var Config = gowdk.Config{ if config.Build.Targets[1].Name != "public-admin" || len(config.Build.Targets[1].Modules) != 2 || config.Build.Targets[1].Modules[0] != "public" || config.Build.Targets[1].Modules[1] != "admin" { t.Fatalf("unexpected combined build target: %#v", config.Build.Targets[1]) } - if config.Render.Default != gowdk.Action { + if config.Render.Default != gowdk.SSR { t.Fatalf("unexpected render default: %q", config.Render.Default) } if config.I18N.DefaultLocale != "en" || len(config.I18N.Locales) != 2 || config.I18N.Locales[1].Code != "pt-BR" || config.I18N.Locales[1].PathPrefix != "/br" { @@ -619,6 +619,35 @@ var Config = gowdk.Config{ } } +func TestLoadConfigFileRejectsRemovedActionRenderMode(t *testing.T) { + for _, defaultMode := range []string{`"action"`, `gowdk.Action`} { + t.Run(defaultMode, func(t *testing.T) { + root := t.TempDir() + path := filepath.Join(root, DefaultConfigFile) + if err := os.WriteFile(path, []byte(`package app + +import "github.com/cssbruno/gowdk" + +var Config = gowdk.Config{ + Render: gowdk.RenderConfig{ + Default: `+defaultMode+`, + }, +} +`), 0o644); err != nil { + t.Fatal(err) + } + + _, err := LoadConfigFile(path) + if err == nil { + t.Fatal("expected removed action render mode error") + } + if !strings.Contains(err.Error(), `unknown render mode "action"`) && !strings.Contains(err.Error(), `unknown render mode "Action"`) { + t.Fatalf("unexpected error: %v", err) + } + }) + } +} + func TestLoadConfigFileReadsSSRAddon(t *testing.T) { root := t.TempDir() path := filepath.Join(root, DefaultConfigFile) diff --git a/internal/publicapi/gowdk_test.go b/internal/publicapi/gowdk_test.go index 31a5769c..c06b4362 100644 --- a/internal/publicapi/gowdk_test.go +++ b/internal/publicapi/gowdk_test.go @@ -40,7 +40,7 @@ func TestRenderConfigDefaultMode(t *testing.T) { if got := (gowdk.RenderConfig{}).DefaultMode(); got != gowdk.SPA { t.Fatalf("expected spa default, got %q", got) } - if got := (gowdk.RenderConfig{Default: gowdk.Action}).DefaultMode(); got != gowdk.Action { + if got := (gowdk.RenderConfig{Default: gowdk.SSR}).DefaultMode(); got != gowdk.SSR { t.Fatalf("expected configured default, got %q", got) } } @@ -144,7 +144,6 @@ func TestParseRenderModeAndModePredicates(t *testing.T) { buildTime bool }{ {"spa", gowdk.SPA, false, true}, - {"action", gowdk.Action, false, true}, {"hybrid", gowdk.Hybrid, false, false}, {"ssr", gowdk.SSR, true, false}, } @@ -169,4 +168,8 @@ func TestParseRenderModeAndModePredicates(t *testing.T) { if err == nil || !strings.Contains(err.Error(), `unknown render mode "server"`) { t.Fatalf("expected unknown mode error, got %v", err) } + _, err = gowdk.ParseRenderMode("action") + if err == nil || !strings.Contains(err.Error(), `unknown render mode "action"`) { + t.Fatalf("expected removed action mode error, got %v", err) + } }