@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
|
@@ -8,6 +8,99 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { DEEP_QUERY_JS } from './deep-query.js';
|
|
10
10
|
import { DOM_HELPERS_JS } from './dom-helpers.js';
|
|
11
|
+
import { OBSERVER_GLOBAL } from './observer.js';
|
|
12
|
+
/**
|
|
13
|
+
* In-page access to the page observer's element identity (spec v4 §5.6),
|
|
14
|
+
* injected verbatim into `buildSnapshotJs`, `buildFindJs` and `buildStateJs`.
|
|
15
|
+
* The observer global is looked up ONCE per evaluation and used only when it
|
|
16
|
+
* is present, not torn down, and exposes `refFor`:
|
|
17
|
+
* - `refOf(el)` returns the observer's `<doc_tag>:e<N>` ref for `el`, or `null`;
|
|
18
|
+
* - `withDocId(result)` adds `doc_id` to `result` and returns it;
|
|
19
|
+
* - `snapshotStore()` returns the observer when it keeps snapshot records
|
|
20
|
+
* (`recordSnapshot` / `getSnapshot`, used by `snapshot({ since })`), else
|
|
21
|
+
* `null`.
|
|
22
|
+
* Without the observer (injection failed, pre-observer document) all are
|
|
23
|
+
* no-ops, so every result is byte-identical to the pre-ref output.
|
|
24
|
+
*/
|
|
25
|
+
export const PAGE_OBSERVER_JS = `
|
|
26
|
+
const pageObserver = (() => {
|
|
27
|
+
try {
|
|
28
|
+
const g = window[${JSON.stringify(OBSERVER_GLOBAL)}];
|
|
29
|
+
if (g && !g.dead && typeof g.refFor === 'function') return g;
|
|
30
|
+
} catch (e) {}
|
|
31
|
+
return null;
|
|
32
|
+
})();
|
|
33
|
+
function refOf(el) {
|
|
34
|
+
if (!pageObserver) return null;
|
|
35
|
+
try {
|
|
36
|
+
const ref = pageObserver.refFor(el);
|
|
37
|
+
return typeof ref === 'string' ? ref : null;
|
|
38
|
+
} catch (e) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function withDocId(result) {
|
|
43
|
+
if (pageObserver && typeof pageObserver.doc_id === 'string') result.doc_id = pageObserver.doc_id;
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
function snapshotStore() {
|
|
47
|
+
if (
|
|
48
|
+
pageObserver &&
|
|
49
|
+
typeof pageObserver.recordSnapshot === 'function' &&
|
|
50
|
+
typeof pageObserver.getSnapshot === 'function'
|
|
51
|
+
) {
|
|
52
|
+
return pageObserver;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
57
|
+
/**
|
|
58
|
+
* In-page action-target resolution (spec v4 §6.3), injected after
|
|
59
|
+
* `DEEP_QUERY_JS` and `PAGE_OBSERVER_JS` into the builders that take a
|
|
60
|
+
* `selector` or a `ref` (click, type, focus, element rect, `wait_for` by
|
|
61
|
+
* ref, `find` by ref):
|
|
62
|
+
* `resolveTarget(opts)` with a non-empty `opts.ref` asks the observer
|
|
63
|
+
* (`resolveRefDetailed`, which re-resolves a replaced node by its semantic
|
|
64
|
+
* key) and answers `{ ok: true, el, reresolved }`, `{ ok: false, reason:
|
|
65
|
+
* 'ref-stale', ref, doc_id }` or `{ ok: false, reason: 'observer-unavailable'
|
|
66
|
+
* }`; otherwise it resolves `opts.selector` exactly as the selector builders
|
|
67
|
+
* always did (`invalid-selector` checked against `document` first, then
|
|
68
|
+
* `deepQueryFirst`, `not-found`). Kept out of `PAGE_OBSERVER_JS` so the
|
|
69
|
+
* snapshot and state sources do not carry code they never call.
|
|
70
|
+
*/
|
|
71
|
+
export const RESOLVE_TARGET_JS = `
|
|
72
|
+
function resolveTarget(opts) {
|
|
73
|
+
if (typeof opts.ref === 'string' && opts.ref.length > 0) {
|
|
74
|
+
if (!pageObserver || typeof pageObserver.resolveRefDetailed !== 'function') {
|
|
75
|
+
return { ok: false, reason: 'observer-unavailable' };
|
|
76
|
+
}
|
|
77
|
+
let found = null;
|
|
78
|
+
try {
|
|
79
|
+
found = pageObserver.resolveRefDetailed(opts.ref);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
found = null;
|
|
82
|
+
}
|
|
83
|
+
if (!found || !found.el) return withDocId({ ok: false, reason: 'ref-stale', ref: opts.ref });
|
|
84
|
+
return { ok: true, el: found.el, reresolved: found.reresolved === true };
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
document.querySelector(opts.selector);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
|
|
90
|
+
}
|
|
91
|
+
const el = deepQueryFirst(opts.selector);
|
|
92
|
+
if (!el) return { ok: false, reason: 'not-found' };
|
|
93
|
+
return { ok: true, el: el, reresolved: false };
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
/** JSON for the `selector` / `ref` pair, embedded as data in the built
|
|
97
|
+
* source; `ref` is included only when given so a selector build keeps the
|
|
98
|
+
* same options object as before. */
|
|
99
|
+
function targetJson(opts) {
|
|
100
|
+
return typeof opts.ref === 'string' && opts.ref.length > 0
|
|
101
|
+
? { selector: opts.selector, ref: opts.ref }
|
|
102
|
+
: { selector: opts.selector };
|
|
103
|
+
}
|
|
11
104
|
export function buildSnapshotJs(opts = {}) {
|
|
12
105
|
const optsJson = JSON.stringify({
|
|
13
106
|
withinSelector: typeof opts.within_selector === 'string' ? opts.within_selector : null,
|
|
@@ -16,23 +109,25 @@ export function buildSnapshotJs(opts = {}) {
|
|
|
16
109
|
maxInteractive: typeof opts.max_interactive === 'number' && opts.max_interactive > 0
|
|
17
110
|
? Math.min(opts.max_interactive, 500)
|
|
18
111
|
: 120,
|
|
112
|
+
since: typeof opts.since === 'string' ? opts.since : null,
|
|
19
113
|
});
|
|
20
114
|
return `
|
|
21
115
|
(() => {
|
|
22
116
|
${DEEP_QUERY_JS}
|
|
23
117
|
${DOM_HELPERS_JS}
|
|
118
|
+
${PAGE_OBSERVER_JS}
|
|
24
119
|
const opts = ${optsJson};
|
|
25
120
|
let root = document;
|
|
26
121
|
let notice = '';
|
|
27
122
|
if (opts.withinSelector) {
|
|
28
123
|
const sub = deepQueryFirst(opts.withinSelector);
|
|
29
124
|
if (!sub) {
|
|
30
|
-
return {
|
|
125
|
+
return withDocId({
|
|
31
126
|
title: document.title,
|
|
32
127
|
url: location.href,
|
|
33
128
|
interactive: [],
|
|
34
129
|
notice: 'within_selector did not match any element',
|
|
35
|
-
};
|
|
130
|
+
});
|
|
36
131
|
}
|
|
37
132
|
root = sub;
|
|
38
133
|
}
|
|
@@ -75,6 +170,8 @@ export function buildSnapshotJs(opts = {}) {
|
|
|
75
170
|
const role = el.getAttribute('role') || tag;
|
|
76
171
|
const selInfo = genSelectorInfo(el);
|
|
77
172
|
const entry = { tag, role, selector: selInfo.selector };
|
|
173
|
+
const ref = refOf(el);
|
|
174
|
+
if (ref) entry.ref = ref;
|
|
78
175
|
if (selInfo.ambiguous) entry.ambiguous = true;
|
|
79
176
|
const txt = shortText(el);
|
|
80
177
|
if (txt) entry.text = txt;
|
|
@@ -94,29 +191,118 @@ export function buildSnapshotJs(opts = {}) {
|
|
|
94
191
|
if (frame) entry.frame = frame;
|
|
95
192
|
interactive.push(entry);
|
|
96
193
|
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
url: location.href,
|
|
100
|
-
interactive: interactive.slice(0, opts.maxInteractive),
|
|
101
|
-
};
|
|
194
|
+
let headings = null;
|
|
195
|
+
let visibleText = '';
|
|
102
196
|
if (!opts.onlyInteractive) {
|
|
103
|
-
const
|
|
197
|
+
const found = [];
|
|
104
198
|
deepQueryAll('h1, h2, h3', root).forEach((h) => {
|
|
105
199
|
if (!isVisible(h)) return;
|
|
106
200
|
if (inExcludedLandmark(h)) return;
|
|
107
201
|
const t = shortText(h);
|
|
108
|
-
if (t)
|
|
202
|
+
if (t) found.push({ level: h.tagName, text: t });
|
|
109
203
|
});
|
|
110
|
-
|
|
204
|
+
headings = found.slice(0, 30);
|
|
111
205
|
const textRoot = (root === document) ? (document.body || document) : root;
|
|
112
|
-
|
|
206
|
+
visibleText = (textRoot && textRoot.innerText) ? textRoot.innerText.slice(0, 4000) : '';
|
|
207
|
+
}
|
|
208
|
+
let snapshotId = null;
|
|
209
|
+
if (withDocId({}).doc_id && typeof pageObserver.nextSnapshotId === 'function') {
|
|
210
|
+
const issued = pageObserver.nextSnapshotId();
|
|
211
|
+
if (typeof issued === 'string') snapshotId = issued;
|
|
212
|
+
}
|
|
213
|
+
function fullResult() {
|
|
214
|
+
const result = {
|
|
215
|
+
title: document.title,
|
|
216
|
+
url: location.href,
|
|
217
|
+
interactive: interactive.slice(0, opts.maxInteractive),
|
|
218
|
+
};
|
|
219
|
+
if (headings) result.headings = headings;
|
|
113
220
|
if (visibleText) result.text = visibleText;
|
|
221
|
+
if (notice) result.notice = notice;
|
|
222
|
+
withDocId(result);
|
|
223
|
+
if (snapshotId) result.snapshot_id = snapshotId;
|
|
224
|
+
return result;
|
|
114
225
|
}
|
|
115
|
-
|
|
116
|
-
|
|
226
|
+
// Record every snapshot (with or without since) so a later call can diff
|
|
227
|
+
// against it. Entries are keyed by ref; the hash is the entry serialised
|
|
228
|
+
// without its ref, in emission order. Capped at the first 500 entries.
|
|
229
|
+
const store = snapshotId ? snapshotStore() : null;
|
|
230
|
+
// A snapshot_id is \`<doc_id>:s<N>\`: a since whose prefix (before the LAST
|
|
231
|
+
// ':') is not this document's doc_id, or that has no ':', came from another
|
|
232
|
+
// document and is never looked up.
|
|
233
|
+
const sinceCut = opts.since === null ? -1 : opts.since.lastIndexOf(':');
|
|
234
|
+
const sinceSameDoc =
|
|
235
|
+
sinceCut >= 0 && withDocId({}).doc_id === opts.since.slice(0, sinceCut);
|
|
236
|
+
const previous = store && sinceSameDoc ? store.getSnapshot(opts.since) : null;
|
|
237
|
+
const current = new Map();
|
|
238
|
+
const headingsHash = headings ? JSON.stringify(headings) : null;
|
|
239
|
+
const textHash = opts.onlyInteractive ? null : visibleText;
|
|
240
|
+
if (store) {
|
|
241
|
+
for (const entry of interactive) {
|
|
242
|
+
if (current.size >= 500) break;
|
|
243
|
+
if (typeof entry.ref !== 'string') continue;
|
|
244
|
+
const copy = {};
|
|
245
|
+
for (const key of Object.keys(entry)) if (key !== 'ref') copy[key] = entry[key];
|
|
246
|
+
current.set(entry.ref, { hash: JSON.stringify(copy), entry });
|
|
247
|
+
}
|
|
248
|
+
store.recordSnapshot(snapshotId, { entries: current, headings_hash: headingsHash, text_hash: textHash });
|
|
249
|
+
}
|
|
250
|
+
if (opts.since === null) return fullResult();
|
|
251
|
+
if (!store) {
|
|
252
|
+
const result = fullResult();
|
|
253
|
+
result.since = opts.since;
|
|
254
|
+
result.since_status = 'observer-unavailable';
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
if (!previous || !previous.entries || typeof previous.entries.get !== 'function') {
|
|
258
|
+
const result = fullResult();
|
|
259
|
+
result.since = opts.since;
|
|
260
|
+
result.since_status = sinceSameDoc ? 'evicted' : 'doc-changed';
|
|
261
|
+
return result;
|
|
262
|
+
}
|
|
263
|
+
const added = [];
|
|
264
|
+
const changed = [];
|
|
265
|
+
const removed = [];
|
|
266
|
+
current.forEach((item, ref) => {
|
|
267
|
+
const old = previous.entries.get(ref);
|
|
268
|
+
if (!old) added.push(item.entry);
|
|
269
|
+
else if (old.hash !== item.hash) changed.push(item.entry);
|
|
270
|
+
});
|
|
271
|
+
previous.entries.forEach((item, ref) => {
|
|
272
|
+
if (current.has(ref) || removed.length >= 500) return;
|
|
273
|
+
const gone = { ref, tag: item.entry.tag };
|
|
274
|
+
if (item.entry.text) gone.text = item.entry.text;
|
|
275
|
+
removed.push(gone);
|
|
276
|
+
});
|
|
277
|
+
// max_interactive applies after diffing (added first, then changed), so
|
|
278
|
+
// a window shift never masquerades as change.
|
|
279
|
+
const listed = added.concat(changed);
|
|
280
|
+
const kept = listed.slice(0, opts.maxInteractive);
|
|
281
|
+
const diff = withDocId({ title: document.title, url: location.href });
|
|
282
|
+
diff.snapshot_id = snapshotId;
|
|
283
|
+
diff.since = opts.since;
|
|
284
|
+
diff.added = kept.slice(0, Math.min(added.length, kept.length));
|
|
285
|
+
diff.removed = removed;
|
|
286
|
+
diff.changed = kept.slice(diff.added.length);
|
|
287
|
+
if (listed.length > kept.length) diff.overflow = listed.length - kept.length;
|
|
288
|
+
if (!opts.onlyInteractive) {
|
|
289
|
+
if (headingsHash !== previous.headings_hash) diff.headings = headings;
|
|
290
|
+
if (textHash !== previous.text_hash) diff.text = visibleText;
|
|
291
|
+
}
|
|
292
|
+
return diff;
|
|
117
293
|
})()
|
|
118
294
|
`;
|
|
119
295
|
}
|
|
296
|
+
/** Only the documented key fields reach the built source, as JSON data. */
|
|
297
|
+
function findKeyJson(key) {
|
|
298
|
+
return Array.isArray(key.path)
|
|
299
|
+
? {
|
|
300
|
+
role: key.role,
|
|
301
|
+
name: key.name,
|
|
302
|
+
path: key.path.map((step) => ({ tag: step.tag, index: step.index })),
|
|
303
|
+
}
|
|
304
|
+
: { role: key.role, name: key.name };
|
|
305
|
+
}
|
|
120
306
|
export function buildFindJs(opts) {
|
|
121
307
|
const optsJson = JSON.stringify({
|
|
122
308
|
text: opts.text,
|
|
@@ -124,12 +310,98 @@ export function buildFindJs(opts) {
|
|
|
124
310
|
exact: opts.exact === true,
|
|
125
311
|
candidateLimit: 5,
|
|
126
312
|
nearMissLimit: 3,
|
|
313
|
+
...(typeof opts.ref === 'string' && opts.ref.length > 0 ? { ref: opts.ref } : {}),
|
|
314
|
+
...(opts.key ? { key: findKeyJson(opts.key) } : {}),
|
|
127
315
|
});
|
|
128
316
|
return `
|
|
129
317
|
(() => {
|
|
130
318
|
${DEEP_QUERY_JS}
|
|
131
319
|
${DOM_HELPERS_JS}
|
|
320
|
+
${PAGE_OBSERVER_JS}
|
|
321
|
+
${typeof opts.ref === 'string' && opts.ref.length > 0 ? RESOLVE_TARGET_JS : ''}
|
|
132
322
|
const opts = ${optsJson};
|
|
323
|
+
function semanticKeyOf(el) {
|
|
324
|
+
if (!pageObserver || typeof pageObserver.semanticKeyFor !== 'function') return null;
|
|
325
|
+
try {
|
|
326
|
+
const key = pageObserver.semanticKeyFor(el);
|
|
327
|
+
return key && typeof key === 'object' ? key : null;
|
|
328
|
+
} catch (e) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function singleMatch(el, ref, reresolved) {
|
|
333
|
+
const center = viewportCenterOf(el);
|
|
334
|
+
const selInfo = genSelectorInfo(el);
|
|
335
|
+
const result = { matched: true, selector: selInfo.selector };
|
|
336
|
+
if (ref) result.ref = ref;
|
|
337
|
+
result.coords = {
|
|
338
|
+
x: Math.round(center.x),
|
|
339
|
+
y: Math.round(center.y),
|
|
340
|
+
};
|
|
341
|
+
result.tag = el.tagName.toLowerCase();
|
|
342
|
+
result.text = shortText(el);
|
|
343
|
+
if (selInfo.ambiguous) result.ambiguous = true;
|
|
344
|
+
const frame = frameSelectorFor(el);
|
|
345
|
+
if (frame) result.frame = frame;
|
|
346
|
+
if (reresolved) result.reresolved = true;
|
|
347
|
+
const key = semanticKeyOf(el);
|
|
348
|
+
if (key) result.semantic_key = key;
|
|
349
|
+
return withDocId(result);
|
|
350
|
+
}
|
|
351
|
+
if (typeof opts.ref === 'string') {
|
|
352
|
+
const target = resolveTarget(opts);
|
|
353
|
+
if (!target.ok) {
|
|
354
|
+
const failure = { matched: false, reason: target.reason, ref: opts.ref };
|
|
355
|
+
return withDocId(failure);
|
|
356
|
+
}
|
|
357
|
+
return singleMatch(target.el, opts.ref, target.reresolved);
|
|
358
|
+
}
|
|
359
|
+
if (opts.key) {
|
|
360
|
+
if (!pageObserver || typeof pageObserver.semanticKeyFor !== 'function') {
|
|
361
|
+
return { matched: false, reason: 'observer-unavailable' };
|
|
362
|
+
}
|
|
363
|
+
const wanted = opts.key;
|
|
364
|
+
const candidates = [];
|
|
365
|
+
for (const el of deepQueryAll('*')) {
|
|
366
|
+
const key = semanticKeyOf(el);
|
|
367
|
+
if (key && key.role === wanted.role && key.name === wanted.name) {
|
|
368
|
+
candidates.push({ el: el, path: Array.isArray(key.path) ? key.path : [] });
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const count = candidates.length;
|
|
372
|
+
const shared = 'key: ' + count + ' candidates share role and name; ';
|
|
373
|
+
let picked = null;
|
|
374
|
+
let error = count > 1 ? shared + 'pass path to disambiguate' : null;
|
|
375
|
+
if (!Array.isArray(wanted.path)) {
|
|
376
|
+
if (count === 1) picked = candidates[0].el;
|
|
377
|
+
} else {
|
|
378
|
+
// Same rule as the observer's re-resolution: identical tag path and
|
|
379
|
+
// exactly one such candidate; identical rows are refused, never guessed.
|
|
380
|
+
let sameTags = 0;
|
|
381
|
+
let only = null;
|
|
382
|
+
for (const c of candidates) {
|
|
383
|
+
if (c.path.length !== wanted.path.length) continue;
|
|
384
|
+
let same = true;
|
|
385
|
+
for (let i = 0; i < c.path.length && same; i++) {
|
|
386
|
+
if (c.path[i].tag !== wanted.path[i].tag) same = false;
|
|
387
|
+
}
|
|
388
|
+
if (!same) continue;
|
|
389
|
+
sameTags++;
|
|
390
|
+
only = c.el;
|
|
391
|
+
}
|
|
392
|
+
if (sameTags === 1) {
|
|
393
|
+
picked = only;
|
|
394
|
+
} else if (sameTags > 1) {
|
|
395
|
+
error = 'key: ' + sameTags + ' candidates share role, name and tag path';
|
|
396
|
+
} else if (count > 0) {
|
|
397
|
+
error = shared + 'none has the same tag path';
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (picked) return singleMatch(picked, refOf(picked), false);
|
|
401
|
+
const failure = { matched: false, reason: 'not-found' };
|
|
402
|
+
if (error) failure.error = error;
|
|
403
|
+
return withDocId(failure);
|
|
404
|
+
}
|
|
133
405
|
const needle = opts.text.toLowerCase();
|
|
134
406
|
const needleTokens = needle.split(/[^a-z0-9]+/).filter(Boolean);
|
|
135
407
|
const ROLE_SELECTORS = {
|
|
@@ -189,6 +461,8 @@ export function buildFindJs(opts) {
|
|
|
189
461
|
}
|
|
190
462
|
function toNearMiss(el) {
|
|
191
463
|
const entry = { text: snippetOf(el), selector: genSelector(el) };
|
|
464
|
+
const ref = refOf(el);
|
|
465
|
+
if (ref) entry.ref = ref;
|
|
192
466
|
const roleAttr = el.getAttribute('role');
|
|
193
467
|
if (roleAttr) entry.role = roleAttr;
|
|
194
468
|
return entry;
|
|
@@ -221,60 +495,46 @@ export function buildFindJs(opts) {
|
|
|
221
495
|
' but none with role "' + opts.role + '"' +
|
|
222
496
|
(closest ? ' — closest: ' + describeForError(closest) + ' "' + snippetOf(closest) + '"' : '');
|
|
223
497
|
result.near_misses = ranked.map(toNearMiss);
|
|
224
|
-
return result;
|
|
498
|
+
return withDocId(result);
|
|
225
499
|
}
|
|
226
500
|
const ranked = rankCandidates(broadAll);
|
|
227
501
|
if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
|
|
228
|
-
return result;
|
|
502
|
+
return withDocId(result);
|
|
229
503
|
}
|
|
230
504
|
const ranked = rankCandidates(all);
|
|
231
505
|
if (ranked.length > 0) result.near_misses = ranked.map(toNearMiss);
|
|
232
|
-
return result;
|
|
506
|
+
return withDocId(result);
|
|
233
507
|
}
|
|
234
508
|
if (matches.length > 1) {
|
|
235
|
-
return {
|
|
509
|
+
return withDocId({
|
|
236
510
|
matched: false,
|
|
237
511
|
reason: 'multiple-matches',
|
|
238
|
-
candidates: matches.slice(0, opts.candidateLimit).map((el) =>
|
|
239
|
-
selector: genSelector(el)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
512
|
+
candidates: matches.slice(0, opts.candidateLimit).map((el) => {
|
|
513
|
+
const candidate = { selector: genSelector(el) };
|
|
514
|
+
const ref = refOf(el);
|
|
515
|
+
if (ref) candidate.ref = ref;
|
|
516
|
+
candidate.text = shortText(el);
|
|
517
|
+
candidate.tag = el.tagName.toLowerCase();
|
|
518
|
+
return candidate;
|
|
519
|
+
}),
|
|
520
|
+
});
|
|
244
521
|
}
|
|
245
522
|
const el = matches[0];
|
|
246
|
-
|
|
247
|
-
const selInfo = genSelectorInfo(el);
|
|
248
|
-
const result = {
|
|
249
|
-
matched: true,
|
|
250
|
-
selector: selInfo.selector,
|
|
251
|
-
coords: {
|
|
252
|
-
x: Math.round(center.x),
|
|
253
|
-
y: Math.round(center.y),
|
|
254
|
-
},
|
|
255
|
-
tag: el.tagName.toLowerCase(),
|
|
256
|
-
text: shortText(el),
|
|
257
|
-
};
|
|
258
|
-
if (selInfo.ambiguous) result.ambiguous = true;
|
|
259
|
-
const frame = frameSelectorFor(el);
|
|
260
|
-
if (frame) result.frame = frame;
|
|
261
|
-
return result;
|
|
523
|
+
return singleMatch(el, refOf(el), false);
|
|
262
524
|
})()
|
|
263
525
|
`;
|
|
264
526
|
}
|
|
265
527
|
export function buildClickResolveJs(opts) {
|
|
266
|
-
const optsJson = JSON.stringify({
|
|
528
|
+
const optsJson = JSON.stringify({ ...targetJson(opts), force: opts.force });
|
|
267
529
|
return `
|
|
268
530
|
(() => {
|
|
269
531
|
${DEEP_QUERY_JS}
|
|
532
|
+
${PAGE_OBSERVER_JS}
|
|
533
|
+
${RESOLVE_TARGET_JS}
|
|
270
534
|
const opts = ${optsJson};
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
|
|
275
|
-
}
|
|
276
|
-
const el = deepQueryFirst(opts.selector);
|
|
277
|
-
if (!el) return { ok: false, reason: 'not-found' };
|
|
535
|
+
const target = resolveTarget(opts);
|
|
536
|
+
if (!target.ok) return target;
|
|
537
|
+
const el = target.el;
|
|
278
538
|
const chain = frameElementChain(el);
|
|
279
539
|
for (const fe of chain) {
|
|
280
540
|
if (fe.scrollIntoView) fe.scrollIntoView({ block: 'center', inline: 'center' });
|
|
@@ -289,41 +549,59 @@ export function buildClickResolveJs(opts) {
|
|
|
289
549
|
const result = { ok: true, x: center.x, y: center.y, tag };
|
|
290
550
|
const hit = occlusion.allowed ? occlusion.hit : occlusion.blocker;
|
|
291
551
|
if (hit) result.hit_element = hit;
|
|
552
|
+
if (target.reresolved) result.reresolved = true;
|
|
292
553
|
return result;
|
|
293
554
|
})()
|
|
294
555
|
`;
|
|
295
556
|
}
|
|
296
557
|
export function buildTypeResolveJs(opts) {
|
|
297
|
-
const optsJson = JSON.stringify(
|
|
558
|
+
const optsJson = JSON.stringify(targetJson(opts));
|
|
298
559
|
return `
|
|
299
560
|
(() => {
|
|
300
561
|
${DEEP_QUERY_JS}
|
|
562
|
+
${PAGE_OBSERVER_JS}
|
|
563
|
+
${RESOLVE_TARGET_JS}
|
|
301
564
|
const opts = ${optsJson};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
|
|
306
|
-
}
|
|
307
|
-
const el = deepQueryFirst(opts.selector);
|
|
308
|
-
if (!el) return { ok: false, reason: 'not-found' };
|
|
565
|
+
const target = resolveTarget(opts);
|
|
566
|
+
if (!target.ok) return target;
|
|
567
|
+
const el = target.el;
|
|
309
568
|
el.focus();
|
|
310
569
|
${opts.clear ? "if ('value' in el) { el.value = ''; el.dispatchEvent(new Event('input', { bubbles: true })); }" : ''}
|
|
311
|
-
return { ok: true };
|
|
570
|
+
return target.reresolved ? { ok: true, reresolved: true } : { ok: true };
|
|
312
571
|
})()`;
|
|
313
572
|
}
|
|
314
573
|
export function buildFocusJs(opts) {
|
|
315
|
-
const optsJson = JSON.stringify(
|
|
574
|
+
const optsJson = JSON.stringify(targetJson(opts));
|
|
316
575
|
return `
|
|
317
576
|
(() => {
|
|
318
577
|
${DEEP_QUERY_JS}
|
|
578
|
+
${PAGE_OBSERVER_JS}
|
|
579
|
+
${RESOLVE_TARGET_JS}
|
|
319
580
|
const opts = ${optsJson};
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
581
|
+
const target = resolveTarget(opts);
|
|
582
|
+
const byRef = typeof opts.ref === 'string';
|
|
583
|
+
if (!target.ok) return byRef ? target : false;
|
|
584
|
+
target.el.focus();
|
|
585
|
+
if (!byRef) return true;
|
|
586
|
+
return target.reresolved ? { ok: true, reresolved: true } : { ok: true };
|
|
324
587
|
})()`;
|
|
325
588
|
}
|
|
326
|
-
export function buildWaitForSelectorJs(
|
|
589
|
+
export function buildWaitForSelectorJs(target, condition) {
|
|
590
|
+
if (typeof target !== 'string') {
|
|
591
|
+
const refOptsJson = JSON.stringify({ ref: target.ref, condition });
|
|
592
|
+
return `
|
|
593
|
+
(() => {
|
|
594
|
+
${DEEP_QUERY_JS}
|
|
595
|
+
${PAGE_OBSERVER_JS}
|
|
596
|
+
${RESOLVE_TARGET_JS}
|
|
597
|
+
const opts = ${refOptsJson};
|
|
598
|
+
const target = resolveTarget(opts);
|
|
599
|
+
if (!target.ok && target.reason === 'observer-unavailable') return target;
|
|
600
|
+
const el = target.ok ? target.el : null;
|
|
601
|
+
${WAIT_FOR_CONDITION_JS}
|
|
602
|
+
})()`;
|
|
603
|
+
}
|
|
604
|
+
const selector = target;
|
|
327
605
|
const optsJson = JSON.stringify({ selector, condition });
|
|
328
606
|
return `
|
|
329
607
|
(() => {
|
|
@@ -331,7 +609,12 @@ export function buildWaitForSelectorJs(selector, condition) {
|
|
|
331
609
|
const opts = ${optsJson};
|
|
332
610
|
document.querySelector(opts.selector);
|
|
333
611
|
const el = deepQueryFirst(opts.selector);
|
|
334
|
-
|
|
612
|
+
${WAIT_FOR_CONDITION_JS}
|
|
613
|
+
})()`;
|
|
614
|
+
}
|
|
615
|
+
/** The condition check shared by both `wait_for` probe targets; `el` is
|
|
616
|
+
* the resolved element or `null`. */
|
|
617
|
+
const WAIT_FOR_CONDITION_JS = `if (opts.condition === 'attached') return Boolean(el);
|
|
335
618
|
if (opts.condition === 'detached') return !el;
|
|
336
619
|
const wantHidden = opts.condition === 'hidden';
|
|
337
620
|
if (!el) return wantHidden;
|
|
@@ -340,22 +623,18 @@ export function buildWaitForSelectorJs(selector, condition) {
|
|
|
340
623
|
if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return wantHidden;
|
|
341
624
|
const r = el.getBoundingClientRect();
|
|
342
625
|
const shown = r.width > 0 && r.height > 0;
|
|
343
|
-
return wantHidden ? !shown : shown
|
|
344
|
-
})()`;
|
|
345
|
-
}
|
|
626
|
+
return wantHidden ? !shown : shown;`;
|
|
346
627
|
export function buildElementRectJs(opts) {
|
|
347
|
-
const optsJson = JSON.stringify(
|
|
628
|
+
const optsJson = JSON.stringify(targetJson(opts));
|
|
348
629
|
return `
|
|
349
630
|
(() => {
|
|
350
631
|
${DEEP_QUERY_JS}
|
|
632
|
+
${PAGE_OBSERVER_JS}
|
|
633
|
+
${RESOLVE_TARGET_JS}
|
|
351
634
|
const opts = ${optsJson};
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
return { ok: false, reason: 'invalid-selector', error: e && e.message ? e.message : String(e) };
|
|
356
|
-
}
|
|
357
|
-
const el = deepQueryFirst(opts.selector);
|
|
358
|
-
if (!el) return { ok: false, reason: 'not-found' };
|
|
635
|
+
const target = resolveTarget(opts);
|
|
636
|
+
if (!target.ok) return target;
|
|
637
|
+
const el = target.el;
|
|
359
638
|
const chain = frameElementChain(el);
|
|
360
639
|
// behavior 'instant' overrides CSS scroll-behavior: smooth, which would
|
|
361
640
|
// leave the rect below stale while the scroll is still animating.
|
|
@@ -380,13 +659,15 @@ export function buildElementRectJs(opts) {
|
|
|
380
659
|
scrollX = top.scrollX || 0;
|
|
381
660
|
scrollY = top.scrollY || 0;
|
|
382
661
|
} catch (_) {}
|
|
383
|
-
|
|
662
|
+
const result = {
|
|
384
663
|
ok: true,
|
|
385
664
|
x: offsetX + rect.left + scrollX,
|
|
386
665
|
y: offsetY + rect.top + scrollY,
|
|
387
666
|
width: rect.width,
|
|
388
667
|
height: rect.height,
|
|
389
668
|
};
|
|
669
|
+
if (target.reresolved) result.reresolved = true;
|
|
670
|
+
return result;
|
|
390
671
|
})()`;
|
|
391
672
|
}
|
|
392
673
|
export function buildDragProbeJs(opts) {
|
|
@@ -623,12 +904,16 @@ export function buildExpectProbeJs(opts) {
|
|
|
623
904
|
* `focused` beyond `<body>`, no `dialogs` when none are open, and no
|
|
624
905
|
* `scroll` when the page is at its default (0,0) position — token-lean by
|
|
625
906
|
* construction, matching the omit-falsy convention the other builders use.
|
|
907
|
+
*
|
|
908
|
+
* With the page observer installed (see `PAGE_OBSERVER_JS`), `focused`
|
|
909
|
+
* carries `ref` right after `selector` and the result carries `doc_id`.
|
|
626
910
|
*/
|
|
627
911
|
export function buildStateJs() {
|
|
628
912
|
return `
|
|
629
913
|
(() => {
|
|
630
914
|
${DEEP_QUERY_JS}
|
|
631
915
|
${DOM_HELPERS_JS}
|
|
916
|
+
${PAGE_OBSERVER_JS}
|
|
632
917
|
function deepActiveElement() {
|
|
633
918
|
let el = document.activeElement;
|
|
634
919
|
let guard = 0;
|
|
@@ -689,7 +974,10 @@ export function buildStateJs() {
|
|
|
689
974
|
const active = deepActiveElement();
|
|
690
975
|
if (active && active !== document.body && active.tagName) {
|
|
691
976
|
const selInfo = genSelectorInfo(active);
|
|
692
|
-
const focused = { selector: selInfo.selector
|
|
977
|
+
const focused = { selector: selInfo.selector };
|
|
978
|
+
const ref = refOf(active);
|
|
979
|
+
if (ref) focused.ref = ref;
|
|
980
|
+
focused.tag = active.tagName.toLowerCase();
|
|
693
981
|
if (selInfo.ambiguous) focused.ambiguous = true;
|
|
694
982
|
result.focused = focused;
|
|
695
983
|
}
|
|
@@ -709,7 +997,7 @@ export function buildStateJs() {
|
|
|
709
997
|
const scrollY = Math.round(window.scrollY);
|
|
710
998
|
if (scrollX !== 0 || scrollY !== 0) result.scroll = { x: scrollX, y: scrollY };
|
|
711
999
|
|
|
712
|
-
return result;
|
|
1000
|
+
return withDocId(result);
|
|
713
1001
|
})()
|
|
714
1002
|
`;
|
|
715
1003
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builders.js","sourceRoot":"","sources":["../../src/inpage/builders.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;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/inpage/builders.ts"],"names":[],"mappings":"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"}
|