Skip to content

Commit

Permalink
Use SourceLoader to load external source maps. See dop251/goja#235
Browse files Browse the repository at this point in the history
  • Loading branch information
dop251 committed Dec 19, 2020
1 parent 0226646 commit e244704
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 17 deletions.
44 changes: 27 additions & 17 deletions require/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"text/template"

js "github.com/dop251/goja"
"github.com/dop251/goja/parser"
)

type ModuleLoader func(*js.Runtime, *js.Object)
Expand Down Expand Up @@ -61,6 +62,10 @@ func NewRegistryWithLoader(srcLoader SourceLoader) *Registry {

type Option func(*Registry)

// WithLoader sets a function which will be called by the require() function in order to get a source code for a
// module at the given path. The same function will be used to get external source maps.
// Note, this only affects the modules loaded by the require() function. If you need to use it as a source map
// loader for code parsed in a different way (such as runtime.RunString() or eval()), use (*Runtime).SetParserOptions()
func WithLoader(srcLoader SourceLoader) Option {
return func(r *Registry) {
r.srcLoader = srcLoader
Expand Down Expand Up @@ -123,32 +128,37 @@ func (r *Registry) getSource(p string) ([]byte, error) {
return srcLoader(p)
}

func (r *Registry) getCompiledSource(p string) (prg *js.Program, err error) {
func (r *Registry) getCompiledSource(p string) (*js.Program, error) {
r.Lock()
defer r.Unlock()

prg = r.compiled[p]
prg := r.compiled[p]
if prg == nil {
if buf, err1 := r.getSource(p); err1 == nil {
s := string(buf)
buf, err := r.getSource(p)
if err != nil {
return nil, err
}
s := string(buf)

if filepath.Ext(p) == ".json" {
s = "module.exports = JSON.parse('" + template.JSEscapeString(s) + "')"
}
if filepath.Ext(p) == ".json" {
s = "module.exports = JSON.parse('" + template.JSEscapeString(s) + "')"
}

source := "(function(exports, require, module) {" + s + "\n})"
prg, err = js.Compile(p, source, false)
if err == nil {
if r.compiled == nil {
r.compiled = make(map[string]*js.Program)
}
r.compiled[p] = prg
source := "(function(exports, require, module) {" + s + "\n})"
parsed, err := js.Parse(p, source, parser.WithSourceMapLoader(r.srcLoader))
if err != nil {
return nil, err
}
prg, err = js.CompileAST(parsed, false)
if err == nil {
if r.compiled == nil {
r.compiled = make(map[string]*js.Program)
}
} else {
err = err1
r.compiled[p] = prg
}
return prg, err
}
return
return prg, nil
}

func (r *RequireModule) require(call js.FunctionCall) js.Value {
Expand Down
28 changes: 28 additions & 0 deletions require/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,3 +335,31 @@ func TestErrorPropagation(t *testing.T) {
t.Fatal(err)
}
}

func TestSourceMapLoader(t *testing.T) {
vm := js.New()
r := NewRegistry(WithLoader(func(p string) ([]byte, error) {
switch p {
case "dir/m.js":
return []byte(`throw 'test passed';
//# sourceMappingURL=m.js.map`), nil
case "dir/m.js.map":
return []byte(`{"version":3,"file":"m.js","sourceRoot":"","sources":["m.ts"],"names":[],"mappings":";AAAA"}
`), nil
}
return nil, ModuleFileDoesNotExistError
}))

rr := r.Enable(vm)
_, err := rr.Require("./dir/m")
if err == nil {
t.Fatal("Expected an error")
}
if ex, ok := err.(*js.Exception); ok {
if !ex.Value().StrictEquals(vm.ToValue("test passed")) {
t.Fatalf("Unexpected Exception: %v", ex)
}
} else {
t.Fatal(err)
}
}

0 comments on commit e244704

Please sign in to comment.