Skip to content

Commit

Permalink
Compose panel Options and FieldConfig composite types into a unified …
Browse files Browse the repository at this point in the history
…panel builder
  • Loading branch information
K-Phoen committed Oct 7, 2023
1 parent 31a3a6f commit 9e3d7bf
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 159 deletions.
16 changes: 14 additions & 2 deletions internal/jennies/golang/jennies.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,26 @@ func Jennies() *codejen.JennyList[[]*ast.Schema] {
codejen.AdaptOneToMany[[]ast.Builder, []*ast.Schema](
&Builder{},
func(schemas []*ast.Schema) []ast.Builder {
var err error

generator := &ast.BuilderGenerator{}
builders := generator.FromAST(schemas)

// apply common veneers
builders = veneers.Common().ApplyTo(builders)
builders, err = veneers.Common().ApplyTo(builders)
if err != nil {
// FIXME: codejen.AdaptOneToMany() doesn't let us return an error
panic(err)
}

// apply Go-specific veneers
return Veneers().ApplyTo(builders)
builders, err = Veneers().ApplyTo(builders)
if err != nil {
// FIXME: codejen.AdaptOneToMany() doesn't let us return an error
panic(err)
}

return builders
},
),
)
Expand Down
16 changes: 14 additions & 2 deletions internal/jennies/typescript/jennies.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,26 @@ func Jennies() *codejen.JennyList[[]*ast.Schema] {
codejen.AdaptOneToMany[[]ast.Builder, []*ast.Schema](
&Builder{},
func(schemas []*ast.Schema) []ast.Builder {
var err error

generator := &ast.BuilderGenerator{}
builders := generator.FromAST(schemas)

// apply common veneers
builders = veneers.Common().ApplyTo(builders)
builders, err = veneers.Common().ApplyTo(builders)
if err != nil {
// FIXME: codejen.AdaptOneToMany() doesn't let us return an error
panic(err)
}

// apply TS-specific veneers
return Veneers().ApplyTo(builders)
builders, err = Veneers().ApplyTo(builders)
if err != nil {
// FIXME: codejen.AdaptOneToMany() doesn't let us return an error
panic(err)
}

return builders
},
),
)
Expand Down
116 changes: 0 additions & 116 deletions internal/veneers/builder/actions.go

This file was deleted.

172 changes: 159 additions & 13 deletions internal/veneers/builder/rules.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,173 @@
package builder

