mirror of
https://github.com/grafana/grafana.git
synced 2025-01-10 08:03:58 -06:00
473898e47c
* Move some thema code inside grafana * Use new codegen instead of thema for core kinds * Replace TS generator * Use new generator for go types * Remove thema from oapi generator * Remove thema from generators * Don't use kindsys/thema for core kinds * Remove kindsys/thema from plugins * Remove last thema related * Remove most of cuectx and move utils_ts into codegen. It also deletes wire dependency * Merge plugins generators * Delete thema dependency 🎉 * Fix CODEOWNERS * Fix package name * Fix TS output names * More path fixes * Fix mod codeowners * Use original plugin's name * Remove kindsys dependency 🎉 * Modify oapi schema and create an apply function to fix elasticsearch errors * cue.mod was deleted by mistake * Fix TS panels * sort imports * Fixing elasticsearch output * Downgrade oapi-codegen library * Update output ts files * More fixes * Restore old elasticsearch generated file and skip its generation. Remove core imports into plugins * More lint fixes * Add codeowners * restore embed.go file * Fix embed.go
283 lines
6.9 KiB
Go
283 lines
6.9 KiB
Go
package generators
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"github.com/dave/dst"
|
|
"github.com/dave/dst/dstutil"
|
|
)
|
|
|
|
// depointerizer returns an AST manipulator that removes redundant
|
|
// pointer indirection from the defined types.
|
|
func depointerizer() dstutil.ApplyFunc {
|
|
return func(c *dstutil.Cursor) bool {
|
|
switch x := c.Node().(type) {
|
|
case *dst.Field:
|
|
if s, is := x.Type.(*dst.StarExpr); is {
|
|
switch deref := depoint(s).(type) {
|
|
case *dst.ArrayType, *dst.MapType:
|
|
x.Type = deref
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
func depoint(e dst.Expr) dst.Expr {
|
|
if star, is := e.(*dst.StarExpr); is {
|
|
return star.X
|
|
}
|
|
return e
|
|
}
|
|
|
|
func setStar(e dst.Expr) string {
|
|
if _, is := e.(*dst.StarExpr); is {
|
|
return "*"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func fixTODOComments() dstutil.ApplyFunc {
|
|
return func(cursor *dstutil.Cursor) bool {
|
|
switch f := cursor.Node().(type) {
|
|
case *dst.File:
|
|
for _, d := range f.Decls {
|
|
if isTypeSpec(d) {
|
|
removeGoFieldComment(d.Decorations().Start.All())
|
|
}
|
|
fixTODOComment(d.Decorations().Start.All())
|
|
}
|
|
case *dst.Field:
|
|
if len(f.Names) > 0 {
|
|
removeGoFieldComment(f.Decorations().Start.All())
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
}
|
|
|
|
func fixTODOComment(comments []string) {
|
|
todoRegex := regexp.MustCompile("(//) (.*) (TODO.*)")
|
|
if len(comments) > 0 {
|
|
comments[0] = todoRegex.ReplaceAllString(comments[0], "$1 $3")
|
|
}
|
|
}
|
|
|
|
func removeGoFieldComment(comments []string) {
|
|
todoRegex := regexp.MustCompile("(//) ([A-Z].*?) ([A-Z]?.*?) (.*)")
|
|
if len(comments) > 0 {
|
|
matches := todoRegex.FindAllStringSubmatch(comments[0], -1)
|
|
if len(matches) > 0 {
|
|
if strings.EqualFold(matches[0][3], matches[0][2]) {
|
|
comments[0] = fmt.Sprintf("%s %s %s", matches[0][1], matches[0][3], matches[0][4])
|
|
} else {
|
|
r := []rune(matches[0][3])
|
|
if !unicode.IsLower(r[0]) {
|
|
comments[0] = fmt.Sprintf("%s %s %s", matches[0][1], matches[0][3], matches[0][4])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func isTypeSpec(d dst.Decl) bool {
|
|
gd, ok := d.(*dst.GenDecl)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
_, is := gd.Specs[0].(*dst.TypeSpec)
|
|
return is
|
|
}
|
|
|
|
// It fixes the "generic" fields. It happens when a value in cue could be different structs.
|
|
// For Go it generates a struct with a json.RawMessage field inside and multiple functions to map it between the different possibilities.
|
|
func fixRawData() dstutil.ApplyFunc {
|
|
return func(c *dstutil.Cursor) bool {
|
|
f, is := c.Node().(*dst.File)
|
|
if !is {
|
|
return false
|
|
}
|
|
|
|
rawFields := make(map[string]bool)
|
|
existingRawFields := make(map[string]bool)
|
|
for _, decl := range f.Decls {
|
|
switch x := decl.(type) {
|
|
// Find the structs that only contains one json.RawMessage inside
|
|
case *dst.GenDecl:
|
|
for _, t := range x.Specs {
|
|
if ts, ok := t.(*dst.TypeSpec); ok {
|
|
if tp, ok := ts.Type.(*dst.StructType); ok && len(tp.Fields.List) == 1 {
|
|
if fn, ok := tp.Fields.List[0].Type.(*dst.SelectorExpr); ok {
|
|
if fmt.Sprintf("%s.%s", fn.X, fn.Sel.Name) == "json.RawMessage" {
|
|
rawFields[ts.Name.Name] = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Find the functions of the previous structs to verify that are the ones that we are looking for.
|
|
case *dst.FuncDecl:
|
|
for _, recv := range x.Recv.List {
|
|
fnType := depoint(recv.Type).(*dst.Ident).Name
|
|
if rawFields[fnType] {
|
|
existingRawFields[fnType] = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
dstutil.Apply(f, func(c *dstutil.Cursor) bool {
|
|
switch x := c.Node().(type) {
|
|
// Delete the functions
|
|
case *dst.FuncDecl:
|
|
c.Delete()
|
|
case *dst.GenDecl:
|
|
// Deletes all "generics" generated for these json.RawMessage structs
|
|
comments := x.Decorations().Start.All()
|
|
if len(comments) > 0 {
|
|
if strings.HasSuffix(comments[0], "defines model for .") {
|
|
c.Delete()
|
|
}
|
|
}
|
|
for _, spec := range x.Specs {
|
|
if tp, ok := spec.(*dst.TypeSpec); ok {
|
|
// Delete structs with only json.RawMessage
|
|
if existingRawFields[tp.Name.Name] && tp.Name.Name != "MetricAggregation2" {
|
|
c.Delete()
|
|
continue
|
|
}
|
|
// Set types that was using these structs as interface{}
|
|
if st, ok := tp.Type.(*dst.StructType); ok {
|
|
iterateStruct(st, withoutRawData(existingRawFields))
|
|
}
|
|
if mt, ok := tp.Type.(*dst.MapType); ok {
|
|
iterateMap(mt, withoutRawData(existingRawFields))
|
|
}
|
|
if at, ok := tp.Type.(*dst.ArrayType); ok {
|
|
iterateArray(at, withoutRawData(existingRawFields))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}, nil)
|
|
|
|
return true
|
|
}
|
|
}
|
|
|
|
// Fixes type name containing underscores in the generated Go files
|
|
func fixUnderscoreInTypeName() dstutil.ApplyFunc {
|
|
return func(c *dstutil.Cursor) bool {
|
|
switch x := c.Node().(type) {
|
|
case *dst.GenDecl:
|
|
if specs, isType := x.Specs[0].(*dst.TypeSpec); isType {
|
|
if strings.Contains(specs.Name.Name, "_") {
|
|
oldName := specs.Name.Name
|
|
specs.Name.Name = strings.ReplaceAll(specs.Name.Name, "_", "")
|
|
x.Decs.Start[0] = strings.ReplaceAll(x.Decs.Start[0], oldName, specs.Name.Name)
|
|
}
|
|
if st, ok := specs.Type.(*dst.StructType); ok {
|
|
iterateStruct(st, withoutUnderscore)
|
|
}
|
|
if mt, ok := specs.Type.(*dst.MapType); ok {
|
|
iterateMap(mt, withoutUnderscore)
|
|
}
|
|
if at, ok := specs.Type.(*dst.ArrayType); ok {
|
|
iterateArray(at, withoutUnderscore)
|
|
}
|
|
}
|
|
case *dst.Field:
|
|
findFieldsWithUnderscores(x)
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
func findFieldsWithUnderscores(x *dst.Field) {
|
|
switch t := x.Type.(type) {
|
|
case *dst.Ident:
|
|
withoutUnderscore(t)
|
|
case *dst.StarExpr:
|
|
if i, is := t.X.(*dst.Ident); is {
|
|
withoutUnderscore(i)
|
|
}
|
|
case *dst.ArrayType:
|
|
iterateArray(t, withoutUnderscore)
|
|
case *dst.MapType:
|
|
iterateMap(t, withoutUnderscore)
|
|
}
|
|
}
|
|
|
|
func withoutUnderscore(i *dst.Ident) {
|
|
if strings.Contains(i.Name, "_") {
|
|
i.Name = strings.ReplaceAll(i.Name, "_", "")
|
|
}
|
|
}
|
|
|
|
func withoutRawData(existingFields map[string]bool) func(ident *dst.Ident) {
|
|
return func(i *dst.Ident) {
|
|
if existingFields[i.Name] {
|
|
i.Name = setStar(i) + "any"
|
|
}
|
|
}
|
|
}
|
|
|
|
func iterateStruct(s *dst.StructType, fn func(i *dst.Ident)) {
|
|
for i, f := range s.Fields.List {
|
|
switch mx := depoint(f.Type).(type) {
|
|
case *dst.Ident:
|
|
fn(mx)
|
|
case *dst.ArrayType:
|
|
iterateArray(mx, fn)
|
|
case *dst.MapType:
|
|
iterateMap(mx, fn)
|
|
case *dst.StructType:
|
|
iterateStruct(mx, fn)
|
|
case *dst.InterfaceType:
|
|
s.Fields.List[i].Type = interfaceToAny(f.Type)
|
|
}
|
|
}
|
|
}
|
|
|
|
func iterateMap(s *dst.MapType, fn func(i *dst.Ident)) {
|
|
switch mx := s.Value.(type) {
|
|
case *dst.Ident:
|
|
fn(mx)
|
|
case *dst.ArrayType:
|
|
iterateArray(mx, fn)
|
|
case *dst.MapType:
|
|
iterateMap(mx, fn)
|
|
case *dst.InterfaceType:
|
|
s.Value = interfaceToAny(s.Value)
|
|
}
|
|
}
|
|
|
|
func iterateArray(a *dst.ArrayType, fn func(i *dst.Ident)) {
|
|
switch mx := a.Elt.(type) {
|
|
case *dst.Ident:
|
|
fn(mx)
|
|
case *dst.ArrayType:
|
|
iterateArray(mx, fn)
|
|
case *dst.StructType:
|
|
iterateStruct(mx, fn)
|
|
case *dst.InterfaceType:
|
|
a.Elt = interfaceToAny(a.Elt)
|
|
}
|
|
}
|
|
|
|
func interfaceToAny(i dst.Expr) dst.Expr {
|
|
star := ""
|
|
if _, is := i.(*dst.StarExpr); is {
|
|
star = "*"
|
|
}
|
|
|
|
return &dst.Ident{Name: star + "any"}
|
|
}
|