Files
strata-compile/compiler/internal/ast/nodes.go
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

305 lines
7.5 KiB
Go

package ast
// Node is the base interface for all AST nodes
type Node interface {
NodeType() string
}
// StrataFile represents a parsed .strata file
type StrataFile struct {
Template *TemplateNode
Script *ScriptNode
Style *StyleNode
}
func (s *StrataFile) NodeType() string { return "StrataFile" }
// TemplateNode represents the <template> block
type TemplateNode struct {
Children []Node
}
func (t *TemplateNode) NodeType() string { return "Template" }
// ScriptNode represents the <script> block
type ScriptNode struct {
Content string
Lang string // "ts" or "js"
}
func (s *ScriptNode) NodeType() string { return "Script" }
// StyleNode represents the <style> block
type StyleNode struct {
Content string
Lang string // "css", "scss", "sass", "less"
Scoped bool
}
func (s *StyleNode) NodeType() string { return "Style" }
// ElementNode represents an HTML element
type ElementNode struct {
Tag string
Attributes map[string]string
Directives []Directive
Children []Node
IsComponent bool
}
func (e *ElementNode) NodeType() string { return "Element" }
// TextNode represents text content
type TextNode struct {
Content string
}
func (t *TextNode) NodeType() string { return "Text" }
// InterpolationNode represents { expression } variable binding
type InterpolationNode struct {
Expression string
}
func (i *InterpolationNode) NodeType() string { return "Interpolation" }
// ForBlockNode represents { s-for item in items } ... { /s-for }
type ForBlockNode struct {
Item string // Loop variable name (e.g., "item")
Index string // Optional index variable (e.g., "i" in "item, i")
Iterable string // Expression to iterate (e.g., "items")
Children []Node // Content inside the for block
}
func (f *ForBlockNode) NodeType() string { return "ForBlock" }
// IfBlockNode represents { s-if } ... { s-elif } ... { s-else } ... { /s-if }
type IfBlockNode struct {
Condition string // The if condition
Children []Node // Content when condition is true
ElseIf []*ElseIfBranch
Else []Node // Content for else branch
}
func (i *IfBlockNode) NodeType() string { return "IfBlock" }
// ElseIfBranch represents an elif branch in conditional
type ElseIfBranch struct {
Condition string
Children []Node
}
// ImportNode represents { s-imp "@alias/file" }
type ImportNode struct {
Path string // Import path (e.g., "@components/Button")
Alias string // Optional alias for the import
}
func (i *ImportNode) NodeType() string { return "Import" }
// DirectiveType represents the type of directive
type DirectiveType int
const (
DirectiveConditional DirectiveType = iota // s-if, s-else-if, s-else
DirectiveLoop // s-for
DirectiveModel // s-model
DirectiveEvent // s-on:event, @event
DirectiveBind // :attr
DirectiveClient // s-client:load, s-client:visible, etc.
DirectiveFetch // s-fetch
DirectiveRef // s-ref
DirectiveHTML // s-html
DirectiveStatic // s-static
)
// Directive represents a Strata directive
type Directive struct {
Type DirectiveType
Name string // Original attribute name
Value string // Attribute value
Arg string // Argument (e.g., "click" in @click)
Modifiers []string // Modifiers (e.g., "prevent" in @click.prevent)
}
// ComponentNode represents a component usage
type ComponentNode struct {
Name string
Props map[string]string
Directives []Directive
Slots map[string][]Node
}
func (c *ComponentNode) NodeType() string { return "Component" }
// SlotNode represents a <slot> element
type SlotNode struct {
Name string // default or named
Fallback []Node
}
func (s *SlotNode) NodeType() string { return "Slot" }
// ImportDeclaration represents an import statement
type ImportDeclaration struct {
Default string // Default import name
Named []string // Named imports
Source string // Import source path
}
// ComponentDefinition represents a component's parsed definition
type ComponentDefinition struct {
Name string
Props []PropDefinition
Imports []ImportDeclaration
Setup string // The setup function body
}
// PropDefinition represents a component prop
type PropDefinition struct {
Name string
Type string
Required bool
Default string
}
// StoreDefinition represents a parsed store
type StoreDefinition struct {
Name string
State map[string]string // Field name -> type
Actions []ActionDefinition
Encrypt []string // Fields to encrypt
Persist []string // Fields to persist
Shared []string // Fields to share across tabs
}
// ActionDefinition represents a store action
type ActionDefinition struct {
Name string
Params []string
Body string
Async bool
}
// ToHTML converts a TemplateNode to HTML string
func (t *TemplateNode) ToHTML() string {
var result string
for _, child := range t.Children {
result += nodeToHTML(child)
}
return result
}
// nodeToHTML converts any AST node to HTML
func nodeToHTML(node Node) string {
if node == nil {
return ""
}
switch n := node.(type) {
case *ElementNode:
return elementToHTML(n)
case *TextNode:
return n.Content
case *InterpolationNode:
// For dev mode, output a placeholder that will be filled by JS
return `<span data-strata-bind="` + n.Expression + `"></span>`
case *ForBlockNode:
return forBlockToHTML(n)
case *IfBlockNode:
return ifBlockToHTML(n)
case *ImportNode:
// Imports are handled at compile time, not rendered
return ""
default:
return ""
}
}
// forBlockToHTML converts a ForBlockNode to HTML with data attributes
func forBlockToHTML(f *ForBlockNode) string {
html := `<template data-strata-for="` + f.Item
if f.Index != "" {
html += `, ` + f.Index
}
html += ` in ` + f.Iterable + `">`
for _, child := range f.Children {
html += nodeToHTML(child)
}
html += `</template>`
return html
}
// ifBlockToHTML converts an IfBlockNode to HTML with data attributes
func ifBlockToHTML(i *IfBlockNode) string {
html := `<template data-strata-if="` + i.Condition + `">`
for _, child := range i.Children {
html += nodeToHTML(child)
}
html += `</template>`
// Handle elif branches
for _, elif := range i.ElseIf {
html += `<template data-strata-elif="` + elif.Condition + `">`
for _, child := range elif.Children {
html += nodeToHTML(child)
}
html += `</template>`
}
// Handle else branch
if len(i.Else) > 0 {
html += `<template data-strata-else>`
for _, child := range i.Else {
html += nodeToHTML(child)
}
html += `</template>`
}
return html
}
// elementToHTML converts an ElementNode to HTML
func elementToHTML(el *ElementNode) string {
if el == nil {
return ""
}
html := "<" + el.Tag
// Add attributes
for name, value := range el.Attributes {
if value != "" {
html += ` ` + name + `="` + value + `"`
} else {
html += ` ` + name
}
}
// Add directive attributes for dev mode debugging
for _, dir := range el.Directives {
html += ` data-strata-` + dir.Name + `="` + dir.Value + `"`
}
html += ">"
// Add children
for _, child := range el.Children {
html += nodeToHTML(child)
}
// Close tag (unless void element)
voidElements := map[string]bool{
"area": true, "base": true, "br": true, "col": true,
"embed": true, "hr": true, "img": true, "input": true,
"link": true, "meta": true, "param": true, "source": true,
"track": true, "wbr": true,
}
if !voidElements[el.Tag] {
html += "</" + el.Tag + ">"
}
return html
}