github.com/Comcast/plax@v0.8.32/subst/js.go (about) 1 /* 2 * Copyright 2021 Comcast Cable Communications Management, LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * SPDX-License-Identifier: Apache-2.0 17 */ 18 19 package subst 20 21 import ( 22 "fmt" 23 "strings" 24 "time" 25 26 "github.com/Comcast/sheens/match" 27 "github.com/dop251/goja" 28 ) 29 30 // JSExec executes the javascript source with the given context and environment mappings 31 func JSExec(ctx *Ctx, src string, env map[string]interface{}) (interface{}, error) { 32 x, err := jsExec(ctx, src, env) 33 if err != nil { 34 return nil, fmt.Errorf("JavaScript problem: %w", err) 35 } 36 return x, nil 37 } 38 39 func jsExec(ctx *Ctx, src string, env map[string]interface{}) (interface{}, error) { 40 41 js := goja.New() 42 43 js.Set("print", func(args ...interface{}) { 44 acc := make([]string, 0, len(args)) 45 for _, x := range args { 46 acc = append(acc, JSON(x)) 47 } 48 fmt.Printf("%s\n", strings.Join(acc, ",")) 49 }) 50 51 js.Set("now", func() interface{} { 52 return time.Now().UTC().Format(time.RFC3339Nano) 53 }) 54 55 js.Set("match", func(pat, msg interface{}, bs map[string]interface{}) []map[string]interface{} { 56 if bs == nil { 57 bs = match.NewBindings() 58 } 59 bss, err := match.Match(pat, msg, bs) 60 if err != nil { 61 panic(js.ToValue(err.Error())) 62 } 63 // Strip type (match.Bindings) to enable standard 64 // Javascript access to the maps. 65 acc := make([]map[string]interface{}, len(bss)) 66 for i, bs := range bss { 67 acc[i] = map[string]interface{}(bs) 68 } 69 return acc 70 }) 71 72 js.Set("tsMs", func(s string) int64 { 73 t, err := time.Parse(time.RFC3339Nano, s) 74 if err != nil { 75 return 0 76 } 77 return t.UnixNano() / 1000 / 1000 78 }) 79 80 for k, v := range env { 81 js.Set(k, v) 82 } 83 84 v, err := js.RunString(src) 85 if err != nil { 86 return nil, err 87 } 88 89 return v.Export(), nil 90 }