package main import ( "bytes" "encoding/json" "flag" "fmt" "go/format" "io/ioutil" "log" "strings" ) const headerFmt = `// GENERATED BY gitlab.codemonkeysoftware.net/b/hatmill/internal/codegen // DO NOT EDIT! package %s ` func fileHeader(packageName string, needImport bool) string { header := fmt.Sprintf(headerFmt, packageName) if needImport { header += `import . "gitlab.codemonkeysoftware.net/b/hatmill"` + "\n" } return header } 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 } type AttribDef struct { Name string `json:"name"` Type AttribType `json:"type"` } func (def AttribDef) String() string { const ( boolType = "bool" stringType = "string" stringTemplate = `func %s(value string) Attrib { return Attrib{ Key: "%s", Value: value, } } ` boolTemplate = `func %s() Attrib { return Attrib{ Key: "%s", } } ` ) var template string switch def.Type { case Bool: template = boolTemplate case String: template = stringTemplate default: panic(fmt.Errorf("unknown attribute type: %s", def.Type)) } return fmt.Sprintf(template, strings.Title(def.Name), def.Name) } type ElemDef struct { Name string `json:"name"` Empty bool `json:"empty"` } func (def ElemDef) String() string { const ( parentTemplate = `// %[1]s creates a <%[2]s> element. func %[1]s(attribs ...Attrib) func(children ...Term) *ParentElement { return func(children ...Term) *ParentElement { return &ParentElement{ EmptyElement: EmptyElement{ TagName: "%[2]s", Attribs: attribs, }, Children: children, } } } ` emptyTemplate = `// %[1]s creates a <%[2]s> element. func %[1]s(attribs ...Attrib) EmptyElement { return EmptyElement{ TagName: "%[2]s", Attribs: attribs, } } ` ) template := parentTemplate if def.Empty { template = emptyTemplate } return fmt.Sprintf(template, strings.Title(def.Name), def.Name) } type Defs struct { Attributes []AttribDef `json:"attributes"` Elements []ElemDef `json:"elements"` } func main() { inputPath := flag.String("input", "", "JSON input file") outputPath := flag.String("output", "", ".go output file") packageName := flag.String("package", "", "output package name") addImport := flag.Bool("import", false, "import hatmill in output package") 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, *addImport)) for _, elemDef := range defs.Elements { output.WriteString(elemDef.String()) } for _, attribDef := range defs.Attributes { output.WriteString(attribDef.String()) } formatted, err := format.Source(output.Bytes()) if err != nil { log.Fatal(err) } err = ioutil.WriteFile(*outputPath, formatted, 0644) if err != nil { log.Fatal(err) } }