diff --git a/go.mod b/go.mod index 941d4a87948..5bd9cf9b10c 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/PuerkitoBio/goquery v1.8.0 github.com/Soontao/goHttpDigestClient v0.0.0-20170320082612-6d28bb1415c5 github.com/andybalholm/brotli v1.0.4 - github.com/dop251/goja v0.0.0-20220324112439-a18ffb9c5866 + github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf github.com/fatih/color v1.13.0 github.com/golang/protobuf v1.5.2 github.com/gorilla/websocket v1.5.0 diff --git a/go.sum b/go.sum index 2924883d135..f62c719b4ef 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dop251/goja v0.0.0-20220324112439-a18ffb9c5866 h1:LAjokPR4PSrBQ2uLG9jFAa4ajdXUn4acffvcdfN58WA= -github.com/dop251/goja v0.0.0-20220324112439-a18ffb9c5866/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= +github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= diff --git a/js/modules/k6/http/file_test.go b/js/modules/k6/http/file_test.go index ba22524e026..a771562a4a7 100644 --- a/js/modules/k6/http/file_test.go +++ b/js/modules/k6/http/file_test.go @@ -81,3 +81,16 @@ func TestHTTPFile(t *testing.T) { }) } } + +func TestHTTPFileDataInRequest(t *testing.T) { + t.Parallel() + + tb, _, _, rt, _ := newRuntime(t) //nolint:dogsled + _, err := rt.RunString(tb.Replacer.Replace(` + let f = http.file("something"); + let res = http.request("POST", "HTTPBIN_URL/post", f.data); + if (res.status != 200) { + throw new Error("Unexpected status " + res.status) + }`)) + require.NoError(t, err) +} diff --git a/js/tc39/breaking_test_errors.json b/js/tc39/breaking_test_errors.json index f756e4b7ced..360c8c7fb76 100644 --- a/js/tc39/breaking_test_errors.json +++ b/js/tc39/breaking_test_errors.json @@ -158,8 +158,8 @@ "test/language/eval-code/direct/gen-meth-fn-body-cntns-arguments-lex-bind-declare-arguments.js-strict:false": "test/language/eval-code/direct/gen-meth-fn-body-cntns-arguments-lex-bind-declare-arguments.js: SyntaxError: test/language/eval-code/direct/gen-meth-fn-body-cntns-arguments-lex-bind-declare-arguments.js: arguments is a reserved word in strict mode (15:6)\n 13 | \n 14 | let o = { * f(p = eval(\"var arguments\")) {\n> 15 | let arguments;\n | ^\n 16 | }};\n 17 | assert.throws(SyntaxError, o.f);\n 18 | ", "test/language/eval-code/direct/gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign.js-strict:false": "test/language/eval-code/direct/gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign.js: SyntaxError: test/language/eval-code/direct/gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign.js: arguments is a reserved word in strict mode (14:6)\n 12 | \n 13 | let o = { * f(p = eval(\"var arguments = 'param'\")) {\n> 14 | var arguments;\n | ^\n 15 | }};\n 16 | assert.throws(SyntaxError, o.f);\n 17 | ", "test/language/eval-code/direct/gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments.js-strict:false": "test/language/eval-code/direct/gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments.js: SyntaxError: test/language/eval-code/direct/gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments.js: arguments is a reserved word in strict mode (14:6)\n 12 | \n 13 | let o = { * f(p = eval(\"var arguments\")) {\n> 14 | var arguments;\n | ^\n 15 | }};\n 16 | assert.throws(SyntaxError, o.f);\n 17 | ", - "test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign.js-strict:false": "test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign.js: test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign.js: Line 13:12 Unexpected token * (and 5 more errors)", - "test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments.js-strict:false": "test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments.js: test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments.js: Line 13:12 Unexpected token * (and 5 more errors)", + "test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign.js-strict:false": "test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign.js: test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign.js: Line 13:12 Unexpected token * (and 11 more errors)", + "test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments.js-strict:false": "test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments.js: test/language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments.js: Line 13:12 Unexpected token * (and 11 more errors)", "test/language/eval-code/direct/lex-env-distinct-cls.js-strict:true": "test/language/eval-code/direct/lex-env-distinct-cls.js: SyntaxError: SyntaxError: : Line 1:1 Unexpected reserved word ", "test/language/eval-code/direct/lex-env-no-init-cls.js-strict:true": "test/language/eval-code/direct/lex-env-no-init-cls.js: Test262Error: Expected a ReferenceError but got a SyntaxError ", "test/language/eval-code/direct/new.target-fn.js-strict:true": "test/language/eval-code/direct/new.target-fn.js: SyntaxError: SyntaxError: : Line 1:1 new.target expression is not allowed here ", @@ -186,11 +186,11 @@ "test/language/expressions/class/class-name-ident-await-escaped.js-strict:true": "test/language/expressions/class/class-name-ident-await-escaped.js: SyntaxError: test/language/expressions/class/class-name-ident-await-escaped.js: await is a reserved word (18:14)\n 16 | ---*/\n 17 | \n> 18 | var C = class aw\\u0061it {};\n | ^\n 19 | ", "test/language/expressions/class/class-name-ident-await.js-strict:true": "test/language/expressions/class/class-name-ident-await.js: SyntaxError: test/language/expressions/class/class-name-ident-await.js: await is a reserved word (17:14)\n 15 | ---*/\n 16 | \n> 17 | var C = class await {};\n | ^\n 18 | ", "test/language/expressions/class/constructor-this-tdz-during-initializers.js-strict:true": "test/language/expressions/class/constructor-this-tdz-during-initializers.js: SyntaxError: test/language/expressions/class/constructor-this-tdz-during-initializers.js: Unexpected token (31:8)\n 29 | \n 30 | var C = class extends Base {\n> 31 | field = (thisDuringField = this, thisFromProbe = probeCtorThis());\n | ^\n 32 | constructor() {\n 33 | probeCtorThis = () => this;\n 34 | assert.throws(ReferenceError, probeCtorThis); ", - "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-async-arrow-function-expression.js-strict:true": "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-async-arrow-function-expression.js: test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-async-arrow-function-expression.js: Line 44:5 Malformed arrow function parameter list (and 11 more errors)", + "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-async-arrow-function-expression.js-strict:true": "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-async-arrow-function-expression.js: test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-async-arrow-function-expression.js: Line 44:5 Malformed arrow function parameter list (and 15 more errors)", "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-await-expression.js-strict:true": "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-await-expression.js: SyntaxError: test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-await-expression.js: await is a reserved word (41:7)\n 39 | \n 40 | let C = class {\n> 41 | get [await 9]() {\n | ^\n 42 | return 9;\n 43 | }\n 44 | ", "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-expression-coalesce.js-strict:true": "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-expression-coalesce.js: SyntaxError: test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-expression-coalesce.js: Unexpected token (41:10)\n 39 | \n 40 | let C = class {\n> 41 | get [x ?? 1]() {\n | ^\n 42 | return 2;\n 43 | }\n 44 | ", "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-integer-separators.js-strict:true": "test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-integer-separators.js: SyntaxError: test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-integer-separators.js: Identifier directly after number (40:8)\n 38 | \n 39 | let C = class {\n> 40 | get [1_2_3_4_5_6_7_8]() {\n | ^\n 41 | return 1_2_3_4_5_6_7_8;\n 42 | }\n 43 | ", - "test/language/expressions/class/cpn-class-expr-computed-property-name-from-async-arrow-function-expression.js-strict:true": "test/language/expressions/class/cpn-class-expr-computed-property-name-from-async-arrow-function-expression.js: test/language/expressions/class/cpn-class-expr-computed-property-name-from-async-arrow-function-expression.js: Line 40:5 Malformed arrow function parameter list (and 11 more errors)", + "test/language/expressions/class/cpn-class-expr-computed-property-name-from-async-arrow-function-expression.js-strict:true": "test/language/expressions/class/cpn-class-expr-computed-property-name-from-async-arrow-function-expression.js: test/language/expressions/class/cpn-class-expr-computed-property-name-from-async-arrow-function-expression.js: Line 40:5 Malformed arrow function parameter list (and 13 more errors)", "test/language/expressions/class/cpn-class-expr-computed-property-name-from-await-expression.js-strict:true": "test/language/expressions/class/cpn-class-expr-computed-property-name-from-await-expression.js: SyntaxError: test/language/expressions/class/cpn-class-expr-computed-property-name-from-await-expression.js: await is a reserved word (41:3)\n 39 | \n 40 | let C = class {\n> 41 | [await 9]() {\n | ^\n 42 | return 9;\n 43 | }\n 44 | static [await 9]() { ", "test/language/expressions/class/cpn-class-expr-computed-property-name-from-expression-coalesce.js-strict:true": "test/language/expressions/class/cpn-class-expr-computed-property-name-from-expression-coalesce.js: SyntaxError: test/language/expressions/class/cpn-class-expr-computed-property-name-from-expression-coalesce.js: Unexpected token (41:6)\n 39 | \n 40 | let C = class {\n> 41 | [x ?? 1]() {\n | ^\n 42 | return 2;\n 43 | }\n 44 | static [x ?? 1]() { ", "test/language/expressions/class/cpn-class-expr-computed-property-name-from-integer-separators.js-strict:true": "test/language/expressions/class/cpn-class-expr-computed-property-name-from-integer-separators.js: SyntaxError: test/language/expressions/class/cpn-class-expr-computed-property-name-from-integer-separators.js: Identifier directly after number (40:4)\n 38 | \n 39 | let C = class {\n> 40 | [1_2_3_4_5_6_7_8]() {\n | ^\n 41 | return 1_2_3_4_5_6_7_8;\n 42 | }\n 43 | static [1_2_3_4_5_6_7_8]() { ", @@ -1248,11 +1248,11 @@ "test/language/statements/class/class-name-ident-await-escaped.js-strict:true": "test/language/statements/class/class-name-ident-await-escaped.js: SyntaxError: test/language/statements/class/class-name-ident-await-escaped.js: await is a reserved word (18:6)\n 16 | ---*/\n 17 | \n> 18 | class aw\\u0061it {}\n | ^\n 19 | ", "test/language/statements/class/class-name-ident-await.js-strict:true": "test/language/statements/class/class-name-ident-await.js: SyntaxError: test/language/statements/class/class-name-ident-await.js: await is a reserved word (17:6)\n 15 | ---*/\n 16 | \n> 17 | class await {}\n | ^\n 18 | ", "test/language/statements/class/classelementname-abrupt-completion.js-strict:true": "test/language/statements/class/classelementname-abrupt-completion.js: SyntaxError: test/language/statements/class/classelementname-abrupt-completion.js: Missing class properties transform.\n 39 | assert.throws(Test262Error, function() {\n 40 | class C {\n> 41 | [f()]\n | ^\n 42 | }\n 43 | });\n 44 | ", - "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-async-arrow-function-expression.js-strict:true": "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-async-arrow-function-expression.js: test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-async-arrow-function-expression.js: Line 44:5 Malformed arrow function parameter list (and 11 more errors)", + "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-async-arrow-function-expression.js-strict:true": "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-async-arrow-function-expression.js: test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-async-arrow-function-expression.js: Line 44:5 Malformed arrow function parameter list (and 15 more errors)", "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-await-expression.js-strict:true": "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-await-expression.js: SyntaxError: test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-await-expression.js: await is a reserved word (41:7)\n 39 | \n 40 | class C {\n> 41 | get [await 9]() {\n | ^\n 42 | return 9;\n 43 | }\n 44 | ", "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-expression-coalesce.js-strict:true": "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-expression-coalesce.js: SyntaxError: test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-expression-coalesce.js: Unexpected token (41:10)\n 39 | \n 40 | class C {\n> 41 | get [x ?? 1]() {\n | ^\n 42 | return 2;\n 43 | }\n 44 | ", "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-integer-separators.js-strict:true": "test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-integer-separators.js: SyntaxError: test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-integer-separators.js: Identifier directly after number (40:8)\n 38 | \n 39 | class C {\n> 40 | get [1_2_3_4_5_6_7_8]() {\n | ^\n 41 | return 1_2_3_4_5_6_7_8;\n 42 | }\n 43 | ", - "test/language/statements/class/cpn-class-decl-computed-property-name-from-async-arrow-function-expression.js-strict:true": "test/language/statements/class/cpn-class-decl-computed-property-name-from-async-arrow-function-expression.js: test/language/statements/class/cpn-class-decl-computed-property-name-from-async-arrow-function-expression.js: Line 40:5 Malformed arrow function parameter list (and 11 more errors)", + "test/language/statements/class/cpn-class-decl-computed-property-name-from-async-arrow-function-expression.js-strict:true": "test/language/statements/class/cpn-class-decl-computed-property-name-from-async-arrow-function-expression.js: test/language/statements/class/cpn-class-decl-computed-property-name-from-async-arrow-function-expression.js: Line 40:5 Malformed arrow function parameter list (and 13 more errors)", "test/language/statements/class/cpn-class-decl-computed-property-name-from-await-expression.js-strict:true": "test/language/statements/class/cpn-class-decl-computed-property-name-from-await-expression.js: SyntaxError: test/language/statements/class/cpn-class-decl-computed-property-name-from-await-expression.js: await is a reserved word (41:3)\n 39 | \n 40 | class C {\n> 41 | [await 9]() {\n | ^\n 42 | return 9;\n 43 | }\n 44 | static [await 9]() { ", "test/language/statements/class/cpn-class-decl-computed-property-name-from-expression-coalesce.js-strict:true": "test/language/statements/class/cpn-class-decl-computed-property-name-from-expression-coalesce.js: SyntaxError: test/language/statements/class/cpn-class-decl-computed-property-name-from-expression-coalesce.js: Unexpected token (41:6)\n 39 | \n 40 | class C {\n> 41 | [x ?? 1]() {\n | ^\n 42 | return 2;\n 43 | }\n 44 | static [x ?? 1]() { ", "test/language/statements/class/cpn-class-decl-computed-property-name-from-integer-separators.js-strict:true": "test/language/statements/class/cpn-class-decl-computed-property-name-from-integer-separators.js: SyntaxError: test/language/statements/class/cpn-class-decl-computed-property-name-from-integer-separators.js: Identifier directly after number (40:4)\n 38 | \n 39 | class C {\n> 40 | [1_2_3_4_5_6_7_8]() {\n | ^\n 41 | return 1_2_3_4_5_6_7_8;\n 42 | }\n 43 | static [1_2_3_4_5_6_7_8]() { ", diff --git a/vendor/github.com/dop251/goja/.tc39_test262_checkout.sh b/vendor/github.com/dop251/goja/.tc39_test262_checkout.sh index 07fe7811054..65dedfc68af 100644 --- a/vendor/github.com/dop251/goja/.tc39_test262_checkout.sh +++ b/vendor/github.com/dop251/goja/.tc39_test262_checkout.sh @@ -1,6 +1,6 @@ #!/bin/sh # this is just the commit it was last tested with -sha=e87b0048c402479df1d9cb391fb86620cf3200fd +sha=926b0960d737b9f1dfd0ec0c1dfd95d836016d33 mkdir -p testdata/test262 cd testdata/test262 diff --git a/vendor/github.com/dop251/goja/array.go b/vendor/github.com/dop251/goja/array.go index 6cff33fe389..f8028d27210 100644 --- a/vendor/github.com/dop251/goja/array.go +++ b/vendor/github.com/dop251/goja/array.go @@ -127,9 +127,6 @@ func (a *arrayObject) setLengthInt(l uint32, throw bool) bool { } func (a *arrayObject) setLength(v uint32, throw bool) bool { - if v == a.length { - return true - } if !a.lengthProp.writable { a.val.runtime.typeErrorResult(throw, "length is not writable") return false @@ -201,7 +198,7 @@ func (a *arrayObject) getStr(name unistring.String, receiver Value) Value { return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver) } -func (a *arrayObject) getLengthProp() Value { +func (a *arrayObject) getLengthProp() *valueProperty { a.lengthProp.value = intToValue(int64(a.length)) return &a.lengthProp } @@ -382,7 +379,10 @@ func (r *Runtime) defineArrayLength(prop *valueProperty, descr PropertyDescripto } if descr.Value != nil { - ret = setter(newLen, false) + oldLen := uint32(prop.value.ToInteger()) + if oldLen != newLen { + ret = setter(newLen, false) + } } else { ret = true } @@ -437,7 +437,7 @@ func (a *arrayObject) defineOwnPropertyStr(name unistring.String, descr Property return a._defineIdxProperty(idx, descr, throw) } if name == "length" { - return a.val.runtime.defineArrayLength(&a.lengthProp, descr, a.setLength, throw) + return a.val.runtime.defineArrayLength(a.getLengthProp(), descr, a.setLength, throw) } return a.baseObject.defineOwnPropertyStr(name, descr, throw) } diff --git a/vendor/github.com/dop251/goja/array_sparse.go b/vendor/github.com/dop251/goja/array_sparse.go index 0c0917a8ba7..9a352aff48f 100644 --- a/vendor/github.com/dop251/goja/array_sparse.go +++ b/vendor/github.com/dop251/goja/array_sparse.go @@ -78,9 +78,6 @@ func (a *sparseArrayObject) setLengthInt(l uint32, throw bool) bool { } func (a *sparseArrayObject) setLength(v uint32, throw bool) bool { - if v == a.length { - return true - } if !a.lengthProp.writable { a.val.runtime.typeErrorResult(throw, "length is not writable") return false @@ -120,7 +117,7 @@ func (a *sparseArrayObject) getIdx(idx valueInt, receiver Value) Value { return prop } -func (a *sparseArrayObject) getLengthProp() Value { +func (a *sparseArrayObject) getLengthProp() *valueProperty { a.lengthProp.value = intToValue(int64(a.length)) return &a.lengthProp } @@ -369,7 +366,7 @@ func (a *sparseArrayObject) defineOwnPropertyStr(name unistring.String, descr Pr return a._defineIdxProperty(idx, descr, throw) } if name == "length" { - return a.val.runtime.defineArrayLength(&a.lengthProp, descr, a.setLength, throw) + return a.val.runtime.defineArrayLength(a.getLengthProp(), descr, a.setLength, throw) } return a.baseObject.defineOwnPropertyStr(name, descr, throw) } diff --git a/vendor/github.com/dop251/goja/builtin_array.go b/vendor/github.com/dop251/goja/builtin_array.go index 5003f2558c8..954e1a234c0 100644 --- a/vendor/github.com/dop251/goja/builtin_array.go +++ b/vendor/github.com/dop251/goja/builtin_array.go @@ -144,8 +144,8 @@ func (r *Runtime) arrayproto_pop(call FunctionCall) Value { obj := call.This.ToObject(r) if a, ok := obj.self.(*arrayObject); ok { l := a.length + var val Value if l > 0 { - var val Value l-- if l < uint32(len(a.values)) { val = a.values[l] @@ -161,10 +161,15 @@ func (r *Runtime) arrayproto_pop(call FunctionCall) Value { //a._setLengthInt(l, false) a.values[l] = nil a.values = a.values[:l] + } else { + val = _undefined + } + if a.lengthProp.writable { a.length = l - return val + } else { + a.setLength(0, true) // will throw } - return _undefined + return val } else { return r.arrayproto_pop_generic(obj) } @@ -313,7 +318,7 @@ func (r *Runtime) arrayproto_slice(call FunctionCall) Value { a := arraySpeciesCreate(o, count) if src := r.checkStdArrayObj(o); src != nil { - if dst, ok := a.self.(*arrayObject); ok { + if dst := r.checkStdArrayObjWithProto(a); dst != nil { values := make([]Value, count) copy(values, src.values[start:]) setArrayValues(dst, values) @@ -396,7 +401,7 @@ func (r *Runtime) arrayproto_splice(call FunctionCall) Value { itemCount := max(int64(len(call.Arguments)-2), 0) newLength := length - actualDeleteCount + itemCount if src := r.checkStdArrayObj(o); src != nil { - if dst, ok := a.self.(*arrayObject); ok { + if dst := r.checkStdArrayObjWithProto(a); dst != nil { values := make([]Value, actualDeleteCount) copy(values, src.values[actualStart:]) setArrayValues(dst, values) @@ -484,7 +489,7 @@ func (r *Runtime) arrayproto_unshift(call FunctionCall) Value { argCount := int64(len(call.Arguments)) newLen := intToValue(length + argCount) newSize := length + argCount - if arr := r.checkStdArrayObj(o); arr != nil && newSize < math.MaxUint32 { + if arr := r.checkStdArrayObjWithProto(o); arr != nil && newSize < math.MaxUint32 { if int64(cap(arr.values)) >= newSize { arr.values = arr.values[:newSize] copy(arr.values[argCount:], arr.values[:length]) @@ -917,8 +922,11 @@ func (r *Runtime) arrayproto_reverse(call FunctionCall) Value { func (r *Runtime) arrayproto_shift(call FunctionCall) Value { o := call.This.ToObject(r) - if a := r.checkStdArrayObj(o); a != nil { + if a := r.checkStdArrayObjWithProto(o); a != nil { if len(a.values) == 0 { + if !a.lengthProp.writable { + a.setLength(0, true) // will throw + } return _undefined } first := a.values[0] @@ -1138,6 +1146,20 @@ func (r *Runtime) checkStdArrayObj(obj *Object) *arrayObject { return nil } +func (r *Runtime) checkStdArrayObjWithProto(obj *Object) *arrayObject { + if arr := r.checkStdArrayObj(obj); arr != nil { + if p1, ok := arr.prototype.self.(*arrayObject); ok && p1.propValueCount == 0 { + if p2, ok := p1.prototype.self.(*baseObject); ok && p2.prototype == nil { + p2.ensurePropOrder() + if p2.idxPropCount == 0 { + return arr + } + } + } + } + return nil +} + func (r *Runtime) checkStdArray(v Value) *arrayObject { if obj, ok := v.(*Object); ok { return r.checkStdArrayObj(obj) @@ -1195,7 +1217,7 @@ func (r *Runtime) array_from(call FunctionCall) Value { } iter := r.getIterator(items, usingIterator) if mapFn == nil { - if a := r.checkStdArrayObj(arr); a != nil { + if a := r.checkStdArrayObjWithProto(arr); a != nil { var values []Value iter.iterate(func(val Value) { values = append(values, val) @@ -1222,7 +1244,7 @@ func (r *Runtime) array_from(call FunctionCall) Value { arr = r.newArrayValues(nil) } if mapFn == nil { - if a := r.checkStdArrayObj(arr); a != nil { + if a := r.checkStdArrayObjWithProto(arr); a != nil { values := make([]Value, l) for k := int64(0); k < l; k++ { values[k] = nilSafe(arrayLike.self.getIdx(valueInt(k), nil)) @@ -1344,6 +1366,8 @@ func (r *Runtime) createArrayProto(val *Object) objectImpl { bl.setOwnStr("includes", valueTrue, true) bl.setOwnStr("keys", valueTrue, true) bl.setOwnStr("values", valueTrue, true) + bl.setOwnStr("groupBy", valueTrue, true) + bl.setOwnStr("groupByToMap", valueTrue, true) o._putSym(SymUnscopables, valueProp(bl.val, false, false, true)) return o diff --git a/vendor/github.com/dop251/goja/object.go b/vendor/github.com/dop251/goja/object.go index 5426733c535..d3fc45f6504 100644 --- a/vendor/github.com/dop251/goja/object.go +++ b/vendor/github.com/dop251/goja/object.go @@ -590,9 +590,7 @@ func (o *baseObject) setForeignStr(name unistring.String, val, receiver Value, t func (o *baseObject) setForeignIdx(name valueInt, val, receiver Value, throw bool) (bool, bool) { if idx := toIdx(name); idx != math.MaxUint32 { - if o.lastSortedPropLen != len(o.propNames) { - o.fixPropOrder() - } + o.ensurePropOrder() if o.idxPropCount == 0 { return o._setForeignIdx(name, name, nil, receiver, throw) } @@ -1238,9 +1236,7 @@ func copyNamesIfNeeded(names []unistring.String, extraCap int) []unistring.Strin } func (o *baseObject) iterateStringKeys() iterNextFunc { - if len(o.propNames) > o.lastSortedPropLen { - o.fixPropOrder() - } + o.ensurePropOrder() propNames := prepareNamesForCopy(o.propNames) o.propNames = propNames return (&objectPropIter{ @@ -1301,6 +1297,13 @@ func (o *baseObject) equal(objectImpl) bool { return false } +// hopefully this gets inlined +func (o *baseObject) ensurePropOrder() { + if o.lastSortedPropLen < len(o.propNames) { + o.fixPropOrder() + } +} + // Reorder property names so that any integer properties are shifted to the beginning of the list // in ascending order. This is to conform to https://262.ecma-international.org/#sec-ordinaryownpropertykeys. // Personally I think this requirement is strange. I can sort of understand where they are coming from, @@ -1336,9 +1339,7 @@ func (o *baseObject) fixPropOrder() { } func (o *baseObject) stringKeys(all bool, keys []Value) []Value { - if len(o.propNames) > o.lastSortedPropLen { - o.fixPropOrder() - } + o.ensurePropOrder() if all { for _, k := range o.propNames { keys = append(keys, stringValueFromRaw(k)) diff --git a/vendor/github.com/dop251/goja/object_goarray_reflect.go b/vendor/github.com/dop251/goja/object_goarray_reflect.go index 9b6998afc55..92f9e958097 100644 --- a/vendor/github.com/dop251/goja/object_goarray_reflect.go +++ b/vendor/github.com/dop251/goja/object_goarray_reflect.go @@ -50,7 +50,7 @@ func (o *objectGoArrayReflect) _getIdx(idx int) Value { if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() { return _null } - return o.val.runtime.ToValue(v.Interface()) + return o.val.runtime.toValue(v.Interface(), v) } func (o *objectGoArrayReflect) getIdx(idx valueInt, receiver Value) Value { diff --git a/vendor/github.com/dop251/goja/object_gomap_reflect.go b/vendor/github.com/dop251/goja/object_gomap_reflect.go index 2734acfb401..324e68fe802 100644 --- a/vendor/github.com/dop251/goja/object_gomap_reflect.go +++ b/vendor/github.com/dop251/goja/object_gomap_reflect.go @@ -41,7 +41,7 @@ func (o *objectGoMapReflect) _get(n Value) Value { return nil } if v := o.value.MapIndex(key); v.IsValid() { - return o.val.runtime.ToValue(v.Interface()) + return o.val.runtime.toValue(v.Interface(), v) } return nil @@ -53,7 +53,7 @@ func (o *objectGoMapReflect) _getStr(name string) Value { return nil } if v := o.value.MapIndex(key); v.IsValid() { - return o.val.runtime.ToValue(v.Interface()) + return o.val.runtime.toValue(v.Interface(), v) } return nil diff --git a/vendor/github.com/dop251/goja/object_goreflect.go b/vendor/github.com/dop251/goja/object_goreflect.go index 86e8fb54b08..0fde90710cb 100644 --- a/vendor/github.com/dop251/goja/object_goreflect.go +++ b/vendor/github.com/dop251/goja/object_goreflect.go @@ -155,22 +155,15 @@ func (o *objectGoReflect) _getMethod(jsName string) reflect.Value { return reflect.Value{} } -func (o *objectGoReflect) getAddr(v reflect.Value) reflect.Value { - if (v.Kind() == reflect.Struct || v.Kind() == reflect.Slice) && v.CanAddr() { - return v.Addr() - } - return v -} - func (o *objectGoReflect) _get(name string) Value { if o.value.Kind() == reflect.Struct { if v := o._getField(name); v.IsValid() { - return o.val.runtime.ToValue(o.getAddr(v).Interface()) + return o.val.runtime.toValue(v.Interface(), v) } } if v := o._getMethod(name); v.IsValid() { - return o.val.runtime.ToValue(v.Interface()) + return o.val.runtime.toValue(v.Interface(), v) } return nil @@ -181,7 +174,7 @@ func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value { if o.value.Kind() == reflect.Struct { if v := o._getField(n); v.IsValid() { return &valueProperty{ - value: o.val.runtime.ToValue(o.getAddr(v).Interface()), + value: o.val.runtime.toValue(v.Interface(), v), writable: v.CanSet(), enumerable: true, } @@ -190,7 +183,7 @@ func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value { if v := o._getMethod(n); v.IsValid() { return &valueProperty{ - value: o.val.runtime.ToValue(v.Interface()), + value: o.val.runtime.toValue(v.Interface(), v), enumerable: true, } } diff --git a/vendor/github.com/dop251/goja/parser/expression.go b/vendor/github.com/dop251/goja/parser/expression.go index 568f89113a8..339cd74c67e 100644 --- a/vendor/github.com/dop251/goja/parser/expression.go +++ b/vendor/github.com/dop251/goja/parser/expression.go @@ -333,6 +333,9 @@ func (self *_parser) parseObjectProperty() ast.Property { } keyStartIdx := self.idx literal, parsedLiteral, value, tkn := self.parseObjectPropertyKey() + if value == nil { + return nil + } if tkn == token.IDENTIFIER || tkn == token.STRING || tkn == token.KEYWORD || tkn == token.ILLEGAL { switch { case self.token == token.LEFT_PARENTHESIS: @@ -367,54 +370,43 @@ func (self *_parser) parseObjectProperty() ast.Property { Initializer: initializer, } } - case literal == "get" && self.token != token.COLON: + case (literal == "get" || literal == "set") && self.token != token.COLON: _, _, keyValue, _ := self.parseObjectPropertyKey() + if keyValue == nil { + return nil + } + var kind ast.PropertyKind idx1 := self.idx parameterList := self.parseFunctionParameterList() - if len(parameterList.List) > 0 || parameterList.Rest != nil { - self.error(idx1, "Getter must not have any formal parameters.") - } - node := &ast.FunctionLiteral{ - Function: keyStartIdx, - ParameterList: parameterList, - } - node.Body, node.DeclarationList = self.parseFunctionBlock() - node.Source = self.slice(keyStartIdx, node.Body.Idx1()) - return &ast.PropertyKeyed{ - Key: keyValue, - Kind: ast.PropertyKindGet, - Value: node, + if literal == "get" { + kind = ast.PropertyKindGet + if len(parameterList.List) > 0 || parameterList.Rest != nil { + self.error(idx1, "Getter must not have any formal parameters.") + } + } else { + kind = ast.PropertyKindSet } - case literal == "set" && self.token != token.COLON: - _, _, keyValue, _ := self.parseObjectPropertyKey() - parameterList := self.parseFunctionParameterList() - node := &ast.FunctionLiteral{ Function: keyStartIdx, ParameterList: parameterList, } - node.Body, node.DeclarationList = self.parseFunctionBlock() node.Source = self.slice(keyStartIdx, node.Body.Idx1()) - return &ast.PropertyKeyed{ Key: keyValue, - Kind: ast.PropertyKindSet, + Kind: kind, Value: node, } } } self.expect(token.COLON) - if value != nil { - return &ast.PropertyKeyed{ - Key: value, - Kind: ast.PropertyKindValue, - Value: self.parseAssignmentExpression(), - Computed: tkn == token.ILLEGAL, - } + return &ast.PropertyKeyed{ + Key: value, + Kind: ast.PropertyKindValue, + Value: self.parseAssignmentExpression(), + Computed: tkn == token.ILLEGAL, } - return nil } func (self *_parser) parseObjectLiteral() *ast.ObjectLiteral { diff --git a/vendor/github.com/dop251/goja/runtime.go b/vendor/github.com/dop251/goja/runtime.go index 86a16f13fdf..eace4d61f2f 100644 --- a/vendor/github.com/dop251/goja/runtime.go +++ b/vendor/github.com/dop251/goja/runtime.go @@ -1624,6 +1624,10 @@ Note that the underlying type is not lost, calling Export() returns the original reflect based types. */ func (r *Runtime) ToValue(i interface{}) Value { + return r.toValue(i, reflect.Value{}) +} + +func (r *Runtime) toValue(i interface{}, origValue reflect.Value) Value { switch i := i.(type) { case nil: return _null @@ -1739,7 +1743,18 @@ func (r *Runtime) ToValue(i interface{}) Value { return obj } - origValue := reflect.ValueOf(i) + if !origValue.IsValid() { + origValue = reflect.ValueOf(i) + } else { + // If origValue was a result of an Index(), or Field(), or such, its Kind may be Interface: + // a := []interface{}{(*S)(nil)} + // a0 := reflect.ValueOf(a).Index(0) // a0.Kind() is reflect.Interface + // a1 := reflect.ValueOf(a[0]) // a1.Kind() is reflect.Ptr + // Need to "dereference" it to make it consistent with plain value being passed. + for origValue.Kind() == reflect.Interface { + origValue = origValue.Elem() + } + } value := origValue for value.Kind() == reflect.Ptr { value = reflect.Indirect(value) diff --git a/vendor/github.com/dop251/goja/vm.go b/vendor/github.com/dop251/goja/vm.go index e3901c1e4fc..db0fc051b88 100644 --- a/vendor/github.com/dop251/goja/vm.go +++ b/vendor/github.com/dop251/goja/vm.go @@ -3086,14 +3086,22 @@ func (vm *vm) alreadyDeclared(name unistring.String) Value { func (vm *vm) checkBindVarsGlobal(names []unistring.String) { o := vm.r.globalObject.self sn := vm.r.global.stash.names - if o, ok := o.(*baseObject); ok { + if bo, ok := o.(*baseObject); ok { // shortcut - for _, name := range names { - if !o.hasOwnPropertyStr(name) && !o.extensible { - panic(vm.r.NewTypeError("Cannot define global variable '%s', global object is not extensible", name)) + if bo.extensible { + for _, name := range names { + if _, exists := sn[name]; exists { + panic(vm.alreadyDeclared(name)) + } } - if _, exists := sn[name]; exists { - panic(vm.alreadyDeclared(name)) + } else { + for _, name := range names { + if !bo.hasOwnPropertyStr(name) { + panic(vm.r.NewTypeError("Cannot define global variable '%s', global object is not extensible", name)) + } + if _, exists := sn[name]; exists { + panic(vm.alreadyDeclared(name)) + } } } } else { @@ -3115,10 +3123,10 @@ func (vm *vm) createGlobalVarBindings(names []unistring.String, d bool) { vm.r.global.varNames = globalVarNames } o := vm.r.globalObject.self - if o, ok := o.(*baseObject); ok { + if bo, ok := o.(*baseObject); ok { for _, name := range names { - if !o.hasOwnPropertyStr(name) && o.extensible { - o._putProp(name, _undefined, true, true, d) + if !bo.hasOwnPropertyStr(name) && bo.extensible { + bo._putProp(name, _undefined, true, true, d) } globalVarNames[name] = struct{}{} } diff --git a/vendor/modules.txt b/vendor/modules.txt index 3cd524befe6..7a154fdbbe8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -23,7 +23,7 @@ github.com/davecgh/go-spew/spew ## explicit github.com/dlclark/regexp2 github.com/dlclark/regexp2/syntax -# github.com/dop251/goja v0.0.0-20220324112439-a18ffb9c5866 +# github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf ## explicit; go 1.14 github.com/dop251/goja github.com/dop251/goja/ast