brave-real-playwright-core
Version:
Brave-optimized Playwright Core (v1.55.0) with comprehensive stealth patches and error stack sanitization
264 lines (263 loc) • 8.27 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var crAccessibility_exports = {};
__export(crAccessibility_exports, {
getAccessibilityTree: () => getAccessibilityTree
});
module.exports = __toCommonJS(crAccessibility_exports);
async function getAccessibilityTree(client, needle) {
const { nodes } = await client.send("Accessibility.getFullAXTree");
const tree = CRAXNode.createTree(client, nodes);
return {
tree,
needle: needle ? await tree._findElement(needle) : null
};
}
class CRAXNode {
constructor(client, payload) {
this._children = [];
this._richlyEditable = false;
this._editable = false;
this._focusable = false;
this._expanded = false;
this._hidden = false;
this._client = client;
this._payload = payload;
this._name = this._payload.name ? this._payload.name.value : "";
this._role = this._payload.role ? this._payload.role.value : "Unknown";
for (const property of this._payload.properties || []) {
if (property.name === "editable") {
this._richlyEditable = property.value.value === "richtext";
this._editable = true;
}
if (property.name === "focusable")
this._focusable = property.value.value;
if (property.name === "expanded")
this._expanded = property.value.value;
if (property.name === "hidden")
this._hidden = property.value.value;
}
}
_isPlainTextField() {
if (this._richlyEditable)
return false;
if (this._editable)
return true;
return this._role === "textbox" || this._role === "ComboBox" || this._role === "searchbox";
}
_isTextOnlyObject() {
const role = this._role;
return role === "LineBreak" || role === "text" || role === "InlineTextBox" || role === "StaticText";
}
_hasFocusableChild() {
if (this._cachedHasFocusableChild === void 0) {
this._cachedHasFocusableChild = false;
for (const child of this._children) {
if (child._focusable || child._hasFocusableChild()) {
this._cachedHasFocusableChild = true;
break;
}
}
}
return this._cachedHasFocusableChild;
}
children() {
return this._children;
}
async _findElement(element) {
const objectId = element._objectId;
const { node: { backendNodeId } } = await this._client.send("DOM.describeNode", { objectId });
const needle = this.find((node) => node._payload.backendDOMNodeId === backendNodeId);
return needle || null;
}
find(predicate) {
if (predicate(this))
return this;
for (const child of this._children) {
const result = child.find(predicate);
if (result)
return result;
}
return null;
}
isLeafNode() {
if (!this._children.length)
return true;
if (this._isPlainTextField() || this._isTextOnlyObject())
return true;
switch (this._role) {
case "doc-cover":
case "graphics-symbol":
case "img":
case "Meter":
case "scrollbar":
case "slider":
case "separator":
case "progressbar":
return true;
default:
break;
}
if (this._hasFocusableChild())
return false;
if (this._focusable && this._role !== "WebArea" && this._role !== "RootWebArea" && this._name)
return true;
if (this._role === "heading" && this._name)
return true;
return false;
}
isControl() {
switch (this._role) {
case "button":
case "checkbox":
case "ColorWell":
case "combobox":
case "DisclosureTriangle":
case "listbox":
case "menu":
case "menubar":
case "menuitem":
case "menuitemcheckbox":
case "menuitemradio":
case "radio":
case "scrollbar":
case "searchbox":
case "slider":
case "spinbutton":
case "switch":
case "tab":
case "textbox":
case "tree":
return true;
default:
return false;
}
}
isInteresting(insideControl) {
const role = this._role;
if (role === "Ignored" || this._hidden)
return false;
if (this._focusable || this._richlyEditable)
return true;
if (this.isControl())
return true;
if (insideControl)
return false;
return this.isLeafNode() && !!this._name;
}
normalizedRole() {
switch (this._role) {
case "RootWebArea":
return "WebArea";
case "StaticText":
return "text";
default:
return this._role;
}
}
serialize() {
const properties = /* @__PURE__ */ new Map();
for (const property of this._payload.properties || [])
properties.set(property.name.toLowerCase(), property.value.value);
if (this._payload.description)
properties.set("description", this._payload.description.value);
const node = {
role: this.normalizedRole(),
name: this._payload.name ? this._payload.name.value || "" : ""
};
const userStringProperties = [
"description",
"keyshortcuts",
"roledescription",
"valuetext"
];
for (const userStringProperty of userStringProperties) {
if (!properties.has(userStringProperty))
continue;
node[userStringProperty] = properties.get(userStringProperty);
}
const booleanProperties = [
"disabled",
"expanded",
"focused",
"modal",
"multiline",
"multiselectable",
"readonly",
"required",
"selected"
];
for (const booleanProperty of booleanProperties) {
if (booleanProperty === "focused" && (this._role === "WebArea" || this._role === "RootWebArea"))
continue;
const value = properties.get(booleanProperty);
if (!value)
continue;
node[booleanProperty] = value;
}
const numericalProperties = [
"level",
"valuemax",
"valuemin"
];
for (const numericalProperty of numericalProperties) {
if (!properties.has(numericalProperty))
continue;
node[numericalProperty] = properties.get(numericalProperty);
}
const tokenProperties = [
"autocomplete",
"haspopup",
"invalid",
"orientation"
];
for (const tokenProperty of tokenProperties) {
const value = properties.get(tokenProperty);
if (!value || value === "false")
continue;
node[tokenProperty] = value;
}
const axNode = node;
if (this._payload.value) {
if (typeof this._payload.value.value === "string")
axNode.valueString = this._payload.value.value;
if (typeof this._payload.value.value === "number")
axNode.valueNumber = this._payload.value.value;
}
if (properties.has("checked"))
axNode.checked = properties.get("checked") === "true" ? "checked" : properties.get("checked") === "false" ? "unchecked" : "mixed";
if (properties.has("pressed"))
axNode.pressed = properties.get("pressed") === "true" ? "pressed" : properties.get("pressed") === "false" ? "released" : "mixed";
return axNode;
}
static createTree(client, payloads) {
const nodeById = /* @__PURE__ */ new Map();
for (const payload of payloads)
nodeById.set(payload.nodeId, new CRAXNode(client, payload));
for (const node of nodeById.values()) {
for (const childId of node._payload.childIds || [])
node._children.push(nodeById.get(childId));
}
return nodeById.values().next().value;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getAccessibilityTree
});