@ubio/webvision 2.6.6 → 3.0.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/build/global.js +253 -248
- package/build/global.js.map +3 -3
- package/build/page.mjs +253 -248
- package/out/page/dom.d.ts +2 -0
- package/out/page/dom.js +18 -0
- package/out/page/dom.js.map +1 -1
- package/out/page/highlight.d.ts +8 -1
- package/out/page/highlight.js +3 -2
- package/out/page/highlight.js.map +1 -1
- package/out/page/index.d.ts +1 -2
- package/out/page/index.js +1 -2
- package/out/page/index.js.map +1 -1
- package/out/page/page.d.ts +16 -0
- package/out/page/page.js +67 -0
- package/out/page/page.js.map +1 -0
- package/out/page/parser.d.ts +7 -8
- package/out/page/parser.js +35 -26
- package/out/page/parser.js.map +1 -1
- package/out/page/snapshot.d.ts +2 -2
- package/out/page/snapshot.js +2 -2
- package/out/page/snapshot.js.map +1 -1
- package/out/page/tree.d.ts +9 -13
- package/out/page/tree.js +12 -3
- package/out/page/tree.js.map +1 -1
- package/package.json +1 -1
- package/out/page/counter.d.ts +0 -6
- package/out/page/counter.js +0 -13
- package/out/page/counter.js.map +0 -1
- package/out/page/frame.d.ts +0 -27
- package/out/page/frame.js +0 -85
- package/out/page/frame.js.map +0 -1
package/build/global.js
CHANGED
|
@@ -21,7 +21,6 @@ var WebVision = (() => {
|
|
|
21
21
|
// src/page/index.ts
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
|
-
Counter: () => Counter,
|
|
25
24
|
INTERACTIVE_ROLES: () => INTERACTIVE_ROLES,
|
|
26
25
|
INTERACTIVE_TAGS: () => INTERACTIVE_TAGS,
|
|
27
26
|
PointSet: () => PointSet,
|
|
@@ -44,6 +43,7 @@ var WebVision = (() => {
|
|
|
44
43
|
containsSelector: () => containsSelector,
|
|
45
44
|
escapeAttribute: () => escapeAttribute,
|
|
46
45
|
fixZIndex: () => fixZIndex,
|
|
46
|
+
getElementDepth: () => getElementDepth,
|
|
47
47
|
getNormalizedText: () => getNormalizedText,
|
|
48
48
|
getOffsetTop: () => getOffsetTop,
|
|
49
49
|
getOverlayContainer: () => getOverlayContainer,
|
|
@@ -63,26 +63,13 @@ var WebVision = (() => {
|
|
|
63
63
|
probeViewport: () => probeViewport,
|
|
64
64
|
renderVxNode: () => renderVxNode,
|
|
65
65
|
resolveDomNode: () => resolveDomNode,
|
|
66
|
+
serializeElement: () => serializeElement,
|
|
66
67
|
showPoint: () => showPoint,
|
|
67
68
|
traverseElements: () => traverseElements,
|
|
68
69
|
traverseVxNode: () => traverseVxNode,
|
|
69
70
|
truncateAttrValue: () => truncateAttrValue
|
|
70
71
|
});
|
|
71
72
|
|
|
72
|
-
// src/page/counter.ts
|
|
73
|
-
var Counter = class {
|
|
74
|
-
constructor(value = 0) {
|
|
75
|
-
this.value = value;
|
|
76
|
-
}
|
|
77
|
-
next() {
|
|
78
|
-
this.value += 1;
|
|
79
|
-
return this.value;
|
|
80
|
-
}
|
|
81
|
-
current() {
|
|
82
|
-
return this.value;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
|
|
86
73
|
// src/page/dom.ts
|
|
87
74
|
var ORIGINAL_STYLE_SYMBOL = Symbol("vx:originalStyle");
|
|
88
75
|
var INTERACTIVE_TAGS = ["a", "button", "input", "textarea", "select", "label", "option", "optgroup"];
|
|
@@ -269,6 +256,24 @@ var WebVision = (() => {
|
|
|
269
256
|
}
|
|
270
257
|
}
|
|
271
258
|
}
|
|
259
|
+
function getElementDepth(el) {
|
|
260
|
+
let depth = 0;
|
|
261
|
+
while (el.parentElement) {
|
|
262
|
+
el = el.parentElement;
|
|
263
|
+
depth += 1;
|
|
264
|
+
}
|
|
265
|
+
return depth;
|
|
266
|
+
}
|
|
267
|
+
function serializeElement(el) {
|
|
268
|
+
const sig = [];
|
|
269
|
+
const depth = getElementDepth(el);
|
|
270
|
+
sig.push(String(depth));
|
|
271
|
+
sig.push(el.tagName);
|
|
272
|
+
for (const attr of el.attributes) {
|
|
273
|
+
sig.push(`${attr.name}=${attr.value}`);
|
|
274
|
+
}
|
|
275
|
+
return sig.join("|");
|
|
276
|
+
}
|
|
272
277
|
|
|
273
278
|
// src/page/traverse.ts
|
|
274
279
|
function* traverseVxNode(vxNode, depth = 0) {
|
|
@@ -351,6 +356,186 @@ var WebVision = (() => {
|
|
|
351
356
|
return !Object.values(obj).some((value) => !!value);
|
|
352
357
|
}
|
|
353
358
|
|
|
359
|
+
// src/page/render.ts
|
|
360
|
+
function renderVxNode(scope, options = {}) {
|
|
361
|
+
const buffer = [];
|
|
362
|
+
for (const { vxNode, depth } of traverseVxNode(scope)) {
|
|
363
|
+
if (options.skipNonInteractive && !vxNode.isInteractive) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
const indent = options.skipNonInteractive ? "" : " ".repeat(depth);
|
|
367
|
+
buffer.push(renderIndentedLine(indent, vxNode, options));
|
|
368
|
+
}
|
|
369
|
+
return buffer.join("\n");
|
|
370
|
+
}
|
|
371
|
+
function renderIndentedLine(indent, vxNode, options = {}) {
|
|
372
|
+
const diffPrefix = options.renderDiff ? vxNode.isNew ? "+ " : " " : "";
|
|
373
|
+
if (!vxNode.tagName) {
|
|
374
|
+
return [diffPrefix, indent, vxNode.textContent].filter(Boolean).join("");
|
|
375
|
+
}
|
|
376
|
+
const tagLine = renderTagLine(vxNode, options);
|
|
377
|
+
const htmlStyle = options.renderStyle === "html";
|
|
378
|
+
return [
|
|
379
|
+
diffPrefix,
|
|
380
|
+
indent,
|
|
381
|
+
tagLine,
|
|
382
|
+
htmlStyle ? "" : " ",
|
|
383
|
+
vxNode.textContent ?? ""
|
|
384
|
+
].join("");
|
|
385
|
+
}
|
|
386
|
+
function renderTagLine(vxNode, options) {
|
|
387
|
+
const htmlStyle = options.renderStyle === "html";
|
|
388
|
+
const components = [];
|
|
389
|
+
if (options.renderTagNames && vxNode.tagName) {
|
|
390
|
+
components.push(vxNode.tagName);
|
|
391
|
+
}
|
|
392
|
+
if (options.renderIds && vxNode.id) {
|
|
393
|
+
if (htmlStyle) {
|
|
394
|
+
components.push(`id="${vxNode.id}"`);
|
|
395
|
+
} else {
|
|
396
|
+
components.push(`#${vxNode.id}`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (options.renderClassNames && vxNode.classList?.length) {
|
|
400
|
+
if (htmlStyle) {
|
|
401
|
+
components.push(`class="${vxNode.classList.join(" ")}"`);
|
|
402
|
+
} else {
|
|
403
|
+
components.push("." + vxNode.classList.join("."));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (options.renderRefs) {
|
|
407
|
+
const isRenderRef = [
|
|
408
|
+
options.renderRefs === "all",
|
|
409
|
+
options.renderRefs === true && !isContainerNode(vxNode)
|
|
410
|
+
].some(Boolean);
|
|
411
|
+
if (isRenderRef) {
|
|
412
|
+
components.push(`[@${vxNode.ref}]`);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const attrs = [];
|
|
416
|
+
if (options.renderLabelAttrs) {
|
|
417
|
+
for (const [attr, value] of Object.entries(vxNode.labelAttrs ?? {})) {
|
|
418
|
+
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (options.renderValueAttrs) {
|
|
422
|
+
for (const [attr, value] of Object.entries(vxNode.valueAttrs ?? {})) {
|
|
423
|
+
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (options.renderSrcAttrs) {
|
|
427
|
+
for (const [attr, value] of Object.entries(vxNode.srcAttrs ?? {})) {
|
|
428
|
+
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (htmlStyle) {
|
|
432
|
+
components.push(...attrs);
|
|
433
|
+
} else {
|
|
434
|
+
components.push(...attrs.map((attr) => `[${attr}]`));
|
|
435
|
+
}
|
|
436
|
+
return htmlStyle ? `<${components.join(" ")}>` : components.join("");
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/page/snapshot.ts
|
|
440
|
+
var VX_DOM_SYMBOL = Symbol("vx:dom");
|
|
441
|
+
var VX_TREE_SYMBOL = Symbol("vx:tree");
|
|
442
|
+
var VX_LAST_REFS_SYMBOL = Symbol("vx:lastRefs");
|
|
443
|
+
async function captureSnapshot(options = {}) {
|
|
444
|
+
const parser = new VxTreeParser(options);
|
|
445
|
+
const domMap = parser.getDomMap();
|
|
446
|
+
const vxTree = parser.getTree(options.frameId ?? "0", options.iframeRef);
|
|
447
|
+
globalThis[VX_DOM_SYMBOL] = domMap;
|
|
448
|
+
globalThis[VX_TREE_SYMBOL] = vxTree;
|
|
449
|
+
return vxTree;
|
|
450
|
+
}
|
|
451
|
+
function getSnapshot() {
|
|
452
|
+
const vxTree = globalThis[VX_TREE_SYMBOL];
|
|
453
|
+
if (!vxTree) {
|
|
454
|
+
throw new Error("[VX] Snapshot not found");
|
|
455
|
+
}
|
|
456
|
+
return vxTree;
|
|
457
|
+
}
|
|
458
|
+
function resolveDomNode(ref) {
|
|
459
|
+
const domMap = globalThis[VX_DOM_SYMBOL];
|
|
460
|
+
if (!domMap) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
return domMap.get(ref) ?? null;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// src/page/tree.ts
|
|
467
|
+
var VxTreeView = class {
|
|
468
|
+
constructor(nodes, frameId, iframeRef) {
|
|
469
|
+
this.nodes = nodes;
|
|
470
|
+
this.frameId = frameId;
|
|
471
|
+
this.iframeRef = iframeRef;
|
|
472
|
+
this.refMap = /* @__PURE__ */ new Map();
|
|
473
|
+
this.buildRefMap(nodes);
|
|
474
|
+
}
|
|
475
|
+
get nodeCount() {
|
|
476
|
+
return this.refMap.size;
|
|
477
|
+
}
|
|
478
|
+
*traverse() {
|
|
479
|
+
for (const vxNode of this.nodes) {
|
|
480
|
+
yield* traverseVxNode(vxNode, 0);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
buildRefMap(nodes) {
|
|
484
|
+
for (const node of nodes) {
|
|
485
|
+
if (node.ref) {
|
|
486
|
+
this.refMap.set(node.ref, node);
|
|
487
|
+
}
|
|
488
|
+
this.buildRefMap(node.children ?? []);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
hasRef(ref) {
|
|
492
|
+
return this.refMap.has(ref);
|
|
493
|
+
}
|
|
494
|
+
findNode(ref) {
|
|
495
|
+
return this.refMap.get(ref) ?? null;
|
|
496
|
+
}
|
|
497
|
+
render(options = {}) {
|
|
498
|
+
return this.nodes.map((node) => {
|
|
499
|
+
return renderVxNode(node, options);
|
|
500
|
+
}).join("\n");
|
|
501
|
+
}
|
|
502
|
+
highlight(options = {}) {
|
|
503
|
+
if (options.clearOverlay) {
|
|
504
|
+
clearOverlay();
|
|
505
|
+
}
|
|
506
|
+
const leafOnly = !options.includeAll;
|
|
507
|
+
const refs = this.collectRefs(leafOnly, options.filterRefs);
|
|
508
|
+
this.highlightRefs(refs, options);
|
|
509
|
+
}
|
|
510
|
+
highlightRefs(refs, options = {}) {
|
|
511
|
+
for (const ref of refs) {
|
|
512
|
+
const el = resolveDomNode(ref);
|
|
513
|
+
if (el instanceof Element) {
|
|
514
|
+
const vxNode = this.findNode(ref);
|
|
515
|
+
const isNew = vxNode?.isNew ?? false;
|
|
516
|
+
const color = options.useColors ? void 0 : isNew ? "#0a0" : "#060";
|
|
517
|
+
highlightEl(el, ref, color);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
collectRefs(leafOnly = true, filterRefs) {
|
|
522
|
+
const refs = [];
|
|
523
|
+
for (const { vxNode } of this.traverse()) {
|
|
524
|
+
if (!vxNode.ref) {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
if (leafOnly && isContainerNode(vxNode)) {
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
if (filterRefs && !filterRefs.includes(vxNode.ref)) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
refs.push(vxNode.ref);
|
|
534
|
+
}
|
|
535
|
+
return refs;
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
354
539
|
// src/page/parser.ts
|
|
355
540
|
var VX_NODE_SYMBOL = Symbol("vx:node");
|
|
356
541
|
var VX_IGNORE_SYMBOL = Symbol("vx:ignore");
|
|
@@ -422,41 +607,36 @@ var WebVision = (() => {
|
|
|
422
607
|
var VxTreeParser = class {
|
|
423
608
|
constructor(options = {}) {
|
|
424
609
|
this.options = options;
|
|
610
|
+
this.viewport = { width: 0, height: 0 };
|
|
611
|
+
this.vxNodes = [];
|
|
425
612
|
this.probeElements = [];
|
|
426
613
|
this.domRefMap = /* @__PURE__ */ new Map();
|
|
427
|
-
|
|
614
|
+
}
|
|
615
|
+
async parse() {
|
|
428
616
|
this.viewport = getViewportSize();
|
|
429
|
-
this.
|
|
430
|
-
if (options.probeViewport) {
|
|
617
|
+
if (this.options.probeViewport) {
|
|
431
618
|
this.probeElements = probeViewport();
|
|
432
619
|
}
|
|
433
|
-
const vxRoot = this.
|
|
434
|
-
this.refRange = [startRef, this.counter.current()];
|
|
620
|
+
const vxRoot = await this.parseNode(document.documentElement, null);
|
|
435
621
|
this.vxNodes = this.pruneRecursive(vxRoot);
|
|
436
622
|
}
|
|
437
|
-
|
|
438
|
-
return this.
|
|
439
|
-
}
|
|
440
|
-
getTree() {
|
|
441
|
-
return new VxTreeView(this.vxNodes, this.refRange);
|
|
623
|
+
getTree(frameId, iframeRef) {
|
|
624
|
+
return new VxTreeView(this.vxNodes, frameId, iframeRef);
|
|
442
625
|
}
|
|
443
626
|
getNodes() {
|
|
444
627
|
return this.vxNodes;
|
|
445
628
|
}
|
|
446
|
-
getRefRange() {
|
|
447
|
-
return this.refRange;
|
|
448
|
-
}
|
|
449
629
|
getDomMap() {
|
|
450
630
|
return this.domRefMap;
|
|
451
631
|
}
|
|
452
|
-
parseNode(node, parent) {
|
|
632
|
+
async parseNode(node, parent) {
|
|
453
633
|
if (!node || node[VX_IGNORE_SYMBOL]) {
|
|
454
634
|
return null;
|
|
455
635
|
}
|
|
456
636
|
if (node instanceof Text) {
|
|
457
637
|
const textContent = normalizeText(node.textContent ?? "");
|
|
458
638
|
if (textContent) {
|
|
459
|
-
return this.makeNode(node, {
|
|
639
|
+
return await this.makeNode(node, {
|
|
460
640
|
textContent,
|
|
461
641
|
hasVisibleArea: parent?.hasVisibleArea,
|
|
462
642
|
isOutsideViewport: parent?.isOutsideViewport,
|
|
@@ -469,11 +649,11 @@ var WebVision = (() => {
|
|
|
469
649
|
if (this.options.opaqueOverlays) {
|
|
470
650
|
makeOverlaysOpaque(node);
|
|
471
651
|
}
|
|
472
|
-
return this.parseElement(node);
|
|
652
|
+
return await this.parseElement(node);
|
|
473
653
|
}
|
|
474
654
|
return null;
|
|
475
655
|
}
|
|
476
|
-
parseElement(el) {
|
|
656
|
+
async parseElement(el) {
|
|
477
657
|
const skip = VX_IGNORE_TAGS.includes(el.tagName.toLowerCase()) || isHidden(el);
|
|
478
658
|
if (skip) {
|
|
479
659
|
this.clearRecursive(el);
|
|
@@ -482,7 +662,7 @@ var WebVision = (() => {
|
|
|
482
662
|
const parentEl = el.matches("option, optgroup") ? el.closest("select") ?? el : el;
|
|
483
663
|
const rect = parentEl.getBoundingClientRect();
|
|
484
664
|
const id = el.getAttribute("id") ?? "";
|
|
485
|
-
const vxNode = this.makeNode(el, {
|
|
665
|
+
const vxNode = await this.makeNode(el, {
|
|
486
666
|
tagName: el.tagName.toLowerCase(),
|
|
487
667
|
id: isRandomIdentifier(id) ? void 0 : id,
|
|
488
668
|
classList: Array.from(el.classList).filter((cls) => !isRandomIdentifier(cls)).slice(0, 4),
|
|
@@ -495,7 +675,13 @@ var WebVision = (() => {
|
|
|
495
675
|
isProbeHit: this.isProbeHit(parentEl),
|
|
496
676
|
isKept: el.matches(VX_KEEP_SELECTOR)
|
|
497
677
|
});
|
|
498
|
-
const children = [
|
|
678
|
+
const children = [];
|
|
679
|
+
for (const child of el.childNodes) {
|
|
680
|
+
const childNode = await this.parseNode(child, vxNode);
|
|
681
|
+
if (childNode != null) {
|
|
682
|
+
children.push(childNode);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
499
685
|
if (children.length === 1 && !children[0]?.tagName) {
|
|
500
686
|
vxNode.textContent = normalizeText(children[0].textContent ?? "");
|
|
501
687
|
} else {
|
|
@@ -503,15 +689,17 @@ var WebVision = (() => {
|
|
|
503
689
|
}
|
|
504
690
|
return vxNode;
|
|
505
691
|
}
|
|
506
|
-
makeNode(node, spec) {
|
|
507
|
-
const ref = this.counter.next();
|
|
692
|
+
async makeNode(node, spec) {
|
|
508
693
|
const isNew = !node[VX_NODE_SYMBOL];
|
|
694
|
+
const ref = await this.createRef(node);
|
|
509
695
|
const vxNode = {
|
|
510
696
|
...spec,
|
|
511
697
|
ref,
|
|
512
698
|
isNew
|
|
513
699
|
};
|
|
514
|
-
|
|
700
|
+
if (ref) {
|
|
701
|
+
this.domRefMap.set(ref, node);
|
|
702
|
+
}
|
|
515
703
|
node[VX_NODE_SYMBOL] = vxNode;
|
|
516
704
|
return vxNode;
|
|
517
705
|
}
|
|
@@ -649,6 +837,13 @@ var WebVision = (() => {
|
|
|
649
837
|
}
|
|
650
838
|
}
|
|
651
839
|
}
|
|
840
|
+
async createRef(node) {
|
|
841
|
+
if (node instanceof Element) {
|
|
842
|
+
const sig = serializeElement(node);
|
|
843
|
+
const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(sig).buffer);
|
|
844
|
+
return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, "0")).join("").substring(0, 8);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
652
847
|
};
|
|
653
848
|
|
|
654
849
|
// src/page/overlay.ts
|
|
@@ -692,7 +887,7 @@ var WebVision = (() => {
|
|
|
692
887
|
}
|
|
693
888
|
|
|
694
889
|
// src/page/highlight.ts
|
|
695
|
-
function highlightEl(el, ref
|
|
890
|
+
function highlightEl(el, ref, color) {
|
|
696
891
|
if (!(el instanceof Element)) {
|
|
697
892
|
return;
|
|
698
893
|
}
|
|
@@ -728,191 +923,18 @@ var WebVision = (() => {
|
|
|
728
923
|
label.style.transform = "translateY(50%)";
|
|
729
924
|
label.textContent = String(ref);
|
|
730
925
|
}
|
|
731
|
-
function getRandomColor(
|
|
926
|
+
function getRandomColor(ref) {
|
|
927
|
+
const index = ref.charCodeAt(0);
|
|
732
928
|
const hue = index * 120 * 0.382 % 360;
|
|
733
929
|
return `hsl(${hue}, 85%, 50%)`;
|
|
734
930
|
}
|
|
735
931
|
|
|
736
|
-
// src/page/
|
|
737
|
-
function renderVxNode(scope, options = {}) {
|
|
738
|
-
const buffer = [];
|
|
739
|
-
for (const { vxNode, depth } of traverseVxNode(scope)) {
|
|
740
|
-
if (options.skipNonInteractive && !vxNode.isInteractive) {
|
|
741
|
-
continue;
|
|
742
|
-
}
|
|
743
|
-
const indent = options.skipNonInteractive ? "" : " ".repeat(depth);
|
|
744
|
-
buffer.push(renderIndentedLine(indent, vxNode, options));
|
|
745
|
-
}
|
|
746
|
-
return buffer.join("\n");
|
|
747
|
-
}
|
|
748
|
-
function renderIndentedLine(indent, vxNode, options = {}) {
|
|
749
|
-
const diffPrefix = options.renderDiff ? vxNode.isNew ? "+ " : " " : "";
|
|
750
|
-
if (!vxNode.tagName) {
|
|
751
|
-
return [diffPrefix, indent, vxNode.textContent].filter(Boolean).join("");
|
|
752
|
-
}
|
|
753
|
-
const tagLine = renderTagLine(vxNode, options);
|
|
754
|
-
const htmlStyle = options.renderStyle === "html";
|
|
755
|
-
return [
|
|
756
|
-
diffPrefix,
|
|
757
|
-
indent,
|
|
758
|
-
tagLine,
|
|
759
|
-
htmlStyle ? "" : " ",
|
|
760
|
-
vxNode.textContent ?? ""
|
|
761
|
-
].join("");
|
|
762
|
-
}
|
|
763
|
-
function renderTagLine(vxNode, options) {
|
|
764
|
-
const htmlStyle = options.renderStyle === "html";
|
|
765
|
-
const components = [];
|
|
766
|
-
if (options.renderTagNames && vxNode.tagName) {
|
|
767
|
-
components.push(vxNode.tagName);
|
|
768
|
-
}
|
|
769
|
-
if (options.renderIds && vxNode.id) {
|
|
770
|
-
if (htmlStyle) {
|
|
771
|
-
components.push(`id="${vxNode.id}"`);
|
|
772
|
-
} else {
|
|
773
|
-
components.push(`#${vxNode.id}`);
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
if (options.renderClassNames && vxNode.classList?.length) {
|
|
777
|
-
if (htmlStyle) {
|
|
778
|
-
components.push(`class="${vxNode.classList.join(" ")}"`);
|
|
779
|
-
} else {
|
|
780
|
-
components.push("." + vxNode.classList.join("."));
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
if (options.renderRefs) {
|
|
784
|
-
const isRenderRef = [
|
|
785
|
-
options.renderRefs === "all",
|
|
786
|
-
options.renderRefs === true && !isContainerNode(vxNode)
|
|
787
|
-
].some(Boolean);
|
|
788
|
-
if (isRenderRef) {
|
|
789
|
-
components.push(`[@${vxNode.ref}]`);
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
const attrs = [];
|
|
793
|
-
if (options.renderLabelAttrs) {
|
|
794
|
-
for (const [attr, value] of Object.entries(vxNode.labelAttrs ?? {})) {
|
|
795
|
-
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
if (options.renderValueAttrs) {
|
|
799
|
-
for (const [attr, value] of Object.entries(vxNode.valueAttrs ?? {})) {
|
|
800
|
-
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
if (options.renderSrcAttrs) {
|
|
804
|
-
for (const [attr, value] of Object.entries(vxNode.srcAttrs ?? {})) {
|
|
805
|
-
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
if (htmlStyle) {
|
|
809
|
-
components.push(...attrs);
|
|
810
|
-
} else {
|
|
811
|
-
components.push(...attrs.map((attr) => `[${attr}]`));
|
|
812
|
-
}
|
|
813
|
-
return htmlStyle ? `<${components.join(" ")}>` : components.join("");
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
// src/page/snapshot.ts
|
|
817
|
-
var VX_DOM_SYMBOL = Symbol("vx:dom");
|
|
818
|
-
var VX_TREE_SYMBOL = Symbol("vx:tree");
|
|
819
|
-
var VX_LAST_REFS_SYMBOL = Symbol("vx:lastRefs");
|
|
820
|
-
function captureSnapshot(options = {}) {
|
|
821
|
-
const parser = new VxTreeParser(options);
|
|
822
|
-
const domMap = parser.getDomMap();
|
|
823
|
-
const vxTree = parser.getTree();
|
|
824
|
-
globalThis[VX_DOM_SYMBOL] = domMap;
|
|
825
|
-
globalThis[VX_TREE_SYMBOL] = vxTree;
|
|
826
|
-
return vxTree;
|
|
827
|
-
}
|
|
828
|
-
function getSnapshot() {
|
|
829
|
-
const vxTree = globalThis[VX_TREE_SYMBOL];
|
|
830
|
-
if (!vxTree) {
|
|
831
|
-
throw new Error("[VX] Snapshot not found");
|
|
832
|
-
}
|
|
833
|
-
return vxTree;
|
|
834
|
-
}
|
|
835
|
-
function resolveDomNode(ref) {
|
|
836
|
-
const domMap = globalThis[VX_DOM_SYMBOL];
|
|
837
|
-
if (!domMap) {
|
|
838
|
-
return null;
|
|
839
|
-
}
|
|
840
|
-
return domMap.get(ref) ?? null;
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
// src/page/tree.ts
|
|
844
|
-
var VxTreeView = class {
|
|
845
|
-
constructor(nodes, refRange) {
|
|
846
|
-
this.nodes = nodes;
|
|
847
|
-
this.refRange = refRange;
|
|
848
|
-
this.refMap = /* @__PURE__ */ new Map();
|
|
849
|
-
this.buildRefMap(nodes);
|
|
850
|
-
}
|
|
851
|
-
get nodeCount() {
|
|
852
|
-
return this.refMap.size;
|
|
853
|
-
}
|
|
854
|
-
*traverse() {
|
|
855
|
-
for (const vxNode of this.nodes) {
|
|
856
|
-
yield* traverseVxNode(vxNode, 0);
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
buildRefMap(nodes) {
|
|
860
|
-
for (const node of nodes) {
|
|
861
|
-
this.refMap.set(node.ref, node);
|
|
862
|
-
this.buildRefMap(node.children ?? []);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
findNode(ref) {
|
|
866
|
-
return this.refMap.get(ref) ?? null;
|
|
867
|
-
}
|
|
868
|
-
render(options = {}) {
|
|
869
|
-
return this.nodes.map((node) => {
|
|
870
|
-
return renderVxNode(node, options);
|
|
871
|
-
}).join("\n");
|
|
872
|
-
}
|
|
873
|
-
highlight(options = {}) {
|
|
874
|
-
if (options.clearOverlay) {
|
|
875
|
-
clearOverlay();
|
|
876
|
-
}
|
|
877
|
-
const leafOnly = !options.includeAll;
|
|
878
|
-
const refs = this.collectRefs(leafOnly, options.filterRefs);
|
|
879
|
-
this.highlightRefs(refs, options);
|
|
880
|
-
}
|
|
881
|
-
highlightRefs(refs, options = {}) {
|
|
882
|
-
for (const ref of refs) {
|
|
883
|
-
const el = resolveDomNode(ref);
|
|
884
|
-
if (el instanceof Element) {
|
|
885
|
-
const vxNode = this.findNode(ref);
|
|
886
|
-
const isNew = vxNode?.isNew ?? false;
|
|
887
|
-
const color = options.useColors ? void 0 : isNew ? "#0a0" : "#060";
|
|
888
|
-
highlightEl(el, ref, color);
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
collectRefs(leafOnly = true, filterRefs) {
|
|
893
|
-
const refs = [];
|
|
894
|
-
for (const { vxNode } of this.traverse()) {
|
|
895
|
-
if (leafOnly && isContainerNode(vxNode)) {
|
|
896
|
-
continue;
|
|
897
|
-
}
|
|
898
|
-
if (filterRefs && !filterRefs.includes(vxNode.ref)) {
|
|
899
|
-
continue;
|
|
900
|
-
}
|
|
901
|
-
refs.push(vxNode.ref);
|
|
902
|
-
}
|
|
903
|
-
return refs;
|
|
904
|
-
}
|
|
905
|
-
};
|
|
906
|
-
|
|
907
|
-
// src/page/frame.ts
|
|
932
|
+
// src/page/page.ts
|
|
908
933
|
var VxPageView = class {
|
|
909
|
-
constructor(
|
|
910
|
-
this.vxFrames = vxFrames;
|
|
911
|
-
this.vxFrameMap = /* @__PURE__ */ new Map();
|
|
934
|
+
constructor(vxTrees) {
|
|
912
935
|
this.vxTreeMap = /* @__PURE__ */ new Map();
|
|
913
|
-
for (const
|
|
914
|
-
this.
|
|
915
|
-
this.vxTreeMap.set(frame.frameId, new VxTreeView(frame.nodes, frame.refRange));
|
|
936
|
+
for (const vxTree of vxTrees) {
|
|
937
|
+
this.vxTreeMap.set(vxTree.frameId, vxTree);
|
|
916
938
|
}
|
|
917
939
|
}
|
|
918
940
|
get vxTrees() {
|
|
@@ -922,43 +944,28 @@ var WebVision = (() => {
|
|
|
922
944
|
return this.vxTrees.reduce((acc, vxTree) => acc + vxTree.nodeCount, 0);
|
|
923
945
|
}
|
|
924
946
|
findNodeByRef(ref) {
|
|
925
|
-
const
|
|
926
|
-
if (
|
|
947
|
+
const frame = this.findFrameByRef(ref);
|
|
948
|
+
if (frame == null) {
|
|
927
949
|
return null;
|
|
928
950
|
}
|
|
929
|
-
return
|
|
951
|
+
return frame.findNode(ref);
|
|
930
952
|
}
|
|
931
|
-
|
|
953
|
+
findFrameById(frameId) {
|
|
932
954
|
return this.vxTreeMap.get(frameId) ?? null;
|
|
933
955
|
}
|
|
934
|
-
findTreeByRef(ref) {
|
|
935
|
-
const vxFrame = this.findFrameByRef(ref);
|
|
936
|
-
if (vxFrame == null) {
|
|
937
|
-
return null;
|
|
938
|
-
}
|
|
939
|
-
return this.vxTreeMap.get(vxFrame.frameId) ?? null;
|
|
940
|
-
}
|
|
941
|
-
findFrameByFrameId(frameId) {
|
|
942
|
-
return this.vxFrameMap.get(frameId) ?? null;
|
|
943
|
-
}
|
|
944
956
|
findFrameByRef(ref) {
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
);
|
|
948
|
-
if (!vxFrame) {
|
|
949
|
-
return null;
|
|
950
|
-
}
|
|
951
|
-
return this.vxFrameMap.get(vxFrame.frameId) ?? null;
|
|
957
|
+
const frame = this.vxTrees.find((f) => f.hasRef(ref));
|
|
958
|
+
return frame ?? null;
|
|
952
959
|
}
|
|
953
960
|
getFrameByRef(ref) {
|
|
954
|
-
const
|
|
955
|
-
if (
|
|
961
|
+
const frame = this.findFrameByRef(ref);
|
|
962
|
+
if (frame == null) {
|
|
956
963
|
throw new Error(`[VX] Frame not found for [ref=${ref}]`);
|
|
957
964
|
}
|
|
958
|
-
return
|
|
965
|
+
return frame;
|
|
959
966
|
}
|
|
960
967
|
findParentFrame(frameId) {
|
|
961
|
-
const frame = this.
|
|
968
|
+
const frame = this.findFrameById(frameId);
|
|
962
969
|
const iframeRef = frame?.iframeRef;
|
|
963
970
|
if (iframeRef == null) {
|
|
964
971
|
return null;
|
|
@@ -966,7 +973,7 @@ var WebVision = (() => {
|
|
|
966
973
|
return this.findFrameByRef(iframeRef);
|
|
967
974
|
}
|
|
968
975
|
isFrameShown(frameId) {
|
|
969
|
-
const frame = this.
|
|
976
|
+
const frame = this.findFrameById(frameId);
|
|
970
977
|
if (!frame) {
|
|
971
978
|
return false;
|
|
972
979
|
}
|
|
@@ -975,14 +982,12 @@ var WebVision = (() => {
|
|
|
975
982
|
if (parentFrame == null || iframeRef == null) {
|
|
976
983
|
return true;
|
|
977
984
|
}
|
|
978
|
-
const
|
|
979
|
-
const existsInParent = !!vxTree?.findNode(iframeRef);
|
|
985
|
+
const existsInParent = !!parentFrame.findNode(iframeRef);
|
|
980
986
|
return existsInParent ? this.isFrameShown(parentFrame.frameId) : false;
|
|
981
987
|
}
|
|
982
988
|
renderAll(options) {
|
|
983
|
-
return this.
|
|
984
|
-
const
|
|
985
|
-
const rendered = vxTree?.render(options);
|
|
989
|
+
return this.vxTrees.map((frame) => {
|
|
990
|
+
const rendered = frame?.render(options);
|
|
986
991
|
return [
|
|
987
992
|
`FRAME ${frame.frameId}${frame.iframeRef ? ` [@${frame.iframeRef}]` : ""}`,
|
|
988
993
|
rendered
|