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"
|
|
|
|
)
|
|
|
|
|
2019-04-09 03:52:26 +00:00
|
|
|
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 03:49:46 +00:00
|
|
|
type AttribTypeInfo struct {
|
|
|
|
Template string
|
|
|
|
}
|
2019-04-23 02:23:56 +00:00
|
|
|
|
2019-04-27 21:26:59 +00:00
|
|
|
func simpleTemplate(paramType, convertExpr string) string {
|
|
|
|
conversion := fmt.Sprintf(convertExpr, "value")
|
|
|
|
return fmt.Sprintf(`func %%s(value %s) hatmill.Attrib {
|
|
|
|
return hatmill.Attrib{
|
|
|
|
Key: "%%s",
|
2019-08-31 15:05:43 +00:00
|
|
|
Value: String(%s),
|
2019-04-23 02:23:56 +00:00
|
|
|
}
|
2019-04-27 21:26:59 +00:00
|
|
|
}
|
|
|
|
`, paramType, conversion)
|
|
|
|
}
|
2019-04-23 03:49:46 +00:00
|
|
|
|
2019-05-30 04:26:36 +00:00
|
|
|
func listTemplate(separator string) string {
|
|
|
|
return fmt.Sprintf(`func %%s(value ...string) hatmill.Attrib {
|
|
|
|
return hatmill.Attrib{
|
|
|
|
Key: "%%s",
|
2019-08-31 15:05:43 +00:00
|
|
|
Value: String(strings.Join(value, "%s")),
|
2019-05-30 04:26:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
`, separator)
|
|
|
|
}
|
|
|
|
|
2019-04-27 21:26:59 +00:00
|
|
|
var attribTypes = map[string]AttribTypeInfo{
|
|
|
|
"string": {Template: simpleTemplate("string", "%s")},
|
2019-04-23 03:49:46 +00:00
|
|
|
"bool": {
|
2019-04-27 21:26:59 +00:00
|
|
|
Template: `func %s() hatmill.Attrib {
|
2019-04-23 03:49:46 +00:00
|
|
|
return hatmill.Attrib{
|
2019-04-27 21:26:59 +00:00
|
|
|
Key: "%s",
|
2019-04-23 03:49:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
2019-04-27 02:49:10 +00:00
|
|
|
"explicit bool": {
|
2019-08-31 16:30:17 +00:00
|
|
|
Template: simpleTemplate("bool", "Bool(%s).String()"),
|
2019-04-27 02:49:10 +00:00
|
|
|
},
|
2019-04-23 03:49:46 +00:00
|
|
|
"int": {
|
2019-08-31 16:20:58 +00:00
|
|
|
Template: simpleTemplate("int", "Int(%s).String()"),
|
2019-04-23 03:49:46 +00:00
|
|
|
},
|
2019-04-23 04:12:12 +00:00
|
|
|
"float": {
|
2019-08-31 15:56:56 +00:00
|
|
|
Template: simpleTemplate("float32", "Float(%s).String()"),
|
2019-04-23 04:12:12 +00:00
|
|
|
},
|
2019-05-30 03:32:16 +00:00
|
|
|
"space list": {
|
2019-08-31 15:47:37 +00:00
|
|
|
Template: simpleTemplate("...string", "SpaceList(%s).String()"),
|
2019-05-30 04:26:36 +00:00
|
|
|
},
|
|
|
|
"comma list": {
|
2019-08-31 15:51:43 +00:00
|
|
|
Template: simpleTemplate("...string", "CommaList(%s).String()"),
|
2019-05-30 03:32:16 +00:00
|
|
|
},
|
2019-03-24 21:42:48 +00:00
|
|
|
}
|
2019-03-24 19:28:36 +00:00
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
// Def represents a top-level definition and its required imports.
|
|
|
|
type Def struct {
|
2019-08-31 16:30:17 +00:00
|
|
|
Source string
|
2019-04-23 02:23:56 +00:00
|
|
|
}
|
2019-03-24 21:42:48 +00:00
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
type Spec interface {
|
|
|
|
Generate() Def
|
2019-03-24 19:28:36 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
type AttribSpec struct {
|
2019-08-27 22:59:59 +00:00
|
|
|
Name string `json:"name"`
|
|
|
|
Type string `json:"type"`
|
2019-04-23 02:23:56 +00:00
|
|
|
}
|
2019-04-09 04:10:02 +00:00
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
func (spec AttribSpec) Generate() Def {
|
2019-04-27 21:26:59 +00:00
|
|
|
name := spec.Name
|
|
|
|
ident := identifier(spec.Name)
|
2019-08-27 22:59:59 +00:00
|
|
|
comment := fmt.Sprintf("// %s creates a \"%s\" attribute\n", ident, name)
|
2019-04-23 03:49:46 +00:00
|
|
|
template := attribTypes[spec.Type].Template
|
|
|
|
return Def{
|
2019-08-31 16:30:17 +00:00
|
|
|
Source: comment + fmt.Sprintf(template, ident, name),
|
2019-04-23 03:49:46 +00:00
|
|
|
}
|
2019-03-24 21:42:48 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 02:23:56 +00:00
|
|
|
type ElemSpec struct {
|
2019-08-27 22:59:59 +00:00
|
|
|
Name string `json:"name"`
|
|
|
|
Void bool `json:"void"`
|
2019-03-24 21:42:48 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
func (spec ElemSpec) Generate() Def {
|
2019-04-09 04:10:02 +00:00
|
|
|
const (
|
2019-04-27 21:26:59 +00:00
|
|
|
parentTemplate = `func %s(attribs ...hatmill.Attrib) func(children ...hatmill.Term) hatmill.ParentElement {
|
2019-04-03 02:05:48 +00:00
|
|
|
return func(children ...hatmill.Term) hatmill.ParentElement {
|
|
|
|
return hatmill.ParentElement{
|
|
|
|
VoidElement: hatmill.VoidElement{
|
2019-04-27 21:26:59 +00:00
|
|
|
TagName: "%s",
|
2019-03-24 21:42:48 +00:00
|
|
|
Attribs: attribs,
|
|
|
|
},
|
|
|
|
Children: children,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`
|
2019-04-27 21:26:59 +00:00
|
|
|
voidTemplate = `func %s(attribs ...hatmill.Attrib) hatmill.VoidElement {
|
2019-04-03 02:05:48 +00:00
|
|
|
return hatmill.VoidElement{
|
2019-04-27 21:26:59 +00:00
|
|
|
TagName: "%s",
|
2019-03-24 21:42:48 +00:00
|
|
|
Attribs: attribs,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`
|
2019-04-09 04:10:02 +00:00
|
|
|
)
|
2019-03-24 21:42:48 +00:00
|
|
|
|
2019-04-27 21:26:59 +00:00
|
|
|
name := spec.Name
|
|
|
|
ident := identifier(spec.Name)
|
2019-08-27 22:59:59 +00:00
|
|
|
comment := fmt.Sprintf("// %s creates a <%s> element.\n", ident, name)
|
2019-04-09 04:10:02 +00:00
|
|
|
template := parentTemplate
|
2019-04-23 03:49:46 +00:00
|
|
|
if spec.Void {
|
2019-04-09 04:10:02 +00:00
|
|
|
template = voidTemplate
|
|
|
|
}
|
2019-04-23 03:49:46 +00:00
|
|
|
return Def{
|
2019-08-27 22:59:59 +00:00
|
|
|
Source: comment + fmt.Sprintf(template, ident, name),
|
2019-04-23 03:49:46 +00:00
|
|
|
}
|
2019-03-24 19:28:36 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
func Render(defs []Def, pkgName string) ([]byte, error) {
|
2019-04-23 02:23:56 +00:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
buf.WriteString(`// GENERATED BY gitlab.codemonkeysoftware.net/b/hatmill/internal/codegen
|
|
|
|
// DO NOT EDIT!
|
|
|
|
|
|
|
|
`)
|
2019-04-23 03:49:46 +00:00
|
|
|
fmt.Fprintln(buf, "package ", pkgName)
|
|
|
|
buf.WriteString(`import "gitlab.codemonkeysoftware.net/b/hatmill"
|
|
|
|
`)
|
|
|
|
|
|
|
|
for _, def := range defs {
|
|
|
|
buf.WriteString(def.Source)
|
2019-04-23 02:23:56 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
formatted, err := format.Source(buf.Bytes())
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("generated invalid code: %s\nSource code:\n%s", err, buf)
|
|
|
|
}
|
|
|
|
return formatted, err
|
2019-04-23 02:23:56 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
func WriteCodeFile(specs []Spec, path, pkgName string) error {
|
|
|
|
var defs []Def
|
|
|
|
for _, spec := range specs {
|
|
|
|
defs = append(defs, spec.Generate())
|
|
|
|
}
|
|
|
|
b, err := Render(defs, pkgName)
|
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-03-24 21:42:48 +00:00
|
|
|
|
2019-04-09 04:10:02 +00:00
|
|
|
input, err := ioutil.ReadFile(*inputPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2019-03-24 21:42:48 +00:00
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
var specs struct {
|
|
|
|
AttribSpecs []AttribSpec `json:"attributes"`
|
|
|
|
ElemSpecs []ElemSpec `json:"elements"`
|
|
|
|
}
|
|
|
|
|
2019-04-23 02:23:56 +00:00
|
|
|
err = json.Unmarshal(input, &specs)
|
2019-04-09 04:10:02 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2019-03-24 21:42:48 +00:00
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
var attribSpecs []Spec
|
|
|
|
for _, spec := range specs.AttribSpecs {
|
|
|
|
attribSpecs = append(attribSpecs, spec)
|
|
|
|
}
|
|
|
|
err = WriteCodeFile(attribSpecs, *attribPath, *attribPkg)
|
2019-04-03 03:42:16 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2019-04-23 03:49:46 +00:00
|
|
|
var elemSpecs []Spec
|
|
|
|
for _, spec := range specs.ElemSpecs {
|
|
|
|
elemSpecs = append(elemSpecs, spec)
|
|
|
|
}
|
|
|
|
err = WriteCodeFile(elemSpecs, *elemPath, *elemPkg)
|
2019-04-03 03:42:16 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2019-04-23 03:49:46 +00:00
|
|
|
|
2019-03-24 19:28:36 +00:00
|
|
|
}
|