Documentation
¶
Index ¶
- Variables
- func WrapAsIIFE(js string) string
- type AliasRuntime
- type ModuleProvider
- type ModuleSpec
- type Registry
- func (r *Registry) LoadRequire(fromDir, spec string) (*ModuleSpec, error)
- func (r *Registry) PrepareUse(localFrom string, libFrom []string, fileDir string) (*ModuleSpec, error)
- func (r *Registry) RegisterGoBuiltin(name string, provider ModuleProvider)
- func (r *Registry) RegisterTSBuiltin(name, tsSource string)
- type SourceMap
- type TranspileResult
Constants ¶
This section is empty.
Variables ¶
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 }
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 }
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 }
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 }
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 }
var BuiltinJSTS []byte
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 }
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 }
var BuiltinMathGo = func(vm *goja.Runtime) (*goja.Object, error) { ex := vm.NewObject() return ex, nil }
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 }
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 }
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 }
var BuiltinStringGo = func(vm *goja.Runtime) (*goja.Object, error) { ex := vm.NewObject() return ex, nil }
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 }
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 }
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 }
var ErrPermissionDenied = errors.New("permissions denied")
Functions ¶
func WrapAsIIFE ¶
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) SetupStdLib ¶
SetupStdLib installs the standard library into the VM. This MUST be called before Require is used or the VM is invoked.
type ModuleProvider ¶
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 (*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 ¶
type TranspileResult ¶
func TranspileTS ¶
func TranspileTS(module *ModuleSpec, source string) (TranspileResult, error)
Source Files
¶
- alias_runtime.go
- builtin_base64.go
- builtin_collection_utils.go
- builtin_crypto.go
- builtin_encoding.go
- builtin_go.go
- builtin_hash.go
- builtin_json.go
- builtin_jwt.go
- builtin_math.go
- builtin_net.go
- builtin_regex.go
- builtin_semver.go
- builtin_string.go
- builtin_time.go
- builtin_ts_src.go
- builtin_url.go
- builtin_uuid.go
- registry.go
- stdlib.go
- stdlib_env.go
- tscompile.go