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  }