github.com/kurthockenbury/dnscontrol@v0.2.8/pkg/js/js.go (about)

     1  package js
     2  
     3  import (
     4  	"encoding/json"
     5  	"io/ioutil"
     6  
     7  	"github.com/StackExchange/dnscontrol/models"
     8  	"github.com/StackExchange/dnscontrol/pkg/printer"
     9  	"github.com/StackExchange/dnscontrol/pkg/transform"
    10  
    11  	"github.com/robertkrimen/otto"
    12  	// load underscore js into vm by default
    13  
    14  	_ "github.com/robertkrimen/otto/underscore" // required by otto
    15  )
    16  
    17  // ExecuteJavascript accepts a javascript string and runs it, returning the resulting dnsConfig.
    18  func ExecuteJavascript(script string, devMode bool) (*models.DNSConfig, error) {
    19  	vm := otto.New()
    20  
    21  	vm.Set("require", require)
    22  	vm.Set("REV", reverse)
    23  
    24  	helperJs := GetHelpers(devMode)
    25  	// run helper script to prime vm and initialize variables
    26  	if _, err := vm.Run(helperJs); err != nil {
    27  		return nil, err
    28  	}
    29  
    30  	// run user script
    31  	if _, err := vm.Run(script); err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	// export conf as string and unmarshal
    36  	value, err := vm.Run(`JSON.stringify(conf)`)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	str, err := value.ToString()
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	conf := &models.DNSConfig{}
    45  	if err = json.Unmarshal([]byte(str), conf); err != nil {
    46  		return nil, err
    47  	}
    48  	return conf, nil
    49  }
    50  
    51  // GetHelpers returns the filename of helpers.js, or the esc'ed version.
    52  func GetHelpers(devMode bool) string {
    53  	return _escFSMustString(devMode, "/helpers.js")
    54  }
    55  
    56  func require(call otto.FunctionCall) otto.Value {
    57  	if len(call.ArgumentList) != 1 {
    58  		throw(call.Otto, "require takes exactly one argument")
    59  	}
    60  	file := call.Argument(0).String()
    61  	printer.Debugf("requiring: %s\n", file)
    62  	data, err := ioutil.ReadFile(file)
    63  	if err != nil {
    64  		throw(call.Otto, err.Error())
    65  	}
    66  	_, err = call.Otto.Run(string(data))
    67  	if err != nil {
    68  		throw(call.Otto, err.Error())
    69  	}
    70  	return otto.TrueValue()
    71  }
    72  
    73  func throw(vm *otto.Otto, str string) {
    74  	panic(vm.MakeCustomError("Error", str))
    75  }
    76  
    77  func reverse(call otto.FunctionCall) otto.Value {
    78  	if len(call.ArgumentList) != 1 {
    79  		throw(call.Otto, "REV takes exactly one argument")
    80  	}
    81  	dom := call.Argument(0).String()
    82  	rev, err := transform.ReverseDomainName(dom)
    83  	if err != nil {
    84  		throw(call.Otto, err.Error())
    85  	}
    86  	v, _ := otto.ToValue(rev)
    87  	return v
    88  }