-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Using Otto, we aren’t able to use full regular expressions that JavaScript supports, since it uses the default regular expression engine in Go. Goja supports regular expressions from JavaScript
- Loading branch information
Showing
3 changed files
with
158 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,103 @@ | ||
package js | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"strings" | ||
"sync" | ||
|
||
"github.com/robertkrimen/otto" | ||
Dbg "github.com/robertkrimen/otto/dbg" | ||
"github.com/dop251/goja" | ||
"github.com/enmand/quarid-go/generated/langsupport" | ||
) | ||
|
||
// Implements require() in the JavaScript VM. | ||
func RequireFunc(call otto.FunctionCall) otto.Value { | ||
// Require implements the 'require(module)' pattern from NodeJS | ||
type Require struct { | ||
modules map[string]*goja.Program | ||
runtime *goja.Runtime | ||
|
||
v, _ := call.Otto.Get(_modpath) | ||
l sync.Mutex | ||
} | ||
|
||
// NewRequire returns a new Require object | ||
func NewRequire(runtime *goja.Runtime) *Require { | ||
return &Require{ | ||
modules: make(map[string]*goja.Program), | ||
runtime: runtime, | ||
} | ||
} | ||
|
||
path, _ := call.Argument(0).ToString() | ||
fullPath := fmt.Sprintf("%s/%s", v.String(), path) | ||
// Require implements require() in the JavaScript VM. | ||
func (r *Require) Require(call goja.FunctionCall) goja.Value { | ||
pathVal := call.Argument(0) | ||
if goja.IsNull(pathVal) && goja.IsUndefined(pathVal) { | ||
return r.runtime.NewGoError(errors.New("no path given")) | ||
} | ||
|
||
if !strings.Contains(path, ".") { | ||
return _internalRequire(call, fullPath) | ||
} else { | ||
return _externalRequire(call, fullPath) | ||
path := pathVal.String() | ||
if strings.HasPrefix(path, "./") { | ||
return r._externalRequire(call, path) | ||
} | ||
|
||
return r._internalRequire(call, path) | ||
|
||
} | ||
|
||
func _internalRequire(call otto.FunctionCall, path string) otto.Value { | ||
requireError(path, "internal") | ||
return otto.UndefinedValue() | ||
func (r *Require) _externalRequire(call goja.FunctionCall, path string) goja.Value { | ||
r.requireError(path, "external", errors.New("not implemented")) | ||
return goja.Undefined() | ||
} | ||
|
||
func _externalRequire(call otto.FunctionCall, path string) otto.Value { | ||
d, err := ioutil.ReadFile(path) | ||
func (r *Require) _internalRequire(call goja.FunctionCall, path string) goja.Value { | ||
script, err := readBoxedFile(path) | ||
if err != nil || script == nil { | ||
// No external module found, let's search our internal path | ||
r.requireError(path, "internal", err) | ||
return r._internalRequire(call, path) | ||
|
||
} | ||
source := "(function(module, exports) {" + string(*script) + "\n})" | ||
p, err := goja.Compile(path, source, false) | ||
if err != nil { | ||
// No external module found, let's search our internal path | ||
return _internalRequire(call, path) | ||
r.requireError(path, "internal", fmt.Errorf("unable to compile %s", path)) | ||
return nil | ||
} | ||
|
||
_, v, err := otto.Run(d) | ||
out, err := r.runtime.RunProgram(p) | ||
if err != nil { | ||
requireError(path, "external") | ||
return otto.UndefinedValue() | ||
r.requireError(path, "internal", errors.New("unable to run program")) | ||
} | ||
|
||
reqCall, ok := goja.AssertFunction(out) | ||
if ok != true { | ||
r.requireError(path, "internal", errors.New("unable to get transpiled function")) | ||
return nil | ||
} | ||
|
||
return v | ||
exports := r.runtime.NewObject() | ||
_, err = reqCall(out, nil, exports) | ||
|
||
return exports | ||
} | ||
|
||
func (r *Require) requireError(path, requireType string, err error) { | ||
fmt.Printf(" warn/Module '%s' (%s module search) module not loaded: %s\n", path, requireType, err) | ||
} | ||
|
||
func requireError(path, requireType string) { | ||
_, dbf := Dbg.New() | ||
dbf( | ||
"%/warn//Module '%s' (%s module search) not found, module not loaded", | ||
path, | ||
requireType, | ||
) | ||
func readBoxedFile(path string) (*string, error) { | ||
var fullPath string | ||
if strings.HasPrefix(path, "!") { | ||
fullPath = fmt.Sprintf("js/%s", path[1:]) | ||
} | ||
|
||
if strings.HasPrefix(path, "@") { | ||
fullPath = fmt.Sprintf("js/node_modules/%s", path) | ||
} | ||
|
||
d, err := langsupport.ReadFile(fullPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
script := string(d) | ||
return &script, nil | ||
} |