github.com/snyk/vervet/v4@v4.27.2/internal/generator/functions.go (about)

     1  package generator
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     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.AdditionalPropertiesAllowed != nil &&
    64  				*s.AdditionalPropertiesAllowed
    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 := ioutil.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  }