DOM tree manipulation, CSS inspection and modification, and styling analysis. This covers domains that provide access to the document structure, CSS rules, and visual styling information.
DOM tree manipulation and inspection for accessing and modifying document structure.
namespace Protocol.DOM {
type NodeId = integer;
type BackendNodeId = integer;
type PseudoType = ('first-line' | 'first-letter' | 'before' | 'after' | 'marker' | 'backdrop' | 'selection' | 'target-text' | 'spelling-error' | 'grammar-error' | 'highlight' | 'first-line-inherited' | 'scrollbar' | 'scrollbar-thumb' | 'scrollbar-button' | 'scrollbar-track' | 'scrollbar-track-piece' | 'scrollbar-corner' | 'resizer' | 'input-list-button' | 'view-transition' | 'view-transition-group' | 'view-transition-image-pair' | 'view-transition-old' | 'view-transition-new');
type ShadowRootType = ('user-agent' | 'open' | 'closed');
type CompatibilityMode = ('QuirksMode' | 'LimitedQuirksMode' | 'NoQuirksMode');
interface Node {
nodeId: NodeId;
parentId?: NodeId;
backendNodeId: BackendNodeId;
nodeType: integer;
nodeName: string;
localName: string;
nodeValue: string;
childNodeCount?: integer;
children?: Node[];
attributes?: string[];
documentURL?: string;
baseURL?: string;
publicId?: string;
systemId?: string;
xmlVersion?: string;
name?: string;
value?: string;
pseudoType?: PseudoType;
pseudoIdentifier?: string;
shadowRootType?: ShadowRootType;
frameId?: Page.FrameId;
contentDocument?: Node;
shadowRoots?: Node[];
templateContent?: Node;
pseudoElements?: Node[];
importedDocument?: Node;
distributedNodes?: BackendNode[];
isSVG?: boolean;
compatibilityMode?: CompatibilityMode;
assignedSlot?: BackendNode;
}
interface BackendNode {
nodeType: integer;
nodeName: string;
backendNodeId: BackendNodeId;
}
interface GetDocumentRequest {
depth?: integer;
pierce?: boolean;
}
interface GetDocumentResponse {
root: Node;
}
interface QuerySelectorRequest {
nodeId: NodeId;
selector: string;
}
interface QuerySelectorResponse {
nodeId: NodeId;
}
interface QuerySelectorAllRequest {
nodeId: NodeId;
selector: string;
}
interface QuerySelectorAllResponse {
nodeIds: NodeId[];
}
interface GetAttributesRequest {
nodeId: NodeId;
}
interface GetAttributesResponse {
attributes: string[];
}
interface SetAttributeValueRequest {
nodeId: NodeId;
name: string;
value: string;
}
interface RemoveAttributeRequest {
nodeId: NodeId;
name: string;
}
interface GetOuterHTMLRequest {
nodeId?: NodeId;
backendNodeId?: BackendNodeId;
objectId?: Runtime.RemoteObjectId;
}
interface GetOuterHTMLResponse {
outerHTML: string;
}
interface SetOuterHTMLRequest {
nodeId: NodeId;
outerHTML: string;
}
interface DocumentUpdatedEvent {}
interface SetChildNodesEvent {
parentId: NodeId;
nodes: Node[];
}
interface AttributeModifiedEvent {
nodeId: NodeId;
name: string;
value: string;
}
interface AttributeRemovedEvent {
nodeId: NodeId;
name: string;
}
interface CharacterDataModifiedEvent {
nodeId: NodeId;
characterData: string;
}
interface ChildNodeInsertedEvent {
parentNodeId: NodeId;
previousNodeId: NodeId;
node: Node;
}
interface ChildNodeRemovedEvent {
parentNodeId: NodeId;
nodeId: NodeId;
}
}Usage Example:
import Protocol from "devtools-protocol/types/protocol";
// Get the document root
async function getDocument(): Promise<Protocol.DOM.Node> {
const request: Protocol.DOM.GetDocumentRequest = {
depth: -1,
pierce: true
};
// Implementation would send DOM.getDocument
const response: Protocol.DOM.GetDocumentResponse = {
root: {
nodeId: 1,
backendNodeId: 1,
nodeType: 9, // Document node
nodeName: "#document",
localName: "",
nodeValue: "",
childNodeCount: 1,
documentURL: "https://example.com",
children: []
}
};
return response.root;
}
// Query for elements
async function findElementsBySelector(nodeId: Protocol.DOM.NodeId, selector: string): Promise<Protocol.DOM.NodeId[]> {
const request: Protocol.DOM.QuerySelectorAllRequest = {
nodeId,
selector
};
// Implementation would send DOM.querySelectorAll
const response: Protocol.DOM.QuerySelectorAllResponse = {
nodeIds: [2, 3, 4]
};
return response.nodeIds;
}
// Modify element attributes
async function setElementAttribute(nodeId: Protocol.DOM.NodeId, name: string, value: string): Promise<void> {
const request: Protocol.DOM.SetAttributeValueRequest = {
nodeId,
name,
value
};
// Implementation would send DOM.setAttributeValue
}
// Handle DOM change events
function onAttributeModified(event: Protocol.DOM.AttributeModifiedEvent) {
console.log(`Attribute ${event.name} changed to "${event.value}" on node ${event.nodeId}`);
}
function onChildNodeInserted(event: Protocol.DOM.ChildNodeInsertedEvent) {
console.log(`Child node inserted into ${event.parentNodeId}:`, event.node.nodeName);
}CSS style inspection and modification for analyzing and changing element styling.
namespace Protocol.CSS {
type StyleSheetId = string;
type CSSRuleId = string;
interface CSSRule {
styleSheetId?: StyleSheetId;
selectorList: SelectorList;
origin: StyleSheetOrigin;
style: CSSStyle;
media?: CSSMedia[];
containerQueries?: CSSContainerQuery[];
supports?: CSSSupports[];
layers?: CSSLayer[];
scopes?: CSSScope[];
}
interface CSSStyle {
styleSheetId?: StyleSheetId;
cssProperties: CSSProperty[];
shorthandEntries: ShorthandEntry[];
cssText?: string;
range?: SourceRange;
}
interface CSSProperty {
name: string;
value: string;
important?: boolean;
implicit?: boolean;
text?: string;
parsedOk?: boolean;
disabled?: boolean;
range?: SourceRange;
longhandProperties?: CSSProperty[];
}
interface SelectorList {
selectors: CSSSelector[];
text: string;
}
interface CSSSelector {
text: string;
range?: SourceRange;
}
interface CSSStyleSheetHeader {
styleSheetId: StyleSheetId;
frameId: Page.FrameId;
sourceURL: string;
sourceMapURL?: string;
origin: StyleSheetOrigin;
title: string;
ownerNode?: DOM.BackendNodeId;
disabled: boolean;
hasSourceURL?: boolean;
isInline: boolean;
isMutable: boolean;
isConstructed: boolean;
startLine: number;
startColumn: number;
length: number;
endLine: number;
endColumn: number;
}
interface GetComputedStyleForNodeRequest {
nodeId: DOM.NodeId;
}
interface GetComputedStyleForNodeResponse {
computedStyle: CSSComputedStyleProperty[];
}
interface CSSComputedStyleProperty {
name: string;
value: string;
}
interface GetInlineStylesForNodeRequest {
nodeId: DOM.NodeId;
}
interface GetInlineStylesForNodeResponse {
inlineStyle?: CSSStyle;
attributesStyle?: CSSStyle;
}
interface GetMatchedStylesForNodeRequest {
nodeId: DOM.NodeId;
}
interface GetMatchedStylesForNodeResponse {
inlineStyle?: CSSStyle;
attributesStyle?: CSSStyle;
matchedCSSRules?: RuleMatch[];
pseudoElements?: PseudoElementMatches[];
inherited?: InheritedStyleEntry[];
inheritedPseudoElements?: InheritedPseudoElementMatches[];
cssKeyframesRules?: CSSKeyframesRule[];
cssPositionTryRules?: CSSPositionTryRule[];
}
interface RuleMatch {
rule: CSSRule;
matchingSelectors: integer[];
}
interface SetStyleTextsRequest {
edits: StyleDeclarationEdit[];
}
interface SetStyleTextsResponse {
styles: CSSStyle[];
}
interface StyleDeclarationEdit {
styleSheetId: StyleSheetId;
range: SourceRange;
text: string;
}
interface GetStyleSheetTextRequest {
styleSheetId: StyleSheetId;
}
interface GetStyleSheetTextResponse {
text: string;
}
interface SetStyleSheetTextRequest {
styleSheetId: StyleSheetId;
text: string;
}
interface StyleSheetAddedEvent {
header: CSSStyleSheetHeader;
}
interface StyleSheetRemovedEvent {
styleSheetId: StyleSheetId;
}
interface StyleSheetChangedEvent {
styleSheetId: StyleSheetId;
}
}Usage Example:
import Protocol from "devtools-protocol/types/protocol";
// Get computed styles for an element
async function getElementStyles(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.CSSComputedStyleProperty[]> {
const request: Protocol.CSS.GetComputedStyleForNodeRequest = {
nodeId
};
// Implementation would send CSS.getComputedStyleForNode
const response: Protocol.CSS.GetComputedStyleForNodeResponse = {
computedStyle: [
{ name: "color", value: "rgb(0, 0, 0)" },
{ name: "font-size", value: "16px" },
{ name: "display", value: "block" }
]
};
return response.computedStyle;
}
// Get matched CSS rules for an element
async function getMatchedRules(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.RuleMatch[]> {
const request: Protocol.CSS.GetMatchedStylesForNodeRequest = {
nodeId
};
// Implementation would send CSS.getMatchedStylesForNode
const response: Protocol.CSS.GetMatchedStylesForNodeResponse = {
matchedCSSRules: [
{
rule: {
selectorList: {
selectors: [{ text: ".example" }],
text: ".example"
},
origin: "regular",
style: {
cssProperties: [
{ name: "color", value: "red", important: false }
],
shorthandEntries: [],
cssText: "color: red;"
}
},
matchingSelectors: [0]
}
]
};
return response.matchedCSSRules || [];
}
// Modify CSS styles
async function modifyElementStyle(styleSheetId: Protocol.CSS.StyleSheetId, range: Protocol.CSS.SourceRange, newText: string): Promise<Protocol.CSS.CSSStyle[]> {
const request: Protocol.CSS.SetStyleTextsRequest = {
edits: [{
styleSheetId,
range,
text: newText
}]
};
// Implementation would send CSS.setStyleTexts
const response: Protocol.CSS.SetStyleTextsResponse = {
styles: []
};
return response.styles;
}
// Handle CSS events
function onStyleSheetAdded(event: Protocol.CSS.StyleSheetAddedEvent) {
console.log(`Stylesheet added: ${event.header.sourceURL}`);
}
function onStyleSheetChanged(event: Protocol.CSS.StyleSheetChangedEvent) {
console.log(`Stylesheet changed: ${event.styleSheetId}`);
}DOM-related debugging features for setting breakpoints on DOM mutations and events.
namespace Protocol.DOMDebugger {
type DOMBreakpointType = ('subtree-modified' | 'attribute-modified' | 'node-removed');
type CSPViolationType = ('trustedtype-sink-violation' | 'trustedtype-policy-violation');
interface EventListener {
type: string;
useCapture: boolean;
passive: boolean;
once: boolean;
scriptId: Runtime.ScriptId;
lineNumber: integer;
columnNumber: integer;
handler?: Runtime.RemoteObject;
originalHandler?: Runtime.RemoteObject;
backendNodeId?: DOM.BackendNodeId;
}
interface SetDOMBreakpointRequest {
nodeId: DOM.NodeId;
type: DOMBreakpointType;
}
interface RemoveDOMBreakpointRequest {
nodeId: DOM.NodeId;
type: DOMBreakpointType;
}
interface SetEventListenerBreakpointRequest {
eventName: string;
targetName?: string;
}
interface RemoveEventListenerBreakpointRequest {
eventName: string;
targetName?: string;
}
interface GetEventListenersRequest {
objectId: Runtime.RemoteObjectId;
depth?: integer;
pierce?: boolean;
}
interface GetEventListenersResponse {
listeners: EventListener[];
}
}DOM tree snapshots for analysis and testing purposes.
namespace Protocol.DOMSnapshot {
interface DOMNode {
nodeType: integer;
nodeName: string;
nodeValue: string;
textValue?: string;
inputValue?: string;
inputChecked?: boolean;
optionSelected?: boolean;
backendNodeId: DOM.BackendNodeId;
childNodeIndexes?: integer[];
attributes?: NameValue[];
pseudoElementIndexes?: integer[];
layoutNodeIndex?: integer;
documentURL?: string;
baseURL?: string;
contentLanguage?: string;
documentEncoding?: string;
publicId?: string;
systemId?: string;
frameId?: Page.FrameId;
contentDocumentIndex?: integer;
pseudoType?: DOM.PseudoType;
shadowRootType?: DOM.ShadowRootType;
isClickable?: boolean;
eventListeners?: DOMDebugger.EventListener[];
currentSourceURL?: string;
originURL?: string;
scrollOffsetX?: number;
scrollOffsetY?: number;
}
interface LayoutTreeNode {
domNodeIndex: integer;
boundingBox: DOM.Rect;
layoutText?: string;
inlineTextNodes?: InlineTextBox[];
styleIndex?: integer;
paintOrder?: integer;
isStackingContext?: boolean;
}
interface ComputedStyle {
properties: NameValue[];
}
interface NameValue {
name: string;
value: string;
}
interface CaptureSnapshotRequest {
computedStyles: string[];
includePaintOrder?: boolean;
includeDOMRects?: boolean;
includeBlendedBackgroundColors?: boolean;
includeTextColorOpacities?: boolean;
}
interface CaptureSnapshotResponse {
documents: DocumentSnapshot[];
strings: string[];
}
interface DocumentSnapshot {
documentURL: integer;
title: integer;
baseURL: integer;
contentLanguage: integer;
encodingName: integer;
publicId: integer;
systemId: integer;
frameId: integer;
nodes: DOMNode[];
layout: LayoutTreeSnapshot;
textBoxes: TextBoxSnapshot;
scrollOffsetX?: number;
scrollOffsetY?: number;
contentWidth?: number;
contentHeight?: number;
}
}import Protocol from "devtools-protocol/types/protocol";
class DOMInspector {
private document: Protocol.DOM.Node | null = null;
async initialize(): Promise<void> {
// Get the document
const docResponse = await this.getDocument();
this.document = docResponse.root;
}
private async getDocument(): Promise<Protocol.DOM.GetDocumentResponse> {
const request: Protocol.DOM.GetDocumentRequest = {
depth: -1,
pierce: true
};
// Implementation would send DOM.getDocument
return {
root: {
nodeId: 1,
backendNodeId: 1,
nodeType: 9,
nodeName: "#document",
localName: "",
nodeValue: "",
children: []
}
};
}
async findElementsByText(text: string): Promise<Protocol.DOM.NodeId[]> {
if (!this.document) throw new Error("Document not loaded");
const selector = `//*[contains(text(), "${text}")]`;
// Implementation would use XPath or text-based search
return [];
}
async modifyElementText(nodeId: Protocol.DOM.NodeId, newText: string): Promise<void> {
// Get current HTML
const htmlRequest: Protocol.DOM.GetOuterHTMLRequest = { nodeId };
// Implementation would get current HTML and modify it
const setRequest: Protocol.DOM.SetOuterHTMLRequest = {
nodeId,
outerHTML: `<div>${newText}</div>`
};
// Implementation would send DOM.setOuterHTML
}
setupDOMChangeListeners(): void {
this.onAttributeModified = (event: Protocol.DOM.AttributeModifiedEvent) => {
console.log(`Attribute changed: ${event.name}="${event.value}" on node ${event.nodeId}`);
};
this.onChildNodeInserted = (event: Protocol.DOM.ChildNodeInsertedEvent) => {
console.log(`Node inserted: ${event.node.nodeName} into ${event.parentNodeId}`);
};
this.onChildNodeRemoved = (event: Protocol.DOM.ChildNodeRemovedEvent) => {
console.log(`Node removed: ${event.nodeId} from ${event.parentNodeId}`);
};
}
}import Protocol from "devtools-protocol/types/protocol";
class StyleAnalyzer {
async analyzeElementStyles(nodeId: Protocol.DOM.NodeId): Promise<StyleAnalysis> {
// Get computed styles
const computedRequest: Protocol.CSS.GetComputedStyleForNodeRequest = { nodeId };
const computedStyles = await this.getComputedStyles(computedRequest);
// Get matched rules
const matchedRequest: Protocol.CSS.GetMatchedStylesForNodeRequest = { nodeId };
const matchedRules = await this.getMatchedRules(matchedRequest);
// Get inline styles
const inlineRequest: Protocol.CSS.GetInlineStylesForNodeRequest = { nodeId };
const inlineStyles = await this.getInlineStyles(inlineRequest);
return {
computed: computedStyles,
matched: matchedRules,
inline: inlineStyles
};
}
private async getComputedStyles(request: Protocol.CSS.GetComputedStyleForNodeRequest): Promise<Protocol.CSS.CSSComputedStyleProperty[]> {
// Implementation would send CSS.getComputedStyleForNode
return [];
}
private async getMatchedRules(request: Protocol.CSS.GetMatchedStylesForNodeRequest): Promise<Protocol.CSS.RuleMatch[]> {
// Implementation would send CSS.getMatchedStylesForNode
return [];
}
private async getInlineStyles(request: Protocol.CSS.GetInlineStylesForNodeRequest): Promise<{ inlineStyle?: Protocol.CSS.CSSStyle; attributesStyle?: Protocol.CSS.CSSStyle }> {
// Implementation would send CSS.getInlineStylesForNode
return {};
}
async modifyElementStyle(nodeId: Protocol.DOM.NodeId, property: string, value: string): Promise<void> {
// First get the current inline styles
const inlineRequest: Protocol.CSS.GetInlineStylesForNodeRequest = { nodeId };
const inlineResponse = await this.getInlineStyles(inlineRequest);
if (inlineResponse.inlineStyle) {
// Modify existing inline style
const newCssText = `${inlineResponse.inlineStyle.cssText} ${property}: ${value};`;
const editRequest: Protocol.CSS.SetStyleTextsRequest = {
edits: [{
styleSheetId: inlineResponse.inlineStyle.styleSheetId!,
range: inlineResponse.inlineStyle.range!,
text: newCssText
}]
};
// Implementation would send CSS.setStyleTexts
} else {
// Add new inline style via DOM attribute
const setAttrRequest: Protocol.DOM.SetAttributeValueRequest = {
nodeId,
name: "style",
value: `${property}: ${value};`
};
// Implementation would send DOM.setAttributeValue
}
}
}
interface StyleAnalysis {
computed: Protocol.CSS.CSSComputedStyleProperty[];
matched: Protocol.CSS.RuleMatch[];
inline: { inlineStyle?: Protocol.CSS.CSSStyle; attributesStyle?: Protocol.CSS.CSSStyle };
}import Protocol from "devtools-protocol/types/protocol";
class DOMDebugger {
async setBreakpointOnNodeChanges(nodeId: Protocol.DOM.NodeId): Promise<void> {
// Set breakpoint on subtree modifications
const subtreeRequest: Protocol.DOMDebugger.SetDOMBreakpointRequest = {
nodeId,
type: 'subtree-modified'
};
// Set breakpoint on attribute modifications
const attrRequest: Protocol.DOMDebugger.SetDOMBreakpointRequest = {
nodeId,
type: 'attribute-modified'
};
// Set breakpoint on node removal
const removeRequest: Protocol.DOMDebugger.SetDOMBreakpointRequest = {
nodeId,
type: 'node-removed'
};
// Implementation would send DOMDebugger.setDOMBreakpoint for each
}
async setEventListenerBreakpoints(events: string[]): Promise<void> {
for (const eventName of events) {
const request: Protocol.DOMDebugger.SetEventListenerBreakpointRequest = {
eventName
};
// Implementation would send DOMDebugger.setEventListenerBreakpoint
}
}
async analyzeEventListeners(objectId: Protocol.Runtime.RemoteObjectId): Promise<Protocol.DOMDebugger.EventListener[]> {
const request: Protocol.DOMDebugger.GetEventListenersRequest = {
objectId,
depth: 10,
pierce: true
};
// Implementation would send DOMDebugger.getEventListeners
const response: Protocol.DOMDebugger.GetEventListenersResponse = {
listeners: []
};
return response.listeners;
}
}