@jobshimo/browser-link 0.35.0 → 0.37.0
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/dist/agent-instructions/content.js +21 -0
- package/dist/agent-instructions/content.js.map +1 -1
- package/dist/cdp/flow.d.ts +36 -3
- package/dist/cdp/flow.js +54 -19
- package/dist/cdp/flow.js.map +1 -1
- package/dist/cdp/inpage/builders.d.ts +152 -20
- package/dist/cdp/inpage/builders.js +365 -77
- package/dist/cdp/inpage/builders.js.map +1 -1
- package/dist/cdp/inpage/observer.d.ts +50 -1
- package/dist/cdp/inpage/observer.js +333 -3
- package/dist/cdp/inpage/observer.js.map +1 -1
- package/dist/cdp/transport.js +91 -9
- package/dist/cdp/transport.js.map +1 -1
- package/dist/extension/background.js +92 -13
- package/dist/extension/background.js.map +1 -1
- package/dist/extension/flow.d.ts +36 -3
- package/dist/extension/flow.js +54 -19
- package/dist/extension/flow.js.map +1 -1
- package/dist/extension/inpage/builders.d.ts +152 -20
- package/dist/extension/inpage/builders.js +365 -77
- package/dist/extension/inpage/builders.js.map +1 -1
- package/dist/extension/inpage/observer.d.ts +50 -1
- package/dist/extension/inpage/observer.js +333 -3
- package/dist/extension/inpage/observer.js.map +1 -1
- package/dist/extension/manifest.json +1 -1
- package/dist/map/queries.d.ts +2 -0
- package/dist/map/queries.js +23 -1
- package/dist/map/queries.js.map +1 -1
- package/dist/map/tools.js +26 -4
- package/dist/map/tools.js.map +1 -1
- package/dist/tools/browser-definitions.js +89 -17
- package/dist/tools/browser-definitions.js.map +1 -1
- package/dist/tools/browser-dispatch.d.ts +19 -26
- package/dist/tools/browser-dispatch.js +166 -16
- package/dist/tools/browser-dispatch.js.map +1 -1
- package/dist/tools/server-instructions.js +21 -0
- package/dist/tools/server-instructions.js.map +1 -1
- package/package.json +1 -1
|
@@ -22,6 +22,99 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { DEEP_QUERY_JS } from './deep-query.js';
|
|
24
24
|
import { DOM_HELPERS_JS } from './dom-helpers.js';
|
|
25
|
+
import { OBSERVER_GLOBAL } from './observer.js';
|
|
26
|
+
/**
|
|
27
|
+
* In-page access to the page observer's element identity (spec v4 §5.6),
|
|
28
|
+
* injected verbatim into `buildSnapshotJs`, `buildFindJs` and `buildStateJs`.
|
|
29
|
+
* The observer global is looked up ONCE per evaluation and used only when it
|
|
30
|
+
* is present, not torn down, and exposes `refFor`:
|
|
31
|
+
* - `refOf(el)` returns the observer's `<doc_tag>:e<N>` ref for `el`, or `null`;
|
|
32
|
+
* - `withDocId(result)` adds `doc_id` to `result` and returns it;
|
|
33
|
+
* - `snapshotStore()` returns the observer when it keeps snapshot records
|
|
34
|
+
* (`recordSnapshot` / `getSnapshot`, used by `snapshot({ since })`), else
|
|
35
|
+
* `null`.
|
|
36
|
+
* Without the observer (injection failed, pre-observer document) all are
|
|
37
|
+
* no-ops, so every result is byte-identical to the pre-ref output.
|
|
38
|
+
*/
|
|
39
|
+
export const PAGE_OBSERVER_JS = `
|
|
40
|
+
const pageObserver = (() => {
|
|
41
|
+
try {
|
|
42
|
+
const g = window[${JSON.stringify(OBSERVER_GLOBAL)}];
|
|
43
|
+
if (g && !g.dead && typeof g.refFor === 'function') return g;
|
|
44
|
+
} catch (e) {}
|
|
45
|
+
return null;
|
|
46
|
+
})();
|
|
47
|
+
function refOf(el) {
|
|
48
|
+
if (!pageObserver) return null;
|
|
49
|
+
try {
|
|
50
|
+
const ref = pageObserver.refFor(el);
|
|
51
|
+
return typeof ref === 'string' ? ref : null;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function withDocId(result) {
|
|
57
|
+
if (pageObserver && typeof pageObserver.doc_id === 'string') result.doc_id = pageObserver.doc_id;
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
function snapshotStore() {
|
|
61
|
+
if (
|
|
62
|
+
pageObserver &&
|
|
63
|
+
typeof pageObserver.recordSnapshot === 'function' &&
|
|
64
|
+
typeof pageObserver.getSnapshot === 'function'
|
|
65
|
+
) {
|
|
66
|
+
return pageObserver;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
/**
|
|
72
|
+
* In-page action-target resolution (spec v4 §6.3), injected after
|
|
73
|
+
* `DEEP_QUERY_JS` and `PAGE_OBSERVER_JS` into the builders that take a
|
|
74
|
+
* `selector` or a `ref` (click, type, focus, element rect, `wait_for` by
|
|
75
|
+
* ref, `find` by ref):
|
|
76
|
+
* `resolveTarget(opts)` with a non-empty `opts.ref` asks the observer
|
|
77
|
+
* (`resolveRefDetailed`, which re-resolves a replaced node by its semantic
|
|
78
|
+
* key) and answers `{ ok: true, el, reresolved }`, `{ ok: false, reason:
|
|
79
|
+
* 'ref-stale', ref, doc_id }` or `{ ok: false, reason: 'observer-unavailable'
|
|
80
|
+
* }`; otherwise it resolves `opts.selector` exactly as the selector builders
|
|
81
|
+
* always did (`invalid-selector` checked against `document` first, then
|
|
82
|
+
* `deepQueryFirst`, `not-found`). Kept out of `PAGE_OBSERVER_JS` so the
|
|
83
|
+
* snapshot and state sources do not carry code they never call.
|
|
84
|
+
*/
|
|
85
|
+
export const RESOLVE_TARGET_JS = `
|
|
86
|
+
function resolveTarget(opts) {
|
|
87
|
+
if (typeof opts.ref === 'string' && opts.ref.length > 0) {
|
|
88
|
+
if (!pageObserver || typeof pageObserver.resolveRefDetailed !== 'function') {
|
|
89
|
+
return { ok: false, reason: 'observer-unavailable' };
|
|
90
|
+
}
|
|
91
|
+
let found = null;
|
|
92
|
+
try {
|
|
93
|
+
found = pageObserver.resolveRefDetailed(opts.ref);
|
|
94
|
+
} catch (e) {
|
|
95
|
+
found = null;
|
|
96
|
+
}
|
|
97
|
+
if (!found || !found.el) return withDocId({ ok: false, reason: 'ref-stale', ref: opts.ref });
|
|
98
|
+
return { ok: true, el: found.el, reresolved: found.reresolved === true };
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
document.querySelector(opts.selector);
|
|
102
|
+
} catch (e) {
|
|
103
|
+
return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
|
|
104
|
+
}
|
|
105
|
+
const el = deepQueryFirst(opts.selector);
|
|
106
|
+
if (!el) return { ok: false, reason: 'not-found' };
|
|
107
|
+
return { ok: true, el: el, reresolved: false };
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
110
|
+
/** JSON for the `selector` / `ref` pair, embedded as data in the built
|
|
111
|
+
* source; `ref` is included only when given so a selector build keeps the
|
|
112
|
+
* same options object as before. */
|
|
113
|
+
function targetJson(opts) {
|
|
114
|
+
return typeof opts.ref === 'string' && opts.ref.length > 0
|
|
115
|
+
? { selector: opts.selector, ref: opts.ref }
|
|
116
|
+
: { selector: opts.selector };
|
|
117
|
+
}
|
|
25
118
|
export function buildSnapshotJs(opts = {}) {
|
|
26
119
|
const optsJson = JSON.stringify({
|
|
27
120
|
withinSelector: typeof opts.within_selector === 'string' ? opts.within_selector : null,
|
|
@@ -30,23 +123,25 @@ export function buildSnapshotJs(opts = {}) {
|
|
|
30
123
|
maxInteractive: typeof opts.max_interactive === 'number' && opts.max_interactive > 0
|
|
31
124
|
? Math.min(opts.max_interactive, 500)
|
|
32
125
|
: 120,
|
|
126
|
+
since: typeof opts.since === 'string' ? opts.since : null,
|
|
33
127
|
});
|
|
34
128
|
return `
|
|
35
129
|
(() => {
|
|
36
130
|
${DEEP_QUERY_JS}
|
|
37
131
|
${DOM_HELPERS_JS}
|
|
132
|
+
${PAGE_OBSERVER_JS}
|
|
38
133
|
const opts = ${optsJson};
|
|
39
134
|
let root = document;
|
|
40
135
|
let notice = '';
|
|
41
136
|
if (opts.withinSelector) {
|
|
42
137
|
const sub = deepQueryFirst(opts.withinSelector);
|
|
43
138
|
if (!sub) {
|
|
44
|
-
return {
|
|
139
|
+
return withDocId({
|
|
45
140
|
title: document.title,
|
|
46
141
|
url: location.href,
|
|
47
142
|
interactive: [],
|
|
48
143
|
notice: 'within_selector did not match any element',
|
|
49
|
-
};
|
|
144
|
+
});
|
|
50
145
|
}
|
|
51
146
|
root = sub;
|
|
52
147
|
}
|
|
@@ -89,6 +184,8 @@ export function buildSnapshotJs(opts = {}) {
|
|
|
89
184
|
const role = el.getAttribute('role') || tag;
|
|
90
185
|
const selInfo = genSelectorInfo(el);
|
|
91
186
|
const entry = { tag, role, selector: selInfo.selector };
|
|
187
|
+
const ref = refOf(el);
|
|
188
|
+
if (ref) entry.ref = ref;
|
|
92
189
|
if (selInfo.ambiguous) entry.ambiguous = true;
|
|
93
190
|
const txt = shortText(el);
|
|
94
191
|
if (txt) entry.text = txt;
|
|
@@ -108,29 +205,118 @@ export function buildSnapshotJs(opts = {}) {
|
|
|
108
205
|
if (frame) entry.frame = frame;
|
|
109
206
|
interactive.push(entry);
|
|
110
207
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
url: location.href,
|
|
114
|
-
interactive: interactive.slice(0, opts.maxInteractive),
|
|
115
|
-
};
|
|
208
|
+
let headings = null;
|
|
209
|
+
let visibleText = '';
|
|
116
210
|
if (!opts.onlyInteractive) {
|
|
117
|
-
const
|
|
211
|
+
const found = [];
|
|
118
212
|
deepQueryAll('h1, h2, h3', root).forEach((h) => {
|
|
119
213
|
if (!isVisible(h)) return;
|
|
120
214
|
if (inExcludedLandmark(h)) return;
|
|
121
215
|
const t = shortText(h);
|
|
122
|
-
if (t)
|
|
216
|
+
if (t) found.push({ level: h.tagName, text: t });
|
|
123
217
|
});
|
|
124
|
-
|
|
218
|
+
headings = found.slice(0, 30);
|
|
125
219
|
const textRoot = (root === document) ? (document.body || document) : root;
|
|
126
|
-
|
|
220
|
+
visibleText = (textRoot && textRoot.innerText) ? textRoot.innerText.slice(0, 4000) : '';
|
|
221
|
+
}
|
|
222
|
+
let snapshotId = null;
|
|
223
|
+
if (withDocId({}).doc_id && typeof pageObserver.nextSnapshotId === 'function') {
|
|
224
|
+
const issued = pageObserver.nextSnapshotId();
|
|
225
|
+
if (typeof issued === 'string') snapshotId = issued;
|
|
226
|
+
}
|
|
227
|
+
function fullResult() {
|
|
228
|
+
const result = {
|
|
229
|
+
title: document.title,
|
|
230
|
+
url: location.href,
|
|
231
|
+
interactive: interactive.slice(0, opts.maxInteractive),
|
|
232
|
+
};
|
|
233
|
+
if (headings) result.headings = headings;
|
|
127
234
|
if (visibleText) result.text = visibleText;
|
|
235
|
+
if (notice) result.notice = notice;
|
|
236
|
+
withDocId(result);
|
|
237
|
+
if (snapshotId) result.snapshot_id = snapshotId;
|
|
238
|
+
return result;
|
|
128
239
|
}
|
|
129
|
-
|
|
130
|
-
|
|
240
|
+
// Record every snapshot (with or without since) so a later call can diff
|
|
241
|
+
// against it. Entries are keyed by ref; the hash is the entry serialised
|
|
242
|
+
// without its ref, in emission order. Capped at the first 500 entries.
|
|
243
|
+
const store = snapshotId ? snapshotStore() : null;
|
|
244
|
+
// A snapshot_id is \`<doc_id>:s<N>\`: a since whose prefix (before the LAST
|
|
245
|
+
// ':') is not this document's doc_id, or that has no ':', came from another
|
|
246
|
+
// document and is never looked up.
|
|
247
|
+
const sinceCut = opts.since === null ? -1 : opts.since.lastIndexOf(':');
|
|
248
|
+
const sinceSameDoc =
|
|
249
|
+
sinceCut >= 0 && withDocId({}).doc_id === opts.since.slice(0, sinceCut);
|
|
250
|
+
const previous = store && sinceSameDoc ? store.getSnapshot(opts.since) : null;
|
|
251
|
+
const current = new Map();
|
|
252
|
+
const headingsHash = headings ? JSON.stringify(headings) : null;
|
|
253
|
+
const textHash = opts.onlyInteractive ? null : visibleText;
|
|
254
|
+
if (store) {
|
|
255
|
+
for (const entry of interactive) {
|
|
256
|
+
if (current.size >= 500) break;
|
|
257
|
+
if (typeof entry.ref !== 'string') continue;
|
|
258
|
+
const copy = {};
|
|
259
|
+
for (const key of Object.keys(entry)) if (key !== 'ref') copy[key] = entry[key];
|
|
260
|
+
current.set(entry.ref, { hash: JSON.stringify(copy), entry });
|
|
261
|
+
}
|
|
262
|
+
store.recordSnapshot(snapshotId, { entries: current, headings_hash: headingsHash, text_hash: textHash });
|
|
263
|
+
}
|
|
264
|
+
if (opts.since === null) return fullResult();
|
|
265
|
+
if (!store) {
|
|
266
|
+
const result = fullResult();
|
|
267
|
+
result.since = opts.since;
|
|
268
|
+
result.since_status = 'observer-unavailable';
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
if (!previous || !previous.entries || typeof previous.entries.get !== 'function') {
|
|
272
|
+
const result = fullResult();
|
|
273
|
+
result.since = opts.since;
|
|
274
|
+
result.since_status = sinceSameDoc ? 'evicted' : 'doc-changed';
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
277
|
+
const added = [];
|
|
278
|
+
const changed = [];
|
|
279
|
+
const removed = [];
|
|
280
|
+
current.forEach((item, ref) => {
|
|
281
|
+
const old = previous.entries.get(ref);
|
|
282
|
+
if (!old) added.push(item.entry);
|
|
283
|
+
else if (old.hash !== item.hash) changed.push(item.entry);
|
|
284
|
+
});
|
|
285
|
+
previous.entries.forEach((item, ref) => {
|
|
286
|
+
if (current.has(ref) || removed.length >= 500) return;
|
|
287
|
+
const gone = { ref, tag: item.entry.tag };
|
|
288
|
+
if (item.entry.text) gone.text = item.entry.text;
|
|
289
|
+
removed.push(gone);
|
|
290
|
+
});
|
|
291
|
+
// max_interactive applies after diffing (added first, then changed), so
|
|
292
|
+
// a window shift never masquerades as change.
|
|
293
|
+
const listed = added.concat(changed);
|
|
294
|
+
const kept = listed.slice(0, opts.maxInteractive);
|
|
295
|
+
const diff = withDocId({ title: document.title, url: location.href });
|
|
296
|
+
diff.snapshot_id = snapshotId;
|
|
297
|
+
diff.since = opts.since;
|
|
298
|
+
diff.added = kept.slice(0, Math.min(added.length, kept.length));
|
|
299
|
+
diff.removed = removed;
|
|
300
|
+
diff.changed = kept.slice(diff.added.length);
|
|
301
|
+
if (listed.length > kept.length) diff.overflow = listed.length - kept.length;
|
|
302
|
+
if (!opts.onlyInteractive) {
|
|
303
|
+
if (headingsHash !== previous.headings_hash) diff.headings = headings;
|
|
304
|
+
if (textHash !== previous.text_hash) diff.text = visibleText;
|
|
305
|
+
}
|
|
306
|
+
return diff;
|
|
131
307
|
})()
|
|
132
308
|
`;
|
|
133
309
|
}
|
|
310
|
+
/** Only the documented key fields reach the built source, as JSON data. */
|
|
311
|
+
function findKeyJson(key) {
|
|
312
|
+
return Array.isArray(key.path)
|
|
313
|
+
? {
|
|
314
|
+
role: key.role,
|
|
315
|
+
name: key.name,
|
|
316
|
+
path: key.path.map((step) => ({ tag: step.tag, index: step.index })),
|
|
317
|
+
}
|
|
318
|
+
: { role: key.role, name: key.name };
|
|
319
|
+
}
|
|
134
320
|
export function buildFindJs(opts) {
|
|
135
321
|
const optsJson = JSON.stringify({
|
|
136
322
|
text: opts.text,
|
|
@@ -138,12 +324,98 @@ export function buildFindJs(opts) {
|
|
|
138
324
|
exact: opts.exact === true,
|
|
139
325
|
candidateLimit: 5,
|
|
140
326
|
nearMissLimit: 3,
|
|
327
|
+
...(typeof opts.ref === 'string' && opts.ref.length > 0 ? { ref: opts.ref } : {}),
|
|
328
|
+
...(opts.key ? { key: findKeyJson(opts.key) } : {}),
|
|
141
329
|
});
|
|
142
330
|
return `
|
|
143
331
|
(() => {
|
|
144
332
|
${DEEP_QUERY_JS}
|
|
145
333
|
${DOM_HELPERS_JS}
|
|
334
|
+
${PAGE_OBSERVER_JS}
|
|
335
|
+
${typeof opts.ref === 'string' && opts.ref.length > 0 ? RESOLVE_TARGET_JS : ''}
|
|
146
336
|
const opts = ${optsJson};
|
|
337
|
+
function semanticKeyOf(el) {
|
|
338
|
+
if (!pageObserver || typeof pageObserver.semanticKeyFor !== 'function') return null;
|
|
339
|
+
try {
|
|
340
|
+
const key = pageObserver.semanticKeyFor(el);
|
|
341
|
+
return key && typeof key === 'object' ? key : null;
|
|
342
|
+
} catch (e) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function singleMatch(el, ref, reresolved) {
|
|
347
|
+
const center = viewportCenterOf(el);
|
|
348
|
+
const selInfo = genSelectorInfo(el);
|
|
349
|
+
const result = { matched: true, selector: selInfo.selector };
|
|
350
|
+
if (ref) result.ref = ref;
|
|
351
|
+
result.coords = {
|
|
352
|
+
x: Math.round(center.x),
|
|
353
|
+
y: Math.round(center.y),
|
|
354
|
+
};
|
|
355
|
+
result.tag = el.tagName.toLowerCase();
|
|
356
|
+
result.text = shortText(el);
|
|
357
|
+
if (selInfo.ambiguous) result.ambiguous = true;
|
|
358
|
+
const frame = frameSelectorFor(el);
|
|
359
|
+
if (frame) result.frame = frame;
|
|
360
|
+
if (reresolved) result.reresolved = true;
|
|
361
|
+
const key = semanticKeyOf(el);
|
|
362
|
+
if (key) result.semantic_key = key;
|
|
363
|
+
return withDocId(result);
|
|
364
|
+
}
|
|
365
|
+
if (typeof opts.ref === 'string') {
|
|
366
|
+
const target = resolveTarget(opts);
|
|
367
|
+
if (!target.ok) {
|
|
368
|
+
const failure = { matched: false, reason: target.reason, ref: opts.ref };
|
|
369
|
+
return withDocId(failure);
|
|
370
|
+
}
|
|
371
|
+
return singleMatch(target.el, opts.ref, target.reresolved);
|
|
372
|
+
}
|
|
373
|
+
if (opts.key) {
|
|
374
|
+
if (!pageObserver || typeof pageObserver.semanticKeyFor !== 'function') {
|
|
375
|
+
return { matched: false, reason: 'observer-unavailable' };
|
|
376
|
+
}
|
|
377
|
+
const wanted = opts.key;
|
|
378
|
+
const candidates = [];
|
|
379
|
+
for (const el of deepQueryAll('*')) {
|
|
380
|
+
const key = semanticKeyOf(el);
|
|
381
|
+
if (key && key.role === wanted.role && key.name === wanted.name) {
|
|
382
|
+
candidates.push({ el: el, path: Array.isArray(key.path) ? key.path : [] });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const count = candidates.length;
|
|
386
|
+
const shared = 'key: ' + count + ' candidates share role and name; ';
|
|
387
|
+
let picked = null;
|
|
388
|
+
let error = count > 1 ? shared + 'pass path to disambiguate' : null;
|
|
389
|
+
if (!Array.isArray(wanted.path)) {
|
|
390
|
+
if (count === 1) picked = candidates[0].el;
|
|
391
|
+
} else {
|
|
392
|
+
// Same rule as the observer's re-resolution: identical tag path and
|
|
393
|
+
// exactly one such candidate; identical rows are refused, never guessed.
|
|
394
|
+
let sameTags = 0;
|
|
395
|
+
let only = null;
|
|
396
|
+
for (const c of candidates) {
|
|
397
|
+
if (c.path.length !== wanted.path.length) continue;
|
|
398
|
+
let same = true;
|
|
399
|
+
for (let i = 0; i < c.path.length && same; i++) {
|
|
400
|
+
if (c.path[i].tag !== wanted.path[i].tag) same = false;
|
|
401
|
+
}
|
|
402
|
+
if (!same) continue;
|
|
403
|
+
sameTags++;
|
|
404
|
+
only = c.el;
|
|
405
|
+
}
|
|
406
|
+
if (sameTags === 1) {
|
|
407
|
+
picked = only;
|
|
408
|
+
} else if (sameTags > 1) {
|
|
409
|
+
error = 'key: ' + sameTags + ' candidates share role, name and tag path';
|
|
410
|
+
} else if (count > 0) {
|
|
411
|
+
error = shared + 'none has the same tag path';
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (picked) return singleMatch(picked, refOf(picked), false);
|
|
415
|
+
const failure = { matched: false, reason: 'not-found' };
|
|
416
|
+
if (error) failure.error = error;
|
|
417
|
+
return withDocId(failure);
|
|
418
|
+
}
|
|
147
419
|
const needle = opts.text.toLowerCase();
|
|
148
420
|
const needleTokens = needle.split(/[^a-z0-9]+/).filter(Boolean);
|
|
149
421
|
const ROLE_SELECTORS = {
|
|
@@ -203,6 +475,8 @@ export function buildFindJs(opts) {
|
|
|
203
475
|
}
|
|
204
476
|
function toNearMiss(el) {
|
|
205
477
|
const entry = { text: snippetOf(el), selector: genSelector(el) };
|
|
478
|
+
const ref = refOf(el);
|
|
479
|
+
if (ref) entry.ref = ref;
|
|
206
480
|
const roleAttr = el.getAttribute('role');
|
|
207
481
|
if (roleAttr) entry.role = roleAttr;
|
|
208
482
|
return entry;
|
|
@@ -235,60 +509,46 @@ export function buildFindJs(opts) {
|
|
|
235
509
|
' but none with role "' + opts.role + '"' +
|
|
236
510
|
(closest ? ' — closest: ' + describeForError(closest) + ' "' + snippetOf(closest) + '"' : '');
|
|
237
511
|
result.near_misses = ranked.map(toNearMiss);
|
|
238
|
-
return result;
|
|
512
|
+
return withDocId(result);
|
|
239
513
|
}
|
|
240
514
|
const ranked = rankCandidates(broadAll);
|
|
241
515
|
if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
|
|
242
|
-
return result;
|
|
516
|
+
return withDocId(result);
|
|
243
517
|
}
|
|
244
518
|
const ranked = rankCandidates(all);
|
|
245
519
|
if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
|
|
246
|
-
return result;
|
|
520
|
+
return withDocId(result);
|
|
247
521
|
}
|
|
248
522
|
if (matches.length > 1) {
|
|
249
|
-
return {
|
|
523
|
+
return withDocId({
|
|
250
524
|
matched: false,
|
|
251
525
|
reason: 'multiple-matches',
|
|
252
|
-
candidates: matches.slice(0, opts.candidateLimit).map((el) =>
|
|
253
|
-
selector: genSelector(el)
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
526
|
+
candidates: matches.slice(0, opts.candidateLimit).map((el) => {
|
|
527
|
+
const candidate = { selector: genSelector(el) };
|
|
528
|
+
const ref = refOf(el);
|
|
529
|
+
if (ref) candidate.ref = ref;
|
|
530
|
+
candidate.text = shortText(el);
|
|
531
|
+
candidate.tag = el.tagName.toLowerCase();
|
|
532
|
+
return candidate;
|
|
533
|
+
}),
|
|
534
|
+
});
|
|
258
535
|
}
|
|
259
536
|
const el = matches[0];
|
|
260
|
-
|
|
261
|
-
const selInfo = genSelectorInfo(el);
|
|
262
|
-
const result = {
|
|
263
|
-
matched: true,
|
|
264
|
-
selector: selInfo.selector,
|
|
265
|
-
coords: {
|
|
266
|
-
x: Math.round(center.x),
|
|
267
|
-
y: Math.round(center.y),
|
|
268
|
-
},
|
|
269
|
-
tag: el.tagName.toLowerCase(),
|
|
270
|
-
text: shortText(el),
|
|
271
|
-
};
|
|
272
|
-
if (selInfo.ambiguous) result.ambiguous = true;
|
|
273
|
-
const frame = frameSelectorFor(el);
|
|
274
|
-
if (frame) result.frame = frame;
|
|
275
|
-
return result;
|
|
537
|
+
return singleMatch(el, refOf(el), false);
|
|
276
538
|
})()
|
|
277
539
|
`;
|
|
278
540
|
}
|
|
279
541
|
export function buildClickResolveJs(opts) {
|
|
280
|
-
const optsJson = JSON.stringify({
|
|
542
|
+
const optsJson = JSON.stringify({ ...targetJson(opts), force: opts.force });
|
|
281
543
|
return `
|
|
282
544
|
(() => {
|
|
283
545
|
${DEEP_QUERY_JS}
|
|
546
|
+
${PAGE_OBSERVER_JS}
|
|
547
|
+
${RESOLVE_TARGET_JS}
|
|
284
548
|
const opts = ${optsJson};
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
|
|
289
|
-
}
|
|
290
|
-
const el = deepQueryFirst(opts.selector);
|
|
291
|
-
if (!el) return { ok: false, reason: 'not-found' };
|
|
549
|
+
const target = resolveTarget(opts);
|
|
550
|
+
if (!target.ok) return target;
|
|
551
|
+
const el = target.el;
|
|
292
552
|
const chain = frameElementChain(el);
|
|
293
553
|
for (const fe of chain) {
|
|
294
554
|
if (fe.scrollIntoView) fe.scrollIntoView({ block: 'center', inline: 'center' });
|
|
@@ -303,41 +563,59 @@ export function buildClickResolveJs(opts) {
|
|
|
303
563
|
const result = { ok: true, x: center.x, y: center.y, tag };
|
|
304
564
|
const hit = occlusion.allowed ? occlusion.hit : occlusion.blocker;
|
|
305
565
|
if (hit) result.hit_element = hit;
|
|
566
|
+
if (target.reresolved) result.reresolved = true;
|
|
306
567
|
return result;
|
|
307
568
|
})()
|
|
308
569
|
`;
|
|
309
570
|
}
|
|
310
571
|
export function buildTypeResolveJs(opts) {
|
|
311
|
-
const optsJson = JSON.stringify(
|
|
572
|
+
const optsJson = JSON.stringify(targetJson(opts));
|
|
312
573
|
return `
|
|
313
574
|
(() => {
|
|
314
575
|
${DEEP_QUERY_JS}
|
|
576
|
+
${PAGE_OBSERVER_JS}
|
|
577
|
+
${RESOLVE_TARGET_JS}
|
|
315
578
|
const opts = ${optsJson};
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
|
|
320
|
-
}
|
|
321
|
-
const el = deepQueryFirst(opts.selector);
|
|
322
|
-
if (!el) return { ok: false, reason: 'not-found' };
|
|
579
|
+
const target = resolveTarget(opts);
|
|
580
|
+
if (!target.ok) return target;
|
|
581
|
+
const el = target.el;
|
|
323
582
|
el.focus();
|
|
324
583
|
${opts.clear ? "if ('value' in el) { el.value = ''; el.dispatchEvent(new Event('input', { bubbles: true })); }" : ''}
|
|
325
|
-
return { ok: true };
|
|
584
|
+
return target.reresolved ? { ok: true, reresolved: true } : { ok: true };
|
|
326
585
|
})()`;
|
|
327
586
|
}
|
|
328
587
|
export function buildFocusJs(opts) {
|
|
329
|
-
const optsJson = JSON.stringify(
|
|
588
|
+
const optsJson = JSON.stringify(targetJson(opts));
|
|
330
589
|
return `
|
|
331
590
|
(() => {
|
|
332
591
|
${DEEP_QUERY_JS}
|
|
592
|
+
${PAGE_OBSERVER_JS}
|
|
593
|
+
${RESOLVE_TARGET_JS}
|
|
333
594
|
const opts = ${optsJson};
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
595
|
+
const target = resolveTarget(opts);
|
|
596
|
+
const byRef = typeof opts.ref === 'string';
|
|
597
|
+
if (!target.ok) return byRef ? target : false;
|
|
598
|
+
target.el.focus();
|
|
599
|
+
if (!byRef) return true;
|
|
600
|
+
return target.reresolved ? { ok: true, reresolved: true } : { ok: true };
|
|
338
601
|
})()`;
|
|
339
602
|
}
|
|
340
|
-
export function buildWaitForSelectorJs(
|
|
603
|
+
export function buildWaitForSelectorJs(target, condition) {
|
|
604
|
+
if (typeof target !== 'string') {
|
|
605
|
+
const refOptsJson = JSON.stringify({ ref: target.ref, condition });
|
|
606
|
+
return `
|
|
607
|
+
(() => {
|
|
608
|
+
${DEEP_QUERY_JS}
|
|
609
|
+
${PAGE_OBSERVER_JS}
|
|
610
|
+
${RESOLVE_TARGET_JS}
|
|
611
|
+
const opts = ${refOptsJson};
|
|
612
|
+
const target = resolveTarget(opts);
|
|
613
|
+
if (!target.ok && target.reason === 'observer-unavailable') return target;
|
|
614
|
+
const el = target.ok ? target.el : null;
|
|
615
|
+
${WAIT_FOR_CONDITION_JS}
|
|
616
|
+
})()`;
|
|
617
|
+
}
|
|
618
|
+
const selector = target;
|
|
341
619
|
const optsJson = JSON.stringify({ selector, condition });
|
|
342
620
|
return `
|
|
343
621
|
(() => {
|
|
@@ -345,7 +623,12 @@ export function buildWaitForSelectorJs(selector, condition) {
|
|
|
345
623
|
const opts = ${optsJson};
|
|
346
624
|
document.querySelector(opts.selector);
|
|
347
625
|
const el = deepQueryFirst(opts.selector);
|
|
348
|
-
|
|
626
|
+
${WAIT_FOR_CONDITION_JS}
|
|
627
|
+
})()`;
|
|
628
|
+
}
|
|
629
|
+
/** The condition check shared by both `wait_for` probe targets; `el` is
|
|
630
|
+
* the resolved element or `null`. */
|
|
631
|
+
const WAIT_FOR_CONDITION_JS = `if (opts.condition === 'attached') return Boolean(el);
|
|
349
632
|
if (opts.condition === 'detached') return !el;
|
|
350
633
|
const wantHidden = opts.condition === 'hidden';
|
|
351
634
|
if (!el) return wantHidden;
|
|
@@ -354,22 +637,18 @@ export function buildWaitForSelectorJs(selector, condition) {
|
|
|
354
637
|
if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return wantHidden;
|
|
355
638
|
const r = el.getBoundingClientRect();
|
|
356
639
|
const shown = r.width > 0 && r.height > 0;
|
|
357
|
-
return wantHidden ? !shown : shown
|
|
358
|
-
})()`;
|
|
359
|
-
}
|
|
640
|
+
return wantHidden ? !shown : shown;`;
|
|
360
641
|
export function buildElementRectJs(opts) {
|
|
361
|
-
const optsJson = JSON.stringify(
|
|
642
|
+
const optsJson = JSON.stringify(targetJson(opts));
|
|
362
643
|
return `
|
|
363
644
|
(() => {
|
|
364
645
|
${DEEP_QUERY_JS}
|
|
646
|
+
${PAGE_OBSERVER_JS}
|
|
647
|
+
${RESOLVE_TARGET_JS}
|
|
365
648
|
const opts = ${optsJson};
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
|
|
370
|
-
}
|
|
371
|
-
const el = deepQueryFirst(opts.selector);
|
|
372
|
-
if (!el) return { ok: false, reason: 'not-found' };
|
|
649
|
+
const target = resolveTarget(opts);
|
|
650
|
+
if (!target.ok) return target;
|
|
651
|
+
const el = target.el;
|
|
373
652
|
const chain = frameElementChain(el);
|
|
374
653
|
// behavior 'instant' overrides CSS scroll-behavior: smooth, which would
|
|
375
654
|
// leave the rect below stale while the scroll is still animating.
|
|
@@ -394,13 +673,15 @@ export function buildElementRectJs(opts) {
|
|
|
394
673
|
scrollX = top.scrollX || 0;
|
|
395
674
|
scrollY = top.scrollY || 0;
|
|
396
675
|
} catch (_) {}
|
|
397
|
-
|
|
676
|
+
const result = {
|
|
398
677
|
ok: true,
|
|
399
678
|
x: offsetX + rect.left + scrollX,
|
|
400
679
|
y: offsetY + rect.top + scrollY,
|
|
401
680
|
width: rect.width,
|
|
402
681
|
height: rect.height,
|
|
403
682
|
};
|
|
683
|
+
if (target.reresolved) result.reresolved = true;
|
|
684
|
+
return result;
|
|
404
685
|
})()`;
|
|
405
686
|
}
|
|
406
687
|
export function buildSettleJs(opts) {
|
|
@@ -569,12 +850,16 @@ export function buildExpectProbeJs(opts) {
|
|
|
569
850
|
* `focused` beyond `<body>`, no `dialogs` when none are open, and no
|
|
570
851
|
* `scroll` when the page is at its default (0,0) position — token-lean by
|
|
571
852
|
* construction, matching the omit-falsy convention the other builders use.
|
|
853
|
+
*
|
|
854
|
+
* With the page observer installed (see `PAGE_OBSERVER_JS`), `focused`
|
|
855
|
+
* carries `ref` right after `selector` and the result carries `doc_id`.
|
|
572
856
|
*/
|
|
573
857
|
export function buildStateJs() {
|
|
574
858
|
return `
|
|
575
859
|
(() => {
|
|
576
860
|
${DEEP_QUERY_JS}
|
|
577
861
|
${DOM_HELPERS_JS}
|
|
862
|
+
${PAGE_OBSERVER_JS}
|
|
578
863
|
function deepActiveElement() {
|
|
579
864
|
let el = document.activeElement;
|
|
580
865
|
let guard = 0;
|
|
@@ -635,7 +920,10 @@ export function buildStateJs() {
|
|
|
635
920
|
const active = deepActiveElement();
|
|
636
921
|
if (active && active !== document.body && active.tagName) {
|
|
637
922
|
const selInfo = genSelectorInfo(active);
|
|
638
|
-
const focused = { selector: selInfo.selector
|
|
923
|
+
const focused = { selector: selInfo.selector };
|
|
924
|
+
const ref = refOf(active);
|
|
925
|
+
if (ref) focused.ref = ref;
|
|
926
|
+
focused.tag = active.tagName.toLowerCase();
|
|
639
927
|
if (selInfo.ambiguous) focused.ambiguous = true;
|
|
640
928
|
result.focused = focused;
|
|
641
929
|
}
|
|
@@ -655,7 +943,7 @@ export function buildStateJs() {
|
|
|
655
943
|
const scrollY = Math.round(window.scrollY);
|
|
656
944
|
if (scrollX !== 0 || scrollY !== 0) result.scroll = { x: scrollX, y: scrollY };
|
|
657
945
|
|
|
658
|
-
return result;
|
|
946
|
+
return withDocId(result);
|
|
659
947
|
})()
|
|
660
948
|
`;
|
|
661
949
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builders.js","sourceRoot":"","sources":["../../../src/cdp/inpage/builders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"builders.js","sourceRoot":"","sources":["../../../src/cdp/inpage/builders.ts"],"names":[],"mappings":"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"}
|