try an SDK and a manually defined lang

I don't think I like the SDK way, and langV2 seems to be so simialr to
V1 that I'm probably going to stick with V1 for now and see if i can get
it to do what I need.
This commit is contained in:
2025-08-20 00:13:41 -06:00
parent e9a422ef07
commit 9b209dfe63
8 changed files with 378 additions and 18 deletions

File diff suppressed because one or more lines are too long

33
examples/langV2/debug.go Normal file
View File

@ -0,0 +1,33 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"masonry/langV2"
)
func main() {
// Read the example.masonry file
content, err := ioutil.ReadFile("example.masonry2")
if err != nil {
fmt.Printf("Error reading example.masonry: %v\n", err)
return
}
input := string(content)
ast, err := langV2.ParseInput(input)
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Printf("🎉 Successfully parsed complete DSL with pages!\n\n")
out, err := json.MarshalIndent(ast, "", " ")
if err != nil {
panic(err)
}
println(string(out))
}
}

View File

@ -0,0 +1,39 @@
entity User {
id: string required unique
email: string required unique validate email
name: string required
age: int validate min "18"
created_at: datetime
}
entity Post {
id: string required unique
title: string required validate maxlen "100"
content: string required
author_id: string required relates to User as one via "user_id"
published: bool default "false"
}
server UserService {
GET "/users" entity User
POST "/users" entity User
GET "/users/{id}" entity User
PUT "/users/{id}" entity User
}
server BlogService {
GET "/posts" entity Post
POST "/posts" entity Post
GET "/posts/{id}" entity Post
DELETE "/posts/{id}" entity Post
}
page UserProfile {
User from UserService
Post from BlogService
}
page Dashboard {
User from UserService
Post from BlogService
}

136
examples/sdk/debug_sdk.go Normal file
View File

@ -0,0 +1,136 @@
package main
import (
"encoding/json"
"masonry/sdk"
)
func main() {
userEntity := sdk.Entity{
Name: "User",
Description: nil,
Fields: []sdk.Field{
{
Name: "id",
Type: "int",
Required: true,
Unique: true,
Default: nil,
Validations: []sdk.Validation{
{
Type: "validate",
Value: nil,
},
},
Relationship: nil,
},
{
Name: "username",
Type: "string",
Required: true,
Unique: true,
Default: nil,
Validations: []sdk.Validation{
{
Type: "validate",
Value: nil,
},
},
Relationship: nil,
},
{
Name: "email",
Type: "string",
Required: true,
Unique: true,
Default: nil,
Validations: []sdk.Validation{
{
Type: "validate",
Value: nil,
},
},
Relationship: nil,
},
{
Name: "password",
Type: "string",
Required: true,
Unique: false,
Default: nil,
Validations: []sdk.Validation{
{
Type: "validate",
Value: nil,
},
},
Relationship: nil,
},
{
Name: "created_at",
Type: "datetime",
Required: true,
Unique: false,
Default: nil,
Validations: []sdk.Validation{
{
Type: "validate",
Value: nil,
},
},
Relationship: nil,
},
{
Name: "updated_at",
Type: "datetime",
Required: true,
Unique: false,
Default: nil,
Validations: []sdk.Validation{
{
Type: "validate",
Value: nil,
},
},
Relationship: nil,
},
},
}
createUserDesc := "Create a new user with username, email, and password. Returns the created user object."
createUser := sdk.Endpoint{
Method: "POST",
Path: "/user",
Entity: userEntity,
Description: &createUserDesc,
Auth: true,
Permissions: nil,
}
server := sdk.Server{
Name: "TestServer",
Settings: []sdk.ServerSetting{
{
Host: "localhost",
Port: 8000,
},
},
Endpoints: []sdk.Endpoint{
createUser,
},
}
def := sdk.Definition{
Server: []sdk.Server{
server,
},
}
out, err := json.MarshalIndent(def, "", " ")
if err != nil {
panic(err)
}
println(string(out))
println("🎉 Successfully built SDK definition!")
println("You can now use this SDK definition in your application.")
}

79
langV2/lang.go Normal file
View File

@ -0,0 +1,79 @@
package langV2
import (
participle "github.com/alecthomas/participle/v2"
)
// Root AST node containing all definitions
type AST struct {
Definitions []Definition `parser:"@@*"`
}
type Definition struct {
Entity *EntityDef `parser:"@@"`
Server *ServerDef `parser:"| @@"`
Page *PageDef `parser:"| @@"`
Component *ComponentDef `parser:"| @@"`
}
type EntityDef struct {
Name string `parser:"'entity' @Ident"`
Fields []Field `parser:"'{' @@* '}'"`
}
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:"@@?"`
}
type Validation struct {
Type string `parser:"'validate' @Ident"`
Value *string `parser:"@String?"`
}
type Relationship struct {
Type string `parser:"'relates' 'to' @Ident"`
Cardinality string `parser:"'as' @('one' | 'many')"`
ForeignKey *string `parser:"('via' @String)?"`
}
type ServerDef struct {
Name string `parser:"'server' @Ident"`
Endpoints []EndpointDef `parser:"'{' @@* '}'"`
}
type EndpointDef struct {
Method string `parser:"@('GET'|'POST'|'PUT'|'DELETE')"`
Path string `parser:"@String"`
EntityRef string `parser:"'entity' @Ident"`
}
type ComponentDef struct {
EntityRef string `parser:"@Ident"`
ServerRef string `parser:"('from' @Ident)?"`
}
type PageDef struct {
Name string `parser:"'page' @Ident"`
Components []ComponentDef `parser:"'{' @@* '}'"`
}
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
}

91
sdk/sdk.go Normal file
View File

@ -0,0 +1,91 @@
package sdk
type Definition struct {
Server []Server `json:"server,omitempty"`
Entity []Entity `json:"entity,omitempty"`
Endpoint []Endpoint `json:"endpoint,omitempty"`
Page []Page `json:"page,omitempty"`
}
type Server struct {
Name string `json:"name"`
Settings []ServerSetting `json:"settings,omitempty"`
Endpoints []Endpoint `json:"endpoints,omitempty"` // Optional endpoints for the server
}
type ServerSetting struct {
Host string `json:"host,omitempty"`
Port int `json:"port,omitempty"`
// TODO: Add more settings as needed e.g. TLS, CORS, etc.
}
type Entity struct {
Name string `json:"name"`
Description *string `json:"description,omitempty"`
Fields []Field `json:"fields,omitempty"`
}
type Field struct {
Name string `json:"name"`
Type string `json:"type"`
Required bool `json:"required,omitempty"`
Unique bool `json:"unique,omitempty"`
Index bool `json:"index,omitempty"`
Default *string `json:"default,omitempty"`
Validations []Validation `json:"validations,omitempty"`
Relationship *Relationship `json:"relationship,omitempty"`
}
type Validation struct {
Type string `json:"type"`
Value *string `json:"value,omitempty"`
}
type Relationship struct {
Type string `json:"type"`
Cardinality string `json:"cardinality"`
ForeignKey *string `json:"foreign_key,omitempty"`
Through *string `json:"through,omitempty"`
}
type Endpoint struct {
Method string `json:"method"`
Path string `json:"path"`
Entity Entity `json:"entity,omitempty"`
Description *string `json:"description,omitempty"`
Auth bool `json:"auth,omitempty"`
Permissions []string `json:"permissions,omitempty"`
}
type Page struct {
Name string `json:"name"`
Path string `json:"path"`
Title *string `json:"title,omitempty"`
Description *string `json:"description,omitempty"`
Auth bool `json:"auth,omitempty"`
Permissions []string `json:"permissions,omitempty"`
Components []Component `json:"components,omitempty"` // List of components used in the page
Styles []string `json:"styles,omitempty"` // List of stylesheets or CSS
Script []string `json:"script,omitempty"` // List of scripts or JS files
Metadata map[string]string `json:"metadata,omitempty"` // Additional metadata for the page
}
type Component struct {
Name string `json:"name"` // Name of the component
Description *string `json:"description,omitempty"` // Optional description of the component
Props []Prop `json:"props,omitempty"` // List of properties for the component
Type string `json:"type"` // Type of the component (e.g., "form", "table", etc.)
Entity Entity `json:"entity,omitempty"` // Optional entity this component is associated with
Styles []string `json:"styles,omitempty"` // List of stylesheets or CSS for the component
Script []string `json:"script,omitempty"` // List of scripts or JS files for the component
}
type Prop struct {
Name string `json:"name"` // Name of the property
Description *string `json:"description,omitempty"` // Optional description of the property
Type string `json:"type"` // Type of the property (e.g., "string", "number", "boolean", etc.)
Required bool `json:"required,omitempty"` // Whether the property is required
Default *string `json:"default,omitempty"` // Default value for the property
Validations []Validation `json:"validations,omitempty"` // List of validations for the property
Relationship *Relationship `json:"relationship,omitempty"` // Optional relationship
}