fix(codegen): make bundle generation deterministic
All checks were successful
Security Scan / security (push) Successful in 9s
Test / test (push) Successful in 50s

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-03-30 05:34:47 +00:00
parent 714d7adc90
commit f9f0aa197b
3 changed files with 33 additions and 2 deletions

View file

@ -3,6 +3,7 @@
package codegen
import (
"sort"
"text/template"
core "dappco.re/go/core"
@ -76,8 +77,14 @@ func TagToClassName(tag string) string {
func GenerateBundle(slots map[string]string) (string, error) {
seen := make(map[string]bool)
b := core.NewBuilder()
keys := make([]string, 0, len(slots))
for slot := range slots {
keys = append(keys, slot)
}
sort.Strings(keys)
for slot, tag := range slots {
for _, slot := range keys {
tag := slots[slot]
if seen[tag] {
continue
}

View file

@ -3,6 +3,7 @@
package codegen
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
@ -56,6 +57,29 @@ func TestGenerateBundle_DeduplicatesRegistrations_Good(t *testing.T) {
assert.Equal(t, 2, countSubstr(js, "customElements.define"))
}
func TestGenerateBundle_DeterministicOrdering_Good(t *testing.T) {
slots := map[string]string{
"Z": "zed-panel",
"A": "alpha-panel",
"M": "main-content",
}
js, err := GenerateBundle(slots)
require.NoError(t, err)
alpha := strings.Index(js, "class AlphaPanel")
main := strings.Index(js, "class MainContent")
zed := strings.Index(js, "class ZedPanel")
assert.NotEqual(t, -1, alpha)
assert.NotEqual(t, -1, main)
assert.NotEqual(t, -1, zed)
assert.Less(t, alpha, main)
assert.Less(t, main, zed)
assert.Equal(t, 3, countSubstr(js, "extends HTMLElement"))
assert.Equal(t, 3, countSubstr(js, "customElements.define"))
}
func countSubstr(s, substr string) int {
if substr == "" {
return len(s) + 1

View file

@ -293,4 +293,4 @@ func TestGenerateClass_ValidTag(t *testing.T) {
- `Responsive.Variant()` accepts only `*Layout`, not arbitrary `Node` values. Arbitrary subtrees must be wrapped in a single-slot layout first.
- `Context.service` is unexported. Custom translation injection requires `NewContextWithService()`. There is no way to swap the translator after construction.
- The WASM module has no integration test for the JavaScript exports. `size_test.go` tests binary size only; it does not exercise `renderToString` behaviour from JavaScript.
- `codegen.GenerateBundle()` iterates a `map`, so the order of class definitions in the output is non-deterministic. This does not affect correctness but may cause cosmetic diffs between runs.
- `codegen.GenerateBundle()` now renders output classes in sorted slot-key order so generated bundles are stable between runs.