github.com/jgarto/itcv@v0.0.0-20180826224514-4eea09c1aa0d/cmd/cssGen/main.go (about)

     1  // cssGen is a temporary code generator for the myitcv.io/react.CSS type
     2  //
     3  package main
     4  
     5  import (
     6  	"bytes"
     7  	"flag"
     8  	"fmt"
     9  	"go/format"
    10  	"io/ioutil"
    11  	"log"
    12  	"path/filepath"
    13  	"strings"
    14  	"text/template"
    15  	"unicode/utf8"
    16  
    17  	"myitcv.io/gogenerate"
    18  )
    19  
    20  // using
    21  // https://github.com/Microsoft/TypeScript/blob/8b9fa4ce7420fdf2f540300dc80fa91f5b89ea93/lib/lib.dom.d.ts#L1692
    22  // as a reference
    23  //
    24  var attrs = map[string]*typ{
    25  	"Float":     &typ{},
    26  	"FontSize":  &typ{HTML: "font-size"},
    27  	"FontStyle": &typ{HTML: "font-style"},
    28  	"Height":    &typ{},
    29  	"MaxHeight": &typ{HTML: "max-height"},
    30  	"MarginTop": &typ{HTML: "margin-top"},
    31  	"OverflowY": &typ{HTML: "overflow-y"},
    32  	"MinHeight": &typ{HTML: "min-height"},
    33  	"Overflow":  &typ{},
    34  	"Resize":    &typ{},
    35  	"Width":     &typ{},
    36  	"Position":  &typ{},
    37  	"Top":       &typ{},
    38  	"Left":      &typ{},
    39  	"ZIndex":    &typ{HTML: "z-index"},
    40  }
    41  
    42  const (
    43  	cssGenCmd = "cssGen"
    44  )
    45  
    46  func main() {
    47  	log.SetFlags(0)
    48  	log.SetPrefix(cssGenCmd + ": ")
    49  
    50  	flag.Parse()
    51  
    52  	for n, a := range attrs {
    53  		a.Name = n
    54  		if a.React == "" {
    55  			a.React = lowerInitial(n)
    56  		}
    57  		if a.HTML == "" {
    58  			a.HTML = strings.ToLower(n)
    59  		}
    60  		if a.Type == "" {
    61  			a.Type = "string"
    62  		}
    63  	}
    64  
    65  	write := func(tmpl string, fn string) {
    66  		buf := bytes.NewBuffer(nil)
    67  
    68  		t, err := template.New("t").Parse(tmpl)
    69  		if err != nil {
    70  			fatalf("could not parse template: %v", err)
    71  		}
    72  
    73  		err = t.Execute(buf, attrs)
    74  		if err != nil {
    75  			fatalf("could not execute template: %v", err)
    76  		}
    77  
    78  		toWrite := buf.Bytes()
    79  		out, err := format.Source(toWrite)
    80  		if err == nil {
    81  			toWrite = out
    82  		}
    83  
    84  		if err := ioutil.WriteFile(fn, toWrite, 0644); err != nil {
    85  			fatalf("could not write %v: %v", fn, err)
    86  		}
    87  	}
    88  
    89  	write(tmpl, gogenerate.NameFile("react", cssGenCmd))
    90  	write(jsxTmpl, filepath.Join("jsx", gogenerate.NameFile("jsx", cssGenCmd)))
    91  }
    92  
    93  func lowerInitial(s string) string {
    94  	if s == "" {
    95  		return ""
    96  	}
    97  
    98  	r, w := utf8.DecodeRuneInString(s)
    99  	return strings.ToLower(string(r)) + s[w:]
   100  }
   101  
   102  type typ struct {
   103  	Name string
   104  
   105  	// React is the React property name if not equivalent to the lower-initial
   106  	// camel-case version of .Name
   107  	React string
   108  
   109  	// HTML is the HTML property name if not equivalent to the lowercase version
   110  	// of .Name
   111  	HTML string
   112  
   113  	// Type is the type. Default is "string"
   114  	Type string
   115  }
   116  
   117  var tmpl = `
   118   // Code generated by cssGen. DO NOT EDIT.
   119  
   120  package react
   121  
   122  import "github.com/gopherjs/gopherjs/js"
   123  
   124  // CSS defines CSS attributes for HTML components. Largely based on
   125  // https://developer.mozilla.org/en-US/docs/Web/CSS/Reference
   126  //
   127  type CSS struct {
   128  	o *js.Object
   129  
   130  	{{range . }}
   131  	{{.Name}} {{.Type}}
   132  	{{- end}}
   133  }
   134  
   135  // TODO: until we have a resolution on
   136  // https://github.com/gopherjs/gopherjs/issues/236 we define hack() below
   137  
   138  func (c *CSS) hack() *CSS {
   139  	if c == nil {
   140  		return nil
   141  	}
   142  
   143  	o := object.New()
   144  
   145  	{{range . }}
   146  	o.Set("{{.React}}", c.{{.Name}})
   147  	{{- end}}
   148  
   149  	return &CSS{o: o}
   150  }
   151  `
   152  
   153  var jsxTmpl = `
   154  package jsx
   155  
   156  import (
   157  	"fmt"
   158  	"strings"
   159  
   160  	"myitcv.io/react"
   161  )
   162  
   163  func parseCSS(s string) *react.CSS {
   164  	res := new(react.CSS)
   165  
   166  	parts := strings.Split(s, ";")
   167  
   168  	for _, p := range parts {
   169  		kv := strings.Split(p, ":")
   170  		if len(kv) != 2 {
   171  			panic(fmt.Errorf("invalid key-val %q in %q", p, s))
   172  		}
   173  
   174  		k, v := kv[0], kv[1]
   175  
   176  		k = strings.TrimSpace(k)
   177  		v = strings.TrimSpace(v)
   178  		v = strings.Trim(v, "\"")
   179  
   180  		switch k {
   181  		{{range .}}
   182  		case "{{.HTML}}":
   183  			res.{{.Name}} = v
   184  		{{end}}
   185  		default:
   186  			panic(fmt.Errorf("unknown CSS key %q in %q", k, s))
   187  		}
   188  	}
   189  
   190  	return res
   191  }
   192  `
   193  
   194  func fatalf(format string, args ...interface{}) {
   195  	panic(fmt.Errorf(format, args...))
   196  }