lib

package
v0.0.0-...-6c5b1ce Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2022 License: BSD-2-Clause Imports: 88 Imported by: 0

Documentation

Index

Constants

View Source
const MAX_PARSE_FORM_MEMORY = 10000

Variables

View Source
var Assert = []dune.NativeFunction{
	{
		Name:      "assert.contains",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			a := args[0].String()
			b := args[1].String()

			if !strings.Contains(b, a) {
				return dune.NullValue, fmt.Errorf("'%s' not contained in '%s'", a, b)
			}
			return dune.NullValue, nil
		},
	},

	{
		Name:      "assert.equal",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var msg string
			ln := len(args)
			switch ln {
			case 2:
			case 3:
				a3 := args[2]
				if a3.Type != dune.String {
					return dune.NullValue, fmt.Errorf("expected error message to be a string, got %v", a3.TypeName())
				}
				msg = a3.String()
			default:
				return dune.NullValue, fmt.Errorf("expected 2 or 3 args, got %d", ln)

			}

			a := args[0]
			b := args[1]

			if !areEqual(a, b) {
				if msg != "" {
					return dune.NullValue, errors.New(msg)
				}
				return dune.NullValue, fmt.Errorf("values are different: %v, %v", serializeOrErr(a), serializeOrErr(b))
			}
			return dune.NullValue, nil
		},
	},
	{
		Name:      "assert.isTrue",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]

			switch a.Type {
			case dune.Bool:
				if a.ToBool() {
					return dune.TrueValue, nil
				}
			}

			return dune.NullValue, fmt.Errorf("expected true, got %v", a)
		},
	},
	{
		Name:      "assert.isFalse",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]

			switch a.Type {
			case dune.Bool:
				if !a.ToBool() {
					return dune.TrueValue, nil
				}
			}

			return dune.NullValue, fmt.Errorf("expected false, got %v", a)
		},
	},
	{
		Name:      "assert.isNull",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]

			switch a.Type {
			case dune.Null, dune.Undefined:
			default:
				return dune.NullValue, fmt.Errorf("expected null, got %v", a)
			}

			return dune.NullValue, nil
		},
	},
	{
		Name:      "assert.isNotNull",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]

			switch a.Type {
			case dune.Null, dune.Undefined:
				return dune.NullValue, fmt.Errorf("%v is null", a)
			default:
			}

			return dune.NullValue, nil
		},
	},
	{
		Name:      "assert.exception",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			if a.Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 1 to be a string, got %s", a.TypeName())
			}

			expected := a.String()

			v := args[1]
			err := runFuncOrClosure(vm, v)
			if err == nil {
				return dune.NullValue, fmt.Errorf("expected exception: %s", expected)
			}

			if expected != "" && !strings.Contains(err.Error(), expected) {
				return dune.NullValue, fmt.Errorf("invalid exception, does not contain '%s': %s", expected, err.Error())
			}

			vm.Error = nil

			return dune.NullValue, nil
		},
	},
	{
		Name:      "assert.int",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[1].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()

			var v int64
			var err error

			switch a.Type {
			case dune.Int:
				v = a.ToInt()
			case dune.String:
				v, err = strconv.ParseInt(a.String(), 0, 64)
				if err != nil {
					return dune.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not int", a.TypeName()))
				}
			default:
				return dune.NullValue, fmt.Errorf(msg)
			}

			return dune.NewInt64(v), nil
		},
	},
	{
		Name:      "assert.float",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[1].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()

			var v int64
			var err error

			switch a.Type {
			case dune.Int:
				v = a.ToInt()
			case dune.String:
				v, err = strconv.ParseInt(a.String(), 0, 64)
				if err != nil {
					return dune.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not float", a.TypeName()))
				}
			default:
				return dune.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not float", a.TypeName()))
			}

			return dune.NewInt64(v), nil
		},
	},
	{
		Name:      "assert.string",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[1].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()

			var v string

			switch a.Type {
			case dune.Int, dune.Float, dune.Bool, dune.String:
				v = a.String()
			default:
				return dune.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not a string", a.TypeName()))
			}

			return dune.NewString(v), nil
		},
	},
	{
		Name:      "assert.bool",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[1].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()
			var v dune.Value

			switch a.Type {

			case dune.Bool:
				v = a

			case dune.Int:
				switch a.ToInt() {
				case 0:
					v = dune.FalseValue
				case 1:
					v = dune.TrueValue
				default:
					return dune.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not bool", a.TypeName()))
				}

			case dune.String:
				s := a.String()
				s = strings.Trim(s, " ")
				switch s {
				case "true", "1":
					v = dune.TrueValue
				case "false", "0":
					v = dune.FalseValue
				default:
					return dune.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not bool", a.TypeName()))
				}

			default:
				return dune.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not bool", a.TypeName()))

			}

			return v, nil
		},
	},
	{
		Name:      "assert.object",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[1].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()

			switch a.Type {
			case dune.Map:
			default:
				return dune.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not an object", a.TypeName()))
			}

			return a, nil
		},
	},
}
View Source
var Async = []dune.NativeFunction{
	{
		Name:        "go",
		Arguments:   1,
		Permissions: []string{"async"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return launchGoroutine(args, vm, nil)
		},
	},
}
View Source
var Base64 = []dune.NativeFunction{
	{
		Name:      "base64.encode",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			switch a.Type {
			case dune.Null, dune.Undefined:
				return dune.NullValue, nil
			case dune.Bytes, dune.String:
				encoder := base64.RawStdEncoding
				encoded := encoder.EncodeToString(a.ToBytes())
				return dune.NewString(encoded), nil
			default:
				return dune.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
	{
		Name:      "base64.encodeWithPadding",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			switch a.Type {
			case dune.Null, dune.Undefined:
				return dune.NullValue, nil
			case dune.Bytes, dune.String:
				encoder := base64.StdEncoding.WithPadding(base64.StdPadding)
				encoded := encoder.EncodeToString(a.ToBytes())
				return dune.NewString(encoded), nil
			default:
				return dune.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
	{
		Name:      "base64.decode",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			switch a.Type {
			case dune.Null, dune.Undefined:
				return dune.NullValue, nil
			case dune.String:
				encoder := base64.RawStdEncoding
				encoded, err := encoder.DecodeString(a.String())
				if err != nil {
					return dune.NullValue, err
				}
				return dune.NewBytes(encoded), nil
			default:
				return dune.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
	{
		Name:      "base64.decodeWithPadding",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			switch a.Type {
			case dune.Null, dune.Undefined:
				return dune.NullValue, nil
			case dune.String:
				encoder := base64.StdEncoding.WithPadding(base64.StdPadding)
				encoded, err := encoder.DecodeString(a.String())
				if err != nil {
					return dune.NullValue, err
				}
				return dune.NewBytes(encoded), nil
			default:
				return dune.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
}
View Source
var Binary = []dune.NativeFunction{
	{
		Name:      "binary.putInt16LittleEndian",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Int); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.LittleEndian.PutUint16(b, uint16(i))
			return dune.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt32LittleEndian",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Int); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.LittleEndian.PutUint32(b, uint32(i))
			return dune.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt64LittleEndian",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Int); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.LittleEndian.PutUint64(b, uint64(i))
			return dune.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt16BigEndian",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Int); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.BigEndian.PutUint16(b, uint16(i))
			return dune.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt32BigEndian",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Int); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.BigEndian.PutUint32(b, uint32(i))
			return dune.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt64BigEndian",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Int); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.BigEndian.PutUint64(b, uint64(i))
			return dune.NullValue, nil
		},
	},
	{
		Name:      "binary.int16LittleEndian",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.LittleEndian.Uint16(b)
			return dune.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int32LittleEndian",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.LittleEndian.Uint32(b)
			return dune.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int64LittleEndian",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.LittleEndian.Uint64(b)
			return dune.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int16BigEndian",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.BigEndian.Uint16(b)
			return dune.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int32BigEndian",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.BigEndian.Uint32(b)
			return dune.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int64BigEndian",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.BigEndian.Uint64(b)
			return dune.NewInt64(int64(i)), nil
		},
	},
}
View Source
var Bufio = []dune.NativeFunction{
	{
		Name:      "bufio.newScanner",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			r := args[0].ToObject()

			reader, ok := r.(io.Reader)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a io.Reader, got %v", args[0])
			}

			s := bufio.NewScanner(reader)

			return dune.NewObject(&scanner{s}), nil
		},
	},
	{
		Name:      "bufio.newReader",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			r := args[0].ToObject()

			reader, ok := r.(io.Reader)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a io.Reader, got %v", args[0])
			}

			s := bufio.NewReader(reader)

			return dune.NewObject(&bufioReader{s}), nil
		},
	},
	{
		Name:      "bufio.newWriter",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			r := args[0].ToObject()

			w, ok := r.(io.Writer)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a io.Writer, got %v", args[0])
			}

			s := bufio.NewWriter(w)

			return dune.NewObject(&bufioWriter{s}), nil
		},
	},
}
View Source
var Bytecode = []dune.NativeFunction{
	{
		Name:      "bytecode.compile",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.Object); err != nil {
				return dune.NullValue, err
			}

			path := args[0].String()

			var fs filesystem.FS

			l := len(args)

			if l > 1 {
				filesystem, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return dune.NullValue, fmt.Errorf("expected a filesystem, got %v", args[1])
				}
				fs = filesystem.FS
			} else {
				fs = vm.FileSystem
			}

			p, err := dune.Compile(fs, path)
			if err != nil {
				return dune.NullValue, fmt.Errorf("compiling %s: %w", path, err)
			}

			if err := ValidatePermissions(p, vm); err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.compileStr",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			code := args[0].String()

			p, err := dune.CompileStr(code)
			if err != nil {
				return dune.NullValue, errors.New(err.Error())
			}

			if err := ValidatePermissions(p, vm); err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.hash",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.Bool, dune.Bool, dune.Object); err != nil {
				return dune.NullValue, err
			}

			path := args[0].String()

			var fs filesystem.FS

			l := len(args)

			if l > 1 {
				filesystem, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return dune.NullValue, fmt.Errorf("expected a filesystem, got %v", args[1])
				}
				fs = filesystem.FS
			} else {
				fs = vm.FileSystem
			}

			hash, err := parser.Hash(fs, path)
			if err != nil {
				return dune.NullValue, fmt.Errorf("compiling %s: %w", path, err)
			}

			s := base64.StdEncoding.EncodeToString(hash)
			return dune.NewString(s), nil
		},
	},
	{
		Name:      "bytecode.parseStr",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			code := args[0].String()

			p, err := dune.ParseStr(code)
			if err != nil {
				return dune.NullValue, errors.New(err.Error())
			}

			return dune.NewObject(&astProgram{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.loadProgram",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			p, err := binary.Load(args[0].ToBytes())
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.load",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.Object); err != nil {
				return dune.NullValue, err
			}

			l := len(args)
			path := args[0].String()
			var fs filesystem.FS

			if l > 1 {
				filesystem, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return dune.NullValue, fmt.Errorf("expected a filesystem, got %v", args[1])
				}
				fs = filesystem.FS
			} else {
				fs = vm.FileSystem
			}

			f, err := fs.Open(path)
			if err != nil {
				return dune.NullValue, err
			}
			defer f.Close()

			p, err := binary.Read(f)
			if err != nil {
				return dune.NullValue, err
			}

			p.Name = strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))

			return dune.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.readProgram",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			r, ok := args[0].ToObjectOrNil().(io.Reader)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected parameter 1 to be io.Reader, got %T", args[0].ToObjectOrNil())
			}

			p, err := binary.Read(r)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.writeProgram",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object, dune.Object); err != nil {
				return dune.NullValue, err
			}

			w, ok := args[0].ToObjectOrNil().(io.Writer)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected parameter 1 to be io.Reader, got %T", args[0].ToObjectOrNil())
			}

			p, ok := args[1].ToObjectOrNil().(*program)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected parameter 2 to be a program, got %T", args[0].ToObjectOrNil())
			}

			if err := binary.Write(w, p.prog); err != nil {
				return dune.NullValue, err
			}

			return dune.NullValue, nil
		},
	},
}
View Source
var Bytes = []dune.NativeFunction{
	{
		Name:      "bytes.newReader",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			r := args[0].ToBytes()

			s := bytes.NewReader(r)

			reader := NewReader(s)

			return dune.NewObject(reader), nil
		},
	},
	{
		Name:      "Bytes.prototype.copyAt",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.Int {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be int, got %s", args[0].TypeName())
			}

			switch args[1].Type {
			case dune.Bytes, dune.Array, dune.String:
			default:
				return dune.NullValue, fmt.Errorf("expected arg 2 to be bytes, got %s", args[1].TypeName())
			}

			a := this.ToBytes()
			start := int(args[0].ToInt())
			b := args[1].ToBytes()

			lenB := len(b)

			if lenB+start > len(a) {
				return dune.NullValue, fmt.Errorf("the array has not enough capacity")
			}

			for i := 0; i < lenB; i++ {
				a[i+start] = b[i]
			}

			return dune.NullValue, nil
		},
	},
	{
		Name:      "Bytes.prototype.append",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if this.Type != dune.Bytes {
				return dune.NullValue, fmt.Errorf("expected byte array, got %s", this.TypeName())
			}
			a := this.ToBytes()

			b := args[0]
			if b.Type != dune.Bytes {
				return dune.NullValue, fmt.Errorf("expected array, got %s", b.TypeName())
			}

			c := append(a, b.ToBytes()...)

			return dune.NewBytes(c), nil
		},
	},
	{
		Name:      "Bytes.prototype.indexOf",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if this.Type != dune.Bytes {
				return dune.NullValue, fmt.Errorf("expected byte array, got %s", this.TypeName())
			}
			a := this.ToBytes()
			v := byte(args[0].ToInt())

			for i, j := range a {
				if j == v {
					return dune.NewInt(i), nil
				}
			}

			return dune.NewInt(-1), nil
		},
	},
	{
		Name: "Bytes.prototype.reverse",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if this.Type != dune.Bytes {
				return dune.NullValue, fmt.Errorf("expected byte array, got %s", this.TypeName())
			}
			a := this.ToBytes()
			l := len(a) - 1

			for i, k := 0, l/2; i <= k; i++ {
				a[i], a[l-i] = a[l-i], a[i]
			}

			return dune.NullValue, nil
		},
	},
	{
		Name:      "Bytes.prototype.slice",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if this.Type != dune.Bytes {
				return dune.NullValue, fmt.Errorf("expected string array, got %s", this.TypeName())
			}
			a := this.ToBytes()
			l := len(a)

			switch len(args) {
			case 0:
				a = a[0:]
			case 1:
				a = a[int(args[0].ToInt()):]
			case 2:
				start := int(args[0].ToInt())
				if start < 0 || start > l {
					return dune.NullValue, fmt.Errorf("index out of range")
				}

				end := start + int(args[1].ToInt())
				if end < 0 || end > l {
					return dune.NullValue, fmt.Errorf("index out of range")
				}

				a = a[start:end]
			default:
				return dune.NullValue, fmt.Errorf("expected 0, 1 or 2 params, got %d", len(args))
			}

			return dune.NewBytes(a), nil
		},
	},
	{
		Name:      "Bytes.prototype.range",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if this.Type != dune.Bytes {
				return dune.NullValue, fmt.Errorf("expected array, called on %s", this.TypeName())
			}
			a := this.ToBytes()
			l := len(a)

			switch len(args) {
			case 0:
				a = a[0:]
			case 1:
				a = a[int(args[0].ToInt()):]
			case 2:
				start := int(args[0].ToInt())
				if start < 0 || start > l {
					return dune.NullValue, fmt.Errorf("index out of range")
				}

				end := int(args[1].ToInt())
				if end < 0 || end > l {
					return dune.NullValue, fmt.Errorf("index out of range")
				}

				a = a[start:end]
			default:
				return dune.NullValue, fmt.Errorf("expected 0, 1 or 2 params, got %d", len(args))
			}

			return dune.NewBytes(a), nil
		},
	},
}
View Source
var CSV = []dune.NativeFunction{
	{
		Name:      "csv.newReader",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			r, ok := args[0].ToObject().(io.Reader)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}

			reader := csv.NewReader(r)

			return dune.NewObject(&csvReader{reader}), nil
		},
	},
	{
		Name:      "csv.newWriter",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			w, ok := args[0].ToObject().(io.Writer)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}

			writer := csv.NewWriter(w)

			return dune.NewObject(&csvWriter{writer}), nil
		},
	},
}
View Source
var Caching = []dune.NativeFunction{
	{
		Name:      "caching.newCache",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)

			var d time.Duration

			switch l {
			case 0:
				d = 1 * time.Minute
			case 1:
				var a = args[0]
				switch a.Type {
				case dune.Int:
					dd, err := ToDuration(a)
					if err != nil {
						return dune.NullValue, err
					}
					d = dd
				case dune.Object:
					dur, ok := a.ToObject().(Duration)
					if !ok {
						return dune.NullValue, fmt.Errorf("expected duration, got %s", a.TypeName())
					}
					d = time.Duration(dur)
				}
			default:
				return dune.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", l)
			}
			return dune.NewObject(newCacheObj(d)), nil
		},
	},
}
View Source
var Console = []dune.NativeFunction{
	{
		Name:      "console.debug",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return consoleLog(true, args, vm)
		},
	},
	{
		Name:      "console.enableDebug",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			debugEnabled = true
			return dune.NullValue, nil
		},
	},
	{
		Name:      "console.disableDebug",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			debugEnabled = false
			return dune.NullValue, nil
		},
	},
	{
		Name:      "console.log",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return consoleLog(false, args, vm)
		},
	},
	{
		Name:      "console.enableTrace",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			traceEnabled = true
			return dune.NullValue, nil
		},
	},
	{
		Name:      "console.disableTrace",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			traceEnabled = false
			return dune.NullValue, nil
		},
	},
}
View Source
var Convert = []dune.NativeFunction{
	{
		Name:      "convert.toByte",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			var r dune.Value

			switch a.Type {
			case dune.String:
			default:
				return dune.NullValue, fmt.Errorf("can't convert %v to byte", a.Type)
			}

			s := a.String()
			if len(s) != 1 {
				return dune.NullValue, fmt.Errorf("can't convert %v to int", a.Type)
			}

			return r, nil
		},
	},
	{
		Name:      "convert.toRune",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]

			switch a.Type {
			case dune.String:
				s := a.String()
				if len(s) != 1 {
					return dune.NullValue, fmt.Errorf("can't convert %v to rune", s)
				}
				return dune.NewRune(rune(s[0])), nil
			case dune.Int:
				i := a.ToInt()
				if i > 255 {
					return dune.NullValue, fmt.Errorf("can't convert %v to rune", i)
				}
				return dune.NewRune(rune(i)), nil
			default:
				return dune.NullValue, fmt.Errorf("can't convert %v to byte", a.Type)
			}
		},
	},
	{
		Name:      "convert.toInt",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			var r dune.Value

			switch a.Type {
			case dune.Int:
				r = a
			case dune.Float:
				r = dune.NewInt64(a.ToInt())
			case dune.Rune:
				r = dune.NewInt64(a.ToInt())
			case dune.String:
				s := strings.Trim(a.String(), " ")
				i, err := strconv.ParseInt(s, 0, 64)
				if err != nil {
					return dune.NullValue, err
				}
				r = dune.NewInt64(i)
			case dune.Func:
				r = dune.NewInt64(a.ToInt())
			default:
				return dune.NullValue, fmt.Errorf("can't convert %v to int", a.Type)
			}

			return r, nil
		},
	},
	{
		Name:      "convert.toFloat",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			switch a.Type {
			case dune.Int:
				return dune.NewFloat(a.ToFloat()), nil
			case dune.Float:
				return a, nil
			case dune.String:
				s := strings.Trim(a.String(), " ")
				f, err := strconv.ParseFloat(s, 64)
				if err != nil {
					return dune.NullValue, err
				}
				return dune.NewFloat(f), nil
			default:
				return dune.NullValue, fmt.Errorf("can't convert %v to int", a.Type)
			}
		},
	},
	{
		Name:      "convert.toBool",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]

			switch a.Type {
			case dune.Bool:
				return a, nil

			case dune.Int:
				switch a.ToInt() {
				case 0:
					return dune.FalseValue, nil
				case 1:
					return dune.TrueValue, nil
				default:
					return dune.NullValue, fmt.Errorf("can't convert %v to bool", a.Type)
				}

			case dune.String:
				s := a.String()
				s = strings.Trim(s, " ")
				switch s {
				case "true", "1":
					return dune.TrueValue, nil
				case "false", "0":
					return dune.FalseValue, nil
				default:
					return dune.NullValue, fmt.Errorf("can't convert %v to bool", s)
				}

			case dune.Null, dune.Undefined:
				return dune.FalseValue, nil

			default:
				return dune.NullValue, fmt.Errorf("can't convert %v to bool", a.Type)

			}
		},
	},
	{
		Name:      "convert.toString",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			return dune.NewString(a.String()), nil
		},
	},
	{
		Name:      "convert.toBytes",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			var r dune.Value

			switch a.Type {
			case dune.String:
				r = dune.NewBytes(a.ToBytes())
			case dune.Bytes:
				r = a
			default:
				return dune.NullValue, fmt.Errorf("can't convert %v to int", a.Type)
			}

			return r, nil
		},
	},
}
View Source
var Crypt = []dune.NativeFunction{
	{
		Name:      "crypto.signSHA1_RSA_PCKS1",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			key := args[0].ToBytes()
			text := args[1].String()

			h := sha1.New()
			h.Write([]byte(text))
			sum := h.Sum(nil)

			block, _ := pem.Decode(key)
			if block == nil {
				return dune.NullValue, fmt.Errorf("error parsing private key")
			}

			privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
			if err != nil {
				return dune.NullValue, fmt.Errorf("error parsing private key: %w", err)
			}

			sig, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, sum)
			if err != nil {
				return dune.NullValue, fmt.Errorf("error signing: %w", err)
			}

			return dune.NewBytes(sig), nil
		},
	},
	{
		Name:      "crypto.signSHA1",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			s := args[0].String() + getGlobalPassword()
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))
			return dune.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.checkSignSHA1",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			s := args[0].String() + getGlobalPassword()
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))
			ok := hash == args[1].String()

			return dune.NewBool(ok), nil
		},
	},
	{
		Name:        "crypto.signTempSHA1",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {

			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			s := args[0].String() + tempSignKey
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))
			return dune.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.checkTempSignSHA1",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			s := args[0].String() + tempSignKey
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))

			ok := hash == args[1].String()
			return dune.NewBool(ok), nil
		},
	},
	{
		Name:        "crypto.setGlobalPassword",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {

			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			setGlobalPassword(args[0].String())
			return dune.NullValue, nil
		},
	},
	{
		Name:      "crypto.hmacSHA256",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			msg := args[0].ToBytes()
			key := args[1].ToBytes()

			sig := hmac.New(sha256.New, key)
			sig.Write(msg)
			hash := sig.Sum(nil)

			return dune.NewBytes(hash), nil
		},
	},
	{
		Name:      "crypto.hmacSHA512",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			msg := args[0].ToBytes()
			key := args[1].ToBytes()

			sig := hmac.New(sha512.New, key)
			sig.Write(msg)
			hash := sig.Sum(nil)

			return dune.NewBytes(hash), nil
		},
	},
	{
		Name:      "crypto.hashSHA",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			h := sha1.New()
			h.Write([]byte(args[0].String()))
			hash := hex.EncodeToString(h.Sum(nil))
			return dune.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.hashSHA256",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			h := sha256.New()
			h.Write([]byte(args[0].String()))
			hash := hex.EncodeToString(h.Sum(nil))
			return dune.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.hashSHA512",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			h := sha512.New()
			h.Write([]byte(args[0].String()))
			hash := hex.EncodeToString(h.Sum(nil))
			return dune.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.encryptString",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			var pwd string
			switch len(args) {
			case 0:
				return dune.NullValue, fmt.Errorf("expected 1 argument, got 0")
			case 1:
				pwd = getGlobalPassword()
				if pwd == "" {
					return dune.NullValue, fmt.Errorf("no password configured")
				}
			case 2:
				pwd = args[1].String()
			}

			s, err := Encrypts(args[0].String(), pwd)
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewString(s), nil
		},
	},
	{
		Name:      "crypto.decryptString",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			var pwd string
			switch len(args) {
			case 0:
				return dune.NullValue, fmt.Errorf("expected 1 argument, got 0")
			case 1:
				pwd = getGlobalPassword()
				if pwd == "" {
					return dune.NullValue, fmt.Errorf("no password configured")
				}
			case 2:
				pwd = args[1].String()
			}

			s, err := Decrypts(args[0].String(), pwd)
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewString(s), nil
		},
	},
	{
		Name:      "crypto.encrypt",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			var pwd string
			switch len(args) {
			case 0:
				return dune.NullValue, fmt.Errorf("expected 1 argument, got 0")
			case 1:
				pwd = getGlobalPassword()
				if pwd == "" {
					return dune.NullValue, fmt.Errorf("no password configured")
				}

			case 2:
				pwd = args[1].String()
			}

			b, err := Encrypt(args[0].ToBytes(), []byte(pwd))
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.decrypt",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			var pwd string
			switch len(args) {
			case 0:
				return dune.NullValue, fmt.Errorf("expected 1 argument, got 0")
			case 1:
				pwd = getGlobalPassword()
				if pwd == "" {
					return dune.NullValue, fmt.Errorf("no password configured")
				}

			case 2:
				pwd = args[1].String()
			}

			b, err := Decrypt(args[0].ToBytes(), []byte(pwd))
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.encryptTripleDES",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Bytes); err != nil {
				return dune.NullValue, err
			}
			b, err := EncryptTripleDESCBC(args[0].ToBytes(), args[1].ToBytes())
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.decryptTripleDES",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes, dune.Bytes); err != nil {
				return dune.NullValue, err
			}
			b, err := DecryptTripleDESCBC(args[0].ToBytes(), args[1].ToBytes())
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.hashPassword",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			s := HashPassword(args[0].String())
			return dune.NewString(s), nil
		},
	},
	{
		Name:      "crypto.compareHashAndPassword",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			ok := CheckHashPasword(args[0].String(), args[1].String())
			return dune.NewBool(ok), nil
		},
	},
	{
		Name:      "crypto.rand",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}
			ln := int(args[0].ToInt())
			v, err := rand.Int(rand.Reader, big.NewInt(int64(ln)))
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewInt64(v.Int64()), nil
		},
	},
	{
		Name:      "crypto.random",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}

			b := Random(int(args[0].ToInt()))
			return dune.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.randomAlphanumeric",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}
			ln := int(args[0].ToInt())
			if ln < 1 {
				return dune.NullValue, fmt.Errorf("invalid len: %d", ln)
			}
			s := RandomAlphanumeric(ln)
			return dune.NewString(s), nil
		},
	},
}
View Source
var Encoding = []dune.NativeFunction{
	{
		Name:      "encoding.newDecoderCP850",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d := charmap.CodePage850.NewDecoder()
			return dune.NewObject(&decoder{d}), nil
		},
	},
	{
		Name:      "encoding.newEncoderCP850",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d := charmap.CodePage850.NewEncoder()
			return dune.NewObject(&encoder{d}), nil
		},
	},
	{
		Name:      "encoding.newDecoderISO8859_1",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d := charmap.ISO8859_1.NewDecoder()
			return dune.NewObject(&decoder{d}), nil
		},
	},
	{
		Name:      "encoding.newEncoderISO8859_1",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d := charmap.ISO8859_1.NewEncoder()
			return dune.NewObject(&encoder{d}), nil
		},
	},
	{
		Name:      "encoding.newDecoderWindows1252",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d := charmap.Windows1252.NewDecoder()
			return dune.NewObject(&decoder{d}), nil
		},
	},
	{
		Name:      "encoding.newEncoderWindows1252",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d := charmap.Windows1252.NewEncoder()
			return dune.NewObject(&encoder{d}), nil
		},
	},
	{
		Name:      "encoding.newDecoderUTF16_LE",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder()
			return dune.NewObject(&decoder{d}), nil
		},
	},
	{
		Name:      "encoding.newEncoderUTF16_LE",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			e := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
			return dune.NewObject(&encoder{e}), nil
		},
	},
}
View Source
var ErrFileNotFound = errors.New("file not found")
View Source
var ErrInvalidType = errors.New("invalid value type")
View Source
var ErrNoFileSystem = errors.New("there is no filesystem")
View Source
var ErrReadOnly = errors.New("readonly property")
View Source
var ErrReadOnlyOrUndefined = errors.New("undefined or readonly property")
View Source
var ErrUnauthorized = errors.New("unauthorized")
View Source
var ErrUndefined = errors.New("undefined")
View Source
var Errors = []dune.NativeFunction{
	{
		Name:      "errors.parse",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			var e dune.VMError

			err := json.Unmarshal(args[0].ToBytes(), &e)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&e), nil
		},
	},
	{
		Name:      "errors.is",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object, dune.String); err != nil {
				return dune.NullValue, err
			}
			e, ok := args[0].ToObjectOrNil().(*dune.VMError)
			if !ok {
				return dune.FalseValue, nil
			}
			return dune.NewBool(e.Is(args[1].String())), nil
		},
	},
	{
		Name:      "errors.wrap",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.Object); err != nil {
				return dune.NullValue, err
			}

			msg := args[0].String()

			e, ok := args[1].ToObjectOrNil().(error)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected arg 2 to be an error. Got %s", args[1].TypeName())
			}

			err := dune.Wrap(msg, e)

			return dune.NewObject(err), nil
		},
	},
	{
		Name:      "errors.unwrap",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			e, ok := args[0].ToObjectOrNil().(*dune.VMError)
			if !ok {
				return dune.FalseValue, nil
			}

			e = e.Wrapped

			if e == nil {
				return dune.NullValue, nil
			}

			return dune.NewObject(e), nil
		},
	},
	{
		Name:      "errors.rethrow",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			ln := len(args)

			if ln == 0 {
				return dune.NullValue, fmt.Errorf("expected at least one argument, got 0")
			}

			e, ok := args[0].ToObjectOrNil().(*dune.VMError)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected error, got %s", args[0].String())
			}

			if ln > 1 {
				a := args[1]
				if a.Type != dune.String {
					return dune.NullValue, fmt.Errorf("expected parameter 1 to be a string, got %s", a.Type)
				}
				details := a.String()
				if ln > 2 {
					values := make([]interface{}, ln-2)
					for i, a := range args[2:] {
						v := a.Export(0)
						if t, ok := v.(*dune.VMError); ok {

							v = t.ErrorMessage()
						}
						values[i] = v
					}
					details = fmt.Sprintf(details, values...)
				}

				if e.Details == "" {
					e.Details = details
				} else {
					e.Details += "\n" + details
				}
			}

			e.IsRethrow = true

			return dune.NullValue, e
		},
	},
	{
		Name:      "errors.newError",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			argsLen := len(args)
			if argsLen < 1 {
				return dune.NullValue, fmt.Errorf("expected at least 1 parameter, got %d", len(args))
			}

			m := args[0]
			if m.Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected parameter 1 to be a string, got %s", m.Type)
			}

			return newCodeError(0, m.String(), args[1:], vm)
		},
	},
	{
		Name:      "errors.newCode",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			argsLen := len(args)
			if argsLen < 1 {
				return dune.NullValue, fmt.Errorf("expected at least 1 parameter, got %d", len(args))
			}

			code := args[0]
			if code.Type != dune.Int {
				return dune.NullValue, fmt.Errorf("expected parameter 1 to be a int, got %s", code.Type)
			}

			var msg string
			var fmtArgs []dune.Value

			if argsLen > 1 {
				m := args[1]
				if m.Type != dune.String {
					return dune.NullValue, fmt.Errorf("expected parameter 2 to be a string, got %s", m.Type)
				}
				msg = m.ToString()
				fmtArgs = args[2:]
			} else {
				msg = fmt.Sprintf("Error %d", code.ToInt())
				fmtArgs = args[1:]
			}

			return codeErrorf(int(code.ToInt()), msg, fmtArgs, vm)
		},
	},
	{
		Name:      "errors.notFound",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return newHTTPCodeError(404, args, vm)
		},
	},
	{
		Name:      "errors.badRequest",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return newHTTPCodeError(400, args, vm)
		},
	},
	{
		Name:      "errors.unauthorized",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return newHTTPCodeError(401, args, vm)
		},
	},
}
View Source
var FSNotify = []dune.NativeFunction{
	{
		Name:        "fsnotify.newWatcher",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]
			switch v.Type {
			case dune.Func:
			case dune.Object:
			default:
				return dune.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
			}

			w, err := newFileWatcher(v, vm)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(w), nil
		},
	},
}
View Source
var FilePath = []dune.NativeFunction{
	{
		Name:      "filepath.clean",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			s := args[0].String()
			if s == "" {
				return args[0], nil
			}

			if s[0] != '/' {
				return dune.NullValue, fmt.Errorf("relative paths are not allowed")
			}

			v := filepath.Clean(s)
			return dune.NewString(v), nil
		},
	},
	{
		Name:      "filepath.join",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			parts := make([]string, len(args))
			for i, v := range args {
				if v.Type != dune.String {
					return dune.NullValue, fmt.Errorf("argument %d is not a string (%s)", i+1, v.TypeName())
				}
				parts[i] = v.String()
			}

			path := filepath.Join(parts...)
			return dune.NewString(path), nil
		},
	},
	{
		Name:      "filepath.joinAbs",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			parts := make([]string, 0, len(args))
			for i, v := range args {
				if v.Type != dune.String {
					return dune.NullValue, fmt.Errorf("argument %d is not a string (%s)", i, v.TypeName())
				}
				s := v.String()
				if strings.HasPrefix(s, "/") {
					parts = nil
				}
				parts = append(parts, s)
			}

			path := filepath.Join(parts...)
			return dune.NewString(path), nil
		},
	},
	{
		Name:      "filepath.abs",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}

			path, err := fs.Abs(args[0].String())
			if err != nil {
				return dune.NullValue, fmt.Errorf("abs %s: %w", args[0].String(), err)
			}

			return dune.NewString(path), nil
		},
	},
	{
		Name:      "filepath.ext",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			path := args[0].String()
			ext := filepath.Ext(path)
			return dune.NewString(ext), nil
		},
	},
	{
		Name:      "filepath.base",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			path := args[0].String()
			name := filepath.Base(path)
			return dune.NewString(name), nil
		},
	},
	{
		Name:      "filepath.baseWithoutExt",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			path := args[0].String()
			name := filepath.Base(path)
			if i := strings.LastIndexByte(name, '.'); i != -1 {
				name = name[:i]
			}
			return dune.NewString(name), nil
		},
	},
	{
		Name:      "filepath.dir",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			path := args[0].String()
			name := filepath.Dir(path)
			return dune.NewString(name), nil
		},
	},
}
View Source
var FileUtil = []dune.NativeFunction{
	{
		Name:      "fileutil.isDirEmpty",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.Object); err != nil {
				return dune.NullValue, err
			}
			if err := ValidateArgRange(args, 1, 2); err != nil {
				return dune.NullValue, err
			}

			fs, ok := args[1].ToObject().(*FileSystemObj)
			if !ok {
				return dune.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[1])
			}

			name := args[0].String()

			f, err := fs.FS.Open(name)
			if err != nil {
				return dune.NullValue, err
			}
			defer f.Close()

			_, err = f.Readdir(1)
			if err != nil {
				if err == io.EOF {
					return dune.NewBool(true), nil
				}
				return dune.NullValue, err
			}

			return dune.NewBool(false), nil
		},
	},
	{
		Name:      "fileutil.copy",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			src := args[0].String()
			dst := args[1].String()

			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, fmt.Errorf("no filesystem")
			}

			r, err := fs.Open(src)
			if err != nil {
				return dune.NullValue, err
			}

			defer r.Close()

			w, err := fs.OpenForWrite(dst)
			if err != nil {
				return dune.NullValue, err
			}

			defer w.Close()

			if _, err := io.Copy(w, r); err != nil {
				return dune.NullValue, err
			}

			return dune.NullValue, nil
		},
	},
}
View Source
var GZIP = []dune.NativeFunction{
	{
		Name:      "gzip.newWriter",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			w, ok := args[0].ToObjectOrNil().(io.Writer)
			if !ok {
				return dune.NullValue, fmt.Errorf("exepected a Writer, got %s", args[0].TypeName())
			}

			g := gzip.NewWriter(w)
			v := &gzipWriter{g}
			return dune.NewObject(v), nil
		},
	},
	{
		Name:      "gzip.newReader",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			r, ok := args[0].ToObjectOrNil().(io.Reader)
			if !ok {
				return dune.NullValue, fmt.Errorf("exepected a reader, got %s", args[0].TypeName())
			}

			gr, err := gzip.NewReader(r)
			if err != nil {
				return dune.NullValue, err
			}
			v := &gzipReader{gr}
			return dune.NewObject(v), nil
		},
	},
}
View Source
var HASH = []dune.NativeFunction{
	{
		Name: "hash.newMD5",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			hash := md5.New()
			return dune.NewObject(hasher{hash}), nil
		},
	},
	{
		Name: "hash.newSHA256",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			hash := sha256.New()
			return dune.NewObject(hasher{hash}), nil
		},
	},
}
View Source
var HEX = []dune.NativeFunction{
	{
		Name:      "hex.encodeToString",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()
			s := hex.EncodeToString(b)
			return dune.NewString(s), nil
		},
	},
}
View Source
var HTML = []dune.NativeFunction{
	{
		Name:      "html.encode",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			switch a.Type {
			case dune.Null, dune.Undefined:
				return dune.NullValue, nil
			case dune.String:
				return dune.NewString(html.EscapeString(a.String())), nil
			default:
				return dune.NewString(a.String()), nil
			}
		},
	},
	{
		Name:      "html.decode",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			switch a.Type {
			case dune.Null, dune.Undefined:
				return dune.NullValue, nil
			case dune.String:
				return dune.NewString(html.UnescapeString(a.String())), nil
			default:
				return dune.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
}
View Source
var HTTP = []dune.NativeFunction{
	{
		Name: "->http.OK",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(200), nil
		},
	},
	{
		Name: "->http.REDIRECT",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(302), nil
		},
	},
	{
		Name: "->http.BAD_REQUEST",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(400), nil
		},
	},
	{
		Name: "->http.UNAUTHORIZED",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(401), nil
		},
	},
	{
		Name: "->http.NOT_FOUND",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(404), nil
		},
	},
	{
		Name: "->http.TIMEOUT",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(408), nil
		},
	},
	{
		Name: "->http.INTERNAL_ERROR",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(500), nil
		},
	},
	{
		Name: "->http.UNAVAILABLE",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(503), nil
		},
	},
	{
		Name: "->http.SameSiteDefaultMode",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(http.SameSiteDefaultMode)), nil
		},
	},
	{
		Name: "->http.SameSiteDefaultMode",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(http.SameSiteDefaultMode)), nil
		},
	},

	{
		Name: "->http.SameSiteLaxMode",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(http.SameSiteLaxMode)), nil
		},
	},
	{
		Name: "->http.SameSiteStrictMode",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(http.SameSiteStrictMode)), nil
		},
	},
	{
		Name: "->http.SameSiteNoneMode",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(http.SameSiteNoneMode)), nil
		},
	},
	{
		Name:      "http.cacheBreaker",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			cacheMut.RLock()
			v := dune.NewString(cacheBreaker)
			cacheMut.RUnlock()
			return v, nil
		},
	},
	{
		Name:        "http.resetCacheBreaker",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			cacheMut.Lock()
			cacheBreaker = RandString(9)
			cacheMut.Unlock()
			return dune.NullValue, nil
		},
	},
	{
		Name:        "http.newServer",
		Arguments:   0,
		Permissions: []string{"netListen"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := &server{
				vm:                vm,
				handler:           -1,
				readTimeout:       10 * time.Second,
				writeTimeout:      10 * time.Second,
				readHeaderTimeout: 10 * time.Second,
				idleTimeout:       100 * time.Second,
			}

			return dune.NewObject(s), nil
		},
	},
	{
		Name:      "http.newResponseRecorder",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			r, ok := args[0].ToObjectOrNil().(*request)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a request, got %v", args[0].TypeName())
			}

			w := &responseWriter{
				writer:  httptest.NewRecorder(),
				request: r.request,
			}

			return dune.NewObject(w), nil
		},
	},
	{
		Name:      "http.newCookie",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			c := &cookie{}
			return dune.NewObject(c), nil
		},
	},
	{
		Name:      "http.encodeURIComponent",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			v := args[0].String()
			u := url.QueryEscape(v)
			return dune.NewString(u), nil
		},
	},
	{
		Name:      "http.decodeURIComponent",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			v := args[0].String()
			u, err := url.QueryUnescape(v)
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewString(u), nil
		},
	},
	{
		Name:        "http.newRequest",
		Arguments:   -1,
		Permissions: []string{"networking"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return dune.NullValue, err
			}

			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 1 to be string, got %v", args[0].Type)
			}

			if args[1].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 2 to be string, got %v", args[1].Type)
			}

			var method string
			var urlStr string
			var queryMap map[dune.Value]dune.Value
			var reader io.Reader
			var contentType string

			switch len(args) {
			case 2:
				method = args[0].String()
				urlStr = args[1].String()
			case 3:
				method = args[0].String()
				urlStr = args[1].String()
				form := url.Values{}

				v := args[2]

				switch v.Type {
				case dune.Null, dune.Undefined:
				case dune.String:
					switch method {
					case "POST", "PUT", "PATCH":
					default:
						return dune.NullValue, fmt.Errorf("can only pass a data string with POST, PUT or PATCH")
					}
					reader = strings.NewReader(v.String())
					contentType = "application/json; charset=UTF-8"
				case dune.Map:
					m := v.ToMap()
					if method == "GET" {
						queryMap = m.Map
					} else {
						m.RLock()
						for k, v := range m.Map {
							if v.IsNilOrEmpty() {
								continue
							}
							vs, err := serialize(v)
							if err != nil {
								return dune.NullValue, fmt.Errorf("error serializing parameter: %v", v.Type)
							}
							form.Add(k.String(), vs)
						}
						m.RUnlock()
						reader = strings.NewReader(form.Encode())
						contentType = "application/x-www-form-urlencoded"
					}
				case dune.Object:
					r, ok := v.ToObject().(io.Reader)
					if !ok {
						return dune.NullValue, fmt.Errorf("invalid argument 3 type: got %v", v.TypeName())
					}
					reader = r
				default:
					return dune.NullValue, fmt.Errorf("expected argument 3 to be object, got %v", v.Type)
				}
			}

			r, err := http.NewRequest(method, urlStr, reader)
			if err != nil {
				return dune.NullValue, err
			}

			switch method {
			case "POST", "PUT", "PATCH":
				if contentType != "" {
					r.Header.Add("Content-Type", contentType)
				}
			case "GET":
				if queryMap != nil {
					q := r.URL.Query()
					for k, v := range queryMap {
						if v.IsNilOrEmpty() {
							continue
						}
						vs, err := serialize(v)
						if err != nil {
							return dune.NullValue, fmt.Errorf("error serializing parameter: %v", v.Type)
						}
						q.Add(k.String(), vs)
					}
					r.URL.RawQuery = q.Encode()
				}
			}

			return dune.NewObject(&request{request: r}), nil
		},
	},
	{
		Name:        "http.get",
		Arguments:   -1,
		Permissions: []string{"networking"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			client := &http.Client{}
			timeout := 20 * time.Second

			ln := len(args)

			if ln == 0 {
				return dune.NullValue, fmt.Errorf("expected 1 to 3 arguments, got %d", len(args))
			}

			a := args[0]
			if a.Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 0 to be string, got %s", a.TypeName())
			}
			url := a.String()

			if ln == 0 {
			} else if ln > 1 {
				a := args[1]
				switch a.Type {
				case dune.Undefined, dune.Null:
				case dune.Int, dune.Object:
					var err error
					timeout, err = ToDuration(args[1])
					if err != nil {
						return dune.NullValue, err
					}
				default:
					return dune.NullValue, fmt.Errorf("expected argument 1 to be duration")
				}
			}

			if ln > 2 {
				b := args[2]
				switch b.Type {
				case dune.Null, dune.Undefined:
				case dune.Object:
					t, ok := args[2].ToObjectOrNil().(*tlsConfig)
					if !ok {
						return dune.NullValue, fmt.Errorf("expected argument 2 to be tls.Config")
					}
					client.Transport = getTransport(t.conf)
				default:
					return dune.NullValue, fmt.Errorf("expected argument 2 to be string, got %s", b.TypeName())
				}
			}

			client.Timeout = timeout
			resp, err := client.Get(url)
			if err != nil {
				return dune.NullValue, err
			}

			b, err := io.ReadAll(resp.Body)

			err2 := resp.Body.Close()

			if err != nil {
				return dune.NullValue, err
			}

			if err2 != nil {
				return dune.NullValue, err2
			}

			if !isHTTPSuccess(resp.StatusCode) {
				return dune.NullValue, fmt.Errorf("http Error %d: %v", resp.StatusCode, string(b))
			}

			return dune.NewString(string(b)), nil
		},
	},
	{
		Name:        "http.post",
		Arguments:   2,
		Permissions: []string{"networking"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.Map); err != nil {
				return dune.NullValue, err
			}
			u := args[0].String()

			data := url.Values{}

			m := args[1].ToMap()
			m.RLock()
			for k, v := range m.Map {
				data.Add(k.String(), v.String())
			}
			m.RUnlock()

			resp, err := http.PostForm(u, data)
			if err != nil {
				return dune.NullValue, err
			}

			b, err := io.ReadAll(resp.Body)
			resp.Body.Close()
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewString(string(b)), nil
		},
	},
	{
		Name:        "http.getJSON",
		Arguments:   1,
		Permissions: []string{"networking"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			url := args[0].String()

			resp, err := http.Get(url)
			if err != nil {
				return dune.NullValue, err
			}

			b, err := io.ReadAll(resp.Body)
			resp.Body.Close()
			if err != nil {
				return dune.NullValue, err
			}

			v, err := unmarshal(b)
			if err != nil {
				return dune.NullValue, err
			}

			return v, nil
		},
	},
	{
		Name:      "http.parseURL",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			if len(args) == 0 {
				u := &url.URL{}
				return dune.NewObject(&URL{url: u}), nil
			}

			rawURL := args[0].String()
			u, err := url.Parse(rawURL)
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewObject(&URL{u}), nil
		},
	},
}
View Source
var HTTPUTIL = []dune.NativeFunction{
	{
		Name:      "httputil.newSingleHostReverseProxy",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			u, ok := a.ToObjectOrNil().(*URL)
			if !ok {
				return dune.NullValue, fmt.Errorf("invalid argument 1: expected http.URL, got %v", a.TypeName())
			}

			p := &reverseProxy{
				proxy: httputil.NewSingleHostReverseProxy(u.url),
			}

			return dune.NewObject(p), nil
		},
	},
}
View Source
var IO = []dune.NativeFunction{
	{
		Name:      "io.readAll",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			r := args[0].ToObject()

			reader, ok := r.(io.Reader)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a io.Reader, got %v", args[0])
			}

			b, err := ReadAll(reader, vm)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewBytes(b), nil
		},
	},
	{
		Name:      "io.newBuffer",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewObject(NewBuffer()), nil
		},
	},
	{
		Name:      "io.copy",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object, dune.Object); err != nil {
				return dune.NullValue, err
			}

			dst, ok := args[0].ToObject().(io.Writer)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}

			src, ok := args[1].ToObject().(io.Reader)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}

			i, err := io.Copy(dst, src)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewInt64(i), nil
		},
	},
	{
		Name:      "io.newRootedFS",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.Object); err != nil {
				return dune.NullValue, err
			}
			fs, ok := args[1].ToObject().(*FileSystemObj)
			if !ok {
				return dune.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[1])
			}
			root := args[0].String()
			rFS, err := filesystem.NewRootedFS(root, fs.FS)
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewObject(NewFileSystem(rFS)), nil
		},
	},
	{
		Name:      "io.newRestrictedFS",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			fs, ok := args[0].ToObject().(*FileSystemObj)
			if !ok {
				return dune.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[1])
			}

			rFS, err := filesystem.NewRestrictedFS(fs.FS)
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewObject(NewFileSystem(rFS)), nil
		},
	},
	{
		Name: "io.newVirtualFS",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return dune.NullValue, err
			}

			fs := filesystem.NewVirtualFS()
			return dune.NewObject(NewFileSystem(fs)), nil
		},
	},
	{
		Name:      "io.newReadOnlyFS",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			fs, ok := args[0].ToObject().(*FileSystemObj)
			if !ok {
				return dune.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[1])
			}

			rfs := filesystem.NewReadOnlyFS(fs.FS)
			return dune.NewObject(NewFileSystem(rfs)), nil
		},
	},
}
View Source
var Inmutable = []dune.NativeFunction{
	{
		Name:      "inmutable.newObject",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bool, dune.Map); err != nil {
				return dune.NullValue, err
			}

			p := &InmutableObject{
				canAddNew: args[0].ToBool(),
				values:    make(map[string]dune.Value),
			}

			for k, v := range args[1].ToMap().Map {
				p.values[k.String()] = v
			}

			return dune.NewObject(p), nil
		},
	},
}
View Source
var JSON = []dune.NativeFunction{
	{
		Name:      "json.marshal",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			ln := len(args)
			if ln == 0 || ln > 3 {
				return dune.NullValue, fmt.Errorf("expected 1, 2 or 3 arguments, got %d", len(args))
			}

			var indent bool
			var escapeHTML bool

			if ln > 1 {
				v := args[1]
				if v.Type != dune.Bool {
					return dune.NullValue, fmt.Errorf("expected arg 2 to be boolean, got %s", v.TypeName())
				}
				indent = v.ToBool()
			}

			if ln > 2 {
				v := args[2]
				if v.Type != dune.Bool {
					return dune.NullValue, fmt.Errorf("expected arg 3 to be boolean, got %s", v.TypeName())
				}
				escapeHTML = v.ToBool()
			}

			obj := args[0].ExportMarshal(0)

			buf := &bytes.Buffer{}

			encoder := json.NewEncoder(buf)

			if indent {
				encoder.SetIndent("", "    ")
			}

			encoder.SetEscapeHTML(escapeHTML)

			if err := encoder.Encode(obj); err != nil {
				return dune.NullValue, err
			}

			buf.Truncate(buf.Len() - 1)

			return dune.NewString(buf.String()), nil
		},
	},
	{
		Name:      "json.unmarshal",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if len(args) != 1 {
				return dune.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			a := args[0]

			switch a.Type {
			case dune.String, dune.Bytes:
			default:
				return dune.NullValue, fmt.Errorf("expected argument to be string or byte[], got %v", args[0].Type)
			}

			if a.String() == "" {
				return dune.NullValue, nil
			}

			v, err := unmarshal(a.ToBytes())
			if err != nil {
				return dune.NullValue, err
			}

			return v, nil
		},
	},
}
View Source
var Locale = []dune.NativeFunction{
	{
		Name:      "locale.clearTranslations",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			locale.ClearTransations()
			return dune.NullValue, nil
		},
	},
	{
		Name:      "locale.addTranslation",
		Arguments: 3,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			language := args[0].String()
			value := args[1].String()
			translation := args[2].String()

			locale.AddTranslation(language, value, translation)
			return dune.NullValue, nil
		},
	},
	{
		Name:      "->locale.currentLocalizer",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}
			c := dune.NewObject(loc)
			return c, nil
		},
	},
	{
		Name:      "locale.setLocalizer",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			loc, ok := args[0].ToObjectOrNil().(*localizer)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}
			vm.Localizer = loc
			return dune.NullValue, nil
		},
	},
	{
		Name:      "->locale.currentLanguage",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := dune.NewString(vm.Language)
			return s, nil
		},
	},
	{
		Name:      "->locale.defaultLocalizer",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			c := dune.NewObject(defaultLocalizer)
			return c, nil
		},
	},
	{
		Name:        "locale.setDefaultLocalizer",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			loc, ok := args[0].ToObjectOrNil().(*localizer)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}
			defaultLocalizer = loc
			return dune.NullValue, nil
		},
	},
	{
		Name:      "locale.setCurrentLanguage",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			vm.Language = args[0].String()
			return dune.NullValue, nil
		},
	},
	{
		Name:      "locale.newCulture",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			name := args[0].String()
			c := dune.NewObject(&culture{culture: locale.NewCulture(name)})
			return c, nil
		},
	},
	{
		Name:      "locale.newLocalizer",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			lt := dune.NewObject(&localizer{})
			return lt, nil
		},
	},
	{
		Name:      "locale.parseNumber",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}

			v, err := loc.ParseNumber(args[0].String())
			if err != nil {
				return dune.NullValue, err
			}

			if v == float64(int64(v)) {
				return dune.NewInt(int(v)), nil
			}
			return dune.NewFloat(v), nil
		},
	},
	{
		Name:      "locale.parseDate",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			if len(args) == 0 {
				return dune.NullValue, fmt.Errorf("expected at least 1 argument, got %d", len(args))
			}

			var format string
			if len(args) == 2 {
				switch args[1].Type {
				case dune.Null, dune.Undefined:
					format = ""
				default:
					format = args[1].String()
				}
			} else {
				format = ""
			}

			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}

			v, err := loc.ParseDate(args[0].String(), format, vm.Location)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(TimeObj(v)), nil
		},
	},
	{
		Name:      "locale.format",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if len(args) != 2 {
				return dune.NullValue, fmt.Errorf("expected 2 arguments, got %d", len(args))
			}

			a := args[0]
			if a.Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument 1 to be a string, got %v", a.TypeName())
			}

			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}

			b := args[1].Export(0)
			s := loc.Format(vm.Language, a.String(), b)
			return dune.NewString(s), nil
		},
	},
}
View Source
var Log = []dune.NativeFunction{
	{
		Name:        "->logging.defaultLogger",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if defaultLogger == nil {
				return dune.NullValue, nil
			}
			return dune.NewObject(defaultLogger), nil
		},
	},
	{
		Name:        "logging.setDefaultLogger",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			db, ok := args[0].ToObjectOrNil().(*logger)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a logging, got %s", args[0].TypeName())
			}

			defaultLogger = db

			return dune.NullValue, nil
		},
	},
	{
		Name:        "logging.fatal",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			err := writeLog("system", args)
			if err != nil {
				return dune.NullValue, err
			}

			os.Exit(1)
			return dune.NullValue, nil
		},
	},
	{
		Name:        "logging.write",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l < 2 {
				return dune.NullValue, fmt.Errorf("expected at least 2 parameters, got %d", len(args))
			}

			name := args[0]
			if name.Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected parameter 1 to be a string, got %s", name.Type)
			}

			err := writeLog(name.String(), args[1:])
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NullValue, nil
		},
	},
	{
		Name:        "logging.system",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if len(args) == 0 {
				return dune.NullValue, fmt.Errorf("expected at least 1 parameter, got 0")
			}

			err := writeLog("system", args)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NullValue, nil
		},
	},
	{
		Name:        "logging.newLogger",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.Object); err != nil {
				return dune.NullValue, err
			}

			ln := len(args)
			if ln == 0 || ln > 2 {
				return dune.NullValue, fmt.Errorf("expected 1 or 2 arguments, got %d", ln)
			}

			path := args[0].String()

			var fs filesystem.FS

			if ln == 2 {
				afs, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return dune.NullValue, fmt.Errorf("invalid argument 2 type: %s", args[1].TypeName())
				}
				fs = afs.FS
			} else {
				fs = filesystem.OS
			}

			t := &logger{
				db: logging.New(path, fs),
			}

			return dune.NewObject(t), nil
		},
	},
}
View Source
var Markdown = []dune.NativeFunction{
	{
		Name:      "markdown.toHTML",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			b := args[0].ToBytes()
			out := blackfriday.MarkdownCommon(b)
			return dune.NewString(string(out)), nil
		},
	},
}
View Source
var Math = []dune.NativeFunction{
	{
		Name:      "math.pow",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Float, dune.Float); err != nil {
				return dune.NullValue, err
			}
			v := math.Pow(args[0].ToFloat(), args[1].ToFloat())
			return dune.NewFloat(v), nil
		},
	},
	{
		Name:      "math.abs",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}
			v := math.Abs(args[0].ToFloat())
			return dune.NewFloat(v), nil
		},
	},
	{
		Name:      "math.floor",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}
			v := math.Floor(args[0].ToFloat())
			return dune.NewInt64(int64(v)), nil
		},
	},
	{
		Name:      "math.ceil",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}
			v := math.Ceil(args[0].ToFloat())
			return dune.NewInt64(int64(v)), nil
		},
	},
	{
		Name:      "math.round",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {

			l := len(args)
			if l > 2 {
				return dune.NullValue, fmt.Errorf("expected 1 or 2 params, got %d", l)
			}

			f := args[0]
			switch f.Type {
			case dune.Float, dune.Int:
			default:
				return dune.NullValue, fmt.Errorf("expected parameter 1 to be a number, got %s", f.TypeName())
			}

			if l == 1 {
				v := math.Round(f.ToFloat())
				return dune.NewInt64(int64(v)), nil
			}

			d := args[1]
			if d.Type != dune.Int {
				return dune.NullValue, fmt.Errorf("expected parameter 2 to be int, got %s", d.TypeName())
			}

			i := math.Pow10(int(d.ToInt()))
			v := math.Round(f.ToFloat()*i) / i
			return dune.NewFloat(v), nil
		},
	},
	{
		Name:      "math.rand",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}
			v := rand.Intn(int(args[0].ToInt()))
			return dune.NewInt(v), nil
		},
	},
	{
		Name:      "math.median",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			values := make([]float64, len(args))

			for i, v := range args {
				switch v.Type {
				case dune.Int, dune.Float:
					values[i] = v.ToFloat()
				default:
					return dune.NullValue, fmt.Errorf("element at %d is not a number: %s", i, v.TypeName())
				}
			}

			r := median(values)
			return dune.NewFloat(r), nil
		},
	},
	{
		Name:      "math.min",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var min float64

			for i, v := range args {
				switch v.Type {
				case dune.Int, dune.Float:
					k := v.ToFloat()
					if i == 0 {
						min = k
					} else if k < min {
						min = k
					}
				default:
					return dune.NullValue, fmt.Errorf("element at %d is not a number: %s", i, v.TypeName())
				}
			}

			return dune.NewFloat(min), nil
		},
	},
	{
		Name:      "math.max",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var max float64

			for i, v := range args {
				switch v.Type {
				case dune.Int, dune.Float:
					k := v.ToFloat()
					if i == 0 {
						max = k
					} else if k > max {
						max = k
					}
				default:
					return dune.NullValue, fmt.Errorf("element at %d is not a number: %s", i, v.TypeName())
				}
			}

			return dune.NewFloat(max), nil
		},
	},
	{
		Name:      "math.standardDev",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			values := make([]float64, len(args))
			for i, v := range args {
				switch v.Type {
				case dune.Int, dune.Float:
					values[i] = v.ToFloat()
				default:
					return dune.NullValue, fmt.Errorf("element at %d is not a number: %s", i, v.TypeName())
				}
			}

			m := median(values)
			d := stdDev(values, m)
			return dune.NewFloat(d), nil
		},
	},
}
View Source
var Multipart = []dune.NativeFunction{
	{
		Name:      "multipart.newWriter",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			r := args[0].ToObject()

			w, ok := r.(io.Writer)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a io.Writer, got %v", args[0])
			}

			m := multipart.NewWriter(w)
			return dune.NewObject(&multipartWriter{m}), nil
		},
	},
}
View Source
var Net = []dune.NativeFunction{
	{
		Name:      "net.inCIDR",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			cidr := args[0].String()

			ip := net.ParseIP(args[1].String())

			_, ipnet, err := net.ParseCIDR(cidr)
			if err != nil {
				return dune.NullValue, err
			}

			v := ipnet.Contains(ip)

			return dune.NewBool(v), nil
		},
	},
	{
		Name:        "net.listen",
		Arguments:   2,
		Permissions: []string{"netListen"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			listener, err := newNetListener(args[0].String(), args[1].String(), vm)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(listener), nil
		},
	},
	{
		Name:        "net.listenTCP",
		Arguments:   2,
		Permissions: []string{"netListen"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.Object); err != nil {
				return dune.NullValue, err
			}

			addr, ok := args[1].ToObject().(*tcpAddr)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected param 2 to be TCPAddr, got %s", args[1].TypeName())
			}

			listener, err := newTCPListener(args[0].String(), addr.addr, vm)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(listener), nil
		},
	},
	{
		Name:      "net.resolveTCPAddr",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			addr, err := net.ResolveTCPAddr(args[0].String(), args[1].String())
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&tcpAddr{addr: addr}), nil
		},
	},
	{
		Name:      "net.dialTCP",
		Arguments: 3,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOrNilArgs(args, dune.String, dune.Object, dune.Object); err != nil {
				return dune.NullValue, err
			}

			network := args[0].String()

			var localAddr *net.TCPAddr

			lArg := args[1].ToObjectOrNil()
			if lArg != nil {
				ltcpAddr, ok := lArg.(*tcpAddr)
				if !ok {
					return dune.NullValue, fmt.Errorf("expected param 2 to be TCPAddr, got %s", args[1].TypeName())
				}
				localAddr = ltcpAddr.addr
			}

			remoteAddr, ok := args[2].ToObject().(*tcpAddr)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected param 3 to be TCPAddr, got %s", args[1].TypeName())
			}

			conn, err := net.DialTCP(network, localAddr, remoteAddr.addr)
			if err != nil {
				return dune.NullValue, err
			}

			tc := newTCPConn(conn, vm)

			return dune.NewObject(tc), nil
		},
	},
	{
		Name:      "net.dial",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}
			conn, err := net.Dial(args[0].String(), args[1].String())
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(newNetConn(conn, vm)), nil
		},
	},
	{
		Name:      "net.dialTimeout",
		Arguments: 3,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected param 1 to be string, got %s", args[0].TypeName())
			}
			if args[1].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected param 2 to be string, got %s", args[1].TypeName())
			}

			d, err := ToDuration(args[2])
			if err != nil {
				return dune.NullValue, err
			}

			conn, err := net.DialTimeout(args[0].String(), args[1].String(), d)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(newNetConn(conn, vm)), nil
		},
	},
	{
		Name:        "net.getIPAddress",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			addrs, err := net.InterfaceAddrs()
			if err != nil {
				return dune.NullValue, err
			}

			for _, address := range addrs {
				if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
					if ipnet.IP.To4() != nil {
						return dune.NewString(ipnet.IP.String()), nil
					}
				}
			}

			return dune.NullValue, fmt.Errorf("no IP address found")
		},
	},
	{
		Name:        "net.getMacAddress",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			addrs, err := net.InterfaceAddrs()
			if err != nil {
				return dune.NullValue, err
			}

			var ip string

			for _, address := range addrs {
				if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
					if ipnet.IP.To4() != nil {
						ip = ipnet.IP.String()
						break
					}
				}
			}

			if ip == "" {
				return dune.NullValue, fmt.Errorf("no IP address found")
			}

			interfaces, err := net.Interfaces()
			if err != nil {
				return dune.NullValue, err
			}

			var hardwareName string

			for _, interf := range interfaces {
				if addrs, err := interf.Addrs(); err == nil {
					for _, addr := range addrs {

						if strings.Contains(addr.String(), ip) {
							hardwareName = interf.Name
							break
						}
					}
				}
			}

			if hardwareName == "" {
				return dune.NullValue, fmt.Errorf("no network hardware found")
			}

			netInterface, err := net.InterfaceByName(hardwareName)
			if err != nil {
				return dune.NullValue, err
			}

			macAddress := netInterface.HardwareAddr

			hwAddr, err := net.ParseMAC(macAddress.String())
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewString(hwAddr.String()), nil
		},
	},
}
View Source
var Number = []dune.NativeFunction{
	{
		Name:      "Number.prototype.format",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			switch this.Type {
			case dune.Int, dune.Float:
				break
			default:
				return dune.NullValue, fmt.Errorf("expected byte array, got %s", this.TypeName())
			}

			format := args[0].ToString()

			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}

			num := this.Export(0)

			s := loc.Format(vm.Language, format, num)

			return dune.NewString(s), nil
		},
	},
}
View Source
var OS = []dune.NativeFunction{
	{
		Name: "->os.ErrNotExist",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewString("no such file or directory"), nil
		},
	},
	{
		Name:        "os.hostName",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			name, err := os.Hostname()
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewString(name), nil
		},
	},
	{
		Name: "->os.pathSeparator",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewString(string(os.PathSeparator)), nil
		},
	},
	{
		Name:        "->os.userHomeDir",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d, err := os.UserHomeDir()
			if err != nil {
				return dune.NullValue, ErrUnauthorized
			}
			return dune.NewString(d), nil
		},
	},
	{
		Name:        "->os.stdout",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			f := &file{f: os.Stdout}
			return dune.NewObject(f), nil
		},
	},
	{
		Name:        "->os.stdin",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			f := &file{f: os.Stdin}
			return dune.NewObject(f), nil
		},
	},
	{
		Name:        "->os.stderr",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			f := &file{f: os.Stderr}
			return dune.NewObject(f), nil
		},
	},
	{
		Name:        "os.mapPath",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			p := args[0].String()

			if len(p) > 0 && p[0] == '~' {
				usr, err := user.Current()
				if err != nil {
					return dune.NullValue, err
				}
				p = filepath.Join(usr.HomeDir, p[1:])
			}

			return dune.NewString(p), nil
		},
	},
	{
		Name:        "os.exit",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}

			var exitCode int
			if len(args) > 0 {
				exitCode = int(args[0].ToInt())
			}

			os.Exit(exitCode)
			return dune.NullValue, nil
		},
	},
	{
		Name:        "os.exec",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l == 0 {
				return dune.NullValue, fmt.Errorf("expected at least 1 argument")
			}

			values := make([]string, l)
			for i, v := range args {
				values[i] = v.String()
			}

			cmd := exec.Command(values[0], values[1:]...)
			cmd.Stderr = os.Stderr
			cmd.Stdout = os.Stdout

			if err := cmd.Run(); err != nil {
				return dune.NullValue, err
			}

			return dune.NullValue, nil
		},
	},
	{
		Name:        "os.newCommand",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l == 0 {
				return dune.NullValue, fmt.Errorf("expected at least 1 argument")
			}

			values := make([]string, l)
			for i, v := range args {
				values[i] = v.String()
			}

			cmd := newCommand(values[0], values[1:]...)

			return dune.NewObject(cmd), nil
		},
	},

	{
		Name:      "os.getWd",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}

			f := &FileSystemObj{fs}
			return f.getWd(args, vm)
		},
	},
	{
		Name:      "os.open",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.open(args, vm)
		},
	},
	{
		Name:      "os.openIfExists",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.openIfExists(args, vm)
		},
	},
	{
		Name:      "os.openForWrite",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.openForWrite(args, vm)
		},
	},
	{
		Name:      "os.openForAppend",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.openForAppend(args, vm)
		},
	},
	{
		Name:      "os.chdir",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.chdir(args, vm)
		},
	},
	{
		Name:      "os.exists",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.exists(args, vm)
		},
	},
	{
		Name:      "os.rename",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.rename(args, vm)
		},
	},
	{
		Name:      "os.removeAll",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.removeAll(args, vm)
		},
	},
	{
		Name:      "os.readAll",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readAll(args, vm)
		},
	},
	{
		Name:      "os.readAllIfExists",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readAllIfExists(args, vm)
		},
	},
	{
		Name:      "os.readString",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readString(args, vm)
		},
	},
	{
		Name:      "os.readStringIfExists",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readStringIfExists(args, vm)
		},
	},
	{
		Name:      "os.write",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.write(args, vm)
		},
	},
	{
		Name:      "os.append",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.append(args, vm)
		},
	},
	{
		Name:      "os.mkdir",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.mkdir(args, vm)
		},
	},
	{
		Name:      "os.stat",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.stat(args, vm)
		},
	},
	{
		Name:      "os.readDir",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readDir(args, vm)
		},
	},
	{
		Name:      "os.readNames",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return dune.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readNames(args, vm)
		},
	},

	{
		Name:        "os.readLine",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {

			r := bufio.NewReader(os.Stdin)
			s, err := r.ReadString('\n')
			if err != nil {
				return dune.NullValue, err
			}

			s = s[:len(s)-1]

			return dune.NewString(s), nil
		},
	},
	{
		Name: "->os.fileSystem",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if vm.FileSystem == nil {
				return dune.NullValue, nil
			}
			return dune.NewObject(NewFileSystem(vm.FileSystem)), nil
		},
	},
	{
		Name:        "os.getEnv",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			s := os.Getenv(args[0].String())
			return dune.NewString(s), nil
		},
	},
	{
		Name:        "os.setEnv",
		Arguments:   2,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			if err := os.Setenv(args[0].String(), args[1].String()); err != nil {
				return dune.NullValue, err
			}
			return dune.NullValue, nil
		},
	},
}
View Source
var Png = []dune.NativeFunction{
	{
		Name:      "png.decode",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			r, ok := args[0].ToObject().(io.Reader)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}

			img, err := png.Decode(r)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(imageObj{img}), nil
		},
	},
	{
		Name:      "png.encode",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object, dune.Object); err != nil {
				return dune.NullValue, err
			}

			w, ok := args[0].ToObject().(io.Writer)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}

			i, ok := args[1].ToObject().(imageObj)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}

			err := png.Encode(w, i.img)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NullValue, nil
		},
	},
}
View Source
var Printing = []dune.NativeFunction{
	{
		Name:      "printing.listPrinters",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			list, err := printutil.ListPrinters()
			if err != nil {
				return dune.NullValue, err
			}

			values := make([]dune.Value, len(list))

			for i, name := range list {
				values[i] = dune.NewString((name))
			}

			return dune.NewArrayValues(values), nil
		},
	},
	{
		Name:      "printing.newPrinter",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.Bool); err != nil {
				return dune.NullValue, err
			}

			var name string
			var cups bool

			switch len(args) {
			case 0:
				return dune.NullValue, fmt.Errorf("expected at least one argument")

			case 1:
				name = args[0].ToString()

			case 2:
				name = args[0].ToString()
				cups = args[1].ToBool()
			}

			p := printutil.New(name, cups)

			return dune.NewObject(&printerObj{p}), nil
		},
	},
}
View Source
var RSA = []dune.NativeFunction{
	{
		Name:      "rsa.generateKey",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}

			reader := rand.Reader

			var bitSize int
			if len(args) == 0 {
				bitSize = 2048
			} else {
				bitSize = int(args[0].ToInt())
			}

			key, err := rsa.GenerateKey(reader, bitSize)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&rsaPrivateKey{key}), nil
		},
	},
	{
		Name:      "rsa.decodePEMKey",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0].ToBytes()

			block, _ := pem.Decode(v)

			if block == nil {
				return dune.NullValue, fmt.Errorf("error decoding private key")
			}

			enc := x509.IsEncryptedPEMBlock(block)

			b := block.Bytes

			var err error
			if enc {

				b, err = x509.DecryptPEMBlock(block, nil)
				if err != nil {
					return dune.NullValue, fmt.Errorf("error decrypting private key")
				}
			}

			key, err := x509.ParsePKCS1PrivateKey(b)
			if err != nil {
				return dune.NullValue, fmt.Errorf("error parsing private key: %w", err)
			}

			return dune.NewObject(&rsaPrivateKey{key}), nil
		},
	},
	{
		Name:      "rsa.decodePublicPEMKey",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0].ToBytes()

			block, _ := pem.Decode(v)

			if block == nil {
				return dune.NullValue, fmt.Errorf("error decoding public key")
			}

			enc := x509.IsEncryptedPEMBlock(block)

			b := block.Bytes

			var err error
			if enc {

				b, err = x509.DecryptPEMBlock(block, nil)
				if err != nil {
					return dune.NullValue, fmt.Errorf("error decrypting public key")
				}
			}
			ifc, err := x509.ParsePKIXPublicKey(b)
			if err != nil {
				return dune.NullValue, fmt.Errorf("error parsing public key: %v", err)
			}

			key, ok := ifc.(*rsa.PublicKey)
			if !ok {
				return dune.NullValue, fmt.Errorf("not an RSA public key")
			}

			return dune.NewObject(&rsaPublicKey{key}), nil
		},
	},
	{
		Name:      "rsa.signPKCS1v15",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			key, ok := args[0].ToObjectOrNil().(*rsaPrivateKey)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a rsa key, got %v", args[0].TypeName())
			}

			message := args[1].ToBytes()

			hashed := sha256.Sum256(message)

			rng := rand.Reader

			signature, err := rsa.SignPKCS1v15(rng, key.key, crypto.SHA256, hashed[:])
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewBytes(signature), nil
		},
	},
	{
		Name:      "rsa.verifyPKCS1v15",
		Arguments: 3,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			key, ok := args[0].ToObjectOrNil().(*rsaPublicKey)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a rsa key, got %v", args[0].TypeName())
			}

			message := args[1].ToBytes()
			signature := args[2].ToBytes()

			hashed := sha256.Sum256(message)

			err := rsa.VerifyPKCS1v15(key.key, crypto.SHA256, hashed[:], signature)
			if err != nil {
				return dune.FalseValue, err
			}

			return dune.TrueValue, err
		},
	},
}
View Source
var Reflect = []dune.NativeFunction{
	{
		Name:      "reflect.createInstance",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if len(args) == 0 {
				return dune.NullValue, fmt.Errorf("expected at least 1 parameter, got %d", len(args))
			}

			a := args[0]
			if a.Type != dune.String {
				return dune.NullValue, fmt.Errorf("argument 1 must be a string, got %s", a.TypeName())
			}

			instance, err := dune.NewInstance(a.String(), args[1:], vm)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(instance), nil
		},
	},
	{
		Name:      "reflect.nativeFunctions",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := getNativeFuncions(false)
			return v, nil
		},
	},
	{
		Name:      "reflect.nativeProperties",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := getNativeFuncions(true)
			return v, nil
		},
	},
	{
		Name:      "reflect.is",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0].TypeName()
			b := args[1]
			if b.Type != dune.String {
				return dune.NullValue, fmt.Errorf("argument 2 must be a string, got %s", b.TypeName())
			}
			return dune.NewBool(a == b.String()), nil
		},
	},
	{
		Name:      "reflect.isValue",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			switch args[0].Type {
			case dune.Int, dune.Float, dune.Bool, dune.String:
				return dune.FalseValue, nil
			}
			return dune.TrueValue, nil
		},
	},
	{
		Name:      "reflect.isNativeObject",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0].Type == dune.Object
			return dune.NewBool(v), nil
		},
	},
	{
		Name:      "reflect.isArray",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0].Type == dune.Array
			return dune.NewBool(v), nil
		},
	},
	{
		Name:      "reflect.isMap",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0].Type == dune.Map
			return dune.NewBool(v), nil
		},
	},
	{
		Name:      "reflect.typeOf",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]
			return dune.NewString(v.TypeName()), nil
		},
	},
	{
		Name:      "reflect.call",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if len(args) == 0 {
				return dune.NullValue, fmt.Errorf("expected the function name")
			}
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("argument must be a string, got %s", args[0].TypeName())
			}

			return vm.RunFunc(args[0].String(), args[1:]...)
		},
	},
	{
		Name:      "reflect.getFunction",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("argument must be a string, got %s", args[0].TypeName())
			}

			name := args[0].String()
			fn, ok := vm.Program.Function(name)
			if !ok {
				return dune.NullValue, nil
			}

			v := dune.NewFunction(fn.Index)
			return v, nil
		},
	},
	{
		Name:      "reflect.getFunctionInfo",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Func); err != nil {
				return dune.NullValue, err
			}

			i := args[0].ToFunction()

			if i < 0 || i > len(vm.Program.Functions)-1 {
				return dune.NullValue, fmt.Errorf("index out of range")
			}

			f := vm.Program.Functions[i]

			p := program{vm.Program}

			return dune.NewObject(functionInfo{f, p}), nil
		},
	},
	{
		Name:      "reflect.runFunc",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l < 1 {
				return dune.NullValue, fmt.Errorf("expected at least 1 parameter, got %d", l)
			}

			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("argument must be a string, got %s", args[0].TypeName())
			}

			name := args[0].String()

			v, err := vm.RunFunc(name, args[1:]...)
			if err != nil {
				return dune.NullValue, err
			}

			return v, nil
		},
	},
}
View Source
var Regex = []dune.NativeFunction{
	{
		Name:      "regex.match",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			ok, err := regexp.MatchString(args[0].String(), args[1].String())
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewBool(ok), nil
		},
	},
	{
		Name:      "regex.split",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return dune.NullValue, err
			}

			matches := r.Split(args[1].String(), -1)

			ln := len(matches)
			result := make([]dune.Value, ln)
			for i := 0; i < ln; i++ {
				result[i] = dune.NewString(matches[i])
			}

			return dune.NewArrayValues(result), nil
		},
	},
	{
		Name:      "regex.findAllStringSubmatchIndex",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return dune.NullValue, err
			}
			if err := ValidateOptionalArgs(args, dune.String, dune.String, dune.Int); err != nil {
				return dune.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return dune.NullValue, err
			}

			var i int
			if len(args) == 3 {
				i = int(args[2].ToInt())
			} else {
				i = -1
			}

			matches := r.FindAllStringSubmatchIndex(args[1].String(), i)

			var result []dune.Value
			for _, v := range matches {
				a := []dune.Value{dune.NewInt(v[0]), dune.NewInt(v[1])}
				result = append(result, dune.NewArrayValues(a))
			}

			return dune.NewArrayValues(result), nil
		},
	},
	{
		Name:      "regex.findAllString",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return dune.NullValue, err
			}
			if err := ValidateOptionalArgs(args, dune.String, dune.String, dune.Int); err != nil {
				return dune.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return dune.NullValue, err
			}

			var i int
			if len(args) == 3 {
				i = int(args[2].ToInt())
			} else {
				i = -1
			}

			matches := r.FindAllString(args[1].String(), i)

			var result []dune.Value

			for _, v := range matches {
				result = append(result, dune.NewString(v))
			}

			return dune.NewArrayValues(result), nil
		},
	},
	{
		Name:      "regex.findAllStringSubmatch",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return dune.NullValue, err
			}
			if err := ValidateOptionalArgs(args, dune.String, dune.String, dune.Int); err != nil {
				return dune.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return dune.NullValue, err
			}

			var i int
			if len(args) == 3 {
				i = int(args[2].ToInt())
			} else {
				i = -1
			}

			matches := r.FindAllStringSubmatch(args[1].String(), i)

			var result []dune.Value

			for _, v := range matches {
				var subResult []dune.Value
				for _, sv := range v {
					subResult = append(subResult, dune.NewString(sv))
				}
				result = append(result, dune.NewArrayValues(subResult))
			}

			return dune.NewArrayValues(result), nil
		},
	},
	{
		Name:      "regex.replaceAllString",
		Arguments: 3,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.String, dune.String); err != nil {
				return dune.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return dune.NullValue, err
			}

			result := r.ReplaceAllString(args[1].String(), args[2].String())

			return dune.NewString(result), nil
		},
	},
}
View Source
var Router = []dune.NativeFunction{
	{
		Name: "routing.newRouter",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			r := newRouter()
			return dune.NewObject(r), nil
		},
	},
}
View Source
var Runtime = []dune.NativeFunction{
	{
		Name: "->runtime.ErrFunctionNotExist",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewString(dune.ErrFunctionNotExist.Error()), nil
		},
	},
	{
		Name:        "panic",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			panic(args[0].String())
		},
	},
	{
		Name: "->runtime.version",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewString(dune.VERSION), nil
		},
	},
	{
		Name: "runtime.typeDefs",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return dune.NullValue, err
			}
			s := dune.TypeDefs()
			return dune.NewString(s), nil
		},
	},
	{
		Name:        "runtime.runFunc",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if len(args) == 0 {
				return dune.NullValue, fmt.Errorf("expected at least the function name")
			}

			a := args[0]

			switch a.Type {
			case dune.String:
				return vm.RunFunc(a.String(), args[1:]...)
			case dune.Func:
				return vm.RunFuncIndex(a.ToFunction(), args[1:]...)
			default:
				return dune.NullValue, fmt.Errorf("invalid function argument type, got %v", a.Type)
			}
		},
	},
	{
		Name:        "->runtime.context",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return vm.Context, nil
		},
	},
	{
		Name:        "->runtime.StdLib",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return vm.StdLib, nil
		},
	},
	{
		Name:        "runtime.setContext",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			vm.Context = args[0]
			return dune.NullValue, nil
		},
	},
	{
		Name:        "runtime.attribute",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			return programAttribute(vm.Program, args[0].String()), nil
		},
	},
	{
		Name:        "runtime.hasAttribute",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			return programHasAttribute(vm.Program, args[0].String()), nil
		},
	},
	{
		Name:        "runtime.resources",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			res := vm.Program.Resources
			if res == nil {
				return dune.NewArray(0), nil
			}

			a := make([]dune.Value, len(res))

			i := 0
			for k := range res {
				a[i] = dune.NewString(k)
				i++
			}

			return dune.NewArrayValues(a), nil
		},
	},
	{
		Name:        "runtime.resource",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			name := args[0].String()

			res := vm.Program.Resources
			if res == nil {
				return dune.NullValue, nil
			}

			v, ok := res[name]
			if !ok {
				return dune.NullValue, nil
			}

			return dune.NewBytes(v), nil
		},
	},
	{
		Name:        "->runtime.hasResources",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			res := vm.Program.Resources
			if len(res) == 0 {
				return dune.FalseValue, nil
			}

			return dune.TrueValue, nil
		},
	},
	{
		Name:        "runtime.setFileSystem",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			fs, ok := args[0].ToObject().(*FileSystemObj)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a fileSystem, got %s", args[0].TypeName())
			}
			vm.FileSystem = fs.FS
			return dune.NullValue, nil
		},
	},
	{
		Name:      "runtime.newFinalizable",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]

			fin, err := newFinalizable(v, vm)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(fin), nil
		},
	},
	{
		Name:      "defer",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]

			fin, err := newFinalizable(v, vm)
			if err != nil {
				return dune.NullValue, err
			}

			vm.SetFinalizer(fin)
			return dune.NullValue, nil
		},
	},
	{
		Name:      "runtime.setFinalizer",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]

			if v.Type != dune.Object {
				return dune.NullValue, fmt.Errorf("the value is not a finalizer")
			}

			fin, ok := v.ToObject().(dune.Finalizable)
			if !ok {
				return dune.NullValue, fmt.Errorf("the value is not a finalizer")
			}
			vm.SetFinalizer(fin)
			return dune.NullValue, nil
		},
	},
	{
		Name:        "->runtime.OS",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewString(runtime.GOOS), nil
		},
	},
	{
		Name:        "->runtime.executable",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewString(vm.Program.Name), nil
		},
	},
	{
		Name:        "->runtime.nativeExecutable",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			ex, err := os.Executable()
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewString(ex), nil
		},
	},
	{
		Name:      "runtime.newVM",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l == 0 || l > 2 {
				return dune.NullValue, fmt.Errorf("expected 1 or 2 params, got %d", l)
			}

			if args[0].Type != dune.Object {
				return dune.NullValue, fmt.Errorf("argument 1 must be a program, got %s", args[0].TypeName())
			}
			p, ok := args[0].ToObject().(*program)
			if !ok {
				return dune.NullValue, fmt.Errorf("argument 1 must be a program, got %s", args[0].TypeName())
			}

			var m *dune.VM

			if l == 1 {
				m = dune.NewVM(p.prog)
			} else {
				switch args[1].Type {
				case dune.Undefined, dune.Null:
					m = dune.NewVM(p.prog)
				case dune.Array:
					m = dune.NewInitializedVM(p.prog, args[1].ToArray())
				default:
					return dune.NullValue, fmt.Errorf("argument 2 must be an array, got %s", args[1].TypeName())
				}
			}

			m.Stdout = vm.Stdout
			m.Stdin = vm.Stdin
			m.Stderr = vm.Stderr

			m.Now = vm.Now

			m.Localizer = vm.Localizer
			m.Language = vm.Language
			m.Location = vm.Location

			m.MaxAllocations = vm.MaxAllocations
			m.MaxFrames = vm.MaxFrames
			m.MaxSteps = vm.MaxSteps

			if err := m.AddSteps(vm.Steps()); err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&libVM{m}), nil
		},
	},
	{
		Name:        "->runtime.vm",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewObject(&libVM{vm}), nil
		},
	},
	{
		Name:        "runtime.resetSteps",
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			vm.ResetSteps()
			return dune.NullValue, nil
		},
	},
	{
		Name:      "runtime.stackTrace",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := strings.Join(vm.Stacktrace(), "\n")
			return dune.NewString(s), nil
		},
	},
}
View Source
var SQL = []dune.NativeFunction{
	{
		Name:        "sql.open",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l < 2 || l > 3 {
				return dune.NullValue, fmt.Errorf("expected 2 or 3 parameters, got %d", l)
			}

			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("argument 1 must be a string, got %s", args[0].TypeName())
			}

			if args[1].Type != dune.String {
				return dune.NullValue, fmt.Errorf("argument 2 must be a string, got %s", args[1].TypeName())
			}

			driver := args[0].String()
			connString := args[1].String()

			db, err := dbx.Open(driver, connString)
			if err != nil {
				return dune.NullValue, err
			}

			db.SetMaxOpenConns(500)
			db.SetMaxIdleConns(250)
			db.SetConnMaxLifetime(5 * time.Minute)

			if l == 3 {
				if args[2].Type != dune.String {
					return dune.NullValue, fmt.Errorf("argument 3 must be a string, got %s", args[2].TypeName())
				}
				name := args[2].String()
				if err := validateDatabaseName(name); err != nil {
					return dune.NullValue, err
				}
				db = db.Open(name)
			}

			ldb := newDB(db)
			vm.SetGlobalFinalizer(ldb)
			return dune.NewObject(ldb), nil
		},
	},
	{
		Name:        "sql.setWhitelistFuncs",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Array); err != nil {
				return dune.NullValue, err
			}

			a := args[0].ToArray()

			sqx.ValidFuncs = make([]string, len(a))

			for i, v := range a {
				if v.Type != dune.String {
					return dune.NullValue, fmt.Errorf("invalid value at index %d. It's a %s", i, v.TypeName())
				}
				sqx.ValidFuncs[i] = v.String()
			}

			return dune.NullValue, nil
		},
	},
	{
		Name:      "sql.getSelectMainTable",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			var q sqx.Query
			switch t := args[0].ToObjectOrNil().(type) {
			case selectQuery:
				q = t.query
			default:
				return dune.NullValue, fmt.Errorf("not a select query, got %v", args[0].TypeName())
			}

			table := sqx.GetSelectMainTable(q)

			if table == nil {
				return dune.NullValue, nil
			}

			r := make(map[dune.Value]dune.Value)

			r[dune.NewString("name")] = dune.NewString(table.Name)

			if table.Database != "" {
				r[dune.NewString("database")] = dune.NewString(table.Database)
			}

			if table.Alias != "" {
				r[dune.NewString("alias")] = dune.NewString(table.Alias)
			}

			if table.LeftJoin {
				r[dune.NewString("leftJoin")] = dune.TrueValue
			}

			return dune.NewMapValues(r), nil
		},
	},
	{
		Name:      "sql.getTables",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			var q sqx.Query
			switch t := args[0].ToObjectOrNil().(type) {
			case selectQuery:
				q = t.query
			case deleteQuery:
				q = t.query
			case insertQuery:
				q = t.query
			case updateQuery:
				q = t.query
			default:
				return dune.NullValue, fmt.Errorf("expected argument to be Query, got %v", args[0].TypeName())
			}

			tables := sqx.GetTables(q)

			result := make([]dune.Value, len(tables))

			for i, t := range tables {
				r := make(map[dune.Value]dune.Value)
				r[dune.NewString("name")] = dune.NewString(t.Name)
				if t.Database != "" {
					r[dune.NewString("database")] = dune.NewString(t.Database)
				}
				if t.Alias != "" {
					r[dune.NewString("alias")] = dune.NewString(t.Alias)
				}
				if t.LeftJoin {
					r[dune.NewString("leftJoin")] = dune.TrueValue
				}
				result[i] = dune.NewMapValues(r)
			}

			return dune.NewArrayValues(result), nil
		},
	},
	{
		Name:      "sql.getFilterColumns",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			var q sqx.Query
			switch t := args[0].ToObjectOrNil().(type) {
			case selectQuery:
				q = t.query
			case deleteQuery:
				q = t.query
			case insertQuery:
				q = t.query
			case updateQuery:
				q = t.query
			default:
				return dune.NullValue, fmt.Errorf("expected argument to be Query, got %v", args[0].TypeName())
			}

			columns := sqx.GetFilterColumns(q)

			result := make([]dune.Value, len(columns))

			for i, t := range columns {
				r := make(map[dune.Value]dune.Value, len(columns))
				r[dune.NewString("name")] = dune.NewString(t.Name)
				if t.Table != "" {
					r[dune.NewString("table")] = dune.NewString(t.Table)
				}
				result[i] = dune.NewMapValues(r)
			}

			return dune.NewArrayValues(result), nil
		},
	},
	{
		Name:      "sql.validateSelect",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object, dune.Map); err != nil {
				return dune.NullValue, err
			}

			s, ok := args[0].ToObjectOrNil().(selectQuery)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected argument to be SelectQuery, got %v", args[0].TypeName())
			}

			opt := &sqx.ValidateOptions{}

			optMap := args[1].ToMap().Map

			tablesVal, ok := optMap[dune.NewString("tables")]
			if !ok {
				return dune.NullValue, fmt.Errorf("invalid options: expected tables")
			}

			if tablesVal.Type != dune.Map {
				return dune.NullValue, fmt.Errorf("invalid tables value: %v", tablesVal)
			}

			for k, v := range tablesVal.ToMap().Map {
				if k.Type != dune.String {
					return dune.NullValue, fmt.Errorf("invalid table name: %v", k)
				}

				if v.Type != dune.Array {
					return dune.NullValue, fmt.Errorf("invalid tables value for %s: %v", k, v)
				}

				colValues := v.ToArray()

				cols := make([]string, len(colValues))

				for i, c := range colValues {
					if c.Type != dune.String {
						return dune.NullValue, fmt.Errorf("invalid column value for %s: %v", k, c)
					}
					cols[i] = c.String()
				}

				opt.Tables = append(opt.Tables, &sqx.ValidateTable{
					Name:    k.String(),
					Columns: cols,
				})
			}

			err := sqx.ValidateSelect(s.query, opt)

			return dune.NullValue, err
		},
	},
	{
		Name:      "sql.newSelect",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := selectQuery{&sqx.SelectQuery{}}
			return dune.NewObject(s), nil
		},
	},
	{
		Name:      "sql.parse",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l == 0 {
				return dune.NullValue, fmt.Errorf("expected at least one argument, got %d", l)
			}

			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument to be a string, got %v", args[0].Type)
			}

			v := args[0].String()

			var params []interface{}
			if l > 1 {
				params = getSqlParams(args[1:])
			}

			q, err := sqx.Parse(v, params...)
			if err != nil {
				return dune.NullValue, err
			}
			obj, err := getQueryObject(q)
			if err != nil {
				return dune.NullValue, err
			}
			return obj, nil
		},
	},
	{
		Name:      "sql.select",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			switch l {
			case 0:
				s := selectQuery{&sqx.SelectQuery{}}
				return dune.NewObject(s), nil
			}

			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument to be a string, got %v", args[0].Type)
			}

			v := args[0].String()
			var params []interface{}
			if l > 1 {
				params = getSqlParams(args[1:])
			}

			q, err := sqx.Select(v, params...)
			if err != nil {
				return dune.NullValue, err
			}

			s := selectQuery{q}
			return dune.NewObject(s), nil
		},
	},
	{
		Name:      "sql.where",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			switch l {
			case 0:
				s := selectQuery{&sqx.SelectQuery{}}
				return dune.NewObject(s), nil
			}

			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected argument to be a string, got %v", args[0].Type)
			}

			v := args[0].String()

			var params []interface{}
			if l > 1 {
				params = make([]interface{}, l-1)
				for i, v := range args[1:] {
					params[i] = v.Export(0)
				}
			}

			q, err := sqx.Where(v, params...)
			if err != nil {
				return dune.NullValue, err
			}

			s := selectQuery{q}
			return dune.NewObject(s), nil
		},
	},
}
View Source
var STMP = []dune.NativeFunction{
	{
		Name:      "smtp.newMessage",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewObject(&SmtMessage{}), nil
		},
	},
	{
		Name:        "smtp.send",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Object, dune.String, dune.String, dune.String, dune.Int, dune.Bool); err != nil {
				return dune.NullValue, err
			}

			msg, ok := args[0].ToObject().(*SmtMessage)
			if !ok {
				return dune.NullValue, fmt.Errorf("expected a mail message, got %s", args[0].TypeName())
			}

			var err error
			var user, smtPasswd, host string
			var port int
			var skipVerify bool

			switch len(args) {
			case 5:
				user = args[1].String()
				smtPasswd = args[2].String()
				host = args[3].String()
				port = int(args[4].ToInt())

			case 6:
				user = args[1].String()
				smtPasswd = args[2].String()
				host = args[3].String()
				port = int(args[4].ToInt())
				skipVerify = args[5].ToBool()
			default:
				return dune.NullValue, fmt.Errorf("expected 4 or 5 params, got %d", len(args))
			}

			err = msg.Send(user, smtPasswd, host, port, skipVerify)
			return dune.NullValue, err
		},
	},
}
View Source
var Secure = []dune.NativeFunction{
	{
		Name:        "secure.newObject",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			ln := len(args)
			if ln < 2 || ln > 3 {
				return dune.NullValue, fmt.Errorf("expected 2 or 3 arguments, got %d", ln)
			}

			if args[0].Type != dune.Bool {
				return dune.NullValue, fmt.Errorf("expected argument 1 to be bool, got %s", args[0].Type)
			}

			if args[1].Type != dune.Bool {
				return dune.NullValue, fmt.Errorf("expected argument 2 to be bool, got %s", args[1].Type)
			}
			p := &SecureObject{
				values: make(map[string]dune.Value),
				read:   args[0].ToBool(),
				write:  args[1].ToBool(),
			}

			if ln == 3 {
				for k, v := range args[2].ToMap().Map {
					p.values[k.String()] = v
				}
			}

			return dune.NewObject(p), nil
		},
	},
}
View Source
var StdFuncs = []dune.NativeFunction{
	{
		Name: "->stdlib",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return vm.StdLib, nil
		},
	},
	{
		Name:        "runtime.newStdLib",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			ln := len(args)
			if ln != 0 {
				return dune.NullValue, fmt.Errorf("expected no arguments, got %d", ln)
			}

			s := &StdLib{libs: make(map[string]*StdProgram)}

			return dune.NewObject(s), nil
		},
	},
}
View Source
var Strconv = []dune.NativeFunction{
	{
		Name:      "strconv.formatRef",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Int, dune.Int); err != nil {
				return dune.NullValue, err
			}

			s := EncodeCustomBase34(uint64(args[0].ToInt()))

			var size int
			if len(args) > 1 {
				size = int(args[1].ToInt())
				s += customBase34Delimiter + RandomAlphanumeric(size)
			}

			return dune.NewString(strings.ToUpper(s)), nil
		},
	},
	{
		Name:      "strconv.parseRef",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			s := args[0].String()

			i := strings.IndexRune(s, 'L')
			if i != -1 {
				s = s[:i]
			}

			v := DecodeCustomBase34(s)
			return dune.NewInt64(int64(v)), nil
		},
	},
	{
		Name:      "strconv.formatInt",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int, dune.Int); err != nil {
				return dune.NullValue, err
			}
			v := strconv.FormatInt(args[0].ToInt(), int(args[1].ToInt()))
			return dune.NewString(v), nil
		},
	},
	{
		Name:      "strconv.parseInt",
		Arguments: 3,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.Int, dune.Int); err != nil {
				return dune.NullValue, err
			}
			v, err := strconv.ParseInt(args[0].String(), int(args[1].ToInt()), int(args[2].ToInt()))
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewInt64(v), nil
		},
	},
	{
		Name:      "strconv.formatCustomBase34",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}
			v := EncodeCustomBase34(uint64(args[0].ToInt()))
			return dune.NewString(v), nil
		},
	},
	{
		Name:      "strconv.parseCustomBase34",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			v := DecodeCustomBase34(args[0].String())
			return dune.NewInt64(int64(v)), nil
		},
	},
}
View Source
var Strings = []dune.NativeFunction{
	{
		Name:      "strings.sanitize",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.Bool); err != nil {
				return dune.NullValue, err
			}

			if err := ValidateArgRange(args, 1, 2); err != nil {
				return dune.NullValue, err
			}

			s := args[0].String()

			var dashes bool
			if len(args) == 2 {
				dashes = args[1].ToBool()
			}

			var lastDash bool
			buf := make([]rune, 0, len(s))
			for _, r := range s {
				if isAlphanumeric(r, 1) {
					buf = append(buf, r)
					lastDash = false
				} else {
					if dashes && !lastDash {
						buf = append(buf, '-')
					}
					lastDash = true
				}
			}

			return dune.NewString(string(buf)), nil
		},
	},
	{
		Name:      "strings.newReader",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			r := strings.NewReader(args[0].String())

			return dune.NewObject(&reader{r}), nil
		},
	},
	{
		Name:      "String.prototype.runeAt",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			if a.Type != dune.Int {
				return dune.NullValue, fmt.Errorf("expected int, got %s", a.Type)
			}

			i := int(a.ToInt())

			if i < 0 {
				return dune.NullValue, vm.NewError("Index out of range in string")
			}

			v := utf8string.NewString(this.String())

			if int(i) >= v.RuneCount() {
				return dune.NullValue, vm.NewError("Index out of range in string")
			}

			return dune.NewRune(v.At(int(i))), nil
		},
	},
	{
		Name:      "strings.equalFold",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]
			b := args[1]

			switch a.Type {
			case dune.Null, dune.Undefined:
				switch b.Type {
				case dune.Null, dune.Undefined:
					return dune.TrueValue, nil
				case dune.String:
					return dune.FalseValue, nil
				default:
					return dune.NullValue, fmt.Errorf("expected argument 2 to be string got %v", b.Type)
				}
			case dune.String:
			default:
				return dune.NullValue, fmt.Errorf("expected argument 1 to be string got %v", a.Type)
			}

			switch b.Type {
			case dune.Null, dune.Undefined:

				return dune.FalseValue, nil
			case dune.String:
			default:
				return dune.NullValue, fmt.Errorf("expected argument 2 to be string got %v", b.Type)
			}

			eq := strings.EqualFold(a.String(), b.String())
			return dune.NewBool(eq), nil
		},
	},
	{
		Name:      "strings.isIdent",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]
			switch v.Type {
			case dune.String, dune.Rune:
			default:
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", v.TypeName())
			}

			b := IsIdent(v.String())
			return dune.NewBool(b), nil
		},
	},
	{
		Name:      "strings.isAlphanumeric",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]
			switch v.Type {
			case dune.String, dune.Rune:
			default:
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", v.TypeName())
			}
			b := IsAlphanumeric(v.String())
			return dune.NewBool(b), nil
		},
	},
	{
		Name:      "strings.isAlphanumericIdent",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]
			switch v.Type {
			case dune.String, dune.Rune:
			default:
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", v.TypeName())
			}
			b := IsAlphanumericIdent(v.String())
			return dune.NewBool(b), nil
		},
	},
	{
		Name:      "strings.isNumeric",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]
			switch v.Type {
			case dune.String, dune.Rune:
			case dune.Int, dune.Float:
				return dune.TrueValue, nil
			default:
				return dune.FalseValue, nil
			}

			b := IsNumeric(v.String())
			return dune.NewBool(b), nil
		},
	},
	{
		Name:      "strings.isEmpty",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]
			switch v.Type {
			case dune.Null, dune.Undefined:
				return dune.TrueValue, nil
			case dune.String, dune.Rune:
				return dune.NewBool(v.String() == ""), nil
			default:
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", v.TypeName())
			}
		},
	},
	{
		Name:      "strings.isChar",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]
			switch v.Type {
			case dune.String, dune.Rune:
			default:
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}

			s := v.String()
			if len(s) != 1 {
				return dune.FalseValue, nil
			}

			r := rune(s[0])
			if 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
				return dune.TrueValue, nil
			}

			return dune.FalseValue, nil
		},
	},
	{
		Name:      "strings.isDigit",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			v := args[0]
			switch v.Type {
			case dune.String, dune.Rune:
			default:
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}

			s := v.String()
			if len(s) != 1 {
				return dune.FalseValue, nil
			}

			r := rune(s[0])
			if '0' <= r && r <= '9' {
				return dune.TrueValue, nil
			}

			return dune.FalseValue, nil
		},
	},
	{
		Name:      "strings.sort",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.Array {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be array, got %s", args[0].TypeName())
			}

			a := args[0].ToArray()

			s := make([]string, len(a))

			for i, v := range a {
				s[i] = v.String()
			}

			sort.Strings(s)

			for i, v := range s {
				a[i] = dune.NewString(v)
			}

			return dune.NullValue, nil
		},
	},
	{
		Name:      "strings.repeat",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String, dune.Int); err != nil {
				return dune.NullValue, err
			}

			a := args[0].String()
			b := int(args[1].ToInt())

			values := make([]string, b)

			for i := 0; i < b; i++ {
				values[i] = a
			}

			s := strings.Join(values, "")
			return dune.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.replaceRegex",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			exp := args[0].String()
			repl := args[1].String()
			s := this.String()
			r, err := regexp.Compile(exp)
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewString(r.ReplaceAllString(s, repl)), nil
		},
	},
	{
		Name: "String.prototype.toLower",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := this.String()
			return dune.NewString(strings.ToLower(s)), nil
		},
	},
	{
		Name: "String.prototype.toUpper",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := this.String()
			return dune.NewString(strings.ToUpper(s)), nil
		},
	},
	{
		Name: "String.prototype.toTitle",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := this.String()
			if len(s) > 0 {
				s = strings.ToUpper(s[:1]) + s[1:]
			}
			return dune.NewString(s), nil
		},
	},
	{
		Name: "String.prototype.toUntitle",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := this.String()
			if len(s) > 0 {
				s = strings.ToLower(s[:1]) + s[1:]
			}
			return dune.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.replace",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l < 2 || l > 3 {
				return dune.NullValue, fmt.Errorf("expected 2 or 3 arguments, got %d", len(args))
			}

			oldStr := args[0].String()
			newStr := args[1].String()

			times := -1
			if l > 2 {
				times = int(args[2].ToInt())
			}

			s := this.String()
			return dune.NewString(strings.Replace(s, oldStr, newStr, times)), nil
		},
	},
	{
		Name:      "String.prototype.split",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			sep := args[0].String()

			s := this.String()

			parts := Split(s, sep)
			res := make([]dune.Value, len(parts))

			for i, v := range parts {
				res[i] = dune.NewString(v)
			}
			return dune.NewArrayValues(res), nil
		},
	},
	{
		Name:      "String.prototype.splitEx",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			sep := args[0].String()

			s := this.String()

			parts := strings.Split(s, sep)
			res := make([]dune.Value, len(parts))

			for i, v := range parts {
				res[i] = dune.NewString(v)
			}
			return dune.NewArrayValues(res), nil
		},
	},
	{
		Name:      "String.prototype.trim",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var cutset string
			switch len(args) {
			case 0:
				cutset = " \t\r\n"
			case 1:
				cutset = args[0].String()
			default:
				return dune.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", len(args))
			}
			s := this.String()
			return dune.NewString(strings.Trim(s, cutset)), nil
		},
	},
	{
		Name:      "String.prototype.trimLeft",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var cutset string
			switch len(args) {
			case 0:
				cutset = " \t\r\n"
			case 1:
				cutset = args[0].String()
			default:
				return dune.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", len(args))
			}
			s := this.String()
			return dune.NewString(strings.TrimLeft(s, cutset)), nil
		},
	},
	{
		Name:      "String.prototype.trimRight",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var cutset string
			switch len(args) {
			case 0:
				cutset = " \t\r\n"
			case 1:
				cutset = args[0].String()
			default:
				return dune.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", len(args))
			}
			s := this.String()
			return dune.NewString(strings.TrimRight(s, cutset)), nil
		},
	},
	{
		Name:      "String.prototype.trimPrefix",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			s := this.String()
			prefix := args[0].String()
			s = strings.TrimPrefix(s, prefix)
			return dune.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.trimSuffix",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			s := this.String()
			prefix := args[0].String()
			s = strings.TrimSuffix(s, prefix)
			return dune.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.substring",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := this.String()

			switch len(args) {
			case 1:
				v1 := args[0]
				if v1.Type != dune.Int {
					return dune.NullValue, fmt.Errorf("expected int, got %s", v1.Type)
				}
				a := int(v1.ToInt())
				if a < 0 || a > len(s) {
					return dune.NullValue, fmt.Errorf("index out of range: %d of %d", a, len(s))
				}
				return dune.NewString(s[a:]), nil
			case 2:
				v1 := args[0]
				if v1.Type != dune.Int {
					return dune.NullValue, fmt.Errorf("expected int, got %s", v1.Type)
				}
				v2 := args[1]
				if v2.Type != dune.Int {
					return dune.NullValue, fmt.Errorf("expected int, got %s", v2.Type)
				}
				l := len(s)
				a := int(v1.ToInt())
				b := int(v2.ToInt())
				if a < 0 || a > l {
					return dune.NullValue, fmt.Errorf("start out of range")
				}
				if b < a || b > l {
					return dune.NullValue, fmt.Errorf("end out of range")
				}
				return dune.NewString(s[a:b]), nil
			}

			return dune.NullValue, fmt.Errorf("expected 1 or 2 parameters")
		},
	},
	{
		Name:      "String.prototype.runeSubstring",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := this.String()

			switch len(args) {
			case 1:
				v1 := args[0]
				if v1.Type != dune.Int {
					return dune.NullValue, fmt.Errorf("expected int, got %s", v1.Type)
				}
				a := int(v1.ToInt())
				if a < 0 || a > len(s) {
					return dune.NullValue, fmt.Errorf("index out of range: %d of %d", a, len(s))
				}
				return dune.NewString(substring(s, a, -1)), nil
			case 2:
				v1 := args[0]
				if v1.Type != dune.Int {
					return dune.NullValue, fmt.Errorf("expected int, got %s", v1.Type)
				}
				v2 := args[1]
				if v2.Type != dune.Int {
					return dune.NullValue, fmt.Errorf("expected int, got %s", v2.Type)
				}
				l := len(s)
				a := int(v1.ToInt())
				b := int(v2.ToInt())
				if a < 0 || a > l {
					return dune.NullValue, fmt.Errorf("start out of range")
				}
				if b < a || b > l {
					return dune.NullValue, fmt.Errorf("end out of range")
				}
				return dune.NewString(substring(s, a, b)), nil
			}

			return dune.NullValue, fmt.Errorf("expected 1 or 2 parameters")
		},
	},
	{
		Name:      "String.prototype.take",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.Int {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be int, got %s", args[0].TypeName())
			}

			s := this.String()
			i := int(args[0].ToInt())

			if i < 0 {
				return dune.NullValue, fmt.Errorf("index out of range: %d", i)
			}
			if len(s) > i {
				s = s[:i]
			}
			return dune.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.hasPrefix",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			v := args[0].String()
			s := this.String()
			return dune.NewBool(strings.HasPrefix(s, v)), nil
		},
	},
	{
		Name:      "String.prototype.hasSuffix",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			v := args[0].String()
			s := this.String()
			return dune.NewBool(strings.HasSuffix(s, v)), nil
		},
	}, {
		Name:      "String.prototype.cut",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			ln := len(args)

			s := this.String()
			var i int
			if len(args) > 1 {
				i = int(args[1].ToInt())
				if i < 0 || i > len(s) {
					res := make([]dune.Value, 2)
					res[0] = dune.NewString(s)
					res[1] = dune.NewString("")
					return dune.NewArrayValues(res), nil
				}
				s = s[i:]
			}

			if ln > 1 {
				if args[1].Type != dune.Int {
					return dune.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", args[1].TypeName())
				}
			}

			var width int
			var index int

			switch args[0].Type {
			case dune.String:
				separator := args[0].String()
				width = len(separator)
				index = strings.Index(s, separator) + i
			case dune.Rune:
				separator := args[0].ToRune()
				width = runewidth.RuneWidth(separator)
				index = strings.IndexRune(s, separator) + i
			default:
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}

			if index == -1 {
				res := make([]dune.Value, 2)
				res[0] = dune.NewString(s)
				res[1] = dune.NewString("")
				return dune.NewArrayValues(res), nil
			}

			res := make([]dune.Value, 2)
			res[0] = dune.NewString(s[0:index])
			res[1] = dune.NewString(s[index+width:])
			return dune.NewArrayValues(res), nil
		},
	},
	{
		Name:      "String.prototype.indexOf",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			s := this.String()
			var i int
			if len(args) > 1 {
				vStart := args[1]
				if vStart.Type != dune.Int {
					return dune.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", vStart.TypeName())
				}
				i = int(vStart.ToInt())
				if i < 0 || i > len(s) {
					return dune.NullValue, fmt.Errorf("index out of range")
				}
				s = s[i:]
			}

			switch args[0].Type {
			case dune.String:
				return dune.NewInt(strings.Index(s, args[0].String())), nil
			case dune.Rune:
				return dune.NewInt(strings.IndexRune(s, args[0].ToRune())), nil
			default:
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
		},
	},
	{
		Name:      "String.prototype.lastIndexOf",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			ln := len(args)

			if ln > 0 {
				if args[0].Type != dune.String {
					return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
				}
			}

			if ln > 1 {
				if args[1].Type != dune.Int {
					return dune.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", args[1].TypeName())
				}
			}

			sep := args[0].String()
			s := this.String()

			if len(args) > 1 {
				i := int(args[1].ToInt())
				if i > len(s) {
					return dune.NullValue, fmt.Errorf("index out of range")
				}
				s = s[i:]
			}
			return dune.NewInt(strings.LastIndex(s, sep)), nil
		},
	},
	{
		Name:      "String.prototype.contains",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			switch args[0].Type {
			case dune.String, dune.Rune:
			default:
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}

			sep := args[0].String()
			s := this.String()
			return dune.NewBool(strings.Contains(s, sep)), nil
		},
	},
	{
		Name:      "String.prototype.rightPad",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			if args[1].Type != dune.Int {
				return dune.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", args[1].TypeName())
			}
			pad := args[0].String()
			if len(pad) != 1 {
				return dune.NullValue, fmt.Errorf("invalid pad size. Must be one character")
			}
			total := int(args[1].ToInt())
			s := this.String()
			return dune.NewString(rightPad(s, rune(pad[0]), total)), nil
		},
	},
	{
		Name:      "String.prototype.leftPad",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			if args[1].Type != dune.Int {
				return dune.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", args[1].TypeName())
			}

			pad := args[0].String()
			if len(pad) != 1 {
				return dune.NullValue, fmt.Errorf("invalid pad size. Must be one character")
			}
			total := int(args[1].ToInt())
			s := this.String()
			return dune.NewString(leftPad(s, rune(pad[0]), total)), nil
		},
	},
	{
		Name:      "String.prototype.equalFold",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			eq := strings.EqualFold(this.String(), args[0].String())
			return dune.NewBool(eq), nil
		},
	},
}
View Source
var Sunrise = []dune.NativeFunction{
	{
		Name:      "astro.sunRiseSet",
		Arguments: 3,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Float, dune.Float, dune.Object); err != nil {
				return dune.NullValue, err
			}

			lat := args[0].ToFloat()
			long := args[1].ToFloat()

			t, ok := args[2].ToObject().(TimeObj)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}

			d := time.Time(t)

			rise, set := sunrise.SunriseSunset(lat, long, d.Year(), d.Month(), d.Day())

			loc := GetLocation(vm)

			m := make(map[dune.Value]dune.Value, 2)

			m[dune.NewString("rise")] = dune.NewObject(TimeObj(rise.In(loc)))
			m[dune.NewString("set")] = dune.NewObject(TimeObj(set.In(loc)))

			return dune.NewMapValues(m), nil

		},
	},
}
View Source
var Sync = []dune.NativeFunction{
	{
		Name:        "sync.withDeadline",
		Arguments:   2,
		Permissions: []string{"sync"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d, err := ToDuration(args[0])
			if err != nil {
				return dune.NullValue, err
			}

			v := args[1]
			switch v.Type {
			case dune.Func:
			case dune.Object:
			default:
				return dune.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
			}

			err = WithDeadline(d, func(dl *Deadline) error {
				obj := dune.NewObject(dl)
				return runAsyncFuncOrClosure(vm, v, obj)
			})

			return dune.NullValue, err
		},
	},
	{
		Name:        "sync.newWaitGroup",
		Arguments:   -1,
		Permissions: []string{"sync"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}

			wg := &waitGroup{w: &sync.WaitGroup{}}

			if len(args) == 1 {
				concurrency := int(args[0].ToInt())
				wg.limit = make(chan bool, concurrency)
			}

			return dune.NewObject(wg), nil
		},
	},
	{
		Name:        "sync.newChannel",
		Arguments:   -1,
		Permissions: []string{"sync"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}

			var ch chan dune.Value
			var b int
			if len(args) > 0 {
				b = int(args[0].ToInt())
				ch = make(chan dune.Value, b)
			} else {
				ch = make(chan dune.Value)
			}

			c := &channel{buffer: b, c: ch}
			return dune.NewObject(c), nil
		},
	},
	{
		Name:        "sync.select",
		Arguments:   -1,
		Permissions: []string{"sync"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			argLen := len(args)
			if argLen == 0 || argLen > 2 {
				return dune.NullValue, fmt.Errorf("expected 1 or 2 args, got %d", argLen)
			}

			a := args[0]
			if a.Type != dune.Array {
				return dune.NullValue, fmt.Errorf("expected arg 1 to be an array of channels, got %s", a.TypeName())
			}

			chans := a.ToArray()
			l := len(chans)
			cases := make([]reflect.SelectCase, l)
			for i, c := range chans {
				ch := c.ToObjectOrNil().(*channel)
				if ch == nil {
					return dune.NullValue, fmt.Errorf("invalid channel at index %d", i)
				}
				cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch.c)}
			}

			if argLen == 2 {
				b := args[1]
				if b.Type != dune.Bool {
					return dune.NullValue, fmt.Errorf("expected arg 2 to be a bool, got %s", b.TypeName())
				}
				if b.ToBool() {
					cases = append(cases, reflect.SelectCase{Dir: reflect.SelectDefault})
				}
			}

			i, value, ok := reflect.Select(cases)

			m := make(map[dune.Value]dune.Value, 3)
			m[dune.NewString("index")] = dune.NewInt(i)

			if value.IsValid() {
				m[dune.NewString("value")] = value.Interface().(dune.Value)
			}

			m[dune.NewString("receivedOK")] = dune.NewBool(ok)

			return dune.NewMapValues(m), nil
		},
	},
	{
		Name:        "sync.newMutex",
		Arguments:   0,
		Permissions: []string{"sync"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			m := &mutex{mutex: sync.Mutex{}}
			return dune.NewObject(m), nil
		},
	},

	{
		Name:        "sync.execLocked",
		Arguments:   -1,
		Permissions: []string{"sync"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l < 2 {
				return dune.NullValue, fmt.Errorf("expected at least 2 parameter, got %d", l)
			}

			keyVal := args[0]
			if keyVal.Type != dune.String {
				return dune.NullValue, fmt.Errorf("key must be a string, got %s", keyVal.TypeName())
			}

			m := globalKeyMutex.getMutex(keyVal.String())

			m.Lock()
			defer m.Unlock()

			var retVal dune.Value
			var err error

			switch args[1].Type {
			case dune.Func:
				f := int(args[1].ToFunction())
				retVal, err = vm.RunFuncIndex(f, args[2:]...)
			case dune.Object:
				closure, ok := args[1].ToObject().(*dune.Closure)
				if !ok {
					return dune.NullValue, fmt.Errorf("%v is not a function", args[1].TypeName())
				}
				retVal, err = vm.RunClosure(closure, args[2:]...)

			default:
				return dune.NullValue, fmt.Errorf("argument 1 must be a string (function name), got %s", args[1].TypeName())
			}

			if err != nil {

				return dune.NullValue, vm.WrapError(err)
			}

			return retVal, nil
		},
	},
}
View Source
var TLS = []dune.NativeFunction{
	{
		Name:      "autocert.newCertManager",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return dune.NullValue, err
			}

			var cache *autocertCache

			ln := len(args)
			if ln < 2 || ln > 3 {
				return dune.NullValue, fmt.Errorf("expected 2 or 3 arguments, got %d", ln)
			}

			if args[0].Type != dune.String {
				return dune.NullValue, fmt.Errorf("invalid cache directory: %s", args[0].TypeName())
			}

			cacheDir := args[0].String()

			var hostPolicy autocert.HostPolicy
			switch args[1].Type {
			case dune.Array:
				domainValues := args[1].ToArray()
				domains := make([]string, len(domainValues))
				for i, v := range domainValues {
					domains[i] = v.String()
				}
				hostPolicy = autocert.HostWhitelist(domains...)

			case dune.Func:
				hostPolicy = func(ctx context.Context, host string) error {
					vm = vm.CloneInitialized(vm.Program, vm.Globals())
					_, err := vm.RunFuncIndex(args[1].ToFunction(), dune.NewString(host))
					return err
				}

			case dune.Object:
				c, ok := args[1].ToObjectOrNil().(*dune.Closure)
				if !ok {
					return dune.NullValue, fmt.Errorf("%v is not a function", args[1].TypeName())
				}
				hostPolicy = func(ctx context.Context, host string) error {
					vm = vm.CloneInitialized(vm.Program, vm.Globals())
					_, err := vm.RunClosure(c, dune.NewString(host))
					return err
				}

			default:
				return dune.NullValue, fmt.Errorf("invalid domains or hostPolicy: %s", args[1].TypeName())
			}

			if ln == 3 {
				var ok bool
				cache, ok = args[2].ToObjectOrNil().(*autocertCache)
				if !ok {
					return dune.NullValue, fmt.Errorf("invalid cache: %s", args[2].TypeName())
				}
			}

			if cache == nil {
				cache = &autocertCache{fs: vm.FileSystem}
			}

			cache.dir = cacheDir

			m := autocert.Manager{
				Cache:      cache,
				Prompt:     autocert.AcceptTOS,
				HostPolicy: hostPolicy,
			}

			cm := &certManager{&m}
			return dune.NewObject(cm), nil
		},
	},
	{
		Name:      "autocert.newFileSystemCache",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			fs, ok := args[0].ToObject().(*FileSystemObj)
			if !ok {
				return dune.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[0])
			}

			c := &autocertCache{fs: fs.FS}
			return dune.NewObject(c), nil
		},
	},
	{
		Name:      "tls.newConfig",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgRange(args, 0, 1); err != nil {
				return dune.NullValue, err
			}
			if err := ValidateOptionalArgs(args, dune.Bool); err != nil {
				return dune.NullValue, err
			}

			tc := &tlsConfig{
				conf: &tls.Config{
					MinVersion:               tls.VersionTLS12,
					CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
					PreferServerCipherSuites: true,
				},
			}

			if len(args) == 1 {
				tc.conf.InsecureSkipVerify = args[0].ToBool()
			}

			return dune.NewObject(tc), nil
		},
	},
	{
		Name:      "tls.generateCert",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
			if err != nil {
				log.Fatal(err)
			}

			template := x509.Certificate{
				SerialNumber: big.NewInt(1),
				Subject: pkix.Name{
					Organization: []string{"Acme Co"},
				},
				NotBefore: time.Now(),
				NotAfter:  time.Now().Add(time.Hour * 24 * 180),

				KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
				ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
				BasicConstraintsValid: true,
			}

			derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
			if err != nil {
				return dune.Value{}, fmt.Errorf("failed to create certificate: %s", err)
			}

			pubBuf := new(bytes.Buffer)
			err = pem.Encode(pubBuf, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
			if err != nil {
				return dune.Value{}, fmt.Errorf("failed to write data to cert.pem: %w", err)
			}

			privBuf := new(bytes.Buffer)
			privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
			if err != nil {
				return dune.Value{}, fmt.Errorf("unable to marshal private key: %w", err)
			}

			err = pem.Encode(privBuf, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
			if err != nil {
				return dune.Value{}, fmt.Errorf("failed to write data to key.pem: %w", err)
			}

			c := &certificate{
				cert: pubBuf.Bytes(),
				key:  privBuf.Bytes(),
			}

			return dune.NewObject(c), nil
		},
	},
}
View Source
var Templates = []dune.NativeFunction{
	{
		Name:      "tsTemplates.exec",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var buf []byte
			var context dune.Value

			l := len(args)
			if l == 0 || l > 2 {
				return dune.NullValue, fmt.Errorf("expected one or two arguments, got %d", l)
			}

			a := args[0]
			switch a.Type {
			case dune.String, dune.Bytes:
				buf = a.ToBytes()
			default:
				return dune.NullValue, ErrInvalidType
			}

			if l == 2 {
				context = args[1]
			}

			return execTemplate(buf, nil, context, vm)
		},
	},
	{
		Name:      "tsTemplates.render",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return render(false, this, args, vm)
		},
	},
	{
		Name:      "tsTemplates.renderHTML",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return render(true, this, args, vm)
		},
	},
	{
		Name:      "tsTemplates.writeHTML",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return writeHTML(true, this, args, vm)
		},
	},
	{
		Name:      "tsTemplates.writeHTMLTemplate",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return writeHTMLTemplate(true, this, args, vm)
		},
	},
	{
		Name:      "tsTemplates.compile",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return compileTemplate(false, this, args, vm)
		},
	},
	{
		Name:      "tsTemplates.compileHTML",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return compileTemplate(true, this, args, vm)
		},
	},
	{
		Name:      "tsTemplates.preprocess",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var path string
			var fs filesystem.FS

			l := len(args)
			switch l {
			case 1:
				path = args[0].String()
				fs = vm.FileSystem
			case 2:
				path = args[0].String()
				fo, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return dune.NullValue, fmt.Errorf("expected a fileSystem, got %s", args[0].TypeName())
				}
				fs = fo.FS
			default:
				return dune.NullValue, fmt.Errorf("expected one or two arguments, got %d", l)
			}

			buf, err := readFile(path, fs, vm)
			if err != nil {
				if os.IsNotExist(err) {
					return dune.NullValue, nil
				}
				return dune.NullValue, fmt.Errorf("error reading template '%s':_ %v", path, err)
			}

			buf, err = processIncludes(path, buf, fs, vm, 0)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewString(string(buf)), nil
		},
	},
}
View Source
var Terminal = []dune.NativeFunction{}/* 118 elements not displayed */
View Source
var Time = []dune.NativeFunction{
	{
		Name: "->time.Monday",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Monday)), nil
		},
	},
	{
		Name: "->time.Tuesday",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Tuesday)), nil
		},
	},
	{
		Name: "->time.Wednesday",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Wednesday)), nil
		},
	},
	{
		Name: "->time.Thursday",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Thursday)), nil
		},
	},
	{
		Name: "->time.Friday",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Friday)), nil
		},
	},
	{
		Name: "->time.Saturday",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Saturday)), nil
		},
	},
	{
		Name: "->time.Sunday",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Sunday)), nil
		},
	},

	{
		Name: "->time.SecMillis",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(secMillis)), nil
		},
	},
	{
		Name: "->time.MinMillis",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(minMillis)), nil
		},
	},
	{
		Name: "->time.HourMillis",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(hourMillis)), nil
		},
	},
	{
		Name: "->time.DayMillis",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(dayMillis)), nil
		},
	},
	{
		Name: "->time.Nanosecond",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Nanosecond)), nil
		},
	},
	{
		Name: "->time.Microsecond",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Microsecond)), nil
		},
	},
	{
		Name: "->time.Millisecond",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Millisecond)), nil
		},
	},
	{
		Name: "->time.Second",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt(int(time.Second)), nil
		},
	},
	{
		Name: "->time.Minute",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt64(int64(time.Minute)), nil
		},
	},
	{
		Name: "->time.Hour",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewInt64(int64(time.Hour)), nil
		},
	},
	{
		Name: "->time.RFC3339",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewString(time.RFC3339), nil
		},
	},
	{
		Name: "->time.DefaultDateFormat",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewString("2006-1-2"), nil
		},
	},
	{
		Name:      "time.date",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			loc := GetLocation(vm)
			return getDate(args, vm, loc)
		},
	},
	{
		Name:      "time.parseDuration",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]

			switch a.Type {
			case dune.Object:
				if _, ok := a.ToObject().(Duration); !ok {
					return dune.NullValue, fmt.Errorf("expected time.Duration, got %s", a.TypeName())
				}
				return a, nil

			case dune.Int:
				return dune.NewObject(Duration(a.ToInt() * int64(time.Millisecond))), nil

			case dune.String:
				v := a.String()

				if IsNumeric(v) {
					i, err := strconv.Atoi(v)
					if err != nil {
						return dune.NullValue, dune.NewCodeError(100005, "invalid format %s. Expected an int", v)
					}
					return dune.NewObject(Duration(int64(i) * int64(time.Millisecond))), nil
				}

				if strings.ContainsRune(v, ':') {
					d, err := parseTime(v)
					if err != nil {
						return dune.NullValue, err
					}
					return d, nil
				}

				return parseDuration(v)

			default:
				return dune.NullValue, fmt.Errorf("expected string, got %s", a.TypeName())
			}
		},
	},
	{
		Name:      "time.parseTime",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			a := args[0]

			switch a.Type {
			case dune.Object:
				if _, ok := a.ToObject().(Duration); !ok {
					return dune.NullValue, fmt.Errorf("expected time.Duration, got %s", a.TypeName())
				}
				return a, nil

			case dune.Int:
				return dune.NewObject(Duration(a.ToInt() * int64(time.Millisecond))), nil

			case dune.String:
				v := args[0].String()

				if IsNumeric(v) {
					i, err := strconv.Atoi(v)
					if err != nil {
						return dune.NullValue, dune.NewCodeError(100005, "invalid format %s. Expected an int", v)
					}
					return dune.NewObject(Duration(int64(i) * int64(time.Millisecond))), nil
				}

				parts := Split(v, ":")
				ln := len(parts)
				if ln < 2 || ln > 3 {
					return dune.NullValue, dune.NewCodeError(100005, "invalid time. Format is for example 18:30")
				}

				h, err := strconv.Atoi(parts[0])
				if err != nil {
					return dune.NullValue, dune.NewCodeError(100005, "invalid hour part %s. Expected an int", parts[0])
				}

				m, err := strconv.Atoi(parts[1])
				if err != nil {
					return dune.NullValue, dune.NewCodeError(100005, "invalid min part %s. Expected an int", parts[1])
				}

				var s int
				if ln > 2 {
					s, err = strconv.Atoi(parts[2])
					if err != nil {
						return dune.NullValue, dune.NewCodeError(100005, "invalid sec part %s. Expected an int", parts[2])
					}
				}
				d := time.Duration(h)*time.Hour + time.Duration(m)*time.Minute + time.Duration(s)*time.Second

				return dune.NewObject(Duration(d)), nil

			default:
				return dune.NullValue, fmt.Errorf("expected string, got %s", a.TypeName())
			}
		},
	},
	{
		Name:      "time.duration",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}

			d, err := ToDuration(args[0])
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(Duration(d)), nil
		},
	},
	{
		Name:      "time.toDuration",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Int, dune.Int, dune.Int); err != nil {
				return dune.NullValue, err
			}

			l := len(args)

			if l == 0 {
				return dune.NullValue, fmt.Errorf("expected at least one parameter")
			}

			d := args[0].ToInt() * int64(time.Hour)

			if l > 1 {
				d += args[1].ToInt() * int64(time.Minute)
			}

			if l > 2 {
				d += args[2].ToInt() * int64(time.Second)
			}

			return dune.NewObject(Duration(d)), nil
		},
	},
	{
		Name:      "time.toMilliseconds",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Int, dune.Int, dune.Int); err != nil {
				return dune.NullValue, err
			}

			l := len(args)

			if l == 0 {
				return dune.NullValue, fmt.Errorf("expected at least one parameter")
			}

			m := args[0].ToInt() * 60 * 60 * 1000

			if l > 1 {
				m += args[1].ToInt() * 60 * 1000
			}

			if l > 2 {
				m += args[2].ToInt() * 1000
			}

			return dune.NewInt64(m), nil
		},
	},
	{
		Name:      "time.unix",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Int); err != nil {
				return dune.NullValue, err
			}
			sec := args[0].ToInt()
			t := time.Unix(sec, 0)
			return dune.NewObject(TimeObj(t)), nil
		},
	},
	{
		Name:        "time.setDefaultLocation",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			name := args[0].String()

			l, err := time.LoadLocation(name)
			if err != nil {
				return dune.NullValue, fmt.Errorf("error loading timezone %s: %w", name, err)
			}

			time.Local = l

			return dune.NullValue, nil
		},
	},
	{
		Name:      "time.setLocation",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			name := args[0].String()

			l, err := time.LoadLocation(name)
			if err != nil {
				return dune.NullValue, fmt.Errorf("error loading timezone %s: %w", name, err)
			}

			vm.Location = l

			return dune.NullValue, nil
		},
	},
	{
		Name:        "time.setFixedNow",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, err
			}

			t, ok := args[0].ToObjectOrNil().(TimeObj)
			if !ok {
				return dune.NullValue, ErrInvalidType
			}

			vm.Now = time.Time(t)
			return dune.NullValue, nil
		},
	},
	{
		Name:        "time.unsetFixedNow",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			vm.Now = time.Time{}
			return dune.NullValue, nil
		},
	},
	{
		Name: "time.now",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if !vm.Now.IsZero() {
				return dune.NewObject(TimeObj(vm.Now)), nil
			}
			loc := GetLocation(vm)
			t := time.Now().In(loc)
			return dune.NewObject(TimeObj(t)), nil
		},
	},
	{
		Name: "time.nowUTC",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			n := vm.Now
			if !n.IsZero() {
				return dune.NewObject(TimeObj(n.UTC())), nil
			}
			return dune.NewObject(TimeObj(time.Now().UTC())), nil
		},
	},
	{
		Name: "time.unixNano",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			n := vm.Now
			if !n.IsZero() {
				return dune.NewInt64(n.UnixNano()), nil
			}
			return dune.NewInt64(time.Now().UnixNano()), nil
		},
	},
	{
		Name:        "time.sleep",
		Arguments:   1,
		Permissions: []string{"sync"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if len(args) != 1 {
				return dune.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			d, err := ToDuration(args[0])
			if err != nil {
				return dune.NullValue, err
			}

			time.Sleep(d)
			return dune.NullValue, nil
		},
	},
	{
		Name: "->time.utc",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			return dune.NewObject(location{time.UTC}), nil
		},
	},
	{
		Name: "->time.local",
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := GetLocation(vm)
			return dune.NewObject(location{l}), nil
		},
	},
	{
		Name:      "time.loadLocation",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}
			l, err := time.LoadLocation(args[0].String())
			if err != nil {
				return dune.NullValue, err
			}
			return dune.NewObject(location{l}), nil
		},
	},
	{
		Name:      "time.parse",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := GetLocation(vm)
			return parseInLocation(l, this, args, vm)
		},
	},
	{
		Name:      "time.parseInLocation",
		Arguments: 3,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			location, ok := args[2].ToObjectOrNil().(location)
			if !ok {
				return dune.NullValue, fmt.Errorf("invalid location, got %s", args[2].TypeName())
			}
			return parseInLocation(location.l, this, args, vm)
		},
	},
	{
		Name:      "time.formatMinutes",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var min float64

			a := args[0]

			switch a.Type {
			case dune.Int, dune.Float:
				min = a.ToFloat()

			default:
				return dune.NullValue, fmt.Errorf("expected a number, got %v", a.TypeName())
			}

			negative := min < 0

			min = math.Abs(min)

			h := int(math.Floor(min / 60))
			m := int(min) % 60

			s := fmt.Sprintf("%02d:%02d", h, m)

			if negative {
				s = "-" + s
			}

			return dune.NewString(s), nil
		},
	},
	{
		Name:        "time.newTicker",
		Arguments:   2,
		Permissions: []string{"async"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d, err := ToDuration(args[0])
			if err != nil {
				return dune.NullValue, err
			}

			v := args[1]
			switch v.Type {
			case dune.Func:

			case dune.Object:
				if _, ok := v.ToObjectOrNil().(*dune.Closure); !ok {
					return dune.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
				}

			default:
				return dune.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
			}

			ticker := time.NewTicker(d)

			go func() {
				for range ticker.C {
					if err := runAsyncFuncOrClosure(vm, v); err != nil {
						fmt.Fprintln(vm.GetStderr(), err)
					}
				}
			}()

			return dune.NewObject(&tickerObj{ticker}), nil
		},
	},
	{
		Name:        "time.newTimer",
		Arguments:   2,
		Permissions: []string{"async"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			d, err := ToDuration(args[0])
			if err != nil {
				return dune.NullValue, fmt.Errorf("expected time.Duration, got: %s", args[0].TypeName())
			}

			v := args[1]
			switch v.Type {
			case dune.Func:
			case dune.Object:
			default:
				return dune.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
			}

			timer := time.NewTimer(d)

			go func() {
				for range timer.C {
					if err := runAsyncFuncOrClosure(vm, v); err != nil {
						fmt.Fprintln(vm.GetStderr(), err)
					}
				}
			}()

			return dune.NewObject(&timerObj{timer}), nil
		},
	},
	{
		Name:      "time.after",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			l := len(args)
			if l == 0 || l > 2 {
				return dune.NullValue, fmt.Errorf("expected 1 or 2 args")
			}

			d, err := ToDuration(args[0])
			if err != nil {
				return dune.NullValue, fmt.Errorf("expected time.Duration, got: %s", args[0].TypeName())
			}

			ch := make(chan dune.Value)
			timer := time.NewTimer(d)

			if l == 1 {
				go func() {
					t := <-timer.C
					ch <- dune.NewObject(TimeObj(t))
				}()
			} else {
				go func() {
					<-timer.C
					ch <- args[1]
				}()
			}

			c := &channel{c: ch}
			return dune.NewObject(c), nil
		},
	},
}
View Source
var WebSocket = []dune.NativeFunction{
	{
		Name:        "websocket.newUpgrader",
		Permissions: []string{"networking"},
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			u := &websocket.Upgrader{
				HandshakeTimeout: 10 * time.Second,
				ReadBufferSize:   1024,
				WriteBufferSize:  1024,
			}
			return dune.NewObject(&upgrader{u}), nil
		},
	},
	{
		Name:      "websocket.isCloseError",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object); err != nil {
				return dune.NullValue, nil
			}

			e, ok := args[0].ToObject().(*websocket.CloseError)
			if !ok {
				return dune.FalseValue, nil
			}

			switch e.Code {
			case
				websocket.CloseNormalClosure,
				websocket.CloseGoingAway,
				websocket.CloseProtocolError,
				websocket.CloseUnsupportedData,
				websocket.CloseNoStatusReceived,
				websocket.CloseAbnormalClosure,
				websocket.CloseInvalidFramePayloadData,
				websocket.ClosePolicyViolation,
				websocket.CloseMessageTooBig,
				websocket.CloseMandatoryExtension,
				websocket.CloseInternalServerErr,
				websocket.CloseServiceRestart,
				websocket.CloseTryAgainLater,
				websocket.CloseTLSHandshake:
				return dune.TrueValue, nil
			default:
				return dune.FalseValue, nil
			}
		},
	},
}
View Source
var XLSX = []dune.NativeFunction{
	{
		Name:      "xlsx.openReaderAt",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object, dune.Int); err != nil {
				return dune.NullValue, err
			}

			r, ok := args[0].ToObjectOrNil().(io.ReaderAt)
			if !ok {
				return dune.NullValue, fmt.Errorf("invalid argument type. Expected a io.ReaderAt, got %s", args[0].TypeName())
			}

			size := args[1].ToInt()

			reader, err := xlsx.OpenReaderAt(r, size)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&xlsxFile{obj: reader}), nil
		},
	},
	{
		Name:      "xlsx.openBinary",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Bytes); err != nil {
				return dune.NullValue, err
			}

			b := args[0].ToBytes()

			reader, err := xlsx.OpenBinary(b)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&xlsxFile{obj: reader}), nil
		},
	},
	{
		Name:      "xlsx.openFile",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			var r io.ReaderAt
			var size int64

			a := args[0]

			switch a.Type {
			case dune.Object:
				f, ok := a.ToObject().(*file)
				if !ok {
					return dune.NullValue, fmt.Errorf("invalid argument type. Expected a io.ReaderAt, got %s", a.TypeName())
				}
				r = f
				st, err := f.Stat()
				if err != nil {
					return dune.NullValue, err
				}
				size = st.Size()

			case dune.String:
				f, err := vm.FileSystem.Open(a.String())
				if err != nil {
					return dune.NullValue, err
				}
				r = f
				st, err := f.Stat()
				if err != nil {
					return dune.NullValue, err
				}
				size = st.Size()

			default:
				return dune.NullValue, fmt.Errorf("invalid argument type. Expected a io.ReaderAt, got %s", a.TypeName())
			}

			reader, err := xlsx.OpenReaderAt(r, size)
			if err != nil {
				return dune.NullValue, err
			}

			return dune.NewObject(&xlsxFile{obj: reader, path: a.String()}), nil
		},
	},
	{
		Name:      "xlsx.newFile",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return dune.NullValue, err
			}

			file := xlsx.NewFile()
			return dune.NewObject(&xlsxFile{obj: file}), nil
		},
	},
	{
		Name:      "xlsx.newStyle",
		Arguments: 0,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return dune.NullValue, err
			}

			s := xlsx.NewStyle()
			return dune.NewObject(&xlsxStyle{obj: s}), nil
		},
	},
}
View Source
var XML = []dune.NativeFunction{
	{
		Name:      "xml.newDocument",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.Bool); err != nil {
				return dune.NullValue, err
			}

			doc := etree.NewDocument()
			doc.WriteSettings.CanonicalText = true
			doc.WriteSettings.CanonicalAttrVal = true

			if len(args) == 1 && args[0].ToBool() {
				doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`)
			}

			return dune.NewObject(&xmlDoc{doc: doc}), nil
		},
	},
	{
		Name:      "xml.newCharData",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			d := etree.NewText(args[0].String())
			return dune.NewObject(&xmlCharData{data: d}), nil
		},
	},
	{
		Name:      "xml.newElement",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			e := etree.NewElement(args[0].String())
			return dune.NewObject(&xmlElement{element: e}), nil
		},
	},
	{
		Name:      "xml.read",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			doc := etree.NewDocument()
			doc.WriteSettings.CanonicalText = true
			doc.WriteSettings.CanonicalAttrVal = true

			if err := doc.ReadFromBytes(args[0].ToBytes()); err != nil {
				return dune.NullValue, err
			}
			return dune.NewObject(&xmlDoc{doc: doc}), nil
		},
	},
	{
		Name:      "xml.readString",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.String); err != nil {
				return dune.NullValue, err
			}

			doc := etree.NewDocument()
			doc.WriteSettings.CanonicalText = true
			doc.WriteSettings.CanonicalAttrVal = true

			if err := doc.ReadFromString(args[0].String()); err != nil {
				return dune.NullValue, err
			}
			return dune.NewObject(&xmlDoc{doc: doc}), nil
		},
	},
}
View Source
var ZIP = []dune.NativeFunction{
	{
		Name:      "zip.newWriter",
		Arguments: 1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			w, ok := args[0].ToObjectOrNil().(io.Writer)
			if !ok {
				return dune.NullValue, fmt.Errorf("exepected a Writer, got %s", args[0].TypeName())
			}

			g := zip.NewWriter(w)
			v := &zipWriter{g}
			return dune.NewObject(v), nil
		},
	},
	{
		Name:      "zip.newReader",
		Arguments: 2,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateArgs(args, dune.Object, dune.Int); err != nil {
				return dune.NullValue, err
			}

			r, ok := args[0].ToObjectOrNil().(io.ReaderAt)
			if !ok {
				return dune.NullValue, fmt.Errorf("exepected a reader, got %s", args[0].TypeName())
			}

			size := args[1].ToInt()

			gr, err := zip.NewReader(r, size)
			if err != nil {
				return dune.NullValue, err
			}

			v := &zipReader{r: gr}
			return dune.NewObject(v), nil
		},
	},
	{
		Name:      "zip.open",
		Arguments: -1,
		Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
			if err := ValidateOptionalArgs(args, dune.String, dune.Object); err != nil {
				return dune.NullValue, err
			}

			if err := ValidateArgRange(args, 1, 2); err != nil {
				return dune.NullValue, err
			}

			var fs filesystem.FS
			if len(args) == 2 {
				fsObj, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return dune.NullValue, fmt.Errorf("exepected a FileSystem, got %s", args[1].TypeName())
				}
				fs = fsObj.FS
			} else {
				fs = vm.FileSystem
			}

			f, err := fs.Open(args[0].String())
			if err != nil {
				return dune.NullValue, err
			}

			fi, err := f.Stat()
			if err != nil {
				return dune.NullValue, err
			}

			size := fi.Size()

			gr, err := zip.NewReader(f, size)
			if err != nil {
				return dune.NullValue, err
			}

			v := &zipReader{gr, f}
			return dune.NewObject(v), nil
		},
	},
}

Functions

func CheckHashPasword

func CheckHashPasword(hash, pwd string) bool

func DecodeCustomBase34

func DecodeCustomBase34(s string) uint64

DecodeCustomBase34 decodes a base34-encoded string back to uint64

func Decrypt

func Decrypt(ciphertext, password []byte) ([]byte, error)

Decrypts decrypts the text.

func DecryptTripleDESCBC

func DecryptTripleDESCBC(encrypted, key []byte) ([]byte, error)

func Decrypts

func Decrypts(text, password string) (string, error)

Decrypts decrypts the text.

func EncodeCustomBase34

func EncodeCustomBase34(value uint64) string

EncodeCustomBase34 encodes a uint64 value to string in base34 format

func Encrypt

func Encrypt(plaintext, password []byte) ([]byte, error)

Encrypts encrypts the text.

func EncryptTripleDESCBC

func EncryptTripleDESCBC(decrypted, key []byte) ([]byte, error)

func Encrypts

func Encrypts(text, password string) (string, error)

Encrypts encrypts the text.

func GetLocation

func GetLocation(vm *dune.VM) *time.Location

func HashPassword

func HashPassword(pwd string) string

func IsAlphanumeric

func IsAlphanumeric(s string) bool

func IsAlphanumericIdent

func IsAlphanumericIdent(s string) bool

func IsDecimal

func IsDecimal(r rune) bool

IsDecimal returns true if r is a digit

func IsIdent

func IsIdent(s string) bool

IsIdent returns if s is a valid identifier.

func IsNumeric

func IsNumeric(s string) bool

IsNumeric returns true if s contains only digits

func NewReader

func NewReader(r io.Reader) *reader

func NewRoute

func NewRoute(url string) *httpRoute

func NewWriter

func NewWriter(w io.Writer) *writer

func Random

func Random(n int) []byte

GenerateRandomBytes returns securely generated random bytes. It will return an error if the system's secure random number generator fails to function correctly, in which case the caller should not continue.

func RandomAlphanumeric

func RandomAlphanumeric(size int) string

func ReadAll

func ReadAll(reader io.Reader, vm *dune.VM) ([]byte, error)

func ReadNames

func ReadNames(fs filesystem.FS, dirname string, recursive bool) ([]string, error)

ReadNames reads the directory and file names contained in dirname.

func SendMail

func SendMail(addr string, a Auth, from string, to []string, msg []byte, insecureSkipVerify bool) error

SendMail connects to the server at addr, switches to TLS if possible, authenticates with the optional mechanism a if possible, and then sends an email from address from, to addresses to, with message msg. The addr must include a port, as in "mail.example.com:smtp".

The addresses in the to parameter are the SMTP RCPT addresses.

The msg parameter should be an RFC 822-style email with headers first, a blank line, and then the message body. The lines of msg should be CRLF terminated. The msg headers should usually include fields such as "From", "To", "Subject", and "Cc". Sending "Bcc" messages is accomplished by including an email address in the to parameter but not including it in the msg headers.

The SendMail function and the the net/smtp package are low-level mechanisms and provide no support for DKIM signing, MIME attachments (see the mime/multipart package), or other mail functionality. Higher-level packages exist outside of the standard library.

func Split

func Split(s, sep string) []string

func ToDuration

func ToDuration(v dune.Value) (time.Duration, error)

func ValidateArgRange

func ValidateArgRange(args []dune.Value, counts ...int) error

func ValidateArgs

func ValidateArgs(args []dune.Value, t ...interface{}) error

validate the number of args ant type

func ValidateOptionalArgs

func ValidateOptionalArgs(args []dune.Value, t ...dune.Type) error

validate that if present, args are of type t

func ValidateOrNilArgs

func ValidateOrNilArgs(args []dune.Value, t ...interface{}) error

validate the number of args ant type

func ValidatePermissions

func ValidatePermissions(p *dune.Program, vm *dune.VM) error

func WithDeadline

func WithDeadline(d time.Duration, fn func(dl *Deadline) error) error

func Write

func Write(w io.Writer, v dune.Value, vm *dune.VM) error

func WriteAt

func WriteAt(w io.WriterAt, v dune.Value, off int64, vm *dune.VM) error

func ZeroPadding

func ZeroPadding(ciphertext []byte, blockSize int) []byte

func ZeroUnPadding

func ZeroUnPadding(origData []byte) []byte

Types

type Addr

type Addr struct {
	// contains filtered or unexported fields
}

func (*Addr) GetMethod

func (a *Addr) GetMethod(name string) dune.NativeMethod

func (*Addr) String

func (a *Addr) String() string

func (*Addr) Type

func (*Addr) Type() string

type Auth

type Auth interface {
	// Start begins an authentication with a server.
	// It returns the name of the authentication protocol
	// and optionally data to include in the initial AUTH message
	// sent to the server. It can return proto == "" to indicate
	// that the authentication should be skipped.
	// If it returns a non-nil error, the SMTP client aborts
	// the authentication attempt and closes the connection.
	Start(server *ServerInfo) (proto string, toServer []byte, err error)

	// Next continues the authentication. The server has just sent
	// the fromServer data. If more is true, the server expects a
	// response, which Next should return as toServer; otherwise
	// Next should return toServer == nil.
	// If Next returns a non-nil error, the SMTP client aborts
	// the authentication attempt and closes the connection.
	Next(fromServer []byte, more bool) (toServer []byte, err error)
}

Auth is implemented by an SMTP authentication mechanism.

func CRAMMD5Auth

func CRAMMD5Auth(username, secret string) Auth

CRAMMD5Auth returns an Auth that implements the CRAM-MD5 authentication mechanism as defined in RFC 2195. The returned Auth uses the given username and secret to authenticate to the server using the challenge-response mechanism.

func LoginAuth

func LoginAuth(username, password string) Auth

loginAuth returns an Auth that implements the LOGIN authentication mechanism as defined in RFC 4616.

func PlainAuth

func PlainAuth(identity, username, password, host string) Auth

PlainAuth returns an Auth that implements the PLAIN authentication mechanism as defined in RFC 4616. The returned Auth uses the given username and password to authenticate on TLS connections to host and act as identity. Usually identity will be left blank to act as username.

type Buffer

type Buffer struct {
	Buf *bytes.Buffer
}

func NewBuffer

func NewBuffer() Buffer

func (Buffer) GetField

func (b Buffer) GetField(name string, vm *dune.VM) (dune.Value, error)

func (Buffer) GetMethod

func (b Buffer) GetMethod(name string) dune.NativeMethod

func (Buffer) Read

func (b Buffer) Read(p []byte) (n int, err error)

func (Buffer) Type

func (b Buffer) Type() string

func (Buffer) Write

func (b Buffer) Write(p []byte) (n int, err error)

type Client

type Client struct {
	Text *textproto.Conn
	// contains filtered or unexported fields
}

func Dial

func Dial(addr string) (*Client, error)

Dial returns a new Client connected to an SMTP server at addr. The addr must include a port, as in "mail.example.com:smtp".

func NewClient

func NewClient(conn net.Conn, host string) (*Client, error)

NewClient returns a new Client using an existing connection and host as a server name to be used when authenticating.

func (*Client) Auth

func (c *Client) Auth(a Auth) error

Auth authenticates a client using the provided authentication mechanism. A failed authentication closes the connection. Only servers that advertise the AUTH extension support this function.

func (*Client) Close

func (c *Client) Close() error

Close closes the connection.

func (*Client) Data

func (c *Client) Data() (io.WriteCloser, error)

Data issues a DATA command to the server and returns a writer that can be used to write the mail headers and body. The caller should close the writer before calling any more methods on c. A call to Data must be preceded by one or more calls to Rcpt.

func (*Client) Extension

func (c *Client) Extension(ext string) (bool, string)

Extension reports whether an extension is support by the server. The extension name is case-insensitive. If the extension is supported, Extension also returns a string that contains any parameters the server specifies for the extension.

func (*Client) Hello

func (c *Client) Hello(localName string) error

Hello sends a HELO or EHLO to the server as the given host name. Calling this method is only necessary if the client needs control over the host name used. The client will introduce itself as "localhost" automatically otherwise. If Hello is called, it must be called before any of the other methods.

func (*Client) Mail

func (c *Client) Mail(from string) error

Mail issues a MAIL command to the server using the provided email address. If the server supports the 8BITMIME extension, Mail adds the BODY=8BITMIME parameter. This initiates a mail transaction and is followed by one or more Rcpt calls.

func (*Client) Quit

func (c *Client) Quit() error

Quit sends the QUIT command and closes the connection to the server.

func (*Client) Rcpt

func (c *Client) Rcpt(to string) error

Rcpt issues a RCPT command to the server using the provided email address. A call to Rcpt must be preceded by a call to Mail and may be followed by a Data call or another Rcpt call.

func (*Client) Reset

func (c *Client) Reset() error

Reset sends the RSET command to the server, aborting the current mail transaction.

func (*Client) StartTLS

func (c *Client) StartTLS(config *tls.Config) error

StartTLS sends the STARTTLS command and encrypts all further communication. Only servers that advertise the STARTTLS extension support this function.

func (*Client) TLSConnectionState

func (c *Client) TLSConnectionState() (state tls.ConnectionState, ok bool)

TLSConnectionState returns the client's TLS connection state. The return values are their zero values if StartTLS did not succeed.

func (*Client) Verify

func (c *Client) Verify(addr string) error

Verify checks the validity of an email address on the server. If Verify returns nil, the address is valid. A non-nil return does not necessarily indicate an invalid address. Many servers will not verify addresses for security reasons.

type Deadline

type Deadline struct {
	// contains filtered or unexported fields
}

func (*Deadline) Cancel

func (dl *Deadline) Cancel()

func (*Deadline) Extend

func (dl *Deadline) Extend(d time.Duration)

func (*Deadline) GetMethod

func (dl *Deadline) GetMethod(name string) dune.NativeMethod

func (*Deadline) Type

func (dl *Deadline) Type() string

type Duration

type Duration time.Duration

func (Duration) Export

func (t Duration) Export(recursionLevel int) interface{}

func (Duration) GetField

func (t Duration) GetField(name string, vm *dune.VM) (dune.Value, error)

func (Duration) GetMethod

func (t Duration) GetMethod(name string) dune.NativeMethod

func (Duration) MarshalJSON

func (t Duration) MarshalJSON() ([]byte, error)

func (Duration) Size

func (t Duration) Size() int

func (Duration) String

func (t Duration) String() string

func (Duration) Type

func (t Duration) Type() string

type FileSystemObj

type FileSystemObj struct {
	FS filesystem.FS
}

func NewFileSystem

func NewFileSystem(fs filesystem.FS) *FileSystemObj

func (*FileSystemObj) GetMethod

func (f *FileSystemObj) GetMethod(name string) dune.NativeMethod

func (*FileSystemObj) Type

func (f *FileSystemObj) Type() string

type IP

type IP struct {
	// contains filtered or unexported fields
}

func (*IP) GetMethod

func (ip *IP) GetMethod(name string) dune.NativeMethod

func (*IP) String

func (ip *IP) String() string

func (*IP) Type

func (*IP) Type() string

type InmutableObject

type InmutableObject struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func (*InmutableObject) GetField

func (p *InmutableObject) GetField(key string, vm *dune.VM) (dune.Value, error)

func (*InmutableObject) SetField

func (p *InmutableObject) SetField(key string, v dune.Value, vm *dune.VM) error

func (*InmutableObject) Type

func (*InmutableObject) Type() string

type SecureObject

type SecureObject struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func (*SecureObject) GetField

func (p *SecureObject) GetField(key string, vm *dune.VM) (dune.Value, error)

func (*SecureObject) SetField

func (p *SecureObject) SetField(key string, v dune.Value, vm *dune.VM) error

func (*SecureObject) Type

func (*SecureObject) Type() string

type ServerInfo

type ServerInfo struct {
	Name string
	Auth []string
	TLS  bool
}

ServerInfo records information about an SMTP server.

type SmtMessage

type SmtMessage struct {
	Attachments map[string]*attachment
	From        mail.Address
	To          dune.Value
	Bcc         dune.Value
	Cc          dune.Value
	ReplyTo     string
	Subject     string
	Body        string
	Html        bool
}

Message represents a smtp message.

func (*SmtMessage) AllRecipients

func (m *SmtMessage) AllRecipients() []string

Tolist returns all the recipients of the email

func (*SmtMessage) AttachBuffer

func (m *SmtMessage) AttachBuffer(filename string, buf []byte, inline bool) error

AttachBuffer attaches a binary attachment.

func (*SmtMessage) BccList

func (m *SmtMessage) BccList() []string

func (*SmtMessage) Bytes

func (m *SmtMessage) Bytes() []byte

Bytes returns the mail data

func (*SmtMessage) CcList

func (m *SmtMessage) CcList() []string

func (*SmtMessage) ContentType

func (m *SmtMessage) ContentType() string

func (*SmtMessage) GetField

func (m *SmtMessage) GetField(key string, vm *dune.VM) (dune.Value, error)

func (*SmtMessage) GetMethod

func (m *SmtMessage) GetMethod(name string) dune.NativeMethod

func (*SmtMessage) Send

func (m *SmtMessage) Send(user, password, host string, port int, insecureSkipVerify bool) error

func (*SmtMessage) SetField

func (m *SmtMessage) SetField(key string, v dune.Value, vm *dune.VM) error

func (*SmtMessage) ToList

func (m *SmtMessage) ToList() []string

func (SmtMessage) Type

func (SmtMessage) Type() string

type StdLib

type StdLib struct {
	// contains filtered or unexported fields
}

func (*StdLib) GetField

func (s *StdLib) GetField(name string, vm *dune.VM) (dune.Value, error)

func (*StdLib) GetMethod

func (s *StdLib) GetMethod(name string) dune.NativeMethod

func (*StdLib) String

func (*StdLib) String() string

func (*StdLib) Type

func (*StdLib) Type() string

type StdProgram

type StdProgram struct {
	// contains filtered or unexported fields
}

func (*StdProgram) GetField

func (lib *StdProgram) GetField(name string, vm *dune.VM) (dune.Value, error)

func (*StdProgram) GetMethod

func (lib *StdProgram) GetMethod(name string) dune.NativeMethod

func (*StdProgram) String

func (*StdProgram) String() string

func (*StdProgram) Type

func (*StdProgram) Type() string

type TimeObj

type TimeObj time.Time

func (TimeObj) Compare

func (t TimeObj) Compare(v dune.Value) int

func (TimeObj) Equals

func (t TimeObj) Equals(v interface{}) bool

func (TimeObj) Export

func (t TimeObj) Export(recursionLevel int) interface{}

func (TimeObj) GetField

func (t TimeObj) GetField(name string, vm *dune.VM) (dune.Value, error)

func (TimeObj) GetMethod

func (t TimeObj) GetMethod(name string) dune.NativeMethod

func (TimeObj) MarshalJSON

func (t TimeObj) MarshalJSON() ([]byte, error)

func (TimeObj) Size

func (t TimeObj) Size() int

func (TimeObj) String

func (t TimeObj) String() string

func (TimeObj) Type

func (t TimeObj) Type() string

type URL

type URL struct {
	// contains filtered or unexported fields
}

func (*URL) GetField

func (u *URL) GetField(name string, vm *dune.VM) (dune.Value, error)

func (*URL) GetMethod

func (u *URL) GetMethod(name string) dune.NativeMethod

func (*URL) SetField

func (u *URL) SetField(name string, v dune.Value, vm *dune.VM) error

func (*URL) String

func (u *URL) String() string

func (*URL) Type

func (*URL) Type() string

Directories

Path Synopsis
Package templates generates source code for templates.
Package templates generates source code for templates.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL