Skip to content

Commit

Permalink
Fix star import with go modules as well
Browse files Browse the repository at this point in the history
And some other lint issues
  • Loading branch information
mstoykov committed Jul 2, 2024
1 parent 4e6b03a commit cd10cac
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 59 deletions.
34 changes: 34 additions & 0 deletions js/module_loading_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -688,3 +688,37 @@ func TestDefaultNamedExports(t *testing.T) {
_, err := getSimpleRunner(t, "/main.js", `export default function main() {}`)
require.NoError(t, err)
}

func TestStarImport(t *testing.T) {
t.Parallel()
fs := fsext.NewMemMapFs()
err := writeToFs(fs, map[string]any{
"/commonjs_file.js": `exports.something = 5;`,
})
require.NoError(t, err)

r1, err := getSimpleRunner(t, "/script.js", `
import * as cjs from "./commonjs_file.js"; // commonjs
import * as k6 from "k6"; // "new" go module
// TODO: test with basic go module maybe
if (cjs.something != 5) {
throw "cjs.something has wrong value" + cjs.something;
}
if (typeof k6.sleep != "function") {
throw "k6.sleep has wrong type" + typeof k6.sleep;
}
export default () => {}
`, fs)
require.NoError(t, err)

arc := r1.MakeArchive()
registry := metrics.NewRegistry()
builtinMetrics := metrics.RegisterBuiltinMetrics(registry)
_, err = NewFromArchive(&lib.TestPreInitState{
Logger: testutils.NewLogger(t),
BuiltinMetrics: builtinMetrics,
Registry: registry,
}, arc)
require.NoError(t, err)
}
38 changes: 15 additions & 23 deletions js/modules/cjsmodule.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package modules
import (
"errors"
"net/url"
"sync"

"github.com/grafana/sobek"
"go.k6.io/k6/js/compiler"
Expand All @@ -12,24 +11,22 @@ import (
// cjsModule represents a commonJS module
type cjsModule struct {
prg *sobek.Program
main bool
exportedNamesCallbacks []func([]string)
exportedNames []string
o sync.Once
exportedNamesCallbacks []func([]string)
}

var _ sobek.ModuleRecord = &cjsModule{}

func newCjsModule(prg *sobek.Program, main bool) sobek.ModuleRecord {
return &cjsModule{prg: prg, main: main}
func newCjsModule(prg *sobek.Program) sobek.ModuleRecord {
return &cjsModule{prg: prg}
}

func (cm *cjsModule) Link() error { return nil }

func (cm *cjsModule) InitializeEnvironment() error { return nil }

func (cm *cjsModule) Instantiate(rt *sobek.Runtime) (sobek.CyclicModuleInstance, error) {
return &cjsModuleInstance{rt: rt, w: cm}, nil
func (cm *cjsModule) Instantiate(_ *sobek.Runtime) (sobek.CyclicModuleInstance, error) {
return &cjsModuleInstance{w: cm}, nil
}

func (cm *cjsModule) RequestedModules() []string { return nil }
Expand All @@ -55,9 +52,8 @@ func (cm *cjsModule) ResolveExport(exportName string, _ ...sobek.ResolveSetEleme
}

type cjsModuleInstance struct {
exports *sobek.Object
rt *sobek.Runtime
w *cjsModule
exports *sobek.Object
isEsModuleMarked bool
}

Expand All @@ -77,7 +73,7 @@ func (cmi *cjsModuleInstance) ExecuteModule(rt *sobek.Runtime, _, _ func(any)) (
_ = module.Set("exports", cmi.exports)
call, ok := sobek.AssertFunction(v)
if !ok {
panic("Somehow a commonjs module is not wrapped in a function - this is a k6 bug")
panic("Somehow a CommonJS module is not wrapped in a function - this is a k6 bug, please report it")
}
if _, err = call(cmi.exports, module, cmi.exports); err != nil {
return nil, err
Expand All @@ -89,28 +85,24 @@ func (cmi *cjsModuleInstance) ExecuteModule(rt *sobek.Runtime, _, _ func(any)) (
}
cmi.exports = exportsV.ToObject(rt)

cmi.w.o.Do(func() {
cmi.w.exportedNames = cmi.exports.Keys()
if cmi.w.exportedNames == nil {
cmi.w.exportedNames = make([]string, 0)
}
for _, callback := range cmi.w.exportedNamesCallbacks {
callback(cmi.w.exportedNames)
}
})
cmi.w.exportedNames = cmi.exports.Keys()
if cmi.w.exportedNames == nil {
cmi.w.exportedNames = make([]string, 0)
}
for _, callback := range cmi.w.exportedNamesCallbacks {
callback(cmi.w.exportedNames)
}
__esModule := cmi.exports.Get("__esModule") //nolint:revive,stylecheck
cmi.isEsModuleMarked = __esModule != nil && __esModule.ToBoolean()
return cmi, nil
}

func (cmi *cjsModuleInstance) GetBindingValue(name string) sobek.Value {
if name == "default" {
// if wmi.w.main || wmi.isEsModuleMarked { // hack for just the main file as it worked like that before :facepalm:
d := cmi.exports.Get("default")
if d != nil {
return d
}
//}
return cmi.exports
}

Expand All @@ -127,5 +119,5 @@ func cjsModuleFromString(fileURL *url.URL, data []byte, c *compiler.Compiler) (s
if err != nil {
return nil, err
}
return newCjsModule(pgm, false), nil
return newCjsModule(pgm), nil
}
33 changes: 18 additions & 15 deletions js/modules/gomodule.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package modules

import (
"sync"

"github.com/grafana/sobek"
)

// This sobek.ModuleRecord wrapper for go/js module which conforms to modules.Module interface
type goModule struct {
m Module
once sync.Once
exportedNames []string
m Module
exportedNames []string
exportedNamesCallbacks []func([]string)
}

func (gm *goModule) Link() error {
Expand All @@ -26,15 +24,17 @@ func (gm *goModule) InitializeEnvironment() error {
}

func (gm *goModule) Instantiate(rt *sobek.Runtime) (sobek.CyclicModuleInstance, error) {
// TODO(@mstoykov): try to work around this in some way maybe hostDefined on Module
vu := rt.GlobalObject().Get("vubox").Export().(vubox).vu //nolint:forcetypeassert
mi := gm.m.NewModuleInstance(vu)
gm.once.Do(func() {
named := mi.Exports().Named
gm.exportedNames = make([]string, len(named))
for name := range named {
gm.exportedNames = append(gm.exportedNames, name)
}
})
named := mi.Exports().Named
gm.exportedNames = make([]string, len(named))
for name := range named {
gm.exportedNames = append(gm.exportedNames, name)
}
for _, callback := range gm.exportedNamesCallbacks {
callback(gm.exportedNames)
}
return &goModuleInstance{rt: rt, mi: mi}, nil
}

Expand All @@ -43,9 +43,12 @@ func (gm *goModule) Evaluate(_ *sobek.Runtime) *sobek.Promise {
}

func (gm *goModule) GetExportedNames(callback func([]string), _ ...sobek.ModuleRecord) bool {
gm.once.Do(func() { panic("this shouldn't happen") })
callback(gm.exportedNames)
return true
if gm.exportedNames != nil {
callback(gm.exportedNames)
return true
}
gm.exportedNamesCallbacks = append(gm.exportedNamesCallbacks, callback)
return false
}

func (gm *goModule) ResolveExport(exportName string, _ ...sobek.ResolveSetElement) (*sobek.ResolvedBinding, bool) {
Expand Down
44 changes: 24 additions & 20 deletions js/modules/gomodule_basic.go
Original file line number Diff line number Diff line change
@@ -1,59 +1,63 @@
package modules

import (
"sync"

"github.com/grafana/sobek"
)

// This sobek.ModuleRecord wrapper for go/js module which does not conform to modules.Module interface
type baseGoModule struct {
m any
once sync.Once
exportedNames []string
type basicGoModule struct {
m any
exportedNames []string
exportedNamesCallbacks []func([]string)
}

var (
_ sobek.CyclicModuleRecord = &baseGoModule{}
_ sobek.CyclicModuleRecord = &basicGoModule{}
_ sobek.CyclicModuleRecord = &goModule{}
)

func (bgm *baseGoModule) Link() error { return nil }
func (bgm *baseGoModule) Evaluate(_ *sobek.Runtime) *sobek.Promise {
func (bgm *basicGoModule) Link() error { return nil }
func (bgm *basicGoModule) Evaluate(_ *sobek.Runtime) *sobek.Promise {
panic("this shouldn't be called")
}

func (bgm *baseGoModule) InitializeEnvironment() error {
func (bgm *basicGoModule) InitializeEnvironment() error {
return nil
}

func (bgm *baseGoModule) Instantiate(rt *sobek.Runtime) (sobek.CyclicModuleInstance, error) {
func (bgm *basicGoModule) Instantiate(rt *sobek.Runtime) (sobek.CyclicModuleInstance, error) {
o := rt.ToValue(bgm.m).ToObject(rt) // TODO checks
bgm.once.Do(func() { bgm.exportedNames = o.Keys() })
bgm.exportedNames = o.Keys()
for _, callback := range bgm.exportedNamesCallbacks {
callback(bgm.exportedNames)
}
return &basicGoModuleInstance{
v: o,
module: bgm,
}, nil
}

func (bgm *baseGoModule) RequestedModules() []string { return nil }
func (bgm *basicGoModule) RequestedModules() []string { return nil }

func (bgm *baseGoModule) ResolveExport(exportName string, _ ...sobek.ResolveSetElement) (*sobek.ResolvedBinding, bool) {
func (bgm *basicGoModule) ResolveExport(name string, _ ...sobek.ResolveSetElement) (*sobek.ResolvedBinding, bool) {
return &sobek.ResolvedBinding{
Module: bgm,
BindingName: exportName,
BindingName: name,
}, false
}

func (bgm *baseGoModule) GetExportedNames(callback func([]string), _ ...sobek.ModuleRecord) bool {
bgm.once.Do(func() { panic("this shouldn't happen") })
callback(bgm.exportedNames)
return true
func (bgm *basicGoModule) GetExportedNames(callback func([]string), _ ...sobek.ModuleRecord) bool {
if bgm.exportedNames != nil {
callback(bgm.exportedNames)
return true
}
bgm.exportedNamesCallbacks = append(bgm.exportedNamesCallbacks, callback)
return false
}

type basicGoModuleInstance struct {
v *sobek.Object
module *baseGoModule
module *basicGoModule
}

func (bgmi *basicGoModuleInstance) GetBindingValue(n string) sobek.Value {
Expand Down
2 changes: 1 addition & 1 deletion js/modules/resolution.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (mr *ModuleResolver) requireModule(name string) (sobek.ModuleRecord, error)
}
k6m, ok := mod.(Module)
if !ok {
return &baseGoModule{m: mod}, nil
return &basicGoModule{m: mod}, nil
}
return &goModule{m: k6m}, nil
}
Expand Down

0 comments on commit cd10cac

Please sign in to comment.