Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fallback engine #300

Merged
merged 6 commits into from
Mar 21, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/snap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.21

- uses: snapcore/action-build@v1
id: build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.21

- name: Test
run: go test ./...
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/antonmedv/fx

go 1.20
go 1.21

require (
github.com/antonmedv/clipboard v1.0.1
Expand All @@ -23,10 +23,10 @@ require (
github.com/aymanbagabas/go-udiff v0.1.3 // indirect
github.com/containerd/console v1.0.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
Expand Down
13 changes: 11 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20240220182346-e401ed450204 h1:O7I1iuzEA7SG+dK8ocOBSlYAA9jBUmCYl/Qa7ey7JAM=
github.com/dop251/goja v0.0.0-20240220182346-e401ed450204/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4=
Expand All @@ -33,15 +34,20 @@ github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I=
github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ=
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
Expand All @@ -52,7 +58,9 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
Expand Down Expand Up @@ -89,6 +97,7 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
Expand Down
22 changes: 15 additions & 7 deletions internal/complete/complete.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package complete

import (
_ "embed"
"fmt"
"os"
"path/filepath"
Expand All @@ -10,6 +11,7 @@ import (
"github.com/dop251/goja"
"github.com/goccy/go-yaml"

"github.com/antonmedv/fx/internal/engine"
"github.com/antonmedv/fx/internal/shlex"
)

Expand Down Expand Up @@ -53,6 +55,9 @@ var globals = []string{
"skip",
}

//go:embed prelude.js
var prelude string

func Complete() bool {
compLine, ok := os.LookupEnv("COMP_LINE")

Expand Down Expand Up @@ -145,7 +150,7 @@ func doComplete(compLine string, compWord string) {
}
}

codeComplete(string(input), args, compWord)
codeComplete(input, args, compWord)
}
}

Expand All @@ -163,7 +168,7 @@ func globalsComplete(compWord string) bool {
return false
}

func codeComplete(input string, args []string, compWord string) {
func codeComplete(input []byte, args []string, compWord string) {
args = args[2:] // Drop binary & file from the args.

if compWord == "" {
Expand All @@ -180,21 +185,24 @@ func codeComplete(input string, args []string, compWord string) {

var code strings.Builder
code.WriteString(prelude)
code.WriteString(fmt.Sprintf("let json = %s\n", input))
code.WriteString(engine.Stdlib)
code.WriteString("let json = ")
code.Write(input)
for _, arg := range args {
if arg == "" {
if arg == "" { // After dropTail, we can have empty strings.
continue
}
code.WriteString(Transform(arg))
code.WriteString(engine.Transform(arg))
}
code.WriteString("\n__keys\n")

out, err := goja.New().RunString(code.String())
vm := goja.New()
value, err := vm.RunString(code.String())
if err != nil {
return
}

if array, ok := out.Export().([]interface{}); ok {
if array, ok := value.Export().([]interface{}); ok {
prefix := dropTail(compWord)
var reply []string
for _, key := range array {
Expand Down
10 changes: 10 additions & 0 deletions internal/complete/prelude.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const __keys = new Set()

Object.prototype.__keys = function () {
if (Array.isArray(this)) return
if (typeof this === 'string') return
if (this instanceof String) return
if (typeof this === 'object' && this !== null)
Object.keys(this).forEach(x => __keys.add(x))
}

126 changes: 126 additions & 0 deletions internal/engine/engine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
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())
}
9 changes: 9 additions & 0 deletions internal/engine/prelude.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const console = {
log: function (...args) {
const parts = []
for (const arg of args) {
parts.push(typeof arg === 'string' ? arg : JSON.stringify(arg, null, 2))
}
println(parts.join(' '))
},
}
32 changes: 9 additions & 23 deletions internal/complete/prelude.go → internal/engine/stdlib.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,3 @@
package complete

const prelude = `
const __keys = new Set()

Object.prototype.__keys = function () {
if (Array.isArray(this)) return
if (typeof this === 'string') return
if (this instanceof String) return
if (typeof this === 'object' && this !== null)
Object.keys(this).forEach(x => __keys.add(x))
}

function apply(fn, ...args) {
if (typeof fn === 'function') return fn(...args)
return fn
Expand All @@ -20,23 +7,23 @@ function len(x) {
if (Array.isArray(x)) return x.length
if (typeof x === 'string') return x.length
if (typeof x === 'object' && x !== null) return Object.keys(x).length
throw new Error()
throw new Error(`Cannot get length of ${typeof x}`)
}

function uniq(x) {
if (Array.isArray(x)) return [...new Set(x)]
throw new Error()
throw new Error(`Cannot get unique values of ${typeof x}`)
}

function sort(x) {
if (Array.isArray(x)) return x.sort()
throw new Error()
throw new Error(`Cannot sort ${typeof x}`)
}

function map(fn) {
return function (x) {
if (Array.isArray(x)) return x.map((v, i) => fn(v, i))
throw new Error()
throw new Error(`Cannot map ${typeof x}`)
}
}

Expand All @@ -47,7 +34,7 @@ function sortBy(fn) {
const fb = fn(b)
return fa < fb ? -1 : fa > fb ? 1 : 0
})
throw new Error()
throw new Error(`Cannot sort ${typeof x}`)
}
}

Expand Down Expand Up @@ -85,21 +72,20 @@ function zip(...x) {

function flatten(x) {
if (Array.isArray(x)) return x.flat()
throw new Error()
throw new Error(`Cannot flatten ${typeof x}`)
}

function reverse(x) {
if (Array.isArray(x)) return x.reverse()
throw new Error()
throw new Error(`Cannot reverse ${typeof x}`)
}

function keys(x) {
if (typeof x === 'object' && x !== null) return Object.keys(x)
throw new Error()
throw new Error(`Cannot get keys of ${typeof x}`)
}

function values(x) {
if (typeof x === 'object' && x !== null) return Object.values(x)
throw new Error()
throw new Error(`Cannot get values of ${typeof x}`)
}
`
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package complete
package engine

import (
"fmt"
Expand Down
Loading
Loading