dt_automate/vendor/github.com/playwright-community/playwright-go/js_handle.go
2025-02-19 18:30:19 +08:00

347 lines
7.2 KiB
Go

package playwright
import (
"errors"
"fmt"
"math"
"math/big"
"net/url"
"reflect"
"time"
)
type jsHandleImpl struct {
channelOwner
preview string
}
func (j *jsHandleImpl) Evaluate(expression string, options ...interface{}) (interface{}, error) {
var arg interface{}
if len(options) == 1 {
arg = options[0]
}
result, err := j.channel.Send("evaluateExpression", map[string]interface{}{
"expression": expression,
"arg": serializeArgument(arg),
})
if err != nil {
return nil, err
}
return parseResult(result), nil
}
func (j *jsHandleImpl) EvaluateHandle(expression string, options ...interface{}) (JSHandle, error) {
var arg interface{}
if len(options) == 1 {
arg = options[0]
}
result, err := j.channel.Send("evaluateExpressionHandle", map[string]interface{}{
"expression": expression,
"arg": serializeArgument(arg),
})
if err != nil {
return nil, err
}
channelOwner := fromChannel(result)
if channelOwner == nil {
return nil, nil
}
return channelOwner.(*jsHandleImpl), nil
}
func (j *jsHandleImpl) GetProperty(name string) (JSHandle, error) {
channel, err := j.channel.Send("getProperty", map[string]interface{}{
"name": name,
})
if err != nil {
return nil, err
}
return fromChannel(channel).(*jsHandleImpl), nil
}
func (j *jsHandleImpl) GetProperties() (map[string]JSHandle, error) {
properties, err := j.channel.Send("getPropertyList")
if err != nil {
return nil, err
}
propertiesMap := make(map[string]JSHandle)
for _, property := range properties.([]interface{}) {
item := property.(map[string]interface{})
propertiesMap[item["name"].(string)] = fromChannel(item["value"]).(*jsHandleImpl)
}
return propertiesMap, nil
}
func (j *jsHandleImpl) AsElement() ElementHandle {
return nil
}
func (j *jsHandleImpl) Dispose() error {
_, err := j.channel.Send("dispose")
if errors.Is(err, ErrTargetClosed) {
return nil
}
return err
}
func (j *jsHandleImpl) String() string {
return j.preview
}
func (j *jsHandleImpl) JSONValue() (interface{}, error) {
v, err := j.channel.Send("jsonValue")
if err != nil {
return nil, err
}
return parseResult(v), nil
}
func parseValue(result interface{}, refs map[float64]interface{}) interface{} {
vMap, ok := result.(map[string]interface{})
if !ok {
return result
}
if v, ok := vMap["n"]; ok {
if math.Ceil(v.(float64))-v.(float64) == 0 {
return int(v.(float64))
}
return v.(float64)
}
if v, ok := vMap["u"]; ok {
u, _ := url.Parse(v.(string))
return u
}
if v, ok := vMap["bi"]; ok {
n := new(big.Int)
n.SetString(v.(string), 0)
return n
}
if v, ok := vMap["ref"]; ok {
if vV, ok := refs[v.(float64)]; ok {
return vV
}
return nil
}
if v, ok := vMap["s"]; ok {
return v.(string)
}
if v, ok := vMap["b"]; ok {
return v.(bool)
}
if v, ok := vMap["v"]; ok {
if v == "undefined" || v == "null" {
return nil
}
if v == "NaN" {
return math.NaN()
}
if v == "Infinity" {
return math.Inf(1)
}
if v == "-Infinity" {
return math.Inf(-1)
}
if v == "-0" {
return math.Copysign(0, -1)
}
return v
}
if v, ok := vMap["d"]; ok {
t, _ := time.Parse(time.RFC3339Nano, v.(string))
return t
}
if v, ok := vMap["a"]; ok {
aV := v.([]interface{})
refs[vMap["id"].(float64)] = aV
for i := range aV {
aV[i] = parseValue(aV[i], refs)
}
return aV
}
if v, ok := vMap["o"]; ok {
aV := v.([]interface{})
out := map[string]interface{}{}
refs[vMap["id"].(float64)] = out
for key := range aV {
entry := aV[key].(map[string]interface{})
out[entry["k"].(string)] = parseValue(entry["v"], refs)
}
return out
}
if v, ok := vMap["e"]; ok {
return parseError(Error{
Name: v.(map[string]interface{})["n"].(string),
Message: v.(map[string]interface{})["m"].(string),
Stack: v.(map[string]interface{})["s"].(string),
})
}
panic(fmt.Errorf("Unexpected value: %v", vMap))
}
func serializeValue(value interface{}, handles *[]*channel, depth int) interface{} {
if handle, ok := value.(*elementHandleImpl); ok {
h := len(*handles)
*handles = append(*handles, handle.channel)
return map[string]interface{}{
"h": h,
}
}
if handle, ok := value.(*jsHandleImpl); ok {
h := len(*handles)
*handles = append(*handles, handle.channel)
return map[string]interface{}{
"h": h,
}
}
if u, ok := value.(*url.URL); ok {
return map[string]interface{}{
"u": u.String(),
}
}
if err, ok := value.(error); ok {
var e *Error
if errors.As(err, &e) {
return map[string]interface{}{
"e": map[string]interface{}{
"n": e.Name,
"m": e.Message,
"s": e.Stack,
},
}
}
return map[string]interface{}{
"e": map[string]interface{}{
"n": "",
"m": err.Error(),
"s": "",
},
}
}
if depth > 100 {
panic(errors.New("Maximum argument depth exceeded"))
}
if value == nil {
return map[string]interface{}{
"v": "undefined",
}
}
if n, ok := value.(*big.Int); ok {
return map[string]interface{}{
"bi": n.String(),
}
}
switch v := value.(type) {
case time.Time:
return map[string]interface{}{
"d": v.Format(time.RFC3339Nano),
}
case int:
return map[string]interface{}{
"n": v,
}
case string:
return map[string]interface{}{
"s": v,
}
case bool:
return map[string]interface{}{
"b": v,
}
}
refV := reflect.ValueOf(value)
switch refV.Kind() {
case reflect.Float32, reflect.Float64:
floatV := refV.Float()
if math.IsInf(floatV, 1) {
return map[string]interface{}{
"v": "Infinity",
}
}
if math.IsInf(floatV, -1) {
return map[string]interface{}{
"v": "-Infinity",
}
}
// https://github.com/golang/go/issues/2196
if floatV == math.Copysign(0, -1) {
return map[string]interface{}{
"v": "-0",
}
}
if math.IsNaN(floatV) {
return map[string]interface{}{
"v": "NaN",
}
}
return map[string]interface{}{
"n": floatV,
}
case reflect.Slice:
aV := make([]interface{}, refV.Len())
for i := 0; i < refV.Len(); i++ {
aV[i] = serializeValue(refV.Index(i).Interface(), handles, depth+1)
}
return map[string]interface{}{
"a": aV,
}
case reflect.Map:
out := []interface{}{}
vM := value.(map[string]interface{})
for key := range vM {
v := serializeValue(vM[key], handles, depth+1)
// had key, so convert "undefined" to "null"
if reflect.DeepEqual(v, map[string]interface{}{
"v": "undefined",
}) {
v = map[string]interface{}{
"v": "null",
}
}
out = append(out, map[string]interface{}{
"k": key,
"v": v,
})
}
return map[string]interface{}{
"o": out,
}
}
return map[string]interface{}{
"v": "undefined",
}
}
func parseResult(result interface{}) interface{} {
return parseValue(result, map[float64]interface{}{})
}
func serializeArgument(arg interface{}) interface{} {
handles := []*channel{}
value := serializeValue(arg, &handles, 0)
return map[string]interface{}{
"value": value,
"handles": handles,
}
}
func newJSHandle(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *jsHandleImpl {
bt := &jsHandleImpl{
preview: initializer["preview"].(string),
}
bt.createChannelOwner(bt, parent, objectType, guid, initializer)
bt.channel.On("previewUpdated", func(ev map[string]interface{}) {
bt.preview = ev["preview"].(string)
})
return bt
}