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 }