@canaryai/cli 0.2.8 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -92
- package/dist/chunk-C2PGZRYK.js +167 -0
- package/dist/chunk-C2PGZRYK.js.map +1 -0
- package/dist/{chunk-K2OB72B6.js → chunk-LC7ZVXPH.js} +2 -2
- package/dist/{chunk-6WWHXWCS.js → chunk-QLFSJG5O.js} +33 -5
- package/dist/chunk-QLFSJG5O.js.map +1 -0
- package/dist/{chunk-FK3EZADZ.js → chunk-XGO62PO2.js} +1829 -868
- package/dist/chunk-XGO62PO2.js.map +1 -0
- package/dist/{debug-workflow-55G4Y6YT.js → debug-workflow-I3F36JBL.js} +57 -36
- package/dist/debug-workflow-I3F36JBL.js.map +1 -0
- package/dist/{docs-RPFT7ZJB.js → docs-REHST3YB.js} +2 -2
- package/dist/{feature-flag-2FDSKOVX.js → feature-flag-3HB5NTMY.js} +3 -2
- package/dist/{feature-flag-2FDSKOVX.js.map → feature-flag-3HB5NTMY.js.map} +1 -1
- package/dist/index.js +22 -9
- package/dist/index.js.map +1 -1
- package/dist/{issues-6ZDNDSD6.js → issues-YU57CHXS.js} +3 -2
- package/dist/{issues-6ZDNDSD6.js.map → issues-YU57CHXS.js.map} +1 -1
- package/dist/{knobs-MZRTYS3P.js → knobs-QJ4IBLCT.js} +3 -2
- package/dist/{knobs-MZRTYS3P.js.map → knobs-QJ4IBLCT.js.map} +1 -1
- package/dist/{local-browser-X7J27IGS.js → local-browser-MKTJ36KY.js} +3 -3
- package/dist/{mcp-4JVLADZL.js → mcp-ZOKM2AUE.js} +49 -238
- package/dist/mcp-ZOKM2AUE.js.map +1 -0
- package/dist/{record-4OX7HXWQ.js → record-TNDBT3NY.js} +130 -28
- package/dist/record-TNDBT3NY.js.map +1 -0
- package/dist/session-RNLKFS2Z.js +751 -0
- package/dist/session-RNLKFS2Z.js.map +1 -0
- package/dist/skill-CZ7SHI3P.js +156 -0
- package/dist/skill-CZ7SHI3P.js.map +1 -0
- package/dist/{src-I4EXB5OD.js → src-2WSMYBMJ.js} +18 -2
- package/package.json +1 -1
- package/dist/chunk-6WWHXWCS.js.map +0 -1
- package/dist/chunk-FK3EZADZ.js.map +0 -1
- package/dist/debug-workflow-55G4Y6YT.js.map +0 -1
- package/dist/mcp-4JVLADZL.js.map +0 -1
- package/dist/record-4OX7HXWQ.js.map +0 -1
- /package/dist/{chunk-K2OB72B6.js.map → chunk-LC7ZVXPH.js.map} +0 -0
- /package/dist/{docs-RPFT7ZJB.js.map → docs-REHST3YB.js.map} +0 -0
- /package/dist/{local-browser-X7J27IGS.js.map → local-browser-MKTJ36KY.js.map} +0 -0
- /package/dist/{src-I4EXB5OD.js.map → src-2WSMYBMJ.js.map} +0 -0
|
@@ -4383,7 +4383,7 @@ var require_src = __commonJS({
|
|
|
4383
4383
|
var require_encoder = __commonJS({
|
|
4384
4384
|
"../../node_modules/.bun/jpeg-js@0.4.4/node_modules/jpeg-js/lib/encoder.js"(exports2, module2) {
|
|
4385
4385
|
"use strict";
|
|
4386
|
-
var
|
|
4386
|
+
var btoa2 = btoa2 || function(buf) {
|
|
4387
4387
|
return Buffer.from(buf).toString("base64");
|
|
4388
4388
|
};
|
|
4389
4389
|
function JPEGEncoder(quality2) {
|
|
@@ -5404,7 +5404,7 @@ var require_encoder = __commonJS({
|
|
|
5404
5404
|
writeWord(65497);
|
|
5405
5405
|
if (typeof module2 === "undefined") return new Uint8Array(byteout);
|
|
5406
5406
|
return Buffer.from(byteout);
|
|
5407
|
-
var jpegDataUri = "data:image/jpeg;base64," +
|
|
5407
|
+
var jpegDataUri = "data:image/jpeg;base64," + btoa2(byteout.join(""));
|
|
5408
5408
|
byteout = [];
|
|
5409
5409
|
var duration = (/* @__PURE__ */ new Date()).getTime() - time_start;
|
|
5410
5410
|
return jpegDataUri;
|
|
@@ -37998,6 +37998,201 @@ var CdpScreencastManager = class {
|
|
|
37998
37998
|
}
|
|
37999
37999
|
};
|
|
38000
38000
|
|
|
38001
|
+
// ../browser-core/src/indexeddb-helpers.ts
|
|
38002
|
+
var MAX_TOTAL_SIZE_BYTES = 10 * 1024 * 1024;
|
|
38003
|
+
async function extractIndexedDB(page) {
|
|
38004
|
+
try {
|
|
38005
|
+
const data = await page.evaluate(async () => {
|
|
38006
|
+
if (!indexedDB.databases) return null;
|
|
38007
|
+
const dbInfos = await indexedDB.databases();
|
|
38008
|
+
if (!dbInfos || dbInfos.length === 0) return null;
|
|
38009
|
+
function serializeValue(value) {
|
|
38010
|
+
if (value instanceof ArrayBuffer) {
|
|
38011
|
+
return {
|
|
38012
|
+
__type: "ArrayBuffer",
|
|
38013
|
+
__data: btoa(String.fromCharCode(...new Uint8Array(value)))
|
|
38014
|
+
};
|
|
38015
|
+
}
|
|
38016
|
+
if (ArrayBuffer.isView(value)) {
|
|
38017
|
+
const buf = value.buffer instanceof ArrayBuffer ? value.buffer : value.buffer;
|
|
38018
|
+
return {
|
|
38019
|
+
__type: "TypedArray",
|
|
38020
|
+
__arrayType: value.constructor.name,
|
|
38021
|
+
__data: btoa(String.fromCharCode(...new Uint8Array(buf, value.byteOffset, value.byteLength)))
|
|
38022
|
+
};
|
|
38023
|
+
}
|
|
38024
|
+
if (value instanceof Blob) {
|
|
38025
|
+
return { __type: "Blob", __skipped: true };
|
|
38026
|
+
}
|
|
38027
|
+
if (value instanceof Date) {
|
|
38028
|
+
return { __type: "Date", __data: value.toISOString() };
|
|
38029
|
+
}
|
|
38030
|
+
if (Array.isArray(value)) {
|
|
38031
|
+
return value.map(serializeValue);
|
|
38032
|
+
}
|
|
38033
|
+
if (value !== null && typeof value === "object") {
|
|
38034
|
+
const result = {};
|
|
38035
|
+
for (const [k, v] of Object.entries(value)) {
|
|
38036
|
+
result[k] = serializeValue(v);
|
|
38037
|
+
}
|
|
38038
|
+
return result;
|
|
38039
|
+
}
|
|
38040
|
+
return value;
|
|
38041
|
+
}
|
|
38042
|
+
const databases = [];
|
|
38043
|
+
for (const dbInfo of dbInfos) {
|
|
38044
|
+
if (!dbInfo.name) continue;
|
|
38045
|
+
try {
|
|
38046
|
+
const db = await new Promise((resolve2, reject2) => {
|
|
38047
|
+
const request2 = indexedDB.open(dbInfo.name, dbInfo.version);
|
|
38048
|
+
request2.onsuccess = () => resolve2(request2.result);
|
|
38049
|
+
request2.onerror = () => reject2(request2.error);
|
|
38050
|
+
request2.onupgradeneeded = () => {
|
|
38051
|
+
request2.transaction?.abort();
|
|
38052
|
+
reject2(new Error("version_mismatch"));
|
|
38053
|
+
};
|
|
38054
|
+
});
|
|
38055
|
+
const objectStores = [];
|
|
38056
|
+
for (const storeName of Array.from(db.objectStoreNames)) {
|
|
38057
|
+
try {
|
|
38058
|
+
const tx = db.transaction(storeName, "readonly");
|
|
38059
|
+
const store = tx.objectStore(storeName);
|
|
38060
|
+
const entries = await new Promise(
|
|
38061
|
+
(resolve2, reject2) => {
|
|
38062
|
+
const items = [];
|
|
38063
|
+
const cursorReq = store.openCursor();
|
|
38064
|
+
cursorReq.onsuccess = () => {
|
|
38065
|
+
const cursor = cursorReq.result;
|
|
38066
|
+
if (cursor) {
|
|
38067
|
+
items.push({
|
|
38068
|
+
key: cursor.key,
|
|
38069
|
+
value: serializeValue(cursor.value)
|
|
38070
|
+
});
|
|
38071
|
+
cursor.continue();
|
|
38072
|
+
} else {
|
|
38073
|
+
resolve2(items);
|
|
38074
|
+
}
|
|
38075
|
+
};
|
|
38076
|
+
cursorReq.onerror = () => reject2(cursorReq.error);
|
|
38077
|
+
}
|
|
38078
|
+
);
|
|
38079
|
+
objectStores.push({
|
|
38080
|
+
name: storeName,
|
|
38081
|
+
keyPath: store.keyPath,
|
|
38082
|
+
autoIncrement: store.autoIncrement,
|
|
38083
|
+
entries
|
|
38084
|
+
});
|
|
38085
|
+
} catch {
|
|
38086
|
+
}
|
|
38087
|
+
}
|
|
38088
|
+
db.close();
|
|
38089
|
+
databases.push({
|
|
38090
|
+
name: dbInfo.name,
|
|
38091
|
+
version: dbInfo.version ?? 1,
|
|
38092
|
+
objectStores
|
|
38093
|
+
});
|
|
38094
|
+
} catch {
|
|
38095
|
+
}
|
|
38096
|
+
}
|
|
38097
|
+
return databases.length > 0 ? { databases } : null;
|
|
38098
|
+
});
|
|
38099
|
+
if (!data) return null;
|
|
38100
|
+
const serialized = JSON.stringify(data);
|
|
38101
|
+
if (serialized.length > MAX_TOTAL_SIZE_BYTES) {
|
|
38102
|
+
return null;
|
|
38103
|
+
}
|
|
38104
|
+
return data;
|
|
38105
|
+
} catch {
|
|
38106
|
+
return null;
|
|
38107
|
+
}
|
|
38108
|
+
}
|
|
38109
|
+
async function restoreIndexedDB(page, data) {
|
|
38110
|
+
if (!data.databases || data.databases.length === 0) return;
|
|
38111
|
+
await page.evaluate(async (databases) => {
|
|
38112
|
+
function deserializeValue(value) {
|
|
38113
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
38114
|
+
const obj = value;
|
|
38115
|
+
if (obj.__type === "ArrayBuffer" && typeof obj.__data === "string") {
|
|
38116
|
+
const binary = atob(obj.__data);
|
|
38117
|
+
const bytes = new Uint8Array(binary.length);
|
|
38118
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
38119
|
+
return bytes.buffer;
|
|
38120
|
+
}
|
|
38121
|
+
if (obj.__type === "TypedArray" && typeof obj.__data === "string") {
|
|
38122
|
+
const binary = atob(obj.__data);
|
|
38123
|
+
const bytes = new Uint8Array(binary.length);
|
|
38124
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
38125
|
+
return bytes.buffer;
|
|
38126
|
+
}
|
|
38127
|
+
if (obj.__type === "Date" && typeof obj.__data === "string") {
|
|
38128
|
+
return new Date(obj.__data);
|
|
38129
|
+
}
|
|
38130
|
+
if (obj.__type === "Blob" && obj.__skipped) {
|
|
38131
|
+
return null;
|
|
38132
|
+
}
|
|
38133
|
+
const result = {};
|
|
38134
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
38135
|
+
result[k] = deserializeValue(v);
|
|
38136
|
+
}
|
|
38137
|
+
return result;
|
|
38138
|
+
}
|
|
38139
|
+
if (Array.isArray(value)) {
|
|
38140
|
+
return value.map(deserializeValue);
|
|
38141
|
+
}
|
|
38142
|
+
return value;
|
|
38143
|
+
}
|
|
38144
|
+
for (const dbData of databases) {
|
|
38145
|
+
try {
|
|
38146
|
+
await new Promise((resolve2, reject2) => {
|
|
38147
|
+
const req = indexedDB.deleteDatabase(dbData.name);
|
|
38148
|
+
req.onsuccess = () => resolve2();
|
|
38149
|
+
req.onerror = () => reject2(req.error);
|
|
38150
|
+
req.onblocked = () => resolve2();
|
|
38151
|
+
});
|
|
38152
|
+
const db = await new Promise((resolve2, reject2) => {
|
|
38153
|
+
const request2 = indexedDB.open(dbData.name, dbData.version);
|
|
38154
|
+
request2.onupgradeneeded = () => {
|
|
38155
|
+
const db2 = request2.result;
|
|
38156
|
+
for (const storeData of dbData.objectStores) {
|
|
38157
|
+
if (!db2.objectStoreNames.contains(storeData.name)) {
|
|
38158
|
+
db2.createObjectStore(storeData.name, {
|
|
38159
|
+
keyPath: storeData.keyPath ?? void 0,
|
|
38160
|
+
autoIncrement: storeData.autoIncrement
|
|
38161
|
+
});
|
|
38162
|
+
}
|
|
38163
|
+
}
|
|
38164
|
+
};
|
|
38165
|
+
request2.onsuccess = () => resolve2(request2.result);
|
|
38166
|
+
request2.onerror = () => reject2(request2.error);
|
|
38167
|
+
});
|
|
38168
|
+
for (const storeData of dbData.objectStores) {
|
|
38169
|
+
if (storeData.entries.length === 0) continue;
|
|
38170
|
+
if (!db.objectStoreNames.contains(storeData.name)) continue;
|
|
38171
|
+
try {
|
|
38172
|
+
const tx = db.transaction(storeData.name, "readwrite");
|
|
38173
|
+
const store = tx.objectStore(storeData.name);
|
|
38174
|
+
for (const entry of storeData.entries) {
|
|
38175
|
+
const value = deserializeValue(entry.value);
|
|
38176
|
+
if (storeData.keyPath) {
|
|
38177
|
+
store.put(value);
|
|
38178
|
+
} else {
|
|
38179
|
+
store.put(value, entry.key);
|
|
38180
|
+
}
|
|
38181
|
+
}
|
|
38182
|
+
await new Promise((resolve2, reject2) => {
|
|
38183
|
+
tx.oncomplete = () => resolve2();
|
|
38184
|
+
tx.onerror = () => reject2(tx.error);
|
|
38185
|
+
});
|
|
38186
|
+
} catch {
|
|
38187
|
+
}
|
|
38188
|
+
}
|
|
38189
|
+
db.close();
|
|
38190
|
+
} catch {
|
|
38191
|
+
}
|
|
38192
|
+
}
|
|
38193
|
+
}, data.databases);
|
|
38194
|
+
}
|
|
38195
|
+
|
|
38001
38196
|
// ../browser-core/src/snapshot-analyzer.ts
|
|
38002
38197
|
var logger = consoleLogger;
|
|
38003
38198
|
function setSnapshotAnalyzerLogger(l) {
|
|
@@ -38343,7 +38538,7 @@ function normalizeIconLabelText(role, text) {
|
|
|
38343
38538
|
return ICON_ONLY_ROLES.has(role) ? "(icon)" : "";
|
|
38344
38539
|
}
|
|
38345
38540
|
|
|
38346
|
-
// ../browser-core/src/snapshot-formatter.ts
|
|
38541
|
+
// ../browser-core/src/snapshot-formatter-shared.ts
|
|
38347
38542
|
var MAX_SEARCH_MATCHES = 10;
|
|
38348
38543
|
var INTERACTIVE_LEAF_ROLES = /* @__PURE__ */ new Set([
|
|
38349
38544
|
"button",
|
|
@@ -38378,134 +38573,6 @@ var STRUCTURAL_ROLES = /* @__PURE__ */ new Set([
|
|
|
38378
38573
|
"section",
|
|
38379
38574
|
"iframe"
|
|
38380
38575
|
]);
|
|
38381
|
-
var VISUAL_HEADING_MAX_LENGTH = 60;
|
|
38382
|
-
function hasInteractiveDescendants(element) {
|
|
38383
|
-
if (element.ref && (INTERACTIVE_ROLES.has(element.role) || isClickableByAttribute(element))) return true;
|
|
38384
|
-
for (const child of element.children) {
|
|
38385
|
-
if (hasInteractiveDescendants(child)) return true;
|
|
38386
|
-
}
|
|
38387
|
-
return false;
|
|
38388
|
-
}
|
|
38389
|
-
function isVisualHeading(element, siblings, siblingIndex) {
|
|
38390
|
-
if (element.role !== "generic" && element.role !== "paragraph") return false;
|
|
38391
|
-
if (isClickableByAttribute(element)) return false;
|
|
38392
|
-
const text = getVisualHeadingText(element);
|
|
38393
|
-
if (!text || text.length < 3 || text.length > VISUAL_HEADING_MAX_LENGTH) return false;
|
|
38394
|
-
if (hasInteractiveDescendants(element)) return false;
|
|
38395
|
-
let interactiveCount = 0;
|
|
38396
|
-
for (let i = siblingIndex + 1; i < siblings.length; i++) {
|
|
38397
|
-
const sib = siblings[i];
|
|
38398
|
-
if (sib.role === "heading" || STRUCTURAL_ROLES.has(sib.role)) break;
|
|
38399
|
-
if (sib.role === "generic" || sib.role === "paragraph") {
|
|
38400
|
-
if (!isClickableByAttribute(sib) && !hasInteractiveDescendants(sib)) {
|
|
38401
|
-
const sibText = getVisualHeadingText(sib);
|
|
38402
|
-
if (sibText && sibText.length >= 3 && sibText.length <= VISUAL_HEADING_MAX_LENGTH) {
|
|
38403
|
-
break;
|
|
38404
|
-
}
|
|
38405
|
-
}
|
|
38406
|
-
}
|
|
38407
|
-
if (hasInteractiveDescendants(sib) || isClickableByAttribute(sib)) {
|
|
38408
|
-
interactiveCount++;
|
|
38409
|
-
}
|
|
38410
|
-
}
|
|
38411
|
-
return interactiveCount >= 3;
|
|
38412
|
-
}
|
|
38413
|
-
function getVisualHeadingText(element) {
|
|
38414
|
-
const direct = element.text;
|
|
38415
|
-
if (direct) return direct;
|
|
38416
|
-
for (const child of element.children) {
|
|
38417
|
-
if (TEXT_CARRYING_ROLES.has(child.role) && child.text) return child.text;
|
|
38418
|
-
}
|
|
38419
|
-
return void 0;
|
|
38420
|
-
}
|
|
38421
|
-
function findNextSectionBoundary(siblings, startIndex) {
|
|
38422
|
-
for (let i = startIndex; i < siblings.length; i++) {
|
|
38423
|
-
const sib = siblings[i];
|
|
38424
|
-
if (sib.role === "heading" || STRUCTURAL_ROLES.has(sib.role)) return i;
|
|
38425
|
-
if (isVisualHeading(sib, siblings, i)) return i;
|
|
38426
|
-
}
|
|
38427
|
-
return siblings.length;
|
|
38428
|
-
}
|
|
38429
|
-
function isFieldLabelCandidate(element) {
|
|
38430
|
-
if (element.role !== "generic" && element.role !== "paragraph" && element.role !== "text" && element.role !== "label" && element.role !== "strong" && element.role !== "emphasis") {
|
|
38431
|
-
return false;
|
|
38432
|
-
}
|
|
38433
|
-
if (isClickableByAttribute(element)) return false;
|
|
38434
|
-
if (hasInteractiveDescendants(element)) return false;
|
|
38435
|
-
const text = getFieldLabelText(element);
|
|
38436
|
-
if (!text || text.length < 1 || text.length > VISUAL_HEADING_MAX_LENGTH) return false;
|
|
38437
|
-
return true;
|
|
38438
|
-
}
|
|
38439
|
-
var FIELD_LABEL_TEXT_ROLES = /* @__PURE__ */ new Set([
|
|
38440
|
-
"generic",
|
|
38441
|
-
"paragraph",
|
|
38442
|
-
"text",
|
|
38443
|
-
"strong",
|
|
38444
|
-
"emphasis",
|
|
38445
|
-
"label",
|
|
38446
|
-
"heading"
|
|
38447
|
-
]);
|
|
38448
|
-
function getFieldLabelText(element) {
|
|
38449
|
-
if (element.text) return element.text.trim();
|
|
38450
|
-
if (element.inputValue && !INTERACTIVE_ROLES.has(element.role)) return element.inputValue.trim();
|
|
38451
|
-
for (const child of element.children) {
|
|
38452
|
-
if (FIELD_LABEL_TEXT_ROLES.has(child.role)) {
|
|
38453
|
-
if (child.text) return child.text.trim();
|
|
38454
|
-
if (child.inputValue && !INTERACTIVE_ROLES.has(child.role)) return child.inputValue.trim();
|
|
38455
|
-
}
|
|
38456
|
-
}
|
|
38457
|
-
return void 0;
|
|
38458
|
-
}
|
|
38459
|
-
function findFieldLabelFromSiblings(siblings, interactiveIndex) {
|
|
38460
|
-
for (let i = interactiveIndex - 1; i >= 0; i--) {
|
|
38461
|
-
const sib = siblings[i];
|
|
38462
|
-
if (INTERACTIVE_ROLES.has(sib.role) || isClickableByAttribute(sib) || STRUCTURAL_ROLES.has(sib.role) || sib.role === "heading") {
|
|
38463
|
-
break;
|
|
38464
|
-
}
|
|
38465
|
-
if (isFieldLabelCandidate(sib)) {
|
|
38466
|
-
return getFieldLabelText(sib);
|
|
38467
|
-
}
|
|
38468
|
-
if (sib.children.length >= 1 && sib.children.length <= 4) {
|
|
38469
|
-
const containerLabel = resolveContainerFieldLabel(sib);
|
|
38470
|
-
if (containerLabel) return containerLabel;
|
|
38471
|
-
}
|
|
38472
|
-
if (sib.children.length > 4) break;
|
|
38473
|
-
}
|
|
38474
|
-
return void 0;
|
|
38475
|
-
}
|
|
38476
|
-
function findFieldLabelInContext(_element, siblings, siblingIndex) {
|
|
38477
|
-
return findFieldLabelFromSiblings(siblings, siblingIndex);
|
|
38478
|
-
}
|
|
38479
|
-
function resolveContainerFieldLabel(container) {
|
|
38480
|
-
const kids = container.children;
|
|
38481
|
-
if (kids.length < 2 || kids.length > 4) return void 0;
|
|
38482
|
-
const firstChild = kids[0];
|
|
38483
|
-
if (isFieldLabelCandidate(firstChild)) {
|
|
38484
|
-
return getFieldLabelText(firstChild);
|
|
38485
|
-
}
|
|
38486
|
-
return void 0;
|
|
38487
|
-
}
|
|
38488
|
-
function shouldDropInheritedFieldLabel(element, inheritedFieldLabel) {
|
|
38489
|
-
if (!inheritedFieldLabel) return false;
|
|
38490
|
-
if (INTERACTIVE_LEAF_ROLES.has(element.role)) return false;
|
|
38491
|
-
if (!isClickableByAttribute(element)) return false;
|
|
38492
|
-
const directText = getElementText(element);
|
|
38493
|
-
if (directText) {
|
|
38494
|
-
return directText.toLowerCase() !== inheritedFieldLabel.toLowerCase();
|
|
38495
|
-
}
|
|
38496
|
-
const childTexts = [];
|
|
38497
|
-
for (const child of element.children) {
|
|
38498
|
-
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38499
|
-
const text = getElementText(child);
|
|
38500
|
-
if (text && TEXT_CARRYING_ROLES.has(child.role)) {
|
|
38501
|
-
childTexts.push(text);
|
|
38502
|
-
}
|
|
38503
|
-
}
|
|
38504
|
-
}
|
|
38505
|
-
const composedText = childTexts.join(" ");
|
|
38506
|
-
if (!composedText) return false;
|
|
38507
|
-
return composedText.toLowerCase() !== inheritedFieldLabel.toLowerCase();
|
|
38508
|
-
}
|
|
38509
38576
|
var TEXT_CARRYING_ROLES = /* @__PURE__ */ new Set([
|
|
38510
38577
|
"generic",
|
|
38511
38578
|
"paragraph",
|
|
@@ -38516,12 +38583,11 @@ var TEXT_CARRYING_ROLES = /* @__PURE__ */ new Set([
|
|
|
38516
38583
|
"blockquote",
|
|
38517
38584
|
"caption"
|
|
38518
38585
|
]);
|
|
38586
|
+
var VISUAL_HEADING_MAX_LENGTH = 60;
|
|
38519
38587
|
var STATUS_WORDS = /* @__PURE__ */ new Set(["favorable", "unfavorable", "success", "error", "warning", "pending"]);
|
|
38520
38588
|
var BLANK_PATTERNS = [
|
|
38521
38589
|
/\s*\(Blank\)\s*/gi,
|
|
38522
|
-
// "(Blank)" in any case
|
|
38523
38590
|
/\s*\(blank\)\s*/gi
|
|
38524
|
-
// Redundant but explicit
|
|
38525
38591
|
];
|
|
38526
38592
|
var MENU_TRIGGER_PATTERNS = [
|
|
38527
38593
|
/^Open menu for /i,
|
|
@@ -38536,21 +38602,77 @@ var SECTION_BOUNDARY_ROLES = /* @__PURE__ */ new Set([
|
|
|
38536
38602
|
"article",
|
|
38537
38603
|
"section",
|
|
38538
38604
|
"complementary"
|
|
38539
|
-
// sidebars
|
|
38540
38605
|
]);
|
|
38606
|
+
var FRAMEWORK_NOISE_RE = /^(ng-binding|ng-scope|ng-pristine|ng-dirty|ng-valid|ng-invalid|ng-untouched|ng-touched|v-enter|v-leave)$/;
|
|
38541
38607
|
function normalizeSearchText(text) {
|
|
38542
38608
|
return text.toLowerCase().replace(/[-_.,;:!?'"()\[\]{}\/\\@#$%^&*+=<>~`|]/g, "").replace(/\s+/g, " ").trim();
|
|
38543
38609
|
}
|
|
38544
|
-
function
|
|
38545
|
-
|
|
38546
|
-
|
|
38547
|
-
|
|
38548
|
-
|
|
38549
|
-
|
|
38550
|
-
|
|
38610
|
+
function isActiveElement(element) {
|
|
38611
|
+
return element.attributes["active"] !== void 0 || element.rawLine.includes("[active]");
|
|
38612
|
+
}
|
|
38613
|
+
function isDisabledElement(element) {
|
|
38614
|
+
return element.attributes["disabled"] !== void 0 || element.rawLine.includes("[disabled]");
|
|
38615
|
+
}
|
|
38616
|
+
function isClickableByAttribute(element) {
|
|
38617
|
+
return element.attributes["cursor"] === "pointer";
|
|
38618
|
+
}
|
|
38619
|
+
function isActionableClickableGeneric(element) {
|
|
38620
|
+
return isClickableByAttribute(element) && !INTERACTIVE_ROLES.has(element.role);
|
|
38621
|
+
}
|
|
38622
|
+
function isSearchInteractiveElement(element) {
|
|
38623
|
+
return INTERACTIVE_LEAF_ROLES.has(element.role) || isActionableClickableGeneric(element);
|
|
38624
|
+
}
|
|
38625
|
+
function getElementText(el) {
|
|
38626
|
+
if (el.text && el.inputValue && FRAMEWORK_NOISE_RE.test(el.text.trim())) {
|
|
38627
|
+
return el.inputValue;
|
|
38628
|
+
}
|
|
38629
|
+
return el.text || el.inputValue;
|
|
38630
|
+
}
|
|
38631
|
+
function composeLabel(element) {
|
|
38632
|
+
const directText = getElementText(element);
|
|
38633
|
+
if (directText) return directText;
|
|
38634
|
+
const textParts = [];
|
|
38635
|
+
function collectText(el, depth) {
|
|
38636
|
+
if (depth > 3) return;
|
|
38637
|
+
const text = getElementText(el);
|
|
38638
|
+
if (text && TEXT_CARRYING_ROLES.has(el.role)) {
|
|
38639
|
+
textParts.push(text);
|
|
38640
|
+
}
|
|
38641
|
+
for (const child of el.children) {
|
|
38642
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38643
|
+
collectText(child, depth + 1);
|
|
38644
|
+
}
|
|
38645
|
+
}
|
|
38646
|
+
}
|
|
38647
|
+
for (const child of element.children) {
|
|
38648
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38649
|
+
collectText(child, 0);
|
|
38650
|
+
}
|
|
38651
|
+
}
|
|
38652
|
+
return textParts.join(" | ") || element.role;
|
|
38653
|
+
}
|
|
38654
|
+
function getDisplayText(element, options) {
|
|
38655
|
+
const isClickable = isActionableClickableGeneric(element);
|
|
38656
|
+
const rawTextSource = options?.overrideLabel ?? (isClickable ? composeLabel(element) : element.text ?? "");
|
|
38657
|
+
return normalizeIconLabelText(element.role, rawTextSource);
|
|
38658
|
+
}
|
|
38659
|
+
function hasInteractiveDescendants(element) {
|
|
38660
|
+
if (element.ref && (INTERACTIVE_ROLES.has(element.role) || isClickableByAttribute(element))) return true;
|
|
38661
|
+
for (const child of element.children) {
|
|
38662
|
+
if (hasInteractiveDescendants(child)) return true;
|
|
38663
|
+
}
|
|
38664
|
+
return false;
|
|
38665
|
+
}
|
|
38666
|
+
function subtreeContainsActive(element) {
|
|
38667
|
+
if (isActiveElement(element)) return true;
|
|
38668
|
+
for (const child of element.children) {
|
|
38669
|
+
if (subtreeContainsActive(child)) return true;
|
|
38551
38670
|
}
|
|
38552
38671
|
return false;
|
|
38553
38672
|
}
|
|
38673
|
+
function cleanLabel(text) {
|
|
38674
|
+
return text.replace(/\s+/g, " ").replace(/…+/g, "...").trim();
|
|
38675
|
+
}
|
|
38554
38676
|
function isBlankValue(value) {
|
|
38555
38677
|
if (!value) return true;
|
|
38556
38678
|
const trimmed = value.trim().toLowerCase();
|
|
@@ -38590,160 +38712,15 @@ function extractDataValue(text) {
|
|
|
38590
38712
|
}
|
|
38591
38713
|
return { label: cleanLabel(cleaned), status };
|
|
38592
38714
|
}
|
|
38593
|
-
function
|
|
38594
|
-
if (
|
|
38595
|
-
|
|
38596
|
-
|
|
38597
|
-
|
|
38598
|
-
|
|
38599
|
-
|
|
38600
|
-
if (el.ref === activeElementRef) {
|
|
38601
|
-
return true;
|
|
38602
|
-
}
|
|
38603
|
-
for (const child of el.children) {
|
|
38604
|
-
if (findPath(child)) return true;
|
|
38605
|
-
}
|
|
38606
|
-
if (el.ref) path5.pop();
|
|
38607
|
-
return false;
|
|
38608
|
-
}
|
|
38609
|
-
for (const el of elements) {
|
|
38610
|
-
if (findPath(el)) break;
|
|
38611
|
-
}
|
|
38612
|
-
for (let i = path5.length - 1; i >= 0; i--) {
|
|
38613
|
-
if (SECTION_BOUNDARY_ROLES.has(path5[i].role)) {
|
|
38614
|
-
return path5[i].ref;
|
|
38615
|
-
}
|
|
38616
|
-
}
|
|
38617
|
-
return null;
|
|
38618
|
-
}
|
|
38619
|
-
function searchElements(elements, searchTerms, scopeRef = null) {
|
|
38620
|
-
const allMatches = [];
|
|
38621
|
-
const normalizedTerms = searchTerms.map((t) => normalizeSearchText(t)).filter(Boolean);
|
|
38622
|
-
if (normalizedTerms.length === 0) return { matches: [], totalFound: 0 };
|
|
38623
|
-
function searchElement(el, inScope) {
|
|
38624
|
-
const nowInScope = inScope || el.ref === scopeRef || scopeRef === null;
|
|
38625
|
-
if (el.ref && nowInScope) {
|
|
38626
|
-
const searchText = [el.text, el.inputValue].filter(Boolean).join(" ");
|
|
38627
|
-
const normalizedSearchText = normalizeSearchText(searchText);
|
|
38628
|
-
for (const term of normalizedTerms) {
|
|
38629
|
-
if (normalizedSearchText.includes(term)) {
|
|
38630
|
-
const normalizedLabel = normalizeIconLabelText(el.role, el.text || "");
|
|
38631
|
-
allMatches.push({
|
|
38632
|
-
ref: el.ref,
|
|
38633
|
-
role: el.role,
|
|
38634
|
-
label: normalizedLabel || el.role,
|
|
38635
|
-
term,
|
|
38636
|
-
isInteractive: INTERACTIVE_LEAF_ROLES.has(el.role)
|
|
38637
|
-
});
|
|
38638
|
-
break;
|
|
38639
|
-
}
|
|
38640
|
-
}
|
|
38641
|
-
}
|
|
38642
|
-
for (const child of el.children) {
|
|
38643
|
-
searchElement(child, nowInScope);
|
|
38644
|
-
}
|
|
38645
|
-
}
|
|
38646
|
-
for (const el of elements) {
|
|
38647
|
-
searchElement(el, scopeRef === null);
|
|
38648
|
-
}
|
|
38649
|
-
const totalFound = allMatches.length;
|
|
38650
|
-
allMatches.sort((a, b) => {
|
|
38651
|
-
if (a.isInteractive && !b.isInteractive) return -1;
|
|
38652
|
-
if (!a.isInteractive && b.isInteractive) return 1;
|
|
38653
|
-
return 0;
|
|
38654
|
-
});
|
|
38655
|
-
return {
|
|
38656
|
-
matches: allMatches.slice(0, MAX_SEARCH_MATCHES),
|
|
38657
|
-
totalFound
|
|
38658
|
-
};
|
|
38659
|
-
}
|
|
38660
|
-
function findElementInSections(sections, targetRef, ancestors = []) {
|
|
38661
|
-
for (const section of sections) {
|
|
38662
|
-
const newAncestors = [...ancestors, section];
|
|
38663
|
-
const path5 = newAncestors.map((s) => s.heading);
|
|
38664
|
-
if (section.elements.some((el) => el.ref === targetRef)) {
|
|
38665
|
-
return { section, ancestors: newAncestors, path: path5 };
|
|
38666
|
-
}
|
|
38667
|
-
const found = findElementInSections(section.subsections, targetRef, newAncestors);
|
|
38668
|
-
if (found) return found;
|
|
38669
|
-
}
|
|
38670
|
-
return null;
|
|
38671
|
-
}
|
|
38672
|
-
function populateSearchContext(matches, sections) {
|
|
38673
|
-
for (const match of matches) {
|
|
38674
|
-
const result = findElementInSections(sections, match.ref);
|
|
38675
|
-
if (result) {
|
|
38676
|
-
const { section, ancestors, path: path5 } = result;
|
|
38677
|
-
const inFocusedDialog = ancestors.some((s) => s.isFocused);
|
|
38678
|
-
const inBackground = section.isBackground || ancestors.some((s) => s.isBackground);
|
|
38679
|
-
if (inFocusedDialog) {
|
|
38680
|
-
match.context = "focused";
|
|
38681
|
-
} else if (inBackground) {
|
|
38682
|
-
match.context = "background";
|
|
38683
|
-
} else {
|
|
38684
|
-
match.context = "foreground";
|
|
38685
|
-
}
|
|
38686
|
-
const SKIP_HEADINGS = ["generic", "main", "iframe"];
|
|
38687
|
-
match.sectionPath = path5.filter((p) => !SKIP_HEADINGS.includes(p.toLowerCase())).slice(-3).join(" > ");
|
|
38688
|
-
}
|
|
38689
|
-
}
|
|
38690
|
-
}
|
|
38691
|
-
function sortMatchesByContext(matches) {
|
|
38692
|
-
const contextOrder = {
|
|
38693
|
-
focused: 0,
|
|
38694
|
-
foreground: 1,
|
|
38695
|
-
background: 2
|
|
38696
|
-
};
|
|
38697
|
-
return [...matches].sort((a, b) => {
|
|
38698
|
-
const aContext = contextOrder[a.context ?? "foreground"] ?? 1;
|
|
38699
|
-
const bContext = contextOrder[b.context ?? "foreground"] ?? 1;
|
|
38700
|
-
if (aContext !== bContext) return aContext - bContext;
|
|
38701
|
-
if (a.isInteractive && !b.isInteractive) return -1;
|
|
38702
|
-
if (!a.isInteractive && b.isInteractive) return 1;
|
|
38703
|
-
return 0;
|
|
38704
|
-
});
|
|
38705
|
-
}
|
|
38706
|
-
function cleanLabel(text) {
|
|
38707
|
-
return text.replace(/\s+/g, " ").replace(/…+/g, "...").trim();
|
|
38708
|
-
}
|
|
38709
|
-
function isActiveElement(element) {
|
|
38710
|
-
return element.attributes["active"] !== void 0 || element.rawLine.includes("[active]");
|
|
38711
|
-
}
|
|
38712
|
-
function isDisabledElement(element) {
|
|
38713
|
-
return element.attributes["disabled"] !== void 0 || element.rawLine.includes("[disabled]");
|
|
38714
|
-
}
|
|
38715
|
-
function isClickableByAttribute(element) {
|
|
38716
|
-
return element.attributes["cursor"] === "pointer";
|
|
38717
|
-
}
|
|
38718
|
-
var FRAMEWORK_NOISE_RE = /^(ng-binding|ng-scope|ng-pristine|ng-dirty|ng-valid|ng-invalid|ng-untouched|ng-touched|v-enter|v-leave)$/;
|
|
38719
|
-
function getElementText(el) {
|
|
38720
|
-
if (el.text && el.inputValue && FRAMEWORK_NOISE_RE.test(el.text.trim())) {
|
|
38721
|
-
return el.inputValue;
|
|
38722
|
-
}
|
|
38723
|
-
return el.text || el.inputValue;
|
|
38724
|
-
}
|
|
38725
|
-
function composeLabel(element) {
|
|
38726
|
-
const directText = getElementText(element);
|
|
38727
|
-
if (directText) return directText;
|
|
38728
|
-
const textParts = [];
|
|
38729
|
-
function collectText(el, depth) {
|
|
38730
|
-
if (depth > 3) return;
|
|
38731
|
-
const text = getElementText(el);
|
|
38732
|
-
if (text && TEXT_CARRYING_ROLES.has(el.role)) {
|
|
38733
|
-
textParts.push(text);
|
|
38734
|
-
}
|
|
38735
|
-
for (const child of el.children) {
|
|
38736
|
-
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38737
|
-
collectText(child, depth + 1);
|
|
38738
|
-
}
|
|
38739
|
-
}
|
|
38740
|
-
}
|
|
38741
|
-
for (const child of element.children) {
|
|
38742
|
-
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38743
|
-
collectText(child, 0);
|
|
38744
|
-
}
|
|
38715
|
+
function isMenuTriggerNoise(element) {
|
|
38716
|
+
if (isActiveElement(element)) return false;
|
|
38717
|
+
if (element.role !== "button") return false;
|
|
38718
|
+
const text = element.text || "";
|
|
38719
|
+
if (!text.trim()) return false;
|
|
38720
|
+
for (const pattern of MENU_TRIGGER_PATTERNS) {
|
|
38721
|
+
if (pattern.test(text)) return true;
|
|
38745
38722
|
}
|
|
38746
|
-
return
|
|
38723
|
+
return false;
|
|
38747
38724
|
}
|
|
38748
38725
|
function countElementsWithRefs(element) {
|
|
38749
38726
|
let count = element.ref ? 1 : 0;
|
|
@@ -38752,74 +38729,23 @@ function countElementsWithRefs(element) {
|
|
|
38752
38729
|
}
|
|
38753
38730
|
return count;
|
|
38754
38731
|
}
|
|
38755
|
-
function
|
|
38756
|
-
|
|
38757
|
-
|
|
38758
|
-
|
|
38759
|
-
|
|
38760
|
-
if (STRUCTURAL_ROLES.has(child.role)) continue;
|
|
38761
|
-
if (INTERACTIVE_LEAF_ROLES.has(child.role) && child.ref) {
|
|
38762
|
-
result.push(formatElement(child));
|
|
38763
|
-
continue;
|
|
38764
|
-
}
|
|
38765
|
-
if (child.role === "listitem" && child.ref) {
|
|
38766
|
-
const text = child.text || composeLabel(child);
|
|
38767
|
-
if (text && text !== "listitem") {
|
|
38768
|
-
result.push(formatElement(child, { overrideLabel: text }));
|
|
38769
|
-
continue;
|
|
38770
|
-
}
|
|
38771
|
-
}
|
|
38772
|
-
if (isClickableByAttribute(child) && child.ref) {
|
|
38773
|
-
result.push(formatElement(child));
|
|
38732
|
+
function collectComboboxOptions(element) {
|
|
38733
|
+
const options = [];
|
|
38734
|
+
function walk(el) {
|
|
38735
|
+
if (el.role === "option" && el.text?.trim()) {
|
|
38736
|
+
options.push(el.text.trim());
|
|
38774
38737
|
}
|
|
38775
|
-
|
|
38776
|
-
|
|
38777
|
-
}
|
|
38778
|
-
function hasActionableChildren(element) {
|
|
38779
|
-
const children2 = [];
|
|
38780
|
-
collectExpandedChildren(element, children2);
|
|
38781
|
-
return children2.length > 0;
|
|
38782
|
-
}
|
|
38783
|
-
function isExpandedWithActionableChildren(element) {
|
|
38784
|
-
if (!isExpandedElement(element)) return false;
|
|
38785
|
-
if (element.role === "combobox") return false;
|
|
38786
|
-
return hasActionableChildren(element);
|
|
38787
|
-
}
|
|
38788
|
-
function composeTriggerLabel(element) {
|
|
38789
|
-
const ariaLabel = element.attributes["aria-label"];
|
|
38790
|
-
if (ariaLabel) return ariaLabel;
|
|
38791
|
-
const fullText = element.text || "";
|
|
38792
|
-
if (fullText) {
|
|
38793
|
-
let collectLeafTexts2 = function(el) {
|
|
38794
|
-
for (const child of el.children) {
|
|
38795
|
-
const text = child.text?.trim();
|
|
38796
|
-
if (text) {
|
|
38797
|
-
leafTexts.push(text);
|
|
38798
|
-
}
|
|
38799
|
-
collectLeafTexts2(child);
|
|
38800
|
-
}
|
|
38801
|
-
};
|
|
38802
|
-
var collectLeafTexts = collectLeafTexts2;
|
|
38803
|
-
const leafTexts = [];
|
|
38804
|
-
collectLeafTexts2(element);
|
|
38805
|
-
if (leafTexts.length > 0) {
|
|
38806
|
-
let stripped = fullText;
|
|
38807
|
-
for (const lt of leafTexts) {
|
|
38808
|
-
stripped = stripped.replace(lt, "");
|
|
38809
|
-
}
|
|
38810
|
-
stripped = stripped.replace(/\s+/g, " ").trim();
|
|
38811
|
-
if (stripped) return stripped;
|
|
38738
|
+
for (const child of el.children) {
|
|
38739
|
+
walk(child);
|
|
38812
38740
|
}
|
|
38813
38741
|
}
|
|
38814
|
-
return element.role;
|
|
38815
|
-
}
|
|
38816
|
-
function subtreeContainsActive(element) {
|
|
38817
|
-
if (isActiveElement(element)) return true;
|
|
38818
38742
|
for (const child of element.children) {
|
|
38819
|
-
|
|
38743
|
+
walk(child);
|
|
38820
38744
|
}
|
|
38821
|
-
return
|
|
38745
|
+
return options.length > 0 ? options : void 0;
|
|
38822
38746
|
}
|
|
38747
|
+
|
|
38748
|
+
// ../browser-core/src/snapshot-formatter-grid.ts
|
|
38823
38749
|
function findDescendantByRole(el, role) {
|
|
38824
38750
|
if (el.role === role) return el;
|
|
38825
38751
|
for (const child of el.children) {
|
|
@@ -38864,6 +38790,176 @@ function isWidgetTable(element) {
|
|
|
38864
38790
|
}
|
|
38865
38791
|
return totalCells > 0 && interactiveCells >= totalCells * 0.5;
|
|
38866
38792
|
}
|
|
38793
|
+
function gridCellPriority(el) {
|
|
38794
|
+
if (el.isActive) return 5;
|
|
38795
|
+
if (FORM_INPUT_ROLES.has(el.role)) return 4;
|
|
38796
|
+
if (el.isClickableGeneric) return 3;
|
|
38797
|
+
if (el.role !== "button") return 2;
|
|
38798
|
+
return 1;
|
|
38799
|
+
}
|
|
38800
|
+
function extractCellText(el) {
|
|
38801
|
+
const findFirstParagraph = (node) => {
|
|
38802
|
+
if (node.role === "paragraph" && node.text) {
|
|
38803
|
+
return node.text.trim();
|
|
38804
|
+
}
|
|
38805
|
+
for (const child of node.children) {
|
|
38806
|
+
if (child.role === "generic" || child.role === "paragraph") {
|
|
38807
|
+
const found = findFirstParagraph(child);
|
|
38808
|
+
if (found) return found;
|
|
38809
|
+
}
|
|
38810
|
+
}
|
|
38811
|
+
return null;
|
|
38812
|
+
};
|
|
38813
|
+
const paragraphText = findFirstParagraph(el);
|
|
38814
|
+
if (paragraphText) return paragraphText;
|
|
38815
|
+
const text = el.text?.trim();
|
|
38816
|
+
if (text) return text;
|
|
38817
|
+
return null;
|
|
38818
|
+
}
|
|
38819
|
+
function extractGridCell(cellEl) {
|
|
38820
|
+
const interactiveElements = [];
|
|
38821
|
+
const findInteractive = (el) => {
|
|
38822
|
+
if (isClickableByAttribute(el) && el.ref && el.role === "generic") {
|
|
38823
|
+
const childTexts = [];
|
|
38824
|
+
for (const child of el.children) {
|
|
38825
|
+
if (child.role === "generic") {
|
|
38826
|
+
const childText = child.text || child.inputValue;
|
|
38827
|
+
if (childText) childTexts.push(childText);
|
|
38828
|
+
}
|
|
38829
|
+
}
|
|
38830
|
+
interactiveElements.push({
|
|
38831
|
+
ref: el.ref,
|
|
38832
|
+
column: el.attributes["label"] || childTexts[0] || "",
|
|
38833
|
+
value: childTexts.join(" - ") || el.text || el.inputValue || "",
|
|
38834
|
+
role: el.role,
|
|
38835
|
+
isClickableGeneric: true,
|
|
38836
|
+
isActive: isActiveElement(el)
|
|
38837
|
+
});
|
|
38838
|
+
}
|
|
38839
|
+
if (INTERACTIVE_LEAF_ROLES.has(el.role) && el.ref) {
|
|
38840
|
+
const value2 = el.role === "checkbox" ? el.attributes["checked"] === "true" ? "checked" : "unchecked" : el.inputValue || el.text || "";
|
|
38841
|
+
interactiveElements.push({
|
|
38842
|
+
ref: el.ref,
|
|
38843
|
+
column: el.attributes["label"] || el.text || "",
|
|
38844
|
+
value: value2,
|
|
38845
|
+
role: el.role,
|
|
38846
|
+
isClickableGeneric: false,
|
|
38847
|
+
isActive: isActiveElement(el)
|
|
38848
|
+
});
|
|
38849
|
+
}
|
|
38850
|
+
for (const child of el.children) findInteractive(child);
|
|
38851
|
+
};
|
|
38852
|
+
findInteractive(cellEl);
|
|
38853
|
+
if (interactiveElements.length === 0) {
|
|
38854
|
+
const textValue = extractCellText(cellEl);
|
|
38855
|
+
if (textValue) {
|
|
38856
|
+
return {
|
|
38857
|
+
ref: cellEl.ref,
|
|
38858
|
+
column: cellEl.text || "",
|
|
38859
|
+
value: textValue,
|
|
38860
|
+
hasValue: true
|
|
38861
|
+
};
|
|
38862
|
+
}
|
|
38863
|
+
return null;
|
|
38864
|
+
}
|
|
38865
|
+
const found = interactiveElements.reduce(
|
|
38866
|
+
(best, current) => gridCellPriority(current) > gridCellPriority(best) ? current : best
|
|
38867
|
+
);
|
|
38868
|
+
const column = stripBlankPatterns(found.column);
|
|
38869
|
+
const value = isBlankValue(found.value) ? "" : stripBlankPatterns(found.value).trim();
|
|
38870
|
+
const gridcellLabel = cellEl.text ? stripBlankPatterns(cellEl.text).trim() : void 0;
|
|
38871
|
+
return {
|
|
38872
|
+
ref: found.ref,
|
|
38873
|
+
column: column.trim(),
|
|
38874
|
+
value,
|
|
38875
|
+
hasValue: value !== "",
|
|
38876
|
+
gridcellLabel: gridcellLabel || void 0,
|
|
38877
|
+
role: found.role
|
|
38878
|
+
};
|
|
38879
|
+
}
|
|
38880
|
+
function reconcileCellColumn(cell, knownColumns) {
|
|
38881
|
+
if (knownColumns.has(cell.column)) return cell;
|
|
38882
|
+
if (cell.gridcellLabel && knownColumns.has(cell.gridcellLabel)) {
|
|
38883
|
+
const newValue = cell.column || cell.value;
|
|
38884
|
+
const cleanValue = isBlankValue(newValue) ? "" : newValue.trim();
|
|
38885
|
+
return {
|
|
38886
|
+
...cell,
|
|
38887
|
+
column: cell.gridcellLabel,
|
|
38888
|
+
value: cleanValue,
|
|
38889
|
+
hasValue: cleanValue !== ""
|
|
38890
|
+
};
|
|
38891
|
+
}
|
|
38892
|
+
let bestMatch = "";
|
|
38893
|
+
for (const col of knownColumns) {
|
|
38894
|
+
if (cell.column.startsWith(col) && col.length > bestMatch.length && (cell.column.length === col.length || cell.column[col.length] === " ")) {
|
|
38895
|
+
bestMatch = col;
|
|
38896
|
+
}
|
|
38897
|
+
}
|
|
38898
|
+
if (bestMatch) {
|
|
38899
|
+
const remainder = cell.column.slice(bestMatch.length).trim();
|
|
38900
|
+
const newValue = isBlankValue(remainder) ? "" : remainder;
|
|
38901
|
+
return {
|
|
38902
|
+
...cell,
|
|
38903
|
+
column: bestMatch,
|
|
38904
|
+
value: newValue || cell.value,
|
|
38905
|
+
hasValue: (newValue || cell.value) !== ""
|
|
38906
|
+
};
|
|
38907
|
+
}
|
|
38908
|
+
return cell;
|
|
38909
|
+
}
|
|
38910
|
+
function reconcileGridCells(grid) {
|
|
38911
|
+
if (grid.columns.length === 0) return grid;
|
|
38912
|
+
const knownColumns = new Set(grid.columns.map((c2) => c2.name));
|
|
38913
|
+
return {
|
|
38914
|
+
...grid,
|
|
38915
|
+
rows: grid.rows.map((row) => {
|
|
38916
|
+
const reconciledCells = row.cells.map((cell) => {
|
|
38917
|
+
const reconciled = reconcileCellColumn(cell, knownColumns);
|
|
38918
|
+
if (knownColumns.has(reconciled.column)) return reconciled;
|
|
38919
|
+
if (grid.columnByPosition && cell.positionInRow !== void 0 && grid.headerChildCount !== void 0 && row.totalChildren === grid.headerChildCount) {
|
|
38920
|
+
const positionalColumn = grid.columnByPosition.get(cell.positionInRow);
|
|
38921
|
+
if (positionalColumn) {
|
|
38922
|
+
const newValue = cell.column || cell.value;
|
|
38923
|
+
const cleanValue = isBlankValue(newValue) ? "" : newValue.trim();
|
|
38924
|
+
return {
|
|
38925
|
+
...cell,
|
|
38926
|
+
column: positionalColumn,
|
|
38927
|
+
value: cleanValue,
|
|
38928
|
+
hasValue: cleanValue !== ""
|
|
38929
|
+
};
|
|
38930
|
+
}
|
|
38931
|
+
}
|
|
38932
|
+
return reconciled;
|
|
38933
|
+
});
|
|
38934
|
+
if (grid.headerCellPositions && row.cellPositions) {
|
|
38935
|
+
const claimedColumns = new Set(
|
|
38936
|
+
reconciledCells.filter((c2) => knownColumns.has(c2.column)).map((c2) => c2.column)
|
|
38937
|
+
);
|
|
38938
|
+
for (let idx = 0; idx < reconciledCells.length; idx++) {
|
|
38939
|
+
const cell = reconciledCells[idx];
|
|
38940
|
+
if (knownColumns.has(cell.column) || cell.positionInRow === void 0) continue;
|
|
38941
|
+
const cellOrdinal = row.cellPositions.indexOf(cell.positionInRow);
|
|
38942
|
+
if (cellOrdinal >= 0 && cellOrdinal < grid.headerCellPositions.length) {
|
|
38943
|
+
const headerPos = grid.headerCellPositions[cellOrdinal];
|
|
38944
|
+
const positionalColumn = grid.columnByPosition?.get(headerPos);
|
|
38945
|
+
if (positionalColumn && !claimedColumns.has(positionalColumn)) {
|
|
38946
|
+
const newValue = cell.column || cell.value;
|
|
38947
|
+
const cleanValue = isBlankValue(newValue) ? "" : newValue.trim();
|
|
38948
|
+
reconciledCells[idx] = {
|
|
38949
|
+
...cell,
|
|
38950
|
+
column: positionalColumn,
|
|
38951
|
+
value: cleanValue,
|
|
38952
|
+
hasValue: cleanValue !== ""
|
|
38953
|
+
};
|
|
38954
|
+
claimedColumns.add(positionalColumn);
|
|
38955
|
+
}
|
|
38956
|
+
}
|
|
38957
|
+
}
|
|
38958
|
+
}
|
|
38959
|
+
return { ...row, cells: reconciledCells };
|
|
38960
|
+
})
|
|
38961
|
+
};
|
|
38962
|
+
}
|
|
38867
38963
|
function detectGrid(element) {
|
|
38868
38964
|
if (element.role !== "grid" && element.role !== "treegrid" && element.role !== "table") {
|
|
38869
38965
|
return null;
|
|
@@ -38874,18 +38970,28 @@ function detectGrid(element) {
|
|
|
38874
38970
|
let headerRowRef = null;
|
|
38875
38971
|
const columnByPosition = /* @__PURE__ */ new Map();
|
|
38876
38972
|
let headerChildCount;
|
|
38973
|
+
let headerCellPositions;
|
|
38974
|
+
const isRowLike = (el) => {
|
|
38975
|
+
if (el.role === "row") return true;
|
|
38976
|
+
const cellCount = el.children.filter(
|
|
38977
|
+
(c2) => c2.role === "cell" || c2.role === "gridcell"
|
|
38978
|
+
).length;
|
|
38979
|
+
return cellCount >= 2;
|
|
38980
|
+
};
|
|
38877
38981
|
const processRow = (rowEl, index) => {
|
|
38878
|
-
if (rowEl
|
|
38982
|
+
if (!isRowLike(rowEl)) return null;
|
|
38879
38983
|
const hasColumnHeaders = rowEl.children.some((c2) => c2.role === "columnheader");
|
|
38880
38984
|
if (hasColumnHeaders) {
|
|
38881
38985
|
headerRowRef = rowEl.ref;
|
|
38882
38986
|
const columnHeaders = rowEl.children.filter((c2) => c2.role === "columnheader");
|
|
38883
|
-
const
|
|
38987
|
+
const childful = columnHeaders.filter((c2) => c2.children.length > 0);
|
|
38988
|
+
const textBearingChildless = columnHeaders.filter((c2) => c2.children.length === 0 && c2.text);
|
|
38989
|
+
const skipChildlessHeaders = childful.length > 0 && textBearingChildless.length <= childful.length;
|
|
38884
38990
|
const columnsBefore = columns.length;
|
|
38885
38991
|
for (let i = 0; i < rowEl.children.length; i++) {
|
|
38886
38992
|
const child = rowEl.children[i];
|
|
38887
38993
|
if (child.role === "columnheader") {
|
|
38888
|
-
if (
|
|
38994
|
+
if (skipChildlessHeaders && child.children.length === 0) continue;
|
|
38889
38995
|
const primaryLabel = findPrimaryColumnLabel(child);
|
|
38890
38996
|
const rawName = (primaryLabel ? getElementText(primaryLabel) : void 0) || child.text || "";
|
|
38891
38997
|
const cleanName = rawName.replace(/,?\s*sorted in \w+ order/i, "").trim();
|
|
@@ -38904,6 +39010,7 @@ function detectGrid(element) {
|
|
|
38904
39010
|
}
|
|
38905
39011
|
if (columns.length > columnsBefore) {
|
|
38906
39012
|
headerChildCount = rowEl.children.length;
|
|
39013
|
+
headerCellPositions = Array.from(columnByPosition.keys()).sort((a, b) => a - b);
|
|
38907
39014
|
}
|
|
38908
39015
|
return null;
|
|
38909
39016
|
}
|
|
@@ -38945,6 +39052,7 @@ function detectGrid(element) {
|
|
|
38945
39052
|
}
|
|
38946
39053
|
if (columns.length > columnsBefore) {
|
|
38947
39054
|
headerChildCount = rowEl.children.length;
|
|
39055
|
+
headerCellPositions = Array.from(columnByPosition.keys()).sort((a, b) => a - b);
|
|
38948
39056
|
}
|
|
38949
39057
|
return null;
|
|
38950
39058
|
}
|
|
@@ -38970,7 +39078,20 @@ function detectGrid(element) {
|
|
|
38970
39078
|
findButtons(cellEl);
|
|
38971
39079
|
}
|
|
38972
39080
|
}
|
|
38973
|
-
const
|
|
39081
|
+
const cellPositions = [];
|
|
39082
|
+
for (let i = 0; i < rowEl.children.length; i++) {
|
|
39083
|
+
if (rowEl.children[i].role === "gridcell" || rowEl.children[i].role === "cell") {
|
|
39084
|
+
cellPositions.push(i);
|
|
39085
|
+
}
|
|
39086
|
+
}
|
|
39087
|
+
const row = {
|
|
39088
|
+
ref: rowEl.ref,
|
|
39089
|
+
index,
|
|
39090
|
+
isSelected,
|
|
39091
|
+
cells,
|
|
39092
|
+
totalChildren: rowEl.children.length,
|
|
39093
|
+
cellPositions
|
|
39094
|
+
};
|
|
38974
39095
|
if (cells.length === 0 && rowEl.children.some((c2) => c2.role === "rowheader")) {
|
|
38975
39096
|
const labels = [];
|
|
38976
39097
|
const buttons = [];
|
|
@@ -38998,7 +39119,7 @@ function detectGrid(element) {
|
|
|
38998
39119
|
return row;
|
|
38999
39120
|
};
|
|
39000
39121
|
const findRows = (el) => {
|
|
39001
|
-
if (el
|
|
39122
|
+
if (isRowLike(el)) {
|
|
39002
39123
|
const row = processRow(el, rows.length);
|
|
39003
39124
|
if (row) rows.push(row);
|
|
39004
39125
|
} else {
|
|
@@ -39016,177 +39137,414 @@ function detectGrid(element) {
|
|
|
39016
39137
|
totalRows: rows.length,
|
|
39017
39138
|
containsActive: subtreeContainsActive(element),
|
|
39018
39139
|
columnByPosition: columnByPosition.size > 0 ? columnByPosition : void 0,
|
|
39019
|
-
headerChildCount
|
|
39140
|
+
headerChildCount,
|
|
39141
|
+
headerCellPositions
|
|
39020
39142
|
};
|
|
39021
39143
|
return reconcileGridCells(rawGrid);
|
|
39022
39144
|
}
|
|
39023
|
-
function
|
|
39024
|
-
|
|
39025
|
-
|
|
39026
|
-
|
|
39027
|
-
|
|
39028
|
-
|
|
39145
|
+
function gridContainsRef(grid, targetRef) {
|
|
39146
|
+
for (const column of grid.columns) {
|
|
39147
|
+
if (column.ref === targetRef) return true;
|
|
39148
|
+
}
|
|
39149
|
+
for (const row of grid.rows) {
|
|
39150
|
+
if (row.ref === targetRef) return true;
|
|
39151
|
+
if (row.cells.some((cell) => cell.ref === targetRef)) return true;
|
|
39152
|
+
if (row.rowActions?.some((action) => action.ref === targetRef)) return true;
|
|
39153
|
+
if (row.expandedContent?.buttons.some((button) => button.ref === targetRef)) return true;
|
|
39154
|
+
}
|
|
39155
|
+
return false;
|
|
39029
39156
|
}
|
|
39030
|
-
function
|
|
39031
|
-
const
|
|
39032
|
-
|
|
39033
|
-
|
|
39157
|
+
function countRenderedGridItems(grid) {
|
|
39158
|
+
const knownColumns = grid.columns.length > 0 ? new Set(grid.columns.map((c2) => c2.name)) : void 0;
|
|
39159
|
+
let count = 0;
|
|
39160
|
+
for (const row of grid.rows) {
|
|
39161
|
+
count += row.cells.filter((c2) => c2.hasValue && (!knownColumns || knownColumns.has(c2.column))).length;
|
|
39162
|
+
count += row.rowActions?.length ?? 0;
|
|
39163
|
+
count += row.expandedContent?.buttons.length ?? 0;
|
|
39164
|
+
}
|
|
39165
|
+
return count;
|
|
39166
|
+
}
|
|
39167
|
+
function formatGridOutput(grid, indent, expanded = false) {
|
|
39168
|
+
const indentStr = " ".repeat(indent);
|
|
39169
|
+
const lines = [];
|
|
39170
|
+
const colInfo = grid.columns.length > 0 ? `${grid.columns.length} columns` : "unknown columns";
|
|
39171
|
+
lines.push(`${indentStr}GRID [${grid.ref}]: ${grid.totalRows} rows, ${colInfo}`);
|
|
39172
|
+
const MAX_DISPLAY_COLUMNS = 10;
|
|
39173
|
+
if (grid.columns.length > 0) {
|
|
39174
|
+
const displayColumns = grid.columns.slice(0, MAX_DISPLAY_COLUMNS);
|
|
39175
|
+
const colsWithRefs = displayColumns.map((c2) => `${c2.name} [${c2.ref}]`).join(", ");
|
|
39176
|
+
const moreColsNote = grid.columns.length > MAX_DISPLAY_COLUMNS ? ` (+${grid.columns.length - MAX_DISPLAY_COLUMNS} more)` : "";
|
|
39177
|
+
lines.push(`${indentStr} Columns: ${colsWithRefs}${moreColsNote}`);
|
|
39178
|
+
}
|
|
39179
|
+
lines.push("");
|
|
39180
|
+
const knownColumns = grid.columns.length > 0 ? new Set(grid.columns.map((c2) => c2.name)) : void 0;
|
|
39181
|
+
const MAX_GRID_ROWS = 30;
|
|
39182
|
+
const displayRows = expanded ? grid.rows : grid.rows.slice(0, MAX_GRID_ROWS);
|
|
39183
|
+
for (const row of displayRows) {
|
|
39184
|
+
lines.push(formatGridRow(row, indent + 1, knownColumns));
|
|
39185
|
+
}
|
|
39186
|
+
if (!expanded && grid.rows.length > MAX_GRID_ROWS) {
|
|
39187
|
+
lines.push(`${indentStr} ... and ${grid.rows.length - MAX_GRID_ROWS} more rows (use expand="${grid.ref}" to see all)`);
|
|
39188
|
+
}
|
|
39189
|
+
return lines.join("\n");
|
|
39190
|
+
}
|
|
39191
|
+
function formatGridRow(row, indent, knownColumns) {
|
|
39192
|
+
const indentStr = " ".repeat(indent);
|
|
39193
|
+
if (row.expandedContent) {
|
|
39194
|
+
const parts = [];
|
|
39195
|
+
if (row.expandedContent.labels.length > 0) {
|
|
39196
|
+
parts.push(row.expandedContent.labels.join(", "));
|
|
39034
39197
|
}
|
|
39035
|
-
for (const
|
|
39036
|
-
|
|
39037
|
-
|
|
39038
|
-
|
|
39198
|
+
for (const btn of row.expandedContent.buttons) {
|
|
39199
|
+
parts.push(`${btn.label} [${btn.ref}]`);
|
|
39200
|
+
}
|
|
39201
|
+
return `${indentStr} \u21B3 Expanded [${row.ref}]: ${parts.join(" | ")}`;
|
|
39202
|
+
}
|
|
39203
|
+
const marker = row.isSelected ? "ACTIVE \u2192 Row" : "Row";
|
|
39204
|
+
const actionsPrefix = row.rowActions?.length ? row.rowActions.map((a) => `[\u25B6 ${a.ref}]`).join(" ") + " " : "";
|
|
39205
|
+
const cellsWithValue = row.cells.filter(
|
|
39206
|
+
(c2) => c2.hasValue && (!knownColumns || knownColumns.has(c2.column))
|
|
39207
|
+
);
|
|
39208
|
+
if (cellsWithValue.length > 0) {
|
|
39209
|
+
const cellStrs = cellsWithValue.map((c2) => {
|
|
39210
|
+
if (c2.role === "checkbox") {
|
|
39211
|
+
const icon = c2.value === "checked" ? "\u2611" : "\u2610";
|
|
39212
|
+
return `${icon} [${c2.ref}]`;
|
|
39213
|
+
}
|
|
39214
|
+
if (c2.column === c2.value) {
|
|
39215
|
+
return `${c2.column} [${c2.ref}]`;
|
|
39039
39216
|
}
|
|
39217
|
+
return `${c2.column} [${c2.ref}]: ${c2.value}`;
|
|
39218
|
+
});
|
|
39219
|
+
return `${indentStr}${actionsPrefix}${marker} [${row.ref}]: ${cellStrs.join(" | ")}`;
|
|
39220
|
+
}
|
|
39221
|
+
return `${indentStr}${actionsPrefix}${marker} [${row.ref}]: (empty row)`;
|
|
39222
|
+
}
|
|
39223
|
+
|
|
39224
|
+
// ../browser-core/src/snapshot-formatter-search.ts
|
|
39225
|
+
function findRelevanceScope(elements, activeElementRef) {
|
|
39226
|
+
if (!activeElementRef) return null;
|
|
39227
|
+
const path5 = [];
|
|
39228
|
+
function findPath(el) {
|
|
39229
|
+
if (el.ref) {
|
|
39230
|
+
path5.push({ ref: el.ref, role: el.role });
|
|
39040
39231
|
}
|
|
39041
|
-
|
|
39042
|
-
|
|
39043
|
-
|
|
39044
|
-
|
|
39045
|
-
|
|
39046
|
-
|
|
39232
|
+
if (el.ref === activeElementRef) {
|
|
39233
|
+
return true;
|
|
39234
|
+
}
|
|
39235
|
+
for (const child of el.children) {
|
|
39236
|
+
if (findPath(child)) return true;
|
|
39237
|
+
}
|
|
39238
|
+
if (el.ref) path5.pop();
|
|
39239
|
+
return false;
|
|
39240
|
+
}
|
|
39241
|
+
for (const el of elements) {
|
|
39242
|
+
if (findPath(el)) break;
|
|
39243
|
+
}
|
|
39244
|
+
for (let i = path5.length - 1; i >= 0; i--) {
|
|
39245
|
+
if (SECTION_BOUNDARY_ROLES.has(path5[i].role)) {
|
|
39246
|
+
return path5[i].ref;
|
|
39247
|
+
}
|
|
39248
|
+
}
|
|
39047
39249
|
return null;
|
|
39048
39250
|
}
|
|
39049
|
-
function
|
|
39050
|
-
const
|
|
39051
|
-
const
|
|
39052
|
-
|
|
39053
|
-
|
|
39054
|
-
|
|
39055
|
-
|
|
39056
|
-
|
|
39057
|
-
|
|
39251
|
+
function searchElements(elements, searchTerms, scopeRef = null) {
|
|
39252
|
+
const allMatches = [];
|
|
39253
|
+
const normalizedTerms = searchTerms.map((t) => normalizeSearchText(t)).filter(Boolean);
|
|
39254
|
+
if (normalizedTerms.length === 0) return { matches: [], totalFound: 0 };
|
|
39255
|
+
function searchElement(el, inScope) {
|
|
39256
|
+
const nowInScope = inScope || el.ref === scopeRef || scopeRef === null;
|
|
39257
|
+
if (el.ref && nowInScope) {
|
|
39258
|
+
const searchLabel = getDisplayText(el);
|
|
39259
|
+
const searchText = [searchLabel, el.inputValue].filter(Boolean).join(" ");
|
|
39260
|
+
const normalizedSearchText = normalizeSearchText(searchText);
|
|
39261
|
+
for (const term of normalizedTerms) {
|
|
39262
|
+
if (normalizedSearchText.includes(term)) {
|
|
39263
|
+
allMatches.push({
|
|
39264
|
+
ref: el.ref,
|
|
39265
|
+
role: el.role,
|
|
39266
|
+
label: searchLabel || el.role,
|
|
39267
|
+
term,
|
|
39268
|
+
isInteractive: isSearchInteractiveElement(el)
|
|
39269
|
+
});
|
|
39270
|
+
break;
|
|
39058
39271
|
}
|
|
39059
39272
|
}
|
|
39060
|
-
interactiveElements.push({
|
|
39061
|
-
ref: el.ref,
|
|
39062
|
-
column: el.attributes["label"] || childTexts[0] || "",
|
|
39063
|
-
value: childTexts.join(" - ") || el.text || el.inputValue || "",
|
|
39064
|
-
role: el.role,
|
|
39065
|
-
isClickableGeneric: true,
|
|
39066
|
-
isActive: isActiveElement(el)
|
|
39067
|
-
});
|
|
39068
39273
|
}
|
|
39069
|
-
|
|
39070
|
-
|
|
39071
|
-
interactiveElements.push({
|
|
39072
|
-
ref: el.ref,
|
|
39073
|
-
column: el.attributes["label"] || el.text || "",
|
|
39074
|
-
value: value2,
|
|
39075
|
-
role: el.role,
|
|
39076
|
-
isClickableGeneric: false,
|
|
39077
|
-
isActive: isActiveElement(el)
|
|
39078
|
-
});
|
|
39274
|
+
for (const child of el.children) {
|
|
39275
|
+
searchElement(child, nowInScope);
|
|
39079
39276
|
}
|
|
39080
|
-
|
|
39277
|
+
}
|
|
39278
|
+
for (const el of elements) {
|
|
39279
|
+
searchElement(el, scopeRef === null);
|
|
39280
|
+
}
|
|
39281
|
+
const totalFound = allMatches.length;
|
|
39282
|
+
allMatches.sort((a, b) => {
|
|
39283
|
+
if (a.isInteractive && !b.isInteractive) return -1;
|
|
39284
|
+
if (!a.isInteractive && b.isInteractive) return 1;
|
|
39285
|
+
return 0;
|
|
39286
|
+
});
|
|
39287
|
+
return {
|
|
39288
|
+
matches: allMatches.slice(0, MAX_SEARCH_MATCHES),
|
|
39289
|
+
totalFound
|
|
39081
39290
|
};
|
|
39082
|
-
|
|
39083
|
-
|
|
39084
|
-
|
|
39085
|
-
|
|
39086
|
-
|
|
39087
|
-
|
|
39088
|
-
|
|
39089
|
-
value: textValue,
|
|
39090
|
-
hasValue: true
|
|
39091
|
-
};
|
|
39291
|
+
}
|
|
39292
|
+
function findElementInSections(sections, targetRef, ancestors = []) {
|
|
39293
|
+
for (const section of sections) {
|
|
39294
|
+
const newAncestors = [...ancestors, section];
|
|
39295
|
+
const path5 = newAncestors.map((s) => s.heading);
|
|
39296
|
+
if (section.elements.some((el) => el.ref === targetRef)) {
|
|
39297
|
+
return { section, ancestors: newAncestors, path: path5 };
|
|
39092
39298
|
}
|
|
39093
|
-
|
|
39299
|
+
if (section.gridInfo && gridContainsRef(section.gridInfo, targetRef)) {
|
|
39300
|
+
return { section, ancestors: newAncestors, path: path5 };
|
|
39301
|
+
}
|
|
39302
|
+
const found = findElementInSections(section.subsections, targetRef, newAncestors);
|
|
39303
|
+
if (found) return found;
|
|
39094
39304
|
}
|
|
39095
|
-
|
|
39096
|
-
|
|
39097
|
-
|
|
39098
|
-
const
|
|
39099
|
-
|
|
39100
|
-
|
|
39101
|
-
|
|
39102
|
-
|
|
39103
|
-
|
|
39104
|
-
|
|
39105
|
-
|
|
39106
|
-
|
|
39107
|
-
|
|
39305
|
+
return null;
|
|
39306
|
+
}
|
|
39307
|
+
function populateSearchContext(matches, sections) {
|
|
39308
|
+
for (const match of matches) {
|
|
39309
|
+
const result = findElementInSections(sections, match.ref);
|
|
39310
|
+
if (result) {
|
|
39311
|
+
const { section, ancestors, path: path5 } = result;
|
|
39312
|
+
const inFocusedDialog = ancestors.some((s) => s.isFocused);
|
|
39313
|
+
const inBackground = section.isBackground || ancestors.some((s) => s.isBackground);
|
|
39314
|
+
if (inFocusedDialog) {
|
|
39315
|
+
match.context = "focused";
|
|
39316
|
+
} else if (inBackground) {
|
|
39317
|
+
match.context = "background";
|
|
39318
|
+
} else {
|
|
39319
|
+
match.context = "foreground";
|
|
39320
|
+
}
|
|
39321
|
+
const SKIP_HEADINGS = ["generic", "main", "iframe"];
|
|
39322
|
+
match.sectionPath = path5.filter((p) => !SKIP_HEADINGS.includes(p.toLowerCase())).slice(-3).join(" > ");
|
|
39323
|
+
}
|
|
39324
|
+
}
|
|
39325
|
+
}
|
|
39326
|
+
function sortMatchesByContext(matches) {
|
|
39327
|
+
const contextOrder = {
|
|
39328
|
+
focused: 0,
|
|
39329
|
+
foreground: 1,
|
|
39330
|
+
background: 2
|
|
39108
39331
|
};
|
|
39332
|
+
return [...matches].sort((a, b) => {
|
|
39333
|
+
const aContext = contextOrder[a.context ?? "foreground"] ?? 1;
|
|
39334
|
+
const bContext = contextOrder[b.context ?? "foreground"] ?? 1;
|
|
39335
|
+
if (aContext !== bContext) return aContext - bContext;
|
|
39336
|
+
if (a.isInteractive && !b.isInteractive) return -1;
|
|
39337
|
+
if (!a.isInteractive && b.isInteractive) return 1;
|
|
39338
|
+
return 0;
|
|
39339
|
+
});
|
|
39109
39340
|
}
|
|
39110
|
-
|
|
39111
|
-
|
|
39112
|
-
|
|
39113
|
-
|
|
39114
|
-
|
|
39115
|
-
|
|
39116
|
-
|
|
39117
|
-
|
|
39118
|
-
|
|
39119
|
-
|
|
39120
|
-
|
|
39341
|
+
|
|
39342
|
+
// ../browser-core/src/snapshot-formatter-sections.ts
|
|
39343
|
+
var FIELD_LABEL_TEXT_ROLES = /* @__PURE__ */ new Set([
|
|
39344
|
+
"generic",
|
|
39345
|
+
"paragraph",
|
|
39346
|
+
"text",
|
|
39347
|
+
"strong",
|
|
39348
|
+
"emphasis",
|
|
39349
|
+
"label",
|
|
39350
|
+
"heading"
|
|
39351
|
+
]);
|
|
39352
|
+
var MIN_ELEMENTS_TO_COLLAPSE = 20;
|
|
39353
|
+
var DIALOG_ROLES = /* @__PURE__ */ new Set(["dialog", "alertdialog"]);
|
|
39354
|
+
function isVisualHeading(element, siblings, siblingIndex) {
|
|
39355
|
+
if (element.role !== "generic" && element.role !== "paragraph") return false;
|
|
39356
|
+
if (isClickableByAttribute(element)) return false;
|
|
39357
|
+
const text = getVisualHeadingText(element);
|
|
39358
|
+
if (!text || text.length < 3 || text.length > VISUAL_HEADING_MAX_LENGTH) return false;
|
|
39359
|
+
if (hasInteractiveDescendants(element)) return false;
|
|
39360
|
+
let interactiveCount = 0;
|
|
39361
|
+
for (let i = siblingIndex + 1; i < siblings.length; i++) {
|
|
39362
|
+
const sib = siblings[i];
|
|
39363
|
+
if (sib.role === "heading" || STRUCTURAL_ROLES.has(sib.role)) break;
|
|
39364
|
+
if (sib.role === "generic" || sib.role === "paragraph") {
|
|
39365
|
+
if (!isClickableByAttribute(sib) && !hasInteractiveDescendants(sib)) {
|
|
39366
|
+
const sibText = getVisualHeadingText(sib);
|
|
39367
|
+
if (sibText && sibText.length >= 3 && sibText.length <= VISUAL_HEADING_MAX_LENGTH) {
|
|
39368
|
+
break;
|
|
39369
|
+
}
|
|
39370
|
+
}
|
|
39371
|
+
}
|
|
39372
|
+
if (hasInteractiveDescendants(sib) || isClickableByAttribute(sib)) {
|
|
39373
|
+
interactiveCount++;
|
|
39374
|
+
}
|
|
39121
39375
|
}
|
|
39122
|
-
|
|
39123
|
-
|
|
39124
|
-
|
|
39125
|
-
|
|
39126
|
-
|
|
39376
|
+
return interactiveCount >= 3;
|
|
39377
|
+
}
|
|
39378
|
+
function getVisualHeadingText(element) {
|
|
39379
|
+
const direct = element.text;
|
|
39380
|
+
if (direct) return direct;
|
|
39381
|
+
for (const child of element.children) {
|
|
39382
|
+
if (TEXT_CARRYING_ROLES.has(child.role) && child.text) return child.text;
|
|
39383
|
+
}
|
|
39384
|
+
return void 0;
|
|
39385
|
+
}
|
|
39386
|
+
function findNextSectionBoundary(siblings, startIndex) {
|
|
39387
|
+
for (let i = startIndex; i < siblings.length; i++) {
|
|
39388
|
+
const sib = siblings[i];
|
|
39389
|
+
if (sib.role === "heading" || STRUCTURAL_ROLES.has(sib.role)) return i;
|
|
39390
|
+
if (isVisualHeading(sib, siblings, i)) return i;
|
|
39391
|
+
}
|
|
39392
|
+
return siblings.length;
|
|
39393
|
+
}
|
|
39394
|
+
function isFieldLabelCandidate(element) {
|
|
39395
|
+
if (element.role !== "generic" && element.role !== "paragraph" && element.role !== "text" && element.role !== "label" && element.role !== "strong" && element.role !== "emphasis") {
|
|
39396
|
+
return false;
|
|
39397
|
+
}
|
|
39398
|
+
if (isClickableByAttribute(element)) return false;
|
|
39399
|
+
if (hasInteractiveDescendants(element)) return false;
|
|
39400
|
+
const text = getFieldLabelText(element);
|
|
39401
|
+
if (!text || text.length < 1 || text.length > VISUAL_HEADING_MAX_LENGTH) return false;
|
|
39402
|
+
return true;
|
|
39403
|
+
}
|
|
39404
|
+
function getFieldLabelText(element) {
|
|
39405
|
+
if (element.text) return element.text.trim();
|
|
39406
|
+
if (element.inputValue && !INTERACTIVE_ROLES.has(element.role)) return element.inputValue.trim();
|
|
39407
|
+
for (const child of element.children) {
|
|
39408
|
+
if (FIELD_LABEL_TEXT_ROLES.has(child.role)) {
|
|
39409
|
+
if (child.text) return child.text.trim();
|
|
39410
|
+
if (child.inputValue && !INTERACTIVE_ROLES.has(child.role)) return child.inputValue.trim();
|
|
39127
39411
|
}
|
|
39128
39412
|
}
|
|
39129
|
-
|
|
39130
|
-
|
|
39131
|
-
|
|
39132
|
-
|
|
39133
|
-
|
|
39134
|
-
|
|
39135
|
-
|
|
39136
|
-
|
|
39137
|
-
};
|
|
39413
|
+
return void 0;
|
|
39414
|
+
}
|
|
39415
|
+
function resolveContainerFieldLabel(container) {
|
|
39416
|
+
const kids = container.children;
|
|
39417
|
+
if (kids.length < 2 || kids.length > 4) return void 0;
|
|
39418
|
+
const firstChild = kids[0];
|
|
39419
|
+
if (isFieldLabelCandidate(firstChild)) {
|
|
39420
|
+
return getFieldLabelText(firstChild);
|
|
39138
39421
|
}
|
|
39139
|
-
return
|
|
39422
|
+
return void 0;
|
|
39140
39423
|
}
|
|
39141
|
-
function
|
|
39142
|
-
|
|
39143
|
-
|
|
39144
|
-
|
|
39145
|
-
|
|
39146
|
-
|
|
39147
|
-
|
|
39148
|
-
|
|
39149
|
-
|
|
39150
|
-
|
|
39151
|
-
|
|
39152
|
-
|
|
39153
|
-
if (positionalColumn) {
|
|
39154
|
-
const newValue = cell.column || cell.value;
|
|
39155
|
-
const cleanValue = isBlankValue(newValue) ? "" : newValue.trim();
|
|
39156
|
-
return {
|
|
39157
|
-
...cell,
|
|
39158
|
-
column: positionalColumn,
|
|
39159
|
-
value: cleanValue,
|
|
39160
|
-
hasValue: cleanValue !== ""
|
|
39161
|
-
};
|
|
39424
|
+
function findFieldLabelFromSiblings(siblings, interactiveIndex) {
|
|
39425
|
+
for (let i = interactiveIndex - 1; i >= 0; i--) {
|
|
39426
|
+
const sib = siblings[i];
|
|
39427
|
+
if (INTERACTIVE_ROLES.has(sib.role) || STRUCTURAL_ROLES.has(sib.role) || sib.role === "heading") {
|
|
39428
|
+
break;
|
|
39429
|
+
}
|
|
39430
|
+
if (isClickableByAttribute(sib)) {
|
|
39431
|
+
if (sib.role === "generic" || sib.role === "paragraph" || sib.role === "label") {
|
|
39432
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
39433
|
+
const prev = siblings[j];
|
|
39434
|
+
if (INTERACTIVE_ROLES.has(prev.role) || isClickableByAttribute(prev) || STRUCTURAL_ROLES.has(prev.role) || prev.role === "heading") {
|
|
39435
|
+
break;
|
|
39162
39436
|
}
|
|
39437
|
+
if (isFieldLabelCandidate(prev)) {
|
|
39438
|
+
return getFieldLabelText(prev);
|
|
39439
|
+
}
|
|
39440
|
+
if (prev.children.length >= 1 && prev.children.length <= 4) {
|
|
39441
|
+
const containerLabel = resolveContainerFieldLabel(prev);
|
|
39442
|
+
if (containerLabel) return containerLabel;
|
|
39443
|
+
}
|
|
39444
|
+
if (prev.children.length > 4) break;
|
|
39163
39445
|
}
|
|
39164
|
-
|
|
39165
|
-
|
|
39166
|
-
}
|
|
39167
|
-
|
|
39446
|
+
}
|
|
39447
|
+
break;
|
|
39448
|
+
}
|
|
39449
|
+
if (isFieldLabelCandidate(sib)) {
|
|
39450
|
+
return getFieldLabelText(sib);
|
|
39451
|
+
}
|
|
39452
|
+
if (sib.children.length >= 1 && sib.children.length <= 4) {
|
|
39453
|
+
const containerLabel = resolveContainerFieldLabel(sib);
|
|
39454
|
+
if (containerLabel) return containerLabel;
|
|
39455
|
+
}
|
|
39456
|
+
if (sib.children.length > 4) break;
|
|
39457
|
+
}
|
|
39458
|
+
return void 0;
|
|
39168
39459
|
}
|
|
39169
|
-
function
|
|
39170
|
-
|
|
39171
|
-
|
|
39172
|
-
|
|
39173
|
-
|
|
39460
|
+
function findFieldLabelInContext(_element, siblings, siblingIndex) {
|
|
39461
|
+
return findFieldLabelFromSiblings(siblings, siblingIndex);
|
|
39462
|
+
}
|
|
39463
|
+
function shouldDropInheritedFieldLabel(element, inheritedFieldLabel) {
|
|
39464
|
+
if (!inheritedFieldLabel) return false;
|
|
39465
|
+
if (INTERACTIVE_LEAF_ROLES.has(element.role)) return false;
|
|
39466
|
+
if (!isClickableByAttribute(element)) return false;
|
|
39467
|
+
const directText = getElementText(element);
|
|
39468
|
+
if (directText) {
|
|
39469
|
+
return directText.toLowerCase() !== inheritedFieldLabel.toLowerCase();
|
|
39470
|
+
}
|
|
39471
|
+
const childTexts = [];
|
|
39472
|
+
for (const child of element.children) {
|
|
39473
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
39474
|
+
const text = getElementText(child);
|
|
39475
|
+
if (text && TEXT_CARRYING_ROLES.has(child.role)) {
|
|
39476
|
+
childTexts.push(text);
|
|
39477
|
+
}
|
|
39174
39478
|
}
|
|
39175
|
-
|
|
39176
|
-
|
|
39177
|
-
|
|
39479
|
+
}
|
|
39480
|
+
const composedText = childTexts.join(" ");
|
|
39481
|
+
if (!composedText) return false;
|
|
39482
|
+
return composedText.toLowerCase() !== inheritedFieldLabel.toLowerCase();
|
|
39483
|
+
}
|
|
39484
|
+
function isExpandedElement(element) {
|
|
39485
|
+
return element.attributes["expanded"] === "true" || element.attributes["aria-expanded"] === "true";
|
|
39486
|
+
}
|
|
39487
|
+
function collectExpandedChildren(element, result) {
|
|
39488
|
+
for (const child of element.children) {
|
|
39489
|
+
if (STRUCTURAL_ROLES.has(child.role)) continue;
|
|
39490
|
+
if (INTERACTIVE_LEAF_ROLES.has(child.role) && child.ref) {
|
|
39491
|
+
result.push(formatElement(child));
|
|
39492
|
+
continue;
|
|
39493
|
+
}
|
|
39494
|
+
if (child.role === "listitem" && child.ref) {
|
|
39495
|
+
const text = child.text || child.children.map((c2) => getElementText(c2)).filter((value) => Boolean(value)).join(" | ") || getDisplayText(child);
|
|
39496
|
+
if (text && text !== "listitem") {
|
|
39497
|
+
result.push(formatElement(child, { overrideLabel: text }));
|
|
39498
|
+
continue;
|
|
39178
39499
|
}
|
|
39179
39500
|
}
|
|
39501
|
+
if (isClickableByAttribute(child) && child.ref) {
|
|
39502
|
+
result.push(formatElement(child));
|
|
39503
|
+
}
|
|
39504
|
+
collectExpandedChildren(child, result);
|
|
39180
39505
|
}
|
|
39181
|
-
|
|
39182
|
-
|
|
39506
|
+
}
|
|
39507
|
+
function hasActionableChildren(element) {
|
|
39508
|
+
const children2 = [];
|
|
39509
|
+
collectExpandedChildren(element, children2);
|
|
39510
|
+
return children2.length > 0;
|
|
39511
|
+
}
|
|
39512
|
+
function isExpandedWithActionableChildren(element) {
|
|
39513
|
+
if (!isExpandedElement(element)) return false;
|
|
39514
|
+
if (element.role === "combobox") return false;
|
|
39515
|
+
return hasActionableChildren(element);
|
|
39516
|
+
}
|
|
39517
|
+
function composeTriggerLabel(element) {
|
|
39518
|
+
const ariaLabel = element.attributes["aria-label"];
|
|
39519
|
+
if (ariaLabel) return ariaLabel;
|
|
39520
|
+
const fullText = element.text || "";
|
|
39521
|
+
if (fullText) {
|
|
39522
|
+
let collectLeafTexts2 = function(el) {
|
|
39523
|
+
for (const child of el.children) {
|
|
39524
|
+
const text = child.text?.trim();
|
|
39525
|
+
if (text) {
|
|
39526
|
+
leafTexts.push(text);
|
|
39527
|
+
}
|
|
39528
|
+
collectLeafTexts2(child);
|
|
39529
|
+
}
|
|
39530
|
+
};
|
|
39531
|
+
var collectLeafTexts = collectLeafTexts2;
|
|
39532
|
+
const leafTexts = [];
|
|
39533
|
+
collectLeafTexts2(element);
|
|
39534
|
+
if (leafTexts.length > 0) {
|
|
39535
|
+
let stripped = fullText;
|
|
39536
|
+
for (const lt of leafTexts) {
|
|
39537
|
+
stripped = stripped.replace(lt, "");
|
|
39538
|
+
}
|
|
39539
|
+
stripped = stripped.replace(/\s+/g, " ").trim();
|
|
39540
|
+
if (stripped) return stripped;
|
|
39541
|
+
}
|
|
39183
39542
|
}
|
|
39184
|
-
return
|
|
39543
|
+
return element.role;
|
|
39185
39544
|
}
|
|
39186
39545
|
function formatElement(element, options) {
|
|
39187
|
-
const isClickable =
|
|
39188
|
-
const
|
|
39189
|
-
const textSource = normalizeIconLabelText(element.role, rawTextSource);
|
|
39546
|
+
const isClickable = isActionableClickableGeneric(element);
|
|
39547
|
+
const textSource = getDisplayText(element, { overrideLabel: options?.overrideLabel });
|
|
39190
39548
|
const extracted = extractDataValue(textSource);
|
|
39191
39549
|
const normalizedAttributes = Object.entries(element.attributes).filter(
|
|
39192
39550
|
([key]) => key !== "ref" && key !== "cursor" && key !== "aria-controls" && key !== "aria-owns" && key !== "options" && key !== "field"
|
|
@@ -39220,105 +39578,141 @@ function formatElement(element, options) {
|
|
|
39220
39578
|
attributes: normalizedAttributes
|
|
39221
39579
|
};
|
|
39222
39580
|
}
|
|
39223
|
-
function collectComboboxOptions(element) {
|
|
39224
|
-
const options = [];
|
|
39225
|
-
function walk(el) {
|
|
39226
|
-
if (el.role === "option" && el.text?.trim()) {
|
|
39227
|
-
options.push(el.text.trim());
|
|
39228
|
-
}
|
|
39229
|
-
for (const child of el.children) {
|
|
39230
|
-
walk(child);
|
|
39231
|
-
}
|
|
39232
|
-
}
|
|
39233
|
-
for (const child of element.children) {
|
|
39234
|
-
walk(child);
|
|
39235
|
-
}
|
|
39236
|
-
return options.length > 0 ? options : void 0;
|
|
39237
|
-
}
|
|
39238
|
-
var MIN_ELEMENTS_TO_COLLAPSE = 20;
|
|
39239
39581
|
function shouldCollapse(section) {
|
|
39240
39582
|
if (section.containsActive) return false;
|
|
39241
39583
|
if (section.hasSearchMatch) return false;
|
|
39242
39584
|
if (section.isBackground) return true;
|
|
39243
39585
|
if (section.role === "dialog" || section.role === "alertdialog") return false;
|
|
39244
|
-
if (section.role === "navigation" || section.role === "menubar" || section.role === "menu")
|
|
39245
|
-
return false;
|
|
39246
|
-
}
|
|
39586
|
+
if (section.role === "navigation" || section.role === "menubar" || section.role === "menu") return false;
|
|
39247
39587
|
if (section.role === "banner") return false;
|
|
39248
39588
|
if (section.role === "form") return false;
|
|
39249
39589
|
if (section.elementCount >= MIN_ELEMENTS_TO_COLLAPSE) return true;
|
|
39250
39590
|
return false;
|
|
39251
39591
|
}
|
|
39252
|
-
function
|
|
39253
|
-
const
|
|
39254
|
-
for (const
|
|
39255
|
-
|
|
39256
|
-
|
|
39257
|
-
|
|
39592
|
+
function deduplicateFieldLabels(elements) {
|
|
39593
|
+
const byFieldLabel = /* @__PURE__ */ new Map();
|
|
39594
|
+
for (const el of elements) {
|
|
39595
|
+
if (!el.fieldLabel) continue;
|
|
39596
|
+
const existing = byFieldLabel.get(el.fieldLabel);
|
|
39597
|
+
if (existing) {
|
|
39598
|
+
existing.push(el);
|
|
39599
|
+
} else {
|
|
39600
|
+
byFieldLabel.set(el.fieldLabel, [el]);
|
|
39258
39601
|
}
|
|
39259
39602
|
}
|
|
39260
|
-
|
|
39261
|
-
|
|
39262
|
-
|
|
39263
|
-
|
|
39264
|
-
|
|
39265
|
-
|
|
39266
|
-
|
|
39267
|
-
|
|
39268
|
-
section.isBackground = true;
|
|
39269
|
-
section.collapsed = shouldCollapse(section);
|
|
39603
|
+
for (const [, group] of byFieldLabel) {
|
|
39604
|
+
if (group.length < 2) continue;
|
|
39605
|
+
for (let i = 0; i < group.length; i++) {
|
|
39606
|
+
const el = group[i];
|
|
39607
|
+
if (el.name && el.name !== el.fieldLabel) {
|
|
39608
|
+
el.fieldLabel = `${el.fieldLabel}: ${el.name}`;
|
|
39609
|
+
} else {
|
|
39610
|
+
el.fieldLabel = `${el.fieldLabel} (${i + 1})`;
|
|
39270
39611
|
}
|
|
39271
39612
|
}
|
|
39272
39613
|
}
|
|
39273
|
-
for (const section of sections) {
|
|
39274
|
-
markBackgroundSections(section.subsections);
|
|
39275
|
-
}
|
|
39276
39614
|
}
|
|
39277
|
-
function
|
|
39278
|
-
|
|
39279
|
-
|
|
39280
|
-
|
|
39281
|
-
const hasSubsectionMatch = section.subsections.some((s) => s.hasSearchMatch);
|
|
39282
|
-
if (hasDirectMatch || hasSubsectionMatch) {
|
|
39283
|
-
section.hasSearchMatch = true;
|
|
39284
|
-
section.collapsed = false;
|
|
39285
|
-
}
|
|
39615
|
+
function buildGridSection(element) {
|
|
39616
|
+
const gridInfo = detectGrid(element);
|
|
39617
|
+
if (!gridInfo) {
|
|
39618
|
+
throw new Error("buildGridSection requires a grid element");
|
|
39286
39619
|
}
|
|
39620
|
+
return {
|
|
39621
|
+
ref: element.ref || "",
|
|
39622
|
+
role: element.role,
|
|
39623
|
+
heading: "Grid",
|
|
39624
|
+
level: 0,
|
|
39625
|
+
elements: [],
|
|
39626
|
+
subsections: [],
|
|
39627
|
+
containsActive: gridInfo.containsActive,
|
|
39628
|
+
collapsed: false,
|
|
39629
|
+
isBackground: false,
|
|
39630
|
+
isFocused: false,
|
|
39631
|
+
elementCount: gridInfo.totalRows * Math.max(gridInfo.columns.length, 1),
|
|
39632
|
+
gridInfo
|
|
39633
|
+
};
|
|
39287
39634
|
}
|
|
39288
|
-
|
|
39289
|
-
|
|
39290
|
-
|
|
39291
|
-
|
|
39292
|
-
|
|
39293
|
-
|
|
39294
|
-
|
|
39635
|
+
function collectInteractiveElements(element, elements, subsections, depth, inheritedFieldLabel) {
|
|
39636
|
+
if ((INTERACTIVE_LEAF_ROLES.has(element.role) || isClickableByAttribute(element)) && element.ref) {
|
|
39637
|
+
const effectiveFieldLabel = shouldDropInheritedFieldLabel(element, inheritedFieldLabel) ? void 0 : inheritedFieldLabel;
|
|
39638
|
+
if (INTERACTIVE_LEAF_ROLES.has(element.role) && isExpandedWithActionableChildren(element)) {
|
|
39639
|
+
elements.push(formatElement(element, { overrideLabel: composeTriggerLabel(element), fieldLabel: effectiveFieldLabel }));
|
|
39640
|
+
collectExpandedChildren(element, elements);
|
|
39641
|
+
return;
|
|
39295
39642
|
}
|
|
39296
|
-
|
|
39297
|
-
|
|
39298
|
-
const focusedDialog = dialogs.find((d) => d.containsActive);
|
|
39299
|
-
if (focusedDialog) {
|
|
39300
|
-
focusedDialog.isFocused = true;
|
|
39301
|
-
dialogStack.unshift(focusedDialog.heading);
|
|
39643
|
+
if (!isMenuTriggerNoise(element)) {
|
|
39644
|
+
elements.push(formatElement(element, { fieldLabel: effectiveFieldLabel }));
|
|
39302
39645
|
}
|
|
39303
|
-
|
|
39304
|
-
|
|
39305
|
-
|
|
39646
|
+
if (!INTERACTIVE_LEAF_ROLES.has(element.role) && isClickableByAttribute(element)) {
|
|
39647
|
+
for (const child of element.children) {
|
|
39648
|
+
collectInteractiveElements(child, elements, subsections, depth + 1, effectiveFieldLabel);
|
|
39306
39649
|
}
|
|
39307
39650
|
}
|
|
39308
|
-
|
|
39309
|
-
|
|
39310
|
-
|
|
39311
|
-
|
|
39312
|
-
|
|
39313
|
-
|
|
39651
|
+
return;
|
|
39652
|
+
}
|
|
39653
|
+
if (element.role === "heading" || STRUCTURAL_ROLES.has(element.role) || element.role === "grid" || element.role === "treegrid" || element.role === "table" && !isWidgetTable(element)) {
|
|
39654
|
+
const section = buildSection(element, depth);
|
|
39655
|
+
if (section) {
|
|
39656
|
+
subsections.push(section);
|
|
39657
|
+
}
|
|
39658
|
+
return;
|
|
39659
|
+
}
|
|
39660
|
+
const kids = element.children;
|
|
39661
|
+
for (let ki = 0; ki < kids.length; ki++) {
|
|
39662
|
+
const child = kids[ki];
|
|
39663
|
+
if (isVisualHeading(child, kids, ki)) {
|
|
39664
|
+
const headingText = getVisualHeadingText(child);
|
|
39665
|
+
const sectionElements = [];
|
|
39666
|
+
const sectionSubsections = [];
|
|
39667
|
+
const nextBoundary = findNextSectionBoundary(kids, ki + 1);
|
|
39668
|
+
for (let si = ki + 1; si < nextBoundary; si++) {
|
|
39669
|
+
collectInteractiveElements(kids[si], sectionElements, sectionSubsections, depth + 2);
|
|
39670
|
+
}
|
|
39671
|
+
if (sectionElements.length > 0 || sectionSubsections.length > 0) {
|
|
39672
|
+
const totalElements = sectionElements.length + sectionSubsections.reduce((sum, s) => sum + s.elementCount, 0);
|
|
39673
|
+
subsections.push({
|
|
39674
|
+
heading: headingText ?? "",
|
|
39675
|
+
ref: child.ref,
|
|
39676
|
+
role: "heading",
|
|
39677
|
+
level: 4,
|
|
39678
|
+
elements: sectionElements,
|
|
39679
|
+
subsections: sectionSubsections,
|
|
39680
|
+
collapsed: false,
|
|
39681
|
+
containsActive: false,
|
|
39682
|
+
isBackground: false,
|
|
39683
|
+
isFocused: false,
|
|
39684
|
+
elementCount: totalElements
|
|
39685
|
+
});
|
|
39686
|
+
ki = nextBoundary - 1;
|
|
39687
|
+
} else {
|
|
39688
|
+
collectInteractiveElements(child, elements, subsections, depth + 1);
|
|
39689
|
+
}
|
|
39690
|
+
} else if ((INTERACTIVE_LEAF_ROLES.has(child.role) || isClickableByAttribute(child)) && child.ref) {
|
|
39691
|
+
const rawFieldLabel = findFieldLabelInContext(child, kids, ki) ?? inheritedFieldLabel;
|
|
39692
|
+
const fieldLabel = shouldDropInheritedFieldLabel(child, rawFieldLabel) ? void 0 : rawFieldLabel;
|
|
39693
|
+
if (!isMenuTriggerNoise(child)) {
|
|
39694
|
+
if (INTERACTIVE_LEAF_ROLES.has(child.role) && isExpandedWithActionableChildren(child)) {
|
|
39695
|
+
elements.push(formatElement(child, { overrideLabel: composeTriggerLabel(child), fieldLabel }));
|
|
39696
|
+
collectExpandedChildren(child, elements);
|
|
39697
|
+
} else {
|
|
39698
|
+
elements.push(formatElement(child, { fieldLabel }));
|
|
39699
|
+
}
|
|
39700
|
+
}
|
|
39701
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role) && isClickableByAttribute(child)) {
|
|
39702
|
+
for (const grandchild of child.children) {
|
|
39703
|
+
collectInteractiveElements(grandchild, elements, subsections, depth + 1, fieldLabel);
|
|
39704
|
+
}
|
|
39705
|
+
}
|
|
39706
|
+
} else {
|
|
39707
|
+
const containerLabel = resolveContainerFieldLabel(child) ?? (child.role === "table" ? findFieldLabelFromSiblings(kids, ki) : void 0) ?? inheritedFieldLabel;
|
|
39708
|
+
collectInteractiveElements(child, elements, subsections, depth + 1, containerLabel);
|
|
39709
|
+
}
|
|
39314
39710
|
}
|
|
39315
|
-
const sorted = processLevel(sections);
|
|
39316
|
-
return { sorted, dialogStack };
|
|
39317
39711
|
}
|
|
39318
39712
|
function buildSection(element, depth) {
|
|
39319
39713
|
const gridInfo = detectGrid(element);
|
|
39320
39714
|
if (gridInfo) {
|
|
39321
|
-
return buildGridSection(element
|
|
39715
|
+
return buildGridSection(element);
|
|
39322
39716
|
}
|
|
39323
39717
|
const isHeading = element.role === "heading";
|
|
39324
39718
|
const isStructural = STRUCTURAL_ROLES.has(element.role);
|
|
@@ -39356,7 +39750,6 @@ function buildSection(element, depth) {
|
|
|
39356
39750
|
ref: child.ref,
|
|
39357
39751
|
role: "heading",
|
|
39358
39752
|
level: 4,
|
|
39359
|
-
// Visual headings rendered at h6 level (4 + 2 = 6)
|
|
39360
39753
|
elements: sectionElements,
|
|
39361
39754
|
subsections: sectionSubsections,
|
|
39362
39755
|
collapsed: false,
|
|
@@ -39400,192 +39793,138 @@ function buildSection(element, depth) {
|
|
|
39400
39793
|
const section = {
|
|
39401
39794
|
ref: element.ref || "",
|
|
39402
39795
|
role: element.role,
|
|
39403
|
-
heading: element.text || (isClickableByAttribute(element) ?
|
|
39796
|
+
heading: element.text || (isClickableByAttribute(element) ? getDisplayText(element) : element.role),
|
|
39404
39797
|
level,
|
|
39405
39798
|
elements: interactiveElements,
|
|
39406
39799
|
subsections,
|
|
39407
39800
|
containsActive,
|
|
39408
39801
|
collapsed: false,
|
|
39409
39802
|
isBackground: false,
|
|
39410
|
-
// Will be set by markBackgroundSections if needed
|
|
39411
39803
|
isFocused: false,
|
|
39412
|
-
// Will be set by sortSectionsByFocus if needed
|
|
39413
39804
|
elementCount
|
|
39414
39805
|
};
|
|
39806
|
+
deduplicateFieldLabels(interactiveElements);
|
|
39415
39807
|
section.collapsed = shouldCollapse(section);
|
|
39416
39808
|
return section;
|
|
39417
39809
|
}
|
|
39418
|
-
function
|
|
39419
|
-
|
|
39420
|
-
|
|
39421
|
-
|
|
39422
|
-
|
|
39423
|
-
|
|
39424
|
-
|
|
39425
|
-
// Grid cells formatted via gridInfo instead
|
|
39426
|
-
subsections: [],
|
|
39427
|
-
containsActive: gridInfo.containsActive,
|
|
39428
|
-
collapsed: false,
|
|
39429
|
-
// Grids use their own summarization
|
|
39430
|
-
isBackground: false,
|
|
39431
|
-
isFocused: false,
|
|
39432
|
-
elementCount: gridInfo.totalRows * Math.max(gridInfo.columns.length, 1),
|
|
39433
|
-
gridInfo
|
|
39434
|
-
};
|
|
39435
|
-
}
|
|
39436
|
-
function collectInteractiveElements(element, elements, subsections, depth, inheritedFieldLabel) {
|
|
39437
|
-
if ((INTERACTIVE_LEAF_ROLES.has(element.role) || isClickableByAttribute(element)) && element.ref) {
|
|
39438
|
-
const effectiveFieldLabel = shouldDropInheritedFieldLabel(element, inheritedFieldLabel) ? void 0 : inheritedFieldLabel;
|
|
39439
|
-
if (INTERACTIVE_LEAF_ROLES.has(element.role) && isExpandedWithActionableChildren(element)) {
|
|
39440
|
-
elements.push(formatElement(element, { overrideLabel: composeTriggerLabel(element), fieldLabel: effectiveFieldLabel }));
|
|
39441
|
-
collectExpandedChildren(element, elements);
|
|
39442
|
-
return;
|
|
39443
|
-
}
|
|
39444
|
-
if (!isMenuTriggerNoise(element)) {
|
|
39445
|
-
elements.push(formatElement(element, { fieldLabel: effectiveFieldLabel }));
|
|
39446
|
-
}
|
|
39447
|
-
if (!INTERACTIVE_LEAF_ROLES.has(element.role) && isClickableByAttribute(element)) {
|
|
39448
|
-
for (const child of element.children) {
|
|
39449
|
-
collectInteractiveElements(child, elements, subsections, depth + 1, effectiveFieldLabel);
|
|
39810
|
+
function markBackgroundSections(sections) {
|
|
39811
|
+
const hasActiveSibling = sections.some((s) => s.containsActive);
|
|
39812
|
+
if (hasActiveSibling) {
|
|
39813
|
+
for (const section of sections) {
|
|
39814
|
+
if (!section.containsActive) {
|
|
39815
|
+
section.isBackground = true;
|
|
39816
|
+
section.collapsed = shouldCollapse(section);
|
|
39450
39817
|
}
|
|
39451
39818
|
}
|
|
39452
|
-
return;
|
|
39453
39819
|
}
|
|
39454
|
-
|
|
39455
|
-
|
|
39820
|
+
for (const section of sections) {
|
|
39821
|
+
markBackgroundSections(section.subsections);
|
|
39822
|
+
}
|
|
39823
|
+
}
|
|
39824
|
+
function buildSectionTree(elements) {
|
|
39825
|
+
const sections = [];
|
|
39826
|
+
for (const element of elements) {
|
|
39827
|
+
const section = buildSection(element, 0);
|
|
39456
39828
|
if (section) {
|
|
39457
|
-
|
|
39829
|
+
sections.push(section);
|
|
39458
39830
|
}
|
|
39459
|
-
return;
|
|
39460
39831
|
}
|
|
39461
|
-
|
|
39462
|
-
|
|
39463
|
-
|
|
39464
|
-
|
|
39465
|
-
|
|
39466
|
-
|
|
39467
|
-
|
|
39468
|
-
|
|
39469
|
-
|
|
39470
|
-
|
|
39471
|
-
|
|
39472
|
-
if (sectionElements.length > 0 || sectionSubsections.length > 0) {
|
|
39473
|
-
const totalElements = sectionElements.length + sectionSubsections.reduce((sum, s) => sum + s.elementCount, 0);
|
|
39474
|
-
subsections.push({
|
|
39475
|
-
heading: headingText ?? "",
|
|
39476
|
-
ref: child.ref,
|
|
39477
|
-
role: "heading",
|
|
39478
|
-
level: 4,
|
|
39479
|
-
elements: sectionElements,
|
|
39480
|
-
subsections: sectionSubsections,
|
|
39481
|
-
collapsed: false,
|
|
39482
|
-
containsActive: false,
|
|
39483
|
-
isBackground: false,
|
|
39484
|
-
isFocused: false,
|
|
39485
|
-
elementCount: totalElements
|
|
39486
|
-
});
|
|
39487
|
-
ki = nextBoundary - 1;
|
|
39488
|
-
} else {
|
|
39489
|
-
collectInteractiveElements(child, elements, subsections, depth + 1);
|
|
39490
|
-
}
|
|
39491
|
-
} else if ((INTERACTIVE_LEAF_ROLES.has(child.role) || isClickableByAttribute(child)) && child.ref) {
|
|
39492
|
-
const rawFieldLabel = findFieldLabelInContext(child, kids, ki) ?? inheritedFieldLabel;
|
|
39493
|
-
const fieldLabel = shouldDropInheritedFieldLabel(child, rawFieldLabel) ? void 0 : rawFieldLabel;
|
|
39494
|
-
if (!isMenuTriggerNoise(child)) {
|
|
39495
|
-
if (INTERACTIVE_LEAF_ROLES.has(child.role) && isExpandedWithActionableChildren(child)) {
|
|
39496
|
-
elements.push(formatElement(child, { overrideLabel: composeTriggerLabel(child), fieldLabel }));
|
|
39497
|
-
collectExpandedChildren(child, elements);
|
|
39498
|
-
} else {
|
|
39499
|
-
elements.push(formatElement(child, { fieldLabel }));
|
|
39500
|
-
}
|
|
39501
|
-
}
|
|
39502
|
-
if (!INTERACTIVE_LEAF_ROLES.has(child.role) && isClickableByAttribute(child)) {
|
|
39503
|
-
for (const grandchild of child.children) {
|
|
39504
|
-
collectInteractiveElements(grandchild, elements, subsections, depth + 1, fieldLabel);
|
|
39505
|
-
}
|
|
39506
|
-
}
|
|
39507
|
-
} else {
|
|
39508
|
-
const containerLabel = resolveContainerFieldLabel(child) ?? (child.role === "table" ? findFieldLabelFromSiblings(kids, ki) : void 0) ?? inheritedFieldLabel;
|
|
39509
|
-
collectInteractiveElements(child, elements, subsections, depth + 1, containerLabel);
|
|
39832
|
+
markBackgroundSections(sections);
|
|
39833
|
+
return sections;
|
|
39834
|
+
}
|
|
39835
|
+
function markMatchingSections(sections, matchedRefs) {
|
|
39836
|
+
for (const section of sections) {
|
|
39837
|
+
const hasDirectMatch = section.elements.some((el) => matchedRefs.has(el.ref)) || (section.gridInfo ? Array.from(matchedRefs).some((ref) => gridContainsRef(section.gridInfo, ref)) : false);
|
|
39838
|
+
markMatchingSections(section.subsections, matchedRefs);
|
|
39839
|
+
const hasSubsectionMatch = section.subsections.some((s) => s.hasSearchMatch);
|
|
39840
|
+
if (hasDirectMatch || hasSubsectionMatch) {
|
|
39841
|
+
section.hasSearchMatch = true;
|
|
39842
|
+
section.collapsed = false;
|
|
39510
39843
|
}
|
|
39511
39844
|
}
|
|
39512
39845
|
}
|
|
39513
|
-
function
|
|
39514
|
-
|
|
39515
|
-
|
|
39516
|
-
|
|
39517
|
-
|
|
39518
|
-
const lines = [];
|
|
39519
|
-
const headingPrefix = section.level > 0 ? "#".repeat(Math.min(section.level + 2, 6)) + " " : "";
|
|
39520
|
-
const refPart = section.ref ? ` [${section.ref}]` : "";
|
|
39521
|
-
const focusedPart = section.isFocused ? " [FOCUSED]" : "";
|
|
39522
|
-
const backgroundPart = section.isBackground ? " [BACKGROUND]" : "";
|
|
39523
|
-
const activePart = section.containsActive && !section.isFocused ? " \u2190 ACTIVE" : "";
|
|
39524
|
-
const headerLine = `${indentStr}${headingPrefix}${section.heading}${refPart}${focusedPart}${backgroundPart}${activePart}`;
|
|
39525
|
-
lines.push(headerLine);
|
|
39526
|
-
if (section.collapsed && !showCollapsed) {
|
|
39527
|
-
if (section.isBackground) {
|
|
39528
|
-
if (section.ref) {
|
|
39529
|
-
lines.push(`${indentStr} (${section.elementCount} elements - use expand="${section.ref}" to see content)`);
|
|
39530
|
-
} else {
|
|
39531
|
-
lines.push(`${indentStr} (${section.elementCount} elements)`);
|
|
39532
|
-
}
|
|
39533
|
-
return lines.join("\n");
|
|
39534
|
-
}
|
|
39535
|
-
const MAX_DIRECT_ELEMENTS = 4;
|
|
39536
|
-
const previewElements = section.elements.slice(0, MAX_DIRECT_ELEMENTS);
|
|
39537
|
-
const remainingDirectCount = section.elements.length - previewElements.length;
|
|
39538
|
-
for (const el of previewElements) {
|
|
39539
|
-
lines.push(formatElementLine(el, indent + 1));
|
|
39540
|
-
}
|
|
39541
|
-
if (remainingDirectCount > 0) {
|
|
39542
|
-
lines.push(`${indentStr} ... +${remainingDirectCount} more elements`);
|
|
39846
|
+
function sortSectionsByFocus(sections) {
|
|
39847
|
+
const dialogStack = [];
|
|
39848
|
+
function processLevel(levelSections) {
|
|
39849
|
+
for (const section of levelSections) {
|
|
39850
|
+
section.subsections = processLevel(section.subsections);
|
|
39543
39851
|
}
|
|
39544
|
-
|
|
39545
|
-
|
|
39852
|
+
const dialogs = levelSections.filter((s) => DIALOG_ROLES.has(s.role));
|
|
39853
|
+
const nonDialogs = levelSections.filter((s) => !DIALOG_ROLES.has(s.role));
|
|
39854
|
+
const focusedDialog = dialogs.find((d) => d.containsActive);
|
|
39855
|
+
if (focusedDialog) {
|
|
39856
|
+
focusedDialog.isFocused = true;
|
|
39857
|
+
dialogStack.unshift(focusedDialog.heading);
|
|
39546
39858
|
}
|
|
39547
|
-
|
|
39548
|
-
|
|
39859
|
+
for (const dialog of dialogs) {
|
|
39860
|
+
if (!dialog.containsActive) {
|
|
39861
|
+
dialogStack.push(dialog.heading);
|
|
39862
|
+
}
|
|
39549
39863
|
}
|
|
39550
|
-
|
|
39551
|
-
|
|
39552
|
-
|
|
39553
|
-
|
|
39864
|
+
const sortedDialogs = dialogs.sort((a, b) => {
|
|
39865
|
+
if (a.containsActive && !b.containsActive) return -1;
|
|
39866
|
+
if (!a.containsActive && b.containsActive) return 1;
|
|
39867
|
+
return 0;
|
|
39868
|
+
});
|
|
39869
|
+
return [...sortedDialogs, ...nonDialogs];
|
|
39554
39870
|
}
|
|
39555
|
-
|
|
39556
|
-
|
|
39557
|
-
|
|
39558
|
-
|
|
39559
|
-
|
|
39871
|
+
const sorted = processLevel(sections);
|
|
39872
|
+
return { sorted, dialogStack };
|
|
39873
|
+
}
|
|
39874
|
+
function expandSectionByRef(sections, targetRef) {
|
|
39875
|
+
for (const section of sections) {
|
|
39876
|
+
if (section.ref === targetRef) {
|
|
39877
|
+
section.collapsed = false;
|
|
39878
|
+
return true;
|
|
39879
|
+
}
|
|
39880
|
+
if (expandSectionByRef(section.subsections, targetRef)) {
|
|
39881
|
+
return true;
|
|
39560
39882
|
}
|
|
39561
39883
|
}
|
|
39562
|
-
return
|
|
39884
|
+
return false;
|
|
39563
39885
|
}
|
|
39564
|
-
function
|
|
39565
|
-
const
|
|
39566
|
-
|
|
39567
|
-
|
|
39886
|
+
function findSectionByRef(sections, targetRef) {
|
|
39887
|
+
for (const section of sections) {
|
|
39888
|
+
if (section.ref === targetRef) {
|
|
39889
|
+
return section;
|
|
39890
|
+
}
|
|
39891
|
+
const found = findSectionByRef(section.subsections, targetRef);
|
|
39892
|
+
if (found) {
|
|
39893
|
+
return found;
|
|
39894
|
+
}
|
|
39568
39895
|
}
|
|
39569
|
-
return
|
|
39896
|
+
return null;
|
|
39570
39897
|
}
|
|
39571
|
-
|
|
39572
|
-
|
|
39573
|
-
|
|
39574
|
-
|
|
39575
|
-
|
|
39898
|
+
|
|
39899
|
+
// ../browser-core/src/snapshot-formatter-render.ts
|
|
39900
|
+
var COLOR_NAMES = [
|
|
39901
|
+
"red",
|
|
39902
|
+
"green",
|
|
39903
|
+
"blue",
|
|
39904
|
+
"yellow",
|
|
39905
|
+
"magenta",
|
|
39906
|
+
"cyan",
|
|
39907
|
+
"orange",
|
|
39908
|
+
"purple",
|
|
39909
|
+
"teal",
|
|
39910
|
+
"pink"
|
|
39911
|
+
];
|
|
39912
|
+
function findActiveElement(elements) {
|
|
39913
|
+
let deepestActive = null;
|
|
39914
|
+
function findDeepest(element) {
|
|
39915
|
+
for (const child of element.children) {
|
|
39916
|
+
findDeepest(child);
|
|
39917
|
+
}
|
|
39918
|
+
if (element.attributes["active"] !== void 0 || element.rawLine.includes("[active]")) {
|
|
39919
|
+
if (!deepestActive) {
|
|
39920
|
+
deepestActive = element;
|
|
39921
|
+
}
|
|
39922
|
+
}
|
|
39576
39923
|
}
|
|
39577
|
-
const
|
|
39578
|
-
|
|
39579
|
-
const heading = subsection.heading || subsection.role;
|
|
39580
|
-
if (elementNames.length === 0) {
|
|
39581
|
-
return `${heading}${refPart}`;
|
|
39924
|
+
for (const element of elements) {
|
|
39925
|
+
findDeepest(element);
|
|
39582
39926
|
}
|
|
39583
|
-
|
|
39584
|
-
const previewNames = elementNames.slice(0, MAX_PREVIEW_NAMES);
|
|
39585
|
-
const remainingCount = elementNames.length - previewNames.length;
|
|
39586
|
-
const namesList = previewNames.join(", ");
|
|
39587
|
-
const moreNote = remainingCount > 0 ? `... +${remainingCount} more` : "";
|
|
39588
|
-
return `${heading}${refPart}: ${namesList}${moreNote}`;
|
|
39927
|
+
return deepestActive;
|
|
39589
39928
|
}
|
|
39590
39929
|
function formatElementLine(el, indent) {
|
|
39591
39930
|
const indentStr = " ".repeat(indent);
|
|
@@ -39637,23 +39976,102 @@ function formatElementLine(el, indent) {
|
|
|
39637
39976
|
}
|
|
39638
39977
|
return indentStr + parts.join(" ");
|
|
39639
39978
|
}
|
|
39640
|
-
|
|
39641
|
-
|
|
39642
|
-
|
|
39643
|
-
|
|
39644
|
-
|
|
39645
|
-
|
|
39646
|
-
|
|
39647
|
-
|
|
39648
|
-
"
|
|
39649
|
-
|
|
39650
|
-
|
|
39651
|
-
|
|
39979
|
+
function collectAllElementsFlat(section) {
|
|
39980
|
+
const elements = [...section.elements];
|
|
39981
|
+
for (const subsection of section.subsections) {
|
|
39982
|
+
elements.push(...collectAllElementsFlat(subsection));
|
|
39983
|
+
}
|
|
39984
|
+
return elements;
|
|
39985
|
+
}
|
|
39986
|
+
function formatSubsectionSummary(subsection) {
|
|
39987
|
+
const refPart = subsection.ref ? ` [${subsection.ref}]` : "";
|
|
39988
|
+
if (subsection.gridInfo) {
|
|
39989
|
+
const colInfo = subsection.gridInfo.columns.length > 0 ? `${subsection.gridInfo.columns.length} columns` : "unknown columns";
|
|
39990
|
+
return `GRID${refPart}: ${subsection.gridInfo.totalRows} rows, ${colInfo}`;
|
|
39991
|
+
}
|
|
39992
|
+
const allElements = collectAllElementsFlat(subsection);
|
|
39993
|
+
const elementNames = allElements.map((el) => el.label || el.name || el.role).filter(Boolean);
|
|
39994
|
+
const heading = subsection.heading || subsection.role;
|
|
39995
|
+
if (elementNames.length === 0) {
|
|
39996
|
+
return `${heading}${refPart}`;
|
|
39997
|
+
}
|
|
39998
|
+
const MAX_PREVIEW_NAMES = 3;
|
|
39999
|
+
const previewNames = elementNames.slice(0, MAX_PREVIEW_NAMES);
|
|
40000
|
+
const remainingCount = elementNames.length - previewNames.length;
|
|
40001
|
+
const namesList = previewNames.join(", ");
|
|
40002
|
+
const moreNote = remainingCount > 0 ? `... +${remainingCount} more` : "";
|
|
40003
|
+
return `${heading}${refPart}: ${namesList}${moreNote}`;
|
|
40004
|
+
}
|
|
40005
|
+
function formatSectionOutput(section, indent, showCollapsed) {
|
|
40006
|
+
if (section.gridInfo) {
|
|
40007
|
+
return formatGridOutput(section.gridInfo, indent);
|
|
40008
|
+
}
|
|
40009
|
+
const indentStr = " ".repeat(indent);
|
|
40010
|
+
const lines = [];
|
|
40011
|
+
const headingPrefix = section.level > 0 ? "#".repeat(Math.min(section.level + 2, 6)) + " " : "";
|
|
40012
|
+
const refPart = section.ref ? ` [${section.ref}]` : "";
|
|
40013
|
+
const focusedPart = section.isFocused ? " [FOCUSED]" : "";
|
|
40014
|
+
const backgroundPart = section.isBackground ? " [BACKGROUND]" : "";
|
|
40015
|
+
const activePart = section.containsActive && !section.isFocused ? " \u2190 ACTIVE" : "";
|
|
40016
|
+
lines.push(`${indentStr}${headingPrefix}${section.heading}${refPart}${focusedPart}${backgroundPart}${activePart}`);
|
|
40017
|
+
if (section.collapsed && !showCollapsed) {
|
|
40018
|
+
if (section.isBackground) {
|
|
40019
|
+
if (section.ref) {
|
|
40020
|
+
lines.push(`${indentStr} (${section.elementCount} elements - use expand="${section.ref}" to see content)`);
|
|
40021
|
+
} else {
|
|
40022
|
+
lines.push(`${indentStr} (${section.elementCount} elements)`);
|
|
40023
|
+
}
|
|
40024
|
+
return lines.join("\n");
|
|
40025
|
+
}
|
|
40026
|
+
const MAX_DIRECT_ELEMENTS = 4;
|
|
40027
|
+
const previewElements = section.elements.slice(0, MAX_DIRECT_ELEMENTS);
|
|
40028
|
+
const remainingDirectCount = section.elements.length - previewElements.length;
|
|
40029
|
+
for (const el of previewElements) {
|
|
40030
|
+
lines.push(formatElementLine(el, indent + 1));
|
|
40031
|
+
}
|
|
40032
|
+
if (remainingDirectCount > 0) {
|
|
40033
|
+
lines.push(`${indentStr} ... +${remainingDirectCount} more elements`);
|
|
40034
|
+
}
|
|
40035
|
+
for (const subsection of section.subsections) {
|
|
40036
|
+
lines.push(`${indentStr} ${formatSubsectionSummary(subsection)}`);
|
|
40037
|
+
}
|
|
40038
|
+
if (section.ref && (section.elements.length > MAX_DIRECT_ELEMENTS || section.subsections.length > 0)) {
|
|
40039
|
+
lines.push(`${indentStr} (use expand="${section.ref}" to see all)`);
|
|
40040
|
+
}
|
|
40041
|
+
return lines.join("\n");
|
|
40042
|
+
}
|
|
40043
|
+
for (const el of section.elements) {
|
|
40044
|
+
lines.push(formatElementLine(el, indent + 1));
|
|
40045
|
+
}
|
|
40046
|
+
for (const subsection of section.subsections) {
|
|
40047
|
+
const subsectionOutput = formatSectionOutput(subsection, indent + 1, showCollapsed);
|
|
40048
|
+
if (subsectionOutput) {
|
|
40049
|
+
lines.push("");
|
|
40050
|
+
lines.push(subsectionOutput);
|
|
40051
|
+
}
|
|
40052
|
+
}
|
|
40053
|
+
return lines.join("\n");
|
|
40054
|
+
}
|
|
40055
|
+
function countRenderedElements(sections) {
|
|
40056
|
+
let count = 0;
|
|
40057
|
+
for (const section of sections) {
|
|
40058
|
+
count += section.elements.length;
|
|
40059
|
+
if (section.gridInfo) {
|
|
40060
|
+
count += countRenderedGridItems(section.gridInfo);
|
|
40061
|
+
}
|
|
40062
|
+
count += countRenderedElements(section.subsections);
|
|
40063
|
+
}
|
|
40064
|
+
return count;
|
|
40065
|
+
}
|
|
40066
|
+
function countTotalSections(sections) {
|
|
40067
|
+
let count = sections.length;
|
|
40068
|
+
for (const section of sections) {
|
|
40069
|
+
count += countTotalSections(section.subsections);
|
|
40070
|
+
}
|
|
40071
|
+
return count;
|
|
40072
|
+
}
|
|
39652
40073
|
function generateFrontmatter(elementCount, sectionCount, activeElement, dialogStack, searchMatches, totalMatchCount, snapshotFilePath, probeResult, currentTime, capturedToasts) {
|
|
39653
|
-
const activeLabel = activeElement ?
|
|
39654
|
-
activeElement.role,
|
|
39655
|
-
INTERACTIVE_LEAF_ROLES.has(activeElement.role) && isExpandedWithActionableChildren(activeElement) ? composeTriggerLabel(activeElement) : activeElement.text || ""
|
|
39656
|
-
) : "";
|
|
40074
|
+
const activeLabel = activeElement ? (FORM_INPUT_ROLES.has(activeElement.role) || activeElement.role === "button" || activeElement.role === "link") && (activeElement.attributes["expanded"] === "true" || activeElement.attributes["aria-expanded"] === "true") ? getDisplayText(activeElement, { overrideLabel: composeTriggerLabel(activeElement) }) : getDisplayText(activeElement) : "";
|
|
39657
40075
|
const activeDesc = activeElement ? `${activeElement.ref} ${activeElement.role} "${activeLabel}"` : "None";
|
|
39658
40076
|
const dialogStackLine = dialogStack.length > 0 ? `
|
|
39659
40077
|
DIALOG STACK: ${dialogStack.join(" \u2192 ")}` : "";
|
|
@@ -39692,9 +40110,8 @@ ${toastLines.join("\n")}`;
|
|
|
39692
40110
|
SEARCH RESULTS (${matchCountText}${sortNote}):
|
|
39693
40111
|
${matchLines.join("\n")}`;
|
|
39694
40112
|
}
|
|
39695
|
-
const INPUT_ROLES = /* @__PURE__ */ new Set(["textbox", "combobox", "searchbox", "spinbutton"]);
|
|
39696
40113
|
let typeActionHint = "";
|
|
39697
|
-
if (activeElement &&
|
|
40114
|
+
if (activeElement && FORM_INPUT_ROLES.has(activeElement.role)) {
|
|
39698
40115
|
typeActionHint = `
|
|
39699
40116
|
- Type in active field: browser_type ref=${activeElement.ref} text="..."`;
|
|
39700
40117
|
}
|
|
@@ -39729,21 +40146,6 @@ ACTIONS:
|
|
|
39729
40146
|
- Use bash or python_execute on the FULL TREE FILE for detailed element analysis
|
|
39730
40147
|
---`;
|
|
39731
40148
|
}
|
|
39732
|
-
function countTotalElements(sections) {
|
|
39733
|
-
let count = 0;
|
|
39734
|
-
for (const section of sections) {
|
|
39735
|
-
count += section.elements.length;
|
|
39736
|
-
count += countTotalElements(section.subsections);
|
|
39737
|
-
}
|
|
39738
|
-
return count;
|
|
39739
|
-
}
|
|
39740
|
-
function countTotalSections(sections) {
|
|
39741
|
-
let count = sections.length;
|
|
39742
|
-
for (const section of sections) {
|
|
39743
|
-
count += countTotalSections(section.subsections);
|
|
39744
|
-
}
|
|
39745
|
-
return count;
|
|
39746
|
-
}
|
|
39747
40149
|
function formatSemanticSnapshot(yaml, options) {
|
|
39748
40150
|
if (!yaml || yaml.trim() === "") {
|
|
39749
40151
|
return "---\nSEMANTIC SNAPSHOT - 0 elements\nPage appears empty or not loaded.\n---";
|
|
@@ -39775,10 +40177,9 @@ function formatSemanticSnapshot(yaml, options) {
|
|
|
39775
40177
|
}
|
|
39776
40178
|
}
|
|
39777
40179
|
if (options?.probeResult?.ref) {
|
|
39778
|
-
|
|
39779
|
-
markMatchingSections(sortedSections, probeRefs);
|
|
40180
|
+
markMatchingSections(sortedSections, /* @__PURE__ */ new Set([options.probeResult.ref]));
|
|
39780
40181
|
}
|
|
39781
|
-
const elementCount =
|
|
40182
|
+
const elementCount = countRenderedElements(sortedSections);
|
|
39782
40183
|
const sectionCount = countTotalSections(sortedSections);
|
|
39783
40184
|
const lines = [];
|
|
39784
40185
|
lines.push(
|
|
@@ -39788,7 +40189,6 @@ function formatSemanticSnapshot(yaml, options) {
|
|
|
39788
40189
|
activeElement,
|
|
39789
40190
|
dialogStack,
|
|
39790
40191
|
sortedMatches,
|
|
39791
|
-
// Use re-sorted matches with context
|
|
39792
40192
|
options?.totalMatchCount,
|
|
39793
40193
|
options?.snapshotFilePath,
|
|
39794
40194
|
options?.probeResult,
|
|
@@ -39818,7 +40218,7 @@ function expandSection(yaml, sectionRef) {
|
|
|
39818
40218
|
const sections = buildSectionTree(elements);
|
|
39819
40219
|
const { sorted: sortedSections, dialogStack } = sortSectionsByFocus(sections);
|
|
39820
40220
|
expandSectionByRef(sortedSections, sectionRef);
|
|
39821
|
-
const elementCount =
|
|
40221
|
+
const elementCount = countRenderedElements(sortedSections);
|
|
39822
40222
|
const sectionCount = countTotalSections(sortedSections);
|
|
39823
40223
|
const lines = [];
|
|
39824
40224
|
lines.push(generateFrontmatter(elementCount, sectionCount, activeElement, dialogStack));
|
|
@@ -39832,29 +40232,26 @@ function expandSection(yaml, sectionRef) {
|
|
|
39832
40232
|
}
|
|
39833
40233
|
return lines.join("\n").trim();
|
|
39834
40234
|
}
|
|
39835
|
-
function
|
|
39836
|
-
|
|
39837
|
-
|
|
39838
|
-
|
|
39839
|
-
|
|
39840
|
-
|
|
39841
|
-
|
|
39842
|
-
|
|
39843
|
-
|
|
40235
|
+
function formatExpandedSectionOutput(section) {
|
|
40236
|
+
const lines = [];
|
|
40237
|
+
const subsectionInfo = section.subsections.length > 0 ? `, ${section.subsections.length} subsections` : "";
|
|
40238
|
+
lines.push(`---`);
|
|
40239
|
+
lines.push(`EXPANDED SECTION: ${section.heading} [${section.ref}]`);
|
|
40240
|
+
lines.push(`Contains ${section.elementCount} elements${subsectionInfo}`);
|
|
40241
|
+
lines.push(`---`);
|
|
40242
|
+
lines.push("");
|
|
40243
|
+
if (section.gridInfo) {
|
|
40244
|
+
lines.push(formatGridOutput(section.gridInfo, 0, true));
|
|
40245
|
+
return lines.join("\n").trim();
|
|
39844
40246
|
}
|
|
39845
|
-
|
|
39846
|
-
|
|
39847
|
-
function findSectionByRef(sections, targetRef) {
|
|
39848
|
-
for (const section of sections) {
|
|
39849
|
-
if (section.ref === targetRef) {
|
|
39850
|
-
return section;
|
|
39851
|
-
}
|
|
39852
|
-
const found = findSectionByRef(section.subsections, targetRef);
|
|
39853
|
-
if (found) {
|
|
39854
|
-
return found;
|
|
39855
|
-
}
|
|
40247
|
+
for (const el of section.elements) {
|
|
40248
|
+
lines.push(formatElementLine(el, 0));
|
|
39856
40249
|
}
|
|
39857
|
-
|
|
40250
|
+
for (const subsection of section.subsections) {
|
|
40251
|
+
lines.push("");
|
|
40252
|
+
lines.push(formatSectionOutput(subsection, 0, false));
|
|
40253
|
+
}
|
|
40254
|
+
return lines.join("\n").trim();
|
|
39858
40255
|
}
|
|
39859
40256
|
function expandSectionOnly(yaml, sectionRef) {
|
|
39860
40257
|
if (!yaml || yaml.trim() === "") {
|
|
@@ -39881,79 +40278,133 @@ Section with ref="${sectionRef}" not found in snapshot.
|
|
|
39881
40278
|
targetSection.collapsed = false;
|
|
39882
40279
|
return formatExpandedSectionOutput(targetSection);
|
|
39883
40280
|
}
|
|
39884
|
-
|
|
39885
|
-
|
|
39886
|
-
|
|
39887
|
-
|
|
39888
|
-
|
|
39889
|
-
|
|
39890
|
-
|
|
39891
|
-
|
|
39892
|
-
|
|
39893
|
-
|
|
39894
|
-
|
|
39895
|
-
|
|
39896
|
-
|
|
39897
|
-
|
|
40281
|
+
|
|
40282
|
+
// ../browser-core/src/table-extractor.ts
|
|
40283
|
+
function extractTablesFromSnapshot(yamlOrResponse, options) {
|
|
40284
|
+
const yaml = yamlOrResponse.includes("Page Snapshot:") ? extractSnapshotYaml(yamlOrResponse) : yamlOrResponse;
|
|
40285
|
+
if (!yaml) return null;
|
|
40286
|
+
const elements = parseSnapshot(yaml);
|
|
40287
|
+
if (elements.length === 0) return null;
|
|
40288
|
+
const grids = [];
|
|
40289
|
+
const findGrids = (els) => {
|
|
40290
|
+
for (const el of els) {
|
|
40291
|
+
const grid = detectGrid(el);
|
|
40292
|
+
if (grid && grid.rows.length > 0) {
|
|
40293
|
+
grids.push({ grid, element: el });
|
|
40294
|
+
}
|
|
40295
|
+
if (!grid) {
|
|
40296
|
+
findGrids(el.children);
|
|
40297
|
+
}
|
|
40298
|
+
}
|
|
40299
|
+
};
|
|
40300
|
+
findGrids(elements);
|
|
40301
|
+
if (grids.length === 0) return null;
|
|
40302
|
+
let target;
|
|
40303
|
+
if (options?.ref) {
|
|
40304
|
+
const match = grids.find((g) => g.grid.ref === options.ref);
|
|
40305
|
+
if (!match) return null;
|
|
40306
|
+
target = match;
|
|
40307
|
+
} else {
|
|
40308
|
+
target = grids.reduce(
|
|
40309
|
+
(best, current) => current.grid.rows.length > best.grid.rows.length ? current : best
|
|
40310
|
+
);
|
|
39898
40311
|
}
|
|
39899
|
-
|
|
40312
|
+
const { columns, rows } = gridInfoToRows(target.grid);
|
|
40313
|
+
if (columns.length === 0) return null;
|
|
40314
|
+
const pagination = detectPaginationInfo(elements, target.grid.ref);
|
|
40315
|
+
return {
|
|
40316
|
+
columns,
|
|
40317
|
+
rows,
|
|
40318
|
+
gridRef: target.grid.ref,
|
|
40319
|
+
pagination: pagination ?? void 0
|
|
40320
|
+
};
|
|
39900
40321
|
}
|
|
39901
|
-
function
|
|
39902
|
-
const
|
|
39903
|
-
|
|
39904
|
-
const
|
|
39905
|
-
|
|
39906
|
-
|
|
39907
|
-
if (grid.columns.length > 0) {
|
|
39908
|
-
const displayColumns = grid.columns.slice(0, MAX_DISPLAY_COLUMNS);
|
|
39909
|
-
const colsWithRefs = displayColumns.map((c2) => `${c2.name} [${c2.ref}]`).join(", ");
|
|
39910
|
-
const moreColsNote = grid.columns.length > MAX_DISPLAY_COLUMNS ? ` (+${grid.columns.length - MAX_DISPLAY_COLUMNS} more)` : "";
|
|
39911
|
-
lines.push(`${indentStr} Columns: ${colsWithRefs}${moreColsNote}`);
|
|
40322
|
+
function gridInfoToRows(grid) {
|
|
40323
|
+
const columns = grid.columns.map((c2) => c2.name);
|
|
40324
|
+
if (columns.length === 0) return { columns: [], rows: [] };
|
|
40325
|
+
const columnIndex = /* @__PURE__ */ new Map();
|
|
40326
|
+
for (let i = 0; i < columns.length; i++) {
|
|
40327
|
+
columnIndex.set(columns[i], i);
|
|
39912
40328
|
}
|
|
39913
|
-
|
|
39914
|
-
const
|
|
39915
|
-
|
|
39916
|
-
|
|
39917
|
-
|
|
39918
|
-
|
|
40329
|
+
const rows = [];
|
|
40330
|
+
for (const row of grid.rows) {
|
|
40331
|
+
const values = new Array(columns.length).fill("");
|
|
40332
|
+
for (const cell of row.cells) {
|
|
40333
|
+
const idx = columnIndex.get(cell.column);
|
|
40334
|
+
if (idx !== void 0) {
|
|
40335
|
+
values[idx] = cleanCellValue(cell.value, cell.gridcellLabel);
|
|
40336
|
+
}
|
|
40337
|
+
}
|
|
40338
|
+
rows.push(values);
|
|
39919
40339
|
}
|
|
39920
|
-
|
|
39921
|
-
|
|
40340
|
+
return { columns, rows };
|
|
40341
|
+
}
|
|
40342
|
+
var SVG_ARTIFACT_PATTERN = /^Styled\(svg\)$/i;
|
|
40343
|
+
function cleanCellValue(value, gridcellLabel) {
|
|
40344
|
+
if (!value || SVG_ARTIFACT_PATTERN.test(value)) {
|
|
40345
|
+
if (gridcellLabel) {
|
|
40346
|
+
return gridcellLabel.replace(/\s*Styled\(svg\)\s*/gi, "").trim();
|
|
40347
|
+
}
|
|
40348
|
+
return "";
|
|
39922
40349
|
}
|
|
39923
|
-
return
|
|
40350
|
+
return value;
|
|
39924
40351
|
}
|
|
39925
|
-
function
|
|
39926
|
-
const
|
|
39927
|
-
|
|
39928
|
-
|
|
39929
|
-
|
|
39930
|
-
|
|
40352
|
+
function formatCSVWithFrontmatter(columns, rows, _options) {
|
|
40353
|
+
const lines = [];
|
|
40354
|
+
lines.push(columns.map(escapeCSVField).join(","));
|
|
40355
|
+
for (const row of rows) {
|
|
40356
|
+
lines.push(row.map(escapeCSVField).join(","));
|
|
40357
|
+
}
|
|
40358
|
+
return lines.join("\n") + "\n";
|
|
40359
|
+
}
|
|
40360
|
+
function appendRowsToCSV(existingCSV, newRows, columns, _options) {
|
|
40361
|
+
const existingLines = existingCSV.split("\n").filter((l) => l.trim() !== "");
|
|
40362
|
+
const dataLines = [];
|
|
40363
|
+
let headerLine = "";
|
|
40364
|
+
for (const line of existingLines) {
|
|
40365
|
+
if (line.startsWith("#")) continue;
|
|
40366
|
+
if (!headerLine) {
|
|
40367
|
+
headerLine = line;
|
|
40368
|
+
continue;
|
|
39931
40369
|
}
|
|
39932
|
-
|
|
39933
|
-
|
|
40370
|
+
dataLines.push(line);
|
|
40371
|
+
}
|
|
40372
|
+
const existingRowSet = new Set(dataLines);
|
|
40373
|
+
const newRowStrings = newRows.map((row) => row.map(escapeCSVField).join(","));
|
|
40374
|
+
const addedRows = [];
|
|
40375
|
+
for (const rowStr of newRowStrings) {
|
|
40376
|
+
if (!existingRowSet.has(rowStr)) {
|
|
40377
|
+
addedRows.push(rowStr);
|
|
40378
|
+
existingRowSet.add(rowStr);
|
|
39934
40379
|
}
|
|
39935
|
-
return `${indentStr} \u21B3 Expanded [${row.ref}]: ${parts.join(" | ")}`;
|
|
39936
40380
|
}
|
|
39937
|
-
const
|
|
39938
|
-
const
|
|
39939
|
-
|
|
39940
|
-
|
|
39941
|
-
|
|
39942
|
-
|
|
39943
|
-
|
|
39944
|
-
|
|
39945
|
-
|
|
39946
|
-
|
|
39947
|
-
|
|
39948
|
-
|
|
39949
|
-
return `${
|
|
40381
|
+
const allDataLines = [...dataLines, ...addedRows];
|
|
40382
|
+
const result = [headerLine || columns.map(escapeCSVField).join(","), ...allDataLines];
|
|
40383
|
+
return result.join("\n") + "\n";
|
|
40384
|
+
}
|
|
40385
|
+
function detectPaginationInfo(elements, _gridRef) {
|
|
40386
|
+
const paginationPattern = /(\d+)\s*[-–]\s*(\d+)\s+of\s+([\d,]+)/i;
|
|
40387
|
+
const searchText = (els) => {
|
|
40388
|
+
for (const el of els) {
|
|
40389
|
+
const text = el.text || "";
|
|
40390
|
+
const match = text.match(paginationPattern);
|
|
40391
|
+
if (match) {
|
|
40392
|
+
const total = parseInt(match[3].replace(/,/g, ""), 10);
|
|
40393
|
+
return { showing: `${match[1]}-${match[2]}`, total };
|
|
39950
40394
|
}
|
|
39951
|
-
|
|
39952
|
-
|
|
39953
|
-
|
|
39954
|
-
|
|
39955
|
-
|
|
40395
|
+
const childResult = searchText(el.children);
|
|
40396
|
+
if (childResult) return childResult;
|
|
40397
|
+
}
|
|
40398
|
+
return null;
|
|
40399
|
+
};
|
|
40400
|
+
return searchText(elements);
|
|
40401
|
+
}
|
|
40402
|
+
function escapeCSVField(field) {
|
|
40403
|
+
if (!field) return "";
|
|
40404
|
+
if (field.includes(",") || field.includes('"') || field.includes("\n")) {
|
|
40405
|
+
return `"${field.replace(/"/g, '""')}"`;
|
|
39956
40406
|
}
|
|
40407
|
+
return field;
|
|
39957
40408
|
}
|
|
39958
40409
|
|
|
39959
40410
|
// ../browser-core/src/snapshot-diff.ts
|
|
@@ -41898,6 +42349,136 @@ function getBrowserToolDefinitionsWithLifecycle() {
|
|
|
41898
42349
|
];
|
|
41899
42350
|
}
|
|
41900
42351
|
|
|
42352
|
+
// ../browser-core/src/tools/dispatcher.ts
|
|
42353
|
+
async function dispatchBrowserTool(executor, toolName, args) {
|
|
42354
|
+
switch (toolName) {
|
|
42355
|
+
case "browser_navigate":
|
|
42356
|
+
return executor.navigate(args.url);
|
|
42357
|
+
case "browser_navigate_back":
|
|
42358
|
+
return executor.navigateBack();
|
|
42359
|
+
case "browser_snapshot":
|
|
42360
|
+
return executor.snapshot({
|
|
42361
|
+
mode: args.mode,
|
|
42362
|
+
expand: args.expand,
|
|
42363
|
+
search: args.search,
|
|
42364
|
+
showCoordinateGrid: args.showCoordinateGrid,
|
|
42365
|
+
probeAt: args.probeAt
|
|
42366
|
+
});
|
|
42367
|
+
case "browser_screenshot":
|
|
42368
|
+
return executor.screenshot({
|
|
42369
|
+
fullPage: args.fullPage,
|
|
42370
|
+
element: args.element,
|
|
42371
|
+
ref: args.ref,
|
|
42372
|
+
label: args.label,
|
|
42373
|
+
returnImage: args.returnImage
|
|
42374
|
+
});
|
|
42375
|
+
case "browser_evaluate":
|
|
42376
|
+
return executor.evaluate({
|
|
42377
|
+
expression: args.function,
|
|
42378
|
+
element: args.element,
|
|
42379
|
+
ref: args.ref
|
|
42380
|
+
});
|
|
42381
|
+
case "browser_console_messages":
|
|
42382
|
+
return executor.consoleMessages({
|
|
42383
|
+
onlyErrors: args.onlyErrors
|
|
42384
|
+
});
|
|
42385
|
+
case "browser_network_requests":
|
|
42386
|
+
return executor.networkRequests();
|
|
42387
|
+
case "browser_click":
|
|
42388
|
+
return executor.click({
|
|
42389
|
+
ref: args.ref,
|
|
42390
|
+
x: args.x,
|
|
42391
|
+
y: args.y,
|
|
42392
|
+
element: args.element,
|
|
42393
|
+
doubleClick: args.doubleClick,
|
|
42394
|
+
button: args.button,
|
|
42395
|
+
modifiers: args.modifiers
|
|
42396
|
+
});
|
|
42397
|
+
case "browser_hover":
|
|
42398
|
+
return executor.hover({
|
|
42399
|
+
ref: args.ref,
|
|
42400
|
+
element: args.element
|
|
42401
|
+
});
|
|
42402
|
+
case "browser_drag":
|
|
42403
|
+
return executor.drag({
|
|
42404
|
+
startRef: args.startRef,
|
|
42405
|
+
endRef: args.endRef,
|
|
42406
|
+
startElement: args.startElement,
|
|
42407
|
+
endElement: args.endElement,
|
|
42408
|
+
startX: args.startX,
|
|
42409
|
+
startY: args.startY,
|
|
42410
|
+
endX: args.endX,
|
|
42411
|
+
endY: args.endY
|
|
42412
|
+
});
|
|
42413
|
+
case "browser_type":
|
|
42414
|
+
return executor.type({
|
|
42415
|
+
ref: args.ref,
|
|
42416
|
+
text: args.text,
|
|
42417
|
+
element: args.element,
|
|
42418
|
+
submit: args.submit,
|
|
42419
|
+
delay: args.delay
|
|
42420
|
+
});
|
|
42421
|
+
case "browser_press_key":
|
|
42422
|
+
return executor.pressKey(args.key);
|
|
42423
|
+
case "browser_fill_form":
|
|
42424
|
+
return executor.fillForm(
|
|
42425
|
+
args.fields
|
|
42426
|
+
);
|
|
42427
|
+
case "browser_select_option":
|
|
42428
|
+
return executor.selectOption({
|
|
42429
|
+
ref: args.ref,
|
|
42430
|
+
value: args.value,
|
|
42431
|
+
element: args.element
|
|
42432
|
+
});
|
|
42433
|
+
case "browser_file_upload":
|
|
42434
|
+
return executor.fileUpload(args.paths);
|
|
42435
|
+
case "browser_scroll":
|
|
42436
|
+
return executor.scroll({
|
|
42437
|
+
direction: args.direction,
|
|
42438
|
+
amount: args.amount,
|
|
42439
|
+
withinRef: args.withinRef,
|
|
42440
|
+
toRef: args.toRef,
|
|
42441
|
+
x: args.x,
|
|
42442
|
+
y: args.y
|
|
42443
|
+
});
|
|
42444
|
+
case "browser_handle_dialog":
|
|
42445
|
+
return executor.handleDialog({
|
|
42446
|
+
action: args.action,
|
|
42447
|
+
promptText: args.promptText
|
|
42448
|
+
});
|
|
42449
|
+
case "browser_dismiss_overlay":
|
|
42450
|
+
return executor.dismissOverlay({
|
|
42451
|
+
preferredStrategy: args.preferredStrategy
|
|
42452
|
+
});
|
|
42453
|
+
case "browser_wait_for":
|
|
42454
|
+
return executor.waitFor({
|
|
42455
|
+
timeSec: args.time,
|
|
42456
|
+
text: args.text,
|
|
42457
|
+
textGone: args.textGone,
|
|
42458
|
+
selector: args.selector,
|
|
42459
|
+
state: args.state,
|
|
42460
|
+
timeout: args.timeout
|
|
42461
|
+
});
|
|
42462
|
+
case "browser_close":
|
|
42463
|
+
return executor.close();
|
|
42464
|
+
case "browser_resize":
|
|
42465
|
+
return executor.resize(args.width, args.height);
|
|
42466
|
+
case "browser_tabs":
|
|
42467
|
+
return executor.tabs({
|
|
42468
|
+
action: args.action,
|
|
42469
|
+
index: args.index
|
|
42470
|
+
});
|
|
42471
|
+
case "browser_list_downloads":
|
|
42472
|
+
return executor.listDownloads();
|
|
42473
|
+
case "browser_read_download":
|
|
42474
|
+
return executor.readDownload(args.downloadId);
|
|
42475
|
+
case "browser_pdf_read":
|
|
42476
|
+
return executor.fetchPdfText(args.url);
|
|
42477
|
+
default:
|
|
42478
|
+
throw new Error(`Unknown browser tool: ${toolName}`);
|
|
42479
|
+
}
|
|
42480
|
+
}
|
|
42481
|
+
|
|
41901
42482
|
// ../browser-core/src/playwright-client.ts
|
|
41902
42483
|
import {
|
|
41903
42484
|
chromium as playwrightChromium
|
|
@@ -43018,6 +43599,29 @@ function appendAttributeIfMissing(line, key, value) {
|
|
|
43018
43599
|
const baseLine = hasTrailingColon ? line.replace(/:\s*$/, "") : line;
|
|
43019
43600
|
return `${baseLine} [${key}=${value}]${hasTrailingColon ? ":" : ""}`;
|
|
43020
43601
|
}
|
|
43602
|
+
function findLabelFromYamlSiblings(elements, targetRef) {
|
|
43603
|
+
const findParent = (els, parent2) => {
|
|
43604
|
+
for (const el of els) {
|
|
43605
|
+
if (el.ref === targetRef) return parent2;
|
|
43606
|
+
const found = findParent(el.children, el);
|
|
43607
|
+
if (found) return found;
|
|
43608
|
+
}
|
|
43609
|
+
return null;
|
|
43610
|
+
};
|
|
43611
|
+
const parent = findParent(elements, null);
|
|
43612
|
+
if (!parent) return void 0;
|
|
43613
|
+
const targetIdx = parent.children.findIndex((c2) => c2.ref === targetRef);
|
|
43614
|
+
if (targetIdx < 0) return void 0;
|
|
43615
|
+
for (let i = targetIdx - 1; i >= 0; i--) {
|
|
43616
|
+
const sib = parent.children[i];
|
|
43617
|
+
const sibText = sib.text?.trim();
|
|
43618
|
+
if (sibText && sibText.length > 0 && sibText.length < 80 && /[a-zA-Z0-9]/.test(sibText)) {
|
|
43619
|
+
if (FORM_FIELD_ROLES.has(sib.role)) continue;
|
|
43620
|
+
return sibText;
|
|
43621
|
+
}
|
|
43622
|
+
}
|
|
43623
|
+
return void 0;
|
|
43624
|
+
}
|
|
43021
43625
|
async function augmentUnlabeledElements(page, yaml, logger2) {
|
|
43022
43626
|
try {
|
|
43023
43627
|
const elements = parseSnapshot(yaml);
|
|
@@ -43323,6 +43927,9 @@ async function augmentGridCellValues(page, yaml, logger2) {
|
|
|
43323
43927
|
}
|
|
43324
43928
|
}
|
|
43325
43929
|
var FORM_FIELD_ROLES = /* @__PURE__ */ new Set(["textbox", "combobox", "searchbox"]);
|
|
43930
|
+
function splitCamelCase(name) {
|
|
43931
|
+
return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\s+/g, " ").trim();
|
|
43932
|
+
}
|
|
43326
43933
|
async function augmentFormFieldLabels(page, yaml, logger2) {
|
|
43327
43934
|
try {
|
|
43328
43935
|
const elements = parseSnapshot(yaml);
|
|
@@ -43340,16 +43947,30 @@ async function augmentFormFieldLabels(page, yaml, logger2) {
|
|
|
43340
43947
|
walkForFields(el);
|
|
43341
43948
|
}
|
|
43342
43949
|
if (formFieldRefs.length === 0) return yaml;
|
|
43343
|
-
|
|
43950
|
+
const glyphFields = formFieldRefs.filter((f) => f.text && !/[a-zA-Z0-9]/.test(f.text));
|
|
43951
|
+
const displayNameIdx = yaml.indexOf("Display Name");
|
|
43952
|
+
const yamlAroundDisplayName = displayNameIdx >= 0 ? yaml.slice(Math.max(0, displayNameIdx - 50), displayNameIdx + 200) : "NOT FOUND";
|
|
43953
|
+
logger2.warn("[DirectPlaywright] augmentFormFieldLabels called", {
|
|
43344
43954
|
count: formFieldRefs.length,
|
|
43345
|
-
|
|
43955
|
+
glyphCount: glyphFields.length,
|
|
43956
|
+
allTexts: formFieldRefs.map((f) => `${f.ref}:${JSON.stringify(f.text)}`),
|
|
43957
|
+
hasDisplayName: yaml.includes("Display Name"),
|
|
43958
|
+
yamlHasGlyph: yaml.includes("\u268A"),
|
|
43959
|
+
yamlAroundDisplayName
|
|
43346
43960
|
});
|
|
43347
43961
|
let augmented = yaml;
|
|
43348
43962
|
for (const { ref, role, text } of formFieldRefs) {
|
|
43349
43963
|
try {
|
|
43964
|
+
const isGlyphField = text && !/[a-zA-Z0-9]/.test(text);
|
|
43965
|
+
if (isGlyphField) {
|
|
43966
|
+
logger2.info("[DirectPlaywright] Glyph-labeled field entering augmentation", { ref, role, text });
|
|
43967
|
+
}
|
|
43350
43968
|
const locator = page.locator(`aria-ref=${ref}`);
|
|
43351
43969
|
const count = await locator.count();
|
|
43352
|
-
if (count === 0)
|
|
43970
|
+
if (count === 0) {
|
|
43971
|
+
if (isGlyphField) logger2.info("[DirectPlaywright] Glyph field: locator count=0, skipping", { ref });
|
|
43972
|
+
continue;
|
|
43973
|
+
}
|
|
43353
43974
|
const label = await locator.first().evaluate((el) => {
|
|
43354
43975
|
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
|
|
43355
43976
|
const labels = el.labels;
|
|
@@ -43358,6 +43979,30 @@ async function augmentFormFieldLabels(page, yaml, logger2) {
|
|
|
43358
43979
|
if (labelText) return labelText;
|
|
43359
43980
|
}
|
|
43360
43981
|
}
|
|
43982
|
+
{
|
|
43983
|
+
const precedingLabels = [];
|
|
43984
|
+
let prevEl = el.previousElementSibling;
|
|
43985
|
+
while (prevEl) {
|
|
43986
|
+
if (prevEl.tagName === "LABEL") {
|
|
43987
|
+
precedingLabels.unshift(prevEl);
|
|
43988
|
+
} else {
|
|
43989
|
+
break;
|
|
43990
|
+
}
|
|
43991
|
+
prevEl = prevEl.previousElementSibling;
|
|
43992
|
+
}
|
|
43993
|
+
if (precedingLabels.length > 1) {
|
|
43994
|
+
const selected = precedingLabels.find((l) => {
|
|
43995
|
+
const cls = l.className.toLowerCase();
|
|
43996
|
+
return cls.includes("selected") || cls.includes("active") || cls.includes("current") || cls.includes("checked");
|
|
43997
|
+
});
|
|
43998
|
+
if (selected?.textContent?.trim()) return selected.textContent.trim();
|
|
43999
|
+
const first = precedingLabels[0];
|
|
44000
|
+
if (first?.textContent?.trim()) return first.textContent.trim();
|
|
44001
|
+
} else if (precedingLabels.length === 1) {
|
|
44002
|
+
const labelText = precedingLabels[0].textContent?.trim();
|
|
44003
|
+
if (labelText) return labelText;
|
|
44004
|
+
}
|
|
44005
|
+
}
|
|
43361
44006
|
const labelledBy = el.getAttribute("aria-labelledby");
|
|
43362
44007
|
if (labelledBy) {
|
|
43363
44008
|
const labelEl = document.getElementById(labelledBy);
|
|
@@ -43365,31 +44010,101 @@ async function augmentFormFieldLabels(page, yaml, logger2) {
|
|
|
43365
44010
|
}
|
|
43366
44011
|
const ariaLabel = el.getAttribute("aria-label");
|
|
43367
44012
|
const placeholder = el.getAttribute("placeholder");
|
|
43368
|
-
if (ariaLabel && ariaLabel !== placeholder) return ariaLabel;
|
|
43369
|
-
let sibling = el.previousElementSibling;
|
|
44013
|
+
if (ariaLabel && ariaLabel !== placeholder && /[a-zA-Z0-9]/.test(ariaLabel)) return ariaLabel;
|
|
43370
44014
|
let target = el;
|
|
43371
|
-
for (let
|
|
43372
|
-
sibling = target.previousElementSibling;
|
|
43373
|
-
|
|
44015
|
+
for (let depth = 0; depth < 3 && target; depth++) {
|
|
44016
|
+
let sibling = target.previousElementSibling;
|
|
44017
|
+
for (let sibCount = 0; sibling && sibCount < 3; sibCount++) {
|
|
43374
44018
|
const sibText = sibling.textContent?.trim();
|
|
43375
44019
|
if (sibText && sibText.length > 0 && sibText.length < 80 && !sibling.querySelector("input, textarea, select, button")) {
|
|
43376
44020
|
return sibText;
|
|
43377
44021
|
}
|
|
44022
|
+
if (sibling.querySelector("input, textarea, select, button")) break;
|
|
44023
|
+
sibling = sibling.previousElementSibling;
|
|
43378
44024
|
}
|
|
43379
44025
|
target = target.parentElement;
|
|
43380
44026
|
}
|
|
43381
44027
|
return void 0;
|
|
43382
44028
|
});
|
|
44029
|
+
if (isGlyphField) {
|
|
44030
|
+
logger2.info("[DirectPlaywright] Glyph field: DOM evaluate result", { ref, label, text });
|
|
44031
|
+
}
|
|
43383
44032
|
if (label && label !== text) {
|
|
43384
44033
|
augmented = updateElementLineByRef(
|
|
43385
44034
|
augmented,
|
|
43386
44035
|
ref,
|
|
43387
44036
|
(line) => injectElementLabel(line, role, label)
|
|
43388
44037
|
);
|
|
44038
|
+
if (isGlyphField) {
|
|
44039
|
+
logger2.info("[DirectPlaywright] Glyph field: injected DOM label", { ref, label });
|
|
44040
|
+
}
|
|
44041
|
+
}
|
|
44042
|
+
const hasGlyphOnlyLabel = text && !/[a-zA-Z0-9]/.test(text);
|
|
44043
|
+
if (hasGlyphOnlyLabel && (!label || label === text || !/[a-zA-Z0-9]/.test(label))) {
|
|
44044
|
+
const yamlLabel = findLabelFromYamlSiblings(elements, ref);
|
|
44045
|
+
logger2.info("[DirectPlaywright] YAML sibling fallback for glyph field", {
|
|
44046
|
+
ref,
|
|
44047
|
+
text,
|
|
44048
|
+
label,
|
|
44049
|
+
yamlLabel
|
|
44050
|
+
});
|
|
44051
|
+
if (yamlLabel) {
|
|
44052
|
+
augmented = updateElementLineByRef(
|
|
44053
|
+
augmented,
|
|
44054
|
+
ref,
|
|
44055
|
+
(line) => injectElementLabel(line, role, yamlLabel)
|
|
44056
|
+
);
|
|
44057
|
+
}
|
|
43389
44058
|
}
|
|
43390
44059
|
} catch {
|
|
43391
44060
|
}
|
|
43392
44061
|
}
|
|
44062
|
+
try {
|
|
44063
|
+
const postElements = parseSnapshot(augmented);
|
|
44064
|
+
const labeledFields = [];
|
|
44065
|
+
const walkForLabeled = (el) => {
|
|
44066
|
+
if (FORM_FIELD_ROLES.has(el.role) && el.ref && el.text) {
|
|
44067
|
+
labeledFields.push({ ref: el.ref, role: el.role, label: el.text });
|
|
44068
|
+
}
|
|
44069
|
+
for (const child of el.children) walkForLabeled(child);
|
|
44070
|
+
};
|
|
44071
|
+
for (const el of postElements) walkForLabeled(el);
|
|
44072
|
+
const byLabel = /* @__PURE__ */ new Map();
|
|
44073
|
+
for (const f of labeledFields) {
|
|
44074
|
+
const existing = byLabel.get(f.label);
|
|
44075
|
+
if (existing) {
|
|
44076
|
+
existing.push({ ref: f.ref, role: f.role });
|
|
44077
|
+
} else {
|
|
44078
|
+
byLabel.set(f.label, [{ ref: f.ref, role: f.role }]);
|
|
44079
|
+
}
|
|
44080
|
+
}
|
|
44081
|
+
for (const [label, fields] of byLabel) {
|
|
44082
|
+
if (fields.length < 2) continue;
|
|
44083
|
+
for (const field of fields) {
|
|
44084
|
+
try {
|
|
44085
|
+
const locator = page.locator(`aria-ref=${field.ref}`);
|
|
44086
|
+
const count = await locator.count();
|
|
44087
|
+
if (count === 0) continue;
|
|
44088
|
+
const disambiguation = await locator.first().evaluate((el) => {
|
|
44089
|
+
const placeholder = el.getAttribute("placeholder") || void 0;
|
|
44090
|
+
const ariaLabel = el.getAttribute("aria-label") || void 0;
|
|
44091
|
+
const name = el.getAttribute("name") || void 0;
|
|
44092
|
+
return { placeholder, ariaLabel, name };
|
|
44093
|
+
});
|
|
44094
|
+
const disambig = disambiguation.placeholder || disambiguation.ariaLabel || (disambiguation.name ? splitCamelCase(disambiguation.name) : void 0);
|
|
44095
|
+
if (disambig && disambig !== label) {
|
|
44096
|
+
augmented = updateElementLineByRef(
|
|
44097
|
+
augmented,
|
|
44098
|
+
field.ref,
|
|
44099
|
+
(line) => injectElementLabel(line, field.role, disambig)
|
|
44100
|
+
);
|
|
44101
|
+
}
|
|
44102
|
+
} catch {
|
|
44103
|
+
}
|
|
44104
|
+
}
|
|
44105
|
+
}
|
|
44106
|
+
} catch {
|
|
44107
|
+
}
|
|
43393
44108
|
return augmented;
|
|
43394
44109
|
} catch (err) {
|
|
43395
44110
|
logger2.debug("[DirectPlaywright] Form field label augmentation failed", {
|
|
@@ -43594,6 +44309,148 @@ async function augmentHiddenSelectOptions(page, yaml, logger2) {
|
|
|
43594
44309
|
return yaml;
|
|
43595
44310
|
}
|
|
43596
44311
|
}
|
|
44312
|
+
async function enrichModalDialogElements(page, logger2) {
|
|
44313
|
+
try {
|
|
44314
|
+
const enrichedCount = await page.evaluate(() => {
|
|
44315
|
+
let count = 0;
|
|
44316
|
+
const MAX_ENRICHMENTS = 3;
|
|
44317
|
+
function shouldSkip(el) {
|
|
44318
|
+
if (el.getAttribute("role") === "dialog" || el.getAttribute("role") === "alertdialog") return true;
|
|
44319
|
+
if (el.getAttribute("data-enriched-dialog") === "true") return true;
|
|
44320
|
+
return false;
|
|
44321
|
+
}
|
|
44322
|
+
function isVisible(el) {
|
|
44323
|
+
const style = window.getComputedStyle(el);
|
|
44324
|
+
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
44325
|
+
if (el instanceof HTMLElement && el.offsetWidth === 0 && el.offsetHeight === 0) return false;
|
|
44326
|
+
return true;
|
|
44327
|
+
}
|
|
44328
|
+
function enrichAsDialog(el) {
|
|
44329
|
+
if (count >= MAX_ENRICHMENTS) return;
|
|
44330
|
+
if (shouldSkip(el)) return;
|
|
44331
|
+
if (!isVisible(el)) return;
|
|
44332
|
+
el.setAttribute("role", "dialog");
|
|
44333
|
+
const heading = el.querySelector("h1, h2, h3, h4, h5, h6");
|
|
44334
|
+
if (heading?.textContent?.trim()) {
|
|
44335
|
+
el.setAttribute("aria-label", heading.textContent.trim());
|
|
44336
|
+
}
|
|
44337
|
+
el.setAttribute("data-enriched-dialog", "true");
|
|
44338
|
+
count++;
|
|
44339
|
+
}
|
|
44340
|
+
function hasInteractiveContent(el) {
|
|
44341
|
+
return el.querySelector('input, textarea, select, button, a[href], [role="button"], [role="link"], [role="textbox"], [role="combobox"]') !== null;
|
|
44342
|
+
}
|
|
44343
|
+
const CLASS_PATTERNS = [
|
|
44344
|
+
/\bmodal(?![-_]?(backdrop|mask|overlay|fade|bg|background))\b/i,
|
|
44345
|
+
/\bdialog\b/i,
|
|
44346
|
+
/\bpopup\b/i,
|
|
44347
|
+
/\blightbox\b/i,
|
|
44348
|
+
/\bdrawer\b/i
|
|
44349
|
+
];
|
|
44350
|
+
const FRAMEWORK_SELECTORS = [
|
|
44351
|
+
".cdk-overlay-pane",
|
|
44352
|
+
".mat-dialog-container",
|
|
44353
|
+
".mat-mdc-dialog-container",
|
|
44354
|
+
".ui-dialog",
|
|
44355
|
+
".modal-dialog",
|
|
44356
|
+
".ant-modal-content",
|
|
44357
|
+
".el-dialog",
|
|
44358
|
+
".v-dialog",
|
|
44359
|
+
".p-dialog"
|
|
44360
|
+
];
|
|
44361
|
+
for (const selector of FRAMEWORK_SELECTORS) {
|
|
44362
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44363
|
+
const els = document.querySelectorAll(selector);
|
|
44364
|
+
for (const el of els) {
|
|
44365
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44366
|
+
if (hasInteractiveContent(el)) {
|
|
44367
|
+
enrichAsDialog(el);
|
|
44368
|
+
}
|
|
44369
|
+
}
|
|
44370
|
+
}
|
|
44371
|
+
if (count < MAX_ENRICHMENTS) {
|
|
44372
|
+
const allElements = document.querySelectorAll("*");
|
|
44373
|
+
for (const el of allElements) {
|
|
44374
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44375
|
+
const className = el.className;
|
|
44376
|
+
if (typeof className !== "string") continue;
|
|
44377
|
+
if (CLASS_PATTERNS.some((pattern) => pattern.test(className))) {
|
|
44378
|
+
if (hasInteractiveContent(el)) {
|
|
44379
|
+
enrichAsDialog(el);
|
|
44380
|
+
}
|
|
44381
|
+
}
|
|
44382
|
+
}
|
|
44383
|
+
}
|
|
44384
|
+
if (count < MAX_ENRICHMENTS) {
|
|
44385
|
+
const allFixed = document.querySelectorAll("*");
|
|
44386
|
+
for (const el of allFixed) {
|
|
44387
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44388
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
44389
|
+
const style = window.getComputedStyle(el);
|
|
44390
|
+
if (style.position !== "fixed" && style.position !== "absolute") continue;
|
|
44391
|
+
const rect = el.getBoundingClientRect();
|
|
44392
|
+
const viewportW = window.innerWidth;
|
|
44393
|
+
const viewportH = window.innerHeight;
|
|
44394
|
+
const coversViewport = rect.width >= viewportW * 0.8 && rect.height >= viewportH * 0.8;
|
|
44395
|
+
if (!coversViewport) continue;
|
|
44396
|
+
const bg = style.backgroundColor;
|
|
44397
|
+
const opacity = parseFloat(style.opacity);
|
|
44398
|
+
const isSemiTransparent = bg.includes("rgba") && !bg.includes("rgba(0, 0, 0, 0)") && bg.match(/,\s*([\d.]+)\)/) && parseFloat(bg.match(/,\s*([\d.]+)\)/)?.[1] || "1") < 1 || opacity < 1 && opacity > 0;
|
|
44399
|
+
if (!isSemiTransparent) continue;
|
|
44400
|
+
const nextSib = el.nextElementSibling;
|
|
44401
|
+
if (nextSib && nextSib instanceof HTMLElement && isVisible(nextSib) && hasInteractiveContent(nextSib)) {
|
|
44402
|
+
enrichAsDialog(nextSib);
|
|
44403
|
+
continue;
|
|
44404
|
+
}
|
|
44405
|
+
if (el.parentElement) {
|
|
44406
|
+
const backdropZ = parseInt(style.zIndex) || 0;
|
|
44407
|
+
for (const sibling of el.parentElement.children) {
|
|
44408
|
+
if (sibling === el || !(sibling instanceof HTMLElement)) continue;
|
|
44409
|
+
const sibStyle = window.getComputedStyle(sibling);
|
|
44410
|
+
const sibZ = parseInt(sibStyle.zIndex) || 0;
|
|
44411
|
+
if (sibZ > backdropZ && isVisible(sibling) && hasInteractiveContent(sibling)) {
|
|
44412
|
+
enrichAsDialog(sibling);
|
|
44413
|
+
break;
|
|
44414
|
+
}
|
|
44415
|
+
}
|
|
44416
|
+
}
|
|
44417
|
+
}
|
|
44418
|
+
}
|
|
44419
|
+
if (count < MAX_ENRICHMENTS) {
|
|
44420
|
+
const allElements = document.querySelectorAll("*");
|
|
44421
|
+
for (const el of allElements) {
|
|
44422
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44423
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
44424
|
+
if (el.getAttribute("data-enriched-dialog") === "true") continue;
|
|
44425
|
+
if (el.getAttribute("role") === "dialog" || el.getAttribute("role") === "alertdialog") continue;
|
|
44426
|
+
const style = window.getComputedStyle(el);
|
|
44427
|
+
if (style.position !== "fixed" && style.position !== "absolute") continue;
|
|
44428
|
+
const zIndex = parseInt(style.zIndex) || 0;
|
|
44429
|
+
if (zIndex <= 100) continue;
|
|
44430
|
+
if (!isVisible(el)) continue;
|
|
44431
|
+
const rect = el.getBoundingClientRect();
|
|
44432
|
+
if (rect.width < 200 || rect.height < 200) continue;
|
|
44433
|
+
const viewportW = window.innerWidth;
|
|
44434
|
+
const viewportH = window.innerHeight;
|
|
44435
|
+
if (rect.width >= viewportW * 0.95 && rect.height >= viewportH * 0.95) continue;
|
|
44436
|
+
if (hasInteractiveContent(el)) {
|
|
44437
|
+
enrichAsDialog(el);
|
|
44438
|
+
}
|
|
44439
|
+
}
|
|
44440
|
+
}
|
|
44441
|
+
return count;
|
|
44442
|
+
});
|
|
44443
|
+
if (enrichedCount > 0) {
|
|
44444
|
+
logger2.debug("[DirectPlaywright] Enriched modal dialog elements", {
|
|
44445
|
+
count: enrichedCount
|
|
44446
|
+
});
|
|
44447
|
+
}
|
|
44448
|
+
} catch (err) {
|
|
44449
|
+
logger2.debug("[DirectPlaywright] Modal dialog enrichment failed", {
|
|
44450
|
+
error: errorMessage2(err)
|
|
44451
|
+
});
|
|
44452
|
+
}
|
|
44453
|
+
}
|
|
43597
44454
|
async function enrichInteractiveSVGElements(page, logger2) {
|
|
43598
44455
|
try {
|
|
43599
44456
|
const enrichedCount = await page.evaluate(() => {
|
|
@@ -43989,7 +44846,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43989
44846
|
extensions,
|
|
43990
44847
|
highlightInteractions,
|
|
43991
44848
|
cursorOverlay,
|
|
43992
|
-
extraHTTPHeaders
|
|
44849
|
+
extraHTTPHeaders,
|
|
44850
|
+
httpCredentials
|
|
43993
44851
|
} = options;
|
|
43994
44852
|
const resolvedBrowserMode = browserMode ?? "headless";
|
|
43995
44853
|
const resolvedViewport = viewport ?? DEFAULT_VIEWPORT;
|
|
@@ -44002,7 +44860,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44002
44860
|
extensions,
|
|
44003
44861
|
highlightInteractions,
|
|
44004
44862
|
cursorOverlay,
|
|
44005
|
-
extraHTTPHeaders
|
|
44863
|
+
extraHTTPHeaders,
|
|
44864
|
+
httpCredentials
|
|
44006
44865
|
};
|
|
44007
44866
|
this.storageStatePath = storageStatePath;
|
|
44008
44867
|
this.pageClosedIntentionally = false;
|
|
@@ -44075,6 +44934,9 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44075
44934
|
if (extraHTTPHeaders && Object.keys(extraHTTPHeaders).length > 0) {
|
|
44076
44935
|
contextOptions.extraHTTPHeaders = extraHTTPHeaders;
|
|
44077
44936
|
}
|
|
44937
|
+
if (httpCredentials) {
|
|
44938
|
+
contextOptions.httpCredentials = httpCredentials;
|
|
44939
|
+
}
|
|
44078
44940
|
this.logger.info("[DirectPlaywright] Using pooled browser via lease", {
|
|
44079
44941
|
leaseId: this.browserLease.leaseId,
|
|
44080
44942
|
browserId: this.browserLease.browserId
|
|
@@ -44102,7 +44964,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44102
44964
|
recordVideo,
|
|
44103
44965
|
stealth,
|
|
44104
44966
|
extensions,
|
|
44105
|
-
extraHTTPHeaders
|
|
44967
|
+
extraHTTPHeaders,
|
|
44968
|
+
httpCredentials
|
|
44106
44969
|
}),
|
|
44107
44970
|
{
|
|
44108
44971
|
logger: this.logger,
|
|
@@ -44121,6 +44984,9 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44121
44984
|
const initialPageId = this._assignPageId(this.page);
|
|
44122
44985
|
this._pageCreationTimes.set(initialPageId, now);
|
|
44123
44986
|
this._tabFocusLog.push({ pageIndex: initialPageId, timestamp: now });
|
|
44987
|
+
if (storageStatePath) {
|
|
44988
|
+
await this.restoreIndexedDBFromStorageState(storageStatePath);
|
|
44989
|
+
}
|
|
44124
44990
|
this.logger.info("[DirectPlaywright] Browser connected successfully", {
|
|
44125
44991
|
browserMode: resolvedBrowserMode,
|
|
44126
44992
|
stealthEnabled: this.stealthEnabled,
|
|
@@ -44200,6 +45066,13 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44200
45066
|
headerNames: Object.keys(mergedHeaders)
|
|
44201
45067
|
});
|
|
44202
45068
|
}
|
|
45069
|
+
const resolvedHttpCredentials = options.httpCredentials ?? this.lastConnectOptions?.httpCredentials;
|
|
45070
|
+
if (resolvedHttpCredentials) {
|
|
45071
|
+
contextOptions.httpCredentials = resolvedHttpCredentials;
|
|
45072
|
+
if (this.lastConnectOptions) {
|
|
45073
|
+
this.lastConnectOptions.httpCredentials = resolvedHttpCredentials;
|
|
45074
|
+
}
|
|
45075
|
+
}
|
|
44203
45076
|
if (nextStorageStatePath) {
|
|
44204
45077
|
try {
|
|
44205
45078
|
await fs4.access(nextStorageStatePath);
|
|
@@ -44251,6 +45124,9 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44251
45124
|
const swapPageId = this._assignPageId(this.page);
|
|
44252
45125
|
this._pageCreationTimes.set(swapPageId, swapNow);
|
|
44253
45126
|
this._tabFocusLog.push({ pageIndex: swapPageId, timestamp: swapNow });
|
|
45127
|
+
if (nextStorageStatePath) {
|
|
45128
|
+
await this.restoreIndexedDBFromStorageState(nextStorageStatePath);
|
|
45129
|
+
}
|
|
44254
45130
|
if (wasScreencasting && this.page && this.screencastHandler) {
|
|
44255
45131
|
await this.startScreencast(this.screencastHandler);
|
|
44256
45132
|
}
|
|
@@ -44269,7 +45145,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44269
45145
|
recordVideo,
|
|
44270
45146
|
stealth,
|
|
44271
45147
|
extensions,
|
|
44272
|
-
extraHTTPHeaders
|
|
45148
|
+
extraHTTPHeaders,
|
|
45149
|
+
httpCredentials
|
|
44273
45150
|
} = options;
|
|
44274
45151
|
const resolvedViewport = viewport ?? DEFAULT_VIEWPORT;
|
|
44275
45152
|
const useStealthMode = stealth === true || typeof stealth === "object" && stealth.enabled;
|
|
@@ -44300,6 +45177,10 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44300
45177
|
headerNames: Object.keys(extraHTTPHeaders)
|
|
44301
45178
|
});
|
|
44302
45179
|
}
|
|
45180
|
+
if (httpCredentials) {
|
|
45181
|
+
contextOptions.httpCredentials = httpCredentials;
|
|
45182
|
+
this.logger.info("[DirectPlaywright] HTTP Basic Authentication configured");
|
|
45183
|
+
}
|
|
44303
45184
|
if (storageStatePath) {
|
|
44304
45185
|
try {
|
|
44305
45186
|
await fs4.access(storageStatePath);
|
|
@@ -44365,6 +45246,52 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44365
45246
|
);
|
|
44366
45247
|
return { browser, context };
|
|
44367
45248
|
}
|
|
45249
|
+
/**
|
|
45250
|
+
* Read the storage state file, check for IndexedDB data, and restore it.
|
|
45251
|
+
* IndexedDB is origin-scoped, so we navigate to the appropriate origin
|
|
45252
|
+
* before writing data, then navigate back.
|
|
45253
|
+
*/
|
|
45254
|
+
async restoreIndexedDBFromStorageState(storageStatePath) {
|
|
45255
|
+
try {
|
|
45256
|
+
const raw = await fs4.readFile(storageStatePath, "utf-8");
|
|
45257
|
+
const parsed = JSON.parse(raw);
|
|
45258
|
+
if (!parsed.indexedDB || !parsed.indexedDB.databases || parsed.indexedDB.databases.length === 0) {
|
|
45259
|
+
return;
|
|
45260
|
+
}
|
|
45261
|
+
const page = this.page;
|
|
45262
|
+
if (!page || page.isClosed()) return;
|
|
45263
|
+
let targetOrigin = null;
|
|
45264
|
+
if (parsed.origins && parsed.origins.length > 0) {
|
|
45265
|
+
targetOrigin = parsed.origins[0].origin;
|
|
45266
|
+
}
|
|
45267
|
+
if (!targetOrigin) {
|
|
45268
|
+
const cookies = parsed.cookies;
|
|
45269
|
+
if (cookies && cookies.length > 0) {
|
|
45270
|
+
const domain = cookies[0].domain.replace(/^\./, "");
|
|
45271
|
+
targetOrigin = `https://${domain}`;
|
|
45272
|
+
}
|
|
45273
|
+
}
|
|
45274
|
+
if (!targetOrigin) {
|
|
45275
|
+
this.logger.debug("[DirectPlaywright] No origin found for IndexedDB restoration, skipping");
|
|
45276
|
+
return;
|
|
45277
|
+
}
|
|
45278
|
+
this.logger.debug("[DirectPlaywright] Restoring IndexedDB data", {
|
|
45279
|
+
targetOrigin,
|
|
45280
|
+
databaseCount: parsed.indexedDB.databases.length,
|
|
45281
|
+
databaseNames: parsed.indexedDB.databases.map((db) => db.name)
|
|
45282
|
+
});
|
|
45283
|
+
await page.goto(targetOrigin, { waitUntil: "commit", timeout: 15e3 });
|
|
45284
|
+
await restoreIndexedDB(page, parsed.indexedDB);
|
|
45285
|
+
this.logger.info("[DirectPlaywright] IndexedDB data restored successfully", {
|
|
45286
|
+
databaseCount: parsed.indexedDB.databases.length
|
|
45287
|
+
});
|
|
45288
|
+
} catch (err) {
|
|
45289
|
+
this.logger.warn("[DirectPlaywright] Failed to restore IndexedDB from storage state", {
|
|
45290
|
+
error: err instanceof Error ? err.message : String(err),
|
|
45291
|
+
storageStatePath
|
|
45292
|
+
});
|
|
45293
|
+
}
|
|
45294
|
+
}
|
|
44368
45295
|
/**
|
|
44369
45296
|
* Resolve a working Chromium executable path, handling version mismatches
|
|
44370
45297
|
* between the Playwright version bundled in this package and the browser
|
|
@@ -45586,7 +46513,25 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45586
46513
|
this.logger.debug("[DirectPlaywright] Getting storage state", {
|
|
45587
46514
|
method: opts?.method ?? "playwright"
|
|
45588
46515
|
});
|
|
45589
|
-
|
|
46516
|
+
const playwrightState = await context.storageState();
|
|
46517
|
+
try {
|
|
46518
|
+
const page = await this.getPage();
|
|
46519
|
+
const indexedDB2 = await extractIndexedDB(page);
|
|
46520
|
+
if (indexedDB2) {
|
|
46521
|
+
this.logger.info("[DirectPlaywright] Extracted IndexedDB data", {
|
|
46522
|
+
databaseCount: indexedDB2.databases.length,
|
|
46523
|
+
databaseNames: indexedDB2.databases.map((db) => db.name)
|
|
46524
|
+
});
|
|
46525
|
+
return { ...playwrightState, indexedDB: indexedDB2 };
|
|
46526
|
+
} else {
|
|
46527
|
+
this.logger.debug("[DirectPlaywright] No IndexedDB databases found on current page");
|
|
46528
|
+
}
|
|
46529
|
+
} catch (err) {
|
|
46530
|
+
this.logger.warn("[DirectPlaywright] Failed to extract IndexedDB, saving without it", {
|
|
46531
|
+
error: err instanceof Error ? err.message : String(err)
|
|
46532
|
+
});
|
|
46533
|
+
}
|
|
46534
|
+
return playwrightState;
|
|
45590
46535
|
}
|
|
45591
46536
|
async getCurrentUrl(_opts) {
|
|
45592
46537
|
return (await this.getPage()).url();
|
|
@@ -45833,6 +46778,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45833
46778
|
}
|
|
45834
46779
|
await this.enrichInteractiveSVGElements(page);
|
|
45835
46780
|
await this.enrichHiddenClickableElements(page);
|
|
46781
|
+
await this.enrichModalDialogElements(page);
|
|
45836
46782
|
let snapshot;
|
|
45837
46783
|
const maxRetries = 3;
|
|
45838
46784
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
@@ -45961,6 +46907,13 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45961
46907
|
async enrichHiddenClickableElements(page) {
|
|
45962
46908
|
await enrichHiddenClickableElements(page, this.logger);
|
|
45963
46909
|
}
|
|
46910
|
+
/**
|
|
46911
|
+
* Enrich positioned overlays that look like modals but lack `role="dialog"`.
|
|
46912
|
+
* Injects `role="dialog"` and `aria-label` so the agent recognizes them.
|
|
46913
|
+
*/
|
|
46914
|
+
async enrichModalDialogElements(page) {
|
|
46915
|
+
await enrichModalDialogElements(page, this.logger);
|
|
46916
|
+
}
|
|
45964
46917
|
/**
|
|
45965
46918
|
* Resolve a ref to a Playwright locator using the internal aria-ref selector.
|
|
45966
46919
|
* This is the same mechanism MCP uses to resolve refs.
|
|
@@ -46993,6 +47946,8 @@ export {
|
|
|
46993
47946
|
CursorOverlay,
|
|
46994
47947
|
setCdpScreencastLogger,
|
|
46995
47948
|
CdpScreencastManager,
|
|
47949
|
+
extractIndexedDB,
|
|
47950
|
+
restoreIndexedDB,
|
|
46996
47951
|
setSnapshotAnalyzerLogger,
|
|
46997
47952
|
extractSnapshotYaml,
|
|
46998
47953
|
parseSnapshot,
|
|
@@ -47007,22 +47962,27 @@ export {
|
|
|
47007
47962
|
normalizeIconLabelText,
|
|
47008
47963
|
normalizeSearchText,
|
|
47009
47964
|
extractDataValue,
|
|
47965
|
+
extractCellText,
|
|
47966
|
+
extractGridCell,
|
|
47967
|
+
reconcileCellColumn,
|
|
47968
|
+
detectGrid,
|
|
47969
|
+
formatGridOutput,
|
|
47970
|
+
formatGridRow,
|
|
47010
47971
|
findRelevanceScope,
|
|
47011
47972
|
searchElements,
|
|
47012
47973
|
populateSearchContext,
|
|
47013
47974
|
sortMatchesByContext,
|
|
47014
|
-
detectGrid,
|
|
47015
|
-
extractCellText,
|
|
47016
|
-
extractGridCell,
|
|
47017
|
-
reconcileCellColumn,
|
|
47018
|
-
findActiveElement,
|
|
47019
47975
|
buildSectionTree,
|
|
47020
47976
|
markMatchingSections,
|
|
47977
|
+
findActiveElement,
|
|
47021
47978
|
formatSemanticSnapshot,
|
|
47022
47979
|
expandSection,
|
|
47023
47980
|
expandSectionOnly,
|
|
47024
|
-
|
|
47025
|
-
|
|
47981
|
+
extractTablesFromSnapshot,
|
|
47982
|
+
gridInfoToRows,
|
|
47983
|
+
formatCSVWithFrontmatter,
|
|
47984
|
+
appendRowsToCSV,
|
|
47985
|
+
detectPaginationInfo,
|
|
47026
47986
|
captureSnapshotState,
|
|
47027
47987
|
compareSnapshots,
|
|
47028
47988
|
hasDiffChanges,
|
|
@@ -47042,6 +48002,7 @@ export {
|
|
|
47042
48002
|
getBrowserToolDefinitions,
|
|
47043
48003
|
BROWSER_LIFECYCLE_TOOLS,
|
|
47044
48004
|
getBrowserToolDefinitionsWithLifecycle,
|
|
48005
|
+
dispatchBrowserTool,
|
|
47045
48006
|
extractSemanticHint,
|
|
47046
48007
|
PlaywrightClient
|
|
47047
48008
|
};
|
|
@@ -47324,4 +48285,4 @@ playwright-extra/dist/index.esm.js:
|
|
|
47324
48285
|
* @license MIT
|
|
47325
48286
|
*)
|
|
47326
48287
|
*/
|
|
47327
|
-
//# sourceMappingURL=chunk-
|
|
48288
|
+
//# sourceMappingURL=chunk-XGO62PO2.js.map
|