diff options
author | Steve Manuel <nilslice@gmail.com> | 2017-05-07 20:07:09 -0700 |
---|---|---|
committer | Steve Manuel <nilslice@gmail.com> | 2017-05-07 20:07:09 -0700 |
commit | dba96b5b097e87ce1ac4d061667fcd68bfc4beab (patch) | |
tree | 69d14ca08f85042ae1f41dfbf755038c666e59b9 /cmd/ponzu/generate.go | |
parent | bf9bc29974c11ff2a636692952446b524dd5b643 (diff) |
adding reference type and auto-repeater generate syntax to the CLI, updating templates to support
Diffstat (limited to 'cmd/ponzu/generate.go')
-rw-r--r-- | cmd/ponzu/generate.go | 157 |
1 files changed, 134 insertions, 23 deletions
diff --git a/cmd/ponzu/generate.go b/cmd/ponzu/generate.go index d28f0a2..5211df8 100644 --- a/cmd/ponzu/generate.go +++ b/cmd/ponzu/generate.go @@ -11,9 +11,10 @@ import ( ) type generateType struct { - Name string - Initial string - Fields []generateField + Name string + Initial string + Fields []generateField + HasReferences bool } type generateField struct { @@ -22,6 +23,10 @@ type generateField struct { TypeName string JSONName string View string + + IsReference bool + ReferenceName string + ReferenceJSONTags []string } var reservedFieldNames = map[string]string{ @@ -59,7 +64,7 @@ func parseType(args []string) (generateType, error) { fields := args[1:] for _, field := range fields { - f, err := parseField(field, t) + f, err := parseField(field, &t) if err != nil { return generateType{}, err } @@ -88,8 +93,12 @@ func parseType(args []string) (generateType, error) { return t, nil } -func parseField(raw string, gt generateType) (generateField, error) { - // contents:string or // contents:string:richtext +func parseField(raw string, gt *generateType) (generateField, error) { + // contents:string + // contents:string:richtext + // author:@author,name,age + // authors:[]@author,name,age + if !strings.Contains(raw, ":") { return generateField{}, fmt.Errorf("Invalid generate argument. [%s]", raw) } @@ -99,16 +108,17 @@ func parseField(raw string, gt generateType) (generateField, error) { field := generateField{ Name: fieldName(data[0]), Initial: gt.Initial, - TypeName: strings.ToLower(data[1]), JSONName: fieldJSONName(data[0]), } - fieldType := "input" + setFieldTypeName(&field, data[1], gt) + + viewType := "input" if len(data) == 3 { - fieldType = data[2] + viewType = data[2] } - err := setFieldView(&field, fieldType) + err := setFieldView(&field, viewType) if err != nil { return generateField{}, err } @@ -116,6 +126,47 @@ func parseField(raw string, gt generateType) (generateField, error) { return field, nil } +// parse the field's type name and check if it is a special reference type, or +// a slice of reference types, which we'll set their underlying type to string +// or []string respectively +func setFieldTypeName(field *generateField, fieldType string, gt *generateType) { + if !strings.Contains(fieldType, "@") { + // not a reference, set as-is downcased + field.TypeName = strings.ToLower(fieldType) + field.IsReference = false + return + } + + // some possibilities are + // @author,name,age + // []@author,name,age + // ------------------- + // [] = slice of author + // @author = reference to Author struct + // ,name,age = JSON tag names from Author struct fields to use as select option display + + if strings.Contains(fieldType, ",") { + referenceConf := strings.Split(fieldType, ",") + fieldType = referenceConf[0] + field.ReferenceJSONTags = referenceConf[1:] + } + + var referenceType string + if strings.HasPrefix(fieldType, "[]") { + referenceType = strings.TrimPrefix(fieldType, "[]@") + fieldType = "[]string" + } else { + referenceType = strings.TrimPrefix(fieldType, "@") + fieldType = "string" + } + + field.TypeName = strings.ToLower(fieldType) + field.ReferenceName = fieldName(referenceType) + field.IsReference = true + gt.HasReferences = true + return +} + // get the initial field name passed and check it for all possible cases // MyTitle:string myTitle:string my_title:string -> MyTitle // error-message:string -> ErrorMessage @@ -174,6 +225,41 @@ func fieldJSONName(name string) string { return name } +func optimizeFieldView(field *generateField, viewType string) string { + viewType = strings.ToLower(viewType) + + if field.IsReference { + viewType = "reference" + } + + // if we have a []T field type, automatically make the input view a repeater + // as long as a repeater exists for the input type + repeaterElements := []string{"input", "select", "file", "reference"} + if strings.HasPrefix(field.TypeName, "[]") { + for _, el := range repeaterElements { + // if the viewType already is declared to be a -repeater + // the comparison below will fail but the switch will + // still find the right generator template + // ex. authors:"[]string":select + // ex. authors:string:select-repeater + if viewType == el { + viewType = viewType + "-repeater" + } + } + } else { + // if the viewType is already declared as a -repeater, but + // the TypeName is not of []T, add the [] prefix so the user + // code is correct + // ex. authors:string:select-repeater + // ex. authors:@author:select-repeater + if strings.HasSuffix(viewType, "-repeater") { + field.TypeName = "[]" + field.TypeName + } + } + + return viewType +} + // set the specified view inside the editor field for a generated field for a type func setFieldView(field *generateField, viewType string) error { var err error @@ -186,34 +272,59 @@ func setFieldView(field *generateField, viewType string) error { } tmplDir := filepath.Join(pwd, "cmd", "ponzu", "templates") - tmplFrom := func(filename string) (*template.Template, error) { - return template.ParseFiles(filepath.Join(tmplDir, filename)) + tmplFromWithDelims := func(filename string, delim [2]string) (*template.Template, error) { + if delim[0] == "" || delim[1] == "" { + delim = [2]string{"{{", "}}"} + } + + return template.New(filename).Delims(delim[0], delim[1]).ParseFiles(filepath.Join(tmplDir, filename)) } - viewType = strings.ToLower(viewType) + viewType = optimizeFieldView(field, viewType) switch viewType { case "checkbox": - tmpl, err = tmplFrom("gen-checkbox.tmpl") + tmpl, err = tmplFromWithDelims("gen-checkbox.tmpl", [2]string{}) case "custom": - tmpl, err = tmplFrom("gen-custom.tmpl") + tmpl, err = tmplFromWithDelims("gen-custom.tmpl", [2]string{}) case "file": - tmpl, err = tmplFrom("gen-file.tmpl") + tmpl, err = tmplFromWithDelims("gen-file.tmpl", [2]string{}) case "hidden": - tmpl, err = tmplFrom("gen-hidden.tmpl") + tmpl, err = tmplFromWithDelims("gen-hidden.tmpl", [2]string{}) case "input", "text": - tmpl, err = tmplFrom("gen-input.tmpl") + tmpl, err = tmplFromWithDelims("gen-input.tmpl", [2]string{}) case "richtext": - tmpl, err = tmplFrom("gen-richtext.tmpl") + tmpl, err = tmplFromWithDelims("gen-richtext.tmpl", [2]string{}) case "select": - tmpl, err = tmplFrom("gen-select.tmpl") + tmpl, err = tmplFromWithDelims("gen-select.tmpl", [2]string{}) case "textarea": - tmpl, err = tmplFrom("gen-textarea.tmpl") + tmpl, err = tmplFromWithDelims("gen-textarea.tmpl", [2]string{}) case "tags": - tmpl, err = tmplFrom("gen-tags.tmpl") + tmpl, err = tmplFromWithDelims("gen-tags.tmpl", [2]string{}) + + case "input-repeater": + tmpl, err = tmplFromWithDelims("gen-input-repeater.tmpl", [2]string{}) + case "select-repeater": + tmpl, err = tmplFromWithDelims("gen-select-repeater.tmpl", [2]string{}) + case "file-repeater": + tmpl, err = tmplFromWithDelims("gen-file-repeater.tmpl", [2]string{}) + + // use [[ and ]] as delimeters since reference views need to generate + // display names containing {{ and }} + case "reference": + tmpl, err = tmplFromWithDelims("gen-reference.tmpl", [2]string{"[[", "]]"}) + if err != nil { + return err + } + case "reference-repeater": + tmpl, err = tmplFromWithDelims("gen-reference-repeater.tmpl", [2]string{"[[", "]]"}) + if err != nil { + return err + } + default: msg := fmt.Sprintf("'%s' is not a recognized view type. Using 'input' instead.", viewType) fmt.Println(msg) - tmpl, err = tmplFrom("gen-input.tmpl") + tmpl, err = tmplFromWithDelims("gen-input.tmpl", [2]string{}) } if err != nil { |