Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions cmd/gh-aw-wasm/compile_recovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import (
"fmt"
"runtime/debug"
)

func compileWorkflowPanicError(r any) error {
return fmt.Errorf("compileWorkflow panic: %v\n%s", r, debug.Stack())
}

func runCompileWithRecovery(doCompile func() (any, error), resolve func(any), reject func(error)) {
defer func() {
if r := recover(); r != nil {
reject(compileWorkflowPanicError(r))
}
}()

result, err := doCompile()
if err != nil {
reject(err)
return
}
resolve(result)
}
71 changes: 71 additions & 0 deletions cmd/gh-aw-wasm/compile_recovery_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package main

import (
"errors"
"strings"
"testing"
)

func TestRunCompileWithRecoverySuccess(t *testing.T) {
var resolved any
var rejected error

runCompileWithRecovery(
func() (any, error) { return "ok", nil },
func(result any) { resolved = result },
func(err error) { rejected = err },
)

if rejected != nil {
t.Fatalf("expected no rejection, got %v", rejected)
}
if resolved != "ok" {
t.Fatalf("expected resolve value %q, got %v", "ok", resolved)
}
}

func TestRunCompileWithRecoveryError(t *testing.T) {
want := errors.New("compile failed")
var resolved any
var rejected error

runCompileWithRecovery(
func() (any, error) { return nil, want },
func(result any) { resolved = result },
func(err error) { rejected = err },
)

if resolved != nil {
t.Fatalf("expected no resolve value, got %v", resolved)
}
if !errors.Is(rejected, want) {
t.Fatalf("expected rejection %v, got %v", want, rejected)
}
}

func TestRunCompileWithRecoveryPanic(t *testing.T) {
var resolved any
var rejected error

runCompileWithRecovery(
func() (any, error) {
panic("boom")
},
func(result any) { resolved = result },
func(err error) { rejected = err },
)

if resolved != nil {
t.Fatalf("expected no resolve value, got %v", resolved)
}
if rejected == nil {
t.Fatal("expected rejection from panic, got nil")
}
message := rejected.Error()
if !strings.Contains(message, "compileWorkflow panic: boom") {
t.Fatalf("expected panic prefix in rejection, got %q", message)
}
if !strings.Contains(message, "TestRunCompileWithRecoveryPanic") {
t.Fatalf("expected stack trace in rejection, got %q", message)
}
}
18 changes: 11 additions & 7 deletions cmd/gh-aw-wasm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,17 @@ func compileWorkflow(this js.Value, args []js.Value) any {

go func() {
defer handler.Release()

result, err := doCompile(markdown, files, filename)
if err != nil {
reject.Invoke(js.Global().Get("Error").New(err.Error()))
return
}
resolve.Invoke(result)
runCompileWithRecovery(
func() (any, error) {
return doCompile(markdown, files, filename)
},
func(result any) {
resolve.Invoke(result)
},
func(err error) {
reject.Invoke(js.Global().Get("Error").New(err.Error()))
},
)
}()

return nil
Expand Down
Loading