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

182 lines
4.3 KiB
Go

package generator
import (
"os"
"path/filepath"
"sort"
"strings"
)
// InjectedScript represents a script file to be injected
type InjectedScript struct {
Name string
Content string
Position string // "head" or "body"
Priority int // Lower = earlier injection
}
// ScriptInjector handles the injectedscripts/ directory
type ScriptInjector struct {
scriptsDir string
scripts []InjectedScript
}
// NewScriptInjector creates a new script injector
func NewScriptInjector(projectDir string) *ScriptInjector {
return &ScriptInjector{
scriptsDir: filepath.Join(projectDir, "src", "injectedscripts"),
scripts: make([]InjectedScript, 0),
}
}
// LoadScripts loads all scripts from injectedscripts/ directory
func (si *ScriptInjector) LoadScripts() error {
if _, err := os.Stat(si.scriptsDir); os.IsNotExist(err) {
return nil // No injectedscripts directory, that's fine
}
entries, err := os.ReadDir(si.scriptsDir)
if err != nil {
return err
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
if !strings.HasSuffix(name, ".js") {
continue
}
content, err := os.ReadFile(filepath.Join(si.scriptsDir, name))
if err != nil {
return err
}
script := si.parseScript(name, string(content))
si.scripts = append(si.scripts, script)
}
// Sort by priority
sort.Slice(si.scripts, func(i, j int) bool {
return si.scripts[i].Priority < si.scripts[j].Priority
})
return nil
}
// parseScript parses a script file and extracts metadata from comments
func (si *ScriptInjector) parseScript(name string, content string) InjectedScript {
script := InjectedScript{
Name: strings.TrimSuffix(name, ".js"),
Content: content,
Position: "head", // default to head
Priority: 100, // default priority
}
// Parse special comments at the top
// /* @position: body */
// /* @priority: 10 */
lines := strings.Split(content, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if !strings.HasPrefix(line, "/*") && !strings.HasPrefix(line, "//") {
break
}
if strings.Contains(line, "@position:") {
if strings.Contains(line, "body") {
script.Position = "body"
} else {
script.Position = "head"
}
}
if strings.Contains(line, "@priority:") {
// Extract priority number
parts := strings.Split(line, "@priority:")
if len(parts) > 1 {
priority := strings.TrimSpace(parts[1])
priority = strings.TrimSuffix(priority, "*/")
priority = strings.TrimSpace(priority)
var p int
if _, err := parseIntFromString(priority, &p); err == nil {
script.Priority = p
}
}
}
}
return script
}
// GetHeadScripts returns scripts for <head>
func (si *ScriptInjector) GetHeadScripts() []InjectedScript {
var result []InjectedScript
for _, s := range si.scripts {
if s.Position == "head" {
result = append(result, s)
}
}
return result
}
// GetBodyScripts returns scripts for end of <body>
func (si *ScriptInjector) GetBodyScripts() []InjectedScript {
var result []InjectedScript
for _, s := range si.scripts {
if s.Position == "body" {
result = append(result, s)
}
}
return result
}
// InjectIntoHTML injects scripts into HTML content
func (si *ScriptInjector) InjectIntoHTML(html string) string {
// Inject head scripts before </head>
headScripts := si.GetHeadScripts()
if len(headScripts) > 0 {
var headContent strings.Builder
for _, s := range headScripts {
headContent.WriteString("<!-- Injected: ")
headContent.WriteString(s.Name)
headContent.WriteString(" -->\n")
headContent.WriteString(s.Content)
headContent.WriteString("\n")
}
html = strings.Replace(html, "</head>", headContent.String()+"</head>", 1)
}
// Inject body scripts before </body>
bodyScripts := si.GetBodyScripts()
if len(bodyScripts) > 0 {
var bodyContent strings.Builder
for _, s := range bodyScripts {
bodyContent.WriteString("<!-- Injected: ")
bodyContent.WriteString(s.Name)
bodyContent.WriteString(" -->\n")
bodyContent.WriteString(s.Content)
bodyContent.WriteString("\n")
}
html = strings.Replace(html, "</body>", bodyContent.String()+"</body>", 1)
}
return html
}
func parseIntFromString(s string, target *int) (int, error) {
var n int
for _, c := range s {
if c >= '0' && c <= '9' {
n = n*10 + int(c-'0')
} else {
break
}
}
*target = n
return n, nil
}