Skip to main content

devtools_traits/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! This module contains shared types and messages for use by devtools/script.
6//! The traits are here instead of in script so that the devtools crate can be
7//! modified independently of the rest of Servo.
8//!
9//! Since these types can be sent through the IPC channel and use non
10//! self-describing serializers, the `flatten`, `skip*`, `tag` and `untagged`
11//! serde annotations are not supported. Types like `serde_json::Value` aren't
12//! supported either. For JSON serialization it is preferred to use a wrapper
13//! struct in the devtools crate instead.
14
15#![crate_name = "devtools_traits"]
16#![crate_type = "rlib"]
17#![deny(unsafe_code)]
18
19use core::fmt;
20use std::collections::HashMap;
21use std::fmt::Display;
22use std::net::TcpStream;
23use std::str::FromStr;
24use std::time::{Duration, SystemTime, UNIX_EPOCH};
25
26pub use embedder_traits::ConsoleLogLevel;
27use embedder_traits::Theme;
28use http::{HeaderMap, Method};
29use malloc_size_of_derive::MallocSizeOf;
30use net_traits::http_status::HttpStatus;
31use net_traits::request::Destination;
32use net_traits::{DebugVec, TlsSecurityInfo};
33use profile_traits::mem::ReportsChan;
34use serde::de::{Error, Visitor};
35use serde::{Deserialize, Serialize};
36use servo_base::cross_process_instant::CrossProcessInstant;
37use servo_base::generic_channel::GenericSender;
38use servo_base::id::{BrowsingContextId, PipelineId, WebViewId};
39use servo_url::ServoUrl;
40use uuid::Uuid;
41
42// Information would be attached to NewGlobal to be received and show in devtools.
43// Extend these fields if we need more information.
44#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
45pub struct DevtoolsPageInfo {
46    pub title: String,
47    pub url: ServoUrl,
48    pub is_top_level_global: bool,
49    pub is_service_worker: bool,
50}
51
52#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
53pub struct CSSError {
54    pub filename: String,
55    pub line: u32,
56    pub column: u32,
57    pub msg: String,
58}
59
60/// Messages to instruct the devtools server to update its known actors/state
61/// according to changes in the browser.
62#[derive(Debug)]
63pub enum DevtoolsControlMsg {
64    /// Messages from threads in the chrome process (resource/constellation/devtools)
65    FromChrome(ChromeToDevtoolsControlMsg),
66    /// Messages from script threads
67    FromScript(ScriptToDevtoolsControlMsg),
68    /// Sent when a devtools client thread terminates.
69    ClientExited,
70}
71
72/// Events that the devtools server must act upon.
73// FIXME: https://github.com/servo/servo/issues/34591
74#[expect(clippy::large_enum_variant)]
75#[derive(Debug)]
76pub enum ChromeToDevtoolsControlMsg {
77    /// A new client has connected to the server.
78    AddClient(TcpStream),
79    /// The browser is shutting down.
80    ServerExitMsg,
81    /// A network event occurred (request, reply, etc.). The actor with the
82    /// provided name should be notified.
83    NetworkEvent(String, NetworkEvent),
84    /// Perform a memory report.
85    CollectMemoryReport(ReportsChan),
86}
87
88/// The state of a page navigation.
89#[derive(Debug, Deserialize, Serialize)]
90pub enum NavigationState {
91    /// A browsing context is about to navigate to a given URL.
92    Start(ServoUrl),
93    /// A browsing context has completed navigating to the provided pipeline.
94    Stop(PipelineId, DevtoolsPageInfo),
95}
96
97#[derive(Debug, Deserialize, Serialize)]
98/// Events that the devtools server must act upon.
99pub enum ScriptToDevtoolsControlMsg {
100    /// A new global object was created, associated with a particular pipeline.
101    /// The means of communicating directly with it are provided.
102    NewGlobal(
103        (BrowsingContextId, PipelineId, Option<WorkerId>, WebViewId),
104        GenericSender<DevtoolScriptControlMsg>,
105        DevtoolsPageInfo,
106    ),
107    /// The given browsing context is performing a navigation.
108    Navigate(BrowsingContextId, NavigationState),
109    /// A particular page has invoked the console API.
110    ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
111    /// Request to clear the console for a given pipeline.
112    ClearConsole(PipelineId, Option<WorkerId>),
113    /// An animation frame with the given timestamp was processed in a script thread.
114    /// The actor with the provided name should be notified.
115    FramerateTick(String, f64),
116
117    /// Report a CSS parse error for the given pipeline
118    ReportCSSError(PipelineId, CSSError),
119
120    /// Report a page error for the given pipeline
121    ReportPageError(PipelineId, PageError),
122
123    /// Report a page title change
124    TitleChanged(PipelineId, String),
125
126    /// Get source information from script
127    CreateSourceActor(
128        GenericSender<DevtoolScriptControlMsg>,
129        PipelineId,
130        SourceInfo,
131    ),
132
133    UpdateSourceContent(PipelineId, String),
134
135    DomMutation(PipelineId, DomMutation),
136
137    /// The debugger is paused, sending frame information.
138    DebuggerPause(PipelineId, FrameOffset, PauseReason),
139
140    /// Get frame information from script
141    CreateFrameActor(GenericSender<String>, PipelineId, FrameInfo),
142
143    /// Get environment information from script
144    CreateEnvironmentActor(
145        GenericSender<String>,
146        EnvironmentInfo,
147        Option<String>,
148        Option<String>,
149    ),
150}
151
152#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
153pub enum DomMutation {
154    AttributeModified {
155        node: String,
156        attribute_name: String,
157        new_value: Option<String>,
158    },
159}
160
161#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
162#[serde(rename_all = "camelCase")]
163pub struct ObjectPreview {
164    pub kind: String,
165    pub own_properties: Option<Vec<PropertyDescriptor>>,
166    pub own_properties_length: Option<u32>,
167    pub function: Option<FunctionPreview>,
168    pub array_length: Option<u32>,
169    pub items: Option<Vec<DebuggerValue>>,
170}
171
172#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
173#[serde(rename_all = "camelCase")]
174pub struct FunctionPreview {
175    pub name: Option<String>,
176    pub display_name: Option<String>,
177    pub parameter_names: Vec<String>,
178    pub is_async: Option<bool>,
179    pub is_generator: Option<bool>,
180}
181
182fn debugger_value_uuid() -> String {
183    Uuid::new_v4().to_string()
184}
185
186struct DebuggerNumberVisitor;
187
188impl Visitor<'_> for DebuggerNumberVisitor {
189    type Value = f64;
190
191    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
192        formatter.write_str("a debugger value number")
193    }
194
195    fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
196        Ok(value)
197    }
198
199    fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
200        Ok(value as f64)
201    }
202
203    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
204        Ok(value as f64)
205    }
206
207    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
208    where
209        E: Error,
210    {
211        value.parse().map_err(E::custom)
212    }
213}
214
215fn deserialize_debugger_number<'de, D>(deserializer: D) -> Result<f64, D::Error>
216where
217    D: serde::Deserializer<'de>,
218{
219    // `DebuggerValue` is also sent over Servo IPC, not only through debugger.js.
220    if !deserializer.is_human_readable() {
221        return f64::deserialize(deserializer);
222    }
223
224    deserializer.deserialize_any(DebuggerNumberVisitor)
225}
226
227#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
228#[serde(rename_all_fields = "camelCase")]
229pub enum DebuggerValue {
230    VoidValue,
231    NullValue,
232    BooleanValue(bool),
233    NumberValue(#[serde(deserialize_with = "deserialize_debugger_number")] f64),
234    StringValue(String),
235    ObjectValue {
236        #[serde(default = "debugger_value_uuid")]
237        uuid: String,
238        class: String,
239        own_property_length: Option<u32>,
240        preview: Option<ObjectPreview>,
241    },
242}
243
244/// <https://searchfox.org/mozilla-central/source/devtools/server/actors/object/property-iterator.js#51>
245#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
246#[serde(rename_all = "camelCase")]
247pub struct PropertyDescriptor {
248    pub name: String,
249    pub value: DebuggerValue,
250    pub configurable: bool,
251    pub enumerable: bool,
252    pub writable: bool,
253    pub is_accessor: bool,
254}
255
256#[derive(Debug, Deserialize, Serialize)]
257#[serde(rename_all = "camelCase")]
258pub struct EvaluateJSReply {
259    pub value: DebuggerValue,
260    pub has_exception: bool,
261}
262
263#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
264pub struct AttrInfo {
265    pub namespace: String,
266    pub name: String,
267    pub value: String,
268}
269
270#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
271#[serde(rename_all = "camelCase")]
272pub struct NodeInfo {
273    pub unique_id: String,
274    pub host: Option<String>,
275    #[serde(rename = "baseURI")]
276    pub base_uri: String,
277    pub parent: String,
278    pub node_type: u16,
279    pub node_name: String,
280    pub node_value: Option<String>,
281    pub num_children: usize,
282    pub attrs: Vec<AttrInfo>,
283    pub is_top_level_document: bool,
284    pub shadow_root_mode: Option<ShadowRootMode>,
285    pub is_shadow_host: bool,
286    pub display: Option<String>,
287    /// Whether this node is currently displayed.
288    ///
289    /// For example, the node might have `display: none`.
290    pub is_displayed: bool,
291
292    /// The `DOCTYPE` name if this is a `DocumentType` node, `None` otherwise
293    pub doctype_name: Option<String>,
294
295    /// The `DOCTYPE` public identifier if this is a `DocumentType` node , `None` otherwise
296    pub doctype_public_identifier: Option<String>,
297
298    /// The `DOCTYPE` system identifier if this is a `DocumentType` node, `None` otherwise
299    pub doctype_system_identifier: Option<String>,
300
301    pub has_event_listeners: bool,
302}
303
304pub struct StartedTimelineMarker {
305    name: String,
306    start_time: CrossProcessInstant,
307    start_stack: Option<Vec<()>>,
308}
309
310#[derive(Debug, Deserialize, Serialize)]
311pub struct TimelineMarker {
312    pub name: String,
313    pub start_time: CrossProcessInstant,
314    pub start_stack: Option<Vec<()>>,
315    pub end_time: CrossProcessInstant,
316    pub end_stack: Option<Vec<()>>,
317}
318
319#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
320pub enum TimelineMarkerType {
321    Reflow,
322    DOMEvent,
323}
324
325#[derive(Debug, Deserialize, Serialize)]
326#[serde(rename_all = "camelCase")]
327pub struct NodeStyle {
328    pub name: String,
329    pub value: String,
330    pub priority: String,
331}
332
333#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
334#[serde(tag = "type", rename_all = "camelCase")]
335pub enum AncestorData {
336    Layer {
337        actor_id: Option<String>,
338        value: Option<String>,
339    },
340}
341
342#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
343#[serde(rename_all = "camelCase")]
344pub struct MatchedRule {
345    pub selector: String,
346    pub stylesheet_index: usize,
347    pub block_id: usize,
348    pub ancestor_data: Vec<AncestorData>,
349}
350
351/// The properties of a DOM node as computed by layout.
352#[derive(Debug, Deserialize, Serialize)]
353#[serde(rename_all = "kebab-case")]
354pub struct ComputedNodeLayout {
355    pub display: String,
356    pub position: String,
357    pub z_index: String,
358    pub box_sizing: String,
359
360    pub margin_top: String,
361    pub margin_right: String,
362    pub margin_bottom: String,
363    pub margin_left: String,
364
365    pub border_top_width: String,
366    pub border_right_width: String,
367    pub border_bottom_width: String,
368    pub border_left_width: String,
369
370    pub padding_top: String,
371    pub padding_right: String,
372    pub padding_bottom: String,
373    pub padding_left: String,
374
375    pub width: f32,
376    pub height: f32,
377}
378
379#[derive(Debug, Default, Deserialize, Serialize)]
380pub struct AutoMargins {
381    pub top: bool,
382    pub right: bool,
383    pub bottom: bool,
384    pub left: bool,
385}
386
387/// Messages to process in a particular script thread, as instructed by a devtools client.
388/// TODO: better error handling, e.g. if pipeline id lookup fails?
389#[derive(Debug, Deserialize, Serialize)]
390pub enum DevtoolScriptControlMsg {
391    /// Retrieve the details of the root node (ie. the document) for the given pipeline.
392    GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
393    /// Retrieve the details of the document element for the given pipeline.
394    GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
395    /// Retrieve the details of the child nodes of the given node in the given pipeline.
396    GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
397    /// Retrieve the CSS style properties defined in the attribute tag for the given node.
398    GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
399    /// Retrieve the CSS style properties defined in an stylesheet for the given selector.
400    GetStylesheetStyle(
401        PipelineId,
402        String,
403        MatchedRule,
404        GenericSender<Option<Vec<NodeStyle>>>,
405    ),
406    /// Retrieve the list of stylesheets for the given pipeline and node.
407    GetStyleSheets(PipelineId, GenericSender<Vec<StyleSheetInfo>>),
408    /// Retrieve the actual CSS text for the stylesheet with the given node ID and index.
409    GetStyleSheetText(PipelineId, i32, GenericSender<Option<String>>),
410    /// Retrieves the CSS selectors for the given node. A selector is comprised of the text
411    /// of the selector and the id of the stylesheet that contains it.
412    GetSelectors(PipelineId, String, GenericSender<Option<Vec<MatchedRule>>>),
413    /// Retrieve the computed CSS style properties for the given node.
414    GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
415    /// Get information about event listeners on a node.
416    GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
417    /// Retrieve the computed layout properties of the given node in the given pipeline.
418    GetLayout(
419        PipelineId,
420        String,
421        GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
422    ),
423    /// Get a unique XPath selector for the node.
424    GetXPath(PipelineId, String, GenericSender<String>),
425    /// Update a given node's attributes with a list of modifications.
426    ModifyAttribute(PipelineId, String, Vec<AttrModification>),
427    /// Update a given node's style rules with a list of modifications.
428    ModifyRule(PipelineId, String, Vec<RuleModification>),
429    /// Request live console messages for a given pipeline (true if desired, false otherwise).
430    WantsLiveNotifications(PipelineId, bool),
431    /// Request live notifications for a given set of timeline events for a given pipeline.
432    SetTimelineMarkers(
433        PipelineId,
434        Vec<TimelineMarkerType>,
435        GenericSender<Option<TimelineMarker>>,
436    ),
437    /// Withdraw request for live timeline notifications for a given pipeline.
438    DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
439    /// Request a callback directed at the given actor name from the next animation frame
440    /// executed in the given pipeline.
441    RequestAnimationFrame(PipelineId, String),
442    /// Direct the WebView containing the given pipeline to load a new URL,
443    /// as if it was typed by the user.
444    NavigateTo(PipelineId, ServoUrl),
445    /// Direct the WebView containing the given pipeline to traverse history backward
446    /// up to one step.
447    GoBack(PipelineId),
448    /// Direct the WebView containing the given pipeline to traverse history forward
449    /// up to one step.
450    GoForward(PipelineId),
451    /// Direct the given pipeline to reload the current page.
452    Reload(PipelineId),
453    /// Gets the list of all allowed CSS rules and possible values.
454    GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
455    /// Simulates a light or dark color scheme for the given pipeline
456    SimulateColorScheme(PipelineId, Theme),
457    /// Highlight the given DOM node
458    HighlightDomNode(PipelineId, Option<String>),
459
460    Eval(
461        String,
462        PipelineId,
463        Option<String>,
464        GenericSender<EvaluateJSReply>,
465    ),
466    GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
467    SetBreakpoint(u32, u32, u32),
468    ClearBreakpoint(u32, u32, u32),
469    Interrupt,
470    Resume(Option<String>, Option<String>),
471    ListFrames(PipelineId, u32, u32, GenericSender<Vec<String>>),
472    GetEnvironment(String, GenericSender<String>),
473    Blackbox(u32, BlackboxCoverage),
474    Unblackbox(u32, BlackboxCoverage),
475}
476
477#[derive(Debug, Deserialize, Serialize)]
478pub enum BlackboxCoverage {
479    Full,
480    Partial((u32, u32), (u32, u32)),
481}
482
483#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
484#[serde(rename_all = "camelCase")]
485pub struct AttrModification {
486    pub attribute_name: String,
487    pub new_value: Option<String>,
488}
489
490#[derive(Clone, Debug, Deserialize, Serialize)]
491#[serde(rename_all = "camelCase")]
492pub struct RuleModification {
493    #[serde(rename = "type")]
494    pub type_: String,
495    pub index: u32,
496    pub name: String,
497    pub value: String,
498    pub priority: String,
499}
500
501#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
502#[serde(rename_all = "camelCase")]
503pub struct StackFrame {
504    pub filename: String,
505    pub function_name: String,
506    pub column_number: u32,
507    pub line_number: u32,
508    // Not implemented in Servo
509    // source_id
510}
511
512pub fn get_time_stamp() -> u64 {
513    SystemTime::now()
514        .duration_since(UNIX_EPOCH)
515        .unwrap_or_default()
516        .as_millis() as u64
517}
518
519#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
520#[serde(rename_all = "camelCase")]
521pub struct ConsoleMessageFields {
522    pub level: ConsoleLogLevel,
523    pub filename: String,
524    pub line_number: u32,
525    pub column_number: u32,
526    pub time_stamp: u64,
527}
528
529#[derive(Clone, Debug, Deserialize, Serialize)]
530pub struct ConsoleMessage {
531    pub fields: ConsoleMessageFields,
532    pub arguments: Vec<DebuggerValue>,
533    pub stacktrace: Option<Vec<StackFrame>>,
534}
535
536#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
537#[serde(rename_all = "camelCase")]
538pub struct PageError {
539    pub error_message: String,
540    pub source_name: String,
541    pub line_number: u32,
542    pub column_number: u32,
543    pub time_stamp: u64,
544}
545
546#[derive(Debug, PartialEq, MallocSizeOf)]
547pub struct HttpRequest {
548    pub url: ServoUrl,
549    pub method: Method,
550    pub headers: HeaderMap,
551    pub body: Option<DebugVec>,
552    pub pipeline_id: PipelineId,
553    pub started_date_time: SystemTime,
554    pub time_stamp: i64,
555    pub connect_time: Duration,
556    pub send_time: Duration,
557    pub destination: Destination,
558    pub is_xhr: bool,
559    pub browsing_context_id: BrowsingContextId,
560}
561
562#[derive(Debug, PartialEq, MallocSizeOf)]
563pub struct HttpResponse {
564    #[ignore_malloc_size_of = "Http type"]
565    pub headers: Option<HeaderMap>,
566    pub status: HttpStatus,
567    pub body: Option<DebugVec>,
568    pub from_cache: bool,
569    pub pipeline_id: PipelineId,
570    pub browsing_context_id: BrowsingContextId,
571}
572
573#[derive(Debug, PartialEq)]
574pub struct SecurityInfoUpdate {
575    pub browsing_context_id: BrowsingContextId,
576    pub security_info: Option<TlsSecurityInfo>,
577}
578
579#[derive(Debug)]
580pub enum NetworkEvent {
581    HttpRequest(HttpRequest),
582    HttpRequestUpdate(HttpRequest),
583    HttpResponse(HttpResponse),
584    SecurityInfo(SecurityInfoUpdate),
585}
586
587impl NetworkEvent {
588    pub fn forward_to_devtools(&self) -> bool {
589        match self {
590            NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
591            NetworkEvent::HttpRequestUpdate(_) => true,
592            NetworkEvent::HttpResponse(_) => true,
593            NetworkEvent::SecurityInfo(_) => true,
594        }
595    }
596}
597
598impl TimelineMarker {
599    pub fn start(name: String) -> StartedTimelineMarker {
600        StartedTimelineMarker {
601            name,
602            start_time: CrossProcessInstant::now(),
603            start_stack: None,
604        }
605    }
606}
607
608impl StartedTimelineMarker {
609    pub fn end(self) -> TimelineMarker {
610        TimelineMarker {
611            name: self.name,
612            start_time: self.start_time,
613            start_stack: self.start_stack,
614            end_time: CrossProcessInstant::now(),
615            end_stack: None,
616        }
617    }
618}
619#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
620pub struct WorkerId(pub Uuid);
621impl Display for WorkerId {
622    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
623        write!(f, "{}", self.0)
624    }
625}
626impl FromStr for WorkerId {
627    type Err = uuid::Error;
628
629    fn from_str(s: &str) -> Result<Self, Self::Err> {
630        Ok(Self(s.parse()?))
631    }
632}
633
634#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
635#[serde(rename_all = "camelCase")]
636pub struct CssDatabaseProperty {
637    pub is_inherited: bool,
638    pub values: Vec<String>,
639    pub supports: Vec<String>,
640    pub subproperties: Vec<String>,
641}
642
643#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
644pub enum ShadowRootMode {
645    Open,
646    Closed,
647}
648
649impl fmt::Display for ShadowRootMode {
650    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
651        match self {
652            Self::Open => write!(f, "open"),
653            Self::Closed => write!(f, "close"),
654        }
655    }
656}
657
658#[derive(Debug, Deserialize, Serialize)]
659pub struct SourceInfo {
660    pub url: ServoUrl,
661    pub introduction_type: String,
662    pub inline: bool,
663    pub worker_id: Option<WorkerId>,
664    pub content: Option<String>,
665    pub content_type: Option<String>,
666    pub spidermonkey_id: u32,
667}
668
669#[derive(Clone, Debug, Deserialize, Serialize)]
670#[serde(rename_all = "camelCase")]
671pub struct RecommendedBreakpointLocation {
672    pub script_id: u32,
673    pub offset: u32,
674    pub line_number: u32,
675    pub column_number: u32,
676    pub is_step_start: bool,
677}
678
679#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
680pub struct FrameInfo {
681    pub display_name: String,
682    pub on_stack: bool,
683    pub oldest: bool,
684    pub terminated: bool,
685    pub type_: String,
686    pub url: String,
687}
688
689#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
690pub struct EnvironmentInfo {
691    pub type_: Option<String>,
692    pub scope_kind: Option<String>,
693    pub function_display_name: Option<String>,
694    pub binding_variables: Vec<PropertyDescriptor>,
695}
696
697#[derive(Clone, Debug, Deserialize, Serialize)]
698pub struct StyleSheetInfo {
699    pub href: Option<String>,
700    pub disabled: bool,
701    pub title: String,
702    pub style_sheet_index: i32,
703    pub system: bool,
704    pub rule_count: u32,
705}
706
707#[derive(Clone, Debug, Deserialize, Serialize)]
708pub struct EventListenerInfo {
709    pub event_type: String,
710    pub capturing: bool,
711}
712
713#[derive(Debug, Deserialize, Serialize)]
714#[serde(rename_all = "camelCase")]
715pub struct PauseReason {
716    #[serde(rename = "type")]
717    pub type_: String,
718    pub on_next: Option<bool>,
719}
720
721#[derive(Debug, Deserialize, Serialize)]
722pub struct FrameOffset {
723    pub actor: String,
724    pub column: u32,
725    pub line: u32,
726}