hatmill/internal/codegen/codegen.go

185 lines
4.0 KiB
Go
Raw Normal View History

2019-03-24 19:28:36 +00:00
package main
import (
"bytes"
2019-04-09 04:10:02 +00:00
"encoding/json"
"flag"
2019-03-24 19:28:36 +00:00
"fmt"
"go/format"
"io/ioutil"
"log"
"strings"
)
func identifier(s string) string {
words := strings.Split(s, "-")
for i, word := range words {
words[i] = strings.Title(word)
}
return strings.Join(words, "")
}
2019-04-23 02:23:56 +00:00
var attribTypes = map[string]string {
"string": `// %[1]s creates a "%[2]s" attribute
func %[1]s(value string) hatmill.Attrib {
return hatmill.Attrib{
Key: "%[2]s",
Value: value,
}
}
`,
"bool": `// %[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
2019-04-23 02:23:56 +00:00
type AttribSpec struct {
Name string `json:"name"`
Type string `json:"type"`
}
2019-04-23 02:23:56 +00:00
type AttribSpecs []AttribSpec
2019-04-23 02:23:56 +00:00
func (a AttribSpecs) Code() Code {
var c Code
const hatmillImport = "gitlab.codemonkeysoftware.net/b/hatmill"
2019-04-09 04:10:02 +00:00
2019-04-23 02:23:56 +00:00
c.Imports = append(c.Imports, hatmillImport)
for _, spec := range a {
c.Defs = append(c.Defs, spec.Generate())
2019-04-09 04:10:02 +00:00
}
2019-04-23 02:23:56 +00:00
return c
2019-03-24 19:28:36 +00:00
}
2019-04-23 02:23:56 +00:00
type ElemSpecs []ElemSpec
2019-03-24 19:28:36 +00:00
2019-04-23 02:23:56 +00:00
func (e ElemSpecs) Code() Code {
var c Code
const hatmillImport = "gitlab.codemonkeysoftware.net/b/hatmill"
2019-03-24 19:28:36 +00:00
2019-04-23 02:23:56 +00:00
c.Imports = append(c.Imports, hatmillImport)
for _, spec := range e {
c.Defs = append(c.Defs, spec.Generate())
2019-04-09 04:10:02 +00:00
}
2019-04-23 02:23:56 +00:00
return c
}
2019-04-09 04:10:02 +00:00
2019-04-23 02:23:56 +00:00
func (def AttribSpec) Generate() string {
template := attribTypes[def.Type]
2019-04-09 04:10:02 +00:00
return fmt.Sprintf(template, identifier(def.Name), def.Name)
}
2019-04-23 02:23:56 +00:00
type ElemSpec struct {
2019-04-09 04:10:02 +00:00
Name string `json:"name"`
Void bool `json:"void"`
}
2019-04-23 02:23:56 +00:00
func (def ElemSpec) Generate() string {
2019-04-09 04:10:02 +00:00
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-04-09 04:10:02 +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,
}
}
`
2019-04-09 04:10:02 +00:00
)
2019-04-09 04:10:02 +00:00
template := parentTemplate
if def.Void {
template = voidTemplate
}
return fmt.Sprintf(template, identifier(def.Name), def.Name)
}
2019-04-23 02:23:56 +00:00
type Specs struct {
Attributes AttribSpecs `json:"attributes"`
Elements ElemSpecs `json:"elements"`
}
// Code is a very slight abstraction of a source code file.
type Code struct {
Package string
Imports []string
Defs []string
2019-03-24 19:28:36 +00:00
}
2019-04-23 02:23:56 +00:00
func (c Code) Bytes() ([]byte, error) {
buf := new(bytes.Buffer)
buf.WriteString(`// GENERATED BY gitlab.codemonkeysoftware.net/b/hatmill/internal/codegen
// DO NOT EDIT!
`)
fmt.Fprintln(buf, "package ", c.Package)
for _, imp := range c.Imports {
fmt.Fprintf(buf, "import \"%s\"\n", imp)
}
for _, def := range c.Defs {
buf.WriteString(def)
}
return format.Source(buf.Bytes())
}
type Coder interface {
Code() Code
}
func WriteCodeFile(c Coder, path, pkg string) error {
code := c.Code()
code.Package = pkg
b, err := code.Bytes()
2019-04-03 03:42:16 +00:00
if err != nil {
return err
}
2019-04-23 02:23:56 +00:00
return ioutil.WriteFile(path, b, 0644)
2019-04-03 03:42:16 +00:00
}
2019-03-24 19:28:36 +00:00
func main() {
2019-04-09 04:10:02 +00:00
inputPath := flag.String("input", "", "JSON input file")
2019-04-03 03:42:16 +00:00
elemPath := flag.String("elemfile", "", "generated element .go file")
elemPkg := flag.String("elempkg", "", "generated element package name")
attribPath := flag.String("attribfile", "", "generated attribute .go file")
attribPkg := flag.String("attribpkg", "", "generated attribute package name")
2019-04-09 04:10:02 +00:00
flag.Parse()
2019-04-09 04:10:02 +00:00
input, err := ioutil.ReadFile(*inputPath)
if err != nil {
log.Fatal(err)
}
2019-04-23 02:23:56 +00:00
var specs Specs
err = json.Unmarshal(input, &specs)
2019-04-09 04:10:02 +00:00
if err != nil {
log.Fatal(err)
}
2019-04-23 02:23:56 +00:00
err = WriteCodeFile(specs.Attributes, *attribPath, *attribPkg)
2019-04-03 03:42:16 +00:00
if err != nil {
log.Fatal(err)
}
2019-04-23 02:23:56 +00:00
err = WriteCodeFile(specs.Elements, *elemPath, *elemPkg)
2019-04-03 03:42:16 +00:00
if err != nil {
log.Fatal(err)
}
2019-03-24 19:28:36 +00:00
}