wip rename

This commit is contained in:
2026-01-28 14:22:35 -05:00
parent 604178341d
commit a613283539
11 changed files with 112 additions and 158 deletions

View File

@@ -1 +0,0 @@
package builtin

View File

@@ -1,4 +1,4 @@
package builtin package functions
import ( import (
"fmt" "fmt"

View File

@@ -1,4 +1,4 @@
package builtin package functions
import ( import (
"context" "context"
@@ -18,21 +18,21 @@ func (t TestArgs) Validate() error {
return nil return nil
} }
func TestAsyncBuiltin(t *testing.T) { func TestAsyncFunction(t *testing.T) {
RegisterAsyncBuiltin("testAsync", func(_ context.Context, args TestArgs) (string, error) { RegisterAsyncFunction("testAsync", func(_ context.Context, args TestArgs) (string, error) {
return "result: " + args.Field1, nil return "result: " + args.Field1, nil
}) })
registryMutex.RLock() registryMutex.RLock()
builtin, ok := builtinRegistry["testAsync"] fn, ok := functionRegistry["testAsync"]
registryMutex.RUnlock() registryMutex.RUnlock()
require.True(t, ok, "testAsync should be registered") require.True(t, ok, "testAsync should be registered")
assert.Contains(t, builtin.Definition(), "Promise<string>", "definition should include Promise<string>") assert.Contains(t, fn.Definition(), "Promise<string>", "definition should include Promise<string>")
} }
func TestAsyncBuiltinResolution(t *testing.T) { func TestAsyncFunctionResolution(t *testing.T) {
RegisterAsyncBuiltin("resolveTest", func(_ context.Context, args TestArgs) (string, error) { RegisterAsyncFunction("resolveTest", func(_ context.Context, args TestArgs) (string, error) {
return "test-result", nil return "test-result", nil
}) })
@@ -43,15 +43,15 @@ func TestAsyncBuiltinResolution(t *testing.T) {
}() }()
vm.SetCanBlock(true) vm.SetCanBlock(true)
RegisterBuiltins(context.Background(), vm) RegisterFunctions(context.Background(), vm)
result, err := vm.Eval(`resolveTest("hello")`, quickjs.EvalGlobal) result, err := vm.Eval(`resolveTest("hello")`, quickjs.EvalGlobal)
require.NoError(t, err) require.NoError(t, err)
assert.NotNil(t, result) assert.NotNil(t, result)
} }
func TestAsyncBuiltinRejection(t *testing.T) { func TestAsyncFunctionRejection(t *testing.T) {
RegisterAsyncBuiltin("rejectTest", func(_ context.Context, args TestArgs) (string, error) { RegisterAsyncFunction("rejectTest", func(_ context.Context, args TestArgs) (string, error) {
return "", assert.AnError return "", assert.AnError
}) })
@@ -62,7 +62,7 @@ func TestAsyncBuiltinRejection(t *testing.T) {
}() }()
vm.SetCanBlock(true) vm.SetCanBlock(true)
RegisterBuiltins(context.Background(), vm) RegisterFunctions(context.Background(), vm)
result, err := vm.Eval(`rejectTest({field1: "hello"})`, quickjs.EvalGlobal) result, err := vm.Eval(`rejectTest({field1: "hello"})`, quickjs.EvalGlobal)
require.NoError(t, err) require.NoError(t, err)
@@ -70,7 +70,7 @@ func TestAsyncBuiltinRejection(t *testing.T) {
} }
func TestNonPromise(t *testing.T) { func TestNonPromise(t *testing.T) {
RegisterBuiltin("nonPromiseTest", func(_ context.Context, args TestArgs) (string, error) { RegisterFunction("nonPromiseTest", func(_ context.Context, args TestArgs) (string, error) {
return "sync-result", nil return "sync-result", nil
}) })
@@ -81,7 +81,7 @@ func TestNonPromise(t *testing.T) {
}() }()
vm.SetCanBlock(true) vm.SetCanBlock(true)
RegisterBuiltins(context.Background(), vm) RegisterFunctions(context.Background(), vm)
result, err := vm.Eval(`nonPromiseTest({field1: "hello"})`, quickjs.EvalGlobal) result, err := vm.Eval(`nonPromiseTest({field1: "hello"})`, quickjs.EvalGlobal)
require.NoError(t, err) require.NoError(t, err)

View File

@@ -1,4 +1,4 @@
package builtin package functions
import ( import (
"fmt" "fmt"
@@ -8,12 +8,12 @@ import (
) )
var ( var (
builtinRegistry = make(map[string]Builtin) functionRegistry = make(map[string]Function)
registryMutex sync.RWMutex registryMutex sync.RWMutex
collector *typeCollector collector *typeCollector
) )
func registerBuiltin[A Args, R any](name string, isAsync bool, fn Func[A, R]) { func registerFunction[A Args, R any](name string, isAsync bool, fn RawFunc[A, R]) {
registryMutex.Lock() registryMutex.Lock()
defer registryMutex.Unlock() defer registryMutex.Unlock()
@@ -23,14 +23,14 @@ func registerBuiltin[A Args, R any](name string, isAsync bool, fn Func[A, R]) {
tType := reflect.TypeFor[A]() tType := reflect.TypeFor[A]()
if tType.Kind() != reflect.Struct { if tType.Kind() != reflect.Struct {
panic(fmt.Sprintf("builtin %s: argument must be a struct type, got %v", name, tType)) panic(fmt.Sprintf("function %s: argument must be a struct type, got %v", name, tType))
} }
fnType := reflect.TypeOf(fn) fnType := reflect.TypeOf(fn)
types := collector.collectTypes(tType, fnType) types := collector.collectTypes(tType, fnType)
paramTypes := collector.getParamTypes() paramTypes := collector.getParamTypes()
builtinRegistry[name] = &builtinImpl[A, R]{ functionRegistry[name] = &functionImpl[A, R]{
name: name, name: name,
fn: fn, fn: fn,
types: types, types: types,
@@ -38,7 +38,7 @@ func registerBuiltin[A Args, R any](name string, isAsync bool, fn Func[A, R]) {
} }
} }
func GetBuiltinsDeclarations() string { func GetFunctionDeclarations() string {
registryMutex.RLock() registryMutex.RLock()
defer registryMutex.RUnlock() defer registryMutex.RUnlock()
@@ -46,14 +46,14 @@ func GetBuiltinsDeclarations() string {
var typeDefs []string var typeDefs []string
var functionDecls []string var functionDecls []string
for _, builtin := range builtinRegistry { for _, fn := range functionRegistry {
for _, t := range builtin.Types() { for _, t := range fn.Types() {
if !typeDefinitions[t] { if !typeDefinitions[t] {
typeDefinitions[t] = true typeDefinitions[t] = true
typeDefs = append(typeDefs, t) typeDefs = append(typeDefs, t)
} }
} }
functionDecls = append(functionDecls, builtin.Definition()) functionDecls = append(functionDecls, fn.Definition())
} }
result := strings.Join(typeDefs, "\n\n") result := strings.Join(typeDefs, "\n\n")
@@ -65,14 +65,14 @@ func GetBuiltinsDeclarations() string {
return result return result
} }
func RegisterBuiltin[T Args, R any](name string, fn Func[T, R]) { func GetRegisteredFunctions() map[string]Function {
registerBuiltin(name, false, fn) return functionRegistry
} }
func RegisterAsyncBuiltin[T Args, R any](name string, fn Func[T, R]) { func RegisterFunction[T Args, R any](name string, fn RawFunc[T, R]) {
registerBuiltin(name, true, fn) registerFunction(name, false, fn)
} }
func GetBuiltins() map[string]Builtin { func RegisterAsyncFunction[T Args, R any](name string, fn RawFunc[T, R]) {
return builtinRegistry registerFunction(name, true, fn)
} }

View File

@@ -1,4 +1,4 @@
package builtin package functions
import ( import (
"context" "context"
@@ -6,39 +6,39 @@ import (
"reflect" "reflect"
) )
type Builtin interface { type Function interface {
Name() string Name() string
Types() []string Types() []string
Definition() string Definition() string
WrapFn(context.Context) func(...any) (any, error) WrapFn(context.Context) func(...any) (any, error)
} }
type Func[A Args, R any] func(ctx context.Context, args A) (R, error) type RawFunc[A Args, R any] func(context.Context, A) (R, error)
type Args interface { type Args interface {
Validate() error Validate() error
} }
type builtinImpl[A Args, R any] struct { type functionImpl[A Args, R any] struct {
name string name string
fn Func[A, R] fn RawFunc[A, R]
definition string definition string
types []string types []string
} }
func (b *builtinImpl[A, R]) Name() string { func (b *functionImpl[A, R]) Name() string {
return b.name return b.name
} }
func (b *builtinImpl[A, R]) Types() []string { func (b *functionImpl[A, R]) Types() []string {
return b.types return b.types
} }
func (b *builtinImpl[A, R]) Definition() string { func (b *functionImpl[A, R]) Definition() string {
return b.definition return b.definition
} }
func (b *builtinImpl[A, R]) WrapFn(ctx context.Context) func(...any) (any, error) { func (b *functionImpl[A, R]) WrapFn(ctx context.Context) func(...any) (any, error) {
return func(allArgs ...any) (any, error) { return func(allArgs ...any) (any, error) {
// Populate Arguments // Populate Arguments
var fnArgs A var fnArgs A

View File

@@ -1,4 +1,4 @@
package builtin package functions
import ( import (
"fmt" "fmt"

View File

@@ -1,4 +1,4 @@
package builtin package functions
import ( import (
"context" "context"
@@ -18,11 +18,11 @@ func (t TestBasicArgs) Validate() error { return nil }
func TestBasicType(t *testing.T) { func TestBasicType(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestBasicArgs, string]("basic", func(ctx context.Context, args TestBasicArgs) (string, error) { RegisterFunction[TestBasicArgs, string]("basic", func(ctx context.Context, args TestBasicArgs) (string, error) {
return args.Name, nil return args.Name, nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function basic(name: string, age: number): string;") assert.Contains(t, defs, "declare function basic(name: string, age: number): string;")
assert.Contains(t, defs, "interface TestBasicArgs") assert.Contains(t, defs, "interface TestBasicArgs")
} }
@@ -30,7 +30,7 @@ func TestBasicType(t *testing.T) {
func resetRegistry() { func resetRegistry() {
registryLock.Lock() registryLock.Lock()
defer registryLock.Unlock() defer registryLock.Unlock()
builtinRegistry = make(map[string]Builtin) functionRegistry = make(map[string]Function)
} }
var ( var (
@@ -47,11 +47,11 @@ func (t TestComplexArgs) Validate() error { return nil }
func TestComplexTypes(t *testing.T) { func TestComplexTypes(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestComplexArgs, bool]("complex", func(ctx context.Context, args TestComplexArgs) (bool, error) { RegisterFunction[TestComplexArgs, bool]("complex", func(ctx context.Context, args TestComplexArgs) (bool, error) {
return args.Flag, nil return args.Flag, nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function complex(items: number[], data: Record<string, any>, flag: boolean): boolean;") assert.Contains(t, defs, "declare function complex(items: number[], data: Record<string, any>, flag: boolean): boolean;")
} }
@@ -66,11 +66,11 @@ func (t TestNestedArgs) Validate() error { return nil }
func TestNestedStruct(t *testing.T) { func TestNestedStruct(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestNestedArgs, string]("nested", func(ctx context.Context, args TestNestedArgs) (string, error) { RegisterFunction[TestNestedArgs, string]("nested", func(ctx context.Context, args TestNestedArgs) (string, error) {
return args.User.FirstName, nil return args.User.FirstName, nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function nested(user: {}): string;") assert.Contains(t, defs, "declare function nested(user: {}): string;")
} }
@@ -84,11 +84,11 @@ func (t TestOptionalArgs) Validate() error { return nil }
func TestOptionalFields(t *testing.T) { func TestOptionalFields(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestOptionalArgs, string]("optional", func(ctx context.Context, args TestOptionalArgs) (string, error) { RegisterFunction[TestOptionalArgs, string]("optional", func(ctx context.Context, args TestOptionalArgs) (string, error) {
return args.Name, nil return args.Name, nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function optional(name: string, age?: number | null, score?: number | null): string;") assert.Contains(t, defs, "declare function optional(name: string, age?: number | null, score?: number | null): string;")
} }
@@ -105,11 +105,11 @@ func (t TestResultArgs) Validate() error { return nil }
func TestResultStruct(t *testing.T) { func TestResultStruct(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestResultArgs, TestResult]("result", func(ctx context.Context, args TestResultArgs) (TestResult, error) { RegisterFunction[TestResultArgs, TestResult]("result", func(ctx context.Context, args TestResultArgs) (TestResult, error) {
return TestResult{ID: 1}, nil return TestResult{ID: 1}, nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function result(input: string): TestResult;") assert.Contains(t, defs, "declare function result(input: string): TestResult;")
assert.Contains(t, defs, "interface TestResult {id: number; data: number[]}") assert.Contains(t, defs, "interface TestResult {id: number; data: number[]}")
} }
@@ -126,11 +126,11 @@ type TestAsyncResult struct {
func TestAsyncPromise(t *testing.T) { func TestAsyncPromise(t *testing.T) {
resetRegistry() resetRegistry()
RegisterAsyncBuiltin[TestAsyncArgs, *TestAsyncStatus]("async", func(ctx context.Context, args TestAsyncArgs) (*TestAsyncStatus, error) { RegisterAsyncFunction[TestAsyncArgs, *TestAsyncStatus]("async", func(ctx context.Context, args TestAsyncArgs) (*TestAsyncStatus, error) {
return &TestAsyncStatus{Code: 200}, nil return &TestAsyncStatus{Code: 200}, nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function async(url: string): Promise<TestAsyncStatus | null>;") assert.Contains(t, defs, "declare function async(url: string): Promise<TestAsyncStatus | null>;")
assert.Contains(t, defs, "interface TestAsyncStatus") assert.Contains(t, defs, "interface TestAsyncStatus")
} }
@@ -151,11 +151,11 @@ func (t TestNestedPointerArgs) Validate() error { return nil }
func TestNestedPointerInResult(t *testing.T) { func TestNestedPointerInResult(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestNestedPointerArgs, *TestNestedPointerResult]("pointerResult", func(ctx context.Context, args TestNestedPointerArgs) (*TestNestedPointerResult, error) { RegisterFunction[TestNestedPointerArgs, *TestNestedPointerResult]("pointerResult", func(ctx context.Context, args TestNestedPointerArgs) (*TestNestedPointerResult, error) {
return &TestNestedPointerResult{Value: "test"}, nil return &TestNestedPointerResult{Value: "test"}, nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function pointerResult(id: number): TestNestedPointerResult | null;") assert.Contains(t, defs, "declare function pointerResult(id: number): TestNestedPointerResult | null;")
} }
@@ -167,11 +167,11 @@ func (t TestUintArgs) Validate() error { return nil }
func TestUintType(t *testing.T) { func TestUintType(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestUintArgs, uint]("uint", func(ctx context.Context, args TestUintArgs) (uint, error) { RegisterFunction[TestUintArgs, uint]("uint", func(ctx context.Context, args TestUintArgs) (uint, error) {
return args.Value, nil return args.Value, nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function uint(value: number): number;") assert.Contains(t, defs, "declare function uint(value: number): number;")
} }
@@ -183,11 +183,11 @@ func (t TestFloatArgs) Validate() error { return nil }
func TestFloatType(t *testing.T) { func TestFloatType(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestFloatArgs, float32]("float", func(ctx context.Context, args TestFloatArgs) (float32, error) { RegisterFunction[TestFloatArgs, float32]("float", func(ctx context.Context, args TestFloatArgs) (float32, error) {
return float32(args.Amount), nil return float32(args.Amount), nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function float(amount: number): number;") assert.Contains(t, defs, "declare function float(amount: number): number;")
} }
@@ -201,11 +201,11 @@ func (t TestPointerInArgs) Validate() error { return nil }
func TestNestedPointerStruct(t *testing.T) { func TestNestedPointerStruct(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestPointerInArgs, string]("nestedPointer", func(ctx context.Context, args TestPointerInArgs) (string, error) { RegisterFunction[TestPointerInArgs, string]("nestedPointer", func(ctx context.Context, args TestPointerInArgs) (string, error) {
return "test", nil return "test", nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function nestedPointer(user?: {} | null): string;") assert.Contains(t, defs, "declare function nestedPointer(user?: {} | null): string;")
} }
@@ -217,11 +217,11 @@ func (t TestErrorOnlyArgs) Validate() error { return nil }
func TestErrorOnlyReturn(t *testing.T) { func TestErrorOnlyReturn(t *testing.T) {
resetRegistry() resetRegistry()
RegisterBuiltin[TestErrorOnlyArgs, struct{}]("errorOnly", func(ctx context.Context, args TestErrorOnlyArgs) (struct{}, error) { RegisterFunction[TestErrorOnlyArgs, struct{}]("errorOnly", func(ctx context.Context, args TestErrorOnlyArgs) (struct{}, error) {
return struct{}{}, nil return struct{}{}, nil
}) })
defs := GetBuiltinsDeclarations() defs := GetFunctionDeclarations()
assert.Contains(t, defs, "declare function errorOnly(input: string): {};") assert.Contains(t, defs, "declare function errorOnly(input: string): {};")
} }

View File

@@ -8,7 +8,7 @@ import (
"github.com/evanw/esbuild/pkg/api" "github.com/evanw/esbuild/pkg/api"
"modernc.org/quickjs" "modernc.org/quickjs"
"reichard.io/poiesis/internal/builtin" "reichard.io/poiesis/internal/functions"
) )
type Runtime struct { type Runtime struct {
@@ -59,7 +59,7 @@ func (r *Runtime) populateGlobals() error {
} }
// Register Custom Functions // Register Custom Functions
for name, builtin := range builtin.GetBuiltins() { for name, builtin := range functions.GetRegisteredFunctions() {
// Register Main Function // Register Main Function
if err := r.vm.RegisterFunc(name, builtin.WrapFn(r.ctx), false); err != nil { if err := r.vm.RegisterFunc(name, builtin.WrapFn(r.ctx), false); err != nil {
return err return err

View File

@@ -1,60 +0,0 @@
package standard
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"modernc.org/quickjs"
"reichard.io/poiesis/internal/builtin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFetchReturnsPromise(t *testing.T) {
vm, err := quickjs.NewVM()
require.NoError(t, err)
defer func() {
_ = vm.Close()
}()
vm.SetCanBlock(true)
builtin.RegisterBuiltins(context.Background(), vm)
result, err := vm.Eval(`fetch({input: "https://example.com"})`, quickjs.EvalGlobal)
require.NoError(t, err)
assert.NotNil(t, result)
}
func TestFetchAsyncAwait(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"status":"ok"}`))
}))
defer server.Close()
vm, err := quickjs.NewVM()
require.NoError(t, err)
defer func() {
_ = vm.Close()
}()
vm.SetCanBlock(true)
builtin.RegisterBuiltins(context.Background(), vm)
result, err := vm.Eval(`fetch({input: "`+server.URL+`"})`, quickjs.EvalGlobal)
require.NoError(t, err)
if obj, ok := result.(*quickjs.Object); ok {
var arr []any
if err := obj.Into(&arr); err == nil && len(arr) > 0 {
if response, ok := arr[0].(map[string]any); ok {
assert.True(t, response["ok"].(bool))
}
}
}
}

View File

@@ -1,4 +1,4 @@
package standard package stdlib
import ( import (
"context" "context"
@@ -8,9 +8,13 @@ import (
"net/http" "net/http"
"strings" "strings"
"reichard.io/poiesis/internal/builtin" "reichard.io/poiesis/internal/functions"
) )
func init() {
functions.RegisterAsyncFunction("fetch", Fetch)
}
type FetchArgs struct { type FetchArgs struct {
Input string `json:"input"` Input string `json:"input"`
Init *RequestInit `json:"init,omitempty"` Init *RequestInit `json:"init,omitempty"`
@@ -106,17 +110,3 @@ func Fetch(_ context.Context, args FetchArgs) (Response, error) {
Headers: resultHeaders, Headers: resultHeaders,
}, nil }, nil
} }
func Add(_ context.Context, args AddArgs) (int, error) {
return args.A + args.B, nil
}
func Greet(_ context.Context, args GreetArgs) (string, error) {
return fmt.Sprintf("Hello, %s!", args.Name), nil
}
func init() {
builtin.RegisterAsyncBuiltin("fetch", Fetch)
builtin.RegisterBuiltin("add", Add)
builtin.RegisterBuiltin("greet", Greet)
}

View File

@@ -1,4 +1,4 @@
package standard package stdlib
import ( import (
"context" "context"
@@ -8,6 +8,8 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"modernc.org/quickjs"
"reichard.io/poiesis/internal/functions"
) )
func TestFetch(t *testing.T) { func TestFetch(t *testing.T) {
@@ -97,24 +99,47 @@ func TestFetchDefaults(t *testing.T) {
assert.True(t, result.OK) assert.True(t, result.OK)
} }
func TestAdd(t *testing.T) { func TestFetchReturnsPromise(t *testing.T) {
ctx := context.Background() vm, err := quickjs.NewVM()
result, err := Add(ctx, AddArgs{A: 5, B: 10})
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 15, result) defer func() {
_ = vm.Close()
}()
vm.SetCanBlock(true)
result, err = Add(ctx, AddArgs{A: -3, B: 7}) functions.RegisterBuiltins(context.Background(), vm)
result, err := vm.Eval(`fetch({input: "https://example.com"})`, quickjs.EvalGlobal)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 4, result) assert.NotNil(t, result)
} }
func TestGreet(t *testing.T) { func TestFetchAsyncAwait(t *testing.T) {
ctx := context.Background() server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
result, err := Greet(ctx, GreetArgs{Name: "World"}) w.Header().Set("Content-Type", "application/json")
require.NoError(t, err) w.WriteHeader(http.StatusOK)
assert.Equal(t, "Hello, World!", result) _, _ = w.Write([]byte(`{"status":"ok"}`))
}))
defer server.Close()
result, err = Greet(ctx, GreetArgs{Name: "Alice"}) vm, err := quickjs.NewVM()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "Hello, Alice!", result) defer func() {
_ = vm.Close()
}()
vm.SetCanBlock(true)
functions.RegisterBuiltins(context.Background(), vm)
result, err := vm.Eval(`fetch({input: "`+server.URL+`"})`, quickjs.EvalGlobal)
require.NoError(t, err)
if obj, ok := result.(*quickjs.Object); ok {
var arr []any
if err := obj.Into(&arr); err == nil && len(arr) > 0 {
if response, ok := arr[0].(map[string]any); ok {
assert.True(t, response["ok"].(bool))
}
}
}
} }