@canaryai/cli 0.2.8 → 0.2.12
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-CEW4BDXD.js +186 -0
- package/dist/chunk-CEW4BDXD.js.map +1 -0
- package/dist/chunk-ERSNYLMZ.js +229 -0
- package/dist/chunk-ERSNYLMZ.js.map +1 -0
- package/dist/{chunk-FK3EZADZ.js → chunk-MSMC6UXW.js} +2021 -873
- package/dist/chunk-MSMC6UXW.js.map +1 -0
- package/dist/{chunk-K2OB72B6.js → chunk-Q7WFBG5C.js} +2 -2
- package/dist/{debug-workflow-55G4Y6YT.js → debug-workflow-53ULOFJC.js} +57 -36
- package/dist/debug-workflow-53ULOFJC.js.map +1 -0
- package/dist/{docs-RPFT7ZJB.js → docs-BEE3LOCO.js} +2 -2
- package/dist/{feature-flag-2FDSKOVX.js → feature-flag-CYTDV4ZB.js} +3 -2
- package/dist/{feature-flag-2FDSKOVX.js.map → feature-flag-CYTDV4ZB.js.map} +1 -1
- package/dist/index.js +72 -137
- package/dist/index.js.map +1 -1
- package/dist/init-M6I3MG3D.js +146 -0
- package/dist/init-M6I3MG3D.js.map +1 -0
- package/dist/{issues-6ZDNDSD6.js → issues-NLM72HLU.js} +3 -2
- package/dist/{issues-6ZDNDSD6.js.map → issues-NLM72HLU.js.map} +1 -1
- package/dist/{knobs-MZRTYS3P.js → knobs-O35GAU5M.js} +3 -2
- package/dist/{knobs-MZRTYS3P.js.map → knobs-O35GAU5M.js.map} +1 -1
- package/dist/list-4K4EIGAT.js +57 -0
- package/dist/list-4K4EIGAT.js.map +1 -0
- package/dist/local-NHXXPHZ3.js +63 -0
- package/dist/local-NHXXPHZ3.js.map +1 -0
- package/dist/{local-browser-X7J27IGS.js → local-browser-VAZORCO3.js} +3 -3
- package/dist/login-ZLP64YQP.js +130 -0
- package/dist/login-ZLP64YQP.js.map +1 -0
- package/dist/mcp-ZF5G5DCB.js +377 -0
- package/dist/mcp-ZF5G5DCB.js.map +1 -0
- package/dist/{record-4OX7HXWQ.js → record-V6QKFFH3.js} +133 -72
- package/dist/record-V6QKFFH3.js.map +1 -0
- package/dist/{release-L4IXOHDF.js → release-7TI7EIGD.js} +8 -4
- package/dist/release-7TI7EIGD.js.map +1 -0
- package/dist/session-UGNJXRUW.js +819 -0
- package/dist/session-UGNJXRUW.js.map +1 -0
- package/dist/skill-ORWAPBDW.js +424 -0
- package/dist/skill-ORWAPBDW.js.map +1 -0
- package/dist/{src-I4EXB5OD.js → src-4VIDSK4A.js} +18 -2
- package/dist/start-E532F3BU.js +112 -0
- package/dist/start-E532F3BU.js.map +1 -0
- package/dist/workflow-HXIUXRFI.js +613 -0
- package/dist/workflow-HXIUXRFI.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-6WWHXWCS.js +0 -65
- package/dist/chunk-6WWHXWCS.js.map +0 -1
- package/dist/chunk-DXIAHB72.js +0 -340
- package/dist/chunk-DXIAHB72.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 +0 -688
- package/dist/mcp-4JVLADZL.js.map +0 -1
- package/dist/record-4OX7HXWQ.js.map +0 -1
- package/dist/release-L4IXOHDF.js.map +0 -1
- /package/dist/{chunk-K2OB72B6.js.map → chunk-Q7WFBG5C.js.map} +0 -0
- /package/dist/{docs-RPFT7ZJB.js.map → docs-BEE3LOCO.js.map} +0 -0
- /package/dist/{local-browser-X7J27IGS.js.map → local-browser-VAZORCO3.js.map} +0 -0
- /package/dist/{src-I4EXB5OD.js.map → src-4VIDSK4A.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) {
|
|
@@ -38342,8 +38537,20 @@ function normalizeIconLabelText(role, text) {
|
|
|
38342
38537
|
}
|
|
38343
38538
|
return ICON_ONLY_ROLES.has(role) ? "(icon)" : "";
|
|
38344
38539
|
}
|
|
38540
|
+
var STYLED_WRAPPER_RE = /^Styled\(\w+\)$/;
|
|
38541
|
+
var MUI_CLASS_RE = /^Mui\w+-[\w-]+$/;
|
|
38542
|
+
var HAS_ASCII_ALNUM_RE = /[A-Za-z0-9]/;
|
|
38543
|
+
function isNoisyLabel(text) {
|
|
38544
|
+
const trimmed = text.trim();
|
|
38545
|
+
if (!trimmed) return false;
|
|
38546
|
+
if (STYLED_WRAPPER_RE.test(trimmed)) return true;
|
|
38547
|
+
if (MUI_CLASS_RE.test(trimmed)) return true;
|
|
38548
|
+
if (HAS_PRIVATE_USE_GLYPH_RE.test(trimmed)) return false;
|
|
38549
|
+
if (!HAS_ASCII_ALNUM_RE.test(trimmed)) return true;
|
|
38550
|
+
return false;
|
|
38551
|
+
}
|
|
38345
38552
|
|
|
38346
|
-
// ../browser-core/src/snapshot-formatter.ts
|
|
38553
|
+
// ../browser-core/src/snapshot-formatter-shared.ts
|
|
38347
38554
|
var MAX_SEARCH_MATCHES = 10;
|
|
38348
38555
|
var INTERACTIVE_LEAF_ROLES = /* @__PURE__ */ new Set([
|
|
38349
38556
|
"button",
|
|
@@ -38378,134 +38585,6 @@ var STRUCTURAL_ROLES = /* @__PURE__ */ new Set([
|
|
|
38378
38585
|
"section",
|
|
38379
38586
|
"iframe"
|
|
38380
38587
|
]);
|
|
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
38588
|
var TEXT_CARRYING_ROLES = /* @__PURE__ */ new Set([
|
|
38510
38589
|
"generic",
|
|
38511
38590
|
"paragraph",
|
|
@@ -38516,12 +38595,11 @@ var TEXT_CARRYING_ROLES = /* @__PURE__ */ new Set([
|
|
|
38516
38595
|
"blockquote",
|
|
38517
38596
|
"caption"
|
|
38518
38597
|
]);
|
|
38598
|
+
var VISUAL_HEADING_MAX_LENGTH = 60;
|
|
38519
38599
|
var STATUS_WORDS = /* @__PURE__ */ new Set(["favorable", "unfavorable", "success", "error", "warning", "pending"]);
|
|
38520
38600
|
var BLANK_PATTERNS = [
|
|
38521
38601
|
/\s*\(Blank\)\s*/gi,
|
|
38522
|
-
// "(Blank)" in any case
|
|
38523
38602
|
/\s*\(blank\)\s*/gi
|
|
38524
|
-
// Redundant but explicit
|
|
38525
38603
|
];
|
|
38526
38604
|
var MENU_TRIGGER_PATTERNS = [
|
|
38527
38605
|
/^Open menu for /i,
|
|
@@ -38536,21 +38614,102 @@ var SECTION_BOUNDARY_ROLES = /* @__PURE__ */ new Set([
|
|
|
38536
38614
|
"article",
|
|
38537
38615
|
"section",
|
|
38538
38616
|
"complementary"
|
|
38539
|
-
// sidebars
|
|
38540
38617
|
]);
|
|
38618
|
+
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
38619
|
function normalizeSearchText(text) {
|
|
38542
38620
|
return text.toLowerCase().replace(/[-_.,;:!?'"()\[\]{}\/\\@#$%^&*+=<>~`|]/g, "").replace(/\s+/g, " ").trim();
|
|
38543
38621
|
}
|
|
38544
|
-
function
|
|
38545
|
-
|
|
38546
|
-
|
|
38547
|
-
|
|
38548
|
-
|
|
38549
|
-
|
|
38550
|
-
|
|
38622
|
+
function isActiveElement(element) {
|
|
38623
|
+
return element.attributes["active"] !== void 0 || element.rawLine.includes("[active]");
|
|
38624
|
+
}
|
|
38625
|
+
function isDisabledElement(element) {
|
|
38626
|
+
return element.attributes["disabled"] !== void 0 || element.rawLine.includes("[disabled]");
|
|
38627
|
+
}
|
|
38628
|
+
function isClickableByAttribute(element) {
|
|
38629
|
+
return element.attributes["cursor"] === "pointer";
|
|
38630
|
+
}
|
|
38631
|
+
function isActionableClickableGeneric(element) {
|
|
38632
|
+
return isClickableByAttribute(element) && !INTERACTIVE_ROLES.has(element.role);
|
|
38633
|
+
}
|
|
38634
|
+
function isSearchInteractiveElement(element) {
|
|
38635
|
+
return INTERACTIVE_LEAF_ROLES.has(element.role) || isActionableClickableGeneric(element);
|
|
38636
|
+
}
|
|
38637
|
+
function getElementText(el) {
|
|
38638
|
+
if (el.text && el.inputValue && FRAMEWORK_NOISE_RE.test(el.text.trim())) {
|
|
38639
|
+
return el.inputValue;
|
|
38640
|
+
}
|
|
38641
|
+
return el.text || el.inputValue;
|
|
38642
|
+
}
|
|
38643
|
+
function composeLabel(element) {
|
|
38644
|
+
const directText = getElementText(element);
|
|
38645
|
+
if (directText) return directText;
|
|
38646
|
+
const textParts = [];
|
|
38647
|
+
function collectText(el, depth) {
|
|
38648
|
+
if (depth > 3) return;
|
|
38649
|
+
const text = getElementText(el);
|
|
38650
|
+
if (text && TEXT_CARRYING_ROLES.has(el.role)) {
|
|
38651
|
+
textParts.push(text);
|
|
38652
|
+
}
|
|
38653
|
+
for (const child of el.children) {
|
|
38654
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38655
|
+
collectText(child, depth + 1);
|
|
38656
|
+
}
|
|
38657
|
+
}
|
|
38658
|
+
}
|
|
38659
|
+
for (const child of element.children) {
|
|
38660
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38661
|
+
collectText(child, 0);
|
|
38662
|
+
}
|
|
38663
|
+
}
|
|
38664
|
+
return textParts.join(" | ") || element.role;
|
|
38665
|
+
}
|
|
38666
|
+
function composeChildLabel(element) {
|
|
38667
|
+
const textParts = [];
|
|
38668
|
+
function collectText(el, depth) {
|
|
38669
|
+
if (depth > 3) return;
|
|
38670
|
+
const text = getElementText(el);
|
|
38671
|
+
if (text && TEXT_CARRYING_ROLES.has(el.role)) {
|
|
38672
|
+
textParts.push(text);
|
|
38673
|
+
}
|
|
38674
|
+
for (const child of el.children) {
|
|
38675
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38676
|
+
collectText(child, depth + 1);
|
|
38677
|
+
}
|
|
38678
|
+
}
|
|
38679
|
+
}
|
|
38680
|
+
for (const child of element.children) {
|
|
38681
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38682
|
+
collectText(child, 0);
|
|
38683
|
+
}
|
|
38684
|
+
}
|
|
38685
|
+
return textParts.length > 0 ? textParts.join(" | ") : null;
|
|
38686
|
+
}
|
|
38687
|
+
function getDisplayText(element, options) {
|
|
38688
|
+
const isClickable = isActionableClickableGeneric(element);
|
|
38689
|
+
let rawTextSource = options?.overrideLabel ?? (isClickable ? composeLabel(element) : element.text ?? "");
|
|
38690
|
+
if (rawTextSource && isNoisyLabel(rawTextSource) && INTERACTIVE_LEAF_ROLES.has(element.role)) {
|
|
38691
|
+
const childText = composeChildLabel(element);
|
|
38692
|
+
rawTextSource = childText ?? "";
|
|
38693
|
+
}
|
|
38694
|
+
return normalizeIconLabelText(element.role, rawTextSource);
|
|
38695
|
+
}
|
|
38696
|
+
function hasInteractiveDescendants(element) {
|
|
38697
|
+
if (element.ref && (INTERACTIVE_ROLES.has(element.role) || isClickableByAttribute(element))) return true;
|
|
38698
|
+
for (const child of element.children) {
|
|
38699
|
+
if (hasInteractiveDescendants(child)) return true;
|
|
38551
38700
|
}
|
|
38552
38701
|
return false;
|
|
38553
38702
|
}
|
|
38703
|
+
function subtreeContainsActive(element) {
|
|
38704
|
+
if (isActiveElement(element)) return true;
|
|
38705
|
+
for (const child of element.children) {
|
|
38706
|
+
if (subtreeContainsActive(child)) return true;
|
|
38707
|
+
}
|
|
38708
|
+
return false;
|
|
38709
|
+
}
|
|
38710
|
+
function cleanLabel(text) {
|
|
38711
|
+
return text.replace(/\s+/g, " ").replace(/…+/g, "...").trim();
|
|
38712
|
+
}
|
|
38554
38713
|
function isBlankValue(value) {
|
|
38555
38714
|
if (!value) return true;
|
|
38556
38715
|
const trimmed = value.trim().toLowerCase();
|
|
@@ -38590,160 +38749,15 @@ function extractDataValue(text) {
|
|
|
38590
38749
|
}
|
|
38591
38750
|
return { label: cleanLabel(cleaned), status };
|
|
38592
38751
|
}
|
|
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
|
-
}
|
|
38752
|
+
function isMenuTriggerNoise(element) {
|
|
38753
|
+
if (isActiveElement(element)) return false;
|
|
38754
|
+
if (element.role !== "button") return false;
|
|
38755
|
+
const text = element.text || "";
|
|
38756
|
+
if (!text.trim()) return false;
|
|
38757
|
+
for (const pattern of MENU_TRIGGER_PATTERNS) {
|
|
38758
|
+
if (pattern.test(text)) return true;
|
|
38745
38759
|
}
|
|
38746
|
-
return
|
|
38760
|
+
return false;
|
|
38747
38761
|
}
|
|
38748
38762
|
function countElementsWithRefs(element) {
|
|
38749
38763
|
let count = element.ref ? 1 : 0;
|
|
@@ -38752,74 +38766,23 @@ function countElementsWithRefs(element) {
|
|
|
38752
38766
|
}
|
|
38753
38767
|
return count;
|
|
38754
38768
|
}
|
|
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));
|
|
38769
|
+
function collectComboboxOptions(element) {
|
|
38770
|
+
const options = [];
|
|
38771
|
+
function walk(el) {
|
|
38772
|
+
if (el.role === "option" && el.text?.trim()) {
|
|
38773
|
+
options.push(el.text.trim());
|
|
38774
38774
|
}
|
|
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;
|
|
38775
|
+
for (const child of el.children) {
|
|
38776
|
+
walk(child);
|
|
38812
38777
|
}
|
|
38813
38778
|
}
|
|
38814
|
-
return element.role;
|
|
38815
|
-
}
|
|
38816
|
-
function subtreeContainsActive(element) {
|
|
38817
|
-
if (isActiveElement(element)) return true;
|
|
38818
38779
|
for (const child of element.children) {
|
|
38819
|
-
|
|
38780
|
+
walk(child);
|
|
38820
38781
|
}
|
|
38821
|
-
return
|
|
38782
|
+
return options.length > 0 ? options : void 0;
|
|
38822
38783
|
}
|
|
38784
|
+
|
|
38785
|
+
// ../browser-core/src/snapshot-formatter-grid.ts
|
|
38823
38786
|
function findDescendantByRole(el, role) {
|
|
38824
38787
|
if (el.role === role) return el;
|
|
38825
38788
|
for (const child of el.children) {
|
|
@@ -38864,6 +38827,177 @@ function isWidgetTable(element) {
|
|
|
38864
38827
|
}
|
|
38865
38828
|
return totalCells > 0 && interactiveCells >= totalCells * 0.5;
|
|
38866
38829
|
}
|
|
38830
|
+
function gridCellPriority(el) {
|
|
38831
|
+
if (el.isActive) return 5;
|
|
38832
|
+
if (FORM_INPUT_ROLES.has(el.role)) return 4;
|
|
38833
|
+
if (el.isClickableGeneric) return 3;
|
|
38834
|
+
if (el.role !== "button") return 2;
|
|
38835
|
+
return 1;
|
|
38836
|
+
}
|
|
38837
|
+
function extractCellText(el) {
|
|
38838
|
+
const findFirstParagraph = (node) => {
|
|
38839
|
+
if (node.role === "paragraph" && node.text) {
|
|
38840
|
+
return node.text.trim();
|
|
38841
|
+
}
|
|
38842
|
+
for (const child of node.children) {
|
|
38843
|
+
if (child.role === "generic" || child.role === "paragraph") {
|
|
38844
|
+
const found = findFirstParagraph(child);
|
|
38845
|
+
if (found) return found;
|
|
38846
|
+
}
|
|
38847
|
+
}
|
|
38848
|
+
return null;
|
|
38849
|
+
};
|
|
38850
|
+
const paragraphText = findFirstParagraph(el);
|
|
38851
|
+
if (paragraphText) return paragraphText;
|
|
38852
|
+
const text = el.text?.trim();
|
|
38853
|
+
if (text) return text;
|
|
38854
|
+
return null;
|
|
38855
|
+
}
|
|
38856
|
+
function extractGridCell(cellEl) {
|
|
38857
|
+
const interactiveElements = [];
|
|
38858
|
+
const findInteractive = (el) => {
|
|
38859
|
+
if (isClickableByAttribute(el) && el.ref && el.role === "generic") {
|
|
38860
|
+
const childTexts = [];
|
|
38861
|
+
for (const child of el.children) {
|
|
38862
|
+
if (child.role === "generic") {
|
|
38863
|
+
const childText = child.text || child.inputValue;
|
|
38864
|
+
if (childText) childTexts.push(childText);
|
|
38865
|
+
}
|
|
38866
|
+
}
|
|
38867
|
+
interactiveElements.push({
|
|
38868
|
+
ref: el.ref,
|
|
38869
|
+
column: el.attributes["label"] || childTexts[0] || "",
|
|
38870
|
+
value: childTexts.join(" - ") || el.text || el.inputValue || "",
|
|
38871
|
+
role: el.role,
|
|
38872
|
+
isClickableGeneric: true,
|
|
38873
|
+
isActive: isActiveElement(el)
|
|
38874
|
+
});
|
|
38875
|
+
}
|
|
38876
|
+
if (INTERACTIVE_LEAF_ROLES.has(el.role) && el.ref) {
|
|
38877
|
+
const value2 = el.role === "checkbox" ? el.attributes["checked"] === "true" ? "checked" : "unchecked" : el.inputValue || el.text || "";
|
|
38878
|
+
interactiveElements.push({
|
|
38879
|
+
ref: el.ref,
|
|
38880
|
+
column: el.attributes["label"] || el.text || "",
|
|
38881
|
+
value: value2,
|
|
38882
|
+
role: el.role,
|
|
38883
|
+
isClickableGeneric: false,
|
|
38884
|
+
isActive: isActiveElement(el)
|
|
38885
|
+
});
|
|
38886
|
+
}
|
|
38887
|
+
for (const child of el.children) findInteractive(child);
|
|
38888
|
+
};
|
|
38889
|
+
findInteractive(cellEl);
|
|
38890
|
+
if (interactiveElements.length === 0) {
|
|
38891
|
+
const textValue = extractCellText(cellEl);
|
|
38892
|
+
if (textValue && !isNoisyLabel(textValue)) {
|
|
38893
|
+
return {
|
|
38894
|
+
ref: cellEl.ref,
|
|
38895
|
+
column: cellEl.text || "",
|
|
38896
|
+
value: textValue,
|
|
38897
|
+
hasValue: true
|
|
38898
|
+
};
|
|
38899
|
+
}
|
|
38900
|
+
return null;
|
|
38901
|
+
}
|
|
38902
|
+
const found = interactiveElements.reduce(
|
|
38903
|
+
(best, current) => gridCellPriority(current) > gridCellPriority(best) ? current : best
|
|
38904
|
+
);
|
|
38905
|
+
const column = stripBlankPatterns(found.column);
|
|
38906
|
+
const rawValue = isBlankValue(found.value) ? "" : stripBlankPatterns(found.value).trim();
|
|
38907
|
+
const value = isNoisyLabel(rawValue) ? "" : rawValue;
|
|
38908
|
+
const gridcellLabel = cellEl.text ? stripBlankPatterns(cellEl.text).trim() : void 0;
|
|
38909
|
+
return {
|
|
38910
|
+
ref: found.ref,
|
|
38911
|
+
column: column.trim(),
|
|
38912
|
+
value,
|
|
38913
|
+
hasValue: value !== "",
|
|
38914
|
+
gridcellLabel: gridcellLabel || void 0,
|
|
38915
|
+
role: found.role
|
|
38916
|
+
};
|
|
38917
|
+
}
|
|
38918
|
+
function reconcileCellColumn(cell, knownColumns) {
|
|
38919
|
+
if (knownColumns.has(cell.column)) return cell;
|
|
38920
|
+
if (cell.gridcellLabel && knownColumns.has(cell.gridcellLabel)) {
|
|
38921
|
+
const newValue = cell.column || cell.value;
|
|
38922
|
+
const cleanValue = isBlankValue(newValue) ? "" : newValue.trim();
|
|
38923
|
+
return {
|
|
38924
|
+
...cell,
|
|
38925
|
+
column: cell.gridcellLabel,
|
|
38926
|
+
value: cleanValue,
|
|
38927
|
+
hasValue: cleanValue !== ""
|
|
38928
|
+
};
|
|
38929
|
+
}
|
|
38930
|
+
let bestMatch = "";
|
|
38931
|
+
for (const col of knownColumns) {
|
|
38932
|
+
if (cell.column.startsWith(col) && col.length > bestMatch.length && (cell.column.length === col.length || cell.column[col.length] === " ")) {
|
|
38933
|
+
bestMatch = col;
|
|
38934
|
+
}
|
|
38935
|
+
}
|
|
38936
|
+
if (bestMatch) {
|
|
38937
|
+
const remainder = cell.column.slice(bestMatch.length).trim();
|
|
38938
|
+
const newValue = isBlankValue(remainder) ? "" : remainder;
|
|
38939
|
+
return {
|
|
38940
|
+
...cell,
|
|
38941
|
+
column: bestMatch,
|
|
38942
|
+
value: newValue || cell.value,
|
|
38943
|
+
hasValue: (newValue || cell.value) !== ""
|
|
38944
|
+
};
|
|
38945
|
+
}
|
|
38946
|
+
return cell;
|
|
38947
|
+
}
|
|
38948
|
+
function reconcileGridCells(grid) {
|
|
38949
|
+
if (grid.columns.length === 0) return grid;
|
|
38950
|
+
const knownColumns = new Set(grid.columns.map((c2) => c2.name));
|
|
38951
|
+
return {
|
|
38952
|
+
...grid,
|
|
38953
|
+
rows: grid.rows.map((row) => {
|
|
38954
|
+
const reconciledCells = row.cells.map((cell) => {
|
|
38955
|
+
const reconciled = reconcileCellColumn(cell, knownColumns);
|
|
38956
|
+
if (knownColumns.has(reconciled.column)) return reconciled;
|
|
38957
|
+
if (grid.columnByPosition && cell.positionInRow !== void 0 && grid.headerChildCount !== void 0 && row.totalChildren === grid.headerChildCount) {
|
|
38958
|
+
const positionalColumn = grid.columnByPosition.get(cell.positionInRow);
|
|
38959
|
+
if (positionalColumn) {
|
|
38960
|
+
const newValue = cell.column || cell.value;
|
|
38961
|
+
const cleanValue = isBlankValue(newValue) ? "" : newValue.trim();
|
|
38962
|
+
return {
|
|
38963
|
+
...cell,
|
|
38964
|
+
column: positionalColumn,
|
|
38965
|
+
value: cleanValue,
|
|
38966
|
+
hasValue: cleanValue !== ""
|
|
38967
|
+
};
|
|
38968
|
+
}
|
|
38969
|
+
}
|
|
38970
|
+
return reconciled;
|
|
38971
|
+
});
|
|
38972
|
+
if (grid.headerCellPositions && row.cellPositions) {
|
|
38973
|
+
const claimedColumns = new Set(
|
|
38974
|
+
reconciledCells.filter((c2) => knownColumns.has(c2.column)).map((c2) => c2.column)
|
|
38975
|
+
);
|
|
38976
|
+
for (let idx = 0; idx < reconciledCells.length; idx++) {
|
|
38977
|
+
const cell = reconciledCells[idx];
|
|
38978
|
+
if (knownColumns.has(cell.column) || cell.positionInRow === void 0) continue;
|
|
38979
|
+
const cellOrdinal = row.cellPositions.indexOf(cell.positionInRow);
|
|
38980
|
+
if (cellOrdinal >= 0 && cellOrdinal < grid.headerCellPositions.length) {
|
|
38981
|
+
const headerPos = grid.headerCellPositions[cellOrdinal];
|
|
38982
|
+
const positionalColumn = grid.columnByPosition?.get(headerPos);
|
|
38983
|
+
if (positionalColumn && !claimedColumns.has(positionalColumn)) {
|
|
38984
|
+
const newValue = cell.column || cell.value;
|
|
38985
|
+
const cleanValue = isBlankValue(newValue) ? "" : newValue.trim();
|
|
38986
|
+
reconciledCells[idx] = {
|
|
38987
|
+
...cell,
|
|
38988
|
+
column: positionalColumn,
|
|
38989
|
+
value: cleanValue,
|
|
38990
|
+
hasValue: cleanValue !== ""
|
|
38991
|
+
};
|
|
38992
|
+
claimedColumns.add(positionalColumn);
|
|
38993
|
+
}
|
|
38994
|
+
}
|
|
38995
|
+
}
|
|
38996
|
+
}
|
|
38997
|
+
return { ...row, cells: reconciledCells };
|
|
38998
|
+
})
|
|
38999
|
+
};
|
|
39000
|
+
}
|
|
38867
39001
|
function detectGrid(element) {
|
|
38868
39002
|
if (element.role !== "grid" && element.role !== "treegrid" && element.role !== "table") {
|
|
38869
39003
|
return null;
|
|
@@ -38874,18 +39008,28 @@ function detectGrid(element) {
|
|
|
38874
39008
|
let headerRowRef = null;
|
|
38875
39009
|
const columnByPosition = /* @__PURE__ */ new Map();
|
|
38876
39010
|
let headerChildCount;
|
|
39011
|
+
let headerCellPositions;
|
|
39012
|
+
const isRowLike = (el) => {
|
|
39013
|
+
if (el.role === "row") return true;
|
|
39014
|
+
const cellCount = el.children.filter(
|
|
39015
|
+
(c2) => c2.role === "cell" || c2.role === "gridcell"
|
|
39016
|
+
).length;
|
|
39017
|
+
return cellCount >= 2;
|
|
39018
|
+
};
|
|
38877
39019
|
const processRow = (rowEl, index) => {
|
|
38878
|
-
if (rowEl
|
|
39020
|
+
if (!isRowLike(rowEl)) return null;
|
|
38879
39021
|
const hasColumnHeaders = rowEl.children.some((c2) => c2.role === "columnheader");
|
|
38880
39022
|
if (hasColumnHeaders) {
|
|
38881
39023
|
headerRowRef = rowEl.ref;
|
|
38882
39024
|
const columnHeaders = rowEl.children.filter((c2) => c2.role === "columnheader");
|
|
38883
|
-
const
|
|
39025
|
+
const childful = columnHeaders.filter((c2) => c2.children.length > 0);
|
|
39026
|
+
const textBearingChildless = columnHeaders.filter((c2) => c2.children.length === 0 && c2.text);
|
|
39027
|
+
const skipChildlessHeaders = childful.length > 0 && textBearingChildless.length <= childful.length;
|
|
38884
39028
|
const columnsBefore = columns.length;
|
|
38885
39029
|
for (let i = 0; i < rowEl.children.length; i++) {
|
|
38886
39030
|
const child = rowEl.children[i];
|
|
38887
39031
|
if (child.role === "columnheader") {
|
|
38888
|
-
if (
|
|
39032
|
+
if (skipChildlessHeaders && child.children.length === 0) continue;
|
|
38889
39033
|
const primaryLabel = findPrimaryColumnLabel(child);
|
|
38890
39034
|
const rawName = (primaryLabel ? getElementText(primaryLabel) : void 0) || child.text || "";
|
|
38891
39035
|
const cleanName = rawName.replace(/,?\s*sorted in \w+ order/i, "").trim();
|
|
@@ -38904,6 +39048,7 @@ function detectGrid(element) {
|
|
|
38904
39048
|
}
|
|
38905
39049
|
if (columns.length > columnsBefore) {
|
|
38906
39050
|
headerChildCount = rowEl.children.length;
|
|
39051
|
+
headerCellPositions = Array.from(columnByPosition.keys()).sort((a, b) => a - b);
|
|
38907
39052
|
}
|
|
38908
39053
|
return null;
|
|
38909
39054
|
}
|
|
@@ -38945,6 +39090,7 @@ function detectGrid(element) {
|
|
|
38945
39090
|
}
|
|
38946
39091
|
if (columns.length > columnsBefore) {
|
|
38947
39092
|
headerChildCount = rowEl.children.length;
|
|
39093
|
+
headerCellPositions = Array.from(columnByPosition.keys()).sort((a, b) => a - b);
|
|
38948
39094
|
}
|
|
38949
39095
|
return null;
|
|
38950
39096
|
}
|
|
@@ -38970,7 +39116,20 @@ function detectGrid(element) {
|
|
|
38970
39116
|
findButtons(cellEl);
|
|
38971
39117
|
}
|
|
38972
39118
|
}
|
|
38973
|
-
const
|
|
39119
|
+
const cellPositions = [];
|
|
39120
|
+
for (let i = 0; i < rowEl.children.length; i++) {
|
|
39121
|
+
if (rowEl.children[i].role === "gridcell" || rowEl.children[i].role === "cell") {
|
|
39122
|
+
cellPositions.push(i);
|
|
39123
|
+
}
|
|
39124
|
+
}
|
|
39125
|
+
const row = {
|
|
39126
|
+
ref: rowEl.ref,
|
|
39127
|
+
index,
|
|
39128
|
+
isSelected,
|
|
39129
|
+
cells,
|
|
39130
|
+
totalChildren: rowEl.children.length,
|
|
39131
|
+
cellPositions
|
|
39132
|
+
};
|
|
38974
39133
|
if (cells.length === 0 && rowEl.children.some((c2) => c2.role === "rowheader")) {
|
|
38975
39134
|
const labels = [];
|
|
38976
39135
|
const buttons = [];
|
|
@@ -38998,7 +39157,7 @@ function detectGrid(element) {
|
|
|
38998
39157
|
return row;
|
|
38999
39158
|
};
|
|
39000
39159
|
const findRows = (el) => {
|
|
39001
|
-
if (el
|
|
39160
|
+
if (isRowLike(el)) {
|
|
39002
39161
|
const row = processRow(el, rows.length);
|
|
39003
39162
|
if (row) rows.push(row);
|
|
39004
39163
|
} else {
|
|
@@ -39016,177 +39175,414 @@ function detectGrid(element) {
|
|
|
39016
39175
|
totalRows: rows.length,
|
|
39017
39176
|
containsActive: subtreeContainsActive(element),
|
|
39018
39177
|
columnByPosition: columnByPosition.size > 0 ? columnByPosition : void 0,
|
|
39019
|
-
headerChildCount
|
|
39178
|
+
headerChildCount,
|
|
39179
|
+
headerCellPositions
|
|
39020
39180
|
};
|
|
39021
39181
|
return reconcileGridCells(rawGrid);
|
|
39022
39182
|
}
|
|
39023
|
-
function
|
|
39024
|
-
|
|
39025
|
-
|
|
39026
|
-
|
|
39027
|
-
|
|
39028
|
-
|
|
39183
|
+
function gridContainsRef(grid, targetRef) {
|
|
39184
|
+
for (const column of grid.columns) {
|
|
39185
|
+
if (column.ref === targetRef) return true;
|
|
39186
|
+
}
|
|
39187
|
+
for (const row of grid.rows) {
|
|
39188
|
+
if (row.ref === targetRef) return true;
|
|
39189
|
+
if (row.cells.some((cell) => cell.ref === targetRef)) return true;
|
|
39190
|
+
if (row.rowActions?.some((action) => action.ref === targetRef)) return true;
|
|
39191
|
+
if (row.expandedContent?.buttons.some((button) => button.ref === targetRef)) return true;
|
|
39192
|
+
}
|
|
39193
|
+
return false;
|
|
39029
39194
|
}
|
|
39030
|
-
function
|
|
39031
|
-
const
|
|
39032
|
-
|
|
39033
|
-
|
|
39195
|
+
function countRenderedGridItems(grid) {
|
|
39196
|
+
const knownColumns = grid.columns.length > 0 ? new Set(grid.columns.map((c2) => c2.name)) : void 0;
|
|
39197
|
+
let count = 0;
|
|
39198
|
+
for (const row of grid.rows) {
|
|
39199
|
+
count += row.cells.filter((c2) => c2.hasValue && (!knownColumns || knownColumns.has(c2.column))).length;
|
|
39200
|
+
count += row.rowActions?.length ?? 0;
|
|
39201
|
+
count += row.expandedContent?.buttons.length ?? 0;
|
|
39202
|
+
}
|
|
39203
|
+
return count;
|
|
39204
|
+
}
|
|
39205
|
+
function formatGridOutput(grid, indent, expanded = false) {
|
|
39206
|
+
const indentStr = " ".repeat(indent);
|
|
39207
|
+
const lines = [];
|
|
39208
|
+
const colInfo = grid.columns.length > 0 ? `${grid.columns.length} columns` : "unknown columns";
|
|
39209
|
+
lines.push(`${indentStr}GRID [${grid.ref}]: ${grid.totalRows} rows, ${colInfo}`);
|
|
39210
|
+
const MAX_DISPLAY_COLUMNS = 10;
|
|
39211
|
+
if (grid.columns.length > 0) {
|
|
39212
|
+
const displayColumns = grid.columns.slice(0, MAX_DISPLAY_COLUMNS);
|
|
39213
|
+
const colsWithRefs = displayColumns.map((c2) => `${c2.name} [${c2.ref}]`).join(", ");
|
|
39214
|
+
const moreColsNote = grid.columns.length > MAX_DISPLAY_COLUMNS ? ` (+${grid.columns.length - MAX_DISPLAY_COLUMNS} more)` : "";
|
|
39215
|
+
lines.push(`${indentStr} Columns: ${colsWithRefs}${moreColsNote}`);
|
|
39216
|
+
}
|
|
39217
|
+
lines.push("");
|
|
39218
|
+
const knownColumns = grid.columns.length > 0 ? new Set(grid.columns.map((c2) => c2.name)) : void 0;
|
|
39219
|
+
const MAX_GRID_ROWS = 30;
|
|
39220
|
+
const displayRows = expanded ? grid.rows : grid.rows.slice(0, MAX_GRID_ROWS);
|
|
39221
|
+
for (const row of displayRows) {
|
|
39222
|
+
lines.push(formatGridRow(row, indent + 1, knownColumns));
|
|
39223
|
+
}
|
|
39224
|
+
if (!expanded && grid.rows.length > MAX_GRID_ROWS) {
|
|
39225
|
+
lines.push(`${indentStr} ... and ${grid.rows.length - MAX_GRID_ROWS} more rows (use expand="${grid.ref}" to see all)`);
|
|
39226
|
+
}
|
|
39227
|
+
return lines.join("\n");
|
|
39228
|
+
}
|
|
39229
|
+
function formatGridRow(row, indent, knownColumns) {
|
|
39230
|
+
const indentStr = " ".repeat(indent);
|
|
39231
|
+
if (row.expandedContent) {
|
|
39232
|
+
const parts = [];
|
|
39233
|
+
if (row.expandedContent.labels.length > 0) {
|
|
39234
|
+
parts.push(row.expandedContent.labels.join(", "));
|
|
39034
39235
|
}
|
|
39035
|
-
for (const
|
|
39036
|
-
|
|
39037
|
-
|
|
39038
|
-
|
|
39236
|
+
for (const btn of row.expandedContent.buttons) {
|
|
39237
|
+
parts.push(`${btn.label} [${btn.ref}]`);
|
|
39238
|
+
}
|
|
39239
|
+
return `${indentStr} \u21B3 Expanded [${row.ref}]: ${parts.join(" | ")}`;
|
|
39240
|
+
}
|
|
39241
|
+
const marker = row.isSelected ? "ACTIVE \u2192 Row" : "Row";
|
|
39242
|
+
const actionsPrefix = row.rowActions?.length ? row.rowActions.map((a) => `[\u25B6 ${a.ref}]`).join(" ") + " " : "";
|
|
39243
|
+
const cellsWithValue = row.cells.filter(
|
|
39244
|
+
(c2) => c2.hasValue && (!knownColumns || knownColumns.has(c2.column))
|
|
39245
|
+
);
|
|
39246
|
+
if (cellsWithValue.length > 0) {
|
|
39247
|
+
const cellStrs = cellsWithValue.map((c2) => {
|
|
39248
|
+
if (c2.role === "checkbox") {
|
|
39249
|
+
const icon = c2.value === "checked" ? "\u2611" : "\u2610";
|
|
39250
|
+
return `${icon} [${c2.ref}]`;
|
|
39251
|
+
}
|
|
39252
|
+
if (c2.column === c2.value) {
|
|
39253
|
+
return `${c2.column} [${c2.ref}]`;
|
|
39039
39254
|
}
|
|
39255
|
+
return `${c2.column} [${c2.ref}]: ${c2.value}`;
|
|
39256
|
+
});
|
|
39257
|
+
return `${indentStr}${actionsPrefix}${marker} [${row.ref}]: ${cellStrs.join(" | ")}`;
|
|
39258
|
+
}
|
|
39259
|
+
return `${indentStr}${actionsPrefix}${marker} [${row.ref}]: (empty row)`;
|
|
39260
|
+
}
|
|
39261
|
+
|
|
39262
|
+
// ../browser-core/src/snapshot-formatter-search.ts
|
|
39263
|
+
function findRelevanceScope(elements, activeElementRef) {
|
|
39264
|
+
if (!activeElementRef) return null;
|
|
39265
|
+
const path5 = [];
|
|
39266
|
+
function findPath(el) {
|
|
39267
|
+
if (el.ref) {
|
|
39268
|
+
path5.push({ ref: el.ref, role: el.role });
|
|
39040
39269
|
}
|
|
39041
|
-
|
|
39042
|
-
|
|
39043
|
-
|
|
39044
|
-
|
|
39045
|
-
|
|
39046
|
-
|
|
39270
|
+
if (el.ref === activeElementRef) {
|
|
39271
|
+
return true;
|
|
39272
|
+
}
|
|
39273
|
+
for (const child of el.children) {
|
|
39274
|
+
if (findPath(child)) return true;
|
|
39275
|
+
}
|
|
39276
|
+
if (el.ref) path5.pop();
|
|
39277
|
+
return false;
|
|
39278
|
+
}
|
|
39279
|
+
for (const el of elements) {
|
|
39280
|
+
if (findPath(el)) break;
|
|
39281
|
+
}
|
|
39282
|
+
for (let i = path5.length - 1; i >= 0; i--) {
|
|
39283
|
+
if (SECTION_BOUNDARY_ROLES.has(path5[i].role)) {
|
|
39284
|
+
return path5[i].ref;
|
|
39285
|
+
}
|
|
39286
|
+
}
|
|
39047
39287
|
return null;
|
|
39048
39288
|
}
|
|
39049
|
-
function
|
|
39050
|
-
const
|
|
39051
|
-
const
|
|
39052
|
-
|
|
39053
|
-
|
|
39054
|
-
|
|
39055
|
-
|
|
39056
|
-
|
|
39057
|
-
|
|
39289
|
+
function searchElements(elements, searchTerms, scopeRef = null) {
|
|
39290
|
+
const allMatches = [];
|
|
39291
|
+
const normalizedTerms = searchTerms.map((t) => normalizeSearchText(t)).filter(Boolean);
|
|
39292
|
+
if (normalizedTerms.length === 0) return { matches: [], totalFound: 0 };
|
|
39293
|
+
function searchElement(el, inScope) {
|
|
39294
|
+
const nowInScope = inScope || el.ref === scopeRef || scopeRef === null;
|
|
39295
|
+
if (el.ref && nowInScope) {
|
|
39296
|
+
const searchLabel = getDisplayText(el);
|
|
39297
|
+
const searchText = [searchLabel, el.inputValue].filter(Boolean).join(" ");
|
|
39298
|
+
const normalizedSearchText = normalizeSearchText(searchText);
|
|
39299
|
+
for (const term of normalizedTerms) {
|
|
39300
|
+
if (normalizedSearchText.includes(term)) {
|
|
39301
|
+
allMatches.push({
|
|
39302
|
+
ref: el.ref,
|
|
39303
|
+
role: el.role,
|
|
39304
|
+
label: searchLabel || el.role,
|
|
39305
|
+
term,
|
|
39306
|
+
isInteractive: isSearchInteractiveElement(el)
|
|
39307
|
+
});
|
|
39308
|
+
break;
|
|
39058
39309
|
}
|
|
39059
39310
|
}
|
|
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
39311
|
}
|
|
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
|
-
});
|
|
39312
|
+
for (const child of el.children) {
|
|
39313
|
+
searchElement(child, nowInScope);
|
|
39079
39314
|
}
|
|
39080
|
-
|
|
39315
|
+
}
|
|
39316
|
+
for (const el of elements) {
|
|
39317
|
+
searchElement(el, scopeRef === null);
|
|
39318
|
+
}
|
|
39319
|
+
const totalFound = allMatches.length;
|
|
39320
|
+
allMatches.sort((a, b) => {
|
|
39321
|
+
if (a.isInteractive && !b.isInteractive) return -1;
|
|
39322
|
+
if (!a.isInteractive && b.isInteractive) return 1;
|
|
39323
|
+
return 0;
|
|
39324
|
+
});
|
|
39325
|
+
return {
|
|
39326
|
+
matches: allMatches.slice(0, MAX_SEARCH_MATCHES),
|
|
39327
|
+
totalFound
|
|
39081
39328
|
};
|
|
39082
|
-
|
|
39083
|
-
|
|
39084
|
-
|
|
39085
|
-
|
|
39086
|
-
|
|
39087
|
-
|
|
39088
|
-
|
|
39089
|
-
value: textValue,
|
|
39090
|
-
hasValue: true
|
|
39091
|
-
};
|
|
39329
|
+
}
|
|
39330
|
+
function findElementInSections(sections, targetRef, ancestors = []) {
|
|
39331
|
+
for (const section of sections) {
|
|
39332
|
+
const newAncestors = [...ancestors, section];
|
|
39333
|
+
const path5 = newAncestors.map((s) => s.heading);
|
|
39334
|
+
if (section.elements.some((el) => el.ref === targetRef)) {
|
|
39335
|
+
return { section, ancestors: newAncestors, path: path5 };
|
|
39092
39336
|
}
|
|
39093
|
-
|
|
39337
|
+
if (section.gridInfo && gridContainsRef(section.gridInfo, targetRef)) {
|
|
39338
|
+
return { section, ancestors: newAncestors, path: path5 };
|
|
39339
|
+
}
|
|
39340
|
+
const found = findElementInSections(section.subsections, targetRef, newAncestors);
|
|
39341
|
+
if (found) return found;
|
|
39094
39342
|
}
|
|
39095
|
-
|
|
39096
|
-
|
|
39097
|
-
|
|
39098
|
-
const
|
|
39099
|
-
|
|
39100
|
-
|
|
39101
|
-
|
|
39102
|
-
|
|
39103
|
-
|
|
39104
|
-
|
|
39105
|
-
|
|
39106
|
-
|
|
39107
|
-
|
|
39343
|
+
return null;
|
|
39344
|
+
}
|
|
39345
|
+
function populateSearchContext(matches, sections) {
|
|
39346
|
+
for (const match of matches) {
|
|
39347
|
+
const result = findElementInSections(sections, match.ref);
|
|
39348
|
+
if (result) {
|
|
39349
|
+
const { section, ancestors, path: path5 } = result;
|
|
39350
|
+
const inFocusedDialog = ancestors.some((s) => s.isFocused);
|
|
39351
|
+
const inBackground = section.isBackground || ancestors.some((s) => s.isBackground);
|
|
39352
|
+
if (inFocusedDialog) {
|
|
39353
|
+
match.context = "focused";
|
|
39354
|
+
} else if (inBackground) {
|
|
39355
|
+
match.context = "background";
|
|
39356
|
+
} else {
|
|
39357
|
+
match.context = "foreground";
|
|
39358
|
+
}
|
|
39359
|
+
const SKIP_HEADINGS = ["generic", "main", "iframe"];
|
|
39360
|
+
match.sectionPath = path5.filter((p) => !SKIP_HEADINGS.includes(p.toLowerCase())).slice(-3).join(" > ");
|
|
39361
|
+
}
|
|
39362
|
+
}
|
|
39363
|
+
}
|
|
39364
|
+
function sortMatchesByContext(matches) {
|
|
39365
|
+
const contextOrder = {
|
|
39366
|
+
focused: 0,
|
|
39367
|
+
foreground: 1,
|
|
39368
|
+
background: 2
|
|
39108
39369
|
};
|
|
39370
|
+
return [...matches].sort((a, b) => {
|
|
39371
|
+
const aContext = contextOrder[a.context ?? "foreground"] ?? 1;
|
|
39372
|
+
const bContext = contextOrder[b.context ?? "foreground"] ?? 1;
|
|
39373
|
+
if (aContext !== bContext) return aContext - bContext;
|
|
39374
|
+
if (a.isInteractive && !b.isInteractive) return -1;
|
|
39375
|
+
if (!a.isInteractive && b.isInteractive) return 1;
|
|
39376
|
+
return 0;
|
|
39377
|
+
});
|
|
39109
39378
|
}
|
|
39110
|
-
|
|
39111
|
-
|
|
39112
|
-
|
|
39113
|
-
|
|
39114
|
-
|
|
39115
|
-
|
|
39116
|
-
|
|
39117
|
-
|
|
39118
|
-
|
|
39119
|
-
|
|
39120
|
-
|
|
39379
|
+
|
|
39380
|
+
// ../browser-core/src/snapshot-formatter-sections.ts
|
|
39381
|
+
var FIELD_LABEL_TEXT_ROLES = /* @__PURE__ */ new Set([
|
|
39382
|
+
"generic",
|
|
39383
|
+
"paragraph",
|
|
39384
|
+
"text",
|
|
39385
|
+
"strong",
|
|
39386
|
+
"emphasis",
|
|
39387
|
+
"label",
|
|
39388
|
+
"heading"
|
|
39389
|
+
]);
|
|
39390
|
+
var MIN_ELEMENTS_TO_COLLAPSE = 20;
|
|
39391
|
+
var DIALOG_ROLES = /* @__PURE__ */ new Set(["dialog", "alertdialog"]);
|
|
39392
|
+
function isVisualHeading(element, siblings, siblingIndex) {
|
|
39393
|
+
if (element.role !== "generic" && element.role !== "paragraph") return false;
|
|
39394
|
+
if (isClickableByAttribute(element)) return false;
|
|
39395
|
+
const text = getVisualHeadingText(element);
|
|
39396
|
+
if (!text || text.length < 3 || text.length > VISUAL_HEADING_MAX_LENGTH) return false;
|
|
39397
|
+
if (hasInteractiveDescendants(element)) return false;
|
|
39398
|
+
let interactiveCount = 0;
|
|
39399
|
+
for (let i = siblingIndex + 1; i < siblings.length; i++) {
|
|
39400
|
+
const sib = siblings[i];
|
|
39401
|
+
if (sib.role === "heading" || STRUCTURAL_ROLES.has(sib.role)) break;
|
|
39402
|
+
if (sib.role === "generic" || sib.role === "paragraph") {
|
|
39403
|
+
if (!isClickableByAttribute(sib) && !hasInteractiveDescendants(sib)) {
|
|
39404
|
+
const sibText = getVisualHeadingText(sib);
|
|
39405
|
+
if (sibText && sibText.length >= 3 && sibText.length <= VISUAL_HEADING_MAX_LENGTH) {
|
|
39406
|
+
break;
|
|
39407
|
+
}
|
|
39408
|
+
}
|
|
39409
|
+
}
|
|
39410
|
+
if (hasInteractiveDescendants(sib) || isClickableByAttribute(sib)) {
|
|
39411
|
+
interactiveCount++;
|
|
39412
|
+
}
|
|
39121
39413
|
}
|
|
39122
|
-
|
|
39123
|
-
|
|
39124
|
-
|
|
39125
|
-
|
|
39126
|
-
|
|
39414
|
+
return interactiveCount >= 3;
|
|
39415
|
+
}
|
|
39416
|
+
function getVisualHeadingText(element) {
|
|
39417
|
+
const direct = element.text;
|
|
39418
|
+
if (direct) return direct;
|
|
39419
|
+
for (const child of element.children) {
|
|
39420
|
+
if (TEXT_CARRYING_ROLES.has(child.role) && child.text) return child.text;
|
|
39421
|
+
}
|
|
39422
|
+
return void 0;
|
|
39423
|
+
}
|
|
39424
|
+
function findNextSectionBoundary(siblings, startIndex) {
|
|
39425
|
+
for (let i = startIndex; i < siblings.length; i++) {
|
|
39426
|
+
const sib = siblings[i];
|
|
39427
|
+
if (sib.role === "heading" || STRUCTURAL_ROLES.has(sib.role)) return i;
|
|
39428
|
+
if (isVisualHeading(sib, siblings, i)) return i;
|
|
39429
|
+
}
|
|
39430
|
+
return siblings.length;
|
|
39431
|
+
}
|
|
39432
|
+
function isFieldLabelCandidate(element) {
|
|
39433
|
+
if (element.role !== "generic" && element.role !== "paragraph" && element.role !== "text" && element.role !== "label" && element.role !== "strong" && element.role !== "emphasis") {
|
|
39434
|
+
return false;
|
|
39435
|
+
}
|
|
39436
|
+
if (isClickableByAttribute(element)) return false;
|
|
39437
|
+
if (hasInteractiveDescendants(element)) return false;
|
|
39438
|
+
const text = getFieldLabelText(element);
|
|
39439
|
+
if (!text || text.length < 1 || text.length > VISUAL_HEADING_MAX_LENGTH) return false;
|
|
39440
|
+
return true;
|
|
39441
|
+
}
|
|
39442
|
+
function getFieldLabelText(element) {
|
|
39443
|
+
if (element.text) return element.text.trim();
|
|
39444
|
+
if (element.inputValue && !INTERACTIVE_ROLES.has(element.role)) return element.inputValue.trim();
|
|
39445
|
+
for (const child of element.children) {
|
|
39446
|
+
if (FIELD_LABEL_TEXT_ROLES.has(child.role)) {
|
|
39447
|
+
if (child.text) return child.text.trim();
|
|
39448
|
+
if (child.inputValue && !INTERACTIVE_ROLES.has(child.role)) return child.inputValue.trim();
|
|
39127
39449
|
}
|
|
39128
39450
|
}
|
|
39129
|
-
|
|
39130
|
-
|
|
39131
|
-
|
|
39132
|
-
|
|
39133
|
-
|
|
39134
|
-
|
|
39135
|
-
|
|
39136
|
-
|
|
39137
|
-
};
|
|
39451
|
+
return void 0;
|
|
39452
|
+
}
|
|
39453
|
+
function resolveContainerFieldLabel(container) {
|
|
39454
|
+
const kids = container.children;
|
|
39455
|
+
if (kids.length < 2 || kids.length > 4) return void 0;
|
|
39456
|
+
const firstChild = kids[0];
|
|
39457
|
+
if (isFieldLabelCandidate(firstChild)) {
|
|
39458
|
+
return getFieldLabelText(firstChild);
|
|
39138
39459
|
}
|
|
39139
|
-
return
|
|
39460
|
+
return void 0;
|
|
39140
39461
|
}
|
|
39141
|
-
function
|
|
39142
|
-
|
|
39143
|
-
|
|
39144
|
-
|
|
39145
|
-
|
|
39146
|
-
|
|
39147
|
-
|
|
39148
|
-
|
|
39149
|
-
|
|
39150
|
-
|
|
39151
|
-
|
|
39152
|
-
|
|
39153
|
-
|
|
39154
|
-
|
|
39155
|
-
|
|
39156
|
-
return {
|
|
39157
|
-
...cell,
|
|
39158
|
-
column: positionalColumn,
|
|
39159
|
-
value: cleanValue,
|
|
39160
|
-
hasValue: cleanValue !== ""
|
|
39161
|
-
};
|
|
39462
|
+
function findFieldLabelFromSiblings(siblings, interactiveIndex) {
|
|
39463
|
+
for (let i = interactiveIndex - 1; i >= 0; i--) {
|
|
39464
|
+
const sib = siblings[i];
|
|
39465
|
+
if (INTERACTIVE_ROLES.has(sib.role) || STRUCTURAL_ROLES.has(sib.role) || sib.role === "heading") {
|
|
39466
|
+
break;
|
|
39467
|
+
}
|
|
39468
|
+
if (isClickableByAttribute(sib)) {
|
|
39469
|
+
if (sib.role === "generic" || sib.role === "paragraph" || sib.role === "label") {
|
|
39470
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
39471
|
+
const prev = siblings[j];
|
|
39472
|
+
if (INTERACTIVE_ROLES.has(prev.role) || isClickableByAttribute(prev) || STRUCTURAL_ROLES.has(prev.role) || prev.role === "heading") {
|
|
39473
|
+
break;
|
|
39474
|
+
}
|
|
39475
|
+
if (isFieldLabelCandidate(prev)) {
|
|
39476
|
+
return getFieldLabelText(prev);
|
|
39162
39477
|
}
|
|
39478
|
+
if (prev.children.length >= 1 && prev.children.length <= 4) {
|
|
39479
|
+
const containerLabel = resolveContainerFieldLabel(prev);
|
|
39480
|
+
if (containerLabel) return containerLabel;
|
|
39481
|
+
}
|
|
39482
|
+
if (prev.children.length > 4) break;
|
|
39163
39483
|
}
|
|
39164
|
-
|
|
39165
|
-
|
|
39166
|
-
}
|
|
39167
|
-
|
|
39484
|
+
}
|
|
39485
|
+
break;
|
|
39486
|
+
}
|
|
39487
|
+
if (isFieldLabelCandidate(sib)) {
|
|
39488
|
+
return getFieldLabelText(sib);
|
|
39489
|
+
}
|
|
39490
|
+
if (sib.children.length >= 1 && sib.children.length <= 4) {
|
|
39491
|
+
const containerLabel = resolveContainerFieldLabel(sib);
|
|
39492
|
+
if (containerLabel) return containerLabel;
|
|
39493
|
+
}
|
|
39494
|
+
if (sib.children.length > 4) break;
|
|
39495
|
+
}
|
|
39496
|
+
return void 0;
|
|
39168
39497
|
}
|
|
39169
|
-
function
|
|
39170
|
-
|
|
39171
|
-
|
|
39172
|
-
|
|
39173
|
-
|
|
39498
|
+
function findFieldLabelInContext(_element, siblings, siblingIndex) {
|
|
39499
|
+
return findFieldLabelFromSiblings(siblings, siblingIndex);
|
|
39500
|
+
}
|
|
39501
|
+
function shouldDropInheritedFieldLabel(element, inheritedFieldLabel) {
|
|
39502
|
+
if (!inheritedFieldLabel) return false;
|
|
39503
|
+
if (INTERACTIVE_LEAF_ROLES.has(element.role)) return false;
|
|
39504
|
+
if (!isClickableByAttribute(element)) return false;
|
|
39505
|
+
const directText = getElementText(element);
|
|
39506
|
+
if (directText) {
|
|
39507
|
+
return directText.toLowerCase() !== inheritedFieldLabel.toLowerCase();
|
|
39508
|
+
}
|
|
39509
|
+
const childTexts = [];
|
|
39510
|
+
for (const child of element.children) {
|
|
39511
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
39512
|
+
const text = getElementText(child);
|
|
39513
|
+
if (text && TEXT_CARRYING_ROLES.has(child.role)) {
|
|
39514
|
+
childTexts.push(text);
|
|
39515
|
+
}
|
|
39174
39516
|
}
|
|
39175
|
-
|
|
39176
|
-
|
|
39177
|
-
|
|
39517
|
+
}
|
|
39518
|
+
const composedText = childTexts.join(" ");
|
|
39519
|
+
if (!composedText) return false;
|
|
39520
|
+
return composedText.toLowerCase() !== inheritedFieldLabel.toLowerCase();
|
|
39521
|
+
}
|
|
39522
|
+
function isExpandedElement(element) {
|
|
39523
|
+
return element.attributes["expanded"] === "true" || element.attributes["aria-expanded"] === "true";
|
|
39524
|
+
}
|
|
39525
|
+
function collectExpandedChildren(element, result) {
|
|
39526
|
+
for (const child of element.children) {
|
|
39527
|
+
if (STRUCTURAL_ROLES.has(child.role)) continue;
|
|
39528
|
+
if (INTERACTIVE_LEAF_ROLES.has(child.role) && child.ref) {
|
|
39529
|
+
result.push(formatElement(child));
|
|
39530
|
+
continue;
|
|
39531
|
+
}
|
|
39532
|
+
if (child.role === "listitem" && child.ref) {
|
|
39533
|
+
const text = child.text || child.children.map((c2) => getElementText(c2)).filter((value) => Boolean(value)).join(" | ") || getDisplayText(child);
|
|
39534
|
+
if (text && text !== "listitem") {
|
|
39535
|
+
result.push(formatElement(child, { overrideLabel: text }));
|
|
39536
|
+
continue;
|
|
39178
39537
|
}
|
|
39179
39538
|
}
|
|
39539
|
+
if (isClickableByAttribute(child) && child.ref) {
|
|
39540
|
+
result.push(formatElement(child));
|
|
39541
|
+
}
|
|
39542
|
+
collectExpandedChildren(child, result);
|
|
39180
39543
|
}
|
|
39181
|
-
|
|
39182
|
-
|
|
39544
|
+
}
|
|
39545
|
+
function hasActionableChildren(element) {
|
|
39546
|
+
const children2 = [];
|
|
39547
|
+
collectExpandedChildren(element, children2);
|
|
39548
|
+
return children2.length > 0;
|
|
39549
|
+
}
|
|
39550
|
+
function isExpandedWithActionableChildren(element) {
|
|
39551
|
+
if (!isExpandedElement(element)) return false;
|
|
39552
|
+
if (element.role === "combobox") return false;
|
|
39553
|
+
return hasActionableChildren(element);
|
|
39554
|
+
}
|
|
39555
|
+
function composeTriggerLabel(element) {
|
|
39556
|
+
const ariaLabel = element.attributes["aria-label"];
|
|
39557
|
+
if (ariaLabel) return ariaLabel;
|
|
39558
|
+
const fullText = element.text || "";
|
|
39559
|
+
if (fullText) {
|
|
39560
|
+
let collectLeafTexts2 = function(el) {
|
|
39561
|
+
for (const child of el.children) {
|
|
39562
|
+
const text = child.text?.trim();
|
|
39563
|
+
if (text) {
|
|
39564
|
+
leafTexts.push(text);
|
|
39565
|
+
}
|
|
39566
|
+
collectLeafTexts2(child);
|
|
39567
|
+
}
|
|
39568
|
+
};
|
|
39569
|
+
var collectLeafTexts = collectLeafTexts2;
|
|
39570
|
+
const leafTexts = [];
|
|
39571
|
+
collectLeafTexts2(element);
|
|
39572
|
+
if (leafTexts.length > 0) {
|
|
39573
|
+
let stripped = fullText;
|
|
39574
|
+
for (const lt of leafTexts) {
|
|
39575
|
+
stripped = stripped.replace(lt, "");
|
|
39576
|
+
}
|
|
39577
|
+
stripped = stripped.replace(/\s+/g, " ").trim();
|
|
39578
|
+
if (stripped) return stripped;
|
|
39579
|
+
}
|
|
39183
39580
|
}
|
|
39184
|
-
return
|
|
39581
|
+
return element.role;
|
|
39185
39582
|
}
|
|
39186
39583
|
function formatElement(element, options) {
|
|
39187
|
-
const isClickable =
|
|
39188
|
-
const
|
|
39189
|
-
const textSource = normalizeIconLabelText(element.role, rawTextSource);
|
|
39584
|
+
const isClickable = isActionableClickableGeneric(element);
|
|
39585
|
+
const textSource = getDisplayText(element, { overrideLabel: options?.overrideLabel });
|
|
39190
39586
|
const extracted = extractDataValue(textSource);
|
|
39191
39587
|
const normalizedAttributes = Object.entries(element.attributes).filter(
|
|
39192
39588
|
([key]) => key !== "ref" && key !== "cursor" && key !== "aria-controls" && key !== "aria-owns" && key !== "options" && key !== "field"
|
|
@@ -39220,105 +39616,141 @@ function formatElement(element, options) {
|
|
|
39220
39616
|
attributes: normalizedAttributes
|
|
39221
39617
|
};
|
|
39222
39618
|
}
|
|
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
39619
|
function shouldCollapse(section) {
|
|
39240
39620
|
if (section.containsActive) return false;
|
|
39241
39621
|
if (section.hasSearchMatch) return false;
|
|
39242
39622
|
if (section.isBackground) return true;
|
|
39243
39623
|
if (section.role === "dialog" || section.role === "alertdialog") return false;
|
|
39244
|
-
if (section.role === "navigation" || section.role === "menubar" || section.role === "menu")
|
|
39245
|
-
return false;
|
|
39246
|
-
}
|
|
39624
|
+
if (section.role === "navigation" || section.role === "menubar" || section.role === "menu") return false;
|
|
39247
39625
|
if (section.role === "banner") return false;
|
|
39248
39626
|
if (section.role === "form") return false;
|
|
39249
39627
|
if (section.elementCount >= MIN_ELEMENTS_TO_COLLAPSE) return true;
|
|
39250
39628
|
return false;
|
|
39251
39629
|
}
|
|
39252
|
-
function
|
|
39253
|
-
const
|
|
39254
|
-
for (const
|
|
39255
|
-
|
|
39256
|
-
|
|
39257
|
-
|
|
39630
|
+
function deduplicateFieldLabels(elements) {
|
|
39631
|
+
const byFieldLabel = /* @__PURE__ */ new Map();
|
|
39632
|
+
for (const el of elements) {
|
|
39633
|
+
if (!el.fieldLabel) continue;
|
|
39634
|
+
const existing = byFieldLabel.get(el.fieldLabel);
|
|
39635
|
+
if (existing) {
|
|
39636
|
+
existing.push(el);
|
|
39637
|
+
} else {
|
|
39638
|
+
byFieldLabel.set(el.fieldLabel, [el]);
|
|
39639
|
+
}
|
|
39640
|
+
}
|
|
39641
|
+
for (const [, group] of byFieldLabel) {
|
|
39642
|
+
if (group.length < 2) continue;
|
|
39643
|
+
for (let i = 0; i < group.length; i++) {
|
|
39644
|
+
const el = group[i];
|
|
39645
|
+
if (el.name && el.name !== el.fieldLabel) {
|
|
39646
|
+
el.fieldLabel = `${el.fieldLabel}: ${el.name}`;
|
|
39647
|
+
} else {
|
|
39648
|
+
el.fieldLabel = `${el.fieldLabel} (${i + 1})`;
|
|
39649
|
+
}
|
|
39650
|
+
}
|
|
39651
|
+
}
|
|
39652
|
+
}
|
|
39653
|
+
function buildGridSection(element) {
|
|
39654
|
+
const gridInfo = detectGrid(element);
|
|
39655
|
+
if (!gridInfo) {
|
|
39656
|
+
throw new Error("buildGridSection requires a grid element");
|
|
39657
|
+
}
|
|
39658
|
+
return {
|
|
39659
|
+
ref: element.ref || "",
|
|
39660
|
+
role: element.role,
|
|
39661
|
+
heading: "Grid",
|
|
39662
|
+
level: 0,
|
|
39663
|
+
elements: [],
|
|
39664
|
+
subsections: [],
|
|
39665
|
+
containsActive: gridInfo.containsActive,
|
|
39666
|
+
collapsed: false,
|
|
39667
|
+
isBackground: false,
|
|
39668
|
+
isFocused: false,
|
|
39669
|
+
elementCount: gridInfo.totalRows * Math.max(gridInfo.columns.length, 1),
|
|
39670
|
+
gridInfo
|
|
39671
|
+
};
|
|
39672
|
+
}
|
|
39673
|
+
function collectInteractiveElements(element, elements, subsections, depth, inheritedFieldLabel) {
|
|
39674
|
+
if ((INTERACTIVE_LEAF_ROLES.has(element.role) || isClickableByAttribute(element)) && element.ref) {
|
|
39675
|
+
const effectiveFieldLabel = shouldDropInheritedFieldLabel(element, inheritedFieldLabel) ? void 0 : inheritedFieldLabel;
|
|
39676
|
+
if (INTERACTIVE_LEAF_ROLES.has(element.role) && isExpandedWithActionableChildren(element)) {
|
|
39677
|
+
elements.push(formatElement(element, { overrideLabel: composeTriggerLabel(element), fieldLabel: effectiveFieldLabel }));
|
|
39678
|
+
collectExpandedChildren(element, elements);
|
|
39679
|
+
return;
|
|
39258
39680
|
}
|
|
39259
|
-
|
|
39260
|
-
|
|
39261
|
-
|
|
39262
|
-
|
|
39263
|
-
|
|
39264
|
-
|
|
39265
|
-
if (hasActiveSibling) {
|
|
39266
|
-
for (const section of sections) {
|
|
39267
|
-
if (!section.containsActive) {
|
|
39268
|
-
section.isBackground = true;
|
|
39269
|
-
section.collapsed = shouldCollapse(section);
|
|
39681
|
+
if (!isMenuTriggerNoise(element)) {
|
|
39682
|
+
elements.push(formatElement(element, { fieldLabel: effectiveFieldLabel }));
|
|
39683
|
+
}
|
|
39684
|
+
if (!INTERACTIVE_LEAF_ROLES.has(element.role) && isClickableByAttribute(element)) {
|
|
39685
|
+
for (const child of element.children) {
|
|
39686
|
+
collectInteractiveElements(child, elements, subsections, depth + 1, effectiveFieldLabel);
|
|
39270
39687
|
}
|
|
39271
39688
|
}
|
|
39689
|
+
return;
|
|
39272
39690
|
}
|
|
39273
|
-
|
|
39274
|
-
|
|
39275
|
-
|
|
39276
|
-
|
|
39277
|
-
function markMatchingSections(sections, matchedRefs) {
|
|
39278
|
-
for (const section of sections) {
|
|
39279
|
-
const hasDirectMatch = section.elements.some((el) => matchedRefs.has(el.ref));
|
|
39280
|
-
markMatchingSections(section.subsections, matchedRefs);
|
|
39281
|
-
const hasSubsectionMatch = section.subsections.some((s) => s.hasSearchMatch);
|
|
39282
|
-
if (hasDirectMatch || hasSubsectionMatch) {
|
|
39283
|
-
section.hasSearchMatch = true;
|
|
39284
|
-
section.collapsed = false;
|
|
39691
|
+
if (element.role === "heading" || STRUCTURAL_ROLES.has(element.role) || element.role === "grid" || element.role === "treegrid" || element.role === "table" && !isWidgetTable(element)) {
|
|
39692
|
+
const section = buildSection(element, depth);
|
|
39693
|
+
if (section) {
|
|
39694
|
+
subsections.push(section);
|
|
39285
39695
|
}
|
|
39696
|
+
return;
|
|
39286
39697
|
}
|
|
39287
|
-
|
|
39288
|
-
|
|
39289
|
-
|
|
39290
|
-
|
|
39291
|
-
|
|
39292
|
-
|
|
39293
|
-
const
|
|
39294
|
-
|
|
39295
|
-
|
|
39296
|
-
|
|
39297
|
-
|
|
39298
|
-
|
|
39299
|
-
|
|
39300
|
-
|
|
39301
|
-
|
|
39302
|
-
|
|
39303
|
-
|
|
39304
|
-
|
|
39305
|
-
|
|
39698
|
+
const kids = element.children;
|
|
39699
|
+
for (let ki = 0; ki < kids.length; ki++) {
|
|
39700
|
+
const child = kids[ki];
|
|
39701
|
+
if (isVisualHeading(child, kids, ki)) {
|
|
39702
|
+
const headingText = getVisualHeadingText(child);
|
|
39703
|
+
const sectionElements = [];
|
|
39704
|
+
const sectionSubsections = [];
|
|
39705
|
+
const nextBoundary = findNextSectionBoundary(kids, ki + 1);
|
|
39706
|
+
for (let si = ki + 1; si < nextBoundary; si++) {
|
|
39707
|
+
collectInteractiveElements(kids[si], sectionElements, sectionSubsections, depth + 2);
|
|
39708
|
+
}
|
|
39709
|
+
if (sectionElements.length > 0 || sectionSubsections.length > 0) {
|
|
39710
|
+
const totalElements = sectionElements.length + sectionSubsections.reduce((sum, s) => sum + s.elementCount, 0);
|
|
39711
|
+
subsections.push({
|
|
39712
|
+
heading: headingText ?? "",
|
|
39713
|
+
ref: child.ref,
|
|
39714
|
+
role: "heading",
|
|
39715
|
+
level: 4,
|
|
39716
|
+
elements: sectionElements,
|
|
39717
|
+
subsections: sectionSubsections,
|
|
39718
|
+
collapsed: false,
|
|
39719
|
+
containsActive: false,
|
|
39720
|
+
isBackground: false,
|
|
39721
|
+
isFocused: false,
|
|
39722
|
+
elementCount: totalElements
|
|
39723
|
+
});
|
|
39724
|
+
ki = nextBoundary - 1;
|
|
39725
|
+
} else {
|
|
39726
|
+
collectInteractiveElements(child, elements, subsections, depth + 1);
|
|
39727
|
+
}
|
|
39728
|
+
} else if ((INTERACTIVE_LEAF_ROLES.has(child.role) || isClickableByAttribute(child)) && child.ref) {
|
|
39729
|
+
const rawFieldLabel = findFieldLabelInContext(child, kids, ki) ?? inheritedFieldLabel;
|
|
39730
|
+
const fieldLabel = shouldDropInheritedFieldLabel(child, rawFieldLabel) ? void 0 : rawFieldLabel;
|
|
39731
|
+
if (!isMenuTriggerNoise(child)) {
|
|
39732
|
+
if (INTERACTIVE_LEAF_ROLES.has(child.role) && isExpandedWithActionableChildren(child)) {
|
|
39733
|
+
elements.push(formatElement(child, { overrideLabel: composeTriggerLabel(child), fieldLabel }));
|
|
39734
|
+
collectExpandedChildren(child, elements);
|
|
39735
|
+
} else {
|
|
39736
|
+
elements.push(formatElement(child, { fieldLabel }));
|
|
39737
|
+
}
|
|
39738
|
+
}
|
|
39739
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role) && isClickableByAttribute(child)) {
|
|
39740
|
+
for (const grandchild of child.children) {
|
|
39741
|
+
collectInteractiveElements(grandchild, elements, subsections, depth + 1, fieldLabel);
|
|
39742
|
+
}
|
|
39306
39743
|
}
|
|
39744
|
+
} else {
|
|
39745
|
+
const containerLabel = resolveContainerFieldLabel(child) ?? (child.role === "table" ? findFieldLabelFromSiblings(kids, ki) : void 0) ?? inheritedFieldLabel;
|
|
39746
|
+
collectInteractiveElements(child, elements, subsections, depth + 1, containerLabel);
|
|
39307
39747
|
}
|
|
39308
|
-
const sortedDialogs = dialogs.sort((a, b) => {
|
|
39309
|
-
if (a.containsActive && !b.containsActive) return -1;
|
|
39310
|
-
if (!a.containsActive && b.containsActive) return 1;
|
|
39311
|
-
return 0;
|
|
39312
|
-
});
|
|
39313
|
-
return [...sortedDialogs, ...nonDialogs];
|
|
39314
39748
|
}
|
|
39315
|
-
const sorted = processLevel(sections);
|
|
39316
|
-
return { sorted, dialogStack };
|
|
39317
39749
|
}
|
|
39318
39750
|
function buildSection(element, depth) {
|
|
39319
39751
|
const gridInfo = detectGrid(element);
|
|
39320
39752
|
if (gridInfo) {
|
|
39321
|
-
return buildGridSection(element
|
|
39753
|
+
return buildGridSection(element);
|
|
39322
39754
|
}
|
|
39323
39755
|
const isHeading = element.role === "heading";
|
|
39324
39756
|
const isStructural = STRUCTURAL_ROLES.has(element.role);
|
|
@@ -39356,7 +39788,6 @@ function buildSection(element, depth) {
|
|
|
39356
39788
|
ref: child.ref,
|
|
39357
39789
|
role: "heading",
|
|
39358
39790
|
level: 4,
|
|
39359
|
-
// Visual headings rendered at h6 level (4 + 2 = 6)
|
|
39360
39791
|
elements: sectionElements,
|
|
39361
39792
|
subsections: sectionSubsections,
|
|
39362
39793
|
collapsed: false,
|
|
@@ -39400,192 +39831,157 @@ function buildSection(element, depth) {
|
|
|
39400
39831
|
const section = {
|
|
39401
39832
|
ref: element.ref || "",
|
|
39402
39833
|
role: element.role,
|
|
39403
|
-
heading: element.text || (isClickableByAttribute(element) ?
|
|
39834
|
+
heading: element.text || (isClickableByAttribute(element) ? getDisplayText(element) : element.role),
|
|
39404
39835
|
level,
|
|
39405
39836
|
elements: interactiveElements,
|
|
39406
39837
|
subsections,
|
|
39407
39838
|
containsActive,
|
|
39408
39839
|
collapsed: false,
|
|
39409
39840
|
isBackground: false,
|
|
39410
|
-
// Will be set by markBackgroundSections if needed
|
|
39411
39841
|
isFocused: false,
|
|
39412
|
-
// Will be set by sortSectionsByFocus if needed
|
|
39413
39842
|
elementCount
|
|
39414
39843
|
};
|
|
39844
|
+
deduplicateFieldLabels(interactiveElements);
|
|
39415
39845
|
section.collapsed = shouldCollapse(section);
|
|
39416
39846
|
return section;
|
|
39417
39847
|
}
|
|
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);
|
|
39848
|
+
function markBackgroundSections(sections) {
|
|
39849
|
+
const hasActiveSibling = sections.some((s) => s.containsActive);
|
|
39850
|
+
if (hasActiveSibling) {
|
|
39851
|
+
for (const section of sections) {
|
|
39852
|
+
if (!section.containsActive) {
|
|
39853
|
+
section.isBackground = true;
|
|
39854
|
+
section.collapsed = shouldCollapse(section);
|
|
39450
39855
|
}
|
|
39451
39856
|
}
|
|
39452
|
-
return;
|
|
39453
39857
|
}
|
|
39454
|
-
|
|
39455
|
-
|
|
39456
|
-
if (section) {
|
|
39457
|
-
subsections.push(section);
|
|
39458
|
-
}
|
|
39459
|
-
return;
|
|
39858
|
+
for (const section of sections) {
|
|
39859
|
+
markBackgroundSections(section.subsections);
|
|
39460
39860
|
}
|
|
39461
|
-
|
|
39462
|
-
|
|
39463
|
-
|
|
39464
|
-
|
|
39465
|
-
|
|
39466
|
-
|
|
39467
|
-
|
|
39468
|
-
|
|
39469
|
-
for (let si = ki + 1; si < nextBoundary; si++) {
|
|
39470
|
-
collectInteractiveElements(kids[si], sectionElements, sectionSubsections, depth + 2);
|
|
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
|
-
}
|
|
39861
|
+
}
|
|
39862
|
+
function mergeFilterDropdownPairs(elements) {
|
|
39863
|
+
for (let i = elements.length - 2; i >= 0; i--) {
|
|
39864
|
+
const current = elements[i];
|
|
39865
|
+
const next = elements[i + 1];
|
|
39866
|
+
if (current.role === "generic" && current.isClickable && next.role === "img" && next.isClickable && (!next.label || next.label === "img")) {
|
|
39867
|
+
if (!current.fieldLabel && next.fieldLabel) {
|
|
39868
|
+
current.fieldLabel = next.fieldLabel;
|
|
39506
39869
|
}
|
|
39507
|
-
|
|
39508
|
-
const containerLabel = resolveContainerFieldLabel(child) ?? (child.role === "table" ? findFieldLabelFromSiblings(kids, ki) : void 0) ?? inheritedFieldLabel;
|
|
39509
|
-
collectInteractiveElements(child, elements, subsections, depth + 1, containerLabel);
|
|
39870
|
+
elements.splice(i + 1, 1);
|
|
39510
39871
|
}
|
|
39511
39872
|
}
|
|
39512
39873
|
}
|
|
39513
|
-
function
|
|
39514
|
-
|
|
39515
|
-
|
|
39874
|
+
function applyFilterMerge(sections) {
|
|
39875
|
+
for (const section of sections) {
|
|
39876
|
+
mergeFilterDropdownPairs(section.elements);
|
|
39877
|
+
applyFilterMerge(section.subsections);
|
|
39516
39878
|
}
|
|
39517
|
-
|
|
39518
|
-
|
|
39519
|
-
const
|
|
39520
|
-
const
|
|
39521
|
-
|
|
39522
|
-
|
|
39523
|
-
|
|
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");
|
|
39879
|
+
}
|
|
39880
|
+
function buildSectionTree(elements) {
|
|
39881
|
+
const sections = [];
|
|
39882
|
+
for (const element of elements) {
|
|
39883
|
+
const section = buildSection(element, 0);
|
|
39884
|
+
if (section) {
|
|
39885
|
+
sections.push(section);
|
|
39534
39886
|
}
|
|
39535
|
-
|
|
39536
|
-
|
|
39537
|
-
|
|
39538
|
-
|
|
39539
|
-
|
|
39887
|
+
}
|
|
39888
|
+
markBackgroundSections(sections);
|
|
39889
|
+
applyFilterMerge(sections);
|
|
39890
|
+
return sections;
|
|
39891
|
+
}
|
|
39892
|
+
function markMatchingSections(sections, matchedRefs) {
|
|
39893
|
+
for (const section of sections) {
|
|
39894
|
+
const hasDirectMatch = section.elements.some((el) => matchedRefs.has(el.ref)) || (section.gridInfo ? Array.from(matchedRefs).some((ref) => gridContainsRef(section.gridInfo, ref)) : false);
|
|
39895
|
+
markMatchingSections(section.subsections, matchedRefs);
|
|
39896
|
+
const hasSubsectionMatch = section.subsections.some((s) => s.hasSearchMatch);
|
|
39897
|
+
if (hasDirectMatch || hasSubsectionMatch) {
|
|
39898
|
+
section.hasSearchMatch = true;
|
|
39899
|
+
section.collapsed = false;
|
|
39540
39900
|
}
|
|
39541
|
-
|
|
39542
|
-
|
|
39901
|
+
}
|
|
39902
|
+
}
|
|
39903
|
+
function sortSectionsByFocus(sections) {
|
|
39904
|
+
const dialogStack = [];
|
|
39905
|
+
function processLevel(levelSections) {
|
|
39906
|
+
for (const section of levelSections) {
|
|
39907
|
+
section.subsections = processLevel(section.subsections);
|
|
39543
39908
|
}
|
|
39544
|
-
|
|
39545
|
-
|
|
39909
|
+
const dialogs = levelSections.filter((s) => DIALOG_ROLES.has(s.role));
|
|
39910
|
+
const nonDialogs = levelSections.filter((s) => !DIALOG_ROLES.has(s.role));
|
|
39911
|
+
const focusedDialog = dialogs.find((d) => d.containsActive);
|
|
39912
|
+
if (focusedDialog) {
|
|
39913
|
+
focusedDialog.isFocused = true;
|
|
39914
|
+
dialogStack.unshift(focusedDialog.heading);
|
|
39546
39915
|
}
|
|
39547
|
-
|
|
39548
|
-
|
|
39916
|
+
for (const dialog of dialogs) {
|
|
39917
|
+
if (!dialog.containsActive) {
|
|
39918
|
+
dialogStack.push(dialog.heading);
|
|
39919
|
+
}
|
|
39549
39920
|
}
|
|
39550
|
-
|
|
39551
|
-
|
|
39552
|
-
|
|
39553
|
-
|
|
39921
|
+
const sortedDialogs = dialogs.sort((a, b) => {
|
|
39922
|
+
if (a.containsActive && !b.containsActive) return -1;
|
|
39923
|
+
if (!a.containsActive && b.containsActive) return 1;
|
|
39924
|
+
return 0;
|
|
39925
|
+
});
|
|
39926
|
+
return [...sortedDialogs, ...nonDialogs];
|
|
39554
39927
|
}
|
|
39555
|
-
|
|
39556
|
-
|
|
39557
|
-
|
|
39558
|
-
|
|
39559
|
-
|
|
39928
|
+
const sorted = processLevel(sections);
|
|
39929
|
+
return { sorted, dialogStack };
|
|
39930
|
+
}
|
|
39931
|
+
function expandSectionByRef(sections, targetRef) {
|
|
39932
|
+
for (const section of sections) {
|
|
39933
|
+
if (section.ref === targetRef) {
|
|
39934
|
+
section.collapsed = false;
|
|
39935
|
+
return true;
|
|
39936
|
+
}
|
|
39937
|
+
if (expandSectionByRef(section.subsections, targetRef)) {
|
|
39938
|
+
return true;
|
|
39560
39939
|
}
|
|
39561
39940
|
}
|
|
39562
|
-
return
|
|
39941
|
+
return false;
|
|
39563
39942
|
}
|
|
39564
|
-
function
|
|
39565
|
-
const
|
|
39566
|
-
|
|
39567
|
-
|
|
39943
|
+
function findSectionByRef(sections, targetRef) {
|
|
39944
|
+
for (const section of sections) {
|
|
39945
|
+
if (section.ref === targetRef) {
|
|
39946
|
+
return section;
|
|
39947
|
+
}
|
|
39948
|
+
const found = findSectionByRef(section.subsections, targetRef);
|
|
39949
|
+
if (found) {
|
|
39950
|
+
return found;
|
|
39951
|
+
}
|
|
39568
39952
|
}
|
|
39569
|
-
return
|
|
39953
|
+
return null;
|
|
39570
39954
|
}
|
|
39571
|
-
|
|
39572
|
-
|
|
39573
|
-
|
|
39574
|
-
|
|
39575
|
-
|
|
39955
|
+
|
|
39956
|
+
// ../browser-core/src/snapshot-formatter-render.ts
|
|
39957
|
+
var COLOR_NAMES = [
|
|
39958
|
+
"red",
|
|
39959
|
+
"green",
|
|
39960
|
+
"blue",
|
|
39961
|
+
"yellow",
|
|
39962
|
+
"magenta",
|
|
39963
|
+
"cyan",
|
|
39964
|
+
"orange",
|
|
39965
|
+
"purple",
|
|
39966
|
+
"teal",
|
|
39967
|
+
"pink"
|
|
39968
|
+
];
|
|
39969
|
+
function findActiveElement(elements) {
|
|
39970
|
+
let deepestActive = null;
|
|
39971
|
+
function findDeepest(element) {
|
|
39972
|
+
for (const child of element.children) {
|
|
39973
|
+
findDeepest(child);
|
|
39974
|
+
}
|
|
39975
|
+
if (element.attributes["active"] !== void 0 || element.rawLine.includes("[active]")) {
|
|
39976
|
+
if (!deepestActive) {
|
|
39977
|
+
deepestActive = element;
|
|
39978
|
+
}
|
|
39979
|
+
}
|
|
39576
39980
|
}
|
|
39577
|
-
const
|
|
39578
|
-
|
|
39579
|
-
const heading = subsection.heading || subsection.role;
|
|
39580
|
-
if (elementNames.length === 0) {
|
|
39581
|
-
return `${heading}${refPart}`;
|
|
39981
|
+
for (const element of elements) {
|
|
39982
|
+
findDeepest(element);
|
|
39582
39983
|
}
|
|
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}`;
|
|
39984
|
+
return deepestActive;
|
|
39589
39985
|
}
|
|
39590
39986
|
function formatElementLine(el, indent) {
|
|
39591
39987
|
const indentStr = " ".repeat(indent);
|
|
@@ -39637,23 +40033,102 @@ function formatElementLine(el, indent) {
|
|
|
39637
40033
|
}
|
|
39638
40034
|
return indentStr + parts.join(" ");
|
|
39639
40035
|
}
|
|
39640
|
-
|
|
39641
|
-
|
|
39642
|
-
|
|
39643
|
-
|
|
39644
|
-
|
|
39645
|
-
|
|
39646
|
-
|
|
39647
|
-
|
|
39648
|
-
"
|
|
39649
|
-
|
|
39650
|
-
|
|
39651
|
-
|
|
40036
|
+
function collectAllElementsFlat(section) {
|
|
40037
|
+
const elements = [...section.elements];
|
|
40038
|
+
for (const subsection of section.subsections) {
|
|
40039
|
+
elements.push(...collectAllElementsFlat(subsection));
|
|
40040
|
+
}
|
|
40041
|
+
return elements;
|
|
40042
|
+
}
|
|
40043
|
+
function formatSubsectionSummary(subsection) {
|
|
40044
|
+
const refPart = subsection.ref ? ` [${subsection.ref}]` : "";
|
|
40045
|
+
if (subsection.gridInfo) {
|
|
40046
|
+
const colInfo = subsection.gridInfo.columns.length > 0 ? `${subsection.gridInfo.columns.length} columns` : "unknown columns";
|
|
40047
|
+
return `GRID${refPart}: ${subsection.gridInfo.totalRows} rows, ${colInfo}`;
|
|
40048
|
+
}
|
|
40049
|
+
const allElements = collectAllElementsFlat(subsection);
|
|
40050
|
+
const elementNames = allElements.map((el) => el.label || el.name || el.role).filter(Boolean);
|
|
40051
|
+
const heading = subsection.heading || subsection.role;
|
|
40052
|
+
if (elementNames.length === 0) {
|
|
40053
|
+
return `${heading}${refPart}`;
|
|
40054
|
+
}
|
|
40055
|
+
const MAX_PREVIEW_NAMES = 3;
|
|
40056
|
+
const previewNames = elementNames.slice(0, MAX_PREVIEW_NAMES);
|
|
40057
|
+
const remainingCount = elementNames.length - previewNames.length;
|
|
40058
|
+
const namesList = previewNames.join(", ");
|
|
40059
|
+
const moreNote = remainingCount > 0 ? `... +${remainingCount} more` : "";
|
|
40060
|
+
return `${heading}${refPart}: ${namesList}${moreNote}`;
|
|
40061
|
+
}
|
|
40062
|
+
function formatSectionOutput(section, indent, showCollapsed) {
|
|
40063
|
+
if (section.gridInfo) {
|
|
40064
|
+
return formatGridOutput(section.gridInfo, indent);
|
|
40065
|
+
}
|
|
40066
|
+
const indentStr = " ".repeat(indent);
|
|
40067
|
+
const lines = [];
|
|
40068
|
+
const headingPrefix = section.level > 0 ? "#".repeat(Math.min(section.level + 2, 6)) + " " : "";
|
|
40069
|
+
const refPart = section.ref ? ` [${section.ref}]` : "";
|
|
40070
|
+
const focusedPart = section.isFocused ? " [FOCUSED]" : "";
|
|
40071
|
+
const backgroundPart = section.isBackground ? " [BACKGROUND]" : "";
|
|
40072
|
+
const activePart = section.containsActive && !section.isFocused ? " \u2190 ACTIVE" : "";
|
|
40073
|
+
lines.push(`${indentStr}${headingPrefix}${section.heading}${refPart}${focusedPart}${backgroundPart}${activePart}`);
|
|
40074
|
+
if (section.collapsed && !showCollapsed) {
|
|
40075
|
+
if (section.isBackground) {
|
|
40076
|
+
if (section.ref) {
|
|
40077
|
+
lines.push(`${indentStr} (${section.elementCount} elements - use expand="${section.ref}" to see content)`);
|
|
40078
|
+
} else {
|
|
40079
|
+
lines.push(`${indentStr} (${section.elementCount} elements)`);
|
|
40080
|
+
}
|
|
40081
|
+
return lines.join("\n");
|
|
40082
|
+
}
|
|
40083
|
+
const MAX_DIRECT_ELEMENTS = 4;
|
|
40084
|
+
const previewElements = section.elements.slice(0, MAX_DIRECT_ELEMENTS);
|
|
40085
|
+
const remainingDirectCount = section.elements.length - previewElements.length;
|
|
40086
|
+
for (const el of previewElements) {
|
|
40087
|
+
lines.push(formatElementLine(el, indent + 1));
|
|
40088
|
+
}
|
|
40089
|
+
if (remainingDirectCount > 0) {
|
|
40090
|
+
lines.push(`${indentStr} ... +${remainingDirectCount} more elements`);
|
|
40091
|
+
}
|
|
40092
|
+
for (const subsection of section.subsections) {
|
|
40093
|
+
lines.push(`${indentStr} ${formatSubsectionSummary(subsection)}`);
|
|
40094
|
+
}
|
|
40095
|
+
if (section.ref && (section.elements.length > MAX_DIRECT_ELEMENTS || section.subsections.length > 0)) {
|
|
40096
|
+
lines.push(`${indentStr} (use expand="${section.ref}" to see all)`);
|
|
40097
|
+
}
|
|
40098
|
+
return lines.join("\n");
|
|
40099
|
+
}
|
|
40100
|
+
for (const el of section.elements) {
|
|
40101
|
+
lines.push(formatElementLine(el, indent + 1));
|
|
40102
|
+
}
|
|
40103
|
+
for (const subsection of section.subsections) {
|
|
40104
|
+
const subsectionOutput = formatSectionOutput(subsection, indent + 1, showCollapsed);
|
|
40105
|
+
if (subsectionOutput) {
|
|
40106
|
+
lines.push("");
|
|
40107
|
+
lines.push(subsectionOutput);
|
|
40108
|
+
}
|
|
40109
|
+
}
|
|
40110
|
+
return lines.join("\n");
|
|
40111
|
+
}
|
|
40112
|
+
function countRenderedElements(sections) {
|
|
40113
|
+
let count = 0;
|
|
40114
|
+
for (const section of sections) {
|
|
40115
|
+
count += section.elements.length;
|
|
40116
|
+
if (section.gridInfo) {
|
|
40117
|
+
count += countRenderedGridItems(section.gridInfo);
|
|
40118
|
+
}
|
|
40119
|
+
count += countRenderedElements(section.subsections);
|
|
40120
|
+
}
|
|
40121
|
+
return count;
|
|
40122
|
+
}
|
|
40123
|
+
function countTotalSections(sections) {
|
|
40124
|
+
let count = sections.length;
|
|
40125
|
+
for (const section of sections) {
|
|
40126
|
+
count += countTotalSections(section.subsections);
|
|
40127
|
+
}
|
|
40128
|
+
return count;
|
|
40129
|
+
}
|
|
39652
40130
|
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
|
-
) : "";
|
|
40131
|
+
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
40132
|
const activeDesc = activeElement ? `${activeElement.ref} ${activeElement.role} "${activeLabel}"` : "None";
|
|
39658
40133
|
const dialogStackLine = dialogStack.length > 0 ? `
|
|
39659
40134
|
DIALOG STACK: ${dialogStack.join(" \u2192 ")}` : "";
|
|
@@ -39692,9 +40167,8 @@ ${toastLines.join("\n")}`;
|
|
|
39692
40167
|
SEARCH RESULTS (${matchCountText}${sortNote}):
|
|
39693
40168
|
${matchLines.join("\n")}`;
|
|
39694
40169
|
}
|
|
39695
|
-
const INPUT_ROLES = /* @__PURE__ */ new Set(["textbox", "combobox", "searchbox", "spinbutton"]);
|
|
39696
40170
|
let typeActionHint = "";
|
|
39697
|
-
if (activeElement &&
|
|
40171
|
+
if (activeElement && FORM_INPUT_ROLES.has(activeElement.role)) {
|
|
39698
40172
|
typeActionHint = `
|
|
39699
40173
|
- Type in active field: browser_type ref=${activeElement.ref} text="..."`;
|
|
39700
40174
|
}
|
|
@@ -39729,20 +40203,59 @@ ACTIONS:
|
|
|
39729
40203
|
- Use bash or python_execute on the FULL TREE FILE for detailed element analysis
|
|
39730
40204
|
---`;
|
|
39731
40205
|
}
|
|
39732
|
-
function
|
|
39733
|
-
|
|
39734
|
-
|
|
39735
|
-
|
|
39736
|
-
|
|
40206
|
+
function disambiguateDuplicateLabels(sections) {
|
|
40207
|
+
const elementEntries = [];
|
|
40208
|
+
function collectElements(section) {
|
|
40209
|
+
for (const el of section.elements) {
|
|
40210
|
+
elementEntries.push({ el, sectionHeading: section.heading });
|
|
40211
|
+
}
|
|
40212
|
+
for (const sub of section.subsections) {
|
|
40213
|
+
collectElements(sub);
|
|
40214
|
+
}
|
|
39737
40215
|
}
|
|
39738
|
-
return count;
|
|
39739
|
-
}
|
|
39740
|
-
function countTotalSections(sections) {
|
|
39741
|
-
let count = sections.length;
|
|
39742
40216
|
for (const section of sections) {
|
|
39743
|
-
|
|
40217
|
+
collectElements(section);
|
|
40218
|
+
}
|
|
40219
|
+
const SKIP_LABELS = /* @__PURE__ */ new Set(["(icon)", "button", "link", "generic"]);
|
|
40220
|
+
const byLabel = /* @__PURE__ */ new Map();
|
|
40221
|
+
for (const entry of elementEntries) {
|
|
40222
|
+
const label = entry.el.label || entry.el.name;
|
|
40223
|
+
if (!label || label.length === 0) continue;
|
|
40224
|
+
if (SKIP_LABELS.has(label)) continue;
|
|
40225
|
+
if (!entry.el.ref) continue;
|
|
40226
|
+
const existing = byLabel.get(label);
|
|
40227
|
+
if (existing) {
|
|
40228
|
+
existing.push(entry);
|
|
40229
|
+
} else {
|
|
40230
|
+
byLabel.set(label, [entry]);
|
|
40231
|
+
}
|
|
40232
|
+
}
|
|
40233
|
+
for (const [, entries] of byLabel) {
|
|
40234
|
+
if (entries.length < 2) continue;
|
|
40235
|
+
const distinctSections = new Set(entries.map((e) => e.sectionHeading));
|
|
40236
|
+
if (distinctSections.size > 1) {
|
|
40237
|
+
for (const entry of entries) {
|
|
40238
|
+
const currentLabel = entry.el.label || entry.el.name || "";
|
|
40239
|
+
if (entry.el.label) {
|
|
40240
|
+
entry.el.label = `${currentLabel} (in ${entry.sectionHeading})`;
|
|
40241
|
+
} else if (entry.el.name) {
|
|
40242
|
+
entry.el.name = `${currentLabel} (in ${entry.sectionHeading})`;
|
|
40243
|
+
}
|
|
40244
|
+
}
|
|
40245
|
+
} else {
|
|
40246
|
+
const ordinals = ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th"];
|
|
40247
|
+
for (let i = 0; i < entries.length; i++) {
|
|
40248
|
+
const entry = entries[i];
|
|
40249
|
+
const ordinal = i < ordinals.length ? ordinals[i] : `${i + 1}th`;
|
|
40250
|
+
const currentLabel = entry.el.label || entry.el.name || "";
|
|
40251
|
+
if (entry.el.label) {
|
|
40252
|
+
entry.el.label = `${currentLabel} (${ordinal})`;
|
|
40253
|
+
} else if (entry.el.name) {
|
|
40254
|
+
entry.el.name = `${currentLabel} (${ordinal})`;
|
|
40255
|
+
}
|
|
40256
|
+
}
|
|
40257
|
+
}
|
|
39744
40258
|
}
|
|
39745
|
-
return count;
|
|
39746
40259
|
}
|
|
39747
40260
|
function formatSemanticSnapshot(yaml, options) {
|
|
39748
40261
|
if (!yaml || yaml.trim() === "") {
|
|
@@ -39775,10 +40288,10 @@ function formatSemanticSnapshot(yaml, options) {
|
|
|
39775
40288
|
}
|
|
39776
40289
|
}
|
|
39777
40290
|
if (options?.probeResult?.ref) {
|
|
39778
|
-
|
|
39779
|
-
markMatchingSections(sortedSections, probeRefs);
|
|
40291
|
+
markMatchingSections(sortedSections, /* @__PURE__ */ new Set([options.probeResult.ref]));
|
|
39780
40292
|
}
|
|
39781
|
-
|
|
40293
|
+
disambiguateDuplicateLabels(sortedSections);
|
|
40294
|
+
const elementCount = countRenderedElements(sortedSections);
|
|
39782
40295
|
const sectionCount = countTotalSections(sortedSections);
|
|
39783
40296
|
const lines = [];
|
|
39784
40297
|
lines.push(
|
|
@@ -39788,7 +40301,6 @@ function formatSemanticSnapshot(yaml, options) {
|
|
|
39788
40301
|
activeElement,
|
|
39789
40302
|
dialogStack,
|
|
39790
40303
|
sortedMatches,
|
|
39791
|
-
// Use re-sorted matches with context
|
|
39792
40304
|
options?.totalMatchCount,
|
|
39793
40305
|
options?.snapshotFilePath,
|
|
39794
40306
|
options?.probeResult,
|
|
@@ -39804,7 +40316,11 @@ function formatSemanticSnapshot(yaml, options) {
|
|
|
39804
40316
|
lines.push("");
|
|
39805
40317
|
}
|
|
39806
40318
|
}
|
|
39807
|
-
|
|
40319
|
+
let result = lines.join("\n").trim();
|
|
40320
|
+
if (options?.offScreenRefs && options.offScreenRefs.size > 0) {
|
|
40321
|
+
result = markOffScreenElements(result, options.offScreenRefs);
|
|
40322
|
+
}
|
|
40323
|
+
return result;
|
|
39808
40324
|
}
|
|
39809
40325
|
function expandSection(yaml, sectionRef) {
|
|
39810
40326
|
if (!yaml || yaml.trim() === "") {
|
|
@@ -39818,7 +40334,7 @@ function expandSection(yaml, sectionRef) {
|
|
|
39818
40334
|
const sections = buildSectionTree(elements);
|
|
39819
40335
|
const { sorted: sortedSections, dialogStack } = sortSectionsByFocus(sections);
|
|
39820
40336
|
expandSectionByRef(sortedSections, sectionRef);
|
|
39821
|
-
const elementCount =
|
|
40337
|
+
const elementCount = countRenderedElements(sortedSections);
|
|
39822
40338
|
const sectionCount = countTotalSections(sortedSections);
|
|
39823
40339
|
const lines = [];
|
|
39824
40340
|
lines.push(generateFrontmatter(elementCount, sectionCount, activeElement, dialogStack));
|
|
@@ -39832,29 +40348,26 @@ function expandSection(yaml, sectionRef) {
|
|
|
39832
40348
|
}
|
|
39833
40349
|
return lines.join("\n").trim();
|
|
39834
40350
|
}
|
|
39835
|
-
function
|
|
39836
|
-
|
|
39837
|
-
|
|
39838
|
-
|
|
39839
|
-
|
|
39840
|
-
|
|
39841
|
-
|
|
39842
|
-
|
|
39843
|
-
|
|
40351
|
+
function formatExpandedSectionOutput(section) {
|
|
40352
|
+
const lines = [];
|
|
40353
|
+
const subsectionInfo = section.subsections.length > 0 ? `, ${section.subsections.length} subsections` : "";
|
|
40354
|
+
lines.push(`---`);
|
|
40355
|
+
lines.push(`EXPANDED SECTION: ${section.heading} [${section.ref}]`);
|
|
40356
|
+
lines.push(`Contains ${section.elementCount} elements${subsectionInfo}`);
|
|
40357
|
+
lines.push(`---`);
|
|
40358
|
+
lines.push("");
|
|
40359
|
+
if (section.gridInfo) {
|
|
40360
|
+
lines.push(formatGridOutput(section.gridInfo, 0, true));
|
|
40361
|
+
return lines.join("\n").trim();
|
|
39844
40362
|
}
|
|
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
|
-
}
|
|
40363
|
+
for (const el of section.elements) {
|
|
40364
|
+
lines.push(formatElementLine(el, 0));
|
|
39856
40365
|
}
|
|
39857
|
-
|
|
40366
|
+
for (const subsection of section.subsections) {
|
|
40367
|
+
lines.push("");
|
|
40368
|
+
lines.push(formatSectionOutput(subsection, 0, false));
|
|
40369
|
+
}
|
|
40370
|
+
return lines.join("\n").trim();
|
|
39858
40371
|
}
|
|
39859
40372
|
function expandSectionOnly(yaml, sectionRef) {
|
|
39860
40373
|
if (!yaml || yaml.trim() === "") {
|
|
@@ -39881,79 +40394,142 @@ Section with ref="${sectionRef}" not found in snapshot.
|
|
|
39881
40394
|
targetSection.collapsed = false;
|
|
39882
40395
|
return formatExpandedSectionOutput(targetSection);
|
|
39883
40396
|
}
|
|
39884
|
-
function
|
|
39885
|
-
|
|
39886
|
-
|
|
39887
|
-
|
|
39888
|
-
|
|
39889
|
-
|
|
39890
|
-
|
|
39891
|
-
|
|
39892
|
-
|
|
39893
|
-
|
|
39894
|
-
|
|
39895
|
-
|
|
39896
|
-
|
|
39897
|
-
|
|
40397
|
+
function markOffScreenElements(text, offScreenRefs) {
|
|
40398
|
+
if (offScreenRefs.size === 0) return text;
|
|
40399
|
+
return text.replace(/\[(e\d+)\](?! \[off-screen\])/g, (match, ref) => {
|
|
40400
|
+
if (offScreenRefs.has(ref)) {
|
|
40401
|
+
return `[${ref}] [off-screen]`;
|
|
40402
|
+
}
|
|
40403
|
+
return match;
|
|
40404
|
+
});
|
|
40405
|
+
}
|
|
40406
|
+
|
|
40407
|
+
// ../browser-core/src/table-extractor.ts
|
|
40408
|
+
function extractTablesFromSnapshot(yamlOrResponse, options) {
|
|
40409
|
+
const yaml = yamlOrResponse.includes("Page Snapshot:") ? extractSnapshotYaml(yamlOrResponse) : yamlOrResponse;
|
|
40410
|
+
if (!yaml) return null;
|
|
40411
|
+
const elements = parseSnapshot(yaml);
|
|
40412
|
+
if (elements.length === 0) return null;
|
|
40413
|
+
const grids = [];
|
|
40414
|
+
const findGrids = (els) => {
|
|
40415
|
+
for (const el of els) {
|
|
40416
|
+
const grid = detectGrid(el);
|
|
40417
|
+
if (grid && grid.rows.length > 0) {
|
|
40418
|
+
grids.push({ grid, element: el });
|
|
40419
|
+
}
|
|
40420
|
+
if (!grid) {
|
|
40421
|
+
findGrids(el.children);
|
|
40422
|
+
}
|
|
40423
|
+
}
|
|
40424
|
+
};
|
|
40425
|
+
findGrids(elements);
|
|
40426
|
+
if (grids.length === 0) return null;
|
|
40427
|
+
let target;
|
|
40428
|
+
if (options?.ref) {
|
|
40429
|
+
const match = grids.find((g) => g.grid.ref === options.ref);
|
|
40430
|
+
if (!match) return null;
|
|
40431
|
+
target = match;
|
|
40432
|
+
} else {
|
|
40433
|
+
target = grids.reduce(
|
|
40434
|
+
(best, current) => current.grid.rows.length > best.grid.rows.length ? current : best
|
|
40435
|
+
);
|
|
39898
40436
|
}
|
|
39899
|
-
|
|
40437
|
+
const { columns, rows } = gridInfoToRows(target.grid);
|
|
40438
|
+
if (columns.length === 0) return null;
|
|
40439
|
+
const pagination = detectPaginationInfo(elements, target.grid.ref);
|
|
40440
|
+
return {
|
|
40441
|
+
columns,
|
|
40442
|
+
rows,
|
|
40443
|
+
gridRef: target.grid.ref,
|
|
40444
|
+
pagination: pagination ?? void 0
|
|
40445
|
+
};
|
|
39900
40446
|
}
|
|
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}`);
|
|
40447
|
+
function gridInfoToRows(grid) {
|
|
40448
|
+
const columns = grid.columns.map((c2) => c2.name);
|
|
40449
|
+
if (columns.length === 0) return { columns: [], rows: [] };
|
|
40450
|
+
const columnIndex = /* @__PURE__ */ new Map();
|
|
40451
|
+
for (let i = 0; i < columns.length; i++) {
|
|
40452
|
+
columnIndex.set(columns[i], i);
|
|
39912
40453
|
}
|
|
39913
|
-
|
|
39914
|
-
const
|
|
39915
|
-
|
|
39916
|
-
|
|
39917
|
-
|
|
39918
|
-
|
|
40454
|
+
const rows = [];
|
|
40455
|
+
for (const row of grid.rows) {
|
|
40456
|
+
const values = new Array(columns.length).fill("");
|
|
40457
|
+
for (const cell of row.cells) {
|
|
40458
|
+
const idx = columnIndex.get(cell.column);
|
|
40459
|
+
if (idx !== void 0) {
|
|
40460
|
+
values[idx] = cleanCellValue(cell.value, cell.gridcellLabel);
|
|
40461
|
+
}
|
|
40462
|
+
}
|
|
40463
|
+
rows.push(values);
|
|
39919
40464
|
}
|
|
39920
|
-
|
|
39921
|
-
|
|
40465
|
+
return { columns, rows };
|
|
40466
|
+
}
|
|
40467
|
+
var SVG_ARTIFACT_PATTERN = /^Styled\(svg\)$/i;
|
|
40468
|
+
function cleanCellValue(value, gridcellLabel) {
|
|
40469
|
+
if (!value || SVG_ARTIFACT_PATTERN.test(value)) {
|
|
40470
|
+
if (gridcellLabel) {
|
|
40471
|
+
return gridcellLabel.replace(/\s*Styled\(svg\)\s*/gi, "").trim();
|
|
40472
|
+
}
|
|
40473
|
+
return "";
|
|
39922
40474
|
}
|
|
39923
|
-
return
|
|
40475
|
+
return value;
|
|
39924
40476
|
}
|
|
39925
|
-
function
|
|
39926
|
-
const
|
|
39927
|
-
|
|
39928
|
-
|
|
39929
|
-
|
|
39930
|
-
|
|
40477
|
+
function formatCSVWithFrontmatter(columns, rows, _options) {
|
|
40478
|
+
const lines = [];
|
|
40479
|
+
lines.push(columns.map(escapeCSVField).join(","));
|
|
40480
|
+
for (const row of rows) {
|
|
40481
|
+
lines.push(row.map(escapeCSVField).join(","));
|
|
40482
|
+
}
|
|
40483
|
+
return lines.join("\n") + "\n";
|
|
40484
|
+
}
|
|
40485
|
+
function appendRowsToCSV(existingCSV, newRows, columns, _options) {
|
|
40486
|
+
const existingLines = existingCSV.split("\n").filter((l) => l.trim() !== "");
|
|
40487
|
+
const dataLines = [];
|
|
40488
|
+
let headerLine = "";
|
|
40489
|
+
for (const line of existingLines) {
|
|
40490
|
+
if (line.startsWith("#")) continue;
|
|
40491
|
+
if (!headerLine) {
|
|
40492
|
+
headerLine = line;
|
|
40493
|
+
continue;
|
|
39931
40494
|
}
|
|
39932
|
-
|
|
39933
|
-
|
|
40495
|
+
dataLines.push(line);
|
|
40496
|
+
}
|
|
40497
|
+
const existingRowSet = new Set(dataLines);
|
|
40498
|
+
const newRowStrings = newRows.map((row) => row.map(escapeCSVField).join(","));
|
|
40499
|
+
const addedRows = [];
|
|
40500
|
+
for (const rowStr of newRowStrings) {
|
|
40501
|
+
if (!existingRowSet.has(rowStr)) {
|
|
40502
|
+
addedRows.push(rowStr);
|
|
40503
|
+
existingRowSet.add(rowStr);
|
|
39934
40504
|
}
|
|
39935
|
-
return `${indentStr} \u21B3 Expanded [${row.ref}]: ${parts.join(" | ")}`;
|
|
39936
40505
|
}
|
|
39937
|
-
const
|
|
39938
|
-
const
|
|
39939
|
-
|
|
39940
|
-
|
|
39941
|
-
|
|
39942
|
-
|
|
39943
|
-
|
|
39944
|
-
|
|
39945
|
-
|
|
39946
|
-
|
|
39947
|
-
|
|
39948
|
-
|
|
39949
|
-
return `${
|
|
40506
|
+
const allDataLines = [...dataLines, ...addedRows];
|
|
40507
|
+
const result = [headerLine || columns.map(escapeCSVField).join(","), ...allDataLines];
|
|
40508
|
+
return result.join("\n") + "\n";
|
|
40509
|
+
}
|
|
40510
|
+
function detectPaginationInfo(elements, _gridRef) {
|
|
40511
|
+
const paginationPattern = /(\d+)\s*[-–]\s*(\d+)\s+of\s+([\d,]+)/i;
|
|
40512
|
+
const searchText = (els) => {
|
|
40513
|
+
for (const el of els) {
|
|
40514
|
+
const text = el.text || "";
|
|
40515
|
+
const match = text.match(paginationPattern);
|
|
40516
|
+
if (match) {
|
|
40517
|
+
const total = parseInt(match[3].replace(/,/g, ""), 10);
|
|
40518
|
+
return { showing: `${match[1]}-${match[2]}`, total };
|
|
39950
40519
|
}
|
|
39951
|
-
|
|
39952
|
-
|
|
39953
|
-
|
|
39954
|
-
|
|
39955
|
-
|
|
40520
|
+
const childResult = searchText(el.children);
|
|
40521
|
+
if (childResult) return childResult;
|
|
40522
|
+
}
|
|
40523
|
+
return null;
|
|
40524
|
+
};
|
|
40525
|
+
return searchText(elements);
|
|
40526
|
+
}
|
|
40527
|
+
function escapeCSVField(field) {
|
|
40528
|
+
if (!field) return "";
|
|
40529
|
+
if (field.includes(",") || field.includes('"') || field.includes("\n")) {
|
|
40530
|
+
return `"${field.replace(/"/g, '""')}"`;
|
|
39956
40531
|
}
|
|
40532
|
+
return field;
|
|
39957
40533
|
}
|
|
39958
40534
|
|
|
39959
40535
|
// ../browser-core/src/snapshot-diff.ts
|
|
@@ -41007,6 +41583,42 @@ ${effectiveShowCoordinateGrid ? "Coordinate grid enabled - read coordinates from
|
|
|
41007
41583
|
await fs2.writeFile(snapshotFilePath, yaml, "utf-8");
|
|
41008
41584
|
} catch {
|
|
41009
41585
|
}
|
|
41586
|
+
let offScreenRefs;
|
|
41587
|
+
try {
|
|
41588
|
+
const viewportSize = this.client.getViewportSize();
|
|
41589
|
+
const offScreen = await this.client.evaluate(
|
|
41590
|
+
`() => {
|
|
41591
|
+
const vw = ${viewportSize.width};
|
|
41592
|
+
const vh = ${viewportSize.height};
|
|
41593
|
+
const offscreen = [];
|
|
41594
|
+
const els = document.querySelectorAll('[aria-ref]');
|
|
41595
|
+
for (const el of els) {
|
|
41596
|
+
const ref = el.getAttribute('aria-ref');
|
|
41597
|
+
if (!ref) continue;
|
|
41598
|
+
const r = el.getBoundingClientRect();
|
|
41599
|
+
if (r.width === 0 && r.height === 0) continue;
|
|
41600
|
+
if (r.right < 0 || r.left > vw || r.bottom < 0 || r.top > vh) {
|
|
41601
|
+
offscreen.push(ref);
|
|
41602
|
+
}
|
|
41603
|
+
}
|
|
41604
|
+
return offscreen;
|
|
41605
|
+
}`,
|
|
41606
|
+
{ signal: this.signal }
|
|
41607
|
+
);
|
|
41608
|
+
if (typeof offScreen === "string") {
|
|
41609
|
+
try {
|
|
41610
|
+
const parsed = JSON.parse(offScreen);
|
|
41611
|
+
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
41612
|
+
offScreenRefs = new Set(parsed);
|
|
41613
|
+
}
|
|
41614
|
+
} catch {
|
|
41615
|
+
}
|
|
41616
|
+
}
|
|
41617
|
+
} catch (e) {
|
|
41618
|
+
this.logger?.debug?.("[browser_snapshot] Off-screen detection failed", {
|
|
41619
|
+
error: e instanceof Error ? e.message : String(e)
|
|
41620
|
+
});
|
|
41621
|
+
}
|
|
41010
41622
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
41011
41623
|
const semanticText = formatSemanticSnapshot(yaml, {
|
|
41012
41624
|
searchMatches: searchMatches.length > 0 ? searchMatches : void 0,
|
|
@@ -41014,7 +41626,8 @@ ${effectiveShowCoordinateGrid ? "Coordinate grid enabled - read coordinates from
|
|
|
41014
41626
|
snapshotFilePath,
|
|
41015
41627
|
probeResult,
|
|
41016
41628
|
currentTime: now,
|
|
41017
|
-
capturedToasts: this.client.getCapturedToasts?.() ?? []
|
|
41629
|
+
capturedToasts: this.client.getCapturedToasts?.() ?? [],
|
|
41630
|
+
offScreenRefs
|
|
41018
41631
|
});
|
|
41019
41632
|
if (hasImages) {
|
|
41020
41633
|
const resolutionNote = buildResolutionNote(
|
|
@@ -41728,7 +42341,7 @@ function getBrowserToolDefinitions() {
|
|
|
41728
42341
|
},
|
|
41729
42342
|
toRef: {
|
|
41730
42343
|
type: "string",
|
|
41731
|
-
description: "Scroll the page so this element is centered
|
|
42344
|
+
description: "Scroll the page so this element is centered in the viewport. Handles both vertical and horizontal scrolling automatically \u2014 works for grid columns that are horizontally off-screen."
|
|
41732
42345
|
},
|
|
41733
42346
|
x: {
|
|
41734
42347
|
type: "number",
|
|
@@ -41898,6 +42511,136 @@ function getBrowserToolDefinitionsWithLifecycle() {
|
|
|
41898
42511
|
];
|
|
41899
42512
|
}
|
|
41900
42513
|
|
|
42514
|
+
// ../browser-core/src/tools/dispatcher.ts
|
|
42515
|
+
async function dispatchBrowserTool(executor, toolName, args) {
|
|
42516
|
+
switch (toolName) {
|
|
42517
|
+
case "browser_navigate":
|
|
42518
|
+
return executor.navigate(args.url);
|
|
42519
|
+
case "browser_navigate_back":
|
|
42520
|
+
return executor.navigateBack();
|
|
42521
|
+
case "browser_snapshot":
|
|
42522
|
+
return executor.snapshot({
|
|
42523
|
+
mode: args.mode,
|
|
42524
|
+
expand: args.expand,
|
|
42525
|
+
search: args.search,
|
|
42526
|
+
showCoordinateGrid: args.showCoordinateGrid,
|
|
42527
|
+
probeAt: args.probeAt
|
|
42528
|
+
});
|
|
42529
|
+
case "browser_screenshot":
|
|
42530
|
+
return executor.screenshot({
|
|
42531
|
+
fullPage: args.fullPage,
|
|
42532
|
+
element: args.element,
|
|
42533
|
+
ref: args.ref,
|
|
42534
|
+
label: args.label,
|
|
42535
|
+
returnImage: args.returnImage
|
|
42536
|
+
});
|
|
42537
|
+
case "browser_evaluate":
|
|
42538
|
+
return executor.evaluate({
|
|
42539
|
+
expression: args.function,
|
|
42540
|
+
element: args.element,
|
|
42541
|
+
ref: args.ref
|
|
42542
|
+
});
|
|
42543
|
+
case "browser_console_messages":
|
|
42544
|
+
return executor.consoleMessages({
|
|
42545
|
+
onlyErrors: args.onlyErrors
|
|
42546
|
+
});
|
|
42547
|
+
case "browser_network_requests":
|
|
42548
|
+
return executor.networkRequests();
|
|
42549
|
+
case "browser_click":
|
|
42550
|
+
return executor.click({
|
|
42551
|
+
ref: args.ref,
|
|
42552
|
+
x: args.x,
|
|
42553
|
+
y: args.y,
|
|
42554
|
+
element: args.element,
|
|
42555
|
+
doubleClick: args.doubleClick,
|
|
42556
|
+
button: args.button,
|
|
42557
|
+
modifiers: args.modifiers
|
|
42558
|
+
});
|
|
42559
|
+
case "browser_hover":
|
|
42560
|
+
return executor.hover({
|
|
42561
|
+
ref: args.ref,
|
|
42562
|
+
element: args.element
|
|
42563
|
+
});
|
|
42564
|
+
case "browser_drag":
|
|
42565
|
+
return executor.drag({
|
|
42566
|
+
startRef: args.startRef,
|
|
42567
|
+
endRef: args.endRef,
|
|
42568
|
+
startElement: args.startElement,
|
|
42569
|
+
endElement: args.endElement,
|
|
42570
|
+
startX: args.startX,
|
|
42571
|
+
startY: args.startY,
|
|
42572
|
+
endX: args.endX,
|
|
42573
|
+
endY: args.endY
|
|
42574
|
+
});
|
|
42575
|
+
case "browser_type":
|
|
42576
|
+
return executor.type({
|
|
42577
|
+
ref: args.ref,
|
|
42578
|
+
text: args.text,
|
|
42579
|
+
element: args.element,
|
|
42580
|
+
submit: args.submit,
|
|
42581
|
+
delay: args.delay
|
|
42582
|
+
});
|
|
42583
|
+
case "browser_press_key":
|
|
42584
|
+
return executor.pressKey(args.key);
|
|
42585
|
+
case "browser_fill_form":
|
|
42586
|
+
return executor.fillForm(
|
|
42587
|
+
args.fields
|
|
42588
|
+
);
|
|
42589
|
+
case "browser_select_option":
|
|
42590
|
+
return executor.selectOption({
|
|
42591
|
+
ref: args.ref,
|
|
42592
|
+
value: args.value,
|
|
42593
|
+
element: args.element
|
|
42594
|
+
});
|
|
42595
|
+
case "browser_file_upload":
|
|
42596
|
+
return executor.fileUpload(args.paths);
|
|
42597
|
+
case "browser_scroll":
|
|
42598
|
+
return executor.scroll({
|
|
42599
|
+
direction: args.direction,
|
|
42600
|
+
amount: args.amount,
|
|
42601
|
+
withinRef: args.withinRef,
|
|
42602
|
+
toRef: args.toRef,
|
|
42603
|
+
x: args.x,
|
|
42604
|
+
y: args.y
|
|
42605
|
+
});
|
|
42606
|
+
case "browser_handle_dialog":
|
|
42607
|
+
return executor.handleDialog({
|
|
42608
|
+
action: args.action,
|
|
42609
|
+
promptText: args.promptText
|
|
42610
|
+
});
|
|
42611
|
+
case "browser_dismiss_overlay":
|
|
42612
|
+
return executor.dismissOverlay({
|
|
42613
|
+
preferredStrategy: args.preferredStrategy
|
|
42614
|
+
});
|
|
42615
|
+
case "browser_wait_for":
|
|
42616
|
+
return executor.waitFor({
|
|
42617
|
+
timeSec: args.time,
|
|
42618
|
+
text: args.text,
|
|
42619
|
+
textGone: args.textGone,
|
|
42620
|
+
selector: args.selector,
|
|
42621
|
+
state: args.state,
|
|
42622
|
+
timeout: args.timeout
|
|
42623
|
+
});
|
|
42624
|
+
case "browser_close":
|
|
42625
|
+
return executor.close();
|
|
42626
|
+
case "browser_resize":
|
|
42627
|
+
return executor.resize(args.width, args.height);
|
|
42628
|
+
case "browser_tabs":
|
|
42629
|
+
return executor.tabs({
|
|
42630
|
+
action: args.action,
|
|
42631
|
+
index: args.index
|
|
42632
|
+
});
|
|
42633
|
+
case "browser_list_downloads":
|
|
42634
|
+
return executor.listDownloads();
|
|
42635
|
+
case "browser_read_download":
|
|
42636
|
+
return executor.readDownload(args.downloadId);
|
|
42637
|
+
case "browser_pdf_read":
|
|
42638
|
+
return executor.fetchPdfText(args.url);
|
|
42639
|
+
default:
|
|
42640
|
+
throw new Error(`Unknown browser tool: ${toolName}`);
|
|
42641
|
+
}
|
|
42642
|
+
}
|
|
42643
|
+
|
|
41901
42644
|
// ../browser-core/src/playwright-client.ts
|
|
41902
42645
|
import {
|
|
41903
42646
|
chromium as playwrightChromium
|
|
@@ -43018,6 +43761,29 @@ function appendAttributeIfMissing(line, key, value) {
|
|
|
43018
43761
|
const baseLine = hasTrailingColon ? line.replace(/:\s*$/, "") : line;
|
|
43019
43762
|
return `${baseLine} [${key}=${value}]${hasTrailingColon ? ":" : ""}`;
|
|
43020
43763
|
}
|
|
43764
|
+
function findLabelFromYamlSiblings(elements, targetRef) {
|
|
43765
|
+
const findParent = (els, parent2) => {
|
|
43766
|
+
for (const el of els) {
|
|
43767
|
+
if (el.ref === targetRef) return parent2;
|
|
43768
|
+
const found = findParent(el.children, el);
|
|
43769
|
+
if (found) return found;
|
|
43770
|
+
}
|
|
43771
|
+
return null;
|
|
43772
|
+
};
|
|
43773
|
+
const parent = findParent(elements, null);
|
|
43774
|
+
if (!parent) return void 0;
|
|
43775
|
+
const targetIdx = parent.children.findIndex((c2) => c2.ref === targetRef);
|
|
43776
|
+
if (targetIdx < 0) return void 0;
|
|
43777
|
+
for (let i = targetIdx - 1; i >= 0; i--) {
|
|
43778
|
+
const sib = parent.children[i];
|
|
43779
|
+
const sibText = sib.text?.trim();
|
|
43780
|
+
if (sibText && sibText.length > 0 && sibText.length < 80 && /[a-zA-Z0-9]/.test(sibText)) {
|
|
43781
|
+
if (FORM_FIELD_ROLES.has(sib.role)) continue;
|
|
43782
|
+
return sibText;
|
|
43783
|
+
}
|
|
43784
|
+
}
|
|
43785
|
+
return void 0;
|
|
43786
|
+
}
|
|
43021
43787
|
async function augmentUnlabeledElements(page, yaml, logger2) {
|
|
43022
43788
|
try {
|
|
43023
43789
|
const elements = parseSnapshot(yaml);
|
|
@@ -43323,6 +44089,9 @@ async function augmentGridCellValues(page, yaml, logger2) {
|
|
|
43323
44089
|
}
|
|
43324
44090
|
}
|
|
43325
44091
|
var FORM_FIELD_ROLES = /* @__PURE__ */ new Set(["textbox", "combobox", "searchbox"]);
|
|
44092
|
+
function splitCamelCase(name) {
|
|
44093
|
+
return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\s+/g, " ").trim();
|
|
44094
|
+
}
|
|
43326
44095
|
async function augmentFormFieldLabels(page, yaml, logger2) {
|
|
43327
44096
|
try {
|
|
43328
44097
|
const elements = parseSnapshot(yaml);
|
|
@@ -43340,16 +44109,30 @@ async function augmentFormFieldLabels(page, yaml, logger2) {
|
|
|
43340
44109
|
walkForFields(el);
|
|
43341
44110
|
}
|
|
43342
44111
|
if (formFieldRefs.length === 0) return yaml;
|
|
43343
|
-
|
|
44112
|
+
const glyphFields = formFieldRefs.filter((f) => f.text && !/[a-zA-Z0-9]/.test(f.text));
|
|
44113
|
+
const displayNameIdx = yaml.indexOf("Display Name");
|
|
44114
|
+
const yamlAroundDisplayName = displayNameIdx >= 0 ? yaml.slice(Math.max(0, displayNameIdx - 50), displayNameIdx + 200) : "NOT FOUND";
|
|
44115
|
+
logger2.warn("[DirectPlaywright] augmentFormFieldLabels called", {
|
|
43344
44116
|
count: formFieldRefs.length,
|
|
43345
|
-
|
|
44117
|
+
glyphCount: glyphFields.length,
|
|
44118
|
+
allTexts: formFieldRefs.map((f) => `${f.ref}:${JSON.stringify(f.text)}`),
|
|
44119
|
+
hasDisplayName: yaml.includes("Display Name"),
|
|
44120
|
+
yamlHasGlyph: yaml.includes("\u268A"),
|
|
44121
|
+
yamlAroundDisplayName
|
|
43346
44122
|
});
|
|
43347
44123
|
let augmented = yaml;
|
|
43348
44124
|
for (const { ref, role, text } of formFieldRefs) {
|
|
43349
44125
|
try {
|
|
44126
|
+
const isGlyphField = text && !/[a-zA-Z0-9]/.test(text);
|
|
44127
|
+
if (isGlyphField) {
|
|
44128
|
+
logger2.info("[DirectPlaywright] Glyph-labeled field entering augmentation", { ref, role, text });
|
|
44129
|
+
}
|
|
43350
44130
|
const locator = page.locator(`aria-ref=${ref}`);
|
|
43351
44131
|
const count = await locator.count();
|
|
43352
|
-
if (count === 0)
|
|
44132
|
+
if (count === 0) {
|
|
44133
|
+
if (isGlyphField) logger2.info("[DirectPlaywright] Glyph field: locator count=0, skipping", { ref });
|
|
44134
|
+
continue;
|
|
44135
|
+
}
|
|
43353
44136
|
const label = await locator.first().evaluate((el) => {
|
|
43354
44137
|
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
|
|
43355
44138
|
const labels = el.labels;
|
|
@@ -43358,6 +44141,30 @@ async function augmentFormFieldLabels(page, yaml, logger2) {
|
|
|
43358
44141
|
if (labelText) return labelText;
|
|
43359
44142
|
}
|
|
43360
44143
|
}
|
|
44144
|
+
{
|
|
44145
|
+
const precedingLabels = [];
|
|
44146
|
+
let prevEl = el.previousElementSibling;
|
|
44147
|
+
while (prevEl) {
|
|
44148
|
+
if (prevEl.tagName === "LABEL") {
|
|
44149
|
+
precedingLabels.unshift(prevEl);
|
|
44150
|
+
} else {
|
|
44151
|
+
break;
|
|
44152
|
+
}
|
|
44153
|
+
prevEl = prevEl.previousElementSibling;
|
|
44154
|
+
}
|
|
44155
|
+
if (precedingLabels.length > 1) {
|
|
44156
|
+
const selected = precedingLabels.find((l) => {
|
|
44157
|
+
const cls = l.className.toLowerCase();
|
|
44158
|
+
return cls.includes("selected") || cls.includes("active") || cls.includes("current") || cls.includes("checked");
|
|
44159
|
+
});
|
|
44160
|
+
if (selected?.textContent?.trim()) return selected.textContent.trim();
|
|
44161
|
+
const first = precedingLabels[0];
|
|
44162
|
+
if (first?.textContent?.trim()) return first.textContent.trim();
|
|
44163
|
+
} else if (precedingLabels.length === 1) {
|
|
44164
|
+
const labelText = precedingLabels[0].textContent?.trim();
|
|
44165
|
+
if (labelText) return labelText;
|
|
44166
|
+
}
|
|
44167
|
+
}
|
|
43361
44168
|
const labelledBy = el.getAttribute("aria-labelledby");
|
|
43362
44169
|
if (labelledBy) {
|
|
43363
44170
|
const labelEl = document.getElementById(labelledBy);
|
|
@@ -43365,31 +44172,101 @@ async function augmentFormFieldLabels(page, yaml, logger2) {
|
|
|
43365
44172
|
}
|
|
43366
44173
|
const ariaLabel = el.getAttribute("aria-label");
|
|
43367
44174
|
const placeholder = el.getAttribute("placeholder");
|
|
43368
|
-
if (ariaLabel && ariaLabel !== placeholder) return ariaLabel;
|
|
43369
|
-
let sibling = el.previousElementSibling;
|
|
44175
|
+
if (ariaLabel && ariaLabel !== placeholder && /[a-zA-Z0-9]/.test(ariaLabel)) return ariaLabel;
|
|
43370
44176
|
let target = el;
|
|
43371
|
-
for (let
|
|
43372
|
-
sibling = target.previousElementSibling;
|
|
43373
|
-
|
|
44177
|
+
for (let depth = 0; depth < 3 && target; depth++) {
|
|
44178
|
+
let sibling = target.previousElementSibling;
|
|
44179
|
+
for (let sibCount = 0; sibling && sibCount < 3; sibCount++) {
|
|
43374
44180
|
const sibText = sibling.textContent?.trim();
|
|
43375
44181
|
if (sibText && sibText.length > 0 && sibText.length < 80 && !sibling.querySelector("input, textarea, select, button")) {
|
|
43376
44182
|
return sibText;
|
|
43377
44183
|
}
|
|
44184
|
+
if (sibling.querySelector("input, textarea, select, button")) break;
|
|
44185
|
+
sibling = sibling.previousElementSibling;
|
|
43378
44186
|
}
|
|
43379
44187
|
target = target.parentElement;
|
|
43380
44188
|
}
|
|
43381
44189
|
return void 0;
|
|
43382
44190
|
});
|
|
44191
|
+
if (isGlyphField) {
|
|
44192
|
+
logger2.info("[DirectPlaywright] Glyph field: DOM evaluate result", { ref, label, text });
|
|
44193
|
+
}
|
|
43383
44194
|
if (label && label !== text) {
|
|
43384
44195
|
augmented = updateElementLineByRef(
|
|
43385
44196
|
augmented,
|
|
43386
44197
|
ref,
|
|
43387
44198
|
(line) => injectElementLabel(line, role, label)
|
|
43388
44199
|
);
|
|
44200
|
+
if (isGlyphField) {
|
|
44201
|
+
logger2.info("[DirectPlaywright] Glyph field: injected DOM label", { ref, label });
|
|
44202
|
+
}
|
|
44203
|
+
}
|
|
44204
|
+
const hasGlyphOnlyLabel = text && !/[a-zA-Z0-9]/.test(text);
|
|
44205
|
+
if (hasGlyphOnlyLabel && (!label || label === text || !/[a-zA-Z0-9]/.test(label))) {
|
|
44206
|
+
const yamlLabel = findLabelFromYamlSiblings(elements, ref);
|
|
44207
|
+
logger2.info("[DirectPlaywright] YAML sibling fallback for glyph field", {
|
|
44208
|
+
ref,
|
|
44209
|
+
text,
|
|
44210
|
+
label,
|
|
44211
|
+
yamlLabel
|
|
44212
|
+
});
|
|
44213
|
+
if (yamlLabel) {
|
|
44214
|
+
augmented = updateElementLineByRef(
|
|
44215
|
+
augmented,
|
|
44216
|
+
ref,
|
|
44217
|
+
(line) => injectElementLabel(line, role, yamlLabel)
|
|
44218
|
+
);
|
|
44219
|
+
}
|
|
43389
44220
|
}
|
|
43390
44221
|
} catch {
|
|
43391
44222
|
}
|
|
43392
44223
|
}
|
|
44224
|
+
try {
|
|
44225
|
+
const postElements = parseSnapshot(augmented);
|
|
44226
|
+
const labeledFields = [];
|
|
44227
|
+
const walkForLabeled = (el) => {
|
|
44228
|
+
if (FORM_FIELD_ROLES.has(el.role) && el.ref && el.text) {
|
|
44229
|
+
labeledFields.push({ ref: el.ref, role: el.role, label: el.text });
|
|
44230
|
+
}
|
|
44231
|
+
for (const child of el.children) walkForLabeled(child);
|
|
44232
|
+
};
|
|
44233
|
+
for (const el of postElements) walkForLabeled(el);
|
|
44234
|
+
const byLabel = /* @__PURE__ */ new Map();
|
|
44235
|
+
for (const f of labeledFields) {
|
|
44236
|
+
const existing = byLabel.get(f.label);
|
|
44237
|
+
if (existing) {
|
|
44238
|
+
existing.push({ ref: f.ref, role: f.role });
|
|
44239
|
+
} else {
|
|
44240
|
+
byLabel.set(f.label, [{ ref: f.ref, role: f.role }]);
|
|
44241
|
+
}
|
|
44242
|
+
}
|
|
44243
|
+
for (const [label, fields] of byLabel) {
|
|
44244
|
+
if (fields.length < 2) continue;
|
|
44245
|
+
for (const field of fields) {
|
|
44246
|
+
try {
|
|
44247
|
+
const locator = page.locator(`aria-ref=${field.ref}`);
|
|
44248
|
+
const count = await locator.count();
|
|
44249
|
+
if (count === 0) continue;
|
|
44250
|
+
const disambiguation = await locator.first().evaluate((el) => {
|
|
44251
|
+
const placeholder = el.getAttribute("placeholder") || void 0;
|
|
44252
|
+
const ariaLabel = el.getAttribute("aria-label") || void 0;
|
|
44253
|
+
const name = el.getAttribute("name") || void 0;
|
|
44254
|
+
return { placeholder, ariaLabel, name };
|
|
44255
|
+
});
|
|
44256
|
+
const disambig = disambiguation.placeholder || disambiguation.ariaLabel || (disambiguation.name ? splitCamelCase(disambiguation.name) : void 0);
|
|
44257
|
+
if (disambig && disambig !== label) {
|
|
44258
|
+
augmented = updateElementLineByRef(
|
|
44259
|
+
augmented,
|
|
44260
|
+
field.ref,
|
|
44261
|
+
(line) => injectElementLabel(line, field.role, disambig)
|
|
44262
|
+
);
|
|
44263
|
+
}
|
|
44264
|
+
} catch {
|
|
44265
|
+
}
|
|
44266
|
+
}
|
|
44267
|
+
}
|
|
44268
|
+
} catch {
|
|
44269
|
+
}
|
|
43393
44270
|
return augmented;
|
|
43394
44271
|
} catch (err) {
|
|
43395
44272
|
logger2.debug("[DirectPlaywright] Form field label augmentation failed", {
|
|
@@ -43594,6 +44471,148 @@ async function augmentHiddenSelectOptions(page, yaml, logger2) {
|
|
|
43594
44471
|
return yaml;
|
|
43595
44472
|
}
|
|
43596
44473
|
}
|
|
44474
|
+
async function enrichModalDialogElements(page, logger2) {
|
|
44475
|
+
try {
|
|
44476
|
+
const enrichedCount = await page.evaluate(() => {
|
|
44477
|
+
let count = 0;
|
|
44478
|
+
const MAX_ENRICHMENTS = 3;
|
|
44479
|
+
function shouldSkip(el) {
|
|
44480
|
+
if (el.getAttribute("role") === "dialog" || el.getAttribute("role") === "alertdialog") return true;
|
|
44481
|
+
if (el.getAttribute("data-enriched-dialog") === "true") return true;
|
|
44482
|
+
return false;
|
|
44483
|
+
}
|
|
44484
|
+
function isVisible(el) {
|
|
44485
|
+
const style = window.getComputedStyle(el);
|
|
44486
|
+
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
44487
|
+
if (el instanceof HTMLElement && el.offsetWidth === 0 && el.offsetHeight === 0) return false;
|
|
44488
|
+
return true;
|
|
44489
|
+
}
|
|
44490
|
+
function enrichAsDialog(el) {
|
|
44491
|
+
if (count >= MAX_ENRICHMENTS) return;
|
|
44492
|
+
if (shouldSkip(el)) return;
|
|
44493
|
+
if (!isVisible(el)) return;
|
|
44494
|
+
el.setAttribute("role", "dialog");
|
|
44495
|
+
const heading = el.querySelector("h1, h2, h3, h4, h5, h6");
|
|
44496
|
+
if (heading?.textContent?.trim()) {
|
|
44497
|
+
el.setAttribute("aria-label", heading.textContent.trim());
|
|
44498
|
+
}
|
|
44499
|
+
el.setAttribute("data-enriched-dialog", "true");
|
|
44500
|
+
count++;
|
|
44501
|
+
}
|
|
44502
|
+
function hasInteractiveContent(el) {
|
|
44503
|
+
return el.querySelector('input, textarea, select, button, a[href], [role="button"], [role="link"], [role="textbox"], [role="combobox"]') !== null;
|
|
44504
|
+
}
|
|
44505
|
+
const CLASS_PATTERNS = [
|
|
44506
|
+
/\bmodal(?![-_]?(backdrop|mask|overlay|fade|bg|background))\b/i,
|
|
44507
|
+
/\bdialog\b/i,
|
|
44508
|
+
/\bpopup\b/i,
|
|
44509
|
+
/\blightbox\b/i,
|
|
44510
|
+
/\bdrawer\b/i
|
|
44511
|
+
];
|
|
44512
|
+
const FRAMEWORK_SELECTORS = [
|
|
44513
|
+
".cdk-overlay-pane",
|
|
44514
|
+
".mat-dialog-container",
|
|
44515
|
+
".mat-mdc-dialog-container",
|
|
44516
|
+
".ui-dialog",
|
|
44517
|
+
".modal-dialog",
|
|
44518
|
+
".ant-modal-content",
|
|
44519
|
+
".el-dialog",
|
|
44520
|
+
".v-dialog",
|
|
44521
|
+
".p-dialog"
|
|
44522
|
+
];
|
|
44523
|
+
for (const selector of FRAMEWORK_SELECTORS) {
|
|
44524
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44525
|
+
const els = document.querySelectorAll(selector);
|
|
44526
|
+
for (const el of els) {
|
|
44527
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44528
|
+
if (hasInteractiveContent(el)) {
|
|
44529
|
+
enrichAsDialog(el);
|
|
44530
|
+
}
|
|
44531
|
+
}
|
|
44532
|
+
}
|
|
44533
|
+
if (count < MAX_ENRICHMENTS) {
|
|
44534
|
+
const allElements = document.querySelectorAll("*");
|
|
44535
|
+
for (const el of allElements) {
|
|
44536
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44537
|
+
const className = el.className;
|
|
44538
|
+
if (typeof className !== "string") continue;
|
|
44539
|
+
if (CLASS_PATTERNS.some((pattern) => pattern.test(className))) {
|
|
44540
|
+
if (hasInteractiveContent(el)) {
|
|
44541
|
+
enrichAsDialog(el);
|
|
44542
|
+
}
|
|
44543
|
+
}
|
|
44544
|
+
}
|
|
44545
|
+
}
|
|
44546
|
+
if (count < MAX_ENRICHMENTS) {
|
|
44547
|
+
const allFixed = document.querySelectorAll("*");
|
|
44548
|
+
for (const el of allFixed) {
|
|
44549
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44550
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
44551
|
+
const style = window.getComputedStyle(el);
|
|
44552
|
+
if (style.position !== "fixed" && style.position !== "absolute") continue;
|
|
44553
|
+
const rect = el.getBoundingClientRect();
|
|
44554
|
+
const viewportW = window.innerWidth;
|
|
44555
|
+
const viewportH = window.innerHeight;
|
|
44556
|
+
const coversViewport = rect.width >= viewportW * 0.8 && rect.height >= viewportH * 0.8;
|
|
44557
|
+
if (!coversViewport) continue;
|
|
44558
|
+
const bg = style.backgroundColor;
|
|
44559
|
+
const opacity = parseFloat(style.opacity);
|
|
44560
|
+
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;
|
|
44561
|
+
if (!isSemiTransparent) continue;
|
|
44562
|
+
const nextSib = el.nextElementSibling;
|
|
44563
|
+
if (nextSib && nextSib instanceof HTMLElement && isVisible(nextSib) && hasInteractiveContent(nextSib)) {
|
|
44564
|
+
enrichAsDialog(nextSib);
|
|
44565
|
+
continue;
|
|
44566
|
+
}
|
|
44567
|
+
if (el.parentElement) {
|
|
44568
|
+
const backdropZ = parseInt(style.zIndex) || 0;
|
|
44569
|
+
for (const sibling of el.parentElement.children) {
|
|
44570
|
+
if (sibling === el || !(sibling instanceof HTMLElement)) continue;
|
|
44571
|
+
const sibStyle = window.getComputedStyle(sibling);
|
|
44572
|
+
const sibZ = parseInt(sibStyle.zIndex) || 0;
|
|
44573
|
+
if (sibZ > backdropZ && isVisible(sibling) && hasInteractiveContent(sibling)) {
|
|
44574
|
+
enrichAsDialog(sibling);
|
|
44575
|
+
break;
|
|
44576
|
+
}
|
|
44577
|
+
}
|
|
44578
|
+
}
|
|
44579
|
+
}
|
|
44580
|
+
}
|
|
44581
|
+
if (count < MAX_ENRICHMENTS) {
|
|
44582
|
+
const allElements = document.querySelectorAll("*");
|
|
44583
|
+
for (const el of allElements) {
|
|
44584
|
+
if (count >= MAX_ENRICHMENTS) break;
|
|
44585
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
44586
|
+
if (el.getAttribute("data-enriched-dialog") === "true") continue;
|
|
44587
|
+
if (el.getAttribute("role") === "dialog" || el.getAttribute("role") === "alertdialog") continue;
|
|
44588
|
+
const style = window.getComputedStyle(el);
|
|
44589
|
+
if (style.position !== "fixed" && style.position !== "absolute") continue;
|
|
44590
|
+
const zIndex = parseInt(style.zIndex) || 0;
|
|
44591
|
+
if (zIndex <= 100) continue;
|
|
44592
|
+
if (!isVisible(el)) continue;
|
|
44593
|
+
const rect = el.getBoundingClientRect();
|
|
44594
|
+
if (rect.width < 200 || rect.height < 200) continue;
|
|
44595
|
+
const viewportW = window.innerWidth;
|
|
44596
|
+
const viewportH = window.innerHeight;
|
|
44597
|
+
if (rect.width >= viewportW * 0.95 && rect.height >= viewportH * 0.95) continue;
|
|
44598
|
+
if (hasInteractiveContent(el)) {
|
|
44599
|
+
enrichAsDialog(el);
|
|
44600
|
+
}
|
|
44601
|
+
}
|
|
44602
|
+
}
|
|
44603
|
+
return count;
|
|
44604
|
+
});
|
|
44605
|
+
if (enrichedCount > 0) {
|
|
44606
|
+
logger2.debug("[DirectPlaywright] Enriched modal dialog elements", {
|
|
44607
|
+
count: enrichedCount
|
|
44608
|
+
});
|
|
44609
|
+
}
|
|
44610
|
+
} catch (err) {
|
|
44611
|
+
logger2.debug("[DirectPlaywright] Modal dialog enrichment failed", {
|
|
44612
|
+
error: errorMessage2(err)
|
|
44613
|
+
});
|
|
44614
|
+
}
|
|
44615
|
+
}
|
|
43597
44616
|
async function enrichInteractiveSVGElements(page, logger2) {
|
|
43598
44617
|
try {
|
|
43599
44618
|
const enrichedCount = await page.evaluate(() => {
|
|
@@ -43989,7 +45008,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43989
45008
|
extensions,
|
|
43990
45009
|
highlightInteractions,
|
|
43991
45010
|
cursorOverlay,
|
|
43992
|
-
extraHTTPHeaders
|
|
45011
|
+
extraHTTPHeaders,
|
|
45012
|
+
httpCredentials
|
|
43993
45013
|
} = options;
|
|
43994
45014
|
const resolvedBrowserMode = browserMode ?? "headless";
|
|
43995
45015
|
const resolvedViewport = viewport ?? DEFAULT_VIEWPORT;
|
|
@@ -44002,7 +45022,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44002
45022
|
extensions,
|
|
44003
45023
|
highlightInteractions,
|
|
44004
45024
|
cursorOverlay,
|
|
44005
|
-
extraHTTPHeaders
|
|
45025
|
+
extraHTTPHeaders,
|
|
45026
|
+
httpCredentials
|
|
44006
45027
|
};
|
|
44007
45028
|
this.storageStatePath = storageStatePath;
|
|
44008
45029
|
this.pageClosedIntentionally = false;
|
|
@@ -44075,6 +45096,9 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44075
45096
|
if (extraHTTPHeaders && Object.keys(extraHTTPHeaders).length > 0) {
|
|
44076
45097
|
contextOptions.extraHTTPHeaders = extraHTTPHeaders;
|
|
44077
45098
|
}
|
|
45099
|
+
if (httpCredentials) {
|
|
45100
|
+
contextOptions.httpCredentials = httpCredentials;
|
|
45101
|
+
}
|
|
44078
45102
|
this.logger.info("[DirectPlaywright] Using pooled browser via lease", {
|
|
44079
45103
|
leaseId: this.browserLease.leaseId,
|
|
44080
45104
|
browserId: this.browserLease.browserId
|
|
@@ -44102,7 +45126,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44102
45126
|
recordVideo,
|
|
44103
45127
|
stealth,
|
|
44104
45128
|
extensions,
|
|
44105
|
-
extraHTTPHeaders
|
|
45129
|
+
extraHTTPHeaders,
|
|
45130
|
+
httpCredentials
|
|
44106
45131
|
}),
|
|
44107
45132
|
{
|
|
44108
45133
|
logger: this.logger,
|
|
@@ -44121,6 +45146,9 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44121
45146
|
const initialPageId = this._assignPageId(this.page);
|
|
44122
45147
|
this._pageCreationTimes.set(initialPageId, now);
|
|
44123
45148
|
this._tabFocusLog.push({ pageIndex: initialPageId, timestamp: now });
|
|
45149
|
+
if (storageStatePath) {
|
|
45150
|
+
await this.restoreIndexedDBFromStorageState(storageStatePath);
|
|
45151
|
+
}
|
|
44124
45152
|
this.logger.info("[DirectPlaywright] Browser connected successfully", {
|
|
44125
45153
|
browserMode: resolvedBrowserMode,
|
|
44126
45154
|
stealthEnabled: this.stealthEnabled,
|
|
@@ -44200,6 +45228,13 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44200
45228
|
headerNames: Object.keys(mergedHeaders)
|
|
44201
45229
|
});
|
|
44202
45230
|
}
|
|
45231
|
+
const resolvedHttpCredentials = options.httpCredentials ?? this.lastConnectOptions?.httpCredentials;
|
|
45232
|
+
if (resolvedHttpCredentials) {
|
|
45233
|
+
contextOptions.httpCredentials = resolvedHttpCredentials;
|
|
45234
|
+
if (this.lastConnectOptions) {
|
|
45235
|
+
this.lastConnectOptions.httpCredentials = resolvedHttpCredentials;
|
|
45236
|
+
}
|
|
45237
|
+
}
|
|
44203
45238
|
if (nextStorageStatePath) {
|
|
44204
45239
|
try {
|
|
44205
45240
|
await fs4.access(nextStorageStatePath);
|
|
@@ -44251,6 +45286,9 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44251
45286
|
const swapPageId = this._assignPageId(this.page);
|
|
44252
45287
|
this._pageCreationTimes.set(swapPageId, swapNow);
|
|
44253
45288
|
this._tabFocusLog.push({ pageIndex: swapPageId, timestamp: swapNow });
|
|
45289
|
+
if (nextStorageStatePath) {
|
|
45290
|
+
await this.restoreIndexedDBFromStorageState(nextStorageStatePath);
|
|
45291
|
+
}
|
|
44254
45292
|
if (wasScreencasting && this.page && this.screencastHandler) {
|
|
44255
45293
|
await this.startScreencast(this.screencastHandler);
|
|
44256
45294
|
}
|
|
@@ -44269,7 +45307,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44269
45307
|
recordVideo,
|
|
44270
45308
|
stealth,
|
|
44271
45309
|
extensions,
|
|
44272
|
-
extraHTTPHeaders
|
|
45310
|
+
extraHTTPHeaders,
|
|
45311
|
+
httpCredentials
|
|
44273
45312
|
} = options;
|
|
44274
45313
|
const resolvedViewport = viewport ?? DEFAULT_VIEWPORT;
|
|
44275
45314
|
const useStealthMode = stealth === true || typeof stealth === "object" && stealth.enabled;
|
|
@@ -44300,6 +45339,10 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44300
45339
|
headerNames: Object.keys(extraHTTPHeaders)
|
|
44301
45340
|
});
|
|
44302
45341
|
}
|
|
45342
|
+
if (httpCredentials) {
|
|
45343
|
+
contextOptions.httpCredentials = httpCredentials;
|
|
45344
|
+
this.logger.info("[DirectPlaywright] HTTP Basic Authentication configured");
|
|
45345
|
+
}
|
|
44303
45346
|
if (storageStatePath) {
|
|
44304
45347
|
try {
|
|
44305
45348
|
await fs4.access(storageStatePath);
|
|
@@ -44365,6 +45408,52 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44365
45408
|
);
|
|
44366
45409
|
return { browser, context };
|
|
44367
45410
|
}
|
|
45411
|
+
/**
|
|
45412
|
+
* Read the storage state file, check for IndexedDB data, and restore it.
|
|
45413
|
+
* IndexedDB is origin-scoped, so we navigate to the appropriate origin
|
|
45414
|
+
* before writing data, then navigate back.
|
|
45415
|
+
*/
|
|
45416
|
+
async restoreIndexedDBFromStorageState(storageStatePath) {
|
|
45417
|
+
try {
|
|
45418
|
+
const raw = await fs4.readFile(storageStatePath, "utf-8");
|
|
45419
|
+
const parsed = JSON.parse(raw);
|
|
45420
|
+
if (!parsed.indexedDB || !parsed.indexedDB.databases || parsed.indexedDB.databases.length === 0) {
|
|
45421
|
+
return;
|
|
45422
|
+
}
|
|
45423
|
+
const page = this.page;
|
|
45424
|
+
if (!page || page.isClosed()) return;
|
|
45425
|
+
let targetOrigin = null;
|
|
45426
|
+
if (parsed.origins && parsed.origins.length > 0) {
|
|
45427
|
+
targetOrigin = parsed.origins[0].origin;
|
|
45428
|
+
}
|
|
45429
|
+
if (!targetOrigin) {
|
|
45430
|
+
const cookies = parsed.cookies;
|
|
45431
|
+
if (cookies && cookies.length > 0) {
|
|
45432
|
+
const domain = cookies[0].domain.replace(/^\./, "");
|
|
45433
|
+
targetOrigin = `https://${domain}`;
|
|
45434
|
+
}
|
|
45435
|
+
}
|
|
45436
|
+
if (!targetOrigin) {
|
|
45437
|
+
this.logger.debug("[DirectPlaywright] No origin found for IndexedDB restoration, skipping");
|
|
45438
|
+
return;
|
|
45439
|
+
}
|
|
45440
|
+
this.logger.debug("[DirectPlaywright] Restoring IndexedDB data", {
|
|
45441
|
+
targetOrigin,
|
|
45442
|
+
databaseCount: parsed.indexedDB.databases.length,
|
|
45443
|
+
databaseNames: parsed.indexedDB.databases.map((db) => db.name)
|
|
45444
|
+
});
|
|
45445
|
+
await page.goto(targetOrigin, { waitUntil: "commit", timeout: 15e3 });
|
|
45446
|
+
await restoreIndexedDB(page, parsed.indexedDB);
|
|
45447
|
+
this.logger.info("[DirectPlaywright] IndexedDB data restored successfully", {
|
|
45448
|
+
databaseCount: parsed.indexedDB.databases.length
|
|
45449
|
+
});
|
|
45450
|
+
} catch (err) {
|
|
45451
|
+
this.logger.warn("[DirectPlaywright] Failed to restore IndexedDB from storage state", {
|
|
45452
|
+
error: err instanceof Error ? err.message : String(err),
|
|
45453
|
+
storageStatePath
|
|
45454
|
+
});
|
|
45455
|
+
}
|
|
45456
|
+
}
|
|
44368
45457
|
/**
|
|
44369
45458
|
* Resolve a working Chromium executable path, handling version mismatches
|
|
44370
45459
|
* between the Playwright version bundled in this package and the browser
|
|
@@ -45222,17 +46311,42 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45222
46311
|
const locator = await this.resolveRef(toRef);
|
|
45223
46312
|
const box = await locator.boundingBox();
|
|
45224
46313
|
if (box) {
|
|
46314
|
+
const viewportSize = this.getViewportSize();
|
|
45225
46315
|
const elementCenterY = box.y + box.height / 2;
|
|
45226
|
-
const
|
|
45227
|
-
const viewportCenterY = viewportHeight / 2;
|
|
46316
|
+
const viewportCenterY = viewportSize.height / 2;
|
|
45228
46317
|
const scrollY = elementCenterY - viewportCenterY;
|
|
46318
|
+
const elementCenterX = box.x + box.width / 2;
|
|
46319
|
+
const viewportCenterX = viewportSize.width / 2;
|
|
46320
|
+
const boxRight = box.x + box.width;
|
|
46321
|
+
const needsHorizontalScroll = boxRight < 0 || box.x > viewportSize.width || elementCenterX < 0 || elementCenterX > viewportSize.width;
|
|
46322
|
+
const scrollX = needsHorizontalScroll ? elementCenterX - viewportCenterX : 0;
|
|
45229
46323
|
this.logger.debug("[DirectPlaywright] Scrolling to center element", {
|
|
45230
46324
|
toRef,
|
|
45231
46325
|
elementCenterY,
|
|
45232
46326
|
viewportCenterY,
|
|
45233
|
-
scrollY
|
|
46327
|
+
scrollY,
|
|
46328
|
+
elementCenterX,
|
|
46329
|
+
scrollX,
|
|
46330
|
+
needsHorizontalScroll
|
|
45234
46331
|
});
|
|
45235
|
-
await page.evaluate(`window.scrollBy(
|
|
46332
|
+
await page.evaluate(`window.scrollBy(${scrollX}, ${scrollY})`);
|
|
46333
|
+
if (needsHorizontalScroll) {
|
|
46334
|
+
await page.evaluate((ref) => {
|
|
46335
|
+
const el = document.querySelector(`[aria-ref="${ref}"]`);
|
|
46336
|
+
if (!el) return;
|
|
46337
|
+
let parent = el.parentElement;
|
|
46338
|
+
for (let i = 0; i < 10 && parent; i++) {
|
|
46339
|
+
if (parent.scrollWidth > parent.clientWidth) {
|
|
46340
|
+
const elRect = el.getBoundingClientRect();
|
|
46341
|
+
const parentRect = parent.getBoundingClientRect();
|
|
46342
|
+
const targetScrollLeft = parent.scrollLeft + (elRect.left - parentRect.left) - parentRect.width / 2 + elRect.width / 2;
|
|
46343
|
+
parent.scrollLeft = Math.max(0, targetScrollLeft);
|
|
46344
|
+
break;
|
|
46345
|
+
}
|
|
46346
|
+
parent = parent.parentElement;
|
|
46347
|
+
}
|
|
46348
|
+
}, toRef);
|
|
46349
|
+
}
|
|
45236
46350
|
} else {
|
|
45237
46351
|
this.logger.warn("[DirectPlaywright] No bounding box, using scrollIntoViewIfNeeded", {
|
|
45238
46352
|
toRef
|
|
@@ -45586,7 +46700,25 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45586
46700
|
this.logger.debug("[DirectPlaywright] Getting storage state", {
|
|
45587
46701
|
method: opts?.method ?? "playwright"
|
|
45588
46702
|
});
|
|
45589
|
-
|
|
46703
|
+
const playwrightState = await context.storageState();
|
|
46704
|
+
try {
|
|
46705
|
+
const page = await this.getPage();
|
|
46706
|
+
const indexedDB2 = await extractIndexedDB(page);
|
|
46707
|
+
if (indexedDB2) {
|
|
46708
|
+
this.logger.info("[DirectPlaywright] Extracted IndexedDB data", {
|
|
46709
|
+
databaseCount: indexedDB2.databases.length,
|
|
46710
|
+
databaseNames: indexedDB2.databases.map((db) => db.name)
|
|
46711
|
+
});
|
|
46712
|
+
return { ...playwrightState, indexedDB: indexedDB2 };
|
|
46713
|
+
} else {
|
|
46714
|
+
this.logger.debug("[DirectPlaywright] No IndexedDB databases found on current page");
|
|
46715
|
+
}
|
|
46716
|
+
} catch (err) {
|
|
46717
|
+
this.logger.warn("[DirectPlaywright] Failed to extract IndexedDB, saving without it", {
|
|
46718
|
+
error: err instanceof Error ? err.message : String(err)
|
|
46719
|
+
});
|
|
46720
|
+
}
|
|
46721
|
+
return playwrightState;
|
|
45590
46722
|
}
|
|
45591
46723
|
async getCurrentUrl(_opts) {
|
|
45592
46724
|
return (await this.getPage()).url();
|
|
@@ -45833,6 +46965,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45833
46965
|
}
|
|
45834
46966
|
await this.enrichInteractiveSVGElements(page);
|
|
45835
46967
|
await this.enrichHiddenClickableElements(page);
|
|
46968
|
+
await this.enrichModalDialogElements(page);
|
|
45836
46969
|
let snapshot;
|
|
45837
46970
|
const maxRetries = 3;
|
|
45838
46971
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
@@ -45961,6 +47094,13 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45961
47094
|
async enrichHiddenClickableElements(page) {
|
|
45962
47095
|
await enrichHiddenClickableElements(page, this.logger);
|
|
45963
47096
|
}
|
|
47097
|
+
/**
|
|
47098
|
+
* Enrich positioned overlays that look like modals but lack `role="dialog"`.
|
|
47099
|
+
* Injects `role="dialog"` and `aria-label` so the agent recognizes them.
|
|
47100
|
+
*/
|
|
47101
|
+
async enrichModalDialogElements(page) {
|
|
47102
|
+
await enrichModalDialogElements(page, this.logger);
|
|
47103
|
+
}
|
|
45964
47104
|
/**
|
|
45965
47105
|
* Resolve a ref to a Playwright locator using the internal aria-ref selector.
|
|
45966
47106
|
* This is the same mechanism MCP uses to resolve refs.
|
|
@@ -46993,6 +48133,8 @@ export {
|
|
|
46993
48133
|
CursorOverlay,
|
|
46994
48134
|
setCdpScreencastLogger,
|
|
46995
48135
|
CdpScreencastManager,
|
|
48136
|
+
extractIndexedDB,
|
|
48137
|
+
restoreIndexedDB,
|
|
46996
48138
|
setSnapshotAnalyzerLogger,
|
|
46997
48139
|
extractSnapshotYaml,
|
|
46998
48140
|
parseSnapshot,
|
|
@@ -47007,22 +48149,27 @@ export {
|
|
|
47007
48149
|
normalizeIconLabelText,
|
|
47008
48150
|
normalizeSearchText,
|
|
47009
48151
|
extractDataValue,
|
|
48152
|
+
extractCellText,
|
|
48153
|
+
extractGridCell,
|
|
48154
|
+
reconcileCellColumn,
|
|
48155
|
+
detectGrid,
|
|
48156
|
+
formatGridOutput,
|
|
48157
|
+
formatGridRow,
|
|
47010
48158
|
findRelevanceScope,
|
|
47011
48159
|
searchElements,
|
|
47012
48160
|
populateSearchContext,
|
|
47013
48161
|
sortMatchesByContext,
|
|
47014
|
-
detectGrid,
|
|
47015
|
-
extractCellText,
|
|
47016
|
-
extractGridCell,
|
|
47017
|
-
reconcileCellColumn,
|
|
47018
|
-
findActiveElement,
|
|
47019
48162
|
buildSectionTree,
|
|
47020
48163
|
markMatchingSections,
|
|
48164
|
+
findActiveElement,
|
|
47021
48165
|
formatSemanticSnapshot,
|
|
47022
48166
|
expandSection,
|
|
47023
48167
|
expandSectionOnly,
|
|
47024
|
-
|
|
47025
|
-
|
|
48168
|
+
extractTablesFromSnapshot,
|
|
48169
|
+
gridInfoToRows,
|
|
48170
|
+
formatCSVWithFrontmatter,
|
|
48171
|
+
appendRowsToCSV,
|
|
48172
|
+
detectPaginationInfo,
|
|
47026
48173
|
captureSnapshotState,
|
|
47027
48174
|
compareSnapshots,
|
|
47028
48175
|
hasDiffChanges,
|
|
@@ -47042,6 +48189,7 @@ export {
|
|
|
47042
48189
|
getBrowserToolDefinitions,
|
|
47043
48190
|
BROWSER_LIFECYCLE_TOOLS,
|
|
47044
48191
|
getBrowserToolDefinitionsWithLifecycle,
|
|
48192
|
+
dispatchBrowserTool,
|
|
47045
48193
|
extractSemanticHint,
|
|
47046
48194
|
PlaywrightClient
|
|
47047
48195
|
};
|
|
@@ -47324,4 +48472,4 @@ playwright-extra/dist/index.esm.js:
|
|
|
47324
48472
|
* @license MIT
|
|
47325
48473
|
*)
|
|
47326
48474
|
*/
|
|
47327
|
-
//# sourceMappingURL=chunk-
|
|
48475
|
+
//# sourceMappingURL=chunk-MSMC6UXW.js.map
|