You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fx/internal/engine/engine.go

127 lines
2.2 KiB
Go

package engine
import (
_ "embed"
"fmt"
"io"
"os"
"strconv"
"strings"
"github.com/dop251/goja"
"github.com/goccy/go-yaml"
"github.com/antonmedv/fx/internal/jsonx"
)
//go:embed stdlib.js
var Stdlib string
//go:embed prelude.js
var prelude string
func Reduce(args []string) {
if len(args) < 1 {
panic("args must have at least one element")
}
var (
flagYaml bool
flagRaw bool
flagSlurp bool
)
var src io.Reader = os.Stdin
if isFile(args[0]) {
src = open(args[0], &flagYaml)
args = args[1:]
} else if isFile(args[len(args)-1]) {
src = open(args[len(args)-1], &flagYaml)
args = args[:len(args)-1]
}
var fns []string
for _, arg := range args {
switch arg {
case "--yaml":
flagYaml = true
case "--raw", "-r":
flagRaw = true
case "--slurp", "-s":
flagSlurp = true
case "-rs", "-sr":
flagRaw = true
flagSlurp = true
default:
fns = append(fns, arg)
}
}
if flagSlurp {
println("Error: Built-in JS engine does not support \"--slurp\" flag. Install Node.js or Deno to use this flag.")
os.Exit(1)
}
data, err := io.ReadAll(src)
if err != nil {
panic(err)
}
if flagRaw {
data = []byte(strconv.Quote(string(data)))
} else if flagYaml {
data, err = yaml.YAMLToJSON(data)
if err != nil {
println(err.Error())
os.Exit(1)
}
} else {
node, err := jsonx.Parse(data)
if err != nil {
println(err.Error())
os.Exit(1)
}
data = []byte(node.String())
}
var code strings.Builder
code.WriteString(prelude)
code.WriteString(Stdlib)
code.WriteString(fmt.Sprintf("let json = JSON.parse(%q)\n", data))
for _, fn := range fns {
code.WriteString(Transform(fn))
}
code.WriteString("JSON.stringify(json)")
vm := goja.New()
vm.Set("println", func(s string) any {
fmt.Println(s)
return nil
})
value, err := vm.RunString(code.String())
if err != nil {
println(err.Error())
os.Exit(1)
}
output, ok := value.Export().(string)
if !ok {
println("undefined")
return
}
node, err := jsonx.Parse([]byte(output))
if err != nil {
println(err.Error())
os.Exit(1)
}
if len(node.Value) > 0 && node.Value[0] == '"' {
s, _ := strconv.Unquote(string(node.Value))
fmt.Println(s)
return
}
fmt.Print(node.PrettyPrint())
}