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)