github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/statusxgen/generator.go (about)

     1  package statusxgen
     2  
     3  import (
     4  	"go/types"
     5  	"log"
     6  	"path"
     7  	"path/filepath"
     8  	"runtime"
     9  
    10  	gen "github.com/machinefi/w3bstream/pkg/depends/gen/codegen"
    11  	"github.com/machinefi/w3bstream/pkg/depends/kit/statusx"
    12  	"github.com/machinefi/w3bstream/pkg/depends/x/misc/must"
    13  	"github.com/machinefi/w3bstream/pkg/depends/x/pkgx"
    14  	"github.com/machinefi/w3bstream/pkg/depends/x/stringsx"
    15  )
    16  
    17  func New(pkg *pkgx.Pkg) *Generator {
    18  	return &Generator{
    19  		pkg:     pkg,
    20  		scanner: NewScanner(pkg),
    21  		errs:    map[string]*StatusError{},
    22  	}
    23  }
    24  
    25  type Generator struct {
    26  	pkg     *pkgx.Pkg
    27  	scanner *Scanner
    28  	errs    map[string]*StatusError
    29  }
    30  
    31  func (g *Generator) Scan(names ...string) {
    32  	for _, name := range names {
    33  		typeName := g.pkg.TypeName(name)
    34  		g.errs[name] = &StatusError{
    35  			TypeName: typeName,
    36  			Errors:   g.scanner.StatusError(typeName),
    37  		}
    38  	}
    39  }
    40  
    41  func (g *Generator) Output(cwd string) {
    42  	for _, e := range g.errs {
    43  		dir, _ := filepath.Rel(
    44  			cwd,
    45  			must.String(pkgx.PkgPathByPath(e.TypeName.Pkg().Path())),
    46  		)
    47  		filename := gen.GenerateFileSuffix(path.Join(dir, stringsx.LowerSnakeCase(e.Name())+".go"))
    48  
    49  		f := gen.NewFile(e.TypeName.Pkg().Name(), filename)
    50  
    51  		if err := e.WriteToFile(f); err != nil {
    52  			log.Printf("%s generate failed: %v", filename, err)
    53  		}
    54  	}
    55  }
    56  
    57  type StatusError struct {
    58  	TypeName *types.TypeName
    59  	Errors   []*statusx.StatusErr
    60  }
    61  
    62  func (s *StatusError) Name() string { return s.TypeName.Name() }
    63  
    64  func (s *StatusError) SnippetTypeAssert(f *gen.File) gen.Snippet {
    65  	return gen.Exprer(
    66  		"var _ ? = (*?)(nil)",
    67  		gen.Type(f.Use(PkgPath, "Error")),
    68  		gen.Type(s.Name()),
    69  	)
    70  }
    71  
    72  func (s *StatusError) SnippetStatusErr(f *gen.File) gen.Snippet {
    73  	t := gen.Type(f.Use(PkgPath, "StatusErr"))
    74  
    75  	return gen.Func().Named("StatusErr").MethodOf(gen.Var(gen.Type(s.Name()), "v")).
    76  		Return(gen.Var(gen.Star(t))).
    77  		Do(
    78  			f.Expr(`return &?{
    79  Key: v.Key(),
    80  Code: v.Code(),
    81  Msg: v.Msg(),
    82  CanBeTalk: v.CanBeTalk(),
    83  }`,
    84  				t),
    85  		)
    86  }
    87  
    88  func (s *StatusError) SnippetUnwrap(f *gen.File) gen.Snippet {
    89  	return gen.Func().Named("Unwrap").MethodOf(gen.Var(gen.Type(s.Name()), "v")).
    90  		Return(gen.Var(gen.Error)).
    91  		Do(f.Expr(`return v.StatusErr()`))
    92  }
    93  
    94  func (s *StatusError) SnippetError(f *gen.File) gen.Snippet {
    95  	return gen.Func().Named("Error").MethodOf(gen.Var(gen.Type(s.Name()), "v")).
    96  		Return(gen.Var(gen.String)).
    97  		Do(f.Expr(`return v.StatusErr().Error()`))
    98  }
    99  
   100  func (s *StatusError) SnippetStatusCode(f *gen.File) gen.Snippet {
   101  	return gen.Func().Named("StatusCode").MethodOf(gen.Var(gen.Type(s.Name()), "v")).
   102  		Return(gen.Var(gen.Int)).
   103  		Do(
   104  			f.Expr(
   105  				`return ?(int(v))`,
   106  				gen.Ident(f.Use(PkgPath, "StatusCodeFromCode")),
   107  			),
   108  		)
   109  }
   110  
   111  func (s *StatusError) SnippetCode(f *gen.File) gen.Snippet {
   112  	return gen.Func().Named("Code").MethodOf(gen.Var(gen.Type(s.Name()), "v")).
   113  		Return(gen.Var(gen.Int)).
   114  		Do(
   115  			f.Expr(`if with, ok := (interface{})(v).(?); ok {
   116  return with.ServiceCode() + int(v)
   117  }
   118  return int(v)`,
   119  				gen.Ident(f.Use(PkgPath, "ServiceCode"))),
   120  		)
   121  }
   122  
   123  func (s *StatusError) SnippetKey(f *gen.File) gen.Snippet {
   124  	clauses := make([]*gen.SnippetCaseClause, 0)
   125  
   126  	for _, e := range s.Errors {
   127  		clauses = append(clauses,
   128  			gen.CaseClause(gen.Ident(e.Key)).Do(gen.Return(f.Value(e.Key))),
   129  		)
   130  	}
   131  
   132  	return gen.Func().Named("Key").MethodOf(gen.Var(gen.Type(s.Name()), "v")).
   133  		Return(gen.Var(gen.String)).
   134  		Do(
   135  			gen.Switch(gen.Ident("v")).
   136  				When(
   137  					clauses...,
   138  				),
   139  			gen.Return(f.Value("UNKNOWN")),
   140  		)
   141  }
   142  
   143  func (s *StatusError) SnippetMsg(f *gen.File) gen.Snippet {
   144  	clauses := make([]*gen.SnippetCaseClause, 0)
   145  
   146  	for _, e := range s.Errors {
   147  		clauses = append(clauses,
   148  			gen.CaseClause(gen.Ident(e.Key)).Do(gen.Return(f.Value(e.Msg))))
   149  	}
   150  
   151  	return gen.Func().Named("Msg").MethodOf(gen.Var(gen.Type(s.Name()), "v")).
   152  		Return(gen.Var(gen.String)).
   153  		Do(
   154  			gen.Switch(gen.Ident("v")).
   155  				When(
   156  					clauses...,
   157  				),
   158  			gen.Return(f.Value("-")),
   159  		)
   160  }
   161  
   162  func (s *StatusError) SnippetCanBeTalk(f *gen.File) gen.Snippet {
   163  	clauses := make([]*gen.SnippetCaseClause, 0)
   164  
   165  	for _, e := range s.Errors {
   166  		clauses = append(clauses,
   167  			gen.CaseClause(gen.Ident(e.Key)).Do(gen.Return(f.Value(e.CanBeTalk))),
   168  		)
   169  	}
   170  
   171  	return gen.Func().Named("CanBeTalk").MethodOf(gen.Var(gen.Type(s.Name()), "v")).
   172  		Return(gen.Var(gen.Bool)).Do(
   173  		gen.Switch(gen.Ident("v")).When(
   174  			clauses...,
   175  		),
   176  		gen.Return(f.Value(false)),
   177  	)
   178  }
   179  
   180  func (s *StatusError) WriteToFile(f *gen.File) error {
   181  	f.WriteSnippet(
   182  		s.SnippetTypeAssert(f),
   183  		s.SnippetStatusErr(f),
   184  		s.SnippetUnwrap(f),
   185  		s.SnippetError(f),
   186  		s.SnippetStatusCode(f),
   187  		s.SnippetCode(f),
   188  		s.SnippetKey(f),
   189  		s.SnippetMsg(f),
   190  		s.SnippetCanBeTalk(f),
   191  	)
   192  	_, err := f.Write()
   193  	return err
   194  }
   195  
   196  var PkgPath string
   197  
   198  func init() {
   199  	_, current, _, _ := runtime.Caller(0)
   200  	dir := filepath.Join(filepath.Dir(current), "../statusx")
   201  	PkgPath = must.String(pkgx.PkgIdByPath(dir))
   202  }