github.com/servernoj/jade@v0.0.0-20231225191405-efec98d19db1/cmd/jade/main.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "flag" 6 "fmt" 7 "go/ast" 8 "go/parser" 9 "go/printer" 10 "go/token" 11 "io/ioutil" 12 "log" 13 "os" 14 "path/filepath" 15 "regexp" 16 "strconv" 17 18 "github.com/Joker/jade" 19 "golang.org/x/tools/imports" 20 ) 21 22 var ( 23 dict = map[string]string{} 24 lib_name = "" 25 outdir string 26 basedir string 27 pkg_name string 28 stdlib bool 29 stdbuf bool 30 writer bool 31 inline bool 32 format bool 33 ns_files = map[string]bool{} 34 ) 35 36 func use() { 37 fmt.Printf("Usage: %s [OPTION]... [FILE]... \n", os.Args[0]) 38 flag.PrintDefaults() 39 } 40 func init() { 41 flag.StringVar(&outdir, "d", "./", `directory for generated .go files`) 42 flag.StringVar(&basedir, "basedir", "./", `base directory for templates`) 43 flag.StringVar(&pkg_name, "pkg", "jade", `package name for generated files`) 44 flag.BoolVar(&format, "fmt", false, `HTML pretty print output for generated functions`) 45 flag.BoolVar(&inline, "inline", false, `inline HTML in generated functions`) 46 flag.BoolVar(&stdlib, "stdlib", false, `use stdlib functions`) 47 flag.BoolVar(&stdbuf, "stdbuf", false, `use bytes.Buffer [default bytebufferpool.ByteBuffer]`) 48 flag.BoolVar(&writer, "writer", false, `use io.Writer for output`) 49 } 50 51 // 52 53 type goAST struct { 54 node *ast.File 55 fset *token.FileSet 56 } 57 58 func (a *goAST) bytes(bb *bytes.Buffer) []byte { 59 printer.Fprint(bb, a.fset, a.node) 60 return bb.Bytes() 61 } 62 63 func parseGoSrc(fileName string, GoSrc interface{}) (out goAST, err error) { 64 out.fset = token.NewFileSet() 65 out.node, err = parser.ParseFile(out.fset, fileName, GoSrc, parser.ParseComments) 66 return 67 } 68 69 func goImports(absPath string, src []byte) []byte { 70 fmtOut, err := imports.Process(absPath, src, &imports.Options{TabWidth: 4, TabIndent: true, Comments: true, Fragment: true}) 71 if err != nil { 72 log.Fatalln("goImports(): ", err) 73 } 74 75 return fmtOut 76 } 77 78 // 79 80 func genFile(path, outdir, pkg_name string) { 81 log.Printf("\nfile: %q\n", path) 82 83 var ( 84 dir, fname = filepath.Split(path) 85 outPath = outdir + "/" + fname 86 rx, _ = regexp.Compile("[^a-zA-Z0-9]+") 87 constName = rx.ReplaceAllString(fname[:len(fname)-4], "") 88 ) 89 90 wd, err := os.Getwd() 91 if err == nil && wd != dir && dir != "" { 92 os.Chdir(dir) 93 defer os.Chdir(wd) 94 } 95 96 if _, ok := ns_files[fname]; ok { 97 sfx := "_" + strconv.Itoa(len(ns_files)) 98 ns_files[fname+sfx] = true 99 outPath += sfx 100 constName += sfx 101 } else { 102 ns_files[fname] = true 103 } 104 105 fl, err := ioutil.ReadFile(fname) 106 if err != nil { 107 log.Fatalln("cmd/jade: ReadFile(): ", err) 108 } 109 110 // 111 112 jst, err := jade.New(path).Parse(fl) 113 if err != nil { 114 log.Fatalln("cmd/jade: jade.New(path).Parse(): ", err) 115 } 116 117 var ( 118 bb = new(bytes.Buffer) 119 tpl = newLayout(constName) 120 ) 121 tpl.writeBefore(bb) 122 before := bb.Len() 123 jst.WriteIn(bb) 124 if before == bb.Len() { 125 fmt.Print("generated: skipped (empty output) done.\n\n") 126 return 127 } 128 tpl.writeAfter(bb) 129 130 // 131 132 gst, err := parseGoSrc(outPath, bb) 133 if err != nil { 134 // TODO 135 bb.WriteString("\n\nERROR: parseGoSrc(): ") 136 bb.WriteString(err.Error()) 137 ioutil.WriteFile(outPath+"__Error.go", bb.Bytes(), 0644) 138 log.Fatalln("cmd/jade: parseGoSrc(): ", err) 139 } 140 141 gst.collapseWriteString(inline, constName) 142 gst.checkType() 143 gst.checkUnresolvedBlock() 144 145 bb.Reset() 146 fmtOut := goImports(outPath, gst.bytes(bb)) 147 148 // 149 150 err = ioutil.WriteFile(outPath+".go", fmtOut, 0644) 151 if err != nil { 152 log.Fatalln("cmd/jade: WriteFile(): ", err) 153 } 154 fmt.Printf("generated: %s.go done.\n\n", outPath) 155 } 156 157 func genDir(dir, outdir, pkg_name string) { 158 err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 159 if err != nil { 160 return fmt.Errorf("prevent panic by handling failure accessing a path %q: %v\n", dir, err) 161 } 162 163 if ext := filepath.Ext(info.Name()); ext == ".jade" || ext == ".pug" { 164 genFile(path, outdir, pkg_name) 165 } 166 return nil 167 }) 168 if err != nil { 169 log.Fatalln(err) 170 } 171 } 172 173 // 174 175 func main() { 176 flag.Usage = use 177 flag.Parse() 178 if len(flag.Args()) == 0 { 179 use() 180 return 181 } 182 183 jade.Config(golang) 184 185 if _, err := os.Stat(outdir); os.IsNotExist(err) { 186 os.MkdirAll(outdir, 0755) 187 } 188 outdir, _ = filepath.Abs(outdir) 189 190 if _, err := os.Stat(basedir); !os.IsNotExist(err) && basedir != "./" { 191 os.Chdir(basedir) 192 } 193 194 for _, jadePath := range flag.Args() { 195 196 stat, err := os.Stat(jadePath) 197 if err != nil { 198 log.Fatalln(err) 199 } 200 201 absPath, _ := filepath.Abs(jadePath) 202 if stat.IsDir() { 203 genDir(absPath, outdir, pkg_name) 204 } else { 205 genFile(absPath, outdir, pkg_name) 206 } 207 if !stdlib { 208 makeJfile(stdbuf) 209 } 210 } 211 }