{% import ( "github.com/knq/chromedp/cmd/chromedp-gen/internal" ) %} // ExtraTimestampTemplate is a special template for the Timestamp type that // defines its JSON unmarshaling. {% func ExtraTimestampTemplate(t *internal.Type, d *internal.Domain) %}{%code typ := t.IdOrName() %} // MarshalEasyJSON satisfies easyjson.Marshaler. func (t {%s= typ %}) MarshalEasyJSON(out *jwriter.Writer) { out.Float64(float64(time.Time(t).Sub(sysutil.BootTime()))/float64(time.Second)) } // MarshalJSON satisfies json.Marshaler. func (t {%s= typ %}) MarshalJSON() ([]byte, error) { return easyjson.Marshal(t) } // UnmarshalEasyJSON satisfies easyjson.Unmarshaler. func (t *{%s= typ %}) UnmarshalEasyJSON(in *jlexer.Lexer) { *t = {%s= typ %}(sysutil.BootTime().Add(time.Duration(in.Float64()*float64(time.Second)))) } // UnmarshalJSON satisfies json.Unmarshaler. func (t *{%s= typ %}) UnmarshalJSON(buf []byte) error { return easyjson.Unmarshal(buf, t) } {% endfunc %} // ExtraFrameTemplate is a special template for the Page.Frame type, adding FrameState. {% func ExtraFrameTemplate() %} // FrameState is the state of a Frame. type FrameState uint16 // FrameState enum values. const ( FrameDOMContentEventFired FrameState = 1 << (15 - iota) FrameLoadEventFired FrameAttached FrameNavigated FrameLoading FrameScheduledNavigation ) // frameStateNames are the names of the frame states. var frameStateNames = map[FrameState]string{ FrameDOMContentEventFired: "DOMContentEventFired", FrameLoadEventFired: "LoadEventFired", FrameAttached: "Attached", FrameNavigated: "Navigated", FrameLoading: "Loading", FrameScheduledNavigation: "ScheduledNavigation", } // String satisfies stringer interface. func (fs FrameState) String() string { var s []string for k, v := range frameStateNames { if fs&k != 0 { s = append(s, v) } } return "[" + strings.Join(s, " ") + "]" } {% endfunc %} // ExtraNodeTemplate is a special template for the DOM.Node type, adding NodeState. {% func ExtraNodeTemplate() %} // AttributeValue returns the named attribute for the node. func (n *Node) AttributeValue(name string) string { n.RLock() defer n.RUnlock() for i := 0; i < len(n.Attributes); i+=2 { if n.Attributes[i] == name { return n.Attributes[i+1] } } return "" } // xpath builds the xpath string. func (n *Node) xpath(stopAtDocument, stopAtID bool) string { p := "" pos := "" id := n.AttributeValue("id") switch { case n.Parent == nil: return n.LocalName case stopAtDocument && n.NodeType == NodeTypeDocument: return "" case stopAtID && id != "": p = "/" pos = `[@id='`+id+`']` case n.Parent != nil: i := 0 var found bool for j := 0; j < len(n.Parent.Children); j++ { if n.Parent.Children[j].LocalName == n.LocalName { i++ } if n.Parent.Children[j].NodeID == n.NodeID { found = true break } } p = n.Parent.xpath(stopAtDocument, stopAtID) if found { pos = "["+strconv.Itoa(i)+"]" } } return p + "/" + n.LocalName + pos } // PartialXPathByID returns the partial XPath for the node, stopping at the // first parent with an id attribute or at nearest parent document node. func (n *Node) PartialXPathByID() string { return n.xpath(true, true) } // PartialXPath returns the partial XPath for the node, stopping at the nearest // parent document node. func (n *Node) PartialXPath() string { return n.xpath(true, false) } // FullXPathByID returns the full XPath for the node, stopping at the top most // document root or at the closest parent node with an id attribute. func (n *Node) FullXPathByID() string { return n.xpath(false, true) } // FullXPath returns the full XPath for the node, stopping only at the top most // document root. func (n *Node) FullXPath() string { return n.xpath(false, false) } // NodeState is the state of a DOM node. type NodeState uint8 // NodeState enum values. const ( NodeReady NodeState = 1 << (7 - iota) NodeVisible NodeHighlighted ) // nodeStateNames are the names of the node states. var nodeStateNames = map[NodeState]string{ NodeReady: "Ready", NodeVisible: "Visible", NodeHighlighted: "Highlighted", } // String satisfies stringer interface. func (ns NodeState) String() string { var s []string for k, v := range nodeStateNames { if ns&k != 0 { s = append(s, v) } } return "[" + strings.Join(s, " ") + "]" } {% endfunc %} // ExtraFixStringUnmarshaler is a template that forces values to be parsed properly. {% func ExtraFixStringUnmarshaler(typ, parseFunc, extra string) %} // UnmarshalEasyJSON satisfies easyjson.Unmarshaler. func (t *{%s= typ %}) UnmarshalEasyJSON(in *jlexer.Lexer) { buf := in.Raw() if l := len(buf); l > 2 && buf[0] == '"' && buf[l-1] == '"' { buf = buf[1:l-1] } {% if parseFunc != "" %} v, err := strconv.{%s= parseFunc %}(string(buf){%s= extra %}) if err != nil { in.AddError(err) } {% endif %} *t = {%s= typ %}({% if parseFunc != "" %}v{% else %}buf{% end %}) } // UnmarshalJSON satisfies json.Unmarshaler. func (t *{%s= typ %}) UnmarshalJSON(buf []byte) error { return easyjson.Unmarshal(buf, t) } {% endfunc %} // ExtraExceptionDetailsTemplate is a special template for the Runtime.ExceptionDetails type that // defines the standard error interface. {% func ExtraExceptionDetailsTemplate() %} // Error satisfies the error interface. func (e *ExceptionDetails) Error() string { // TODO: watch script parsed events and match the ExceptionDetails.ScriptID // to the name/location of the actual code and display here return fmt.Sprintf("encountered exception '%s' (%d:%d)", e.Text, e.LineNumber, e.ColumnNumber) } {% endfunc %} // ExtraCDPTypes is the template for additional internal type // declarations. {% func ExtraCDPTypes() %} // Error satisfies the error interface. func (t ErrorType) Error() string { return string(t) } // FrameHandler is the common interface for a frame handler. type FrameHandler interface { SetActive(context.Context, FrameID) error GetRoot(context.Context) (*Node, error) WaitFrame(context.Context, FrameID) (*Frame, error) WaitNode(context.Context, *Frame, NodeID) (*Node, error) Listen(...MethodType) <-chan interface{} // Execute executes the specified command using the supplied context and // parameters. Execute(context.Context, MethodType, easyjson.RawMessage) <-chan interface{} } // Empty is an empty JSON object message. var Empty = easyjson.RawMessage(`{}`) {% endfunc %} // ExtraUtilTemplate generates the decode func for the Message type. {% func ExtraUtilTemplate(domains []*internal.Domain) %} type empty struct{} var emptyVal = &empty{} // UnmarshalMessage unmarshals the message result or params. func UnmarshalMessage(msg *cdp.Message) (interface{}, error) { var v easyjson.Unmarshaler switch msg.Method {{% for _, d := range domains %}{% for _, c := range d.Commands %} case cdp.{%s= c.CommandMethodType(d) %}:{% if len(c.Returns) == 0 %} return emptyVal, nil{% else %} v = new({%s= d.PackageRefName() %}.{%s= c.CommandReturnsType() %}){% endif %} {% endfor %}{% for _, e := range d.Events %} case cdp.{%s= e.EventMethodType(d) %}: v = new({%s= d.PackageRefName() %}.{%s= e.EventType() %}) {% endfor %}{% endfor %}} var buf easyjson.RawMessage switch { case msg.Params != nil: buf = msg.Params case msg.Result != nil: buf = msg.Result default: return nil, errors.New("msg missing params or result") } err := easyjson.Unmarshal(buf, v) if err != nil { return nil, err } return v, nil } {% endfunc %} {% func ExtraMethodTypeDomainDecoder() %} // Domain returns the Chrome Debugging Protocol domain of the event or command. func (t MethodType) Domain() string { return string(t[:strings.IndexByte(string(t), '.')]) } {% endfunc %}