js

package
v0.0.4 Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2026 License: Apache-2.0 Imports: 30 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var BuiltinBase64Go = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("encode", func(call goja.FunctionCall) goja.Value {
		return vm.ToValue(base64.StdEncoding.EncodeToString([]byte(call.Argument(0).String())))
	})

	_ = ex.Set("decode", func(call goja.FunctionCall) goja.Value {
		decoded, err := base64.StdEncoding.DecodeString(call.Argument(0).String())
		if err != nil {
			return vm.NewGoError(err)
		}
		return vm.ToValue(string(decoded))
	})

	_ = ex.Set("urlEncode", func(call goja.FunctionCall) goja.Value {
		return vm.ToValue(base64.URLEncoding.EncodeToString([]byte(call.Argument(0).String())))
	})

	_ = ex.Set("urlDecode", func(call goja.FunctionCall) goja.Value {
		decoded, err := base64.URLEncoding.DecodeString(call.Argument(0).String())
		if err != nil {
			return vm.NewGoError(err)
		}
		return vm.ToValue(string(decoded))
	})

	return ex, nil
}
View Source
var BuiltinCollectionGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("list_includes", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("list_includes requires exactly 2 arguments"))
		}
		arrVal := call.Argument(0)
		item := call.Argument(1)

		arr := arrVal.Export()
		arrValue := reflect.ValueOf(arr)
		if arrValue.Kind() != reflect.Slice && arrValue.Kind() != reflect.Array {
			return vm.ToValue(false)
		}

		itemExport := item.Export()
		for i := 0; i < arrValue.Len(); i++ {
			elem := arrValue.Index(i).Interface()
			if reflect.DeepEqual(elem, itemExport) {
				return vm.ToValue(true)
			}
		}
		return vm.ToValue(false)
	})

	_ = ex.Set("list_indexOf", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("list_indexOf requires exactly 2 arguments"))
		}
		arrVal := call.Argument(0)
		item := call.Argument(1)

		arr := arrVal.Export()
		arrValue := reflect.ValueOf(arr)
		if arrValue.Kind() != reflect.Slice && arrValue.Kind() != reflect.Array {
			return vm.ToValue(-1)
		}

		itemExport := item.Export()
		for i := 0; i < arrValue.Len(); i++ {
			elem := arrValue.Index(i).Interface()
			if reflect.DeepEqual(elem, itemExport) {
				return vm.ToValue(i)
			}
		}
		return vm.ToValue(-1)
	})

	_ = ex.Set("list_lastIndexOf", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("list_lastIndexOf requires exactly 2 arguments"))
		}
		arrVal := call.Argument(0)
		item := call.Argument(1)

		arr := arrVal.Export()
		arrValue := reflect.ValueOf(arr)
		if arrValue.Kind() != reflect.Slice && arrValue.Kind() != reflect.Array {
			return vm.ToValue(-1)
		}

		itemExport := item.Export()
		lastIndex := -1
		for i := 0; i < arrValue.Len(); i++ {
			elem := arrValue.Index(i).Interface()
			if reflect.DeepEqual(elem, itemExport) {
				lastIndex = i
			}
		}
		return vm.ToValue(lastIndex)
	})

	_ = ex.Set("list_sort", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("list_sort requires exactly 1 argument"))
		}
		arrVal := call.Argument(0)

		arr := arrVal.Export()
		arrValue := reflect.ValueOf(arr)
		if arrValue.Kind() != reflect.Slice {
			return vm.NewGoError(errors.New("list_sort requires an array"))
		}

		arrInterface := make([]interface{}, arrValue.Len())
		for i := 0; i < arrValue.Len(); i++ {
			arrInterface[i] = arrValue.Index(i).Interface()
		}

		sort.Slice(arrInterface, func(i, j int) bool {
			return compareValues(arrInterface[i], arrInterface[j]) < 0
		})

		return vm.ToValue(arrInterface)
	})

	_ = ex.Set("list_unique", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("list_unique requires exactly 1 argument"))
		}
		arrVal := call.Argument(0)

		arr := arrVal.Export()
		arrValue := reflect.ValueOf(arr)
		if arrValue.Kind() != reflect.Slice && arrValue.Kind() != reflect.Array {
			return vm.NewGoError(errors.New("list_unique requires an array"))
		}

		seen := make(map[interface{}]bool)
		var result []interface{}
		for i := 0; i < arrValue.Len(); i++ {
			elem := arrValue.Index(i).Interface()

			key := reflect.ValueOf(elem)
			if !key.IsValid() || key.CanInterface() {
				if !seen[elem] {
					seen[elem] = true
					result = append(result, elem)
				}
			}
		}

		return vm.ToValue(result)
	})

	_ = ex.Set("list_chunk", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("list_chunk requires exactly 2 arguments"))
		}
		arrVal := call.Argument(0)
		size := int(call.Argument(1).ToInteger())

		if size <= 0 {
			return vm.NewGoError(errors.New("list_chunk size must be positive"))
		}

		arr := arrVal.Export()
		arrValue := reflect.ValueOf(arr)
		if arrValue.Kind() != reflect.Slice && arrValue.Kind() != reflect.Array {
			return vm.NewGoError(errors.New("list_chunk requires an array"))
		}

		var chunks [][]interface{}
		var currentChunk []interface{}

		for i := 0; i < arrValue.Len(); i++ {
			elem := arrValue.Index(i).Interface()
			currentChunk = append(currentChunk, elem)

			if len(currentChunk) == size {
				chunks = append(chunks, currentChunk)
				currentChunk = nil
			}
		}

		if len(currentChunk) > 0 {
			chunks = append(chunks, currentChunk)
		}

		return vm.ToValue(chunks)
	})

	_ = ex.Set("list_flatten", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("list_flatten requires exactly 1 argument"))
		}
		arrVal := call.Argument(0)

		arr := arrVal.Export()
		arrValue := reflect.ValueOf(arr)
		if arrValue.Kind() != reflect.Slice && arrValue.Kind() != reflect.Array {
			return vm.NewGoError(errors.New("list_flatten requires an array"))
		}

		var result []interface{}
		flattenArray(arrValue, &result)

		return vm.ToValue(result)
	})

	_ = ex.Set("map_keys", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("map_keys requires exactly 1 argument"))
		}
		mapVal := call.Argument(0)

		mp := mapVal.Export()
		mapValue := reflect.ValueOf(mp)
		if mapValue.Kind() != reflect.Map {
			return vm.NewGoError(errors.New("map_keys requires a map"))
		}

		var keys []interface{}
		for _, key := range mapValue.MapKeys() {
			keys = append(keys, key.Interface())
		}

		return vm.ToValue(keys)
	})

	_ = ex.Set("map_values", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("map_values requires exactly 1 argument"))
		}
		mapVal := call.Argument(0)

		mp := mapVal.Export()
		mapValue := reflect.ValueOf(mp)
		if mapValue.Kind() != reflect.Map {
			return vm.NewGoError(errors.New("map_values requires a map"))
		}

		var values []interface{}
		for _, key := range mapValue.MapKeys() {
			values = append(values, mapValue.MapIndex(key).Interface())
		}

		return vm.ToValue(values)
	})

	_ = ex.Set("map_entries", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("map_entries requires exactly 1 argument"))
		}
		mapVal := call.Argument(0)

		mp := mapVal.Export()
		mapValue := reflect.ValueOf(mp)
		if mapValue.Kind() != reflect.Map {
			return vm.NewGoError(errors.New("map_entries requires a map"))
		}

		var entries [][]interface{}
		for _, key := range mapValue.MapKeys() {
			entry := []interface{}{key.Interface(), mapValue.MapIndex(key).Interface()}
			entries = append(entries, entry)
		}

		return vm.ToValue(entries)
	})

	_ = ex.Set("map_has", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("map_has requires exactly 2 arguments"))
		}
		mapVal := call.Argument(0)
		key := call.Argument(1)

		mp := mapVal.Export()
		mapValue := reflect.ValueOf(mp)
		if mapValue.Kind() != reflect.Map {
			return vm.ToValue(false)
		}

		keyValue := reflect.ValueOf(key.Export())
		if !keyValue.IsValid() {
			return vm.ToValue(false)
		}

		return vm.ToValue(mapValue.MapIndex(keyValue).IsValid())
	})

	_ = ex.Set("map_get", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) < 2 || len(call.Arguments) > 3 {
			return vm.NewGoError(errors.New("map_get requires 2 or 3 arguments"))
		}
		mapVal := call.Argument(0)
		key := call.Argument(1)
		var defaultValue goja.Value
		if len(call.Arguments) > 2 {
			defaultValue = call.Argument(2)
		}

		mp := mapVal.Export()
		mapValue := reflect.ValueOf(mp)
		if mapValue.Kind() != reflect.Map {
			if defaultValue != nil && defaultValue != goja.Undefined() {
				return defaultValue
			}
			return goja.Undefined()
		}

		keyValue := reflect.ValueOf(key.Export())
		if !keyValue.IsValid() {
			if defaultValue != nil && defaultValue != goja.Undefined() {
				return defaultValue
			}
			return goja.Undefined()
		}

		value := mapValue.MapIndex(keyValue)
		if !value.IsValid() {
			if defaultValue != nil && defaultValue != goja.Undefined() {
				return defaultValue
			}
			return goja.Undefined()
		}

		return vm.ToValue(value.Interface())
	})

	_ = ex.Set("map_size", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("map_size requires exactly 1 argument"))
		}
		mapVal := call.Argument(0)

		mp := mapVal.Export()
		mapValue := reflect.ValueOf(mp)
		if mapValue.Kind() != reflect.Map {
			return vm.NewGoError(errors.New("map_size requires a map"))
		}

		return vm.ToValue(mapValue.Len())
	})

	_ = ex.Set("map_isEmpty", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("map_isEmpty requires exactly 1 argument"))
		}
		mapVal := call.Argument(0)

		mp := mapVal.Export()
		mapValue := reflect.ValueOf(mp)
		if mapValue.Kind() != reflect.Map {
			return vm.NewGoError(errors.New("map_isEmpty requires a map"))
		}

		return vm.ToValue(mapValue.Len() == 0)
	})

	_ = ex.Set("map_merge", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) < 2 {
			return vm.NewGoError(errors.New("map_merge requires at least 2 arguments"))
		}

		mp1 := call.Argument(0).Export()
		map1Value := reflect.ValueOf(mp1)
		if map1Value.Kind() != reflect.Map {
			return vm.NewGoError(errors.New("map_merge requires maps as arguments"))
		}

		resultType := reflect.MapOf(map1Value.Type().Key(), map1Value.Type().Elem())
		result := reflect.MakeMap(resultType)

		for _, key := range map1Value.MapKeys() {
			result.SetMapIndex(key, map1Value.MapIndex(key))
		}

		for i := 1; i < len(call.Arguments); i++ {
			mp2 := call.Argument(i).Export()
			map2Value := reflect.ValueOf(mp2)
			if map2Value.Kind() != reflect.Map {
				return vm.NewGoError(errors.New("map_merge requires maps as arguments"))
			}

			for _, key := range map2Value.MapKeys() {
				result.SetMapIndex(key, map2Value.MapIndex(key))
			}
		}

		return vm.ToValue(result.Interface())
	})

	return ex, nil
}
View Source
var BuiltinCryptoGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("sha256", func(call goja.FunctionCall) goja.Value {
		return vm.ToValue(sha256.New().Sum([]byte(call.Argument(0).String())))
	})

	return ex, nil
}
View Source
var BuiltinEncodingGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("base64Encode", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("base64Encode requires exactly 1 argument"))
		}
		return vm.ToValue(base64.StdEncoding.EncodeToString([]byte(call.Argument(0).String())))
	})

	_ = ex.Set("base64Decode", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("base64Decode requires exactly 1 argument"))
		}
		decoded, err := base64.StdEncoding.DecodeString(call.Argument(0).String())
		if err != nil {
			return vm.NewGoError(err)
		}
		return vm.ToValue(string(decoded))
	})

	_ = ex.Set("base64UrlEncode", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("base64UrlEncode requires exactly 1 argument"))
		}
		return vm.ToValue(base64.URLEncoding.EncodeToString([]byte(call.Argument(0).String())))
	})

	_ = ex.Set("base64UrlDecode", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("base64UrlDecode requires exactly 1 argument"))
		}
		decoded, err := base64.URLEncoding.DecodeString(call.Argument(0).String())
		if err != nil {
			return vm.NewGoError(err)
		}
		return vm.ToValue(string(decoded))
	})

	_ = ex.Set("hexEncode", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("hexEncode requires exactly 1 argument"))
		}
		return vm.ToValue(hex.EncodeToString([]byte(call.Argument(0).String())))
	})

	_ = ex.Set("hexDecode", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("hexDecode requires exactly 1 argument"))
		}
		decoded, err := hex.DecodeString(call.Argument(0).String())
		if err != nil {
			return vm.NewGoError(err)
		}
		return vm.ToValue(string(decoded))
	})

	_ = ex.Set("urlEncode", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("urlEncode requires exactly 1 argument"))
		}
		return vm.ToValue(url.QueryEscape(call.Argument(0).String()))
	})

	_ = ex.Set("urlDecode", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("urlDecode requires exactly 1 argument"))
		}
		decoded, err := url.QueryUnescape(call.Argument(0).String())
		if err != nil {
			return vm.NewGoError(err)
		}
		return vm.ToValue(decoded)
	})

	return ex, nil
}
View Source
var BuiltinHashGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("md5", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("md5 requires exactly 1 argument"))
		}
		data := call.Argument(0).String()
		hash := md5.Sum([]byte(data))
		return vm.ToValue(hex.EncodeToString(hash[:]))
	})

	_ = ex.Set("sha1", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("sha1 requires exactly 1 argument"))
		}
		data := call.Argument(0).String()
		hash := sha1.Sum([]byte(data))
		return vm.ToValue(hex.EncodeToString(hash[:]))
	})

	_ = ex.Set("sha256", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("sha256 requires exactly 1 argument"))
		}
		data := call.Argument(0).String()
		hash := sha256.Sum256([]byte(data))
		return vm.ToValue(hex.EncodeToString(hash[:]))
	})

	_ = ex.Set("sha512", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("sha512 requires exactly 1 argument"))
		}
		data := call.Argument(0).String()
		hash := sha512.Sum512([]byte(data))
		return vm.ToValue(hex.EncodeToString(hash[:]))
	})

	_ = ex.Set("hmac", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 3 {
			return vm.NewGoError(errors.New("hmac requires exactly 3 arguments"))
		}
		algorithm := call.Argument(0).String()
		data := call.Argument(1).String()
		key := call.Argument(2).String()

		var h hash.Hash
		switch algorithm {
		case "md5":
			h = hmac.New(md5.New, []byte(key))
		case "sha1":
			h = hmac.New(sha1.New, []byte(key))
		case "sha256":
			h = hmac.New(sha256.New, []byte(key))
		case "sha384":
			h = hmac.New(sha512.New384, []byte(key))
		case "sha512":
			h = hmac.New(sha512.New, []byte(key))
		default:
			return vm.NewGoError(errors.New("unsupported algorithm: " + algorithm))
		}

		h.Write([]byte(data))
		hashBytes := h.Sum(nil)
		return vm.ToValue(hex.EncodeToString(hashBytes))
	})

	return ex, nil
}
View Source
var BuiltinJSTS []byte
View Source
var BuiltinJsonGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("isValid", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("isValid requires exactly 1 argument"))
		}

		jsonStr := call.Argument(0).String()

		var result interface{}
		err := json.Unmarshal([]byte(jsonStr), &result)
		if err != nil {
			return vm.ToValue(false)
		}

		return vm.ToValue(true)
	})

	return ex, nil
}
View Source
var BuiltinJwtGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("decode", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) < 1 || len(call.Arguments) > 2 {
			return vm.NewGoError(errors.New("decode requires 1 or 2 arguments"))
		}
		tokenStr := call.Argument(0).String()
		var secret string
		if len(call.Arguments) > 1 && call.Argument(1) != goja.Undefined() && call.Argument(1) != goja.Null() {
			secret = call.Argument(1).String()
		}

		parts := strings.Split(tokenStr, ".")
		if len(parts) != 3 {
			return vm.NewGoError(errors.New("invalid token format"))
		}

		headerBytes, err := base64.RawURLEncoding.DecodeString(parts[0])
		if err != nil {
			return vm.NewGoError(err)
		}

		var header map[string]interface{}
		if err := json.Unmarshal(headerBytes, &header); err != nil {
			return vm.NewGoError(err)
		}

		payloadBytes, err := base64.RawURLEncoding.DecodeString(parts[1])
		if err != nil {
			return vm.NewGoError(err)
		}

		var payload map[string]interface{}
		if err := json.Unmarshal(payloadBytes, &payload); err != nil {
			return vm.NewGoError(err)
		}

		if secret != "" {
			alg, ok := header["alg"].(string)
			if !ok {
				return vm.NewGoError(errors.New("algorithm not found in header"))
			}

			message := parts[0] + "." + parts[1]
			signature := parts[2]

			var h hash.Hash
			switch alg {
			case "HS256":
				h = hmac.New(sha256.New, []byte(secret))
			case "HS384":
				h = hmac.New(sha512.New384, []byte(secret))
			case "HS512":
				h = hmac.New(sha512.New, []byte(secret))
			default:
				return vm.NewGoError(errors.New("unsupported algorithm: " + alg))
			}

			h.Write([]byte(message))
			expectedSig := base64.RawURLEncoding.EncodeToString(h.Sum(nil))

			if signature != expectedSig {
				return vm.NewGoError(errors.New("token signature is invalid"))
			}
		}

		return vm.ToValue(payload)
	})

	_ = ex.Set("verify", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) < 2 || len(call.Arguments) > 3 {
			return vm.NewGoError(errors.New("verify requires 2 or 3 arguments"))
		}
		tokenStr := call.Argument(0).String()
		secret := call.Argument(1).String()
		algorithm := "HS256"
		if len(call.Arguments) > 2 && call.Argument(2) != goja.Undefined() && call.Argument(2) != goja.Null() {
			algorithm = call.Argument(2).String()
		}

		parts := strings.Split(tokenStr, ".")
		if len(parts) != 3 {
			return vm.ToValue(false)
		}

		headerBytes, err := base64.RawURLEncoding.DecodeString(parts[0])
		if err != nil {
			return vm.ToValue(false)
		}

		var header map[string]interface{}
		if err := json.Unmarshal(headerBytes, &header); err != nil {
			return vm.ToValue(false)
		}

		alg, ok := header["alg"].(string)
		if !ok || alg != algorithm {
			return vm.ToValue(false)
		}

		message := parts[0] + "." + parts[1]
		signature := parts[2]

		var h hash.Hash
		switch algorithm {
		case "HS256":
			h = hmac.New(sha256.New, []byte(secret))
		case "HS384":
			h = hmac.New(sha512.New384, []byte(secret))
		case "HS512":
			h = hmac.New(sha512.New, []byte(secret))
		default:
			return vm.ToValue(false)
		}

		h.Write([]byte(message))
		expectedSig := base64.RawURLEncoding.EncodeToString(h.Sum(nil))

		return vm.ToValue(signature == expectedSig)
	})

	_ = ex.Set("getPayload", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("getPayload requires exactly 1 argument"))
		}
		tokenStr := call.Argument(0).String()

		parts := strings.Split(tokenStr, ".")
		if len(parts) != 3 {
			return vm.NewGoError(errors.New("invalid token format"))
		}

		decoded, err := base64.RawURLEncoding.DecodeString(parts[1])
		if err != nil {
			return vm.NewGoError(err)
		}

		var payload map[string]interface{}
		if err := json.Unmarshal(decoded, &payload); err != nil {
			return vm.NewGoError(err)
		}

		return vm.ToValue(payload)
	})

	_ = ex.Set("getHeader", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("getHeader requires exactly 1 argument"))
		}
		tokenStr := call.Argument(0).String()

		parts := strings.Split(tokenStr, ".")
		if len(parts) != 3 {
			return vm.NewGoError(errors.New("invalid token format"))
		}

		decoded, err := base64.RawURLEncoding.DecodeString(parts[0])
		if err != nil {
			return vm.NewGoError(err)
		}

		var header map[string]interface{}
		if err := json.Unmarshal(decoded, &header); err != nil {
			return vm.NewGoError(err)
		}

		return vm.ToValue(header)
	})

	return ex, nil
}
View Source
var BuiltinMathGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	return ex, nil
}
View Source
var BuiltinNetGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("cidrContains", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("cidrContains requires exactly 2 arguments"))
		}
		cidrStr := call.Argument(0).String()
		cidrOrIpStr := call.Argument(1).String()

		_, cidrNet, err := net.ParseCIDR(cidrStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		var ip net.IP

		if _, parsedCIDR, err := net.ParseCIDR(cidrOrIpStr); err == nil {
			ip = parsedCIDR.IP
		} else {
			ip = net.ParseIP(cidrOrIpStr)
			if ip == nil {
				return vm.NewGoError(errors.New("invalid IP or CIDR: " + cidrOrIpStr))
			}
		}

		return vm.ToValue(cidrNet.Contains(ip))
	})

	_ = ex.Set("cidrIntersects", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("cidrIntersects requires exactly 2 arguments"))
		}
		cidr1Str := call.Argument(0).String()
		cidr2Str := call.Argument(1).String()

		_, net1, err := net.ParseCIDR(cidr1Str)
		if err != nil {
			return vm.NewGoError(err)
		}

		_, net2, err := net.ParseCIDR(cidr2Str)
		if err != nil {
			return vm.NewGoError(err)
		}

		intersects := net1.Contains(net2.IP) || net2.Contains(net1.IP)
		return vm.ToValue(intersects)
	})

	_ = ex.Set("cidrIsValid", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("cidrIsValid requires exactly 1 argument"))
		}
		cidrStr := call.Argument(0).String()

		_, _, err := net.ParseCIDR(cidrStr)
		if err != nil {
			return vm.ToValue(false)
		}
		return vm.ToValue(true)
	})

	_ = ex.Set("cidrExpand", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("cidrExpand requires exactly 1 argument"))
		}
		cidrStr := call.Argument(0).String()

		ip, ipNet, err := net.ParseCIDR(cidrStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		var hosts []string
		for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); inc(ip) {
			hosts = append(hosts, ip.String())
		}

		return vm.ToValue(hosts)
	})

	_ = ex.Set("cidrMerge", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("cidrMerge requires exactly 1 argument"))
		}

		addrsArg := call.Argument(0)
		var addrs []string

		addrsExported := addrsArg.Export()
		switch v := addrsExported.(type) {
		case []interface{}:
			for _, item := range v {
				if str, ok := item.(string); ok {
					addrs = append(addrs, str)
				}
			}
		case []string:
			addrs = v
		default:
			return vm.NewGoError(errors.New("cidrMerge requires an array of IPs/CIDRs"))
		}

		// Parse all addresses
		var parsedIPs []netip.Prefix
		for _, addr := range addrs {
			prefix, err := netip.ParsePrefix(addr)
			if err != nil {

				ip, err := netip.ParseAddr(addr)
				if err != nil {
					return vm.NewGoError(errors.New("invalid IP or CIDR: " + addr))
				}
				if ip.Is4() {
					prefix = netip.PrefixFrom(ip, 32)
				} else {
					prefix = netip.PrefixFrom(ip, 128)
				}
			}
			parsedIPs = append(parsedIPs, prefix)
		}

		merged := netipPrefixMerge(parsedIPs)

		result := make([]string, len(merged))
		for i, p := range merged {
			result[i] = p.String()
		}

		return vm.ToValue(result)
	})

	_ = ex.Set("parseIP", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("parseIP requires exactly 1 argument"))
		}
		ipStr := call.Argument(0).String()

		ip := net.ParseIP(ipStr)
		if ip == nil {
			return goja.Null()
		}
		return vm.ToValue(ip.String())
	})

	_ = ex.Set("isIPv4", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("isIPv4 requires exactly 1 argument"))
		}
		ipStr := call.Argument(0).String()

		ip := net.ParseIP(ipStr)
		if ip == nil {
			return vm.ToValue(false)
		}
		return vm.ToValue(ip.To4() != nil)
	})

	_ = ex.Set("isIPv6", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("isIPv6 requires exactly 1 argument"))
		}
		ipStr := call.Argument(0).String()

		ip := net.ParseIP(ipStr)
		if ip == nil {
			return vm.ToValue(false)
		}
		return vm.ToValue(ip.To4() == nil && ip.To16() != nil)
	})

	_ = ex.Set("isPrivate", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("isPrivate requires exactly 1 argument"))
		}
		ipStr := call.Argument(0).String()

		ip := net.ParseIP(ipStr)
		if ip == nil {
			return vm.ToValue(false)
		}
		return vm.ToValue(ip.IsPrivate())
	})

	_ = ex.Set("isPublic", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("isPublic requires exactly 1 argument"))
		}
		ipStr := call.Argument(0).String()

		ip := net.ParseIP(ipStr)
		if ip == nil {
			return vm.ToValue(false)
		}
		return vm.ToValue(ip.IsGlobalUnicast() && !ip.IsPrivate() && !ip.IsLoopback())
	})

	_ = ex.Set("isLoopback", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("isLoopback requires exactly 1 argument"))
		}
		ipStr := call.Argument(0).String()

		ip := net.ParseIP(ipStr)
		if ip == nil {
			return vm.ToValue(false)
		}
		return vm.ToValue(ip.IsLoopback())
	})

	_ = ex.Set("isMulticast", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("isMulticast requires exactly 1 argument"))
		}
		ipStr := call.Argument(0).String()

		ip := net.ParseIP(ipStr)
		if ip == nil {
			return vm.ToValue(false)
		}
		return vm.ToValue(ip.IsMulticast())
	})

	return ex, nil
}
View Source
var BuiltinRegexGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("match", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("match requires exactly 2 arguments"))
		}
		pattern := call.Argument(0).String()
		str := call.Argument(1).String()

		re, err := getCompiledRegex(pattern)
		if err != nil {
			return vm.NewGoError(err)
		}
		return vm.ToValue(re.MatchString(str))
	})

	_ = ex.Set("find", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("find requires exactly 2 arguments"))
		}
		pattern := call.Argument(0).String()
		str := call.Argument(1).String()

		re, err := getCompiledRegex(pattern)
		if err != nil {
			return vm.NewGoError(err)
		}
		match := re.FindString(str)
		if match == "" {
			return goja.Null()
		}
		return vm.ToValue(match)
	})

	_ = ex.Set("findAll", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("findAll requires exactly 2 arguments"))
		}
		pattern := call.Argument(0).String()
		str := call.Argument(1).String()

		re, err := getCompiledRegex(pattern)
		if err != nil {
			return vm.NewGoError(err)
		}
		matches := re.FindAllString(str, -1)
		return vm.ToValue(matches)
	})

	_ = ex.Set("replace", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 3 {
			return vm.NewGoError(errors.New("replace requires exactly 3 arguments"))
		}
		pattern := call.Argument(0).String()
		str := call.Argument(1).String()
		replacement := call.Argument(2).String()

		re, err := getCompiledRegex(pattern)
		if err != nil {
			return vm.NewGoError(err)
		}
		result := re.ReplaceAllString(str, replacement)
		return vm.ToValue(result)
	})

	_ = ex.Set("replaceAll", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 3 {
			return vm.NewGoError(errors.New("replaceAll requires exactly 3 arguments"))
		}
		pattern := call.Argument(0).String()
		str := call.Argument(1).String()
		replacement := call.Argument(2).String()

		re, err := getCompiledRegex(pattern)
		if err != nil {
			return vm.NewGoError(err)
		}
		result := re.ReplaceAllString(str, replacement)
		return vm.ToValue(result)
	})

	_ = ex.Set("split", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("split requires exactly 2 arguments"))
		}
		pattern := call.Argument(0).String()
		str := call.Argument(1).String()

		re, err := getCompiledRegex(pattern)
		if err != nil {
			return vm.NewGoError(err)
		}
		parts := re.Split(str, -1)
		return vm.ToValue(parts)
	})

	return ex, nil
}
View Source
var BuiltinSemverGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("compare", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("compare requires exactly 2 arguments"))
		}

		aStr := call.Argument(0).String()
		bStr := call.Argument(1).String()

		a, err := semver.NewVersion(aStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		b, err := semver.NewVersion(bStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		result := a.Compare(b)
		return vm.ToValue(result)
	})

	_ = ex.Set("isValid", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("isValid requires exactly 1 argument"))
		}

		versionStr := call.Argument(0).String()

		_, err := semver.NewVersion(versionStr)
		if err != nil {
			return vm.ToValue(false)
		}

		return vm.ToValue(true)
	})

	_ = ex.Set("stripPrefix", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("stripPrefix requires exactly 1 argument"))
		}

		versionStr := call.Argument(0).String()

		if len(versionStr) > 0 && (versionStr[0] == 'v' || versionStr[0] == 'V') {
			versionStr = versionStr[1:]
		}

		return vm.ToValue(versionStr)
	})

	_ = ex.Set("satisfies", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("satisfies requires exactly 2 arguments"))
		}

		versionStr := call.Argument(0).String()
		constraintStr := call.Argument(1).String()

		version, err := semver.NewVersion(versionStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		constraint, err := semver.NewConstraint(constraintStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		return vm.ToValue(constraint.Check(version))
	})

	_ = ex.Set("major", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("major requires exactly 1 argument"))
		}

		versionStr := call.Argument(0).String()

		version, err := semver.NewVersion(versionStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		return vm.ToValue(int64(version.Major()))
	})

	_ = ex.Set("minor", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("minor requires exactly 1 argument"))
		}

		versionStr := call.Argument(0).String()

		version, err := semver.NewVersion(versionStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		return vm.ToValue(int64(version.Minor()))
	})

	_ = ex.Set("patch", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("patch requires exactly 1 argument"))
		}

		versionStr := call.Argument(0).String()

		version, err := semver.NewVersion(versionStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		return vm.ToValue(int64(version.Patch()))
	})

	_ = ex.Set("prerelease", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("prerelease requires exactly 1 argument"))
		}

		versionStr := call.Argument(0).String()

		version, err := semver.NewVersion(versionStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		prerelease := version.Prerelease()
		if prerelease == "" {
			return goja.Null()
		}

		return vm.ToValue(prerelease)
	})

	_ = ex.Set("metadata", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("metadata requires exactly 1 argument"))
		}

		versionStr := call.Argument(0).String()

		version, err := semver.NewVersion(versionStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		metadata := version.Metadata()
		if metadata == "" {
			return goja.Null()
		}

		return vm.ToValue(metadata)
	})

	return ex, nil
}
View Source
var BuiltinStringGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	return ex, nil
}
View Source
var BuiltinTimeGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("RFC3339", time.RFC3339)
	_ = ex.Set("RFC3339Nano", time.RFC3339Nano)
	_ = ex.Set("RFC1123", time.RFC1123)
	_ = ex.Set("RFC1123Z", time.RFC1123Z)
	_ = ex.Set("RFC822", time.RFC822)
	_ = ex.Set("RFC822Z", time.RFC822Z)

	_ = ex.Set("now", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) > 0 {
			return vm.NewGoError(errors.New("now requires exactly 0 arguments"))
		}

		timestampVal := vm.Get(constants.ExecutionStartTimeUnixKey)
		if timestampVal != nil && timestampVal != goja.Undefined() && timestampVal != goja.Null() {
			return timestampVal
		}

		return vm.ToValue(time.Now().Unix())
	})

	_ = ex.Set("parse", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("parse requires exactly 1 argument"))
		}
		timeStr := call.Argument(0).String()

		t, err := time.Parse(time.RFC3339, timeStr)
		if err != nil {

			t, err = time.Parse(time.RFC3339Nano, timeStr)
			if err != nil {
				return vm.NewGoError(err)
			}
		}

		return vm.ToValue(t.Unix())
	})

	_ = ex.Set("format", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("format requires exactly 2 arguments"))
		}
		timestamp := int64(call.Argument(0).ToFloat())
		formatStr := call.Argument(1).String()

		t := time.Unix(timestamp, 0)
		formatted := t.Format(formatStr)

		return vm.ToValue(formatted)
	})

	_ = ex.Set("isBefore", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("isBefore requires exactly 2 arguments"))
		}
		ts1 := int64(call.Argument(0).ToFloat())
		ts2 := int64(call.Argument(1).ToFloat())
		return vm.ToValue(ts1 < ts2)
	})

	_ = ex.Set("isAfter", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("isAfter requires exactly 2 arguments"))
		}
		ts1 := int64(call.Argument(0).ToFloat())
		ts2 := int64(call.Argument(1).ToFloat())
		return vm.ToValue(ts1 > ts2)
	})

	_ = ex.Set("isBetween", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 3 {
			return vm.NewGoError(errors.New("isBetween requires exactly 3 arguments"))
		}
		ts := int64(call.Argument(0).ToFloat())
		start := int64(call.Argument(1).ToFloat())
		end := int64(call.Argument(2).ToFloat())
		return vm.ToValue(ts >= start && ts <= end)
	})

	_ = ex.Set("addDuration", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("addDuration requires exactly 2 arguments"))
		}
		timestamp := int64(call.Argument(0).ToFloat())
		durationStr := call.Argument(1).String()

		duration, err := time.ParseDuration(durationStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		t := time.Unix(timestamp, 0)
		result := t.Add(duration)

		return vm.ToValue(result.Unix())
	})

	_ = ex.Set("subtractDuration", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 2 {
			return vm.NewGoError(errors.New("subtractDuration requires exactly 2 arguments"))
		}
		timestamp := int64(call.Argument(0).ToFloat())
		durationStr := call.Argument(1).String()

		duration, err := time.ParseDuration(durationStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		t := time.Unix(timestamp, 0)
		result := t.Add(-duration)

		return vm.ToValue(result.Unix())
	})

	_ = ex.Set("unix", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("unix requires exactly 1 argument"))
		}
		timestamp := int64(call.Argument(0).ToFloat())
		return vm.ToValue(time.Unix(timestamp, 0).Unix())
	})

	return ex, nil
}
View Source
var BuiltinUrlGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("parse", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("parse requires exactly 1 argument"))
		}
		urlStr := call.Argument(0).String()

		parsed, err := url.Parse(urlStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		result := vm.NewObject()
		_ = result.Set("scheme", parsed.Scheme)
		_ = result.Set("host", parsed.Host)
		_ = result.Set("path", parsed.Path)
		_ = result.Set("query", parsed.RawQuery)
		_ = result.Set("fragment", parsed.Fragment)
		_ = result.Set("user", parsed.User.String())

		return result
	})

	_ = ex.Set("join", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) == 0 {
			return vm.NewGoError(errors.New("join requires at least 1 argument"))
		}

		// Collect all parts
		var parts []string
		for i := 0; i < len(call.Arguments); i++ {
			if call.Argument(i) != goja.Undefined() && call.Argument(i) != goja.Null() {
				parts = append(parts, call.Argument(i).String())
			}
		}

		if len(parts) == 0 {
			return vm.ToValue("")
		}

		base, err := url.Parse(parts[0])
		if err != nil {
			return vm.NewGoError(err)
		}

		for i := 1; i < len(parts); i++ {
			relative, err := url.Parse(parts[i])
			if err != nil {
				return vm.NewGoError(err)
			}
			base = base.ResolveReference(relative)
		}

		return vm.ToValue(base.String())
	})

	_ = ex.Set("getHost", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("getHost requires exactly 1 argument"))
		}
		urlStr := call.Argument(0).String()

		parsed, err := url.Parse(urlStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		return vm.ToValue(parsed.Host)
	})

	_ = ex.Set("getPath", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("getPath requires exactly 1 argument"))
		}
		urlStr := call.Argument(0).String()

		parsed, err := url.Parse(urlStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		return vm.ToValue(parsed.Path)
	})

	_ = ex.Set("getQuery", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("getQuery requires exactly 1 argument"))
		}
		urlStr := call.Argument(0).String()

		parsed, err := url.Parse(urlStr)
		if err != nil {
			return vm.NewGoError(err)
		}

		return vm.ToValue(parsed.RawQuery)
	})

	_ = ex.Set("isValid", func(call goja.FunctionCall) goja.Value {
		if len(call.Arguments) != 1 {
			return vm.NewGoError(errors.New("isValid requires exactly 1 argument"))
		}
		urlStr := call.Argument(0).String()

		parsed, err := url.Parse(urlStr)
		if err != nil {
			return vm.ToValue(false)
		}

		isValid := parsed.Scheme != "" && (parsed.Host != "" || strings.HasPrefix(urlStr, "/"))
		return vm.ToValue(isValid)
	})

	return ex, nil
}
View Source
var BuiltinUuidGo = func(vm *goja.Runtime) (*goja.Object, error) {
	ex := vm.NewObject()

	_ = ex.Set("v4", func(call goja.FunctionCall) goja.Value {
		return vm.ToValue(uuid.New().String())
	})

	_ = ex.Set("v6", func(call goja.FunctionCall) goja.Value {
		v6, err := uuid.NewV6()
		if err != nil {
			return vm.NewGoError(err)
		}
		return vm.ToValue(v6.String())
	})

	_ = ex.Set("v7", func(call goja.FunctionCall) goja.Value {
		v7, err := uuid.NewV7()
		if err != nil {
			return vm.NewGoError(err)
		}
		return vm.ToValue(v7.String())
	})

	return ex, nil
}
View Source
var ErrPermissionDenied = errors.New("permissions denied")

