agent-web-interface 4.0.1 → 4.1.1
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/src/snapshot/extractors/index.d.ts +2 -1
- package/dist/src/snapshot/extractors/index.d.ts.map +1 -1
- package/dist/src/snapshot/extractors/index.js +2 -0
- package/dist/src/snapshot/extractors/index.js.map +1 -1
- package/dist/src/snapshot/extractors/interactivity-detector.d.ts +27 -0
- package/dist/src/snapshot/extractors/interactivity-detector.d.ts.map +1 -0
- package/dist/src/snapshot/extractors/interactivity-detector.js +190 -0
- package/dist/src/snapshot/extractors/interactivity-detector.js.map +1 -0
- package/dist/src/snapshot/extractors/types.d.ts +15 -0
- package/dist/src/snapshot/extractors/types.d.ts.map +1 -1
- package/dist/src/snapshot/extractors/types.js.map +1 -1
- package/dist/src/snapshot/snapshot-compiler.d.ts +14 -0
- package/dist/src/snapshot/snapshot-compiler.d.ts.map +1 -1
- package/dist/src/snapshot/snapshot-compiler.js +153 -3
- package/dist/src/snapshot/snapshot-compiler.js.map +1 -1
- package/dist/src/snapshot/snapshot.types.d.ts +2 -0
- package/dist/src/snapshot/snapshot.types.d.ts.map +1 -1
- package/dist/src/snapshot/snapshot.types.js +1 -1
- package/dist/src/snapshot/snapshot.types.js.map +1 -1
- package/dist/src/state/actionables-filter.d.ts.map +1 -1
- package/dist/src/state/actionables-filter.js +9 -31
- package/dist/src/state/actionables-filter.js.map +1 -1
- package/dist/src/state/element-registry.js +2 -2
- package/dist/src/state/element-registry.js.map +1 -1
- package/dist/src/state/locator-generator.d.ts.map +1 -1
- package/dist/src/state/locator-generator.js +1 -10
- package/dist/src/state/locator-generator.js.map +1 -1
- package/dist/src/state/node-layer.d.ts +22 -0
- package/dist/src/state/node-layer.d.ts.map +1 -0
- package/dist/src/state/node-layer.js +42 -0
- package/dist/src/state/node-layer.js.map +1 -0
- package/dist/src/state/state-manager.d.ts.map +1 -1
- package/dist/src/state/state-manager.js +9 -8
- package/dist/src/state/state-manager.js.map +1 -1
- package/dist/src/state/state-renderer.d.ts.map +1 -1
- package/dist/src/state/state-renderer.js +4 -0
- package/dist/src/state/state-renderer.js.map +1 -1
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module snapshot/extractors
|
|
7
7
|
*/
|
|
8
|
-
export type { RawDomNode, RawAxNode, AxProperty, AxPropertyValue, NodeLayoutInfo, RawNodeData, ExtractorContext, DomExtractionResult, AxExtractionResult, LayoutExtractionResult, } from './types.js';
|
|
8
|
+
export type { RawDomNode, RawAxNode, AxProperty, AxPropertyValue, NodeLayoutInfo, RawNodeData, ExtractorContext, DomExtractionResult, AxExtractionResult, LayoutExtractionResult, InteractivitySignals, } from './types.js';
|
|
9
9
|
export { createExtractorContext, isValidRawDomNode, isValidRawAxNode, isValidNodeLayoutInfo, DOM_NODE_TYPES, INTERACTIVE_AX_ROLES, READABLE_AX_ROLES, STRUCTURAL_AX_ROLES, } from './types.js';
|
|
10
10
|
export { extractDom } from './dom-extractor.js';
|
|
11
11
|
export { extractAx, classifyAxRole, type RoleClassification } from './ax-extractor.js';
|
|
@@ -16,4 +16,5 @@ export { resolveRegion } from './region-resolver.js';
|
|
|
16
16
|
export { buildLocators } from './locator-builder.js';
|
|
17
17
|
export { resolveGrouping, type GroupingInfo } from './grouping-resolver.js';
|
|
18
18
|
export { extractAttributes, sanitizeUrl, type AttributeExtractionOptions, } from './attribute-extractor.js';
|
|
19
|
+
export { detectInteractivity } from './interactivity-detector.js';
|
|
19
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/snapshot/extractors/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,YAAY,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/snapshot/extractors/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,YAAY,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG5F,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAG3F,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG5E,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,KAAK,0BAA0B,GAChC,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -24,4 +24,6 @@ export { buildLocators } from './locator-builder.js';
|
|
|
24
24
|
export { resolveGrouping } from './grouping-resolver.js';
|
|
25
25
|
// Attribute Extractor
|
|
26
26
|
export { extractAttributes, sanitizeUrl, } from './attribute-extractor.js';
|
|
27
|
+
// Interactivity Detector
|
|
28
|
+
export { detectInteractivity } from './interactivity-detector.js';
|
|
27
29
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/snapshot/extractors/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/snapshot/extractors/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAEpB,gBAAgB;AAChB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,eAAe;AACf,OAAO,EAAE,SAAS,EAAE,cAAc,EAA2B,MAAM,mBAAmB,CAAC;AAEvF,mBAAmB;AACnB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE5F,kBAAkB;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,iBAAiB;AACjB,OAAO,EAAE,YAAY,EAA0C,MAAM,qBAAqB,CAAC;AAE3F,kBAAkB;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,kBAAkB;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,oBAAoB;AACpB,OAAO,EAAE,eAAe,EAAqB,MAAM,wBAAwB,CAAC;AAE5E,sBAAsB;AACtB,OAAO,EACL,iBAAiB,EACjB,WAAW,GAEZ,MAAM,0BAA0B,CAAC;AAElC,yBAAyB;AACzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactivity Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects implicit interactivity signals on non-semantic elements:
|
|
5
|
+
* - Event listeners (click/mousedown/pointerdown) on self or ancestors
|
|
6
|
+
* - CSS cursor: pointer
|
|
7
|
+
* - tabindex >= 0
|
|
8
|
+
*
|
|
9
|
+
* @module snapshot/extractors/interactivity-detector
|
|
10
|
+
*
|
|
11
|
+
* CDP Domains:
|
|
12
|
+
* - DOM: pushNodesByBackendIdsToFrontend, resolveNode
|
|
13
|
+
* - CSS: getComputedStyleForNode
|
|
14
|
+
* - DOMDebugger: getEventListeners
|
|
15
|
+
* - Runtime: releaseObject
|
|
16
|
+
*/
|
|
17
|
+
import type { ExtractorContext, RawDomNode, InteractivitySignals } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Detect implicit interactivity signals on non-interactive elements.
|
|
20
|
+
*
|
|
21
|
+
* @param ctx - Extractor context with CDP client
|
|
22
|
+
* @param candidateIds - backendNodeIds of non-interactive nodes to check
|
|
23
|
+
* @param domNodes - DOM tree for attribute lookup and ancestor walking
|
|
24
|
+
* @returns Map of backendNodeId → InteractivitySignals (only for nodes with positive signals)
|
|
25
|
+
*/
|
|
26
|
+
export declare function detectInteractivity(ctx: ExtractorContext, candidateIds: number[], domNodes: Map<number, RawDomNode>): Promise<Map<number, InteractivitySignals>>;
|
|
27
|
+
//# sourceMappingURL=interactivity-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactivity-detector.d.ts","sourceRoot":"","sources":["../../../../src/snapshot/extractors/interactivity-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAsBrF;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,gBAAgB,EACrB,YAAY,EAAE,MAAM,EAAE,EACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GAChC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAyI5C"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactivity Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects implicit interactivity signals on non-semantic elements:
|
|
5
|
+
* - Event listeners (click/mousedown/pointerdown) on self or ancestors
|
|
6
|
+
* - CSS cursor: pointer
|
|
7
|
+
* - tabindex >= 0
|
|
8
|
+
*
|
|
9
|
+
* @module snapshot/extractors/interactivity-detector
|
|
10
|
+
*
|
|
11
|
+
* CDP Domains:
|
|
12
|
+
* - DOM: pushNodesByBackendIdsToFrontend, resolveNode
|
|
13
|
+
* - CSS: getComputedStyleForNode
|
|
14
|
+
* - DOMDebugger: getEventListeners
|
|
15
|
+
* - Runtime: releaseObject
|
|
16
|
+
*/
|
|
17
|
+
/** Event types that indicate click interactivity */
|
|
18
|
+
const CLICK_EVENT_TYPES = new Set(['click', 'mousedown', 'pointerdown']);
|
|
19
|
+
/** Maximum ancestor levels to walk for delegated event detection */
|
|
20
|
+
const MAX_ANCESTOR_DEPTH = 5;
|
|
21
|
+
/**
|
|
22
|
+
* Detect implicit interactivity signals on non-interactive elements.
|
|
23
|
+
*
|
|
24
|
+
* @param ctx - Extractor context with CDP client
|
|
25
|
+
* @param candidateIds - backendNodeIds of non-interactive nodes to check
|
|
26
|
+
* @param domNodes - DOM tree for attribute lookup and ancestor walking
|
|
27
|
+
* @returns Map of backendNodeId → InteractivitySignals (only for nodes with positive signals)
|
|
28
|
+
*/
|
|
29
|
+
export async function detectInteractivity(ctx, candidateIds, domNodes) {
|
|
30
|
+
const results = new Map();
|
|
31
|
+
if (candidateIds.length === 0)
|
|
32
|
+
return results;
|
|
33
|
+
const { cdp } = ctx;
|
|
34
|
+
// Phase 1: Check tabindex from DOM attributes (free — no CDP calls)
|
|
35
|
+
const tabindexResults = new Map();
|
|
36
|
+
for (const id of candidateIds) {
|
|
37
|
+
const domNode = domNodes.get(id);
|
|
38
|
+
if (domNode?.attributes?.tabindex !== undefined) {
|
|
39
|
+
const tabindex = parseInt(domNode.attributes.tabindex, 10);
|
|
40
|
+
tabindexResults.set(id, !isNaN(tabindex) && tabindex >= 0);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Phase 2: Batch resolve backendNodeIds → nodeIds for CSS and event listener checks
|
|
44
|
+
let nodeIdMap;
|
|
45
|
+
try {
|
|
46
|
+
const pushResult = await cdp.send('DOM.pushNodesByBackendIdsToFrontend', { backendNodeIds: candidateIds });
|
|
47
|
+
nodeIdMap = new Map();
|
|
48
|
+
for (let i = 0; i < candidateIds.length; i++) {
|
|
49
|
+
if (pushResult.nodeIds[i] !== 0) {
|
|
50
|
+
nodeIdMap.set(candidateIds[i], pushResult.nodeIds[i]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// If push fails, return what we have from tabindex
|
|
56
|
+
for (const [id, hasTabindex] of tabindexResults) {
|
|
57
|
+
if (hasTabindex) {
|
|
58
|
+
results.set(id, {
|
|
59
|
+
has_click_listener: false,
|
|
60
|
+
has_cursor_pointer: false,
|
|
61
|
+
has_tabindex: true,
|
|
62
|
+
listener_source: 'none',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return results;
|
|
67
|
+
}
|
|
68
|
+
// Phase 3: Check cursor:pointer and event listeners for each candidate
|
|
69
|
+
// Cache ancestor listener results to avoid redundant checks
|
|
70
|
+
const ancestorListenerCache = new Map();
|
|
71
|
+
for (const backendNodeId of candidateIds) {
|
|
72
|
+
const nodeId = nodeIdMap.get(backendNodeId);
|
|
73
|
+
if (!nodeId)
|
|
74
|
+
continue;
|
|
75
|
+
const signals = {
|
|
76
|
+
has_click_listener: false,
|
|
77
|
+
has_cursor_pointer: false,
|
|
78
|
+
has_tabindex: tabindexResults.get(backendNodeId) ?? false,
|
|
79
|
+
listener_source: 'none',
|
|
80
|
+
};
|
|
81
|
+
// Check cursor:pointer
|
|
82
|
+
try {
|
|
83
|
+
const styleResult = await cdp.send('CSS.getComputedStyleForNode', { nodeId });
|
|
84
|
+
const cursorProp = styleResult.computedStyle.find((p) => p.name === 'cursor');
|
|
85
|
+
if (cursorProp?.value === 'pointer') {
|
|
86
|
+
signals.has_cursor_pointer = true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// CSS check failed — continue with other signals
|
|
91
|
+
}
|
|
92
|
+
// Short-circuit: skip expensive listener checks if we already have a positive signal
|
|
93
|
+
if (signals.has_cursor_pointer || signals.has_tabindex) {
|
|
94
|
+
results.set(backendNodeId, signals);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// Check event listeners on self
|
|
98
|
+
let objectId;
|
|
99
|
+
try {
|
|
100
|
+
const resolveResult = await cdp.send('DOM.resolveNode', {
|
|
101
|
+
backendNodeId,
|
|
102
|
+
});
|
|
103
|
+
objectId = resolveResult.object.objectId;
|
|
104
|
+
if (objectId) {
|
|
105
|
+
const listenersResult = await cdp.send('DOMDebugger.getEventListeners', { objectId });
|
|
106
|
+
const hasClickListener = listenersResult.listeners.some((l) => CLICK_EVENT_TYPES.has(l.type));
|
|
107
|
+
if (hasClickListener) {
|
|
108
|
+
signals.has_click_listener = true;
|
|
109
|
+
signals.listener_source = 'self';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Resolve or listener check failed — continue
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
// Release the remote object to prevent memory leaks
|
|
118
|
+
if (objectId) {
|
|
119
|
+
try {
|
|
120
|
+
await cdp.send('Runtime.releaseObject', { objectId });
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Ignore release failures
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Check ancestor event listeners (if no self listener found)
|
|
128
|
+
if (!signals.has_click_listener) {
|
|
129
|
+
const hasAncestorListener = await checkAncestorListeners(cdp, backendNodeId, domNodes, ancestorListenerCache);
|
|
130
|
+
if (hasAncestorListener) {
|
|
131
|
+
signals.has_click_listener = true;
|
|
132
|
+
signals.listener_source = 'ancestor';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Only add to results if any signal is positive
|
|
136
|
+
if (signals.has_click_listener || signals.has_cursor_pointer || signals.has_tabindex) {
|
|
137
|
+
results.set(backendNodeId, signals);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return results;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Walk up ancestor chain checking for delegated click listeners.
|
|
144
|
+
* Results are cached to avoid redundant CDP calls when siblings share parents.
|
|
145
|
+
*/
|
|
146
|
+
async function checkAncestorListeners(cdp, backendNodeId, domNodes, cache) {
|
|
147
|
+
let currentId = backendNodeId;
|
|
148
|
+
for (let depth = 0; depth < MAX_ANCESTOR_DEPTH; depth++) {
|
|
149
|
+
const domNode = domNodes.get(currentId);
|
|
150
|
+
const parentId = domNode?.parentId;
|
|
151
|
+
if (parentId === undefined)
|
|
152
|
+
break;
|
|
153
|
+
// Check cache first
|
|
154
|
+
if (cache.has(parentId)) {
|
|
155
|
+
return cache.get(parentId);
|
|
156
|
+
}
|
|
157
|
+
// Check parent's event listeners
|
|
158
|
+
let objectId;
|
|
159
|
+
try {
|
|
160
|
+
const resolveResult = await cdp.send('DOM.resolveNode', {
|
|
161
|
+
backendNodeId: parentId,
|
|
162
|
+
});
|
|
163
|
+
objectId = resolveResult.object.objectId;
|
|
164
|
+
if (objectId) {
|
|
165
|
+
const listenersResult = await cdp.send('DOMDebugger.getEventListeners', { objectId });
|
|
166
|
+
const hasClickListener = listenersResult.listeners.some((l) => CLICK_EVENT_TYPES.has(l.type));
|
|
167
|
+
cache.set(parentId, hasClickListener);
|
|
168
|
+
if (hasClickListener) {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
cache.set(parentId, false);
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
if (objectId) {
|
|
178
|
+
try {
|
|
179
|
+
await cdp.send('Runtime.releaseObject', { objectId });
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Ignore release failures
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
currentId = parentId;
|
|
187
|
+
}
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=interactivity-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactivity-detector.js","sourceRoot":"","sources":["../../../../src/snapshot/extractors/interactivity-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -114,6 +114,21 @@ export interface RawNodeData {
|
|
|
114
114
|
layout?: NodeLayoutInfo;
|
|
115
115
|
/** Backend node ID (primary key for correlation) */
|
|
116
116
|
backendNodeId: number;
|
|
117
|
+
/** Implicit interactivity signals (click listeners, cursor:pointer, tabindex) */
|
|
118
|
+
interactivity?: InteractivitySignals;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Implicit interactivity detection result for a node.
|
|
122
|
+
*/
|
|
123
|
+
export interface InteractivitySignals {
|
|
124
|
+
/** Element has click/mousedown/pointerdown event listener */
|
|
125
|
+
has_click_listener: boolean;
|
|
126
|
+
/** Element has CSS cursor: pointer */
|
|
127
|
+
has_cursor_pointer: boolean;
|
|
128
|
+
/** Element has tabindex >= 0 */
|
|
129
|
+
has_tabindex: boolean;
|
|
130
|
+
/** Where the click listener was found */
|
|
131
|
+
listener_source: 'self' | 'ancestor' | 'none';
|
|
117
132
|
}
|
|
118
133
|
/**
|
|
119
134
|
* Context passed to all extractors for accessing CDP and configuration
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/snapshot/extractors/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAMxF;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IAEf,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IAEtB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IAEjB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IAEjB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpC,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAEnC,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;kEAC8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,eAAe,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IAEf,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,yDAAyD;IACzD,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAE1B,kDAAkD;IAClD,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,IAAI,EAAE,IAAI,CAAC;IAEX,wBAAwB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,+EAA+E;IAC/E,SAAS,EAAE,OAAO,CAAC;IAEnB,0DAA0D;IAC1D,UAAU,CAAC,EAAE,UAAU,CAAC;IAExB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,wBAAwB;IACxB,OAAO,CAAC,EAAE,UAAU,CAAC;IAErB,uBAAuB;IACvB,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB,yBAAyB;IACzB,MAAM,CAAC,EAAE,cAAc,CAAC;IAExB,oDAAoD;IACpD,aAAa,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/snapshot/extractors/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/snapshot/extractors/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/snapshot/extractors/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAiLH;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAAc,EACd,QAAkB,EAClB,UAAoC,EAAE;IAEtC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AACpC,CAAC;AA6CD,+EAA+E;AAC/E,0BAA0B;AAC1B,+EAA+E;AAE/E;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAgB;IAChD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CACL,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;QAC/B,OAAO,IAAI,CAAC,aAAa,KAAK,QAAQ;QACtC,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ;QACjC,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAClC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAe;IAC9C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC;AACzC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAsB;IAC1D,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CACL,MAAM,CAAC,IAAI,KAAK,SAAS;QACzB,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC/B,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,QAAQ;QACjC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,QAAQ;QACjC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,QAAQ;QACjC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,QAAQ;QACjC,OAAO,MAAM,CAAC,SAAS,KAAK,SAAS,CACtC,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,YAAY,EAAE,CAAC;IACf,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,CAAC;IACf,aAAa,EAAE,CAAC;IAChB,kBAAkB,EAAE,EAAE;IACtB,sBAAsB,EAAE,EAAE;CAClB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IAC1C,QAAQ;IACR,MAAM;IACN,SAAS;IACT,WAAW;IACX,UAAU;IACV,SAAS;IACT,UAAU;IACV,kBAAkB;IAClB,eAAe;IACf,QAAQ;IACR,OAAO;IACP,UAAU;IACV,QAAQ;IACR,KAAK;IACL,QAAQ;IACR,YAAY;IACZ,WAAW;CACZ,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IACvC,SAAS;IACT,WAAW;IACX,MAAM;IACN,YAAY;IACZ,MAAM;IACN,UAAU;IACV,OAAO;IACP,QAAQ;IACR,OAAO;IACP,KAAK;IACL,MAAM;IACN,cAAc;IACd,WAAW;CACZ,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IACzC,QAAQ;IACR,YAAY;IACZ,MAAM;IACN,eAAe;IACf,aAAa;IACb,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,aAAa;IACb,SAAS;IACT,SAAS;CACV,CAAC,CAAC"}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import type { Page } from 'puppeteer-core';
|
|
14
14
|
import type { CdpClient } from '../cdp/cdp-client.interface.js';
|
|
15
15
|
import type { BaseSnapshot, SnapshotOptions } from './snapshot.types.js';
|
|
16
|
+
import { type RawNodeData } from './extractors/index.js';
|
|
16
17
|
/**
|
|
17
18
|
* Snapshot compiler options
|
|
18
19
|
*/
|
|
@@ -66,6 +67,19 @@ export declare class SnapshotCompiler {
|
|
|
66
67
|
*/
|
|
67
68
|
private filterNoiseNodes;
|
|
68
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Slice nodes to max_nodes budget while preserving high z-index overlay content.
|
|
72
|
+
*
|
|
73
|
+
* Portal-rendered content (dropdowns, popovers, modals) appears at the end of
|
|
74
|
+
* DOM order. On heavy pages, a naive slice truncates it.
|
|
75
|
+
*
|
|
76
|
+
* Strategy:
|
|
77
|
+
* 1. Partition nodes into overlay (z-index > threshold) and main
|
|
78
|
+
* 2. Take all overlay nodes (up to 30% of budget)
|
|
79
|
+
* 3. Fill remaining budget with main nodes (DOM order)
|
|
80
|
+
* 4. Re-sort by original DOM order
|
|
81
|
+
*/
|
|
82
|
+
export declare function sliceWithOverlayPriority(nodes: RawNodeData[], maxNodes: number): RawNodeData[];
|
|
69
83
|
/**
|
|
70
84
|
* Export a compile function for simpler usage.
|
|
71
85
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot-compiler.d.ts","sourceRoot":"","sources":["../../../src/snapshot/snapshot-compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,KAAK,EACV,YAAY,EAGZ,eAAe,EAMhB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"snapshot-compiler.d.ts","sourceRoot":"","sources":["../../../src/snapshot/snapshot-compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,KAAK,EACV,YAAY,EAGZ,eAAe,EAMhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAYL,KAAK,WAAW,EAOjB,MAAM,uBAAuB,CAAC;AAkS/B;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,OAAO,CAAC,eAAe,CAAC;IAC9D,2EAA2E;IAC3E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,4DAA4D;IAC5D,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAuED;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IAEnD,iDAAiD;IACjD,OAAO,CAAC,eAAe,CAAK;gBAEhB,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;IAI7C;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAK1B;;;;;;;OAOG;IACG,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAuVjF;;OAEG;YACW,iBAAiB;IAe/B;;OAEG;IACH,OAAO,CAAC,aAAa;IAsHrB;;OAEG;IACH,OAAO,CAAC,cAAc;IA2BtB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;CAqGzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CA2C9F;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAChC,OAAO,CAAC,YAAY,CAAC,CAGvB"}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* - CSS: Computed styles (optional, for layout)
|
|
12
12
|
*/
|
|
13
13
|
import { createExtractorContext, extractDom, extractAx, extractLayout, extractState, resolveLabel, resolveRegion, buildLocators, resolveGrouping, classifyAxRole, extractAttributes, } from './extractors/index.js';
|
|
14
|
+
import { detectInteractivity } from './extractors/interactivity-detector.js';
|
|
14
15
|
import { getTextContent } from '../lib/text-utils.js';
|
|
15
16
|
const ROOT_CONTEXT = 'root';
|
|
16
17
|
const LIGHT_DOM_CONTEXT = 'light';
|
|
@@ -463,8 +464,101 @@ export class SnapshotCompiler {
|
|
|
463
464
|
return orderA - orderB;
|
|
464
465
|
});
|
|
465
466
|
}
|
|
466
|
-
//
|
|
467
|
-
|
|
467
|
+
// Phase 2.5: Detect implicit interactivity on non-interactive nodes
|
|
468
|
+
// Also check unincluded AX nodes with unknown classification for interactivity
|
|
469
|
+
const nonInteractiveIds = [];
|
|
470
|
+
const interactiveKindSet = new Set([
|
|
471
|
+
'button',
|
|
472
|
+
'link',
|
|
473
|
+
'input',
|
|
474
|
+
'textarea',
|
|
475
|
+
'select',
|
|
476
|
+
'combobox',
|
|
477
|
+
'checkbox',
|
|
478
|
+
'radio',
|
|
479
|
+
'switch',
|
|
480
|
+
'slider',
|
|
481
|
+
'tab',
|
|
482
|
+
'menuitem',
|
|
483
|
+
]);
|
|
484
|
+
// Collect non-interactive nodes already in nodesToProcess (Case A)
|
|
485
|
+
for (const nodeData of nodesToProcess) {
|
|
486
|
+
const kind = nodeData.axNode?.role
|
|
487
|
+
? (mapRoleToKind(nodeData.axNode.role) ?? 'generic')
|
|
488
|
+
: 'generic';
|
|
489
|
+
if (!interactiveKindSet.has(kind)) {
|
|
490
|
+
nonInteractiveIds.push(nodeData.backendNodeId);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
// Collect unknown-classification AX nodes NOT yet in nodesToProcess (Case B)
|
|
494
|
+
// Cap candidates to bound worst-case CDP call volume on complex pages
|
|
495
|
+
const MAX_CASE_B_CANDIDATES = 200;
|
|
496
|
+
const alreadyIncluded = new Set(nodesToProcess.map((n) => n.backendNodeId));
|
|
497
|
+
const caseB_candidates = [];
|
|
498
|
+
if (axResult) {
|
|
499
|
+
for (const [backendNodeId, axNode] of axResult.nodes) {
|
|
500
|
+
if (alreadyIncluded.has(backendNodeId))
|
|
501
|
+
continue;
|
|
502
|
+
if (caseB_candidates.length >= MAX_CASE_B_CANDIDATES)
|
|
503
|
+
break;
|
|
504
|
+
const classification = classifyAxRole(axNode.role);
|
|
505
|
+
if (classification === 'unknown') {
|
|
506
|
+
caseB_candidates.push(backendNodeId);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
// Run interactivity detection on both sets
|
|
511
|
+
let interactivityMap = new Map();
|
|
512
|
+
const allCandidates = [...nonInteractiveIds, ...caseB_candidates];
|
|
513
|
+
if (allCandidates.length > 0 && domResult) {
|
|
514
|
+
try {
|
|
515
|
+
interactivityMap = await detectInteractivity(ctx, allCandidates, domResult.nodes);
|
|
516
|
+
}
|
|
517
|
+
catch (err) {
|
|
518
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
519
|
+
warnings.push(`Interactivity detection failed: ${message}`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
// Merge interactivity signals into existing nodes (Case A)
|
|
523
|
+
for (const nodeData of nodesToProcess) {
|
|
524
|
+
const signals = interactivityMap.get(nodeData.backendNodeId);
|
|
525
|
+
if (signals) {
|
|
526
|
+
nodeData.interactivity = signals;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
// Add newly discovered interactive nodes (Case B)
|
|
530
|
+
for (const backendNodeId of caseB_candidates) {
|
|
531
|
+
const signals = interactivityMap.get(backendNodeId);
|
|
532
|
+
if (signals) {
|
|
533
|
+
const domNode = domResult?.nodes.get(backendNodeId);
|
|
534
|
+
const axNode = axResult?.nodes.get(backendNodeId);
|
|
535
|
+
nodesToProcess.push({
|
|
536
|
+
backendNodeId,
|
|
537
|
+
domNode,
|
|
538
|
+
axNode,
|
|
539
|
+
interactivity: signals,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// Re-sort if we added Case B nodes (they need to be in DOM order)
|
|
544
|
+
if (caseB_candidates.some((id) => interactivityMap.has(id))) {
|
|
545
|
+
if (domOrderAvailable && domOrderIndex) {
|
|
546
|
+
const orderMap = domOrderIndex;
|
|
547
|
+
nodesToProcess.sort((a, b) => {
|
|
548
|
+
const orderA = orderMap.get(a.backendNodeId);
|
|
549
|
+
const orderB = orderMap.get(b.backendNodeId);
|
|
550
|
+
if (orderA === undefined && orderB === undefined)
|
|
551
|
+
return 0;
|
|
552
|
+
if (orderA === undefined)
|
|
553
|
+
return 1;
|
|
554
|
+
if (orderB === undefined)
|
|
555
|
+
return -1;
|
|
556
|
+
return orderA - orderB;
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
// Limit nodes (now respects DOM order and preserves overlay content)
|
|
561
|
+
const limitedNodes = sliceWithOverlayPriority(nodesToProcess, this.options.max_nodes);
|
|
468
562
|
// Phase 3: Layout extraction (batched)
|
|
469
563
|
let layoutResult;
|
|
470
564
|
if (this.options.includeLayout && limitedNodes.length > 0) {
|
|
@@ -507,7 +601,7 @@ export class SnapshotCompiler {
|
|
|
507
601
|
'slider',
|
|
508
602
|
'tab',
|
|
509
603
|
'menuitem',
|
|
510
|
-
].includes(n.kind)).length;
|
|
604
|
+
].includes(n.kind) || n.implicitly_interactive).length;
|
|
511
605
|
const meta = {
|
|
512
606
|
node_count: nodes.length,
|
|
513
607
|
interactive_count: interactiveCount,
|
|
@@ -628,6 +722,13 @@ export class SnapshotCompiler {
|
|
|
628
722
|
if (attributes && Object.keys(attributes).length > 0) {
|
|
629
723
|
node.attributes = attributes;
|
|
630
724
|
}
|
|
725
|
+
// Set implicitly_interactive flag
|
|
726
|
+
if (nodeData.interactivity) {
|
|
727
|
+
const { has_click_listener, has_cursor_pointer, has_tabindex } = nodeData.interactivity;
|
|
728
|
+
if (has_click_listener || has_cursor_pointer || has_tabindex) {
|
|
729
|
+
node.implicitly_interactive = true;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
631
732
|
return node;
|
|
632
733
|
}
|
|
633
734
|
/**
|
|
@@ -753,6 +854,55 @@ export class SnapshotCompiler {
|
|
|
753
854
|
});
|
|
754
855
|
}
|
|
755
856
|
}
|
|
857
|
+
/**
|
|
858
|
+
* Slice nodes to max_nodes budget while preserving high z-index overlay content.
|
|
859
|
+
*
|
|
860
|
+
* Portal-rendered content (dropdowns, popovers, modals) appears at the end of
|
|
861
|
+
* DOM order. On heavy pages, a naive slice truncates it.
|
|
862
|
+
*
|
|
863
|
+
* Strategy:
|
|
864
|
+
* 1. Partition nodes into overlay (z-index > threshold) and main
|
|
865
|
+
* 2. Take all overlay nodes (up to 30% of budget)
|
|
866
|
+
* 3. Fill remaining budget with main nodes (DOM order)
|
|
867
|
+
* 4. Re-sort by original DOM order
|
|
868
|
+
*/
|
|
869
|
+
export function sliceWithOverlayPriority(nodes, maxNodes) {
|
|
870
|
+
if (nodes.length <= maxNodes) {
|
|
871
|
+
return nodes;
|
|
872
|
+
}
|
|
873
|
+
const OVERLAY_Z_THRESHOLD = 100;
|
|
874
|
+
const MAX_OVERLAY_RATIO = 0.3;
|
|
875
|
+
const overlayNodes = [];
|
|
876
|
+
const mainNodes = [];
|
|
877
|
+
for (const node of nodes) {
|
|
878
|
+
const zIndex = node.layout?.zIndex;
|
|
879
|
+
if (zIndex !== undefined && zIndex > OVERLAY_Z_THRESHOLD) {
|
|
880
|
+
overlayNodes.push(node);
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
mainNodes.push(node);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
// No overlay content → simple slice
|
|
887
|
+
if (overlayNodes.length === 0) {
|
|
888
|
+
return nodes.slice(0, maxNodes);
|
|
889
|
+
}
|
|
890
|
+
// Reserve budget for overlay (capped at 30% of total)
|
|
891
|
+
const maxOverlay = Math.min(overlayNodes.length, Math.floor(maxNodes * MAX_OVERLAY_RATIO));
|
|
892
|
+
const overlaySlice = overlayNodes.slice(0, maxOverlay);
|
|
893
|
+
// Fill remaining budget with main content
|
|
894
|
+
const mainBudget = maxNodes - overlaySlice.length;
|
|
895
|
+
const mainSlice = mainNodes.slice(0, mainBudget);
|
|
896
|
+
// Merge and re-sort by original DOM order
|
|
897
|
+
const merged = [...mainSlice, ...overlaySlice];
|
|
898
|
+
const indexMap = new Map(nodes.map((n, i) => [n.backendNodeId, i]));
|
|
899
|
+
merged.sort((a, b) => {
|
|
900
|
+
const ia = indexMap.get(a.backendNodeId) ?? Infinity;
|
|
901
|
+
const ib = indexMap.get(b.backendNodeId) ?? Infinity;
|
|
902
|
+
return ia - ib;
|
|
903
|
+
});
|
|
904
|
+
return merged;
|
|
905
|
+
}
|
|
756
906
|
/**
|
|
757
907
|
* Export a compile function for simpler usage.
|
|
758
908
|
*/
|