refactor: keep compiler source standalone

Signed-off-by: Cole Speelman <crspeelman@gmail.com>
This commit is contained in:
2026-08-11 23:58:25 -04:00
parent 0941075baa
commit 7b839f8155
40 changed files with 130 additions and 1581 deletions
-14
View File
@@ -1,14 +0,0 @@
Zero-Clause BSD
Copyright (c) 2025-2026 Cole Speelman
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
-15
View File
@@ -1,15 +0,0 @@
<!-- SPDX-FileCopyrightText: 2025-2026 Cole Speelman -->
<!-- SPDX-License-Identifier: 0BSD -->
# Example license map
The original files in this synthetic, copyable example are licensed under the
0BSD terms in `LICENSE`, including `.sando` templates, handwritten Go,
`himesan.json`, and committed `.sando.go` output.
The generated files intentionally have no inline SPDX header because Hime-san
replaces the whole file. This module-level license map covers them. Generator
scaffolding copied into those files also has the additional permission in the
root repository's `OUTPUT_EXCEPTION.md`; that permission is not required to
keep this example under 0BSD when the example author already owns the relevant
input code.
-15
View File
@@ -1,15 +0,0 @@
<!-- SPDX-License-Identifier: 0BSD -->
# Synthetic EQL-shaped fixture
This copyable 0BSD example exercises a shared document layout, typed page data,
component composition, loops, text escaping, attribute escaping, and URL
policy without containing EQL Wiki code, data, routes, or its database.
From the repository root:
```sh
go run ./cmd/himesan generate ./examples/eql-shaped
go run ./cmd/himesan check ./examples/eql-shaped
(cd examples/eql-shaped && go test ./... && go run ./cmd/example)
```
-83
View File
@@ -1,83 +0,0 @@
// SPDX-License-Identifier: 0BSD
package main
import (
"bytes"
"context"
"errors"
"fmt"
"net/http"
"os"
"time"
"example.com/eql-shaped/views"
"gamertan.com/sandwich-hime/sando"
)
func main() {
address := os.Getenv("HIMESAN_LISTEN_ADDR")
if address != "" {
serve(address)
return
}
output, err := renderPage(context.Background())
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
_, _ = output.WriteTo(os.Stdout)
}
func serve(address string) {
mux := http.NewServeMux()
mux.HandleFunc("GET /healthz", func(response http.ResponseWriter, _ *http.Request) {
response.Header().Set("Content-Type", "text/plain; charset=utf-8")
response.WriteHeader(http.StatusOK)
_, _ = response.Write([]byte("ok\n"))
})
mux.HandleFunc("GET /", func(response http.ResponseWriter, request *http.Request) {
output, err := renderPage(request.Context())
if err != nil {
http.Error(response, "render failed", http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "text/html; charset=utf-8")
response.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'self'")
response.WriteHeader(http.StatusOK)
_, _ = output.WriteTo(response)
})
server := &http.Server{Addr: address, Handler: mux, ReadHeaderTimeout: 5 * time.Second}
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func renderPage(ctx context.Context) (*bytes.Buffer, error) {
body := views.Home(views.HomeView{
Heading: "EQL-shaped records",
Intro: "Typed markup without making the template compiler your web framework.",
Browse: views.BrowseView{
Query: "pioneer & archivist",
Records: []views.RecordView{
{URL: "/items/1?from=home&kind=book", Title: "A <field> guide", Kind: "book", Featured: true},
{URL: "/items/2", Title: "Community memory", Kind: "archive"},
},
},
})
page := views.Layout(views.LayoutView{
SiteName: "EQL Wiki Fixture",
Title: "Home",
Body: body,
})
var output bytes.Buffer
if err := sando.Render(ctx, &output, page); err != nil {
return nil, err
}
return &output, nil
}
-9
View File
@@ -1,9 +0,0 @@
// SPDX-License-Identifier: 0BSD
module example.com/eql-shaped
go 1.25
require gamertan.com/sandwich-hime/sando v0.0.0
replace gamertan.com/sandwich-hime/sando => ../../sando
-9
View File
@@ -1,9 +0,0 @@
{
"version": 1,
"sourceRoots": ["views"],
"goPackage": "./cmd/example",
"listenAddressEnv": "HIMESAN_LISTEN_ADDR",
"healthPath": "/healthz",
"proxyAddress": "127.0.0.1:7331",
"additionalWatchRoots": []
}
-7
View File
@@ -1,7 +0,0 @@
<?sando go
package views
func Badge(label string)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<strong class="badge"><?= label ?></strong>
-37
View File
@@ -1,37 +0,0 @@
// Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1
// himesan:source-sha256 2c0063ed8724520f146d6717bb7d828ce69be17b41cbfb8f4866664ba09a58a8
package views
import (
__himesan_context "context"
__himesan_sando "gamertan.com/sandwich-hime/sando"
__himesan_io "io"
)
var _ = __himesan_sando.ABI
func Badge(label string) __himesan_sando.Component {
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
_ = __himesan_render_context
//line views/badge.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error
}
//line views/badge.sando:6:37
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<strong class=\"badge\">"); __himesan_error != nil {
return __himesan_error
}
//line views/badge.sando:7:27
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (label)); __himesan_error != nil {
return __himesan_error
}
//line views/badge.sando:7:35
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</strong>\n"); __himesan_error != nil {
return __himesan_error
}
return nil
})
}
@@ -1,17 +0,0 @@
<?sando go
package views
func BrowseResults(view BrowseView)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<section aria-label="Browse results" data-query="<?= view.Query ?>">
<ul>
<? for _, record := range view.Records { ?>
<li>
<a href="<?= record.URL ?>"><?= record.Title ?></a>
<span class="kind"><?= record.Kind ?></span>
<? if record.Featured { ?><?~ Badge("featured") ?><? } ?>
</li>
<? } ?>
</ul>
</section>
@@ -1,85 +0,0 @@
// Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1
// himesan:source-sha256 c5b402971618747c906c84508d5af9fd00aa33391b9b59f093b001a3cb0b2164
package views
import (
__himesan_context "context"
__himesan_sando "gamertan.com/sandwich-hime/sando"
__himesan_io "io"
)
var _ = __himesan_sando.ABI
func BrowseResults(view BrowseView) __himesan_sando.Component {
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
_ = __himesan_render_context
//line views/browse_results.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:6:37
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<section aria-label=\"Browse results\" data-query=\""); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:7:54
if __himesan_error := __himesan_sando.WriteAttr(__himesan_writer, (view.Query)); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:7:67
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\">\n <ul>\n "); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:9:6
for _, record := range view.Records {
//line views/browse_results.sando:9:46
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n <li>\n <a href=\""); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:11:20
if __himesan_error := __himesan_sando.WriteURL(__himesan_writer, (record.URL)); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:11:33
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\">"); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:11:39
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (record.Title)); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:11:54
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</a>\n <span class=\"kind\">"); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:12:30
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (record.Kind)); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:12:44
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</span>\n "); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:13:10
if record.Featured {
//line views/browse_results.sando:13:37
if __himesan_error := __himesan_sando.Render(__himesan_render_context, __himesan_writer, (Badge("featured"))); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:13:60
}
//line views/browse_results.sando:13:64
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n </li>\n "); __himesan_error != nil {
return __himesan_error
}
//line views/browse_results.sando:15:6
}
//line views/browse_results.sando:15:10
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n </ul>\n</section>\n"); __himesan_error != nil {
return __himesan_error
}
return nil
})
}
-11
View File
@@ -1,11 +0,0 @@
<?sando go
package views
func Home(view HomeView)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<section aria-labelledby="home-heading">
<h1 id="home-heading"><?= view.Heading ?></h1>
<p><?= view.Intro ?></p>
<?~ BrowseResults(view.Browse) ?>
</section>
-53
View File
@@ -1,53 +0,0 @@
// Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1
// himesan:source-sha256 696c391538cdc50c5ab1abea23b561fa354e56eaf73b7ad6aabe130389715a8c
package views
import (
__himesan_context "context"
__himesan_sando "gamertan.com/sandwich-hime/sando"
__himesan_io "io"
)
var _ = __himesan_sando.ABI
func Home(view HomeView) __himesan_sando.Component {
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
_ = __himesan_render_context
//line views/home.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:6:37
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<section aria-labelledby=\"home-heading\">\n <h1 id=\"home-heading\">"); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:8:29
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (view.Heading)); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:8:44
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</h1>\n <p>"); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:9:10
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (view.Intro)); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:9:23
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</p>\n "); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:10:7
if __himesan_error := __himesan_sando.Render(__himesan_render_context, __himesan_writer, (BrowseResults(view.Browse))); __himesan_error != nil {
return __himesan_error
}
//line views/home.sando:10:36
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n</section>\n"); __himesan_error != nil {
return __himesan_error
}
return nil
})
}
-20
View File
@@ -1,20 +0,0 @@
<?sando go
package views
func Layout(view LayoutView)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?= view.Title ?> · <?= view.SiteName ?></title>
</head>
<body>
<a href="#main">Skip to content</a>
<header><a href="/"><?= view.SiteName ?></a></header>
<main id="main"><?~ view.Body ?></main>
<footer>Built with Sandwich Hime.</footer>
</body>
</html>
-61
View File
@@ -1,61 +0,0 @@
// Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1
// himesan:source-sha256 c9a8102588cb94f946a36414291d12cb681e605acc93c2b5dc8d74fd33ae5603
package views
import (
__himesan_context "context"
__himesan_sando "gamertan.com/sandwich-hime/sando"
__himesan_io "io"
)
var _ = __himesan_sando.ABI
func Layout(view LayoutView) __himesan_sando.Component {
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
_ = __himesan_render_context
//line views/layout.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:6:37
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>"); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:12:14
if __himesan_error := __himesan_sando.WriteRCDATA(__himesan_writer, (view.Title)); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:12:27
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, " · "); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:12:35
if __himesan_error := __himesan_sando.WriteRCDATA(__himesan_writer, (view.SiteName)); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:12:51
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</title>\n</head>\n<body>\n <a href=\"#main\">Skip to content</a>\n <header><a href=\"/\">"); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:16:27
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (view.SiteName)); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:16:43
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</a></header>\n <main id=\"main\">"); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:17:23
if __himesan_error := __himesan_sando.Render(__himesan_render_context, __himesan_writer, (view.Body)); __himesan_error != nil {
return __himesan_error
}
//line views/layout.sando:17:35
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</main>\n <footer>Built with Sandwich Hime.</footer>\n</body>\n</html>\n"); __himesan_error != nil {
return __himesan_error
}
return nil
})
}
-29
View File
@@ -1,29 +0,0 @@
// SPDX-License-Identifier: 0BSD
package views
import "gamertan.com/sandwich-hime/sando"
type LayoutView struct {
SiteName string
Title string
Body sando.Component
}
type HomeView struct {
Heading string
Intro string
Browse BrowseView
}
type BrowseView struct {
Query string
Records []RecordView
}
type RecordView struct {
URL string
Title string
Kind string
Featured bool
}
-131
View File
@@ -1,131 +0,0 @@
// SPDX-License-Identifier: 0BSD
package views
import (
"bytes"
"context"
"errors"
"html/template"
"io"
"strings"
"testing"
"gamertan.com/sandwich-hime/sando"
)
func TestBrowseResultsEscapesUntrustedValues(t *testing.T) {
t.Parallel()
component := BrowseResults(BrowseView{
Query: `"><script>alert(1)</script>`,
Records: []RecordView{{
URL: `/item?q=" onclick="alert(1)`,
Title: `<img src=x onerror=alert(1)>`,
Kind: `" aria-label="injected`,
}},
})
var output bytes.Buffer
if err := sando.Render(context.Background(), &output, component); err != nil {
t.Fatal(err)
}
got := output.String()
if strings.Contains(got, "<script>") || strings.Contains(got, "<img") || strings.Contains(got, `" onclick=`) {
t.Fatalf("untrusted markup survived escaping: %s", got)
}
}
func TestBrowseResultsRejectsDangerousURL(t *testing.T) {
t.Parallel()
component := BrowseResults(BrowseView{Records: []RecordView{{
URL: " JaVaScRiPt:\talert(1)",
Title: "unsafe",
}}})
var output bytes.Buffer
err := sando.Render(context.Background(), &output, component)
if !errors.Is(err, sando.ErrUnsafeURL) {
t.Fatalf("expected unsafe URL error, got %v", err)
}
}
func TestGeneratedComponentPropagatesWriterFailures(t *testing.T) {
t.Parallel()
component := Badge("proof")
if err := sando.Render(context.Background(), shortWriter{}, component); !errors.Is(err, io.ErrShortWrite) {
t.Fatalf("short writer error = %v, want io.ErrShortWrite", err)
}
want := errors.New("connection closed")
if err := sando.Render(context.Background(), errorWriter{err: want}, component); !errors.Is(err, want) {
t.Fatalf("writer error = %v, want %v", err, want)
}
}
func TestContextEscapingAgainstHTMLTemplateBaseline(t *testing.T) {
t.Parallel()
baseline := template.Must(template.New("probe").Parse(`<a href="{{ .URL }}" title="{{ .Title }}">{{ .Text }}</a>`))
tests := []struct {
name string
url string
title string
text string
}{
{name: "entities", url: "/items?q=one&kind=book", title: `say "hello" & goodbye`, text: `<strong>not markup</strong>`},
{name: "unicode", url: "/items/cole", title: "Café & 雪", text: "Cole's archive ♥"},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
data := struct{ URL, Title, Text string }{test.url, test.title, test.text}
var legacy bytes.Buffer
if err := baseline.Execute(&legacy, data); err != nil {
t.Fatal(err)
}
var generated bytes.Buffer
if err := sando.Render(context.Background(), &generated, SecurityProbe(test.url, test.title, test.text)); err != nil {
t.Fatal(err)
}
if got, want := strings.TrimSpace(generated.String()), legacy.String(); got != want {
t.Fatalf("generated escaping differs from html/template baseline\n got: %s\nwant: %s", got, want)
}
})
}
}
func TestDangerousURLIsBlockedAtLeastAsStrictlyAsHTMLTemplate(t *testing.T) {
t.Parallel()
const dangerous = " JaVaScRiPt:\talert(1)"
baseline := template.Must(template.New("probe").Parse(`<a href="{{ . }}">link</a>`))
var legacy bytes.Buffer
if err := baseline.Execute(&legacy, dangerous); err != nil {
t.Fatal(err)
}
if !strings.Contains(legacy.String(), "#ZgotmplZ") {
t.Fatalf("html/template baseline unexpectedly accepted dangerous URL: %s", legacy.String())
}
var generated bytes.Buffer
err := sando.Render(context.Background(), &generated, SecurityProbe(dangerous, "title", "link"))
if !errors.Is(err, sando.ErrUnsafeURL) {
t.Fatalf("generated renderer error = %v, want ErrUnsafeURL", err)
}
}
type shortWriter struct{}
func (shortWriter) Write(value []byte) (int, error) {
if len(value) == 0 {
return 0, nil
}
return len(value) - 1, nil
}
type errorWriter struct{ err error }
func (writer errorWriter) Write([]byte) (int, error) { return 0, writer.err }
@@ -1,7 +0,0 @@
<?sando go
package views
func SecurityProbe(url string, title string, text string)
?>
<?# SPDX-License-Identifier: 0BSD ?>
<a href="<?= url ?>" title="<?= title ?>"><?= text ?></a>
@@ -1,53 +0,0 @@
// Code generated by himesan; DO NOT EDIT.
// himesan:compiler 0.1.0-dev
// himesan:runtime-abi sando.v1
// himesan:source-sha256 8d59b45799d0ed2e9e6997f286315f2cb794ea660940978ec39efa3b9a3b94ab
package views
import (
__himesan_context "context"
__himesan_sando "gamertan.com/sandwich-hime/sando"
__himesan_io "io"
)
var _ = __himesan_sando.ABI
func SecurityProbe(url string, title string, text string) __himesan_sando.Component {
return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error {
_ = __himesan_render_context
//line views/security_probe.sando:5:3
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n"); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:6:37
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\n<a href=\""); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:14
if __himesan_error := __himesan_sando.WriteURL(__himesan_writer, (url)); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:20
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\" title=\""); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:33
if __himesan_error := __himesan_sando.WriteAttr(__himesan_writer, (title)); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:41
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "\">"); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:47
if __himesan_error := __himesan_sando.WriteText(__himesan_writer, (text)); __himesan_error != nil {
return __himesan_error
}
//line views/security_probe.sando:7:54
if __himesan_error := __himesan_sando.WriteString(__himesan_writer, "</a>\n"); __himesan_error != nil {
return __himesan_error
}
return nil
})
}