Refactored codegen
This commit is contained in:
parent
500e15b5e6
commit
38d31f8a25
@ -11,14 +11,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const headerFmt = `// GENERATED BY gitlab.codemonkeysoftware.net/b/hatmill/internal/codegen
|
|
||||||
// DO NOT EDIT!
|
|
||||||
|
|
||||||
package %s
|
|
||||||
|
|
||||||
import "gitlab.codemonkeysoftware.net/b/hatmill"
|
|
||||||
`
|
|
||||||
|
|
||||||
func identifier(s string) string {
|
func identifier(s string) string {
|
||||||
words := strings.Split(s, "-")
|
words := strings.Split(s, "-")
|
||||||
for i, word := range words {
|
for i, word := range words {
|
||||||
@ -27,84 +19,67 @@ func identifier(s string) string {
|
|||||||
return strings.Join(words, "")
|
return strings.Join(words, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func fileHeader(packageName string) string {
|
var attribTypes = map[string]string {
|
||||||
return fmt.Sprintf(headerFmt, packageName)
|
"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",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
type AttribType int
|
type AttribSpec struct {
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type AttribDef struct {
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type AttribType `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (def AttribDef) Generate() string {
|
type AttribSpecs []AttribSpec
|
||||||
const (
|
|
||||||
boolType = "bool"
|
|
||||||
stringType = "string"
|
|
||||||
|
|
||||||
stringTemplate = `// %[1]s creates a "%[2]s" attribute
|
func (a AttribSpecs) Code() Code {
|
||||||
func %[1]s(value string) hatmill.Attrib {
|
var c Code
|
||||||
return hatmill.Attrib{
|
const hatmillImport = "gitlab.codemonkeysoftware.net/b/hatmill"
|
||||||
Key: "%[2]s",
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
boolTemplate = `// %[1]s creates a "%[2]s" attribute
|
|
||||||
func %[1]s() hatmill.Attrib {
|
|
||||||
return hatmill.Attrib{
|
|
||||||
Key: "%[2]s",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
)
|
|
||||||
|
|
||||||
var template string
|
c.Imports = append(c.Imports, hatmillImport)
|
||||||
switch def.Type {
|
for _, spec := range a {
|
||||||
case Bool:
|
c.Defs = append(c.Defs, spec.Generate())
|
||||||
template = boolTemplate
|
|
||||||
case String:
|
|
||||||
template = stringTemplate
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unknown attribute type: %v", def.Type))
|
|
||||||
}
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
type ElemSpecs []ElemSpec
|
||||||
|
|
||||||
|
func (e ElemSpecs) Code() Code {
|
||||||
|
var c Code
|
||||||
|
const hatmillImport = "gitlab.codemonkeysoftware.net/b/hatmill"
|
||||||
|
|
||||||
|
c.Imports = append(c.Imports, hatmillImport)
|
||||||
|
for _, spec := range e {
|
||||||
|
c.Defs = append(c.Defs, spec.Generate())
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def AttribSpec) Generate() string {
|
||||||
|
template := attribTypes[def.Type]
|
||||||
return fmt.Sprintf(template, identifier(def.Name), def.Name)
|
return fmt.Sprintf(template, identifier(def.Name), def.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ElemDef struct {
|
type ElemSpec struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Void bool `json:"void"`
|
Void bool `json:"void"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (def ElemDef) Generate() string {
|
func (def ElemSpec) Generate() string {
|
||||||
const (
|
const (
|
||||||
parentTemplate = `// %[1]s creates a <%[2]s> element.
|
parentTemplate = `// %[1]s creates a <%[2]s> element.
|
||||||
func %[1]s(attribs ...hatmill.Attrib) func(children ...hatmill.Term) hatmill.ParentElement {
|
func %[1]s(attribs ...hatmill.Attrib) func(children ...hatmill.Term) hatmill.ParentElement {
|
||||||
@ -136,20 +111,46 @@ func (def ElemDef) Generate() string {
|
|||||||
return fmt.Sprintf(template, identifier(def.Name), def.Name)
|
return fmt.Sprintf(template, identifier(def.Name), def.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Defs struct {
|
type Specs struct {
|
||||||
Attributes []AttribDef `json:"attributes"`
|
Attributes AttribSpecs `json:"attributes"`
|
||||||
Elements []ElemDef `json:"elements"`
|
Elements ElemSpecs `json:"elements"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeFormatted(fileName, packageName string, writeDefs func(*bytes.Buffer)) error {
|
// Code is a very slight abstraction of a source code file.
|
||||||
src := new(bytes.Buffer)
|
type Code struct {
|
||||||
src.WriteString(fileHeader(packageName))
|
Package string
|
||||||
writeDefs(src)
|
Imports []string
|
||||||
formatted, err := format.Source(src.Bytes())
|
Defs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return ioutil.WriteFile(fileName, formatted, 0644)
|
return ioutil.WriteFile(path, b, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -165,26 +166,18 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var defs Defs
|
var specs Specs
|
||||||
err = json.Unmarshal(input, &defs)
|
err = json.Unmarshal(input, &specs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeFormatted(*attribPath, *attribPkg, func(buf *bytes.Buffer) {
|
err = WriteCodeFile(specs.Attributes, *attribPath, *attribPkg)
|
||||||
for _, attribDef := range defs.Attributes {
|
|
||||||
buf.WriteString(attribDef.Generate())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeFormatted(*elemPath, *elemPkg, func(buf *bytes.Buffer) {
|
err = WriteCodeFile(specs.Elements, *elemPath, *elemPkg)
|
||||||
for _, elemDef := range defs.Elements {
|
|
||||||
buf.WriteString(elemDef.Generate())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user