github.com/dop251/goja@v0.0.0-20240220182346-e401ed450204/goja/main.go (about)

     1  package main
     2  
     3  import (
     4  	crand "crypto/rand"
     5  	"encoding/binary"
     6  	"flag"
     7  	"fmt"
     8  	"io"
     9  	"log"
    10  	"math/rand"
    11  	"os"
    12  	"runtime/debug"
    13  	"runtime/pprof"
    14  	"time"
    15  
    16  	"github.com/dop251/goja"
    17  	"github.com/dop251/goja_nodejs/console"
    18  	"github.com/dop251/goja_nodejs/require"
    19  )
    20  
    21  var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
    22  var timelimit = flag.Int("timelimit", 0, "max time to run (in seconds)")
    23  
    24  func readSource(filename string) ([]byte, error) {
    25  	if filename == "" || filename == "-" {
    26  		return io.ReadAll(os.Stdin)
    27  	}
    28  	return os.ReadFile(filename)
    29  }
    30  
    31  func load(vm *goja.Runtime, call goja.FunctionCall) goja.Value {
    32  	p := call.Argument(0).String()
    33  	b, err := readSource(p)
    34  	if err != nil {
    35  		panic(vm.ToValue(fmt.Sprintf("Could not read %s: %v", p, err)))
    36  	}
    37  	v, err := vm.RunScript(p, string(b))
    38  	if err != nil {
    39  		panic(err)
    40  	}
    41  	return v
    42  }
    43  
    44  func newRandSource() goja.RandSource {
    45  	var seed int64
    46  	if err := binary.Read(crand.Reader, binary.LittleEndian, &seed); err != nil {
    47  		panic(fmt.Errorf("Could not read random bytes: %v", err))
    48  	}
    49  	return rand.New(rand.NewSource(seed)).Float64
    50  }
    51  
    52  func run() error {
    53  	filename := flag.Arg(0)
    54  	src, err := readSource(filename)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	if filename == "" || filename == "-" {
    60  		filename = "<stdin>"
    61  	}
    62  
    63  	vm := goja.New()
    64  	vm.SetRandSource(newRandSource())
    65  
    66  	new(require.Registry).Enable(vm)
    67  	console.Enable(vm)
    68  
    69  	vm.Set("load", func(call goja.FunctionCall) goja.Value {
    70  		return load(vm, call)
    71  	})
    72  
    73  	vm.Set("readFile", func(name string) (string, error) {
    74  		b, err := os.ReadFile(name)
    75  		if err != nil {
    76  			return "", err
    77  		}
    78  		return string(b), nil
    79  	})
    80  
    81  	if *timelimit > 0 {
    82  		time.AfterFunc(time.Duration(*timelimit)*time.Second, func() {
    83  			vm.Interrupt("timeout")
    84  		})
    85  	}
    86  
    87  	//log.Println("Compiling...")
    88  	prg, err := goja.Compile(filename, string(src), false)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	//log.Println("Running...")
    93  	_, err = vm.RunProgram(prg)
    94  	//log.Println("Finished.")
    95  	return err
    96  }
    97  
    98  func main() {
    99  	defer func() {
   100  		if x := recover(); x != nil {
   101  			debug.Stack()
   102  			panic(x)
   103  		}
   104  	}()
   105  	flag.Parse()
   106  	if *cpuprofile != "" {
   107  		f, err := os.Create(*cpuprofile)
   108  		if err != nil {
   109  			log.Fatal(err)
   110  		}
   111  		pprof.StartCPUProfile(f)
   112  		defer pprof.StopCPUProfile()
   113  	}
   114  
   115  	if err := run(); err != nil {
   116  		//fmt.Printf("err type: %T\n", err)
   117  		switch err := err.(type) {
   118  		case *goja.Exception:
   119  			fmt.Println(err.String())
   120  		case *goja.InterruptedError:
   121  			fmt.Println(err.String())
   122  		default:
   123  			fmt.Println(err)
   124  		}
   125  		os.Exit(64)
   126  	}
   127  }