Files
Carlos Gutierrez 9e451469f5 git commit -m "feat: initial release of Strata framework v0.1.0
- Static compiler with STRC pattern (Static Template Resolution with
   Compartmentalized Layers)
   - Template syntax: { } interpolation, { s-for }, { s-if/s-elif/s-else
    }
   - File types: .strata, .compiler.sts, .service.sts, .api.sts, .sts,
   .scss
   - CLI tools: strata dev, strata build, strata g (generators)
   - create-strata scaffolding CLI with Pokemon API example
   - Dev server with WebSocket HMR (Hot Module Replacement)
   - Documentation: README, ARCHITECTURE, CHANGELOG, CONTRIBUTING,
   LICENSE
2026-01-16 09:01:29 -05:00

165 lines
3.7 KiB
Go

package generator
import (
"bytes"
"crypto/rand"
"encoding/hex"
"fmt"
"html/template"
"os"
"path/filepath"
)
// HTMLGenerator generates index.html only in dist folder
type HTMLGenerator struct {
projectDir string
distDir string
injector *ScriptInjector
encryptionKey []byte
}
// NewHTMLGenerator creates a new HTML generator
func NewHTMLGenerator(projectDir, distDir string) *HTMLGenerator {
return &HTMLGenerator{
projectDir: projectDir,
distDir: distDir,
injector: NewScriptInjector(projectDir),
}
}
// Generate creates the index.html in dist folder
func (hg *HTMLGenerator) Generate(config *BuildConfig) error {
// Load injected scripts
if err := hg.injector.LoadScripts(); err != nil {
return fmt.Errorf("failed to load injected scripts: %w", err)
}
// Generate encryption key at build time
hg.encryptionKey = make([]byte, 32)
if _, err := rand.Read(hg.encryptionKey); err != nil {
return fmt.Errorf("failed to generate encryption key: %w", err)
}
// Create dist directory
if err := os.MkdirAll(hg.distDir, 0755); err != nil {
return fmt.Errorf("failed to create dist directory: %w", err)
}
// Generate HTML
html, err := hg.buildHTML(config)
if err != nil {
return err
}
// Inject scripts
html = hg.injector.InjectIntoHTML(html)
// Write to dist
indexPath := filepath.Join(hg.distDir, "index.html")
if err := os.WriteFile(indexPath, []byte(html), 0644); err != nil {
return fmt.Errorf("failed to write index.html: %w", err)
}
return nil
}
// BuildConfig holds build configuration
type BuildConfig struct {
Title string
Description string
BaseURL string
APIBaseURL string
DevMode bool
Assets AssetManifest
}
// AssetManifest tracks generated assets
type AssetManifest struct {
JS []string
CSS []string
}
func (hg *HTMLGenerator) buildHTML(config *BuildConfig) (string, error) {
tmpl := `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{.Description}}">
<title>{{.Title}}</title>
<base href="{{.BaseURL}}">
{{range .Assets.CSS}}
<link rel="stylesheet" href="{{.}}">
{{end}}
<script>
// Strata config (build-time injected)
window.__STRATA_CONFIG__ = {
apiBaseUrl: "{{.APIBaseURL}}",
devMode: {{.DevMode}},
encryptionKey: [{{.EncryptionKeyArray}}]
};
</script>
</head>
<body>
<div id="app"></div>
<!-- Strata Runtime -->
<script type="module" src="/assets/js/runtime.js"></script>
{{range .Assets.JS}}
<script type="module" src="{{.}}"></script>
{{end}}
</body>
</html>`
// Convert encryption key to array format for JS
keyArray := make([]string, len(hg.encryptionKey))
for i, b := range hg.encryptionKey {
keyArray[i] = fmt.Sprintf("%d", b)
}
keyArrayStr := ""
for i, k := range keyArray {
if i > 0 {
keyArrayStr += ","
}
keyArrayStr += k
}
data := struct {
Title string
Description string
BaseURL string
APIBaseURL string
DevMode bool
Assets AssetManifest
EncryptionKeyArray string
}{
Title: config.Title,
Description: config.Description,
BaseURL: config.BaseURL,
APIBaseURL: config.APIBaseURL,
DevMode: config.DevMode,
Assets: config.Assets,
EncryptionKeyArray: keyArrayStr,
}
t, err := template.New("html").Parse(tmpl)
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := t.Execute(&buf, data); err != nil {
return "", err
}
return buf.String(), nil
}
// GetEncryptionKeyHex returns the encryption key as hex for debugging
func (hg *HTMLGenerator) GetEncryptionKeyHex() string {
return hex.EncodeToString(hg.encryptionKey)
}