3
0

236 lines
4.8 KiB
Go

package codegen
import (
"encoding/json"
"fmt"
"os"
"path"
"strings"
"text/template"
. "github.com/cortezaproject/corteza/server/pkg/y7s"
"gopkg.in/yaml.v3"
)
type (
// definitions are in one file
aFuncDefs struct {
Package string
Name string
Source string
Prefix string
outputDir string
// List of imports
// Used only by generated file and not pre-generated-user-file
Imports []string
Functions aFunctionSet
}
aFunctionSet []*aFuncDef
aFuncDef struct {
Name string
Kind string
Labels map[string]string
Meta *aFuncMetaDef
Params aFuncParamSet
Results aFuncResultSet
}
aFuncParamSet []*aFuncParamDef
aFuncResultSet []*aFuncResultDef
aFuncParamDef struct {
Name string
Required bool
IsArray bool `yaml:"isArray"`
Types []*aFuncParamTypeVarDef
Meta *aFuncParamMetaDef
}
aFuncParamTypeVarDef struct {
WorkflowType string `yaml:"wf"`
GoType string `yaml:"go"`
Suffix string
}
aFuncResultDef struct {
Name string
IsArray bool `yaml:"isArray"`
WorkflowType string `yaml:"wf"`
GoType string `yaml:"go"`
Meta *aFuncParamMetaDef
}
aFuncMetaDef struct {
Short string
Description string
Visual map[string]interface{}
}
aFuncParamMetaDef struct {
Label string
Description string
Visual map[string]interface{}
}
)
func procAutomationFunctions(mm ...string) (dd []*aFuncDefs, err error) {
for _, m := range mm {
f, err := os.Open(m)
if err != nil {
return nil, fmt.Errorf("%s read failed: %w", m, err)
}
defer f.Close()
var (
d = &aFuncDefs{
Package: "automation",
Source: m,
Name: path.Base(m),
outputDir: path.Dir(m),
}
)
d.Name = d.Name[:len(d.Name)-13]
if err := yaml.NewDecoder(f).Decode(d); err != nil {
return nil, fmt.Errorf("could not decode %s: %w", m, err)
}
dd = append(dd, d)
}
return
}
func (set *aFunctionSet) UnmarshalYAML(n *yaml.Node) error {
return Each(n, func(k *yaml.Node, v *yaml.Node) (err error) {
def := &aFuncDef{Name: k.Value}
if err = v.Decode(&def); err != nil {
return err
}
if def.Kind == "" {
def.Kind = "function"
}
*set = append(*set, def)
return nil
})
}
func (set *aFuncParamSet) UnmarshalYAML(n *yaml.Node) error {
return Each(n, func(k *yaml.Node, v *yaml.Node) (err error) {
def := aFuncParamDef{}
if k != nil {
def.Name = k.Value
}
*set = append(*set, &def)
return v.Decode(&def)
})
}
func (set *aFuncResultSet) UnmarshalYAML(n *yaml.Node) error {
return Each(n, func(k *yaml.Node, v *yaml.Node) (err error) {
def := aFuncResultDef{}
if k != nil {
def.Name = k.Value
}
*set = append(*set, &def)
return v.Decode(&def)
})
}
func expandAutomationFunctionTypes(ff []*aFuncDefs, tt []*exprTypesDef) {
// index of all known types
ti := make(map[string]*exprTypeDef)
for _, t := range tt {
for typ, d := range t.Types {
ti[typ] = d
}
}
for _, f := range ff {
for _, fn := range f.Functions {
for _, p := range fn.Params {
for _, t := range p.Types {
if ti[t.WorkflowType] == nil {
fmt.Printf("%s/%s(): unknown type %q used for param %q\n", f.Prefix, fn.Name, t.WorkflowType, p.Name)
continue
}
if t.GoType == "" {
t.GoType = ti[t.WorkflowType].As
if "[]TypedValue" == t.GoType {
t.GoType = "[]expr.TypedValue"
}
}
if t.Suffix == "" && len(p.Types) > 1 {
t.Suffix = t.WorkflowType
}
}
}
for _, r := range fn.Results {
if ti[r.WorkflowType] == nil {
fmt.Printf("%s/%s(): unknown type %q used for result %q\n", f.Prefix, fn.Name, r.WorkflowType, r.Name)
continue
}
if r.GoType == "" {
r.GoType = ti[r.WorkflowType].As
if "[]TypedValue" == r.GoType {
r.GoType = "[]expr.TypedValue"
}
}
}
}
}
}
func genAutomationFunctions(tpl *template.Template, dd ...*aFuncDefs) (err error) {
var (
// Will only be generated if file does not exist previously
tplAFuncGen = tpl.Lookup("afunc.gen.go.tpl")
dst string
)
for _, d := range dd {
// Generic code, actions for every resource goes to a separated file
dst = path.Join(d.outputDir, path.Base(d.Source)[:strings.LastIndex(path.Base(d.Source), ".")]+".gen.go")
json.NewEncoder(os.Stdout).SetIndent("", " ")
err = goTemplate(dst, tplAFuncGen, d)
if err != nil {
return
}
}
return nil
}
// genAutomationFunctionDocs look for afunc.gen.adoc.tpl and generates afunc.gen.adoc from it
func genAutomationFunctionDocs(tpl *template.Template, docsPath string, dd ...*aFuncDefs) (err error) {
var (
typeGenAdoc = tpl.Lookup("afunc.gen.adoc.tpl")
dst string
)
dst = path.Join(docsPath, "afunc.gen.adoc")
return plainTemplate(dst, typeGenAdoc, map[string]interface{}{
"Definitions": dd,
})
}