@ubio/webvision 2.6.5 → 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 -254
- package/build/global.js.map +3 -3
- package/build/page.mjs +253 -254
- 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/render.d.ts +0 -1
- package/out/page/render.js +0 -6
- package/out/page/render.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,197 +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
|
-
const whitelistRefs = options.whitelistRefs ?? [];
|
|
740
|
-
for (const { vxNode, depth } of traverseVxNode(scope)) {
|
|
741
|
-
if (whitelistRefs.length > 0) {
|
|
742
|
-
if (!whitelistRefs.includes(vxNode.ref)) {
|
|
743
|
-
continue;
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
if (options.skipNonInteractive && !vxNode.isInteractive) {
|
|
747
|
-
continue;
|
|
748
|
-
}
|
|
749
|
-
const indent = options.skipNonInteractive ? "" : " ".repeat(depth);
|
|
750
|
-
buffer.push(renderIndentedLine(indent, vxNode, options));
|
|
751
|
-
}
|
|
752
|
-
return buffer.join("\n");
|
|
753
|
-
}
|
|
754
|
-
function renderIndentedLine(indent, vxNode, options = {}) {
|
|
755
|
-
const diffPrefix = options.renderDiff ? vxNode.isNew ? "+ " : " " : "";
|
|
756
|
-
if (!vxNode.tagName) {
|
|
757
|
-
return [diffPrefix, indent, vxNode.textContent].filter(Boolean).join("");
|
|
758
|
-
}
|
|
759
|
-
const tagLine = renderTagLine(vxNode, options);
|
|
760
|
-
const htmlStyle = options.renderStyle === "html";
|
|
761
|
-
return [
|
|
762
|
-
diffPrefix,
|
|
763
|
-
indent,
|
|
764
|
-
tagLine,
|
|
765
|
-
htmlStyle ? "" : " ",
|
|
766
|
-
vxNode.textContent ?? ""
|
|
767
|
-
].join("");
|
|
768
|
-
}
|
|
769
|
-
function renderTagLine(vxNode, options) {
|
|
770
|
-
const htmlStyle = options.renderStyle === "html";
|
|
771
|
-
const components = [];
|
|
772
|
-
if (options.renderTagNames && vxNode.tagName) {
|
|
773
|
-
components.push(vxNode.tagName);
|
|
774
|
-
}
|
|
775
|
-
if (options.renderIds && vxNode.id) {
|
|
776
|
-
if (htmlStyle) {
|
|
777
|
-
components.push(`id="${vxNode.id}"`);
|
|
778
|
-
} else {
|
|
779
|
-
components.push(`#${vxNode.id}`);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
if (options.renderClassNames && vxNode.classList?.length) {
|
|
783
|
-
if (htmlStyle) {
|
|
784
|
-
components.push(`class="${vxNode.classList.join(" ")}"`);
|
|
785
|
-
} else {
|
|
786
|
-
components.push("." + vxNode.classList.join("."));
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
if (options.renderRefs) {
|
|
790
|
-
const isRenderRef = [
|
|
791
|
-
options.renderRefs === "all",
|
|
792
|
-
options.renderRefs === true && !isContainerNode(vxNode)
|
|
793
|
-
].some(Boolean);
|
|
794
|
-
if (isRenderRef) {
|
|
795
|
-
components.push(`[@${vxNode.ref}]`);
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
const attrs = [];
|
|
799
|
-
if (options.renderLabelAttrs) {
|
|
800
|
-
for (const [attr, value] of Object.entries(vxNode.labelAttrs ?? {})) {
|
|
801
|
-
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
if (options.renderValueAttrs) {
|
|
805
|
-
for (const [attr, value] of Object.entries(vxNode.valueAttrs ?? {})) {
|
|
806
|
-
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
if (options.renderSrcAttrs) {
|
|
810
|
-
for (const [attr, value] of Object.entries(vxNode.srcAttrs ?? {})) {
|
|
811
|
-
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
if (htmlStyle) {
|
|
815
|
-
components.push(...attrs);
|
|
816
|
-
} else {
|
|
817
|
-
components.push(...attrs.map((attr) => `[${attr}]`));
|
|
818
|
-
}
|
|
819
|
-
return htmlStyle ? `<${components.join(" ")}>` : components.join("");
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
// src/page/snapshot.ts
|
|
823
|
-
var VX_DOM_SYMBOL = Symbol("vx:dom");
|
|
824
|
-
var VX_TREE_SYMBOL = Symbol("vx:tree");
|
|
825
|
-
var VX_LAST_REFS_SYMBOL = Symbol("vx:lastRefs");
|
|
826
|
-
function captureSnapshot(options = {}) {
|
|
827
|
-
const parser = new VxTreeParser(options);
|
|
828
|
-
const domMap = parser.getDomMap();
|
|
829
|
-
const vxTree = parser.getTree();
|
|
830
|
-
globalThis[VX_DOM_SYMBOL] = domMap;
|
|
831
|
-
globalThis[VX_TREE_SYMBOL] = vxTree;
|
|
832
|
-
return vxTree;
|
|
833
|
-
}
|
|
834
|
-
function getSnapshot() {
|
|
835
|
-
const vxTree = globalThis[VX_TREE_SYMBOL];
|
|
836
|
-
if (!vxTree) {
|
|
837
|
-
throw new Error("[VX] Snapshot not found");
|
|
838
|
-
}
|
|
839
|
-
return vxTree;
|
|
840
|
-
}
|
|
841
|
-
function resolveDomNode(ref) {
|
|
842
|
-
const domMap = globalThis[VX_DOM_SYMBOL];
|
|
843
|
-
if (!domMap) {
|
|
844
|
-
return null;
|
|
845
|
-
}
|
|
846
|
-
return domMap.get(ref) ?? null;
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
// src/page/tree.ts
|
|
850
|
-
var VxTreeView = class {
|
|
851
|
-
constructor(nodes, refRange) {
|
|
852
|
-
this.nodes = nodes;
|
|
853
|
-
this.refRange = refRange;
|
|
854
|
-
this.refMap = /* @__PURE__ */ new Map();
|
|
855
|
-
this.buildRefMap(nodes);
|
|
856
|
-
}
|
|
857
|
-
get nodeCount() {
|
|
858
|
-
return this.refMap.size;
|
|
859
|
-
}
|
|
860
|
-
*traverse() {
|
|
861
|
-
for (const vxNode of this.nodes) {
|
|
862
|
-
yield* traverseVxNode(vxNode, 0);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
buildRefMap(nodes) {
|
|
866
|
-
for (const node of nodes) {
|
|
867
|
-
this.refMap.set(node.ref, node);
|
|
868
|
-
this.buildRefMap(node.children ?? []);
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
findNode(ref) {
|
|
872
|
-
return this.refMap.get(ref) ?? null;
|
|
873
|
-
}
|
|
874
|
-
render(options = {}) {
|
|
875
|
-
return this.nodes.map((node) => {
|
|
876
|
-
return renderVxNode(node, options);
|
|
877
|
-
}).join("\n");
|
|
878
|
-
}
|
|
879
|
-
highlight(options = {}) {
|
|
880
|
-
if (options.clearOverlay) {
|
|
881
|
-
clearOverlay();
|
|
882
|
-
}
|
|
883
|
-
const leafOnly = !options.includeAll;
|
|
884
|
-
const refs = this.collectRefs(leafOnly, options.filterRefs);
|
|
885
|
-
this.highlightRefs(refs, options);
|
|
886
|
-
}
|
|
887
|
-
highlightRefs(refs, options = {}) {
|
|
888
|
-
for (const ref of refs) {
|
|
889
|
-
const el = resolveDomNode(ref);
|
|
890
|
-
if (el instanceof Element) {
|
|
891
|
-
const vxNode = this.findNode(ref);
|
|
892
|
-
const isNew = vxNode?.isNew ?? false;
|
|
893
|
-
const color = options.useColors ? void 0 : isNew ? "#0a0" : "#060";
|
|
894
|
-
highlightEl(el, ref, color);
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
collectRefs(leafOnly = true, filterRefs) {
|
|
899
|
-
const refs = [];
|
|
900
|
-
for (const { vxNode } of this.traverse()) {
|
|
901
|
-
if (leafOnly && isContainerNode(vxNode)) {
|
|
902
|
-
continue;
|
|
903
|
-
}
|
|
904
|
-
if (filterRefs && !filterRefs.includes(vxNode.ref)) {
|
|
905
|
-
continue;
|
|
906
|
-
}
|
|
907
|
-
refs.push(vxNode.ref);
|
|
908
|
-
}
|
|
909
|
-
return refs;
|
|
910
|
-
}
|
|
911
|
-
};
|
|
912
|
-
|
|
913
|
-
// src/page/frame.ts
|
|
932
|
+
// src/page/page.ts
|
|
914
933
|
var VxPageView = class {
|
|
915
|
-
constructor(
|
|
916
|
-
this.vxFrames = vxFrames;
|
|
917
|
-
this.vxFrameMap = /* @__PURE__ */ new Map();
|
|
934
|
+
constructor(vxTrees) {
|
|
918
935
|
this.vxTreeMap = /* @__PURE__ */ new Map();
|
|
919
|
-
for (const
|
|
920
|
-
this.
|
|
921
|
-
this.vxTreeMap.set(frame.frameId, new VxTreeView(frame.nodes, frame.refRange));
|
|
936
|
+
for (const vxTree of vxTrees) {
|
|
937
|
+
this.vxTreeMap.set(vxTree.frameId, vxTree);
|
|
922
938
|
}
|
|
923
939
|
}
|
|
924
940
|
get vxTrees() {
|
|
@@ -928,43 +944,28 @@ var WebVision = (() => {
|
|
|
928
944
|
return this.vxTrees.reduce((acc, vxTree) => acc + vxTree.nodeCount, 0);
|
|
929
945
|
}
|
|
930
946
|
findNodeByRef(ref) {
|
|
931
|
-
const
|
|
932
|
-
if (
|
|
947
|
+
const frame = this.findFrameByRef(ref);
|
|
948
|
+
if (frame == null) {
|
|
933
949
|
return null;
|
|
934
950
|
}
|
|
935
|
-
return
|
|
951
|
+
return frame.findNode(ref);
|
|
936
952
|
}
|
|
937
|
-
|
|
953
|
+
findFrameById(frameId) {
|
|
938
954
|
return this.vxTreeMap.get(frameId) ?? null;
|
|
939
955
|
}
|
|
940
|
-
findTreeByRef(ref) {
|
|
941
|
-
const vxFrame = this.findFrameByRef(ref);
|
|
942
|
-
if (vxFrame == null) {
|
|
943
|
-
return null;
|
|
944
|
-
}
|
|
945
|
-
return this.vxTreeMap.get(vxFrame.frameId) ?? null;
|
|
946
|
-
}
|
|
947
|
-
findFrameByFrameId(frameId) {
|
|
948
|
-
return this.vxFrameMap.get(frameId) ?? null;
|
|
949
|
-
}
|
|
950
956
|
findFrameByRef(ref) {
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
);
|
|
954
|
-
if (!vxFrame) {
|
|
955
|
-
return null;
|
|
956
|
-
}
|
|
957
|
-
return this.vxFrameMap.get(vxFrame.frameId) ?? null;
|
|
957
|
+
const frame = this.vxTrees.find((f) => f.hasRef(ref));
|
|
958
|
+
return frame ?? null;
|
|
958
959
|
}
|
|
959
960
|
getFrameByRef(ref) {
|
|
960
|
-
const
|
|
961
|
-
if (
|
|
961
|
+
const frame = this.findFrameByRef(ref);
|
|
962
|
+
if (frame == null) {
|
|
962
963
|
throw new Error(`[VX] Frame not found for [ref=${ref}]`);
|
|
963
964
|
}
|
|
964
|
-
return
|
|
965
|
+
return frame;
|
|
965
966
|
}
|
|
966
967
|
findParentFrame(frameId) {
|
|
967
|
-
const frame = this.
|
|
968
|
+
const frame = this.findFrameById(frameId);
|
|
968
969
|
const iframeRef = frame?.iframeRef;
|
|
969
970
|
if (iframeRef == null) {
|
|
970
971
|
return null;
|
|
@@ -972,7 +973,7 @@ var WebVision = (() => {
|
|
|
972
973
|
return this.findFrameByRef(iframeRef);
|
|
973
974
|
}
|
|
974
975
|
isFrameShown(frameId) {
|
|
975
|
-
const frame = this.
|
|
976
|
+
const frame = this.findFrameById(frameId);
|
|
976
977
|
if (!frame) {
|
|
977
978
|
return false;
|
|
978
979
|
}
|
|
@@ -981,14 +982,12 @@ var WebVision = (() => {
|
|
|
981
982
|
if (parentFrame == null || iframeRef == null) {
|
|
982
983
|
return true;
|
|
983
984
|
}
|
|
984
|
-
const
|
|
985
|
-
const existsInParent = !!vxTree?.findNode(iframeRef);
|
|
985
|
+
const existsInParent = !!parentFrame.findNode(iframeRef);
|
|
986
986
|
return existsInParent ? this.isFrameShown(parentFrame.frameId) : false;
|
|
987
987
|
}
|
|
988
988
|
renderAll(options) {
|
|
989
|
-
return this.
|
|
990
|
-
const
|
|
991
|
-
const rendered = vxTree?.render(options);
|
|
989
|
+
return this.vxTrees.map((frame) => {
|
|
990
|
+
const rendered = frame?.render(options);
|
|
992
991
|
return [
|
|
993
992
|
`FRAME ${frame.frameId}${frame.iframeRef ? ` [@${frame.iframeRef}]` : ""}`,
|
|
994
993
|
rendered
|