1
0
mirror of https://github.com/MontFerret/ferret.git synced 2025-07-03 00:46:51 +02:00
Files
ferret/pkg/drivers/cdp/eval/function.go
Tim Voronov 90427cd537 Feature/new selector type (#657)
* Added remote type reference resolver

* Added support of XPath query selector

* Added CDP e2e testss covering XPath integration

* Added additional CDP e2e tests covering XPath integration

* Added type check to QuerySelector casting function

* Fixed XPath e2e tests

* Fixed vuln issue

* Added support of XPath selectors to http driver

* Added e2e tests for XPAth
2021-09-16 21:40:20 -04:00

169 lines
2.9 KiB
Go

package eval
import (
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/mafredri/cdp/protocol/runtime"
"github.com/rs/zerolog"
"github.com/wI2L/jettison"
"strings"
)
type (
FunctionReturnType int
FunctionArguments []runtime.CallArgument
Function struct {
exp string
ownerID runtime.RemoteObjectID
args FunctionArguments
returnType FunctionReturnType
async bool
}
)
const defaultArgsCount = 5
const (
ReturnNothing FunctionReturnType = iota
ReturnValue
ReturnRef
)
func F(exp string) *Function {
op := new(Function)
op.exp = exp
op.returnType = ReturnNothing
return op
}
func (fn *Function) AsPartOf(id runtime.RemoteObjectID) *Function {
fn.ownerID = id
return fn
}
func (fn *Function) AsAsync() *Function {
fn.async = true
return fn
}
func (fn *Function) AsSync() *Function {
fn.async = false
return fn
}
func (fn *Function) WithArgRef(id runtime.RemoteObjectID) *Function {
return fn.withArg(runtime.CallArgument{
ObjectID: &id,
})
}
func (fn *Function) WithArgValue(value core.Value) *Function {
raw, err := value.MarshalJSON()
if err != nil {
panic(err)
}
return fn.withArg(runtime.CallArgument{
Value: raw,
})
}
func (fn *Function) WithArgSelector(selector drivers.QuerySelector) *Function {
return fn.WithArg(selector.String())
}
func (fn *Function) WithArg(value interface{}) *Function {
raw, err := jettison.MarshalOpts(value, jettison.NoHTMLEscaping())
if err != nil {
panic(err)
}
return fn.withArg(runtime.CallArgument{
Value: raw,
})
}
func (fn *Function) String() string {
return fn.exp
}
func (fn *Function) returnRef() *Function {
fn.returnType = ReturnRef
return fn
}
func (fn *Function) returnValue() *Function {
fn.returnType = ReturnValue
return fn
}
func (fn *Function) withArg(arg runtime.CallArgument) *Function {
if fn.args == nil {
fn.args = make([]runtime.CallArgument, 0, defaultArgsCount)
}
fn.args = append(fn.args, arg)
return fn
}
func (fn *Function) build(ctx runtime.ExecutionContextID) *runtime.CallFunctionOnArgs {
exp := strings.TrimSpace(fn.exp)
if !strings.HasPrefix(exp, "(") && !strings.HasPrefix(exp, "function") {
exp = wrapExp(exp, len(fn.args))
}
call := runtime.NewCallFunctionOnArgs(exp).
SetAwaitPromise(fn.async)
if fn.returnType == ReturnValue {
call.SetReturnByValue(true)
}
if ctx != EmptyExecutionContextID {
call.SetExecutionContextID(ctx)
}
if fn.ownerID != "" {
call.SetObjectID(fn.ownerID)
}
if len(fn.args) > 0 {
call.SetArguments(fn.args)
}
return call
}
func (rt FunctionReturnType) String() string {
switch rt {
case ReturnValue:
return "value"
case ReturnRef:
return "reference"
default:
return "nothing"
}
}
func (args FunctionArguments) MarshalZerologArray(a *zerolog.Array) {
for _, arg := range args {
if arg.ObjectID != nil {
a.Str(string(*arg.ObjectID))
} else {
a.RawJSON(arg.Value)
}
}
}