type RewriteRule struct {
Selector Selector
Action RewriteAction
import (
"fmt"
"strings"

"github.com/grafana/cog/internal/ast"
"github.com/grafana/cog/internal/tools"
)

type RewriteRule func(builders ast.Builders) (ast.Builders, error)

func mapToSelected(selector Selector, mapFunc func(builders ast.Builders, builder ast.Builder) (ast.Builder, error)) RewriteRule {
return func(builders ast.Builders) (ast.Builders, error) {
for i, b := range builders {
if !selector(b) {
continue
}

newBuilder, err := mapFunc(builders, b)
if err != nil {
return nil, err
}

builders[i] = newBuilder
}

return builders, nil
}
}

func mergeOptions(fromBuilder ast.Builder, intoBuilder ast.Builder, underPath string, excludeOptions []string) ast.Builder {
newBuilder := intoBuilder

for _, opt := range fromBuilder.Options {
if tools.ItemInList(opt.Name, excludeOptions) {
continue
}

// TODO: assignment paths
newOpt := opt
newOpt.Assignments = nil

for _, assignment := range opt.Assignments {
newAssignment := assignment
// @FIXME: this only works if no part of the `underPath` path can be nil
newAssignment.Path = underPath + "." + assignment.Path

newOpt.Assignments = append(newOpt.Assignments, newAssignment)
}

newBuilder.Options = append(newBuilder.Options, newOpt)
}

return newBuilder
}

func Omit(selector Selector) RewriteRule {
return RewriteRule{
Selector: selector,
Action: OmitAction(),
return func(builders ast.Builders) (ast.Builders, error) {
filteredBuilders := make([]ast.Builder, 0, len(builders))

for _, builder := range builders {
if selector(builder) {
continue
}

filteredBuilders = append(filteredBuilders, builder)
}

return filteredBuilders, nil
}
}

func MergeInto(selector Selector, sourceBuilderName string, underPath string, excludeOptions []string) RewriteRule {
return RewriteRule{
Selector: selector,
Action: MergeIntoAction(sourceBuilderName, underPath, excludeOptions),
return mapToSelected(selector, func(builders ast.Builders, destinationBuilder ast.Builder) (ast.Builder, error) {
sourcePkg, sourceBuilderNameWithoutPkg, found := strings.Cut(sourceBuilderName, ".")
if !found {
return destinationBuilder, fmt.Errorf("sourceBuilderName '%s' is incorrect: no package found", sourceBuilderName)
}

sourceBuilder, found := builders.LocateByObject(sourcePkg, sourceBuilderNameWithoutPkg)
if !found {
return destinationBuilder, fmt.Errorf("source builder '%s.%s' not found", sourcePkg, sourceBuilderNameWithoutPkg)
}

// TODO: initializations
newBuilder := mergeOptions(sourceBuilder, destinationBuilder, underPath, excludeOptions)

return newBuilder, nil
})
}

func composePanelType(panelType string, panelBuilder ast.Builder, composableBuilders ast.Builders) ast.Builder {
newBuilder := ast.Builder{
Schema: panelBuilder.Schema,
For: panelBuilder.For,
RootPackage: panelType,
Package: "panel",
}

newBuilder.Initializations = append(newBuilder.Initializations, ast.Assignment{
Path: "type",
ValueType: ast.String(),
Value: panelType,
})

// re-add panel-related options
for _, panelOpt := range panelBuilder.Options {
// this value is a constant that depends on the plugin being composed into a panel
if panelOpt.Name == "type" {
continue
}

newBuilder.Options = append(newBuilder.Options, panelOpt)
}

for _, composableBuilder := range composableBuilders {
if composableBuilder.For.Name == "Options" {
newBuilder = mergeOptions(composableBuilder, newBuilder, "options", nil)
continue
}

if composableBuilder.For.Name == "FieldConfig" {
newBuilder = mergeOptions(composableBuilder, newBuilder, "fieldConfig.defaults.custom", nil)
continue
}

panic("unexpected composable type " + composableBuilder.For.Name)
}

return newBuilder
}

func ComposeDashboardPanel(selector Selector, sourceBuilderName string) RewriteRule {
return RewriteRule{
Selector: selector,
Action: ComposeDashboardPanelAction(sourceBuilderName),
func ComposeDashboardPanel(selector Selector, panelBuilderName string) RewriteRule {
return func(builders ast.Builders) (ast.Builders, error) {
panelBuilderPkg, panelBuilderNameWithoutPkg, found := strings.Cut(panelBuilderName, ".")
if !found {
return nil, fmt.Errorf("panelBuilderName '%s' is incorrect: no package found", panelBuilderPkg)
}

panelBuilder, found := builders.LocateByObject(panelBuilderPkg, panelBuilderNameWithoutPkg)
if !found {
return nil, fmt.Errorf("panel builder '%s' not found", panelBuilderName)
}

// - add to newBuilders all the builders that are not composable (ie: don't comply to the selector)
// - build a map of composable builders, indexed by panel type
// - aggregate the composable builders into a new, composed panel builder
// - add the new composed panel builders to newBuilders

newBuilders := make([]ast.Builder, 0, len(builders))
composableBuilders := make(map[string]ast.Builders)

for _, builder := range builders {
// the builder is for a composable type
if selector(builder) {
panelType := builder.Schema.Metadata.Identifier
composableBuilders[panelType] = append(composableBuilders[panelType], builder)
continue
}

newBuilders = append(newBuilders, builder)
}

for panelType, buildersForType := range composableBuilders {
composedBuilder := composePanelType(panelType, panelBuilder, buildersForType)

newBuilders = append(newBuilders, composedBuilder)
}

return newBuilders, nil
}
}
11 changes: 9 additions & 2 deletions internal/veneers/builder/selectors.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package builder

import (
"strings"

"github.com/grafana/cog/internal/ast"
)

type Selector func(builder ast.Builder) bool

func ByName(objectName string) Selector {
func ByObjectName(objectName string) Selector {
return func(builder ast.Builder) bool {
return builder.For.Name == objectName
objectPkg, objectNameWithoutPkg, found := strings.Cut(objectName, ".")
if !found {
return builder.For.Name == objectName
}

return builder.For.SelfRef.ReferredPkg == objectPkg && builder.For.SelfRef.ReferredType == objectNameWithoutPkg
}
}

Expand Down
Loading

0 comments on commit 9e3d7bf

Please sign in to comment.