wip2
This commit is contained in:
137
internal/runtime/runtime.go
Normal file
137
internal/runtime/runtime.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
"github.com/evanw/esbuild/pkg/api"
|
||||
"reichard.io/poiesis/internal/builtin"
|
||||
)
|
||||
|
||||
type Runtime struct {
|
||||
vm *goja.Runtime
|
||||
stdout io.Writer
|
||||
stderr io.Writer
|
||||
}
|
||||
|
||||
func New() *Runtime {
|
||||
vm := goja.New()
|
||||
|
||||
r := &Runtime{vm: vm, stdout: os.Stdout, stderr: os.Stderr}
|
||||
r.setupConsole()
|
||||
builtin.RegisterBuiltins(vm)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Runtime) setupConsole() {
|
||||
console := r.vm.NewObject()
|
||||
_ = r.vm.Set("console", console)
|
||||
|
||||
_ = console.Set("log", func(call goja.FunctionCall) goja.Value {
|
||||
args := call.Arguments
|
||||
for i, arg := range args {
|
||||
if i > 0 {
|
||||
_, _ = fmt.Fprint(r.stdout, " ")
|
||||
}
|
||||
_, _ = fmt.Fprint(r.stdout, arg.String())
|
||||
}
|
||||
_, _ = fmt.Fprintln(r.stdout)
|
||||
return goja.Undefined()
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Runtime) SetOutput(stdout, stderr io.Writer) {
|
||||
r.stdout = stdout
|
||||
r.stderr = stderr
|
||||
consoleObj := r.vm.Get("console")
|
||||
if consoleObj != nil {
|
||||
console := consoleObj.ToObject(r.vm)
|
||||
if console != nil {
|
||||
r.setupConsole()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Runtime) RunFile(filePath string, stdout, stderr io.Writer) error {
|
||||
r.stdout = stdout
|
||||
r.stderr = stderr
|
||||
r.setupConsole()
|
||||
|
||||
content, err := r.transformFile(filePath)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(stderr, "Error: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(content.errors) > 0 {
|
||||
_, _ = fmt.Fprintf(stderr, "Transpilation errors:\n")
|
||||
for _, err := range content.errors {
|
||||
_, _ = fmt.Fprintf(stderr, " %s\n", err.Text)
|
||||
}
|
||||
return fmt.Errorf("transpilation failed")
|
||||
}
|
||||
|
||||
_, err = r.vm.RunString(content.code)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(stderr, "Execution error: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runtime) RunCode(tsCode string, stdout, stderr io.Writer) error {
|
||||
r.stdout = stdout
|
||||
r.stderr = stderr
|
||||
r.setupConsole()
|
||||
|
||||
content := r.transformCode(tsCode)
|
||||
|
||||
if len(content.errors) > 0 {
|
||||
_, _ = fmt.Fprintf(stderr, "Transpilation errors:\n")
|
||||
for _, err := range content.errors {
|
||||
_, _ = fmt.Fprintf(stderr, " %s\n", err.Text)
|
||||
}
|
||||
return fmt.Errorf("transpilation failed")
|
||||
}
|
||||
|
||||
_, err := r.vm.RunString(content.code)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(stderr, "Execution error: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type transformResult struct {
|
||||
code string
|
||||
errors []api.Message
|
||||
}
|
||||
|
||||
func (r *Runtime) transformFile(filePath string) (*transformResult, error) {
|
||||
tsFileContent, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading file: %w", err)
|
||||
}
|
||||
|
||||
return r.transformCode(string(tsFileContent)), nil
|
||||
}
|
||||
|
||||
func (r *Runtime) transformCode(tsCode string) *transformResult {
|
||||
result := api.Transform(tsCode, api.TransformOptions{
|
||||
Loader: api.LoaderTS,
|
||||
Target: api.ES2020,
|
||||
Format: api.FormatIIFE,
|
||||
Sourcemap: api.SourceMapNone,
|
||||
TreeShaking: api.TreeShakingFalse,
|
||||
})
|
||||
|
||||
return &transformResult{
|
||||
code: string(result.Code),
|
||||
errors: result.Errors,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user