@ubio/webvision 2.6.6 → 3.0.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/build/global.js +259 -248
- package/build/global.js.map +3 -3
- package/build/page.mjs +259 -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 +16 -5
- package/out/page/tree.js.map +1 -1
- package/out/page/util.d.ts +1 -0
- package/out/page/util.js +3 -0
- package/out/page/util.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,
|
|
@@ -59,30 +59,18 @@ var WebVision = (() => {
|
|
|
59
59
|
isRandomIdentifier: () => isRandomIdentifier,
|
|
60
60
|
isRectInViewport: () => isRectInViewport,
|
|
61
61
|
makeOverlaysOpaque: () => makeOverlaysOpaque,
|
|
62
|
+
normalizeRef: () => normalizeRef,
|
|
62
63
|
normalizeText: () => normalizeText,
|
|
63
64
|
probeViewport: () => probeViewport,
|
|
64
65
|
renderVxNode: () => renderVxNode,
|
|
65
66
|
resolveDomNode: () => resolveDomNode,
|
|
67
|
+
serializeElement: () => serializeElement,
|
|
66
68
|
showPoint: () => showPoint,
|
|
67
69
|
traverseElements: () => traverseElements,
|
|
68
70
|
traverseVxNode: () => traverseVxNode,
|
|
69
71
|
truncateAttrValue: () => truncateAttrValue
|
|
70
72
|
});
|
|
71
73
|
|
|
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
74
|
// src/page/dom.ts
|
|
87
75
|
var ORIGINAL_STYLE_SYMBOL = Symbol("vx:originalStyle");
|
|
88
76
|
var INTERACTIVE_TAGS = ["a", "button", "input", "textarea", "select", "label", "option", "optgroup"];
|
|
@@ -269,6 +257,24 @@ var WebVision = (() => {
|
|
|
269
257
|
}
|
|
270
258
|
}
|
|
271
259
|
}
|
|
260
|
+
function getElementDepth(el) {
|
|
261
|
+
let depth = 0;
|
|
262
|
+
while (el.parentElement) {
|
|
263
|
+
el = el.parentElement;
|
|
264
|
+
depth += 1;
|
|
265
|
+
}
|
|
266
|
+
return depth;
|
|
267
|
+
}
|
|
268
|
+
function serializeElement(el) {
|
|
269
|
+
const sig = [];
|
|
270
|
+
const depth = getElementDepth(el);
|
|
271
|
+
sig.push(String(depth));
|
|
272
|
+
sig.push(el.tagName);
|
|
273
|
+
for (const attr of el.attributes) {
|
|
274
|
+
sig.push(`${attr.name}=${attr.value}`);
|
|
275
|
+
}
|
|
276
|
+
return sig.join("|");
|
|
277
|
+
}
|
|
272
278
|
|
|
273
279
|
// src/page/traverse.ts
|
|
274
280
|
function* traverseVxNode(vxNode, depth = 0) {
|
|
@@ -350,6 +356,191 @@ var WebVision = (() => {
|
|
|
350
356
|
function isObjectEmpty(obj) {
|
|
351
357
|
return !Object.values(obj).some((value) => !!value);
|
|
352
358
|
}
|
|
359
|
+
function normalizeRef(ref) {
|
|
360
|
+
return ref.toLowerCase().trim().replace(/^[@#]/, "");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// src/page/render.ts
|
|
364
|
+
function renderVxNode(scope, options = {}) {
|
|
365
|
+
const buffer = [];
|
|
366
|
+
for (const { vxNode, depth } of traverseVxNode(scope)) {
|
|
367
|
+
if (options.skipNonInteractive && !vxNode.isInteractive) {
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
const indent = options.skipNonInteractive ? "" : " ".repeat(depth);
|
|
371
|
+
buffer.push(renderIndentedLine(indent, vxNode, options));
|
|
372
|
+
}
|
|
373
|
+
return buffer.join("\n");
|
|
374
|
+
}
|
|
375
|
+
function renderIndentedLine(indent, vxNode, options = {}) {
|
|
376
|
+
const diffPrefix = options.renderDiff ? vxNode.isNew ? "+ " : " " : "";
|
|
377
|
+
if (!vxNode.tagName) {
|
|
378
|
+
return [diffPrefix, indent, vxNode.textContent].filter(Boolean).join("");
|
|
379
|
+
}
|
|
380
|
+
const tagLine = renderTagLine(vxNode, options);
|
|
381
|
+
const htmlStyle = options.renderStyle === "html";
|
|
382
|
+
return [
|
|
383
|
+
diffPrefix,
|
|
384
|
+
indent,
|
|
385
|
+
tagLine,
|
|
386
|
+
htmlStyle ? "" : " ",
|
|
387
|
+
vxNode.textContent ?? ""
|
|
388
|
+
].join("");
|
|
389
|
+
}
|
|
390
|
+
function renderTagLine(vxNode, options) {
|
|
391
|
+
const htmlStyle = options.renderStyle === "html";
|
|
392
|
+
const components = [];
|
|
393
|
+
if (options.renderTagNames && vxNode.tagName) {
|
|
394
|
+
components.push(vxNode.tagName);
|
|
395
|
+
}
|
|
396
|
+
if (options.renderIds && vxNode.id) {
|
|
397
|
+
if (htmlStyle) {
|
|
398
|
+
components.push(`id="${vxNode.id}"`);
|
|
399
|
+
} else {
|
|
400
|
+
components.push(`#${vxNode.id}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (options.renderClassNames && vxNode.classList?.length) {
|
|
404
|
+
if (htmlStyle) {
|
|
405
|
+
components.push(`class="${vxNode.classList.join(" ")}"`);
|
|
406
|
+
} else {
|
|
407
|
+
components.push("." + vxNode.classList.join("."));
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (options.renderRefs) {
|
|
411
|
+
const isRenderRef = [
|
|
412
|
+
options.renderRefs === "all",
|
|
413
|
+
options.renderRefs === true && !isContainerNode(vxNode)
|
|
414
|
+
].some(Boolean);
|
|
415
|
+
if (isRenderRef) {
|
|
416
|
+
components.push(`[@${vxNode.ref}]`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const attrs = [];
|
|
420
|
+
if (options.renderLabelAttrs) {
|
|
421
|
+
for (const [attr, value] of Object.entries(vxNode.labelAttrs ?? {})) {
|
|
422
|
+
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (options.renderValueAttrs) {
|
|
426
|
+
for (const [attr, value] of Object.entries(vxNode.valueAttrs ?? {})) {
|
|
427
|
+
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (options.renderSrcAttrs) {
|
|
431
|
+
for (const [attr, value] of Object.entries(vxNode.srcAttrs ?? {})) {
|
|
432
|
+
attrs.push(`${attr}="${truncateAttrValue(value)}"`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (htmlStyle) {
|
|
436
|
+
components.push(...attrs);
|
|
437
|
+
} else {
|
|
438
|
+
components.push(...attrs.map((attr) => `[${attr}]`));
|
|
439
|
+
}
|
|
440
|
+
return htmlStyle ? `<${components.join(" ")}>` : components.join("");
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// src/page/snapshot.ts
|
|
444
|
+
var VX_DOM_SYMBOL = Symbol("vx:dom");
|
|
445
|
+
var VX_TREE_SYMBOL = Symbol("vx:tree");
|
|
446
|
+
var VX_LAST_REFS_SYMBOL = Symbol("vx:lastRefs");
|
|
447
|
+
async function captureSnapshot(options = {}) {
|
|
448
|
+
const parser = new VxTreeParser(options);
|
|
449
|
+
const domMap = parser.getDomMap();
|
|
450
|
+
const vxTree = parser.getTree(options.frameId ?? "0", options.iframeRef);
|
|
451
|
+
globalThis[VX_DOM_SYMBOL] = domMap;
|
|
452
|
+
globalThis[VX_TREE_SYMBOL] = vxTree;
|
|
453
|
+
return vxTree;
|
|
454
|
+
}
|
|
455
|
+
function getSnapshot() {
|
|
456
|
+
const vxTree = globalThis[VX_TREE_SYMBOL];
|
|
457
|
+
if (!vxTree) {
|
|
458
|
+
throw new Error("[VX] Snapshot not found");
|
|
459
|
+
}
|
|
460
|
+
return vxTree;
|
|
461
|
+
}
|
|
462
|
+
function resolveDomNode(ref) {
|
|
463
|
+
const domMap = globalThis[VX_DOM_SYMBOL];
|
|
464
|
+
if (!domMap) {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
return domMap.get(ref) ?? null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// src/page/tree.ts
|
|
471
|
+
var VxTreeView = class {
|
|
472
|
+
constructor(nodes, frameId, iframeRef) {
|
|
473
|
+
this.nodes = nodes;
|
|
474
|
+
this.frameId = frameId;
|
|
475
|
+
this.iframeRef = iframeRef;
|
|
476
|
+
this.refMap = /* @__PURE__ */ new Map();
|
|
477
|
+
this.buildRefMap(nodes);
|
|
478
|
+
}
|
|
479
|
+
get nodeCount() {
|
|
480
|
+
return this.refMap.size;
|
|
481
|
+
}
|
|
482
|
+
*traverse() {
|
|
483
|
+
for (const vxNode of this.nodes) {
|
|
484
|
+
yield* traverseVxNode(vxNode, 0);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
buildRefMap(nodes) {
|
|
488
|
+
for (const node of nodes) {
|
|
489
|
+
if (node.ref) {
|
|
490
|
+
this.refMap.set(node.ref, node);
|
|
491
|
+
}
|
|
492
|
+
this.buildRefMap(node.children ?? []);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
hasRef(ref) {
|
|
496
|
+
const nref = normalizeRef(ref);
|
|
497
|
+
return this.refMap.has(nref);
|
|
498
|
+
}
|
|
499
|
+
findNode(ref) {
|
|
500
|
+
const nref = normalizeRef(ref);
|
|
501
|
+
return this.refMap.get(nref) ?? null;
|
|
502
|
+
}
|
|
503
|
+
render(options = {}) {
|
|
504
|
+
return this.nodes.map((node) => {
|
|
505
|
+
return renderVxNode(node, options);
|
|
506
|
+
}).join("\n");
|
|
507
|
+
}
|
|
508
|
+
highlight(options = {}) {
|
|
509
|
+
if (options.clearOverlay) {
|
|
510
|
+
clearOverlay();
|
|
511
|
+
}
|
|
512
|
+
const leafOnly = !options.includeAll;
|
|
513
|
+
const refs = this.collectRefs(leafOnly, options.filterRefs);
|
|
514
|
+
this.highlightRefs(refs, options);
|
|
515
|
+
}
|
|
516
|
+
highlightRefs(refs, options = {}) {
|
|
517
|
+
for (const ref of refs) {
|
|
518
|
+
const el = resolveDomNode(ref);
|
|
519
|
+
if (el instanceof Element) {
|
|
520
|
+
const vxNode = this.findNode(ref);
|
|
521
|
+
const isNew = vxNode?.isNew ?? false;
|
|
522
|
+
const color = options.useColors ? void 0 : isNew ? "#0a0" : "#060";
|
|
523
|
+
highlightEl(el, ref, color);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
collectRefs(leafOnly = true, filterRefs) {
|
|
528
|
+
const refs = [];
|
|
529
|
+
for (const { vxNode } of this.traverse()) {
|
|
530
|
+
if (!vxNode.ref) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
if (leafOnly && isContainerNode(vxNode)) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
if (filterRefs && !filterRefs.includes(vxNode.ref)) {
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
refs.push(vxNode.ref);
|
|
540
|
+
}
|
|
541
|
+
return refs;
|
|
542
|
+
}
|
|
543
|
+
};
|
|
353
544
|
|
|
354
545
|
// src/page/parser.ts
|
|
355
546
|
var VX_NODE_SYMBOL = Symbol("vx:node");
|
|
@@ -422,41 +613,36 @@ var WebVision = (() => {
|
|
|
422
613
|
var VxTreeParser = class {
|
|
423
614
|
constructor(options = {}) {
|
|
424
615
|
this.options = options;
|
|
616
|
+
this.viewport = { width: 0, height: 0 };
|
|
617
|
+
this.vxNodes = [];
|
|
425
618
|
this.probeElements = [];
|
|
426
619
|
this.domRefMap = /* @__PURE__ */ new Map();
|
|
427
|
-
|
|
620
|
+
}
|
|
621
|
+
async parse() {
|
|
428
622
|
this.viewport = getViewportSize();
|
|
429
|
-
this.
|
|
430
|
-
if (options.probeViewport) {
|
|
623
|
+
if (this.options.probeViewport) {
|
|
431
624
|
this.probeElements = probeViewport();
|
|
432
625
|
}
|
|
433
|
-
const vxRoot = this.
|
|
434
|
-
this.refRange = [startRef, this.counter.current()];
|
|
626
|
+
const vxRoot = await this.parseNode(document.documentElement, null);
|
|
435
627
|
this.vxNodes = this.pruneRecursive(vxRoot);
|
|
436
628
|
}
|
|
437
|
-
|
|
438
|
-
return this.
|
|
439
|
-
}
|
|
440
|
-
getTree() {
|
|
441
|
-
return new VxTreeView(this.vxNodes, this.refRange);
|
|
629
|
+
getTree(frameId, iframeRef) {
|
|
630
|
+
return new VxTreeView(this.vxNodes, frameId, iframeRef);
|
|
442
631
|
}
|
|
443
632
|
getNodes() {
|
|
444
633
|
return this.vxNodes;
|
|
445
634
|
}
|
|
446
|
-
getRefRange() {
|
|
447
|
-
return this.refRange;
|
|
448
|
-
}
|
|
449
635
|
getDomMap() {
|
|
450
636
|
return this.domRefMap;
|
|
451
637
|
}
|
|
452
|
-
parseNode(node, parent) {
|
|
638
|
+
async parseNode(node, parent) {
|
|
453
639
|
if (!node || node[VX_IGNORE_SYMBOL]) {
|
|
454
640
|
return null;
|
|
455
641
|
}
|
|
456
642
|
if (node instanceof Text) {
|
|
457
643
|
const textContent = normalizeText(node.textContent ?? "");
|
|
458
644
|
if (textContent) {
|
|
459
|
-
return this.makeNode(node, {
|
|
645
|
+
return await this.makeNode(node, {
|
|
460
646
|
textContent,
|
|
461
647
|
hasVisibleArea: parent?.hasVisibleArea,
|
|
462
648
|
isOutsideViewport: parent?.isOutsideViewport,
|
|
@@ -469,11 +655,11 @@ var WebVision = (() => {
|
|
|
469
655
|
if (this.options.opaqueOverlays) {
|
|
470
656
|
makeOverlaysOpaque(node);
|
|
471
657
|
}
|
|
472
|
-
return this.parseElement(node);
|
|
658
|
+
return await this.parseElement(node);
|
|
473
659
|
}
|
|
474
660
|
return null;
|
|
475
661
|
}
|
|
476
|
-
parseElement(el) {
|
|
662
|
+
async parseElement(el) {
|
|
477
663
|
const skip = VX_IGNORE_TAGS.includes(el.tagName.toLowerCase()) || isHidden(el);
|
|
478
664
|
if (skip) {
|
|
479
665
|
this.clearRecursive(el);
|
|
@@ -482,7 +668,7 @@ var WebVision = (() => {
|
|
|
482
668
|
const parentEl = el.matches("option, optgroup") ? el.closest("select") ?? el : el;
|
|
483
669
|
const rect = parentEl.getBoundingClientRect();
|
|
484
670
|
const id = el.getAttribute("id") ?? "";
|
|
485
|
-
const vxNode = this.makeNode(el, {
|
|
671
|
+
const vxNode = await this.makeNode(el, {
|
|
486
672
|
tagName: el.tagName.toLowerCase(),
|
|
487
673
|
id: isRandomIdentifier(id) ? void 0 : id,
|
|
488
674
|
classList: Array.from(el.classList).filter((cls) => !isRandomIdentifier(cls)).slice(0, 4),
|
|
@@ -495,7 +681,13 @@ var WebVision = (() => {
|
|
|
495
681
|
isProbeHit: this.isProbeHit(parentEl),
|
|
496
682
|
isKept: el.matches(VX_KEEP_SELECTOR)
|
|
497
683
|
});
|
|
498
|
-
const children = [
|
|
684
|
+
const children = [];
|
|
685
|
+
for (const child of el.childNodes) {
|
|
686
|
+
const childNode = await this.parseNode(child, vxNode);
|
|
687
|
+
if (childNode != null) {
|
|
688
|
+
children.push(childNode);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
499
691
|
if (children.length === 1 && !children[0]?.tagName) {
|
|
500
692
|
vxNode.textContent = normalizeText(children[0].textContent ?? "");
|
|
501
693
|
} else {
|
|
@@ -503,15 +695,17 @@ var WebVision = (() => {
|
|
|
503
695
|
}
|
|
504
696
|
return vxNode;
|
|
505
697
|
}
|
|
506
|
-
makeNode(node, spec) {
|
|
507
|
-
const ref = this.counter.next();
|
|
698
|
+
async makeNode(node, spec) {
|
|
508
699
|
const isNew = !node[VX_NODE_SYMBOL];
|
|
700
|
+
const ref = await this.createRef(node);
|
|
509
701
|
const vxNode = {
|
|
510
702
|
...spec,
|
|
511
703
|
ref,
|
|
512
704
|
isNew
|
|
513
705
|
};
|
|
514
|
-
|
|
706
|
+
if (ref) {
|
|
707
|
+
this.domRefMap.set(ref, node);
|
|
708
|
+
}
|
|
515
709
|
node[VX_NODE_SYMBOL] = vxNode;
|
|
516
710
|
return vxNode;
|
|
517
711
|
}
|
|
@@ -649,6 +843,13 @@ var WebVision = (() => {
|
|
|
649
843
|
}
|
|
650
844
|
}
|
|
651
845
|
}
|
|
846
|
+
async createRef(node) {
|
|
847
|
+
if (node instanceof Element) {
|
|
848
|
+
const sig = serializeElement(node);
|
|
849
|
+
const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(sig).buffer);
|
|
850
|
+
return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, "0")).join("").substring(0, 8);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
652
853
|
};
|
|
653
854
|
|
|
654
855
|
// src/page/overlay.ts
|
|
@@ -692,7 +893,7 @@ var WebVision = (() => {
|
|
|
692
893
|
}
|
|
693
894
|
|
|
694
895
|
// src/page/highlight.ts
|
|
695
|
-
function highlightEl(el, ref
|
|
896
|
+
function highlightEl(el, ref, color) {
|
|
696
897
|
if (!(el instanceof Element)) {
|
|
697
898
|
return;
|
|
698
899
|
}
|
|
@@ -728,191 +929,18 @@ var WebVision = (() => {
|
|
|
728
929
|
label.style.transform = "translateY(50%)";
|
|
729
930
|
label.textContent = String(ref);
|
|
730
931
|
}
|
|
731
|
-
function getRandomColor(
|
|
932
|
+
function getRandomColor(ref) {
|
|
933
|
+
const index = ref.charCodeAt(0);
|
|
732
934
|
const hue = index * 120 * 0.382 % 360;
|
|
733
935
|
return `hsl(${hue}, 85%, 50%)`;
|
|
734
936
|
}
|
|
735
937
|
|
|
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
|
|
938
|
+
// src/page/page.ts
|
|
908
939
|
var VxPageView = class {
|
|
909
|
-
constructor(
|
|
910
|
-
this.vxFrames = vxFrames;
|
|
911
|
-
this.vxFrameMap = /* @__PURE__ */ new Map();
|
|
940
|
+
constructor(vxTrees) {
|
|
912
941
|
this.vxTreeMap = /* @__PURE__ */ new Map();
|
|
913
|
-
for (const
|
|
914
|
-
this.
|
|
915
|
-
this.vxTreeMap.set(frame.frameId, new VxTreeView(frame.nodes, frame.refRange));
|
|
942
|
+
for (const vxTree of vxTrees) {
|
|
943
|
+
this.vxTreeMap.set(vxTree.frameId, vxTree);
|
|
916
944
|
}
|
|
917
945
|
}
|
|
918
946
|
get vxTrees() {
|
|
@@ -922,43 +950,28 @@ var WebVision = (() => {
|
|
|
922
950
|
return this.vxTrees.reduce((acc, vxTree) => acc + vxTree.nodeCount, 0);
|
|
923
951
|
}
|
|
924
952
|
findNodeByRef(ref) {
|
|
925
|
-
const
|
|
926
|
-
if (
|
|
953
|
+
const frame = this.findFrameByRef(ref);
|
|
954
|
+
if (frame == null) {
|
|
927
955
|
return null;
|
|
928
956
|
}
|
|
929
|
-
return
|
|
957
|
+
return frame.findNode(ref);
|
|
930
958
|
}
|
|
931
|
-
|
|
959
|
+
findFrameById(frameId) {
|
|
932
960
|
return this.vxTreeMap.get(frameId) ?? null;
|
|
933
961
|
}
|
|
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
962
|
findFrameByRef(ref) {
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
);
|
|
948
|
-
if (!vxFrame) {
|
|
949
|
-
return null;
|
|
950
|
-
}
|
|
951
|
-
return this.vxFrameMap.get(vxFrame.frameId) ?? null;
|
|
963
|
+
const frame = this.vxTrees.find((f) => f.hasRef(ref));
|
|
964
|
+
return frame ?? null;
|
|
952
965
|
}
|
|
953
966
|
getFrameByRef(ref) {
|
|
954
|
-
const
|
|
955
|
-
if (
|
|
967
|
+
const frame = this.findFrameByRef(ref);
|
|
968
|
+
if (frame == null) {
|
|
956
969
|
throw new Error(`[VX] Frame not found for [ref=${ref}]`);
|
|
957
970
|
}
|
|
958
|
-
return
|
|
971
|
+
return frame;
|
|
959
972
|
}
|
|
960
973
|
findParentFrame(frameId) {
|
|
961
|
-
const frame = this.
|
|
974
|
+
const frame = this.findFrameById(frameId);
|
|
962
975
|
const iframeRef = frame?.iframeRef;
|
|
963
976
|
if (iframeRef == null) {
|
|
964
977
|
return null;
|
|
@@ -966,7 +979,7 @@ var WebVision = (() => {
|
|
|
966
979
|
return this.findFrameByRef(iframeRef);
|
|
967
980
|
}
|
|
968
981
|
isFrameShown(frameId) {
|
|
969
|
-
const frame = this.
|
|
982
|
+
const frame = this.findFrameById(frameId);
|
|
970
983
|
if (!frame) {
|
|
971
984
|
return false;
|
|
972
985
|
}
|
|
@@ -975,14 +988,12 @@ var WebVision = (() => {
|
|
|
975
988
|
if (parentFrame == null || iframeRef == null) {
|
|
976
989
|
return true;
|
|
977
990
|
}
|
|
978
|
-
const
|
|
979
|
-
const existsInParent = !!vxTree?.findNode(iframeRef);
|
|
991
|
+
const existsInParent = !!parentFrame.findNode(iframeRef);
|
|
980
992
|
return existsInParent ? this.isFrameShown(parentFrame.frameId) : false;
|
|
981
993
|
}
|
|
982
994
|
renderAll(options) {
|
|
983
|
-
return this.
|
|
984
|
-
const
|
|
985
|
-
const rendered = vxTree?.render(options);
|
|
995
|
+
return this.vxTrees.map((frame) => {
|
|
996
|
+
const rendered = frame?.render(options);
|
|
986
997
|
return [
|
|
987
998
|
`FRAME ${frame.frameId}${frame.iframeRef ? ` [@${frame.iframeRef}]` : ""}`,
|
|
988
999
|
rendered
|