Chore: Hacky first pass on generating composable kinds within grafana/schema (#64723)

* Super hacky first pass on gen types

* First sketchy pass at generated compo kinds in TS, grok-style

* Merge fix

* Create jenny for MajorsOrX for plugins

* Re-generate files with imports

* Delete invalid generated file

* Fix cue

* Update go.mod

* Update schemas

* Fix go-imports

* Regenerate cue files

---------

Co-authored-by: spinillos <selenepinillos@gmail.com>
This commit is contained in:
sam boyer
2023-05-30 05:56:18 -07:00
committed by GitHub
co-authored by spinillos
parent 12dc56ad0c
commit 09895c26b6
77 changed files with 6052 additions and 33 deletions
+5
View File
@@ -34,6 +34,11 @@ func (j *lmox) JennyName() string {
}
func (j *lmox) Generate(kind kindsys.Kind) (codejen.Files, error) {
// TODO remove this once codejen catches nils https://github.com/grafana/codejen/issues/5
if kind == nil {
return nil, nil
}
comm := kind.Props().Common()
sfg := SchemaForGen{
Name: comm.Name,
+6
View File
@@ -2,8 +2,10 @@ package codegen
import (
"github.com/grafana/codejen"
"github.com/grafana/cuetsy"
"github.com/grafana/cuetsy/ts"
"github.com/grafana/cuetsy/ts/ast"
"github.com/grafana/grafana/pkg/cuectx"
"github.com/grafana/thema/encoding/typescript"
)
@@ -25,6 +27,10 @@ func (j TSResourceJenny) Generate(sfg SchemaForGen) (*codejen.File, error) {
f, err := typescript.GenerateTypes(sfg.Schema, &typescript.TypeConfig{
RootName: sfg.Name,
Group: sfg.IsGroup,
CuetsyConfig: &cuetsy.Config{
Export: true,
ImportMapper: cuectx.MapCUEImportToTS,
},
})
if err != nil {
return nil, err
+6
View File
@@ -2,6 +2,8 @@ package codegen
import (
"github.com/grafana/codejen"
"github.com/grafana/cuetsy"
"github.com/grafana/grafana/pkg/cuectx"
"github.com/grafana/thema/encoding/typescript"
)
@@ -21,6 +23,10 @@ func (j TSTypesJenny) JennyName() string {
func (j TSTypesJenny) Generate(sfg SchemaForGen) (*codejen.File, error) {
// TODO allow using name instead of machine name in thema generator
f, err := typescript.GenerateTypes(sfg.Schema, &typescript.TypeConfig{
CuetsyConfig: &cuetsy.Config{
Export: true,
ImportMapper: cuectx.MapCUEImportToTS,
},
RootName: sfg.Name,
Group: sfg.IsGroup,
})
+5
View File
@@ -9,8 +9,10 @@ import (
"cuelang.org/go/cue"
"cuelang.org/go/cue/errors"
"github.com/grafana/codejen"
"github.com/grafana/cuetsy"
"github.com/grafana/cuetsy/ts"
"github.com/grafana/cuetsy/ts/ast"
"github.com/grafana/grafana/pkg/cuectx"
"github.com/grafana/kindsys"
"github.com/grafana/thema"
"github.com/grafana/thema/encoding/typescript"
@@ -44,6 +46,9 @@ func (gen *genTSVeneerIndex) Generate(kinds ...kindsys.Kind) (*codejen.File, err
for _, def := range kinds {
sch := def.Lineage().Latest()
f, err := typescript.GenerateTypes(sch, &typescript.TypeConfig{
CuetsyConfig: &cuetsy.Config{
ImportMapper: cuectx.MapCUEImportToTS,
},
RootName: def.Props().Common().Name,
Group: def.Props().Common().LineageIsGroup,
})
@@ -1,4 +1,4 @@
package codegen
package cuectx
import (
"fmt"
@@ -7,23 +7,20 @@ import (
"cuelang.org/go/cue/ast"
tsast "github.com/grafana/cuetsy/ts/ast"
"github.com/grafana/grafana/pkg/plugins/pfs"
)
// CUE import paths, mapped to corresponding TS import paths. An empty value
// indicates the import path should be dropped in the conversion to TS. Imports
// not present in the list are not not allowed, and code generation will fail.
// not present in the list are not allowed, and code generation will fail.
var importMap = map[string]string{
"github.com/grafana/thema": "",
"github.com/grafana/thema": "",
"github.com/grafana/kindsys": "",
"github.com/grafana/grafana/pkg/plugins/pfs": "",
"github.com/grafana/grafana/packages/grafana-schema/src/common": "@grafana/schema",
}
func init() {
allow := pfs.PermittedCUEImports()
allow := PermittedCUEImports()
strsl := make([]string, 0, len(importMap))
for p := range importMap {
strsl = append(strsl, p)
@@ -36,13 +33,24 @@ func init() {
}
}
// mapCUEImportToTS maps the provided CUE import path to the corresponding
// PermittedCUEImports returns the list of import paths that may be imported in
// Grafana kind definitions.
func PermittedCUEImports() []string {
return []string{
"github.com/grafana/thema",
"github.com/grafana/kindsys",
"github.com/grafana/grafana/pkg/plugins/pfs",
"github.com/grafana/grafana/packages/grafana-schema/src/common",
}
}
// MapCUEImportToTS maps the provided CUE import path to the corresponding
// TypeScript import path in generated code.
//
// Providing an import path that is not allowed results in an error. If a nil
// error and empty string are returned, the import path should be dropped in
// generated code.
func mapCUEImportToTS(path string) (string, error) {
func MapCUEImportToTS(path string) (string, error) {
i, has := importMap[path]
if !has {
return "", fmt.Errorf("import %q in models.cue is not allowed", path)
@@ -50,10 +58,14 @@ func mapCUEImportToTS(path string) (string, error) {
return i, nil
}
// TODO convert this to use cuetsy ts types, once import * form is supported
func convertImport(im *ast.ImportSpec) (tsast.ImportSpec, error) {
// ConvertImport converts a CUE import statement, represented in its AST form,
// to the corresponding TS import, if the CUE import is allowed.
//
// Some CUE imports are allowed but have no corresponding TS import - the CUE
// types from that package are expected to be inlined.
func ConvertImport(im *ast.ImportSpec) (tsast.ImportSpec, error) {
tsim := tsast.ImportSpec{}
pkg, err := mapCUEImportToTS(strings.Trim(im.Path.Value, "\""))
pkg, err := MapCUEImportToTS(strings.Trim(im.Path.Value, "\""))
if err != nil || pkg == "" {
// err should be unreachable if paths has been verified already
// Empty string mapping means skip it
@@ -0,0 +1,72 @@
package codegen
import (
"path/filepath"
"github.com/grafana/codejen"
tsast "github.com/grafana/cuetsy/ts/ast"
corecodegen "github.com/grafana/grafana/pkg/codegen"
"github.com/grafana/grafana/pkg/cuectx"
"github.com/grafana/grafana/pkg/plugins/pfs"
"github.com/grafana/kindsys"
"github.com/grafana/thema"
)
func PluginTSEachMajor(rt *thema.Runtime) codejen.OneToMany[*pfs.PluginDecl] {
latestMajorsOrX := corecodegen.LatestMajorsOrXJenny(filepath.Join("packages", "grafana-schema", "src", "raw", "composable"), false, corecodegen.TSTypesJenny{})
return &pleJenny{
inner: kinds2pd(rt, latestMajorsOrX),
}
}
type pleJenny struct {
inner codejen.OneToMany[*pfs.PluginDecl]
}
func (*pleJenny) JennyName() string {
return "PluginEachMajorJenny"
}
func (j *pleJenny) Generate(decl *pfs.PluginDecl) (codejen.Files, error) {
if !decl.HasSchema() {
return nil, nil
}
jf, err := j.inner.Generate(decl)
if err != nil {
return nil, err
}
files := make(codejen.Files, len(jf))
for i, file := range jf {
tsf := &tsast.File{}
for _, im := range decl.Imports {
if tsim, err := cuectx.ConvertImport(im); err != nil {
return nil, err
} else if tsim.From.Value != "" {
tsf.Imports = append(tsf.Imports, tsim)
}
}
tsf.Nodes = append(tsf.Nodes, tsast.Raw{
Data: string(file.Data),
})
data := []byte(tsf.String())
data = data[:len(data)-1] // remove the additional line break added by the inner jenny
files[i] = *codejen.NewFile(file.RelativePath, data, append(file.From, j)...)
}
return files, nil
}
func kinds2pd(rt *thema.Runtime, j codejen.OneToMany[kindsys.Kind]) codejen.OneToMany[*pfs.PluginDecl] {
return codejen.AdaptOneToMany(j, func(pd *pfs.PluginDecl) kindsys.Kind {
kd, err := kindsys.BindComposable(rt, pd.KindDecl)
if err != nil {
return nil
}
return kd
})
}
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"github.com/grafana/codejen"
tsast "github.com/grafana/cuetsy/ts/ast"
"github.com/grafana/grafana/pkg/cuectx"
"github.com/grafana/grafana/pkg/plugins/pfs"
)
@@ -34,7 +35,7 @@ func (j *ptsJenny) Generate(decl *pfs.PluginDecl) (*codejen.File, error) {
tsf := &tsast.File{}
for _, im := range decl.Imports {
if tsim, err := convertImport(im); err != nil {
if tsim, err := cuectx.ConvertImport(im); err != nil {
return nil, err
} else if tsim.From.Value != "" {
tsf.Imports = append(tsf.Imports, tsim)
+1 -10
View File
@@ -53,16 +53,7 @@ func loadGP(ctx *cue.Context) cue.Value {
// PermittedCUEImports returns the list of import paths that may be used in a
// plugin's grafanaplugin cue package.
//
// TODO probably move this into kindsys
func PermittedCUEImports() []string {
return []string{
"github.com/grafana/thema",
"github.com/grafana/kindsys",
"github.com/grafana/grafana/pkg/plugins/pfs",
"github.com/grafana/grafana/packages/grafana-schema/src/common",
}
}
var PermittedCUEImports = cuectx.PermittedCUEImports
func importAllowed(path string) bool {
for _, p := range PermittedCUEImports() {