Skip to content

Commit

Permalink
tc39: fix some tests around ESM only syntax
Browse files Browse the repository at this point in the history
the compiler.Parse had 1 boolean argument used for two different things:
1. signal that the parser should wrap the code in order to support
   commonJS
2. signal that if it not the above it should be compiled as a module

no tc39 tests should be wrapped as commonJS, but some of them
(especially the ones directly called in it) also are not modules ... so
this was breaking some tests.

The compiler package likely should be completely redone, but that
started to touch too many things so, lets first at least fix the tests.

This is needed to make *some* top-level-await tests work.
  • Loading branch information
mstoykov committed Oct 25, 2024
1 parent 7fb08af commit d5fe855
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 68 deletions.
6 changes: 4 additions & 2 deletions js/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type parsingState struct {
commonJSWrapped bool // whether the original source is wrapped in a function to make it a CommonJS module
compatibilityMode lib.CompatibilityMode
compiler *Compiler
esm bool

loader func(string) ([]byte, error)
}
Expand All @@ -66,13 +67,14 @@ type parsingState struct {
// The returned program can be compiled directly by Sobek.
// Additionally, it returns the end code that has been parsed including any required transformations.
func (c *Compiler) Parse(
src, filename string, commonJSWrap bool,
src, filename string, commonJSWrap bool, esm bool,
) (prg *ast.Program, finalCode string, err error) {
state := &parsingState{
loader: c.Options.SourceMapLoader,
compatibilityMode: c.Options.CompatibilityMode,
commonJSWrapped: commonJSWrap,
compiler: c,
esm: esm,
}
return state.parseImpl(src, filename, commonJSWrap)
}
Expand All @@ -98,7 +100,7 @@ func (ps *parsingState) parseImpl(src, filename string, commonJSWrap bool) (*ast
opts = append(opts, parser.WithDisableSourceMaps)
}

if !commonJSWrap {
if ps.esm {
opts = append(opts, parser.IsModule)
}

Expand Down
14 changes: 7 additions & 7 deletions js/compiler/compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestCompile(t *testing.T) {
t.Parallel()
c := New(testutils.NewLogger(t))
src := `1+(function() { return 2; })()`
prg, code, err := c.Parse(src, "script.js", false)
prg, code, err := c.Parse(src, "script.js", false, false)
require.NoError(t, err)
assert.Equal(t, src, code)
pgm, err := sobek.CompileAST(prg, true)
Expand All @@ -34,7 +34,7 @@ func TestCompile(t *testing.T) {
t.Parallel()
c := New(testutils.NewLogger(t))
src := `exports.d=1+(function() { return 2; })()`
prg, code, err := c.Parse(src, "script.js", true)
prg, code, err := c.Parse(src, "script.js", true, false)
require.NoError(t, err)
pgm, err := sobek.CompileAST(prg, true)
require.NoError(t, err)
Expand All @@ -57,7 +57,7 @@ func TestCompile(t *testing.T) {
t.Parallel()
c := New(testutils.NewLogger(t))
c.Options.CompatibilityMode = lib.CompatibilityModeExtended
prg, code, err := c.Parse(`import "something"`, "script.js", false)
prg, code, err := c.Parse(`import "something"`, "script.js", false, true)
require.NoError(t, err)
assert.Equal(t, `import "something"`, code)
require.NoError(t, err)
Expand All @@ -71,7 +71,7 @@ func TestCompile(t *testing.T) {
t.Parallel()
c := New(testutils.NewLogger(t))
c.Options.CompatibilityMode = lib.CompatibilityModeExtended
prg, code, err := c.Parse(`require("something");`, "script.js", true)
prg, code, err := c.Parse(`require("something");`, "script.js", true, false)
require.NoError(t, err)
assert.Equal(t, `(function(module, exports){require("something");
})
Expand All @@ -98,7 +98,7 @@ func TestCompile(t *testing.T) {
t.Parallel()
c := New(testutils.NewLogger(t))
c.Options.CompatibilityMode = lib.CompatibilityModeExtended
_, _, err := c.Parse(`1+(=>2)()`, "script.js", false)
_, _, err := c.Parse(`1+(=>2)()`, "script.js", false, false)
assert.IsType(t, parser.ErrorList{}, err)
assert.Contains(t, err.Error(), `Line 1:4 Unexpected token =>`)
})
Expand All @@ -122,7 +122,7 @@ func TestCorruptSourceMap(t *testing.T) {
return corruptSourceMap, nil
},
}
_, _, err := compiler.Parse("var s = 5;\n//# sourceMappingURL=somefile", "somefile", false)
_, _, err := compiler.Parse("var s = 5;\n//# sourceMappingURL=somefile", "somefile", false, false)
require.NoError(t, err)
entries := hook.Drain()
require.Len(t, entries, 1)
Expand Down Expand Up @@ -154,7 +154,7 @@ func TestMinimalSourceMap(t *testing.T) {
return corruptSourceMap, nil
},
}
_, _, err := compiler.Parse("class s {};\n//# sourceMappingURL=somefile", "somefile", false)
_, _, err := compiler.Parse("class s {};\n//# sourceMappingURL=somefile", "somefile", false, false)
require.NoError(t, err)
require.Empty(t, hook.Drain())
}
6 changes: 3 additions & 3 deletions js/compiler/enhanced_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ func TestCompile_experimental_enhanced(t *testing.T) {
c := New(testutils.NewLogger(t))
src := `1+(function() { return 2; )()`
c.Options.CompatibilityMode = lib.CompatibilityModeExperimentalEnhanced
_, _, err := c.Parse(src, "script.ts", false)
_, _, err := c.Parse(src, "script.ts", false, false)
assert.IsType(t, &parser.Error{}, err)
assert.Contains(t, err.Error(), `script.ts: Line 1:26 Unexpected ")"`)
})
t.Run("experimental_enhanced", func(t *testing.T) {
t.Parallel()
c := New(testutils.NewLogger(t))
c.Options.CompatibilityMode = lib.CompatibilityModeExperimentalEnhanced
prg, code, err := c.Parse(`let t :string = "something"; require(t);`, "script.ts", false)
prg, code, err := c.Parse(`let t :string = "something"; require(t);`, "script.ts", false, false)
require.NoError(t, err)
assert.Equal(t, `let t = "something";
require(t);
Expand All @@ -72,7 +72,7 @@ require(t);
c := New(testutils.NewLogger(t))
c.Options.CompatibilityMode = lib.CompatibilityModeExperimentalEnhanced
c.Options.SourceMapLoader = func(_ string) ([]byte, error) { return nil, nil }
_, code, err := c.Parse(`let t :string = "something"; require(t);`, "script.ts", false)
_, code, err := c.Parse(`let t :string = "something"; require(t);`, "script.ts", false, false)
require.NoError(t, err)
assert.Equal(t, `let t = "something";
require(t);
Expand Down
12 changes: 3 additions & 9 deletions js/modules/resolution.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/grafana/sobek"
"github.com/grafana/sobek/ast"
"github.com/sirupsen/logrus"

"go.k6.io/k6/js/compiler"
"go.k6.io/k6/loader"
"go.k6.io/k6/usage"
Expand Down Expand Up @@ -103,24 +104,17 @@ func (mr *ModuleResolver) resolveLoaded(basePWD *url.URL, arg string, data []byt
if cached, ok := mr.cache[specifier.String()]; ok {
return cached.mod, cached.err
}
prg, _, err := mr.compiler.Parse(string(data), specifier.String(), false)
prg, _, err := mr.compiler.Parse(string(data), specifier.String(), false, true)

// if there is an error an we can try to parse it wrapped as CommonJS
// if it isn't ESM - we *must* wrap it in order to work
if err != nil || !isESM(prg) {
var newError error
prg, _, newError = mr.compiler.Parse(string(data), specifier.String(), true)
prg, _, newError = mr.compiler.Parse(string(data), specifier.String(), true, false)
if newError == nil || err == nil {
err = newError
}
}
if err != nil {
var newError error
prg, _, newError = mr.compiler.Parse(string(data), specifier.String(), true)
if newError == nil {
err = newError
}
}
if err != nil {
mr.cache[specifier.String()] = moduleCacheElement{err: err}
return nil, err
Expand Down
24 changes: 1 addition & 23 deletions js/tc39/breaking_test_errors-experimental_enhanced.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,16 @@
"test/language/destructuring/binding/syntax/destructuring-array-parameters-function-arguments-length.js-strict:true": "test/language/destructuring/binding/syntax/destructuring-array-parameters-function-arguments-length.js: SyntaxError: Async generators are not supported yet <at omitted>",
"test/language/destructuring/binding/syntax/destructuring-object-parameters-function-arguments-length.js-strict:true": "test/language/destructuring/binding/syntax/destructuring-object-parameters-function-arguments-length.js: SyntaxError: Async generators are not supported yet <at omitted>",
"test/language/expressions/assignment/fn-name-lhs-cover.js-strict:true": "test/language/expressions/assignment/fn-name-lhs-cover.js: Test262Error: descriptor value should be ; object value should be <at omitted>",
"test/language/expressions/assignmenttargettype/simple-basic-identifierreference-await.js-strict:true": "test/language/expressions/assignmenttargettype/simple-basic-identifierreference-await.js: test/language/expressions/assignmenttargettype/simple-basic-identifierreference-await.js: Line 9:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/await/await-BindingIdentifier-in-global.js-strict:true": "test/language/expressions/await/await-BindingIdentifier-in-global.js: test/language/expressions/await/await-BindingIdentifier-in-global.js: Line 12:16 Unexpected token await (and 2 more errors)",
"test/language/expressions/await/await-in-global.js-strict:true": "test/language/expressions/await/await-in-global.js: test/language/expressions/await/await-in-global.js: Line 12:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/await/await-in-nested-function.js-strict:true": "test/language/expressions/await/await-in-nested-function.js: test/language/expressions/await/await-in-nested-function.js: Line 12:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/await/await-in-nested-generator.js-strict:true": "test/language/expressions/await/await-in-nested-generator.js: test/language/expressions/await/await-in-nested-generator.js: Line 13:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/class/class-name-ident-await-escaped-module.js-strict:true": "test/language/expressions/class/class-name-ident-await-escaped-module.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/expressions/class/class-name-ident-await-escaped.js-strict:true": "test/language/expressions/class/class-name-ident-await-escaped.js: test/language/expressions/class/class-name-ident-await-escaped.js: Line 18:15 Keyword must not contain escaped characters (and 3 more errors)",
"test/language/expressions/class/class-name-ident-await-module.js-strict:true": "test/language/expressions/class/class-name-ident-await-module.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/expressions/class/class-name-ident-await.js-strict:true": "test/language/expressions/class/class-name-ident-await.js: test/language/expressions/class/class-name-ident-await.js: Line 17:15 Unexpected token await (and 3 more errors)",
"test/language/expressions/class/elements/private-getter-is-not-a-own-property.js-strict:true": "test/language/expressions/class/elements/private-getter-is-not-a-own-property.js: TypeError: Object has no member '__lookupGetter__' <at omitted>",
"test/language/expressions/class/elements/private-setter-is-not-a-own-property.js-strict:true": "test/language/expressions/class/elements/private-setter-is-not-a-own-property.js: TypeError: Object has no member '__lookupSetter__' <at omitted>",
"test/language/expressions/class/static-init-await-reference.js-strict:true": "test/language/expressions/class/static-init-await-reference.js: test/language/expressions/class/static-init-await-reference.js: Line 15:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/function/static-init-await-reference.js-strict:true": "test/language/expressions/function/static-init-await-reference.js: test/language/expressions/function/static-init-await-reference.js: Line 15:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/generators/static-init-await-reference.js-strict:true": "test/language/expressions/generators/static-init-await-reference.js: test/language/expressions/generators/static-init-await-reference.js: Line 15:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js-strict:true": "test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js: file:///TestTC39/test262/test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js: Line 28:25 import not supported in script (and 19 more errors)",
"test/language/expressions/import.meta/same-object-returned.js-strict:true": "test/language/expressions/import.meta/same-object-returned.js: file:///TestTC39/test262/test/language/expressions/import.meta/same-object-returned.js: Line 28:9 import not supported in script (and 3 more errors)",
"test/language/expressions/import.meta/syntax/goal-module-nested-function.js-strict:true": "test/language/expressions/import.meta/syntax/goal-module-nested-function.js: file:///TestTC39/test262/test/language/expressions/import.meta/syntax/goal-module-nested-function.js: Line 16:3 import not supported in script (and 4 more errors)",
"test/language/expressions/import.meta/syntax/goal-module.js-strict:true": "test/language/expressions/import.meta/syntax/goal-module.js: file:///TestTC39/test262/test/language/expressions/import.meta/syntax/goal-module.js: Line 15:1 import not supported in script (and 3 more errors)",
"test/language/expressions/import.meta/syntax/goal-script.js-strict:true": "test/language/expressions/import.meta/syntax/goal-script.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/expressions/in/private-field-rhs-await-absent.js-strict:true": "test/language/expressions/in/private-field-rhs-await-absent.js: test/language/expressions/in/private-field-rhs-await-absent.js: Line 24:10 Unexpected token await",
"test/language/expressions/object/identifier-shorthand-await-strict-mode.js-strict:false": "test/language/expressions/object/identifier-shorthand-await-strict-mode.js: test/language/expressions/object/identifier-shorthand-await-strict-mode.js: Line 19:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/object/method-definition/static-init-await-reference-accessor.js-strict:true": "test/language/expressions/object/method-definition/static-init-await-reference-accessor.js: test/language/expressions/object/method-definition/static-init-await-reference-accessor.js: Line 15:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/object/method-definition/static-init-await-reference-generator.js-strict:true": "test/language/expressions/object/method-definition/static-init-await-reference-generator.js: test/language/expressions/object/method-definition/static-init-await-reference-generator.js: Line 15:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/object/method-definition/static-init-await-reference-normal.js-strict:true": "test/language/expressions/object/method-definition/static-init-await-reference-normal.js: test/language/expressions/object/method-definition/static-init-await-reference-normal.js: Line 15:5 Unexpected token await (and 1 more errors)",
"test/language/expressions/optional-chaining/iteration-statement-for-await-of.js-strict:true": "test/language/expressions/optional-chaining/iteration-statement-for-await-of.js: test/language/expressions/optional-chaining/iteration-statement-for-await-of.js: Line 32:7 Unexpected token await (and 9 more errors)",
"test/language/expressions/optional-chaining/member-expression.js-strict:true": "test/language/expressions/optional-chaining/member-expression.js: SyntaxError: Async generators are not supported yet <at omitted>",
"test/language/global-code/import.js-strict:true": "test/language/global-code/import.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/literals/numeric/non-octal-decimal-integer.js-strict:false": "test/language/literals/numeric/non-octal-decimal-integer.js: test/language/literals/numeric/non-octal-decimal-integer.js: Line 28:18 Unexpected token ILLEGAL (and 1 more errors)",
"test/language/literals/regexp/S7.8.5_A1.1_T2.js-strict:true": "test/language/literals/regexp/S7.8.5_A1.1_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\ud800», «�») to be true <at omitted>",
"test/language/literals/regexp/S7.8.5_A1.4_T2.js-strict:true": "test/language/literals/regexp/S7.8.5_A1.4_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\\\\\ud800», «\\�») to be true <at omitted>",
Expand Down Expand Up @@ -100,15 +83,10 @@
"test/language/module-code/parse-err-hoist-lex-fun.js-strict:true": "test/language/module-code/parse-err-hoist-lex-fun.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/module-code/parse-err-return.js-strict:true": "test/language/module-code/parse-err-return.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/reserved-words/await-module.js-strict:true": "test/language/reserved-words/await-module.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/reserved-words/await-script.js-strict:true": "test/language/reserved-words/await-script.js: test/language/reserved-words/await-script.js: Line 10:5 Unexpected token await (and 1 more errors)",
"test/language/statements/class/class-name-ident-await-escaped-module.js-strict:true": "test/language/statements/class/class-name-ident-await-escaped-module.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/statements/class/class-name-ident-await-escaped.js-strict:true": "test/language/statements/class/class-name-ident-await-escaped.js: test/language/statements/class/class-name-ident-await-escaped.js: Line 18:7 Keyword must not contain escaped characters",
"test/language/statements/class/class-name-ident-await-module.js-strict:true": "test/language/statements/class/class-name-ident-await-module.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/statements/class/class-name-ident-await.js-strict:true": "test/language/statements/class/class-name-ident-await.js: test/language/statements/class/class-name-ident-await.js: Line 17:7 Unexpected token await",
"test/language/statements/class/elements/private-getter-is-not-a-own-property.js-strict:true": "test/language/statements/class/elements/private-getter-is-not-a-own-property.js: TypeError: Object has no member '__lookupGetter__' <at omitted>",
"test/language/statements/class/elements/private-setter-is-not-a-own-property.js-strict:true": "test/language/statements/class/elements/private-setter-is-not-a-own-property.js: TypeError: Object has no member '__lookupSetter__' <at omitted>",
"test/language/statements/labeled/value-await-module-escaped.js-strict:true": "test/language/statements/labeled/value-await-module-escaped.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/statements/labeled/value-await-module.js-strict:true": "test/language/statements/labeled/value-await-module.js: error is not an object (Test262: This statement should not be evaluated.)",
"test/language/statements/labeled/value-await-non-module-escaped.js-strict:true": "test/language/statements/labeled/value-await-non-module-escaped.js: test/language/statements/labeled/value-await-non-module-escaped.js: Line 16:1 Keyword must not contain escaped characters",
"test/language/statements/labeled/value-await-non-module.js-strict:true": "test/language/statements/labeled/value-await-non-module.js: test/language/statements/labeled/value-await-non-module.js: Line 15:6 Unexpected token :"
"test/language/statements/labeled/value-await-module.js-strict:true": "test/language/statements/labeled/value-await-module.js: error is not an object (Test262: This statement should not be evaluated.)"
}
Loading

0 comments on commit d5fe855

Please sign in to comment.