Functions

func WrapAsIIFE

func WrapAsIIFE(js string) string

WrapAsIIFE wraps module JS to prevent global pollution AND produce a callable factory.

We compile modules to a function form:

(function(require, module, exports) { /* transpiled code */ })

The caller will invoke it with a VM-scoped require() and CJS module/exports.

Types

type AliasRuntime

type AliasRuntime struct {
	VM      *goja.Runtime
	Reg     *Registry
	BaseDir string // directory of the primary "use" module (for resolving relative requires)
	// contains filtered or unexported fields
}

AliasRuntime hosts one clean VM per `use ... as alias` binding. It installs a CJS-like require() and caches module exports by resolved key.

func NewAliasRuntime

func NewAliasRuntime(reg *Registry, baseDir string) *AliasRuntime

func (*AliasRuntime) Require

func (ar *AliasRuntime) Require(ctx context.Context, fromDir, spec string) (*goja.Object, error)

Require implements CommonJS require(spec) with caching.

func (*AliasRuntime) SetupStdLib

func (ar *AliasRuntime) SetupStdLib(ctx context.Context, pack *pack.PackFile) error

SetupStdLib installs the standard library into the VM. This MUST be called before Require is used or the VM is invoked.

type ModuleProvider

type ModuleProvider func(vm *goja.Runtime) (*goja.Object, error)

