hatmill/internal/codegen/codegen.go

172 lines
3.9 KiB
Go
Raw Normal View History

2019-03-24 19:28:36 +00:00
package main
import (
"bytes"
"encoding/json"
"flag"
2019-03-24 19:28:36 +00:00
"fmt"
"go/format"
"io/ioutil"
"log"
"strings"
)
const headerFmt = `// GENERATED BY gitlab.codemonkeysoftware.net/b/hatmill/internal/codegen
// DO NOT EDIT!
2019-03-24 19:28:36 +00:00
package %s
import "gitlab.codemonkeysoftware.net/b/hatmill"
`
2019-03-24 19:28:36 +00:00
func fileHeader(packageName string) string {
return fmt.Sprintf(headerFmt, packageName)
}
2019-03-24 19:28:36 +00:00
type AttribType int
const (
String AttribType = iota
Bool
)
func (t *AttribType) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
return nil
}
var typeName string
err := json.Unmarshal(data, &typeName)
if err != nil {
return fmt.Errorf("type property must be a string")
}
switch typeName {
case "bool":
*t = Bool
case "string":
*t = String
default:
return fmt.Errorf("unrecognized attribute type %s", typeName)
}
return nil
2019-03-24 19:28:36 +00:00
}
type AttribDef struct {
Name string `json:"name"`
Type AttribType `json:"type"`
}
2019-03-24 19:28:36 +00:00
func (def AttribDef) Generate() string {
const (
2019-03-24 19:28:36 +00:00
boolType = "bool"
stringType = "string"
2019-03-25 02:35:40 +00:00
stringTemplate = `// %[1]s creates a "%[2]s" attribute
func %[1]s(value string) hatmill.Attrib {
return hatmill.Attrib{
Key: "%[2]s",
2019-03-24 19:28:36 +00:00
Value: value,
}
}
`
2019-03-25 02:35:40 +00:00
boolTemplate = `// %[1]s creates a "%[2]s" attribute
func %[1]s() hatmill.Attrib {
return hatmill.Attrib{
Key: "%[2]s",
2019-03-24 19:28:36 +00:00
}
}
`
)
var template string
switch def.Type {
case Bool:
template = boolTemplate
case String:
template = stringTemplate
default:
panic(fmt.Errorf("unknown attribute type: %v", def.Type))
}
return fmt.Sprintf(template, strings.Title(def.Name), def.Name)
}
type ElemDef struct {
Name string `json:"name"`
2019-03-29 02:22:31 +00:00
Void bool `json:"void"`
}
func (def ElemDef) Generate() string {
const (
parentTemplate = `// %[1]s creates a <%[2]s> element.
func %[1]s(attribs ...hatmill.Attrib) func(children ...hatmill.Term) hatmill.ParentElement {
return func(children ...hatmill.Term) hatmill.ParentElement {
return hatmill.ParentElement{
VoidElement: hatmill.VoidElement{
TagName: "%[2]s",
Attribs: attribs,
},
Children: children,
}
}
}
`
2019-03-29 02:18:25 +00:00
voidTemplate = `// %[1]s creates a <%[2]s> element.
func %[1]s(attribs ...hatmill.Attrib) hatmill.VoidElement {
return hatmill.VoidElement{
TagName: "%[2]s",
Attribs: attribs,
}
}
`
)
template := parentTemplate
2019-03-29 02:22:31 +00:00
if def.Void {
2019-03-29 02:18:25 +00:00
template = voidTemplate
}
return fmt.Sprintf(template, strings.Title(def.Name), def.Name)
}
type Defs struct {
Attributes []AttribDef `json:"attributes"`
Elements []ElemDef `json:"elements"`
2019-03-24 19:28:36 +00:00
}
func main() {
inputPath := flag.String("input", "", "JSON input file")
outputPath := flag.String("output", "", ".go output file")
packageName := flag.String("package", "", "output package name")
flag.Parse()
input, err := ioutil.ReadFile(*inputPath)
if err != nil {
log.Fatal(err)
}
var defs Defs
err = json.Unmarshal(input, &defs)
if err != nil {
log.Fatal(err)
}
output := new(bytes.Buffer)
output.WriteString(fileHeader(*packageName))
for _, elemDef := range defs.Elements {
output.WriteString(elemDef.Generate())
}
for _, attribDef := range defs.Attributes {
output.WriteString(attribDef.Generate())
}
formatted, err := format.Source(output.Bytes())
if err != nil {
log.Fatal(err)
}
err = ioutil.WriteFile(*outputPath, formatted, 0644)
if err != nil {
log.Fatal(err)
}
2019-03-24 19:28:36 +00:00
}