From af614dd83bf0e2f882d47131d7af1d27b06af455 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Fri, 2 Jul 2021 15:55:08 +0300 Subject: [PATCH 1/4] Add source map support This includes both support for any sourcemap found through the source file and generating sourcemaps when going through babel. There are additional fixes for trying to fix off by 1 line errors in imports, but those may need further work. On not being able to load a sourcemap a warning is emitted but the file is still parsed and compiled just without sourcemaps fixes #1789, #1804 --- core/engine_test.go | 6 +- js/bundle.go | 31 +++++- js/compiler/compiler.go | 175 ++++++++++++++++++++++++------- js/compiler/compiler_test.go | 197 +++++++++++++++++++++-------------- js/initcontext.go | 3 +- js/initcontext_test.go | 100 ++++++++++++++++++ js/tc39/tc39_test.go | 18 ++-- 7 files changed, 397 insertions(+), 133 deletions(-) diff --git a/core/engine_test.go b/core/engine_test.go index 2a2d12be66a..6ef099278b3 100644 --- a/core/engine_test.go +++ b/core/engine_test.go @@ -783,8 +783,8 @@ func TestSetupException(t *testing.T) { require.Error(t, err) var exception errext.Exception require.ErrorAs(t, err, &exception) - require.Equal(t, "Error: baz\n\tat baz (file:///bar.js:7:8(3))\n"+ - "\tat file:///bar.js:4:5(3)\n\tat setup (file:///script.js:7:204(4))\n\tat native\n", + require.Equal(t, "Error: baz\n\tat baz (file:///bar.js:6:16(3))\n"+ + "\tat file:///bar.js:3:8(3)\n\tat setup (file:///script.js:4:2(4))\n\tat native\n", err.Error()) } } @@ -835,7 +835,7 @@ func TestVuInitException(t *testing.T) { var exception errext.Exception require.ErrorAs(t, err, &exception) - assert.Equal(t, "Error: oops in 2\n\tat file:///script.js:10:8(31)\n", err.Error()) + assert.Equal(t, "Error: oops in 2\n\tat file:///script.js:10:9(31)\n", err.Error()) var errWithHint errext.HasHint require.ErrorAs(t, err, &errWithHint) diff --git a/js/bundle.go b/js/bundle.go index 39bf259f6ff..367c57051f8 100644 --- a/js/bundle.go +++ b/js/bundle.go @@ -30,7 +30,6 @@ import ( "runtime" "github.com/dop251/goja" - "github.com/dop251/goja/parser" "github.com/sirupsen/logrus" "github.com/spf13/afero" "gopkg.in/guregu/null.v3" @@ -84,7 +83,12 @@ func NewBundle( // Compile sources, both ES5 and ES6 are supported. code := string(src.Data) c := compiler.New(logger) - pgm, _, err := c.Compile(code, src.URL.String(), "", "", true, compatMode) + c.Options = compiler.Options{ + CompatibilityMode: compatMode, + Strict: true, + SourceMapLoader: generateSourceMapLoader(logger, filesystems), + } + pgm, _, err := c.Compile(code, src.URL.String(), true) if err != nil { return nil, err } @@ -132,7 +136,12 @@ func NewBundleFromArchive( } c := compiler.New(logger) - pgm, _, err := c.Compile(string(arc.Data), arc.FilenameURL.String(), "", "", true, compatMode) + c.Options = compiler.Options{ + Strict: true, + CompatibilityMode: compatMode, + SourceMapLoader: generateSourceMapLoader(logger, arc.Filesystems), + } + pgm, _, err := c.Compile(string(arc.Data), arc.FilenameURL.String(), true) if err != nil { return nil, err } @@ -291,7 +300,6 @@ func (b *Bundle) Instantiate(logger logrus.FieldLogger, vuID uint64) (bi *Bundle // Instantiates the bundle into an existing runtime. Not public because it also messes with a bunch // of other things, will potentially thrash data and makes a mess in it if the operation fails. func (b *Bundle) instantiate(logger logrus.FieldLogger, rt *goja.Runtime, init *InitContext, vuID uint64) error { - rt.SetParserOptions(parser.WithDisableSourceMaps) rt.SetFieldNameMapper(common.FieldNameMapper{}) rt.SetRandSource(common.NewRandSource()) @@ -338,3 +346,18 @@ func (b *Bundle) instantiate(logger logrus.FieldLogger, rt *goja.Runtime, init * return nil } + +func generateSourceMapLoader(logger logrus.FieldLogger, filesystems map[string]afero.Fs, +) func(path string) ([]byte, error) { + return func(path string) ([]byte, error) { + u, err := url.Parse(path) + if err != nil { + return nil, err + } + data, err := loader.Load(logger, filesystems, u, path) + if err != nil { + return nil, err + } + return data.Data, nil + } +} diff --git a/js/compiler/compiler.go b/js/compiler/compiler.go index 8a108a32378..b60f4207c28 100644 --- a/js/compiler/compiler.go +++ b/js/compiler/compiler.go @@ -22,6 +22,8 @@ package compiler import ( _ "embed" // we need this for embedding Babel + "encoding/json" + "errors" "sync" "time" @@ -86,10 +88,13 @@ var ( globalBabel *babel // nolint:gochecknoglobals ) +const sourceMapURLFromBabel = "k6://internal-should-not-leak/file.map" + // A Compiler compiles JavaScript source code (ES5.1 or ES6) into a goja.Program type Compiler struct { - logger logrus.FieldLogger - babel *babel + logger logrus.FieldLogger + babel *babel + Options Options } // New returns a new Compiler @@ -108,7 +113,7 @@ func (c *Compiler) initializeBabel() error { } // Transform the given code into ES5 -func (c *Compiler) Transform(src, filename string) (code string, srcmap []byte, err error) { +func (c *Compiler) Transform(src, filename string, inputSrcMap []byte) (code string, srcMap []byte, err error) { if c.babel == nil { onceBabel.Do(func() { globalBabel, err = newBabel() @@ -119,48 +124,88 @@ func (c *Compiler) Transform(src, filename string) (code string, srcmap []byte, return } - code, srcmap, err = c.babel.Transform(c.logger, src, filename) + code, srcMap, err = c.babel.transformImpl(c.logger, src, filename, c.Options.SourceMapLoader != nil, inputSrcMap) return } +// Options are options to the compiler +type Options struct { + CompatibilityMode lib.CompatibilityMode + SourceMapLoader func(string) ([]byte, error) + Strict bool +} + +// compilationState is helper struct to keep the state of a compilation +type compilationState struct { + // set when we couldn't load external source map so we can try parsing without loading it + couldntLoadSourceMap bool + // srcMap is the current full sourceMap that has been generated read so far + srcMap []byte + main bool + + compiler *Compiler +} + // Compile the program in the given CompatibilityMode, wrapping it between pre and post code -func (c *Compiler) Compile(src, filename, pre, post string, - strict bool, compatMode lib.CompatibilityMode) (*goja.Program, string, error) { - code := pre + src + post - ast, err := parser.ParseFile(nil, filename, code, 0, parser.WithDisableSourceMaps) - if err != nil { - if compatMode == lib.CompatibilityModeExtended { - code, _, err = c.Transform(src, filename) - if err != nil { - return nil, code, err - } - // the compatibility mode "decreases" here as we shouldn't transform twice - return c.Compile(code, filename, pre, post, strict, lib.CompatibilityModeBase) +func (c *Compiler) Compile(src, filename string, main bool) (*goja.Program, string, error) { + return c.compileImpl(src, filename, main, c.Options.CompatibilityMode, nil) +} + +// sourceMapLoader is to be used with goja's WithSourceMapLoader +// it not only gets the file from disk in the simple case, but also returns it if the map was generated from babel +// additioanlly it fixes off by one error in commonjs dependencies due to having to wrap them in a function. +func (c *compilationState) sourceMapLoader(path string) ([]byte, error) { + if path == sourceMapURLFromBabel { + if !c.main { + return c.increaseMappingsByOne(c.srcMap) } - return nil, code, err + return c.srcMap, nil + } + var err error + c.srcMap, err = c.compiler.Options.SourceMapLoader(path) + if err != nil { + c.couldntLoadSourceMap = true + return nil, err + } + if !c.main { + return c.increaseMappingsByOne(c.srcMap) + } + return c.srcMap, err +} + +func (c *Compiler) compileImpl( + src, filename string, main bool, compatibilityMode lib.CompatibilityMode, srcMap []byte, +) (*goja.Program, string, error) { + code := src + state := compilationState{srcMap: srcMap, compiler: c, main: main} + if !main { // the lines in the sourcemap (if available) will be fixed by increaseMappingsByOne + code = "(function(module, exports){\n" + code + "\n})\n" + } + opts := parser.WithDisableSourceMaps + if c.Options.SourceMapLoader != nil { + opts = parser.WithSourceMapLoader(state.sourceMapLoader) + } + ast, err := parser.ParseFile(nil, filename, code, 0, opts) + + if state.couldntLoadSourceMap { + state.couldntLoadSourceMap = false // reset + // we probably don't want to abort scripts which have source maps but they can't be found, + // this also will be a breaking change, so if we couldn't we retry with it disabled + c.logger.WithError(err).Warnf("Couldn't load source map for %s", filename) + ast, err = parser.ParseFile(nil, filename, code, 0, parser.WithDisableSourceMaps) } - pgm, err := goja.CompileAST(ast, strict) - // Parsing only checks the syntax, not whether what the syntax expresses - // is actually supported (sometimes). - // - // For example, destructuring looks a lot like an object with shorthand - // properties, but this is only noticeable once the code is compiled, not - // while parsing. Even now code such as `let [x] = [2]` doesn't return an - // error on the parsing stage but instead in the compilation in base mode. - // - // So, because of this, if there is an error during compilation, it still might - // be worth it to transform the code and try again. if err != nil { - if compatMode == lib.CompatibilityModeExtended { - code, _, err = c.Transform(src, filename) + if compatibilityMode == lib.CompatibilityModeExtended { + code, state.srcMap, err = c.Transform(src, filename, state.srcMap) if err != nil { return nil, code, err } // the compatibility mode "decreases" here as we shouldn't transform twice - return c.Compile(code, filename, pre, post, strict, lib.CompatibilityModeBase) + return c.compileImpl(code, filename, main, lib.CompatibilityModeBase, state.srcMap) } return nil, code, err } + pgm, err := goja.CompileAST(ast, c.Options.Strict) return pgm, code, err } @@ -194,16 +239,59 @@ func newBabel() (*babel, error) { return result, err } -// Transform the given code into ES5, while synchronizing to ensure only a single +// increaseMappingsByOne increases the lines in the sourcemap by line so that it fixes the case where we need to wrap a +// required file in a function to support/emulate commonjs +func (c *compilationState) increaseMappingsByOne(sourceMap []byte) ([]byte, error) { + var err error + m := make(map[string]interface{}) + if err = json.Unmarshal(sourceMap, &m); err != nil { + return nil, err + } + mappings, ok := m["mappings"] + if !ok { + // no mappings, no idea what this will do, but just return it as technically we can have sourcemap with sections + // TODO implement incrementing of `offset` in the sections? to support that case as well + // see https://sourcemaps.info/spec.html#h.n05z8dfyl3yh + // + // TODO (kind of alternatively) drop the newline in the "commonjs" wrapping and have only the first line wrong + // and drop this whole function + return sourceMap, nil + } + if str, ok := mappings.(string); ok { + // ';' is the separator between lines so just adding 1 will make all mappings be for the line after which they were + // originally + m["mappings"] = ";" + str + } else { + // we have mappings but it's not a string - this is some kind of error + // we still won't abort the test but just not load the sourcemap + c.couldntLoadSourceMap = true + return nil, errors.New(`missing "mappings" in sourcemap`) + } + + return json.Marshal(m) +} + +// transformImpl the given code into ES5, while synchronizing to ensure only a single // bundle instance / Goja VM is in use at a time. -// TODO the []byte is there to be used as the returned sourcemap and will be done in PR #2082 -func (b *babel) Transform(logger logrus.FieldLogger, src, filename string) (string, []byte, error) { +func (b *babel) transformImpl( + logger logrus.FieldLogger, src, filename string, sourceMapsEnabled bool, inputSrcMap []byte, +) (string, []byte, error) { b.m.Lock() defer b.m.Unlock() opts := make(map[string]interface{}) for k, v := range DefaultOpts { opts[k] = v } + if sourceMapsEnabled { + opts["sourceMaps"] = true + if inputSrcMap != nil { + srcMap := new(map[string]interface{}) + if err := json.Unmarshal(inputSrcMap, &srcMap); err != nil { + return "", nil, err + } + opts["inputSourceMap"] = srcMap + } + } opts["filename"] = filename startTime := time.Now() @@ -218,7 +306,24 @@ func (b *babel) Transform(logger logrus.FieldLogger, src, filename string) (stri if err = b.vm.ExportTo(vO.Get("code"), &code); err != nil { return code, nil, err } - return code, nil, err + if !sourceMapsEnabled { + return code, nil, nil + } + + // this is to make goja try to load a sourcemap. + // it is a special url as it should never leak outside of this code + // additionally the alternative support from babel is to embed *the whole* sourcemap at the end + code += "\n//# sourceMappingURL=" + sourceMapURLFromBabel + stringify, err := b.vm.RunString("(function(m) { return JSON.stringify(m)})") + if err != nil { + return code, nil, err + } + c, _ := goja.AssertFunction(stringify) + mapAsJSON, err := c(goja.Undefined(), vO.Get("map")) + if err != nil { + return code, nil, err + } + return code, []byte(mapAsJSON.String()), nil } // Pool is a pool of compilers so it can be used easier in parallel tests as they have their own babel. diff --git a/js/compiler/compiler_test.go b/js/compiler/compiler_test.go index 8ba055b8ca8..a719c1b5587 100644 --- a/js/compiler/compiler_test.go +++ b/js/compiler/compiler_test.go @@ -20,12 +20,13 @@ package compiler import ( + "errors" + "io/ioutil" "strings" "testing" - "time" "github.com/dop251/goja" - "github.com/dop251/goja/parser" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -34,31 +35,31 @@ import ( ) func TestTransform(t *testing.T) { - c := New(testutils.NewLogger(t)) + t.Parallel() t.Run("blank", func(t *testing.T) { - src, _, err := c.Transform("", "test.js") + t.Parallel() + c := New(testutils.NewLogger(t)) + src, _, err := c.Transform("", "test.js", nil) assert.NoError(t, err) assert.Equal(t, `"use strict";`, src) - // assert.Equal(t, 3, srcmap.Version) - // assert.Equal(t, "test.js", srcmap.File) - // assert.Equal(t, "", srcmap.Mappings) }) t.Run("double-arrow", func(t *testing.T) { - src, _, err := c.Transform("()=> true", "test.js") + t.Parallel() + c := New(testutils.NewLogger(t)) + src, _, err := c.Transform("()=> true", "test.js", nil) assert.NoError(t, err) assert.Equal(t, `"use strict";() => true;`, src) - // assert.Equal(t, 3, srcmap.Version) - // assert.Equal(t, "test.js", srcmap.File) - // assert.Equal(t, "aAAA,qBAAK,IAAL", srcmap.Mappings) }) t.Run("longer", func(t *testing.T) { + t.Parallel() + c := New(testutils.NewLogger(t)) src, _, err := c.Transform(strings.Join([]string{ `function add(a, b) {`, ` return a + b;`, `};`, ``, `let res = add(1, 2);`, - }, "\n"), "test.js") + }, "\n"), "test.js", nil) assert.NoError(t, err) assert.Equal(t, strings.Join([]string{ `"use strict";function add(a, b) {`, @@ -67,104 +68,138 @@ func TestTransform(t *testing.T) { ``, `let res = add(1, 2);`, }, "\n"), src) - // assert.Equal(t, 3, srcmap.Version) - // assert.Equal(t, "test.js", srcmap.File) - // assert.Equal(t, "aAAA,SAASA,GAAT,CAAaC,CAAb,EAAgBC,CAAhB,EAAmB;AACf,WAAOD,IAAIC,CAAX;AACH;;AAED,IAAIC,MAAMH,IAAI,CAAJ,EAAO,CAAP,CAAV", srcmap.Mappings) + }) + + t.Run("double-arrow with sourceMap", func(t *testing.T) { + t.Parallel() + c := New(testutils.NewLogger(t)) + c.Options.SourceMapLoader = func(string) ([]byte, error) { return nil, errors.New("shouldn't be called") } + src, _, err := c.Transform("()=> true", "test.js", nil) + assert.NoError(t, err) + assert.Equal(t, `"use strict";() => true; +//# sourceMappingURL=k6://internal-should-not-leak/file.map`, src) }) } func TestCompile(t *testing.T) { - c := New(testutils.NewLogger(t)) + t.Parallel() t.Run("ES5", func(t *testing.T) { + t.Parallel() + c := New(testutils.NewLogger(t)) src := `1+(function() { return 2; })()` - pgm, code, err := c.Compile(src, "script.js", "", "", true, lib.CompatibilityModeBase) + pgm, code, err := c.Compile(src, "script.js", true) require.NoError(t, err) assert.Equal(t, src, code) v, err := goja.New().RunProgram(pgm) if assert.NoError(t, err) { assert.Equal(t, int64(3), v.Export()) } + }) - t.Run("Wrap", func(t *testing.T) { - pgm, code, err := c.Compile(src, "script.js", - "(function(){return ", "})", true, lib.CompatibilityModeBase) - require.NoError(t, err) - assert.Equal(t, `(function(){return 1+(function() { return 2; })()})`, code) - v, err := goja.New().RunProgram(pgm) - if assert.NoError(t, err) { - fn, ok := goja.AssertFunction(v) - if assert.True(t, ok, "not a function") { - v, err := fn(goja.Undefined()) - if assert.NoError(t, err) { - assert.Equal(t, int64(3), v.Export()) - } + t.Run("ES5 Wrap", func(t *testing.T) { + t.Parallel() + c := New(testutils.NewLogger(t)) + src := `exports.d=1+(function() { return 2; })()` + pgm, code, err := c.Compile(src, "script.js", false) + require.NoError(t, err) + assert.Equal(t, "(function(module, exports){\nexports.d=1+(function() { return 2; })()\n})\n", code) + rt := goja.New() + v, err := rt.RunProgram(pgm) + if assert.NoError(t, err) { + fn, ok := goja.AssertFunction(v) + if assert.True(t, ok, "not a function") { + exp := make(map[string]goja.Value) + _, err := fn(goja.Undefined(), goja.Undefined(), rt.ToValue(exp)) + if assert.NoError(t, err) { + assert.Equal(t, int64(3), exp["d"].Export()) } } - }) + } + }) - t.Run("Invalid", func(t *testing.T) { - src := `1+(function() { return 2; )()` - _, _, err := c.Compile(src, "script.js", "", "", true, lib.CompatibilityModeExtended) - assert.IsType(t, &goja.Exception{}, err) - assert.Contains(t, err.Error(), `SyntaxError: script.js: Unexpected token (1:26) + t.Run("ES5 Invalid", func(t *testing.T) { + t.Parallel() + c := New(testutils.NewLogger(t)) + src := `1+(function() { return 2; )()` + c.Options.CompatibilityMode = lib.CompatibilityModeExtended + _, _, err := c.Compile(src, "script.js", false) + assert.IsType(t, &goja.Exception{}, err) + assert.Contains(t, err.Error(), `SyntaxError: script.js: Unexpected token (1:26) > 1 | 1+(function() { return 2; )()`) - }) }) t.Run("ES6", func(t *testing.T) { - pgm, code, err := c.Compile(`3**2`, "script.js", "", "", true, lib.CompatibilityModeExtended) + t.Parallel() + c := New(testutils.NewLogger(t)) + c.Options.CompatibilityMode = lib.CompatibilityModeExtended + pgm, code, err := c.Compile(`3**2`, "script.js", true) require.NoError(t, err) assert.Equal(t, `"use strict";Math.pow(3, 2);`, code) v, err := goja.New().RunProgram(pgm) if assert.NoError(t, err) { assert.Equal(t, int64(9), v.Export()) } + }) - t.Run("Wrap", func(t *testing.T) { - pgm, code, err := c.Compile(`fn(3**2)`, "script.js", "(function(fn){", "})", true, lib.CompatibilityModeExtended) - require.NoError(t, err) - assert.Equal(t, `(function(fn){"use strict";fn(Math.pow(3, 2));})`, code) - rt := goja.New() - v, err := rt.RunProgram(pgm) - if assert.NoError(t, err) { - fn, ok := goja.AssertFunction(v) - if assert.True(t, ok, "not a function") { - var out interface{} - _, err := fn(goja.Undefined(), rt.ToValue(func(v goja.Value) { - out = v.Export() - })) - assert.NoError(t, err) - assert.Equal(t, int64(9), out) - } + t.Run("Wrap", func(t *testing.T) { + t.Parallel() + c := New(testutils.NewLogger(t)) + c.Options.CompatibilityMode = lib.CompatibilityModeExtended + pgm, code, err := c.Compile(`exports.fn(3**2)`, "script.js", false) + require.NoError(t, err) + assert.Equal(t, "(function(module, exports){\n\"use strict\";exports.fn(Math.pow(3, 2));\n})\n", code) + rt := goja.New() + v, err := rt.RunProgram(pgm) + if assert.NoError(t, err) { + fn, ok := goja.AssertFunction(v) + if assert.True(t, ok, "not a function") { + exp := make(map[string]goja.Value) + var out interface{} + exp["fn"] = rt.ToValue(func(v goja.Value) { + out = v.Export() + }) + _, err := fn(goja.Undefined(), goja.Undefined(), rt.ToValue(exp)) + assert.NoError(t, err) + assert.Equal(t, int64(9), out) } - }) + } + }) - t.Run("Invalid", func(t *testing.T) { - _, _, err := c.Compile(`1+(=>2)()`, "script.js", "", "", true, lib.CompatibilityModeExtended) - assert.IsType(t, &goja.Exception{}, err) - assert.Contains(t, err.Error(), `SyntaxError: script.js: Unexpected token (1:3) + t.Run("Invalid", func(t *testing.T) { + t.Parallel() + c := New(testutils.NewLogger(t)) + c.Options.CompatibilityMode = lib.CompatibilityModeExtended + _, _, err := c.Compile(`1+(=>2)()`, "script.js", true) + assert.IsType(t, &goja.Exception{}, err) + assert.Contains(t, err.Error(), `SyntaxError: script.js: Unexpected token (1:3) > 1 | 1+(=>2)()`) - }) + }) +} - t.Run("Invalid for goja but not babel", func(t *testing.T) { - t.Skip("Find something else that breaks this as this was fixed in goja :(") - ch := make(chan struct{}) - go func() { - defer close(ch) - // This is a string with U+2029 Paragraph separator in it - // the important part is that goja won't parse it but babel will transform it but still - // goja won't be able to parse the result it is actually "\" - _, _, err := c.Compile(string([]byte{0x22, 0x5c, 0xe2, 0x80, 0xa9, 0x22}), "script.js", "", "", true, lib.CompatibilityModeExtended) - assert.IsType(t, parser.ErrorList{}, err) - assert.Contains(t, err.Error(), ` Unexpected token ILLEGAL`) - }() +func TestCorruptSourceMap(t *testing.T) { + t.Parallel() + corruptSourceMap := []byte(`{"mappings": 12}`) // 12 is a number not a string - select { - case <-ch: - // everything is fine - case <-time.After(time.Second): - // it took too long - t.Fatal("takes too long") - } - }) - }) + logger := logrus.New() + logger.SetLevel(logrus.DebugLevel) + logger.Out = ioutil.Discard + hook := testutils.SimpleLogrusHook{ + HookedLevels: []logrus.Level{logrus.InfoLevel, logrus.WarnLevel}, + } + logger.AddHook(&hook) + + compiler := New(logger) + compiler.Options = Options{ + Strict: true, + SourceMapLoader: func(string) ([]byte, error) { + return corruptSourceMap, nil + }, + } + _, _, err := compiler.Compile("var s = 5;\n//# sourceMappingURL=somefile", "somefile", false) + require.NoError(t, err) + entries := hook.Drain() + require.Len(t, entries, 1) + msg, err := entries[0].String() // we need this in order to get the field error + require.NoError(t, err) + + require.Contains(t, msg, `Could not load source map: missing \"mappings\" in sourcemap`) } diff --git a/js/initcontext.go b/js/initcontext.go index 0847e3d1fa8..5a93de9d8e4 100644 --- a/js/initcontext.go +++ b/js/initcontext.go @@ -270,8 +270,7 @@ func (i *InitContext) requireFile(name string) (goja.Value, error) { } func (i *InitContext) compileImport(src, filename string) (*goja.Program, error) { - pgm, _, err := i.compiler.Compile(src, filename, - "(function(module, exports){\n", "\n})\n", true, i.compatibilityMode) + pgm, _, err := i.compiler.Compile(src, filename, false) return pgm, err } diff --git a/js/initcontext_test.go b/js/initcontext_test.go index decba1f54e2..c2fc1df3df2 100644 --- a/js/initcontext_test.go +++ b/js/initcontext_test.go @@ -585,3 +585,103 @@ func TestInitContextVU(t *testing.T) { require.NoError(t, err) assert.Equal(t, int64(5), v.Export()) } + +func TestSourceMaps(t *testing.T) { + t.Parallel() + logger := testutils.NewLogger(t) + fs := afero.NewMemMapFs() + assert.NoError(t, afero.WriteFile(fs, "/module1.js", []byte(` +export function f2(){ + throw "exception in line 2" + console.log("in f2") +} +export function f1(){ + throw "exception in line 6" + console.log("in f1") +} +`[1:]), 0o644)) + data := ` +import * as module1 from "./module1.js" + +export default function(){ +// throw "exception in line 4" + module1.f2() + console.log("in default") +} +`[1:] + b, err := getSimpleBundle(t, "/script.js", data, fs) + require.NoError(t, err) + + bi, err := b.Instantiate(logger, 0) + require.NoError(t, err) + _, err = bi.exports[consts.DefaultFn](goja.Undefined()) + require.Error(t, err) + exception := new(goja.Exception) + require.ErrorAs(t, err, &exception) + require.Equal(t, exception.String(), "exception in line 2\n\tat f2 (file:///module1.js:2:4(2))\n\tat file:///script.js:5:4(4)\n\tat native\n") +} + +func TestSourceMapsExternal(t *testing.T) { + t.Parallel() + logger := testutils.NewLogger(t) + fs := afero.NewMemMapFs() + // This example is created through the template-typescript + assert.NoError(t, afero.WriteFile(fs, "/test1.js", []byte(` +(()=>{"use strict";var e={};(()=>{var o=e;Object.defineProperty(o,"__esModule",{value:!0}),o.default=function(){!function(e){throw"cool is cool"}()}})();var o=exports;for(var r in e)o[r]=e[r];e.__esModule&&Object.defineProperty(o,"__esModule",{value:!0})})(); +//# sourceMappingURL=test1.js.map +`[1:]), 0o644)) + assert.NoError(t, afero.WriteFile(fs, "/test1.js.map", []byte(` +{"version":3,"sources":["webpack:///./test1.ts"],"names":["s","coolThrow"],"mappings":"2FAGA,sBAHA,SAAmBA,GACf,KAAM,eAGNC,K","file":"test1.js","sourcesContent":["function coolThrow(s: string) {\n throw \"cool \"+ s\n}\nexport default () => {\n coolThrow(\"is cool\")\n};\n"],"sourceRoot":""} +`[1:]), 0o644)) + data := ` +import l from "./test1.js" + +export default function () { + l() +}; +`[1:] + b, err := getSimpleBundle(t, "/script.js", data, fs) + require.NoError(t, err) + + bi, err := b.Instantiate(logger, 0) + require.NoError(t, err) + _, err = bi.exports[consts.DefaultFn](goja.Undefined()) + require.Error(t, err) + exception := new(goja.Exception) + require.ErrorAs(t, err, &exception) + require.Equal(t, "cool is cool\n\tat webpack:///./test1.ts:2:4(2)\n\tat webpack:///./test1.ts:5:4(3)\n\tat file:///script.js:4:2(4)\n\tat native\n", exception.String()) +} + +func TestSourceMapsExternalExtented(t *testing.T) { + t.Parallel() + logger := testutils.NewLogger(t) + fs := afero.NewMemMapFs() + // This example is created through the template-typescript + // but was exported to use import/export syntax so it has to go through babel + assert.NoError(t, afero.WriteFile(fs, "/test1.js", []byte(` +var o={d:(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o:(o,e)=>Object.prototype.hasOwnProperty.call(o,e)},e={};o.d(e,{Z:()=>r});const r=()=>{!function(o){throw"cool is cool"}()};var t=e.Z;export{t as default}; +//# sourceMappingURL=test1.js.map +`[1:]), 0o644)) + assert.NoError(t, afero.WriteFile(fs, "/test1.js.map", []byte(` +{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///./test1.ts"],"names":["__webpack_require__","exports","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","s","coolThrow"],"mappings":"AACA,IAAIA,EAAsB,CCA1B,EAAwB,CAACC,EAASC,KACjC,IAAI,IAAIC,KAAOD,EACXF,EAAoBI,EAAEF,EAAYC,KAASH,EAAoBI,EAAEH,EAASE,IAC5EE,OAAOC,eAAeL,EAASE,EAAK,CAAEI,YAAY,EAAMC,IAAKN,EAAWC,MCJ3E,EAAwB,CAACM,EAAKC,IAAUL,OAAOM,UAAUC,eAAeC,KAAKJ,EAAKC,I,sBCGlF,cAHA,SAAmBI,GACf,KAAM,eAGNC,I","file":"test1.js","sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","function coolThrow(s: string) {\n throw \"cool \"+ s\n}\nexport default () => {\n coolThrow(\"is cool\")\n};\n"],"sourceRoot":""} +`[1:]), 0o644)) + data := ` +import l from "./test1.js" + +export default function () { + l() +}; +`[1:] + b, err := getSimpleBundle(t, "/script.js", data, fs) + require.NoError(t, err) + + bi, err := b.Instantiate(logger, 0) + require.NoError(t, err) + _, err = bi.exports[consts.DefaultFn](goja.Undefined()) + require.Error(t, err) + exception := new(goja.Exception) + require.ErrorAs(t, err, &exception) + // TODO figure out why those are not the same as the one in the previous test TestSourceMapsExternal + // likely settings in the transpilers + require.Equal(t, "cool is cool\n\tat webpack:///./test1.ts:2:4(2)\n\tat r (webpack:///./test1.ts:5:4(3))\n\tat file:///script.js:4:2(4)\n\tat native\n", exception.String()) +} diff --git a/js/tc39/tc39_test.go b/js/tc39/tc39_test.go index c83c0128f57..bace5273af1 100644 --- a/js/tc39/tc39_test.go +++ b/js/tc39/tc39_test.go @@ -475,9 +475,10 @@ func (ctx *tc39TestCtx) compile(base, name string) (*goja.Program, error) { } str := string(b) - compiler := ctx.compilerPool.Get() - defer ctx.compilerPool.Put(compiler) - prg, _, err = compiler.Compile(str, name, "", "", false, lib.CompatibilityModeExtended) + comp := ctx.compilerPool.Get() + defer ctx.compilerPool.Put(comp) + comp.Options = compiler.Options{Strict: false, CompatibilityMode: lib.CompatibilityModeExtended} + prg, _, err = comp.Compile(str, name, true) if err != nil { return nil, err } @@ -516,13 +517,14 @@ func (ctx *tc39TestCtx) runTC39Script(name, src string, includes []string, vm *g } var p *goja.Program - compiler := ctx.compilerPool.Get() - defer ctx.compilerPool.Put(compiler) - p, _, origErr = compiler.Compile(src, name, "", "", false, lib.CompatibilityModeBase) + comp := ctx.compilerPool.Get() + defer ctx.compilerPool.Put(comp) + comp.Options = compiler.Options{Strict: false, CompatibilityMode: lib.CompatibilityModeBase} + p, _, origErr = comp.Compile(src, name, true) if origErr != nil { - src, _, err = compiler.Transform(src, name) + src, _, err = comp.Transform(src, name, nil) if err == nil { - p, _, err = compiler.Compile(src, name, "", "", false, lib.CompatibilityModeBase) + p, _, err = comp.Compile(src, name, true) } } else { err = origErr From e66f2dc356919040931456dd3a78559b5fabafe8 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Fri, 19 Nov 2021 15:37:46 +0200 Subject: [PATCH 2/4] Update sourcemap dependancy to get fixes --- go.mod | 2 +- go.sum | 8 ++---- js/initcontext_test.go | 2 +- .../go-sourcemap/sourcemap/README.md | 5 ++-- .../go-sourcemap/sourcemap/consumer.go | 25 +++++++++++-------- .../go-sourcemap/sourcemap/mappings.go | 10 +++++--- vendor/modules.txt | 2 +- 7 files changed, 28 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 4f4b1f0ebd7..ea9eac623dd 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect - github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect + github.com/go-sourcemap/sourcemap v2.1.4-0.20211119122758-180fcef48034+incompatible // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/onsi/ginkgo v1.14.0 // indirect diff --git a/go.sum b/go.sum index bfb1bff28d1..fc42860b134 100644 --- a/go.sum +++ b/go.sum @@ -79,8 +79,9 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -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/go-sourcemap/sourcemap v2.1.4-0.20211119122758-180fcef48034+incompatible h1:bopx7t9jyUNX1ebhr0G4gtQWmUOgwQRI0QsYhdYLgkU= +github.com/go-sourcemap/sourcemap v2.1.4-0.20211119122758-180fcef48034+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -334,7 +335,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211209100829-84cba5454caf h1:Chci/BE/+xVqrcWnObL99NS8gtXyJrhHDlygBQrggHM= golang.org/x/net v0.0.0-20211209100829-84cba5454caf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -370,17 +370,13 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/js/initcontext_test.go b/js/initcontext_test.go index c2fc1df3df2..b0b6054d2ab 100644 --- a/js/initcontext_test.go +++ b/js/initcontext_test.go @@ -137,7 +137,7 @@ func TestInitContextRequire(t *testing.T) { fs := afero.NewMemMapFs() assert.NoError(t, afero.WriteFile(fs, "/file.js", []byte(`throw new Error("aaaa")`), 0o755)) _, err := getSimpleBundle(t, "/script.js", `import "/file.js"; export default function() {}`, fs) - assert.EqualError(t, err, "Error: aaaa\n\tat file:///file.js:2:7(3)\n\tat reflect.methodValueCall (native)\n\tat file:///script.js:1:109(14)\n") + assert.EqualError(t, err, "Error: aaaa\n\tat file:///file.js:2:7(3)\n\tat reflect.methodValueCall (native)\n\tat file:///script.js:1:0(14)\n") }) imports := map[string]struct { diff --git a/vendor/github.com/go-sourcemap/sourcemap/README.md b/vendor/github.com/go-sourcemap/sourcemap/README.md index ba9b3b881ce..16ce7357a53 100644 --- a/vendor/github.com/go-sourcemap/sourcemap/README.md +++ b/vendor/github.com/go-sourcemap/sourcemap/README.md @@ -1,10 +1,9 @@ # Source maps consumer for Golang [![Build Status](https://travis-ci.org/go-sourcemap/sourcemap.svg)](https://travis-ci.org/go-sourcemap/sourcemap) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/go-sourcemap/sourcemap)](https://pkg.go.dev/github.com/go-sourcemap/sourcemap) -API docs: https://godoc.org/github.com/go-sourcemap/sourcemap. -Examples: https://godoc.org/github.com/go-sourcemap/sourcemap#pkg-examples. -Spec: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit. +> :heart: [**Uptrace.dev** - distributed traces, logs, and errors in one place](https://uptrace.dev) ## Installation diff --git a/vendor/github.com/go-sourcemap/sourcemap/consumer.go b/vendor/github.com/go-sourcemap/sourcemap/consumer.go index 3b2f6e324de..935a4a981eb 100644 --- a/vendor/github.com/go-sourcemap/sourcemap/consumer.go +++ b/vendor/github.com/go-sourcemap/sourcemap/consumer.go @@ -192,19 +192,24 @@ func (c *Consumer) source( return int(m.genLine) >= genLine }) - // Mapping not found. + var match *mapping + // Mapping not found if i == len(m.mappings) { - return - } - - match := &m.mappings[i] - - // Fuzzy match. - if int(match.genLine) > genLine || int(match.genColumn) > genColumn { - if i == 0 { + // lets see if the line is correct but the column is bigger + match = &m.mappings[i-1] + if int(match.genLine) != genLine { return } - match = &m.mappings[i-1] + } else { + match = &m.mappings[i] + + // Fuzzy match. + if int(match.genLine) > genLine || int(match.genColumn) > genColumn { + if i == 0 { + return + } + match = &m.mappings[i-1] + } } if match.sourcesInd >= 0 { diff --git a/vendor/github.com/go-sourcemap/sourcemap/mappings.go b/vendor/github.com/go-sourcemap/sourcemap/mappings.go index f200ce3c113..eb4b04b2987 100644 --- a/vendor/github.com/go-sourcemap/sourcemap/mappings.go +++ b/vendor/github.com/go-sourcemap/sourcemap/mappings.go @@ -23,8 +23,9 @@ type mappings struct { rd *strings.Reader dec base64vlq.Decoder - hasName bool - value mapping + hasValue bool + hasName bool + value mapping values []mapping } @@ -91,6 +92,7 @@ func (m *mappings) parse() error { if err != nil { return err } + m.hasValue = true } } } @@ -142,10 +144,10 @@ func parseNamesInd(m *mappings) (fn, error) { } func (m *mappings) pushValue() { - if m.value.sourceLine == 1 && m.value.sourceColumn == 0 { + if !m.hasValue { return } - + m.hasValue = false if m.hasName { m.values = append(m.values, m.value) m.hasName = false diff --git a/vendor/modules.txt b/vendor/modules.txt index de3b85b1a18..758270bf462 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -39,7 +39,7 @@ github.com/fatih/color # github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 ## explicit github.com/gedex/inflector -# github.com/go-sourcemap/sourcemap v2.1.3+incompatible +# github.com/go-sourcemap/sourcemap v2.1.4-0.20211119122758-180fcef48034+incompatible ## explicit github.com/go-sourcemap/sourcemap github.com/go-sourcemap/sourcemap/internal/base64vlq From b51774e68a9b4f61ff79e318f9fa6d04533e0ac8 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Fri, 19 Nov 2021 17:33:15 +0200 Subject: [PATCH 3/4] Disable retainLines on babel when using sourcemaps this hopefully has some better performance but more importantly the generated code is more readable without it, while the lines don't match. --- js/compiler/compiler.go | 4 ++++ js/compiler/compiler_test.go | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/js/compiler/compiler.go b/js/compiler/compiler.go index b60f4207c28..6b416d90f32 100644 --- a/js/compiler/compiler.go +++ b/js/compiler/compiler.go @@ -283,6 +283,10 @@ func (b *babel) transformImpl( opts[k] = v } if sourceMapsEnabled { + // given that the source map should provide accurate lines(and columns), this option isn't needed + // it also happens to make very long and awkward lines, especially around import/exports and definitely a lot + // less readable overall. Hopefully it also has some performance improvement not trying to keep the same lines + opts["retainLines"] = false opts["sourceMaps"] = true if inputSrcMap != nil { srcMap := new(map[string]interface{}) diff --git a/js/compiler/compiler_test.go b/js/compiler/compiler_test.go index a719c1b5587..0c6b4892a39 100644 --- a/js/compiler/compiler_test.go +++ b/js/compiler/compiler_test.go @@ -76,7 +76,9 @@ func TestTransform(t *testing.T) { c.Options.SourceMapLoader = func(string) ([]byte, error) { return nil, errors.New("shouldn't be called") } src, _, err := c.Transform("()=> true", "test.js", nil) assert.NoError(t, err) - assert.Equal(t, `"use strict";() => true; + assert.Equal(t, `"use strict"; + +() => true; //# sourceMappingURL=k6://internal-should-not-leak/file.map`, src) }) } From 9ae6aaae2cb276135c7c6b27139ec120f275573c Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Fri, 17 Dec 2021 18:54:20 +0200 Subject: [PATCH 4/4] Add test with inline source map --- js/initcontext_test.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/js/initcontext_test.go b/js/initcontext_test.go index b0b6054d2ab..fe2e268bd08 100644 --- a/js/initcontext_test.go +++ b/js/initcontext_test.go @@ -685,3 +685,34 @@ export default function () { // likely settings in the transpilers require.Equal(t, "cool is cool\n\tat webpack:///./test1.ts:2:4(2)\n\tat r (webpack:///./test1.ts:5:4(3))\n\tat file:///script.js:4:2(4)\n\tat native\n", exception.String()) } + +func TestSourceMapsExternalExtentedInlined(t *testing.T) { + t.Parallel() + logger := testutils.NewLogger(t) + fs := afero.NewMemMapFs() + // This example is created through the template-typescript + // but was exported to use import/export syntax so it has to go through babel + assert.NoError(t, afero.WriteFile(fs, "/test1.js", []byte(` +var o={d:(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o:(o,e)=>Object.prototype.hasOwnProperty.call(o,e)},e={};o.d(e,{Z:()=>r});const r=()=>{!function(o){throw"cool is cool"}()};var t=e.Z;export{t as default}; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vL3dlYnBhY2svcnVudGltZS9kZWZpbmUgcHJvcGVydHkgZ2V0dGVycyIsIndlYnBhY2s6Ly8vd2VicGFjay9ydW50aW1lL2hhc093blByb3BlcnR5IHNob3J0aGFuZCIsIndlYnBhY2s6Ly8vLi90ZXN0MS50cyJdLCJuYW1lcyI6WyJfX3dlYnBhY2tfcmVxdWlyZV9fIiwiZXhwb3J0cyIsImRlZmluaXRpb24iLCJrZXkiLCJvIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJlbnVtZXJhYmxlIiwiZ2V0Iiwib2JqIiwicHJvcCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsInMiLCJjb29sVGhyb3ciXSwibWFwcGluZ3MiOiJBQUNBLElBQUlBLEVBQXNCLENDQTFCLEVBQXdCLENBQUNDLEVBQVNDLEtBQ2pDLElBQUksSUFBSUMsS0FBT0QsRUFDWEYsRUFBb0JJLEVBQUVGLEVBQVlDLEtBQVNILEVBQW9CSSxFQUFFSCxFQUFTRSxJQUM1RUUsT0FBT0MsZUFBZUwsRUFBU0UsRUFBSyxDQUFFSSxZQUFZLEVBQU1DLElBQUtOLEVBQVdDLE1DSjNFLEVBQXdCLENBQUNNLEVBQUtDLElBQVVMLE9BQU9NLFVBQVVDLGVBQWVDLEtBQUtKLEVBQUtDLEksc0JDR2xGLGNBSEEsU0FBbUJJLEdBQ2YsS0FBTSxlQUdOQyxJIiwiZmlsZSI6InRlc3QxLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gVGhlIHJlcXVpcmUgc2NvcGVcbnZhciBfX3dlYnBhY2tfcmVxdWlyZV9fID0ge307XG5cbiIsIi8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb25zIGZvciBoYXJtb255IGV4cG9ydHNcbl9fd2VicGFja19yZXF1aXJlX18uZCA9IChleHBvcnRzLCBkZWZpbml0aW9uKSA9PiB7XG5cdGZvcih2YXIga2V5IGluIGRlZmluaXRpb24pIHtcblx0XHRpZihfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZGVmaW5pdGlvbiwga2V5KSAmJiAhX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIGtleSkpIHtcblx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBrZXksIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBkZWZpbml0aW9uW2tleV0gfSk7XG5cdFx0fVxuXHR9XG59OyIsIl9fd2VicGFja19yZXF1aXJlX18ubyA9IChvYmosIHByb3ApID0+IChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wKSkiLCJmdW5jdGlvbiBjb29sVGhyb3coczogc3RyaW5nKSB7XG4gICAgdGhyb3cgXCJjb29sIFwiKyBzXG59XG5leHBvcnQgZGVmYXVsdCAoKSA9PiB7XG4gICAgY29vbFRocm93KFwiaXMgY29vbFwiKVxufTtcbiJdLCJzb3VyY2VSb290IjoiIn0= +`[1:]), 0o644)) + data := ` +import l from "./test1.js" + +export default function () { + l() +}; +`[1:] + b, err := getSimpleBundle(t, "/script.js", data, fs) + require.NoError(t, err) + + bi, err := b.Instantiate(logger, 0) + require.NoError(t, err) + _, err = bi.exports[consts.DefaultFn](goja.Undefined()) + require.Error(t, err) + exception := new(goja.Exception) + require.ErrorAs(t, err, &exception) + // TODO figure out why those are not the same as the one in the previous test TestSourceMapsExternal + // likely settings in the transpilers + require.Equal(t, "cool is cool\n\tat webpack:///./test1.ts:2:4(2)\n\tat r (webpack:///./test1.ts:5:4(3))\n\tat file:///script.js:4:2(4)\n\tat native\n", exception.String()) +}