add bracket syntax replace tests
This commit is contained in:
@ -7,8 +7,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Read the example.masonry file
|
||||
content, err := os.ReadFile("example.masonry")
|
||||
// Read the example.masonry file from the correct path
|
||||
content, err := os.ReadFile("examples/lang/example.masonry")
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading example.masonry: %v\n", err)
|
||||
return
|
||||
@ -16,456 +16,133 @@ func main() {
|
||||
|
||||
input := string(content)
|
||||
|
||||
// Try to parse the DSL
|
||||
ast, err := lang.ParseInput(input)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("🎉 Successfully parsed enhanced DSL with containers and detailed fields!\n\n")
|
||||
fmt.Printf("❌ Parse Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, def := range ast.Definitions {
|
||||
if def.Server != nil {
|
||||
fmt.Printf("📡 Server: %s\n", def.Server.Name)
|
||||
for _, setting := range def.Server.Settings {
|
||||
if setting.Host != nil {
|
||||
fmt.Printf(" host: %s\n", *setting.Host)
|
||||
}
|
||||
if setting.Port != nil {
|
||||
fmt.Printf(" port: %d\n", *setting.Port)
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
// If we get here, parsing was successful!
|
||||
fmt.Printf("🎉 Successfully parsed DSL with block delimiters!\n\n")
|
||||
|
||||
// Count what we parsed
|
||||
var servers, entities, endpoints, pages int
|
||||
for _, def := range ast.Definitions {
|
||||
if def.Server != nil {
|
||||
servers++
|
||||
}
|
||||
if def.Entity != nil {
|
||||
entities++
|
||||
}
|
||||
if def.Endpoint != nil {
|
||||
endpoints++
|
||||
}
|
||||
if def.Page != nil {
|
||||
pages++
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("📊 Parsing Summary:\n")
|
||||
fmt.Printf(" Servers: %d\n", servers)
|
||||
fmt.Printf(" Entities: %d\n", entities)
|
||||
fmt.Printf(" Endpoints: %d\n", endpoints)
|
||||
fmt.Printf(" Pages: %d\n", pages)
|
||||
fmt.Printf(" Total Definitions: %d\n", len(ast.Definitions))
|
||||
|
||||
// Verify key structures parsed correctly
|
||||
fmt.Printf("\n✅ Validation Results:\n")
|
||||
|
||||
// Check server has settings in block
|
||||
for _, def := range ast.Definitions {
|
||||
if def.Server != nil {
|
||||
if len(def.Server.Settings) > 0 {
|
||||
fmt.Printf(" ✓ Server '%s' has %d settings (block syntax working)\n", def.Server.Name, len(def.Server.Settings))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if def.Entity != nil {
|
||||
entity := def.Entity
|
||||
fmt.Printf("🏗️ Entity: %s", entity.Name)
|
||||
if entity.Description != nil {
|
||||
fmt.Printf(" - %s", *entity.Description)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
for _, field := range entity.Fields {
|
||||
fmt.Printf(" %s: %s", field.Name, field.Type)
|
||||
if field.Required {
|
||||
fmt.Printf(" (required)")
|
||||
}
|
||||
if field.Unique {
|
||||
fmt.Printf(" (unique)")
|
||||
}
|
||||
if field.Default != nil {
|
||||
fmt.Printf(" default=%s", *field.Default)
|
||||
}
|
||||
if field.Relationship != nil {
|
||||
fmt.Printf(" relates to %s as %s", field.Relationship.Type, field.Relationship.Cardinality)
|
||||
if field.Relationship.ForeignKey != nil {
|
||||
fmt.Printf(" via %s", *field.Relationship.ForeignKey)
|
||||
}
|
||||
if field.Relationship.Through != nil {
|
||||
fmt.Printf(" through %s", *field.Relationship.Through)
|
||||
}
|
||||
}
|
||||
if len(field.Validations) > 0 {
|
||||
fmt.Printf(" validates: ")
|
||||
for i, val := range field.Validations {
|
||||
if i > 0 {
|
||||
fmt.Printf(", ")
|
||||
}
|
||||
fmt.Printf("%s", val.Type)
|
||||
if val.Value != nil {
|
||||
fmt.Printf("(%s)", *val.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
// Check entities have fields in blocks
|
||||
entityCount := 0
|
||||
for _, def := range ast.Definitions {
|
||||
if def.Entity != nil {
|
||||
entityCount++
|
||||
if len(def.Entity.Fields) > 0 {
|
||||
fmt.Printf(" ✓ Entity '%s' has %d fields (block syntax working)\n", def.Entity.Name, len(def.Entity.Fields))
|
||||
}
|
||||
|
||||
if def.Endpoint != nil {
|
||||
endpoint := def.Endpoint
|
||||
fmt.Printf("🚀 Endpoint: %s %s", endpoint.Method, endpoint.Path)
|
||||
if endpoint.Entity != nil {
|
||||
fmt.Printf(" (for %s)", *endpoint.Entity)
|
||||
}
|
||||
if endpoint.Description != nil {
|
||||
fmt.Printf(" - %s", *endpoint.Description)
|
||||
}
|
||||
if endpoint.Auth {
|
||||
fmt.Printf(" [AUTH]")
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
for _, param := range endpoint.Params {
|
||||
fmt.Printf(" param %s: %s from %s", param.Name, param.Type, param.Source)
|
||||
if param.Required {
|
||||
fmt.Printf(" (required)")
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
if endpoint.Response != nil {
|
||||
fmt.Printf(" returns %s", endpoint.Response.Type)
|
||||
if endpoint.Response.Format != nil {
|
||||
fmt.Printf(" as %s", *endpoint.Response.Format)
|
||||
}
|
||||
if len(endpoint.Response.Fields) > 0 {
|
||||
fmt.Printf(" fields: %v", endpoint.Response.Fields)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
if endpoint.CustomLogic != nil {
|
||||
fmt.Printf(" custom logic: %s\n", *endpoint.CustomLogic)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
if def.Page != nil {
|
||||
page := def.Page
|
||||
fmt.Printf("🎨 Page: %s at %s", page.Name, page.Path)
|
||||
if page.Title != nil {
|
||||
fmt.Printf(" - %s", *page.Title)
|
||||
}
|
||||
if page.Auth {
|
||||
fmt.Printf(" [AUTH]")
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf(" Layout: %s\n", page.Layout)
|
||||
|
||||
if page.LayoutType != nil {
|
||||
fmt.Printf(" Layout Type: %s\n", *page.LayoutType)
|
||||
}
|
||||
|
||||
for _, meta := range page.Meta {
|
||||
fmt.Printf(" Meta %s: %s\n", meta.Name, meta.Content)
|
||||
}
|
||||
|
||||
// Display containers
|
||||
for _, container := range page.Containers {
|
||||
fmt.Printf(" 📦 Container: %s", container.Type)
|
||||
if container.Class != nil {
|
||||
fmt.Printf(" class=\"%s\"", *container.Class)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
for _, section := range container.Sections {
|
||||
fmt.Printf(" 📂 Section: %s", section.Name)
|
||||
if section.Class != nil {
|
||||
fmt.Printf(" class=\"%s\"", *section.Class)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
for _, comp := range section.Components {
|
||||
displayComponent(comp, " ")
|
||||
}
|
||||
|
||||
for _, panel := range section.Panels {
|
||||
fmt.Printf(" 🗂️ Panel: %s trigger=\"%s\"", panel.Name, panel.Trigger)
|
||||
if panel.Position != nil {
|
||||
fmt.Printf(" position=\"%s\"", *panel.Position)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
for _, comp := range panel.Components {
|
||||
displayComponent(comp, " ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, tab := range container.Tabs {
|
||||
fmt.Printf(" 📋 Tab: %s label=\"%s\"", tab.Name, tab.Label)
|
||||
if tab.Active {
|
||||
fmt.Printf(" (active)")
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
for _, comp := range tab.Components {
|
||||
displayComponent(comp, " ")
|
||||
}
|
||||
}
|
||||
|
||||
for _, comp := range container.Components {
|
||||
displayComponent(comp, " ")
|
||||
}
|
||||
}
|
||||
|
||||
// Display direct components
|
||||
for _, comp := range page.Components {
|
||||
displayComponent(comp, " ")
|
||||
}
|
||||
|
||||
// Display modals
|
||||
for _, modal := range page.Modals {
|
||||
fmt.Printf(" 🪟 Modal: %s trigger=\"%s\"\n", modal.Name, modal.Trigger)
|
||||
for _, comp := range modal.Components {
|
||||
displayComponent(comp, " ")
|
||||
}
|
||||
}
|
||||
|
||||
// Display master-detail layout
|
||||
if page.MasterDetail != nil {
|
||||
fmt.Printf(" 🔄 Master-Detail Layout\n")
|
||||
if page.MasterDetail.Master != nil {
|
||||
fmt.Printf(" 📋 Master: %s\n", page.MasterDetail.Master.Name)
|
||||
for _, comp := range page.MasterDetail.Master.Components {
|
||||
displayComponent(comp, " ")
|
||||
}
|
||||
}
|
||||
if page.MasterDetail.Detail != nil {
|
||||
fmt.Printf(" 📄 Detail: %s", page.MasterDetail.Detail.Name)
|
||||
if page.MasterDetail.Detail.Trigger != nil {
|
||||
fmt.Printf(" trigger=\"%s\"", *page.MasterDetail.Detail.Trigger)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
for _, comp := range page.MasterDetail.Detail.Components {
|
||||
displayComponent(comp, " ")
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
if entityCount >= 2 { // Just show first couple
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check endpoints have params in blocks
|
||||
endpointCount := 0
|
||||
for _, def := range ast.Definitions {
|
||||
if def.Endpoint != nil {
|
||||
endpointCount++
|
||||
if len(def.Endpoint.Params) > 0 {
|
||||
fmt.Printf(" ✓ Endpoint '%s %s' has %d params (block syntax working)\n", def.Endpoint.Method, def.Endpoint.Path, len(def.Endpoint.Params))
|
||||
}
|
||||
if endpointCount >= 2 { // Just show first couple
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check pages have content in blocks
|
||||
pageCount := 0
|
||||
for _, def := range ast.Definitions {
|
||||
if def.Page != nil {
|
||||
pageCount++
|
||||
totalContent := len(def.Page.Meta) + len(def.Page.Sections) + len(def.Page.Components)
|
||||
if totalContent > 0 {
|
||||
fmt.Printf(" ✓ Page '%s' has %d content items (block syntax working)\n", def.Page.Name, totalContent)
|
||||
}
|
||||
if pageCount >= 2 { // Just show first couple
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for nested sections (complex structures)
|
||||
var totalSections, nestedSections int
|
||||
for _, def := range ast.Definitions {
|
||||
if def.Page != nil {
|
||||
totalSections += len(def.Page.Sections)
|
||||
for _, section := range def.Page.Sections {
|
||||
nestedSections += countNestedSections(section)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if totalSections > 0 {
|
||||
fmt.Printf(" ✓ Found %d sections with %d nested levels (recursive parsing working)\n", totalSections, nestedSections)
|
||||
}
|
||||
|
||||
fmt.Printf("\n🎯 Block delimiter syntax is working correctly!\n")
|
||||
fmt.Printf(" All constructs (server, entity, endpoint, page, section, component) now use { } blocks\n")
|
||||
fmt.Printf(" No more ambiguous whitespace-dependent parsing\n")
|
||||
fmt.Printf(" Language is now unambiguous and consistent\n")
|
||||
}
|
||||
|
||||
func displayComponent(comp lang.Component, indent string) {
|
||||
fmt.Printf("%s🧩 Component: %s", indent, comp.Type)
|
||||
if comp.Entity != nil {
|
||||
fmt.Printf(" for %s", *comp.Entity)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
// Process elements to extract fields, config, conditions, sections, and actions
|
||||
var fields []lang.ComponentField
|
||||
var config []lang.ComponentAttr
|
||||
var conditions []lang.WhenCondition
|
||||
var sections []lang.ComponentSection
|
||||
var actions []lang.ComponentButtonAttr
|
||||
|
||||
for _, element := range comp.Elements {
|
||||
if element.Field != nil {
|
||||
fields = append(fields, *element.Field)
|
||||
}
|
||||
if element.Config != nil {
|
||||
config = append(config, *element.Config)
|
||||
}
|
||||
if element.Condition != nil {
|
||||
conditions = append(conditions, *element.Condition)
|
||||
}
|
||||
// Helper function to count nested sections recursively
|
||||
func countNestedSections(section lang.Section) int {
|
||||
count := 0
|
||||
for _, element := range section.Elements {
|
||||
if element.Section != nil {
|
||||
sections = append(sections, *element.Section)
|
||||
count++
|
||||
count += countNestedSections(*element.Section)
|
||||
}
|
||||
if element.Action != nil {
|
||||
actions = append(actions, *element.Action)
|
||||
if element.Component != nil {
|
||||
for _, compElement := range element.Component.Elements {
|
||||
if compElement.Section != nil {
|
||||
count++
|
||||
count += countNestedSections(*compElement.Section)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display config attributes
|
||||
for _, attr := range config {
|
||||
if attr.Fields != nil {
|
||||
fmt.Printf("%s fields: %v\n", indent, attr.Fields.Fields)
|
||||
}
|
||||
if attr.Actions != nil {
|
||||
fmt.Printf("%s actions: ", indent)
|
||||
for i, action := range attr.Actions.Actions {
|
||||
if i > 0 {
|
||||
fmt.Printf(", ")
|
||||
}
|
||||
fmt.Printf("%s", action.Name)
|
||||
if action.Endpoint != nil {
|
||||
fmt.Printf(" via %s", *action.Endpoint)
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
if attr.DataSource != nil {
|
||||
fmt.Printf("%s data from: %s\n", indent, attr.DataSource.Endpoint)
|
||||
}
|
||||
if attr.Style != nil {
|
||||
fmt.Printf("%s style: %s", indent, *attr.Style.Theme)
|
||||
if len(attr.Style.Classes) > 0 {
|
||||
fmt.Printf(" classes: %v", attr.Style.Classes)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
if attr.Pagination != nil {
|
||||
fmt.Printf("%s pagination: enabled", indent)
|
||||
if attr.Pagination.PageSize != nil {
|
||||
fmt.Printf(" size %d", *attr.Pagination.PageSize)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
if attr.Filters != nil {
|
||||
fmt.Printf("%s filters: ", indent)
|
||||
for i, filter := range attr.Filters.Filters {
|
||||
if i > 0 {
|
||||
fmt.Printf(", ")
|
||||
}
|
||||
fmt.Printf("%s as %s", filter.Field, filter.Type)
|
||||
if filter.Label != nil {
|
||||
fmt.Printf(" (%s)", *filter.Label)
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
if attr.Validation {
|
||||
fmt.Printf("%s validation: enabled\n", indent)
|
||||
}
|
||||
}
|
||||
|
||||
// Display enhanced fields
|
||||
for _, field := range fields {
|
||||
fmt.Printf("%s 📝 Field: %s type %s", indent, field.Name, field.Type)
|
||||
|
||||
// Process attributes
|
||||
for _, attr := range field.Attributes {
|
||||
if attr.Label != nil {
|
||||
fmt.Printf(" label=\"%s\"", *attr.Label)
|
||||
}
|
||||
if attr.Placeholder != nil {
|
||||
fmt.Printf(" placeholder=\"%s\"", *attr.Placeholder)
|
||||
}
|
||||
if attr.Required {
|
||||
fmt.Printf(" (required)")
|
||||
}
|
||||
if attr.Sortable {
|
||||
fmt.Printf(" (sortable)")
|
||||
}
|
||||
if attr.Searchable {
|
||||
fmt.Printf(" (searchable)")
|
||||
}
|
||||
if attr.Thumbnail {
|
||||
fmt.Printf(" (thumbnail)")
|
||||
}
|
||||
if attr.Default != nil {
|
||||
fmt.Printf(" default=\"%s\"", *attr.Default)
|
||||
}
|
||||
if len(attr.Options) > 0 {
|
||||
fmt.Printf(" options=%v", attr.Options)
|
||||
}
|
||||
if attr.Accept != nil {
|
||||
fmt.Printf(" accept=\"%s\"", *attr.Accept)
|
||||
}
|
||||
if attr.Rows != nil {
|
||||
fmt.Printf(" rows=%d", *attr.Rows)
|
||||
}
|
||||
if attr.Format != nil {
|
||||
fmt.Printf(" format=\"%s\"", *attr.Format)
|
||||
}
|
||||
if attr.Size != nil {
|
||||
fmt.Printf(" size=\"%s\"", *attr.Size)
|
||||
}
|
||||
if attr.Source != nil {
|
||||
fmt.Printf(" source=\"%s\"", *attr.Source)
|
||||
}
|
||||
if attr.Display != nil {
|
||||
fmt.Printf(" display=\"%s\"", *attr.Display)
|
||||
}
|
||||
if attr.Value != nil {
|
||||
fmt.Printf(" value=\"%s\"", *attr.Value)
|
||||
}
|
||||
if attr.Relates != nil {
|
||||
fmt.Printf(" relates to %s", attr.Relates.Type)
|
||||
}
|
||||
if attr.Validation != nil {
|
||||
fmt.Printf(" validates: %s", attr.Validation.Type)
|
||||
if attr.Validation.Value != nil {
|
||||
fmt.Printf("(%s)", *attr.Validation.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
// Display conditions
|
||||
for _, condition := range conditions {
|
||||
fmt.Printf("%s 🔀 When %s %s \"%s\":\n", indent, condition.Field, condition.Operator, condition.Value)
|
||||
for _, field := range condition.Fields {
|
||||
fmt.Printf("%s 📝 Field: %s type %s", indent, field.Name, field.Type)
|
||||
// Process attributes for conditional fields
|
||||
for _, attr := range field.Attributes {
|
||||
if attr.Label != nil {
|
||||
fmt.Printf(" label=\"%s\"", *attr.Label)
|
||||
}
|
||||
if len(attr.Options) > 0 {
|
||||
fmt.Printf(" options=%v", attr.Options)
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
for _, section := range condition.Sections {
|
||||
fmt.Printf("%s 📂 Section: %s\n", indent, section.Name)
|
||||
}
|
||||
for _, button := range condition.Buttons {
|
||||
fmt.Printf("%s 🔘 Button: %s label=\"%s\"", indent, button.Name, button.Label)
|
||||
if button.Style != nil {
|
||||
fmt.Printf(" style=\"%s\"", *button.Style)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
// Display sections
|
||||
for _, section := range sections {
|
||||
fmt.Printf("%s 📂 Section: %s", indent, section.Name)
|
||||
if section.Class != nil {
|
||||
fmt.Printf(" class=\"%s\"", *section.Class)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
for _, field := range section.Fields {
|
||||
fmt.Printf("%s 📝 Field: %s type %s", indent, field.Name, field.Type)
|
||||
// Process attributes for section fields
|
||||
for _, attr := range field.Attributes {
|
||||
if attr.Label != nil {
|
||||
fmt.Printf(" label=\"%s\"", *attr.Label)
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
for _, button := range section.Buttons {
|
||||
fmt.Printf("%s 🔘 Button: %s label=\"%s\"", indent, button.Name, button.Label)
|
||||
if button.Style != nil {
|
||||
fmt.Printf(" style=\"%s\"", *button.Style)
|
||||
}
|
||||
if button.Via != nil {
|
||||
fmt.Printf(" via=\"%s\"", *button.Via)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
for _, action := range section.Actions {
|
||||
fmt.Printf("%s ⚡ Action: %s label=\"%s\"", indent, action.Name, action.Label)
|
||||
if action.Style != nil {
|
||||
fmt.Printf(" style=\"%s\"", *action.Style)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
// Display direct actions/buttons
|
||||
for _, action := range actions {
|
||||
fmt.Printf("%s 🔘 Button: %s label=\"%s\"", indent, action.Name, action.Label)
|
||||
if action.Style != nil {
|
||||
fmt.Printf(" style=\"%s\"", *action.Style)
|
||||
}
|
||||
if action.Icon != nil {
|
||||
fmt.Printf(" icon=\"%s\"", *action.Icon)
|
||||
}
|
||||
if action.Loading != nil {
|
||||
fmt.Printf(" loading=\"%s\"", *action.Loading)
|
||||
}
|
||||
if action.Disabled != nil {
|
||||
fmt.Printf(" disabled when %s", *action.Disabled)
|
||||
}
|
||||
if action.Confirm != nil {
|
||||
fmt.Printf(" confirm=\"%s\"", *action.Confirm)
|
||||
}
|
||||
if action.Target != nil {
|
||||
fmt.Printf(" target=\"%s\"", *action.Target)
|
||||
}
|
||||
if action.Position != nil {
|
||||
fmt.Printf(" position=\"%s\"", *action.Position)
|
||||
}
|
||||
if action.Via != nil {
|
||||
fmt.Printf(" via=\"%s\"", *action.Via)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
@ -1,186 +1,295 @@
|
||||
// Enhanced Masonry DSL example demonstrating new features
|
||||
// This shows the comprehensive language structure with containers, detailed fields, and layouts
|
||||
// Enhanced Masonry DSL example demonstrating simplified unified structure
|
||||
// This shows how containers, tabs, panels, modals, and master-detail are now unified as sections
|
||||
|
||||
// Server configuration
|
||||
server MyApp host "localhost" port 8080
|
||||
server MyApp {
|
||||
host "localhost"
|
||||
port 8080
|
||||
}
|
||||
|
||||
// Entity definitions with various field types and relationships
|
||||
entity User desc "User account management"
|
||||
id: uuid required unique
|
||||
email: string required validate email validate min_length "5"
|
||||
name: string default "Anonymous"
|
||||
created_at: timestamp default "now()"
|
||||
profile_id: uuid relates to Profile as one via "user_id"
|
||||
entity User desc "User account management" {
|
||||
id: uuid required unique
|
||||
email: string required validate email validate min_length "5"
|
||||
name: string default "Anonymous"
|
||||
created_at: timestamp default "now()"
|
||||
profile_id: uuid relates to Profile as one via "user_id"
|
||||
}
|
||||
|
||||
entity Profile desc "User profile information"
|
||||
id: uuid required unique
|
||||
user_id: uuid required relates to User as one
|
||||
bio: text validate max_length "500"
|
||||
avatar_url: string validate url
|
||||
updated_at: timestamp
|
||||
posts: uuid relates to Post as many
|
||||
entity Profile desc "User profile information" {
|
||||
id: uuid required unique
|
||||
user_id: uuid required relates to User as one
|
||||
bio: text validate max_length "500"
|
||||
avatar_url: string validate url
|
||||
updated_at: timestamp
|
||||
posts: uuid relates to Post as many
|
||||
}
|
||||
|
||||
entity Post desc "Blog posts"
|
||||
id: uuid required unique
|
||||
title: string required validate min_length "1" validate max_length "200"
|
||||
content: text required
|
||||
author_id: uuid required relates to User as one
|
||||
published: boolean default "false"
|
||||
created_at: timestamp default "now()"
|
||||
tags: uuid relates to Tag as many through "post_tags"
|
||||
entity Post desc "Blog posts" {
|
||||
id: uuid required unique
|
||||
title: string required validate min_length "1" validate max_length "200"
|
||||
content: text required
|
||||
author_id: uuid required relates to User as one
|
||||
published: boolean default "false"
|
||||
created_at: timestamp default "now()"
|
||||
tags: uuid relates to Tag as many through "post_tags"
|
||||
}
|
||||
|
||||
entity Tag desc "Content tags"
|
||||
id: uuid required unique
|
||||
name: string required unique validate min_length "1" validate max_length "50"
|
||||
slug: string required unique indexed
|
||||
created_at: timestamp default "now()"
|
||||
entity Tag desc "Content tags" {
|
||||
id: uuid required unique
|
||||
name: string required unique validate min_length "1" validate max_length "50"
|
||||
slug: string required unique indexed
|
||||
created_at: timestamp default "now()"
|
||||
}
|
||||
|
||||
// API Endpoints with different HTTP methods and parameter sources
|
||||
endpoint GET "/users" for User desc "List users" auth
|
||||
param page: int from query
|
||||
param limit: int required from query
|
||||
returns list as "json" fields [id, email, name]
|
||||
endpoint GET "/users" for User desc "List users" auth {
|
||||
param page: int from query
|
||||
param limit: int required from query
|
||||
returns list as "json" fields [id, email, name]
|
||||
}
|
||||
|
||||
endpoint POST "/users" for User desc "Create user"
|
||||
param user_data: object required from body
|
||||
returns object as "json" fields [id, email, name]
|
||||
endpoint POST "/users" for User desc "Create user" {
|
||||
param user_data: object required from body
|
||||
returns object as "json" fields [id, email, name]
|
||||
}
|
||||
|
||||
endpoint PUT "/users/{id}" for User desc "Update user"
|
||||
param id: uuid required from path
|
||||
param user_data: object required from body
|
||||
returns object
|
||||
custom "update_user_logic"
|
||||
endpoint PUT "/users/{id}" for User desc "Update user" {
|
||||
param id: uuid required from path
|
||||
param user_data: object required from body
|
||||
returns object
|
||||
custom "update_user_logic"
|
||||
}
|
||||
|
||||
endpoint DELETE "/users/{id}" for User desc "Delete user" auth
|
||||
param id: uuid required from path
|
||||
returns object
|
||||
endpoint DELETE "/users/{id}" for User desc "Delete user" auth {
|
||||
param id: uuid required from path
|
||||
returns object
|
||||
}
|
||||
|
||||
endpoint GET "/posts" for Post desc "List posts"
|
||||
param author_id: uuid from query
|
||||
param published: boolean from query
|
||||
param page: int from query
|
||||
returns list as "json" fields [id, title, author_id, published]
|
||||
endpoint GET "/posts" for Post desc "List posts" {
|
||||
param author_id: uuid from query
|
||||
param published: boolean from query
|
||||
param page: int from query
|
||||
returns list as "json" fields [id, title, author_id, published]
|
||||
}
|
||||
|
||||
endpoint POST "/posts" for Post desc "Create post" auth
|
||||
param post_data: object required from body
|
||||
returns object fields [id, title, content, author_id]
|
||||
endpoint POST "/posts" for Post desc "Create post" auth {
|
||||
param post_data: object required from body
|
||||
returns object fields [id, title, content, author_id]
|
||||
}
|
||||
|
||||
// Enhanced User Management page with container layout
|
||||
page UserManagement at "/admin/users" layout AdminLayout title "User Management" auth
|
||||
meta description "Manage system users"
|
||||
meta keywords "users, admin, management"
|
||||
// Enhanced User Management page with unified section layout
|
||||
page UserManagement at "/admin/users" layout AdminLayout title "User Management" auth {
|
||||
meta description "Manage system users"
|
||||
meta keywords "users, admin, management"
|
||||
|
||||
container main class "grid grid-cols-3 gap-4"
|
||||
section sidebar class "col-span-1"
|
||||
component UserStats for User
|
||||
data from "/users/stats"
|
||||
section main type container class "grid grid-cols-3 gap-4" {
|
||||
section sidebar class "col-span-1" {
|
||||
component UserStats for User {
|
||||
data from "/users/stats"
|
||||
}
|
||||
}
|
||||
|
||||
section content class "col-span-2"
|
||||
component UserTable for User
|
||||
fields [email, name, role, created_at]
|
||||
actions [edit, delete, view]
|
||||
data from "/users"
|
||||
section content class "col-span-2" {
|
||||
component UserTable for User {
|
||||
fields [email, name, role, created_at]
|
||||
actions [edit, delete, view]
|
||||
data from "/users"
|
||||
}
|
||||
|
||||
panel UserEditPanel for User trigger "edit" position "slide-right"
|
||||
component UserForm for User
|
||||
field email type text label "Email" required
|
||||
field name type text label "Name" required
|
||||
field role type select options ["admin", "user"]
|
||||
button save label "Save User" style "primary" via "/users/{id}"
|
||||
button cancel label "Cancel" style "secondary"
|
||||
section editPanel type panel trigger "edit" position "slide-right" for User {
|
||||
component UserForm for User {
|
||||
field email type text label "Email" required
|
||||
field name type text label "Name" required
|
||||
field role type select options ["admin", "user"]
|
||||
button save label "Save User" style "primary" via "/users/{id}"
|
||||
button cancel label "Cancel" style "secondary"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enhanced Form component with detailed field configurations
|
||||
page UserFormPage at "/admin/users/new" layout AdminLayout title "Create User" auth
|
||||
component Form for User
|
||||
field email type text label "Email Address" placeholder "Enter your email" required validate email
|
||||
field name type text label "Full Name" placeholder "Enter your full name" required
|
||||
field role type select label "User Role" options ["admin", "user", "moderator"] default "user"
|
||||
field avatar type file label "Profile Picture" accept "image/*"
|
||||
field bio type textarea label "Biography" placeholder "Tell us about yourself" rows 4
|
||||
page UserFormPage at "/admin/users/new" layout AdminLayout title "Create User" auth {
|
||||
component Form for User {
|
||||
field email type text label "Email Address" placeholder "Enter your email" required validate email
|
||||
field name type text label "Full Name" placeholder "Enter your full name" required
|
||||
field role type select label "User Role" options ["admin", "user", "moderator"] default "user"
|
||||
field avatar type file label "Profile Picture" accept "image/*"
|
||||
field bio type textarea label "Biography" placeholder "Tell us about yourself" rows 4
|
||||
|
||||
when role equals "admin"
|
||||
field permissions type multiselect label "Permissions"
|
||||
options ["users.manage", "posts.manage", "system.config"]
|
||||
when role equals "admin" {
|
||||
component AdminPermissions {
|
||||
field permissions type multiselect label "Permissions" {
|
||||
options ["users.manage", "posts.manage", "system.config"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section actions
|
||||
button save label "Save User" style "primary" loading "Saving..." via "/users"
|
||||
button cancel label "Cancel" style "secondary"
|
||||
section actions {
|
||||
component ActionButtons {
|
||||
button save label "Save User" style "primary" loading "Saving..." via "/users"
|
||||
button cancel label "Cancel" style "secondary"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dashboard with tabbed interface
|
||||
page Dashboard at "/dashboard" layout MainLayout title "Dashboard"
|
||||
container tabs
|
||||
tab overview label "Overview" active
|
||||
component StatsCards
|
||||
component RecentActivity
|
||||
// Dashboard with tabbed interface using unified sections
|
||||
page Dashboard at "/dashboard" layout MainLayout title "Dashboard" {
|
||||
section tabs type container {
|
||||
section overview type tab label "Overview" active {
|
||||
component StatsCards
|
||||
component RecentActivity
|
||||
}
|
||||
|
||||
tab users label "Users"
|
||||
component UserTable for User
|
||||
data from "/users"
|
||||
section users type tab label "Users" {
|
||||
component UserTable for User {
|
||||
data from "/users"
|
||||
}
|
||||
}
|
||||
|
||||
tab posts label "Posts"
|
||||
component PostTable for Post
|
||||
data from "/posts"
|
||||
section posts type tab label "Posts" {
|
||||
component PostTable for Post {
|
||||
data from "/posts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
modal CreateUserModal trigger "create-user"
|
||||
component UserForm for User
|
||||
field email type text label "Email" required
|
||||
field name type text label "Name" required
|
||||
button save label "Create" via "/users"
|
||||
button cancel label "Cancel"
|
||||
section createUserModal type modal trigger "create-user" {
|
||||
component UserForm for User {
|
||||
field email type text label "Email" required
|
||||
field name type text label "Name" required
|
||||
button save label "Create" via "/users"
|
||||
button cancel label "Cancel"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Post Management with master-detail layout
|
||||
page PostManagement at "/admin/posts" layout AdminLayout title "Post Management" auth
|
||||
layout "master-detail"
|
||||
// Post Management with master-detail layout using unified sections
|
||||
page PostManagement at "/admin/posts" layout AdminLayout title "Post Management" auth {
|
||||
section master type master {
|
||||
component PostTable for Post {
|
||||
field title type text label "Title" sortable
|
||||
field author type relation label "Author" display "name" relates to User
|
||||
field status type badge label "Status"
|
||||
}
|
||||
}
|
||||
|
||||
master PostList
|
||||
component Table for Post
|
||||
field title type text label "Title" sortable
|
||||
field author type relation label "Author" display "name" relates to User
|
||||
field status type badge label "Status"
|
||||
section detail type detail trigger "edit" {
|
||||
component PostForm for Post {
|
||||
section basic class "mb-4" {
|
||||
component BasicFields {
|
||||
field title type text label "Post Title" required
|
||||
field content type richtext label "Content" required
|
||||
}
|
||||
}
|
||||
|
||||
detail PostEditor trigger "edit"
|
||||
component Form for Post
|
||||
section basic class "mb-4"
|
||||
field title type text label "Post Title" required
|
||||
field content type richtext label "Content" required
|
||||
|
||||
section metadata class "grid grid-cols-2 gap-4"
|
||||
field author_id type autocomplete label "Author"
|
||||
source "/users" display "name" value "id"
|
||||
field published type toggle label "Published" default "false"
|
||||
field tags type multiselect label "Tags"
|
||||
source "/tags" display "name" value "id"
|
||||
section metadata class "grid grid-cols-2 gap-4" {
|
||||
component MetadataFields {
|
||||
field author_id type autocomplete label "Author" {
|
||||
source "/users" display "name" value "id"
|
||||
}
|
||||
field published type toggle label "Published" default "false"
|
||||
field tags type multiselect label "Tags" {
|
||||
source "/tags" display "name" value "id"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple table component with smart defaults
|
||||
page SimpleUserList at "/users" layout MainLayout title "Users"
|
||||
component SimpleTable for User
|
||||
fields [email, name, created_at]
|
||||
actions [edit, delete]
|
||||
data from "/users"
|
||||
page SimpleUserList at "/users" layout MainLayout title "Users" {
|
||||
component SimpleTable for User {
|
||||
fields [email, name, created_at]
|
||||
actions [edit, delete]
|
||||
data from "/users"
|
||||
}
|
||||
}
|
||||
|
||||
// Detailed table when more control is needed
|
||||
page DetailedUserList at "/admin/users/detailed" layout AdminLayout title "Detailed User Management" auth
|
||||
component DetailedTable for User
|
||||
field email type text label "Email Address"
|
||||
field name type text label "Full Name"
|
||||
// Detailed table with simplified component attributes
|
||||
page DetailedUserList at "/admin/users/detailed" layout AdminLayout title "Detailed User Management" auth {
|
||||
component DetailedTable for User {
|
||||
data from "/users"
|
||||
pagination size 20
|
||||
field email type text label "Email Address"
|
||||
field name type text label "Full Name"
|
||||
}
|
||||
}
|
||||
|
||||
data from "/users"
|
||||
pagination size 20
|
||||
// Complex nested sections example
|
||||
page ComplexLayout at "/complex" layout MainLayout title "Complex Layout" {
|
||||
section mainContainer type container class "flex h-screen" {
|
||||
section sidebar type container class "w-64 bg-gray-100" {
|
||||
section navigation {
|
||||
component NavMenu
|
||||
}
|
||||
|
||||
// Conditional rendering example
|
||||
page ConditionalForm at "/conditional" layout MainLayout title "Conditional Form"
|
||||
component UserForm for User
|
||||
field email type text label "Email" required
|
||||
field role type select options ["admin", "user", "moderator"]
|
||||
section userInfo type panel trigger "profile" position "bottom" {
|
||||
component UserProfile
|
||||
}
|
||||
}
|
||||
|
||||
when role equals "admin"
|
||||
field permissions type multiselect label "Admin Permissions"
|
||||
options ["users.manage", "posts.manage", "system.config"]
|
||||
section content type container class "flex-1" {
|
||||
section header class "h-16 border-b" {
|
||||
component PageHeader
|
||||
}
|
||||
|
||||
when role equals "moderator"
|
||||
field moderation_level type select label "Moderation Level"
|
||||
options ["basic", "advanced", "full"]
|
||||
section body class "flex-1 p-4" {
|
||||
section tabs type container {
|
||||
section overview type tab label "Overview" active {
|
||||
section metrics class "grid grid-cols-3 gap-4" {
|
||||
component MetricCard
|
||||
component MetricCard
|
||||
component MetricCard
|
||||
}
|
||||
}
|
||||
|
||||
section actions
|
||||
button save label "Save User" style "primary" loading "Saving..."
|
||||
button cancel label "Cancel" style "secondary"
|
||||
section details type tab label "Details" {
|
||||
component DetailView
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Conditional rendering with sections and components
|
||||
page ConditionalForm at "/conditional" layout MainLayout title "Conditional Form" {
|
||||
component UserForm for User {
|
||||
field email type text label "Email" required
|
||||
field role type select options ["admin", "user", "moderator"]
|
||||
|
||||
when role equals "admin" {
|
||||
section adminSection class "border-l-4 border-red-500 pl-4" {
|
||||
component AdminPermissions {
|
||||
field permissions type multiselect label "Admin Permissions" {
|
||||
options ["users.manage", "posts.manage", "system.config"]
|
||||
}
|
||||
}
|
||||
|
||||
component AdminSettings {
|
||||
field max_users type number label "Max Users"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when role equals "moderator" {
|
||||
component ModeratorSettings {
|
||||
field moderation_level type select label "Moderation Level" {
|
||||
options ["basic", "advanced", "full"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section actions {
|
||||
component ActionButtons {
|
||||
button save label "Save User" style "primary" loading "Saving..."
|
||||
button cancel label "Cancel" style "secondary"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user