ModuleProvider constructs a CommonJS `module.exports` object in the given VM. Return the object you want to be `module.exports`.

type ModuleSpec

type ModuleSpec struct {
	Key      string        // canonical key used by registry (e.g., @sentra/math or /abs/path/to/mod.ts)
	Path     string        // filesystem path if not builtin
	Dir      string        // base dir for resolving relative requires
	Builtin  bool          // this is a builtin module
	SourceTS string        // original TS/JS (for builtins or disk)
	Program  *goja.Program // compiled IIFE function returning factory (require,module,exports)=>void

	TranspiledCode string
	TranspiledMap  *SourceMap

	BuiltInProvider ModuleProvider // if non-nil, this module is native Go-backed
	// contains filtered or unexported fields
}

func (*ModuleSpec) KeyOrPath

func (m *ModuleSpec) KeyOrPath() string

type Registry

type Registry struct {
	PackRoot string
	// contains filtered or unexported fields
}

func NewRegistry

func NewRegistry(packRoot string) *Registry

func (*Registry) LoadRequire

func (r *Registry) LoadRequire(fromDir, spec string) (*ModuleSpec, error)

LoadRequire resolves & compiles a dependency of another module by spec.

func (*Registry) PrepareUse

func (r *Registry) PrepareUse(localFrom string, libFrom []string, fileDir string) (*ModuleSpec, error)

PrepareUse compiles (or schedules lazy compilation) for a "use" reference.

func (*Registry) RegisterGoBuiltin

func (r *Registry) RegisterGoBuiltin(name string, provider ModuleProvider)

func (*Registry) RegisterTSBuiltin

func (r *Registry) RegisterTSBuiltin(name, tsSource string)

type SourceMap

type SourceMap struct {
	Version  int
	Sources  []string
	Mappings string
	Names    []string
}

type TranspileResult

type TranspileResult struct {
	Code string
	Map  string
}

func TranspileTS

func TranspileTS(module *ModuleSpec, source string) (TranspileResult, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL