github.com/snyk/vervet/v6@v6.2.4/internal/generator/functions.go (about) 1 package generator 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "log" 8 "path/filepath" 9 "strings" 10 "text/template" 11 12 "github.com/dop251/goja" 13 "github.com/getkin/kin-openapi/openapi3" 14 ) 15 16 var ( 17 builtinFuncs = template.FuncMap{ 18 "map": func(keyValues ...interface{}) (map[string]interface{}, error) { 19 if len(keyValues)%2 != 0 { 20 return nil, fmt.Errorf("invalid number of arguments to map") 21 } 22 m := make(map[string]interface{}, len(keyValues)/2) 23 for i := 0; i < len(keyValues); i += 2 { 24 k, ok := keyValues[i].(string) 25 if !ok { 26 return nil, fmt.Errorf("map keys must be strings") 27 } 28 m[k] = keyValues[i+1] 29 } 30 return m, nil 31 }, 32 "indent": func(indent int, s string) string { 33 return strings.ReplaceAll(s, "\n", "\n"+strings.Repeat(" ", indent)) 34 }, 35 "uncapitalize": func(s string) string { 36 if len(s) > 1 { 37 return strings.ToLower(s[0:1]) + s[1:] 38 } 39 return s 40 }, 41 "capitalize": func(s string) string { 42 if len(s) > 1 { 43 return strings.ToUpper(s[0:1]) + s[1:] 44 } 45 return s 46 }, 47 "replaceall": strings.ReplaceAll, 48 "pathOperations": MapPathOperations, 49 "resourceOperations": MapResourceOperations, 50 "isOneOf": func(s *openapi3.Schema) bool { 51 return s != nil && len(s.OneOf) > 0 52 }, 53 "isAnyOf": func(s *openapi3.Schema) bool { 54 return s != nil && len(s.AnyOf) > 0 55 }, 56 "isAllOf": func(s *openapi3.Schema) bool { 57 return s != nil && len(s.AllOf) > 0 58 }, 59 "isAssociativeArray": func(s *openapi3.Schema) bool { 60 return s != nil && 61 s.Type == "object" && 62 len(s.Properties) == 0 && 63 s.AdditionalProperties.Has != nil && 64 *s.AdditionalProperties.Has 65 }, 66 "basename": filepath.Base, 67 } 68 ) 69 70 func withIncludeFunc(t *template.Template) *template.Template { 71 return t.Funcs(template.FuncMap{ 72 "include": func(name string, data interface{}) (string, error) { 73 buf := bytes.NewBuffer(nil) 74 if err := t.ExecuteTemplate(buf, name, data); err != nil { 75 return "", err 76 } 77 return buf.String(), nil 78 }, 79 }) 80 } 81 82 var jsConsole = map[string]func(goja.FunctionCall) goja.Value{ 83 "log": func(call goja.FunctionCall) goja.Value { 84 args := make([]interface{}, len(call.Arguments)) 85 for i := range call.Arguments { 86 args[i] = call.Arguments[i].Export() 87 } 88 log.Println(args...) 89 return goja.Null() 90 }, 91 } 92 93 func (g *Generator) loadFunctions(filename string) error { 94 functionFile, err := g.fs.Open(filename) 95 if err != nil { 96 return err 97 } 98 src, err := io.ReadAll(functionFile) 99 if err != nil { 100 return err 101 } 102 vm := goja.New() 103 _, err = vm.RunScript(filename, string(src)) 104 if err != nil { 105 return err 106 } 107 module := vm.GlobalObject() 108 if err != nil { 109 return err 110 } 111 err = module.Set("console", jsConsole) 112 if err != nil { 113 return err 114 } 115 for _, key := range module.Keys() { 116 fn, ok := goja.AssertFunction(module.Get(key)) 117 if !ok { 118 // not a callable function 119 continue 120 } 121 g.functions[key] = func(args ...interface{}) (interface{}, error) { 122 jsArgs := make([]goja.Value, len(args)) 123 for i := range args { 124 jsArgs[i] = vm.ToValue(args[i]) 125 } 126 return fn(goja.Undefined(), jsArgs...) 127 } 128 } 129 return nil 130 }