define a DSL
This commit is contained in:
181
lang/lang.go
Normal file
181
lang/lang.go
Normal file
@ -0,0 +1,181 @@
|
||||
package lang
|
||||
|
||||
import (
|
||||
"github.com/alecthomas/participle/v2"
|
||||
)
|
||||
|
||||
// Root AST node containing all definitions
|
||||
type AST struct {
|
||||
Definitions []Definition `parser:"@@*"`
|
||||
}
|
||||
|
||||
// Union type for top-level definitions
|
||||
type Definition struct {
|
||||
Server *Server `parser:"@@"`
|
||||
Entity *Entity `parser:"| @@"`
|
||||
Endpoint *Endpoint `parser:"| @@"`
|
||||
Page *Page `parser:"| @@"`
|
||||
}
|
||||
|
||||
// Clean server syntax
|
||||
type Server struct {
|
||||
Name string `parser:"'server' @Ident"`
|
||||
Settings []ServerSetting `parser:"@@*"`
|
||||
}
|
||||
|
||||
type ServerSetting struct {
|
||||
Host *string `parser:"('host' @String)"`
|
||||
Port *int `parser:"| ('port' @Int)"`
|
||||
}
|
||||
|
||||
// Clean entity syntax with better readability
|
||||
type Entity struct {
|
||||
Name string `parser:"'entity' @Ident"`
|
||||
Description *string `parser:"('desc' @String)?"`
|
||||
Fields []Field `parser:"@@*"`
|
||||
}
|
||||
|
||||
// Much cleaner field syntax
|
||||
type Field struct {
|
||||
Name string `parser:"@Ident ':'"`
|
||||
Type string `parser:"@Ident"`
|
||||
Required bool `parser:"@'required'?"`
|
||||
Unique bool `parser:"@'unique'?"`
|
||||
Index bool `parser:"@'indexed'?"`
|
||||
Default *string `parser:"('default' @String)?"`
|
||||
Validations []Validation `parser:"@@*"`
|
||||
Relationship *Relationship `parser:"@@?"`
|
||||
}
|
||||
|
||||
// Simple validation syntax
|
||||
type Validation struct {
|
||||
Type string `parser:"'validate' @Ident"`
|
||||
Value *string `parser:"@String?"`
|
||||
}
|
||||
|
||||
// Clear relationship syntax
|
||||
type Relationship struct {
|
||||
Type string `parser:"'relates' 'to' @Ident"`
|
||||
Cardinality string `parser:"'as' @('one' | 'many')"`
|
||||
ForeignKey *string `parser:"('via' @String)?"`
|
||||
Through *string `parser:"('through' @String)?"`
|
||||
}
|
||||
|
||||
// Endpoint definitions with clean, readable syntax
|
||||
type Endpoint struct {
|
||||
Method string `parser:"'endpoint' @('GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH')"`
|
||||
Path string `parser:"@String"`
|
||||
Entity *string `parser:"('for' @Ident)?"`
|
||||
Description *string `parser:"('desc' @String)?"`
|
||||
Auth bool `parser:"@'auth'?"`
|
||||
Params []EndpointParam `parser:"@@*"`
|
||||
Response *ResponseSpec `parser:"@@?"`
|
||||
CustomLogic *string `parser:"('custom' @String)?"`
|
||||
}
|
||||
|
||||
// Clean parameter syntax
|
||||
type EndpointParam struct {
|
||||
Name string `parser:"'param' @Ident ':'"`
|
||||
Type string `parser:"@Ident"`
|
||||
Required bool `parser:"@'required'?"`
|
||||
Source string `parser:"'from' @('path' | 'query' | 'body')"`
|
||||
}
|
||||
|
||||
// Response specification
|
||||
type ResponseSpec struct {
|
||||
Type string `parser:"'returns' @Ident"`
|
||||
Format *string `parser:"('as' @String)?"`
|
||||
Fields []string `parser:"('fields' '[' @Ident (',' @Ident)* ']')?"`
|
||||
}
|
||||
|
||||
// Page definitions for frontend with clean syntax
|
||||
type Page struct {
|
||||
Name string `parser:"'page' @Ident"`
|
||||
Path string `parser:"'at' @String"`
|
||||
Layout string `parser:"'layout' @Ident"`
|
||||
Title *string `parser:"('title' @String)?"`
|
||||
Description *string `parser:"('desc' @String)?"`
|
||||
Auth bool `parser:"@'auth'?"`
|
||||
Meta []MetaTag `parser:"@@*"`
|
||||
Components []Component `parser:"@@*"`
|
||||
}
|
||||
|
||||
// Meta tags for SEO
|
||||
type MetaTag struct {
|
||||
Name string `parser:"'meta' @Ident"`
|
||||
Content string `parser:"@String"`
|
||||
}
|
||||
|
||||
// Component definitions with endpoint references
|
||||
type Component struct {
|
||||
Type string `parser:"'component' @Ident"`
|
||||
Entity *string `parser:"('for' @Ident)?"`
|
||||
Config []ComponentAttr `parser:"@@*"`
|
||||
}
|
||||
|
||||
// Component attributes and configurations
|
||||
type ComponentAttr struct {
|
||||
Fields *ComponentFields `parser:"@@"`
|
||||
Actions *ComponentActions `parser:"| @@"`
|
||||
DataSource *ComponentDataSource `parser:"| @@"`
|
||||
Style *ComponentStyle `parser:"| @@"`
|
||||
Pagination *ComponentPagination `parser:"| @@"`
|
||||
Filters *ComponentFilters `parser:"| @@"`
|
||||
Validation bool `parser:"| @'validate'"`
|
||||
}
|
||||
|
||||
// Component field specification
|
||||
type ComponentFields struct {
|
||||
Fields []string `parser:"'fields' '[' @Ident (',' @Ident)* ']'"`
|
||||
}
|
||||
|
||||
// Component actions (can reference endpoints)
|
||||
type ComponentActions struct {
|
||||
Actions []ComponentAction `parser:"'actions' '[' @@ (',' @@)* ']'"`
|
||||
}
|
||||
|
||||
type ComponentAction struct {
|
||||
Name string `parser:"@Ident"`
|
||||
Endpoint *string `parser:"('via' @String)?"`
|
||||
}
|
||||
|
||||
// Data source configuration (can reference endpoints)
|
||||
type ComponentDataSource struct {
|
||||
Endpoint string `parser:"'data' 'from' @String"`
|
||||
}
|
||||
|
||||
// Component styling
|
||||
type ComponentStyle struct {
|
||||
Theme *string `parser:"'style' @Ident"`
|
||||
Classes []string `parser:"('classes' '[' @String (',' @String)* ']')?"`
|
||||
}
|
||||
|
||||
// Pagination configuration
|
||||
type ComponentPagination struct {
|
||||
PageSize *int `parser:"'pagination' ('size' @Int)?"`
|
||||
}
|
||||
|
||||
// Filter specifications
|
||||
type ComponentFilters struct {
|
||||
Filters []ComponentFilter `parser:"'filters' '[' @@ (',' @@)* ']'"`
|
||||
}
|
||||
|
||||
type ComponentFilter struct {
|
||||
Field string `parser:"@Ident"`
|
||||
Type string `parser:"'as' @('text' | 'select' | 'date' | 'number')"`
|
||||
Label *string `parser:"('label' @String)?"`
|
||||
}
|
||||
|
||||
func ParseInput(input string) (AST, error) {
|
||||
parser, err := participle.Build[AST](
|
||||
participle.Unquote("String"),
|
||||
)
|
||||
if err != nil {
|
||||
return AST{}, err
|
||||
}
|
||||
ast, err := parser.ParseString("", input)
|
||||
if err != nil {
|
||||
return AST{}, err
|
||||
}
|
||||
return *ast, nil
|
||||
}
|
1114
lang/lang_test.go
Normal file
1114
lang/lang_test.go
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user