grafana/pkg/codegen/generators/utils.go
Selene 473898e47c
Core: Remove thema and kindsys dependencies (#84499)
* 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
2024-03-21 11:11:29 +01:00

131 lines
2.9 KiB
Go

package generators
import (
"fmt"
"strconv"
"strings"
"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/token"
)
// sanitizeLabelString strips characters from a string that are not allowed for
// use in a CUE label.
func sanitizeLabelString(s string) string {
return strings.Map(func(r rune) rune {
switch {
case r >= 'a' && r <= 'z':
fallthrough
case r >= 'A' && r <= 'Z':
fallthrough
case r >= '0' && r <= '9':
fallthrough
case r == '_':
return r
default:
return -1
}
}, s)
}
// trimPathPrefix strips the provided prefix from the provided path, if the
// prefix exists.
//
// If path and prefix are equivalent, and there is at least one additional
// selector in the provided path.
func trimPathPrefix(path, prefix cue.Path) cue.Path {
sels, psels := path.Selectors(), prefix.Selectors()
if len(sels) == 1 {
return path
}
var i int
for ; i < len(psels) && i < len(sels); i++ {
if !selEq(psels[i], sels[i]) {
break
}
}
return cue.MakePath(sels[i:]...)
}
// selEq indicates whether two selectors are equivalent. Selectors are equivalent if
// they are either exactly equal, or if they are equal ignoring path optionality.
func selEq(s1, s2 cue.Selector) bool {
return s1 == s2 || s1.Optional() == s2.Optional()
}
// getFieldByLabel returns the ast.Field with a given label from a struct-ish input.
func getFieldByLabel(n ast.Node, label string) (*ast.Field, error) {
var d []ast.Decl
switch x := n.(type) {
case *ast.File:
d = x.Decls
case *ast.StructLit:
d = x.Elts
default:
return nil, fmt.Errorf("not an *ast.File or *ast.StructLit")
}
for _, el := range d {
if isFieldWithLabel(el, label) {
return el.(*ast.Field), nil
}
}
return nil, fmt.Errorf("no field with label %q", label)
}
func isFieldWithLabel(n ast.Node, label string) bool {
if x, is := n.(*ast.Field); is {
if l, is := x.Label.(*ast.BasicLit); is {
return strEq(l, label)
}
if l, is := x.Label.(*ast.Ident); is {
return identStrEq(l, label)
}
}
return false
}
func strEq(lit *ast.BasicLit, str string) bool {
if lit.Kind != token.STRING {
return false
}
ls, _ := strconv.Unquote(lit.Value)
return str == ls || str == lit.Value
}
func identStrEq(id *ast.Ident, str string) bool {
if str == id.Name {
return true
}
ls, _ := strconv.Unquote(id.Name)
return str == ls
}
// pathHasPrefix tests whether the [cue.Path] p begins with prefix.
func pathHasPrefix(p, prefix cue.Path) bool {
ps, pres := p.Selectors(), prefix.Selectors()
if len(pres) > len(ps) {
return false
}
return pathsAreEq(ps[:len(pres)], pres)
}
func pathsAreEq(p1s, p2s []cue.Selector) bool {
if len(p1s) != len(p2s) {
return false
}
for i := 0; i < len(p2s); i++ {
if !selEq(p2s[i], p1s[i]) {
return false
}
}
return true
}
func getSchemaName(v cue.Value) (string, error) {
nameValue := v.LookupPath(cue.ParsePath("name"))
return nameValue.String()
}