github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/gen/codegen/gen.go (about)

     1  package codegen
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"path"
     8  	"path/filepath"
     9  	"reflect"
    10  	"time"
    11  
    12  	"golang.org/x/tools/go/packages"
    13  
    14  	"github.com/machinefi/w3bstream/pkg/depends/gen/codegen/formatx"
    15  	"github.com/machinefi/w3bstream/pkg/depends/x/stringsx"
    16  )
    17  
    18  type File struct {
    19  	Pkg         string
    20  	Name        string
    21  	Imps        map[string]string
    22  	Pkgs        map[string][]string
    23  	OrderedImps [][2]string
    24  	opts        WriteOption
    25  	bytes.Buffer
    26  }
    27  
    28  func NewFile(pkg, name string) *File {
    29  	return &File{
    30  		Pkg:  pkg,
    31  		Name: name,
    32  		opts: WriteOption{WithCommit: true, MustFormat: true},
    33  	}
    34  }
    35  
    36  func (f *File) bytes() []byte {
    37  	buf := bytes.NewBuffer(nil)
    38  
    39  	if f.opts.WithCommit {
    40  		cmt := Comments(
    41  			`This is a generated source file. DO NOT EDIT`,
    42  			`Source: `+path.Join(f.Pkg, path.Base(f.Name)),
    43  		)
    44  		if f.opts.WithToolVersion {
    45  			cmt.Append(`Version: ` + Version)
    46  		}
    47  		if f.opts.WithTimestamp {
    48  			cmt.Append(`Date: ` + time.Now().Format(time.Stamp))
    49  		}
    50  
    51  		buf.Write(cmt.Bytes())
    52  		buf.WriteRune('\n')
    53  	}
    54  
    55  	buf.Write([]byte("\npackage " + stringsx.LowerSnakeCase(f.Pkg) + "\n"))
    56  
    57  	if len(f.Imps) > 0 {
    58  		if len(f.Imps) == 1 {
    59  			buf.Write([]byte("import "))
    60  		} else if len(f.Imps) > 1 {
    61  			buf.Write([]byte("import (\n"))
    62  		}
    63  
    64  		for _, imp := range f.OrderedImps {
    65  			if IsReserved(imp[0]) {
    66  				panic("[CONFLICT] package name conflict reserved")
    67  			}
    68  			if imp[0] != path.Base(imp[1]) {
    69  				buf.WriteString(imp[0])
    70  				buf.WriteByte(' ')
    71  			}
    72  			buf.WriteByte('"')
    73  			buf.WriteString(imp[1])
    74  			buf.WriteByte('"')
    75  			buf.WriteByte('\n')
    76  		}
    77  
    78  		if len(f.Imps) > 1 {
    79  			buf.Write([]byte(")\n"))
    80  		}
    81  	}
    82  
    83  	buf.Write(f.Buffer.Bytes())
    84  
    85  	if f.opts.MustFormat {
    86  		return formatx.MustFormat(f.Name, "", buf.Bytes(), formatx.SortImports)
    87  	}
    88  	return buf.Bytes()
    89  }
    90  
    91  func (f *File) Bytes() []byte {
    92  	return f.bytes()
    93  }
    94  
    95  // Raw test only
    96  func (f File) Raw() []byte { return f.bytes() }
    97  
    98  // Formatted test only
    99  func (f File) Formatted() []byte { return f.bytes() }
   100  
   101  func (f *File) _import(pkg string) string {
   102  	if f.Imps == nil {
   103  		f.Imps = make(map[string]string)
   104  		f.Pkgs = make(map[string][]string)
   105  	}
   106  
   107  	if _, ok := f.Imps[pkg]; !ok {
   108  		pkgs, err := packages.Load(nil, pkg)
   109  		if err != nil {
   110  			panic(err)
   111  		}
   112  		if len(pkgs) == 0 {
   113  			panic(pkg + " not found")
   114  		}
   115  		pkg = pkgs[0].PkgPath
   116  		min := path.Base(pkg)
   117  
   118  		if len(f.Pkgs[min]) == 0 {
   119  			f.Imps[pkg] = min
   120  		} else {
   121  			f.Imps[pkg] = stringsx.LowerSnakeCase(
   122  				fmt.Sprintf("gen %s %d", min, len(f.Pkgs[min])),
   123  			)
   124  		}
   125  		f.Pkgs[min] = append(f.Pkgs[min], pkg)
   126  		f.OrderedImps = append(f.OrderedImps, [2]string{f.Imps[pkg], pkg})
   127  	}
   128  	return f.Imps[pkg]
   129  }
   130  
   131  func (f *File) Use(pkg, name string) string { return f._import(pkg) + "." + name }
   132  
   133  func (f *File) Expr(format string, args ...interface{}) SnippetExpr {
   134  	return ExprWithAlias(f._import)(format, args...)
   135  }
   136  
   137  func (f *File) Type(t reflect.Type) SnippetType {
   138  	return TypeWithAlias(f._import)(t)
   139  }
   140  
   141  func (f *File) Value(v interface{}) Snippet { return ValueWithAlias(f._import)(v) }
   142  
   143  func (f *File) WriteSnippet(ss ...Snippet) {
   144  	for _, s := range ss {
   145  		if s != nil {
   146  			f.Buffer.Write(s.Bytes())
   147  			f.Buffer.WriteString("\n\n")
   148  		}
   149  	}
   150  }
   151  
   152  func (f *File) Write(opts ...WriterOptionSetter) (int, error) {
   153  	for _, setter := range opts {
   154  		setter(&f.opts)
   155  	}
   156  
   157  	if dir := filepath.Dir(f.Name); dir != "" {
   158  		if err := os.MkdirAll(dir, os.ModePerm); err != nil {
   159  			return -1, err
   160  		}
   161  	}
   162  
   163  	fl, err := os.Create(f.Name)
   164  	if err != nil {
   165  		return -1, err
   166  	}
   167  	defer fl.Close()
   168  
   169  	size, err := fl.Write(f.Bytes())
   170  	if err != nil {
   171  		return -1, err
   172  	}
   173  
   174  	if err := fl.Sync(); err != nil {
   175  		return -1, err
   176  	}
   177  	return size, nil
   178  }
   179  
   180  type WriteOption struct {
   181  	WithCommit      bool
   182  	WithTimestamp   bool
   183  	WithToolVersion bool
   184  	MustFormat      bool
   185  }
   186  
   187  func WriteOptionWithCommit(v *WriteOption)      { v.WithCommit = true }
   188  func WriteOptionWithTimestamp(v *WriteOption)   { v.WithCommit, v.WithTimestamp = true, true }
   189  func WriteOptionWithToolVersion(v *WriteOption) { v.WithCommit, v.WithToolVersion = true, true }
   190  func WriteOptionMustFormat(v *WriteOption)      { v.MustFormat = true }
   191  
   192  type WriterOptionSetter func(v *WriteOption)