-
-
Notifications
You must be signed in to change notification settings - Fork 13
Feat/structured clone #250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3fbf322
e754d71
4329903
8ca25fc
15ef28f
c86ea8b
38a93d0
f46a284
d52a482
4b99cf4
4acce2d
af3e7ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package htmltest | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/gost-dom/browser/html" | ||
| ) | ||
|
|
||
| type ScriptContextHelper struct { | ||
| html.ScriptContext | ||
| t testing.TB | ||
| } | ||
|
|
||
| func NewScriptContextHelper(t testing.TB, ctx html.ScriptContext) ScriptContextHelper { | ||
| return ScriptContextHelper{ctx, t} | ||
| } | ||
|
|
||
| func (h ScriptContextHelper) MustEval(script string) any { | ||
| h.t.Helper() | ||
| res, err := h.Eval(script) | ||
| if err != nil { | ||
| h.t.Fatalf("Script error: %v", err) | ||
| } | ||
| return res | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package js | ||
|
|
||
| type Array[T any] interface { | ||
| Value[T] | ||
| Push(Value[T]) error | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,12 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package js | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "errors" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/gost-dom/browser/internal/constants" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Value represents a value in JavaScript. Referential equality cannot be used | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // to check if to Value instances represent the same value in JavaScript. Use | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // StrictEquals to check if two values are equal. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -15,6 +22,7 @@ type Value[T any] interface { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self() T | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String() string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Number() float64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Int32() int32 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Uint32() uint32 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Boolean() bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -23,16 +31,24 @@ type Value[T any] interface { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IsNull() bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IsSymbol() bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IsString() bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IsNumber() bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IsObject() bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IsBoolean() bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IsFunction() bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IsArray() bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AsFunction() (Function[T], bool) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AsObject() (Object[T], bool) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StrictEquals(Value[T]) bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // IsNullish returns whether a JavaScript value is null or undefined. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func IsNullish[T any](v Value[T]) bool { return v == nil || v.IsNull() || v.IsUndefined() } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func IsUndefined[T any](v Value[T]) bool { return v == nil || v.IsUndefined() } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func IsBoolean[T any](v Value[T]) bool { return v != nil && v.IsBoolean() } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type Function[T any] interface { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Value[T] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -100,14 +116,108 @@ type Promise[T any] interface { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Reject(Value[T]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // IsNullish returns whether a JavaScript value is null or undefined. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func IsNullish[T any](v Value[T]) bool { return v == nil || v.IsNull() || v.IsUndefined() } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func IsBoolean[T any](v Value[T]) bool { return v != nil && v.IsBoolean() } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func AsFunction[T any](v Value[T]) (Function[T], bool) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if IsNullish(v) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return v.AsFunction() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func Clone[T any](v Value[T], s Scope[T]) (Value[T], error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var objects [][2]Value[T] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return clone(v, s, &objects) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func clone[T any](v Value[T], s Scope[T], objects *[][2]Value[T]) (Value[T], error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| switch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case v == nil || v.IsUndefined(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return s.Undefined(), nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case v.IsNull(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return s.Null(), nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case v.IsUndefined(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return s.Undefined(), nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case v.IsString(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return s.NewString(v.String()), nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case v.IsNumber(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return s.NewNumber(v.Number()), nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case v.IsBoolean(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return s.NewBoolean(v.Boolean()), nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case v.IsArray(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return cloneArray(v, s, objects) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case v.IsFunction(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //TODO: Use correct error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, errors.New("Serialize function") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if o, ok := v.AsObject(); ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return cloneObject(o, s, objects) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("Unable to clone value: %v", v) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+131
to
+155
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Remove the duplicate ♻️ Proposed cleanupcase v == nil || v.IsUndefined():
return s.Undefined(), nil
case v.IsNull():
return s.Null(), nil
-case v.IsUndefined():
- return s.Undefined(), nil📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func findKnownValue[T any](o Value[T], knownObjects *[][2]Value[T]) (Value[T], bool) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, pair := range *knownObjects { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| known := pair[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res := pair[1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if o.StrictEquals(known) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res, true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func cloneArray[T any]( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v Value[T], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| s Scope[T], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| knownObjects *[][2]Value[T], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) (Value[T], error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if existing, ok := findKnownValue(v, knownObjects); ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return existing, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| o, ok := v.AsObject() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Object was an array, but not convertible to object. %w", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| constants.ErrGostDomBug, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res := s.NewArray() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *knownObjects = append(*knownObjects, [2]Value[T]{v, res}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for v, err := range Iterate(o) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cloned, err := clone(v, s, knownObjects) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res.Push(cloned) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO: Potential bug here, if the array references itself recursively, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // this would lead to a stack overflow error. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+196
to
+198
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial TODO comment appears outdated—cycles are already handled. The comment suggests recursive arrays could cause stack overflow, but cycle detection via Consider removing or updating this TODO to reflect the actual behavior. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+168
to
+199
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Search for Iterate function definition
rg -n 'func\s+Iterate' -C 5 --type=go
# Search for Array interface definition
rg -n 'type\s+Array\[' -C 5 --type=go
# Search for Push method
rg -n 'func.*\bPush\b' -C 3 --type=go
# Search for Length method
rg -n 'func.*\bLength\b' -C 3 --type=goRepository: gost-dom/browser Length of output: 4509 🏁 Script executed: #!/bin/bash
# Get the full Iterate function implementation
sed -n '117,140p' scripting/internal/js/object.go
# Also check what happens after line 140 in that function
sed -n '117,170p' scripting/internal/js/object.go
# Look at how Object iteration is handled (for properties/indices)
rg -n 'for.*range.*Object' -C 3 --type=go
# Check v8engine array iteration implementation
cat scripting/v8engine/array.go
# Check sobekengine array implementation
cat scripting/sobekengine/array.goRepository: gost-dom/browser Length of output: 3674 🏁 Script executed: #!/bin/bash
# Search for sparse array handling or tests
rg -i 'sparse' --type=go
# Search for structured-clone references
rg -i 'structured.*clone|clone.*structured' --type=go
# Look at the full clone function to understand the context
sed -n '140,200p' scripting/internal/js/value.go
# Search for any tests related to cloning
fd -e test.go -o -e _test.go | xargs rg -l 'clone|Clone' | head -5Repository: gost-dom/browser Length of output: 2133 🏁 Script executed: #!/bin/bash
# Search for array length access or index-based methods
rg -n '\.Length\(\)|\.Get.*\[|for.*i.*<.*Length' -C 2 --type=go | head -50
# Look for tests directory and check for array cloning tests
find . -type f -name '*test*.go' | xargs rg -l 'clone.*[Aa]rray|[Aa]rray.*clone' 2>/dev/null
# Check for any Get(index) or SetIndex methods on Array
rg -n 'func.*\(.*Array\).*Get|func.*\(.*Array\).*SetIndex' -C 2 --type=go
# Search for how array indices are accessed in the codebase
rg -n 'Get.*\(\s*[0-9]' -C 2 --type=go | head -30Repository: gost-dom/browser Length of output: 4134 🏁 Script executed: #!/bin/bash
# Let's verify JavaScript array iterator behavior with sparse arrays
# Search for any documentation or comments about array iteration and sparse arrays
rg -i 'hole|sparse|empty.*slot|undefined.*index' -C 3 --type=go
# Check if there are any tests that demonstrate array cloning behavior
fd '.*test.*\.go$' | xargs grep -l 'cloneArray\|clone.*Array' 2>/dev/null
# Look at the complete clone function signature and how cloneObject handles this
sed -n '140,220p' scripting/internal/js/value.go
# Search for reference to structured clone spec
rg -n 'spec|standard|algorithm' -i --type=go | grep -i cloneRepository: gost-dom/browser Length of output: 4926 🏁 Script executed: #!/bin/bash
# Check if there's an Array.length getter/setter or any length preservation
rg -n 'func.*Length|\.length|array\.length' -i -C 2 --type=go | head -50
# Search for array iteration tests or examples
find . -type f -name '*.go' | xargs grep -l 'Iterate.*array\|array.*Iterate' 2>/dev/null
# Check how NewArray is created and if it has any special properties
rg -n 'NewArray\(\)' -C 5 --type=go
# Look for any references to array.length preservation
rg -n 'Length.*array|array.*Length' -i -C 3 --type=go | grep -i 'set\|prop\|clone' | head -20
# Check the v8engine and sobekengine implementations of array length
rg -n 'func.*\(.*array\).*Length|func.*Length.*\(.*array' -C 3 --type=goRepository: gost-dom/browser Length of output: 3547 🏁 Script executed: #!/bin/bash
# Check if array length is set after cloning
sed -n '168,210p' scripting/internal/js/value.go
# Search for any special array handling after iteration
rg -n 'res\.(Push|Set.*length|Length)' -C 3 --type=go
# Look for how arrays are created and if length is preserved
rg -n 'NewArray' -C 8 --type=go | head -60
# Check if there's any reference to JavaScript array length property
rg -n '\.Get\s*\(\s*"length"' -C 2 --type=go
# Check what the Iterate function returns for sparse arrays specifically
# by looking at how Symbol.iterator is handled
rg -n 'Symbol.*iterator|Symbol\.iterator' -i -C 3 --type=goRepository: gost-dom/browser Length of output: 12689 🏁 Script executed: #!/bin/bash
# Let's verify the actual behavior with a comprehensive search
# Check if array.length is accessed anywhere after cloning
rg -n 'Get.*"length"|Get.*length' -C 5 --type=go | grep -A 5 -B 5 clone
# Check how v8engine's NewArray works - does it handle sparse arrays?
sed -n '200,220p' scripting/v8engine/callback_context.go
# Check if there's any code that reads array.length property
rg -n '\.Get\s*\(\s*"length"\s*\)' -C 3 --type=go
# Look for any tests that verify cloning behavior
fd '.*test.*\.go$' -exec grep -l 'structuredClone\|clone.*array\|sparse' {} \;
# Check if Iterate behavior is documented anywhere
rg -n 'Iterate' -B 5 -A 10 scripting/internal/js/object.go | head -80Repository: gost-dom/browser Length of output: 2429 🏁 Script executed: #!/bin/bash
# Search for any clone tests or sparse array tests
find . -type f -name '*test.go' | head -10 | xargs grep -l 'clone\|Clone' 2>/dev/null
# Look for structured clone in tests
find . -type f -name '*test.go' -exec grep -l 'structuredClone' {} \;
# Check if there are any array cloning tests
find . -type f -name '*test.go' -exec grep -l 'Array\|array' {} \; | xargs grep -l 'clone' 2>/dev/null
# Verify: does Iterate call the array's Symbol.iterator which should iterate all indices?
# Let's check ObjectGetIterator
rg -n 'func ObjectGetIterator' -A 15 --type=go
# Most importantly: after cloning with Push, is the array.length set correctly?
# Let's search for any length assignment or restoration
rg -n 'res\.(length|Length|Set.*length)' -C 3 --type=goRepository: gost-dom/browser Length of output: 1120 🏁 Script executed: #!/bin/bash
# Let's check what the actual behavior of Iterate is for sparse arrays
# by looking at the ObjectEnumerableOwnPropertyKeys which seems related
rg -n 'ObjectEnumerableOwnPropertyKeys|ObjectOwnPropertyKeys' -A 20 --type=go
# Check PropertyDescriptor to understand enumerable property handling
rg -n 'type PropertyDescriptor' -A 10 --type=go
# See how keys/indices are enumerated in ObjectEnumerableOwnPropertyKeys
sed -n '200,250p' scripting/internal/js/object.go
# Check if array length is being preserved after cloning anywhere
rg -n 'array.*length|length.*array' -i -C 3 --type=go | grep -i 'clone\|set'Repository: gost-dom/browser Length of output: 4696 🏁 Script executed: #!/bin/bash
# Critical check: does the cloneArray function preserve array length?
# Let's look at the full function and what comes after the Push loop
sed -n '168,210p' scripting/internal/js/value.go
# Check if there's any array.length reading or restoration after cloning
rg -n 'v\.Get\("length"\)|o\.Get\("length"' -C 5 --type=go | grep -A 10 -B 10 clone
# Verify what JavaScript's Array iterator actually does
# Let's search for any documentation or comments about this
rg -n 'Array.*iterator|iterator.*Array' -i -C 3 --type=go
# Most importantly - check if after cloning, the array length is set
sed -n '168,200p' scripting/internal/js/value.goRepository: gost-dom/browser Length of output: 1874 🏁 Script executed: #!/bin/bash
# The key question: does JavaScript's Array iterator skip holes or yield them as undefined?
# Let's search for documentation or tests that clarify this
rg -n 'Symbol\.iterator|iterator.*hole|hole.*iterator' -i -C 3 --type=go
# Check if there's any use of array indices (0, 1, 2...) vs just using iterator protocol
rg -n 'for.*i.*:=.*0.*i.*<|Get.*[0-9]|Get.*i|SetIndex|GetIndex' -C 2 --type=go | head -60
# Look for cloning tests to see if sparse arrays are tested
find . -type f -name '*.go' -path '*/test*' -o -name '*_test.go' | xargs grep -l 'Clone\|clone' 2>/dev/null | head -5
# Check how other code handles array length preservation
rg -n '\.Get.*length|\.Set.*length' -C 2 --type=go | grep -i arrayRepository: gost-dom/browser Length of output: 8797 🏁 Script executed: #!/bin/bash
# Critical verification: Check if array.length is being accessed or preserved
# during or after cloning
rg -n 'v\.Get\("length"\)|o\.Get\("length"\)|Get.*Length' -C 8 --type=go | grep -B 8 -A 8 'cloneArray\|clone'
# Look specifically at what happens after the cloneArray function
sed -n '168,210p' scripting/internal/js/value.go
# Check if the original array's length is ever read
rg -n 'Get.*"length"|Get.*Length' scripting/internal/js/value.go
# Let's verify the exact behavior by checking what Iterate does
# Get the complete Iterate implementation
sed -n '117,170p' scripting/internal/js/object.goRepository: gost-dom/browser Length of output: 2238 Preserve sparse array structure during cloning. The Consider reading the original array's length property and preserving array structure through index-based cloning rather than relying on the iterator protocol, or ensure all hole handling aligns with the structured-clone algorithm. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func cloneObject[T any](o Object[T], s Scope[T], knownObjects *[][2]Value[T]) (Value[T], error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if existing, ok := findKnownValue(o, knownObjects); ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return existing, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res := s.NewObject() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *knownObjects = append(*knownObjects, [2]Value[T]{o, res}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| keys, err := o.Keys() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, k := range keys { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| oldV, err := o.Get(k) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| newV, err := clone(oldV, s, knownObjects) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res.Set(k, newV) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,96 @@ | ||||||||||||||||||||||||||||||||||||||||||||
| package scripttests | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||||||||||||||||||
| "testing" | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| "github.com/gost-dom/browser/html" | ||||||||||||||||||||||||||||||||||||||||||||
| "github.com/gost-dom/browser/internal/entity" | ||||||||||||||||||||||||||||||||||||||||||||
| "github.com/gost-dom/browser/internal/testing/htmltest" | ||||||||||||||||||||||||||||||||||||||||||||
| "github.com/gost-dom/browser/scripting/internal/js" | ||||||||||||||||||||||||||||||||||||||||||||
| "github.com/stretchr/testify/assert" | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // RunScriptEngineSuites runs test suites of the script engine without a | ||||||||||||||||||||||||||||||||||||||||||||
| // predefined global scope. In contrast to [RunSuites] that expect an engine | ||||||||||||||||||||||||||||||||||||||||||||
| // configured for the global scope in the Window realm. | ||||||||||||||||||||||||||||||||||||||||||||
| func RunScriptEngineSuites[T any](t *testing.T, f ScriptEngineFactory[T]) { | ||||||||||||||||||||||||||||||||||||||||||||
| type Global = entity.Entity | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| e := f(js.ConfigurerFunc[T](func(e js.ScriptEngine[T]) { | ||||||||||||||||||||||||||||||||||||||||||||
| global := e.ConfigureGlobalScope("Global", nil) | ||||||||||||||||||||||||||||||||||||||||||||
| global.CreateOperation("store", func(ctx js.CallbackContext[T]) (js.Value[T], error) { | ||||||||||||||||||||||||||||||||||||||||||||
| v, ok := ctx.ConsumeArg() | ||||||||||||||||||||||||||||||||||||||||||||
| if !ok { | ||||||||||||||||||||||||||||||||||||||||||||
| return nil, ctx.NewTypeError("Missing argument") | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| c, err := js.As[entity.Components](ctx.GlobalThis().NativeValue(), nil) | ||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| entity.SetComponentType(c, v) | ||||||||||||||||||||||||||||||||||||||||||||
| return nil, nil | ||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+22
to
+33
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard against nil js.Value from ConsumeArg. ConsumeArg can yield a nil 🛠️ Proposed fix- global.CreateOperation("store", func(ctx js.CallbackContext[T]) (js.Value[T], error) {
- v, ok := ctx.ConsumeArg()
- if !ok {
- return nil, ctx.NewTypeError("Missing argument")
- }
+ global.CreateOperation("store", func(ctx js.CallbackContext[T]) (js.Value[T], error) {
+ v, ok := ctx.ConsumeArg()
+ if !ok || v == nil {
+ return nil, ctx.NewTypeError("Missing argument")
+ }
c, err := js.As[entity.Components](ctx.GlobalThis().NativeValue(), nil)
if err != nil {
return nil, err
}Based on learnings: In the gost-dom JavaScript binding system, |
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| global.CreateOperation("get", func(ctx js.CallbackContext[T]) (js.Value[T], error) { | ||||||||||||||||||||||||||||||||||||||||||||
| c, err := js.As[entity.Components](ctx.GlobalThis().NativeValue(), nil) | ||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| val, ok := entity.ComponentType[js.Value[T]](c) | ||||||||||||||||||||||||||||||||||||||||||||
| if !ok { | ||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("Value missing") | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| res, err := js.Clone(val, ctx) | ||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||
| t.Errorf("Clone error: %v", err) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| return res, err | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+45
to
+49
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Return early on clone error to avoid returning partial results. Line 47 logs the error with ♻️ Proposed fix res, err := js.Clone(val, ctx)
if err != nil {
- t.Errorf("Clone error: %v", err)
+ return nil, fmt.Errorf("Clone error: %w", err)
}
return res, errOr if you want to log and return: res, err := js.Clone(val, ctx)
if err != nil {
t.Errorf("Clone error: %v", err)
+ return nil, err
}
- return res, err
+ return res, nil📝 Committable suggestion
Suggested change
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||
| })) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| global1 := new(Global) | ||||||||||||||||||||||||||||||||||||||||||||
| global2 := new(Global) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| c1 := htmltest.NewScriptContextHelper( | ||||||||||||||||||||||||||||||||||||||||||||
| t, | ||||||||||||||||||||||||||||||||||||||||||||
| e.NewHost(html.ScriptEngineOptions{}).NewContext(dummyContext{global1, t.Context()}), | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| c2 := htmltest.NewScriptContextHelper( | ||||||||||||||||||||||||||||||||||||||||||||
| t, | ||||||||||||||||||||||||||||||||||||||||||||
| e.NewHost(html.ScriptEngineOptions{}).NewContext(dummyContext{global2, t.Context()}), | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| assert.NoError(t, c1.Run(` | ||||||||||||||||||||||||||||||||||||||||||||
| const b = { | ||||||||||||||||||||||||||||||||||||||||||||
| id: "b", | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| const arr = [1,2,3] | ||||||||||||||||||||||||||||||||||||||||||||
| const recursiveArray = [1,2,3] | ||||||||||||||||||||||||||||||||||||||||||||
| recursiveArray.push(recursiveArray) | ||||||||||||||||||||||||||||||||||||||||||||
| const a = { | ||||||||||||||||||||||||||||||||||||||||||||
| stringVal: "hello", | ||||||||||||||||||||||||||||||||||||||||||||
| numberVal: 42.5, | ||||||||||||||||||||||||||||||||||||||||||||
| trueVal: true, | ||||||||||||||||||||||||||||||||||||||||||||
| falseVal: false, | ||||||||||||||||||||||||||||||||||||||||||||
| b1: b, | ||||||||||||||||||||||||||||||||||||||||||||
| b2: b, | ||||||||||||||||||||||||||||||||||||||||||||
| arr1: arr, | ||||||||||||||||||||||||||||||||||||||||||||
| arr2: arr, | ||||||||||||||||||||||||||||||||||||||||||||
| recursiveArray, | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| globalThis.store(a) | ||||||||||||||||||||||||||||||||||||||||||||
| `)) | ||||||||||||||||||||||||||||||||||||||||||||
| val, ok := entity.ComponentType[js.Value[T]](global1) | ||||||||||||||||||||||||||||||||||||||||||||
| assert.True(t, ok) | ||||||||||||||||||||||||||||||||||||||||||||
| entity.SetComponentType(global2, val) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| assert.NoError(t, c2.Run("const cloned = globalThis.get()")) | ||||||||||||||||||||||||||||||||||||||||||||
| assert.Equal(t, "hello", c2.MustEval("cloned.stringVal")) | ||||||||||||||||||||||||||||||||||||||||||||
| assert.Equal(t, 42.5, c2.MustEval("cloned.numberVal")) | ||||||||||||||||||||||||||||||||||||||||||||
| assert.True(t, c2.MustEval("cloned.trueVal").(bool)) | ||||||||||||||||||||||||||||||||||||||||||||
| assert.False(t, c2.MustEval("cloned.falseVal").(bool)) | ||||||||||||||||||||||||||||||||||||||||||||
| assert.True(t, c2.MustEval("cloned.b1 === cloned.b2").(bool)) | ||||||||||||||||||||||||||||||||||||||||||||
| assert.Equal(t, "1,2,3", c2.MustEval("cloned.arr1.join(',')")) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,17 @@ | ||
| package scripttests | ||
|
|
||
| import ( | ||
| "context" | ||
| "log/slog" | ||
| "net/http" | ||
| "testing" | ||
|
|
||
| "github.com/gost-dom/browser/html" | ||
| "github.com/gost-dom/browser/internal/entity" | ||
| "github.com/gost-dom/browser/internal/testing/browsertest" | ||
| "github.com/gost-dom/browser/scripting/internal/dom/domsuite" | ||
| "github.com/gost-dom/browser/scripting/internal/html/htmlsuite" | ||
| "github.com/gost-dom/browser/scripting/internal/js" | ||
| "github.com/gost-dom/browser/scripting/internal/uievents/uieventssuite" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/suite" | ||
|
|
@@ -28,9 +33,11 @@ func RunBasicSuite(t *testing.T, e html.ScriptEngine) { | |
| assert.True(t, w.MustEval("window === globalThis").(bool)) | ||
| } | ||
|
|
||
| type ScriptEngineFactory[T any] = func(js.Configurer[T]) html.ScriptEngine | ||
|
|
||
| func RunSuites(t *testing.T, e html.ScriptEngine) { | ||
| t.Run("ScriptEngineBehaviour", func(t *testing.T) { testScriptEngineBehaviour(t, e) }) | ||
| t.Run("SharowRoot", runSuite(NewShadowRootSuite(e))) | ||
| t.Run("ShadowRoot", runSuite(NewShadowRootSuite(e))) | ||
| t.Run("DocumentFragment", runSuite(NewDocumentFragmentSuite(e))) | ||
| t.Run("XMLHttpRequest", runSuite(NewXMLHttpRequestSuite(e))) | ||
| t.Run("Location", runSuite(NewLocationSuite(e))) | ||
|
|
@@ -58,3 +65,13 @@ func RunSuites(t *testing.T, e html.ScriptEngine) { | |
| t.Run("html", func(t *testing.T) { htmlsuite.RunHtmlSuite(t, e) }) | ||
| t.Run("dom", func(t *testing.T) { domsuite.RunDomSuite(t, e) }) | ||
| } | ||
|
|
||
| type dummyContext struct { | ||
| *entity.Entity | ||
| ctx context.Context | ||
| } | ||
|
|
||
| func (c dummyContext) Context() context.Context { return c.ctx } | ||
| func (c dummyContext) HTTPClient() http.Client { return *http.DefaultClient } | ||
| func (c dummyContext) LocationHREF() string { return "http://example.com" } | ||
| func (c dummyContext) Logger() *slog.Logger { return nil } | ||
|
Comment on lines
+69
to
+77
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: rg -nC3 '\.Logger\(\)' --type=go | head -100Repository: gost-dom/browser Length of output: 5411 🏁 Script executed: rg -nC3 'dummyContext' --type=goRepository: gost-dom/browser Length of output: 2982 🏁 Script executed: rg -nC5 'func.*NewContext' --type=go | head -60Repository: gost-dom/browser Length of output: 2232 🏁 Script executed: rg -n 'console\.' scripting/internal/scripttests/ --type=go | head -20Repository: gost-dom/browser Length of output: 167 Return a no-op logger instead of nil from Logger().
🛡️ Proposed fix using slog's default or discard handler-func (c dummyContext) Logger() *slog.Logger { return nil }
+func (c dummyContext) Logger() *slog.Logger { return slog.New(slog.DiscardHandler) }Alternatively, if func (c dummyContext) Logger() *slog.Logger { return slog.Default() } |
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,31 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package sobekengine | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "errors" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/grafana/sobek" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type array struct { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| obj *sobek.Object | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func newArray(c *scriptContext, o *sobek.Object) jsArray { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return array{value{c, o}, o} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func (a array) Push(v jsValue) error { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| push := a.obj.Get("push") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if push == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return errors.New("gost-dom/sobekengine: array.push: Underlying object doesn't have a push") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| p, ok := sobek.AssertFunction(push) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return errors.New( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "gost-dom/sobekengine: array.push: Underlying object's push is not a function", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _, err := p(a.obj, v.Self().value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+18
to
+31
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard against nil value in If 🛡️ Proposed fix func (a array) Push(v jsValue) error {
+ if v == nil {
+ return errors.New("gost-dom/sobekengine: array.push: Cannot push nil value")
+ }
push := a.obj.Get("push")
if push == nil {
return errors.New("gost-dom/sobekengine: array.push: Underlying object doesn't have a push")Alternatively, if pushing func (a array) Push(v jsValue) error {
push := a.obj.Get("push")
if push == nil {
return errors.New("gost-dom/sobekengine: array.push: Underlying object doesn't have a push")
}
p, ok := sobek.AssertFunction(push)
if !ok {
return errors.New(
"gost-dom/sobekengine: array.push: Underlying object's push is not a function",
)
}
- _, err := p(a.obj, v.Self().value)
+ var arg sobek.Value
+ if v != nil {
+ arg = v.Self().value
+ }
+ _, err := p(a.obj, arg)
return err
}Based on learnings: In the gost-dom JavaScript binding system, 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.