forked from chromedp/chromedp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheval.go
138 lines (120 loc) · 4.26 KB
/
eval.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package chromedp
import (
"context"
"encoding/json"
"reflect"
"github.com/chromedp/cdproto/runtime"
)
// EvaluateAction are actions that evaluate JavaScript expressions using
// runtime.Evaluate.
type EvaluateAction Action
// Evaluate is an action to evaluate the JavaScript expression, unmarshaling
// the result of the script evaluation to res.
//
// When res is nil, the script result will be ignored.
//
// When res is a *[]byte, the raw JSON-encoded value of the script
// result will be placed in res.
//
// When res is a **runtime.RemoteObject, res will be set to the low-level
// protocol type, and no attempt will be made to convert the result.
// The original objects could be maintained in memory until the page is
// navigated or closed. `runtime.ReleaseObject` or `runtime.ReleaseObjectGroup`
// can be used to ask the browser to release the original objects.
//
// For all other cases, the result of the script will be returned "by value" (i.e.,
// JSON-encoded), and subsequently an attempt will be made to json.Unmarshal
// the script result to res. When the script result is "undefined" or "null",
// and the value that res points to is not a pointer, it returns [ErrJSUndefined]
// of [ErrJSNull] respectively.
func Evaluate(expression string, res interface{}, opts ...EvaluateOption) EvaluateAction {
return ActionFunc(func(ctx context.Context) error {
// set up parameters
p := runtime.Evaluate(expression)
switch res.(type) {
case **runtime.RemoteObject:
default:
p = p.WithReturnByValue(true)
}
// apply opts
for _, o := range opts {
p = o(p)
}
// evaluate
v, exp, err := p.Do(ctx)
if err != nil {
return err
}
if exp != nil {
return exp
}
err = parseRemoteObject(v, res)
return err
})
}
func parseRemoteObject(v *runtime.RemoteObject, res interface{}) (err error) {
if res == nil {
return
}
switch x := res.(type) {
case **runtime.RemoteObject:
*x = v
return
case *[]byte:
*x = v.Value
return
}
if v.Type == "undefined" || v.Value == nil {
rv := reflect.ValueOf(res)
// `res` should be a pointer. When the value that `res` points to is
// not a pointer, it can not be nil. In this case,
// return [ErrJSUndefined] or [ErrJSNull] respectively.
if rv.Kind() == reflect.Pointer && rv.Elem().Kind() != reflect.Pointer {
if v.Type == "undefined" {
return ErrJSUndefined
}
return ErrJSNull
}
// Otherwise, change the value to the json literal null.
v.Value = []byte("null")
}
err = json.Unmarshal(v.Value, res)
return
}
// EvaluateAsDevTools is an action that evaluates a JavaScript expression as
// Chrome DevTools would, evaluating the expression in the "console" context,
// and making the Command Line API available to the script.
//
// See [Evaluate] for more information on how script expressions are evaluated.
//
// Note: this should not be used with untrusted JavaScript.
func EvaluateAsDevTools(expression string, res interface{}, opts ...EvaluateOption) EvaluateAction {
return Evaluate(expression, res, append(opts, EvalObjectGroup("console"), EvalWithCommandLineAPI)...)
}
// EvaluateOption is the type for JavaScript evaluation options.
type EvaluateOption = func(*runtime.EvaluateParams) *runtime.EvaluateParams
// EvalObjectGroup is an evaluate option to set the object group.
func EvalObjectGroup(objectGroup string) EvaluateOption {
return func(p *runtime.EvaluateParams) *runtime.EvaluateParams {
return p.WithObjectGroup(objectGroup)
}
}
// EvalWithCommandLineAPI is an evaluate option to make the DevTools Command
// Line API available to the evaluated script.
//
// See [Evaluate] for more information on how evaluate actions work.
//
// Note: this should not be used with untrusted JavaScript.
func EvalWithCommandLineAPI(p *runtime.EvaluateParams) *runtime.EvaluateParams {
return p.WithIncludeCommandLineAPI(true)
}
// EvalIgnoreExceptions is an evaluate option that will cause JavaScript
// evaluation to ignore exceptions.
func EvalIgnoreExceptions(p *runtime.EvaluateParams) *runtime.EvaluateParams {
return p.WithSilent(true)
}
// EvalAsValue is an evaluate option that will cause the evaluated JavaScript
// expression to encode the result of the expression as a JSON-encoded value.
func EvalAsValue(p *runtime.EvaluateParams) *runtime.EvaluateParams {
return p.WithReturnByValue(true)
}