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()) }