@appsurify-testmap/rrweb-snapshot 2.1.0-alpha.7 → 2.1.1-alpha.2

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/index.d.cts CHANGED
@@ -21,6 +21,10 @@ export declare function buildNodeWithSN(n: serializedNodeWithId, options: {
21
21
  cache: BuildCache;
22
22
  }): Node | null;
23
23
 
24
+ export declare function buildSelector(node: Node): string | null;
25
+
26
+ export declare function buildXPath(node: Node): string;
27
+
24
28
  export declare function classMatchesRegex(node: Node | null, regex: RegExp, checkAncestors: boolean): boolean;
25
29
 
26
30
  export declare function cleanupSnapshot(): void;
@@ -52,8 +56,6 @@ export declare function genId(): number;
52
56
 
53
57
  export declare function getInputType(element: HTMLElement): Lowercase<string> | null;
54
58
 
55
- export declare function getXPath(node: Node): string;
56
-
57
59
  export declare interface ICanvas extends HTMLCanvasElement {
58
60
  __context: string;
59
61
  }
@@ -78,12 +80,10 @@ export declare function isElement(n: Node): n is Element;
78
80
 
79
81
  export declare function isElementInteractive(n: Node): boolean;
80
82
 
81
- export declare function isElementVisible(n: Element): boolean;
83
+ export declare function isElementVisible(el: Element): boolean;
82
84
 
83
85
  export declare function isExcludeAttribute(name: string, exclude: string | RegExp): boolean;
84
86
 
85
- export declare function isIncludeAttribute(name: string, include: string | RegExp): boolean;
86
-
87
87
  export declare function isNativeShadowDom(shadowRoot: ShadowRoot): boolean;
88
88
 
89
89
  export declare function isNodeMetaEqual(a: serializedNode, b: serializedNode): boolean;
@@ -166,7 +166,6 @@ export declare function serializeNodeWithId(n: Node, options: {
166
166
  maskTextClass: string | RegExp;
167
167
  maskTextSelector: string | null;
168
168
  excludeAttribute: string | RegExp;
169
- includeAttribute: string | RegExp;
170
169
  skipChild: boolean;
171
170
  inlineStylesheet: boolean;
172
171
  newlyAddedElement?: boolean;
@@ -209,7 +208,6 @@ export declare function snapshot(n: Document, options?: {
209
208
  maskTextClass?: string | RegExp;
210
209
  maskTextSelector?: string | null;
211
210
  excludeAttribute?: string | RegExp;
212
- includeAttribute?: string | RegExp;
213
211
  inlineStylesheet?: boolean;
214
212
  maskAllInputs?: boolean | MaskInputOptions;
215
213
  maskTextFn?: MaskTextFn;
package/dist/index.d.ts CHANGED
@@ -21,6 +21,10 @@ export declare function buildNodeWithSN(n: serializedNodeWithId, options: {
21
21
  cache: BuildCache;
22
22
  }): Node | null;
23
23
 
24
+ export declare function buildSelector(node: Node): string | null;
25
+
26
+ export declare function buildXPath(node: Node): string;
27
+
24
28
  export declare function classMatchesRegex(node: Node | null, regex: RegExp, checkAncestors: boolean): boolean;
25
29
 
26
30
  export declare function cleanupSnapshot(): void;
@@ -52,8 +56,6 @@ export declare function genId(): number;
52
56
 
53
57
  export declare function getInputType(element: HTMLElement): Lowercase<string> | null;
54
58
 
55
- export declare function getXPath(node: Node): string;
56
-
57
59
  export declare interface ICanvas extends HTMLCanvasElement {
58
60
  __context: string;
59
61
  }
@@ -78,12 +80,10 @@ export declare function isElement(n: Node): n is Element;
78
80
 
79
81
  export declare function isElementInteractive(n: Node): boolean;
80
82
 
81
- export declare function isElementVisible(n: Element): boolean;
83
+ export declare function isElementVisible(el: Element): boolean;
82
84
 
83
85
  export declare function isExcludeAttribute(name: string, exclude: string | RegExp): boolean;
84
86
 
85
- export declare function isIncludeAttribute(name: string, include: string | RegExp): boolean;
86
-
87
87
  export declare function isNativeShadowDom(shadowRoot: ShadowRoot): boolean;
88
88
 
89
89
  export declare function isNodeMetaEqual(a: serializedNode, b: serializedNode): boolean;
@@ -166,7 +166,6 @@ export declare function serializeNodeWithId(n: Node, options: {
166
166
  maskTextClass: string | RegExp;
167
167
  maskTextSelector: string | null;
168
168
  excludeAttribute: string | RegExp;
169
- includeAttribute: string | RegExp;
170
169
  skipChild: boolean;
171
170
  inlineStylesheet: boolean;
172
171
  newlyAddedElement?: boolean;
@@ -209,7 +208,6 @@ export declare function snapshot(n: Document, options?: {
209
208
  maskTextClass?: string | RegExp;
210
209
  maskTextSelector?: string | null;
211
210
  excludeAttribute?: string | RegExp;
212
- includeAttribute?: string | RegExp;
213
211
  inlineStylesheet?: boolean;
214
212
  maskAllInputs?: boolean | MaskInputOptions;
215
213
  maskTextFn?: MaskTextFn;
@@ -166,6 +166,41 @@ function patch(source, name, replacement) {
166
166
  };
167
167
  }
168
168
  }
169
+ function describeNode(el) {
170
+ const tag = el.tagName.toLowerCase();
171
+ const id = el.id ? `#${el.id}` : "";
172
+ const classes = el.classList.length ? "." + Array.from(el.classList).join(".") : "";
173
+ return `${tag}${id}${classes}`;
174
+ }
175
+ function getElementVisibility(el) {
176
+ var _a, _b;
177
+ const win = ((_a = el.ownerDocument) == null ? void 0 : _a.defaultView) ?? window;
178
+ const rect = el.getBoundingClientRect();
179
+ const viewportWidth = win.innerWidth || win.document.documentElement.clientWidth || 0;
180
+ const viewportHeight = win.innerHeight || win.document.documentElement.clientHeight || 0;
181
+ const isRectVisible = rect.width > 0 && rect.height > 0 && rect.bottom > 0 && rect.right > 0 && rect.top < viewportHeight && rect.left < viewportWidth;
182
+ const style = (_b = win.getComputedStyle) == null ? void 0 : _b.call(win, el);
183
+ const isStyleVisible = !!style && style.display !== "none" && style.visibility !== "hidden" && (parseFloat(style.opacity) || 0) > 0;
184
+ const isVisible = isStyleVisible && isRectVisible;
185
+ let ratio = 0;
186
+ if (isVisible) {
187
+ const xOverlap = Math.max(
188
+ 0,
189
+ Math.min(rect.right, viewportWidth) - Math.max(rect.left, 0)
190
+ );
191
+ const yOverlap = Math.max(
192
+ 0,
193
+ Math.min(rect.bottom, viewportHeight) - Math.max(rect.top, 0)
194
+ );
195
+ const intersectionArea = xOverlap * yOverlap;
196
+ const elementArea = rect.width * rect.height;
197
+ ratio = elementArea > 0 ? intersectionArea / elementArea : 0;
198
+ }
199
+ return {
200
+ isVisible,
201
+ ratio
202
+ };
203
+ }
169
204
  const index = {
170
205
  childNodes,
171
206
  parentNode,
@@ -179,7 +214,9 @@ const index = {
179
214
  querySelector,
180
215
  querySelectorAll,
181
216
  mutationObserver: mutationObserverCtor,
182
- patch
217
+ patch,
218
+ describeNode,
219
+ getElementVisibility
183
220
  };
184
221
  function isElement(n) {
185
222
  return n.nodeType === n.ELEMENT_NODE;
@@ -565,71 +602,95 @@ function splitCssText(cssText, style, _testNoPxNorm = false) {
565
602
  function markCssSplits(cssText, style) {
566
603
  return splitCssText(cssText, style).join("/* rr_split */");
567
604
  }
568
- function getXPath(node2) {
569
- if (node2.nodeType === Node.DOCUMENT_NODE) {
570
- return "/";
605
+ function isSelectorUnique(selector, target) {
606
+ try {
607
+ const matches = document.querySelectorAll(selector);
608
+ return matches.length === 1 && matches[0] === target;
609
+ } catch {
610
+ return false;
571
611
  }
572
- if (node2.nodeType === Node.DOCUMENT_TYPE_NODE) {
573
- return "/html/doctype";
612
+ }
613
+ function buildSelector(node2) {
614
+ if (!(node2 instanceof Element)) return null;
615
+ if (node2.id) {
616
+ return `#${CSS.escape(node2.id)}`;
574
617
  }
575
- if (node2.nodeType === Node.ELEMENT_NODE) {
576
- const element = node2;
577
- if (element.id) {
578
- return `//*[@id="${element.id}"]`;
579
- }
580
- if (element.tagName && element.tagName.toLowerCase() === "html") {
581
- return "/html";
582
- }
583
- if (element === document.head) {
584
- return "/html/head";
585
- }
586
- if (element === document.body) {
587
- return "/html/body";
588
- }
589
- const parentNode2 = element.parentNode;
590
- if (!parentNode2) {
591
- return "";
592
- }
593
- const siblings = Array.from(parentNode2.children).filter(
594
- (sibling) => sibling.tagName === element.tagName
595
- );
596
- const index2 = siblings.length > 1 ? `[${siblings.indexOf(element) + 1}]` : "";
597
- return `${getXPath(parentNode2)}/${element.tagName.toLowerCase()}${index2}`;
618
+ const parts = [];
619
+ const tag = node2.tagName.toLowerCase();
620
+ if (node2.classList.length) {
621
+ parts.push(...Array.from(node2.classList).map((cls) => `.${CSS.escape(cls)}`));
598
622
  }
599
- if (node2.nodeType === Node.TEXT_NODE) {
600
- const parent = node2.parentNode;
601
- if (!parent) {
602
- return "";
623
+ Array.from(node2.attributes).forEach((attr) => {
624
+ if (attr.name.startsWith("data-")) {
625
+ parts.push(`[${attr.name}="${CSS.escape(attr.value)}"]`);
603
626
  }
604
- const textSiblings = Array.from(parent.childNodes).filter(
605
- (sibling) => sibling.nodeType === Node.TEXT_NODE
606
- );
607
- const index2 = textSiblings.length > 1 ? `[${textSiblings.indexOf(node2) + 1}]` : "";
608
- return `${getXPath(parent)}/text()${index2}`;
609
- }
610
- if (node2.nodeType === Node.CDATA_SECTION_NODE) {
611
- const parent = node2.parentNode;
612
- if (!parent) {
613
- return "";
627
+ });
628
+ const shortSelector = `${tag}${parts.join("")}`;
629
+ if (isSelectorUnique(shortSelector, node2)) {
630
+ return shortSelector;
631
+ }
632
+ const pathParts = [];
633
+ let current = node2;
634
+ while (current && current.nodeType === Node.ELEMENT_NODE) {
635
+ const parent = current.parentElement;
636
+ const tagName = current.tagName.toLowerCase();
637
+ let nth = "";
638
+ if (parent) {
639
+ const siblings = Array.from(parent.children).filter(
640
+ (el) => el.tagName.toLowerCase() === tagName
641
+ );
642
+ if (siblings.length > 1) {
643
+ nth = `:nth-of-type(${siblings.indexOf(current) + 1})`;
644
+ }
614
645
  }
615
- const cdataSiblings = Array.from(parent.childNodes).filter(
616
- (sibling) => sibling.nodeType === Node.CDATA_SECTION_NODE
617
- );
618
- const index2 = cdataSiblings.length > 1 ? `[${cdataSiblings.indexOf(node2) + 1}]` : "";
619
- return `${getXPath(parent)}/text()${index2}`;
646
+ pathParts.unshift(`${tagName}${nth}`);
647
+ current = parent;
620
648
  }
621
- if (node2.nodeType === Node.COMMENT_NODE) {
622
- const parent = node2.parentNode;
623
- if (!parent) {
624
- return "";
649
+ return pathParts.join(" > ") || null;
650
+ }
651
+ function buildXPath(node2) {
652
+ switch (node2.nodeType) {
653
+ case Node.DOCUMENT_NODE:
654
+ return "/";
655
+ case Node.DOCUMENT_TYPE_NODE:
656
+ return "/html/doctype";
657
+ case Node.ELEMENT_NODE: {
658
+ const element = node2;
659
+ if (element.id) {
660
+ return `//*[@id="${CSS.escape(element.id)}"]`;
661
+ }
662
+ if (element.tagName.toLowerCase() === "html") return "/html";
663
+ if (element === document.head) return "/html/head";
664
+ if (element === document.body) return "/html/body";
665
+ const parent = element.parentNode;
666
+ if (!parent) return "";
667
+ const tag = element.tagName.toLowerCase();
668
+ const siblings = Array.from(parent.children).filter(
669
+ (el) => el.tagName.toLowerCase() === tag
670
+ );
671
+ const index2 = siblings.length > 1 ? `[${siblings.indexOf(element) + 1}]` : "";
672
+ return `${buildXPath(parent)}/${tag}${index2}`;
673
+ }
674
+ case Node.TEXT_NODE:
675
+ case Node.CDATA_SECTION_NODE:
676
+ case Node.COMMENT_NODE: {
677
+ const parent = node2.parentNode;
678
+ if (!parent) return "";
679
+ const typeMap = {
680
+ [Node.TEXT_NODE]: "text()",
681
+ [Node.CDATA_SECTION_NODE]: "text()",
682
+ // CDATA ≡ text() в XPath
683
+ [Node.COMMENT_NODE]: "comment()"
684
+ };
685
+ const sameTypeSiblings = Array.from(parent.childNodes).filter(
686
+ (sibling) => sibling.nodeType === node2.nodeType
687
+ );
688
+ const index2 = sameTypeSiblings.length > 1 ? `[${sameTypeSiblings.indexOf(node2)}]` : "";
689
+ return `${buildXPath(parent)}/${typeMap[node2.nodeType]}${index2}`;
625
690
  }
626
- const commentSiblings = Array.from(parent.childNodes).filter(
627
- (sibling) => sibling.nodeType === Node.COMMENT_NODE
628
- );
629
- const index2 = commentSiblings.length > 1 ? `[${commentSiblings.indexOf(node2) + 1}]` : "";
630
- return `${getXPath(parent)}/comment()${index2}`;
691
+ default:
692
+ return "";
631
693
  }
632
- return "";
633
694
  }
634
695
  function isTextVisible(n) {
635
696
  var _a;
@@ -645,20 +706,9 @@ function isTextVisible(n) {
645
706
  const textContent2 = (_a = n.textContent) == null ? void 0 : _a.trim();
646
707
  return textContent2 !== "";
647
708
  }
648
- function isElementVisible(n) {
649
- var _a;
650
- const win = ((_a = n.ownerDocument) == null ? void 0 : _a.defaultView) ?? null;
651
- const style = win ? win.getComputedStyle(n) : null;
652
- const isStyleVisible = style != null && style.display !== "none" && style.visibility !== "hidden" && parseFloat(style.opacity) !== 0;
653
- const rect = n.getBoundingClientRect();
654
- const result2 = isStyleVisible && isRectVisible(rect);
655
- return result2;
656
- }
657
- function isRectVisible(rect, win = window) {
658
- var _a, _b, _c, _d;
659
- const height = (win == null ? void 0 : win.innerHeight) ?? ((_b = (_a = win == null ? void 0 : win.document) == null ? void 0 : _a.documentElement) == null ? void 0 : _b.clientHeight) ?? 0;
660
- const width = (win == null ? void 0 : win.innerWidth) ?? ((_d = (_c = win == null ? void 0 : win.document) == null ? void 0 : _c.documentElement) == null ? void 0 : _d.clientWidth) ?? 0;
661
- return rect.width > 0 && rect.height > 0 && rect.top >= 0 && rect.left >= 0 && rect.bottom <= height && rect.right <= width;
709
+ function isElementVisible(el) {
710
+ const visibility = index.getElementVisibility(el);
711
+ return visibility.isVisible;
662
712
  }
663
713
  const interactiveEvents = [
664
714
  "change",
@@ -891,9 +941,6 @@ function transformAttribute(doc, tagName, name, value) {
891
941
  function ignoreAttribute(tagName, name, _value) {
892
942
  return (tagName === "video" || tagName === "audio") && name === "autoplay";
893
943
  }
894
- function isIncludeAttribute(name, include) {
895
- return typeof include === "string" ? name.includes(include) : include.test(name);
896
- }
897
944
  function isExcludeAttribute(name, exclude) {
898
945
  return typeof exclude === "string" ? name.includes(exclude) : exclude.test(name);
899
946
  }
@@ -1027,7 +1074,6 @@ function serializeNode(n, options) {
1027
1074
  blockClass,
1028
1075
  blockSelector,
1029
1076
  excludeAttribute,
1030
- includeAttribute,
1031
1077
  needsMask,
1032
1078
  inlineStylesheet,
1033
1079
  maskInputOptions = {},
@@ -1041,22 +1087,19 @@ function serializeNode(n, options) {
1041
1087
  cssCaptured = false
1042
1088
  } = options;
1043
1089
  const rootId = getRootId(doc, mirror);
1044
- const xPath = getXPath(n);
1045
1090
  switch (n.nodeType) {
1046
1091
  case n.DOCUMENT_NODE:
1047
1092
  if (n.compatMode !== "CSS1Compat") {
1048
1093
  return {
1049
1094
  type: NodeType.Document,
1050
1095
  childNodes: [],
1051
- xPath,
1052
1096
  compatMode: n.compatMode
1053
1097
  // probably "BackCompat"
1054
1098
  };
1055
1099
  } else {
1056
1100
  return {
1057
1101
  type: NodeType.Document,
1058
- childNodes: [],
1059
- xPath
1102
+ childNodes: []
1060
1103
  };
1061
1104
  }
1062
1105
  case n.DOCUMENT_TYPE_NODE:
@@ -1065,8 +1108,7 @@ function serializeNode(n, options) {
1065
1108
  name: n.name,
1066
1109
  publicId: n.publicId,
1067
1110
  systemId: n.systemId,
1068
- rootId,
1069
- xPath
1111
+ rootId
1070
1112
  };
1071
1113
  case n.ELEMENT_NODE:
1072
1114
  return serializeElementNode(n, {
@@ -1074,7 +1116,6 @@ function serializeNode(n, options) {
1074
1116
  blockClass,
1075
1117
  blockSelector,
1076
1118
  excludeAttribute,
1077
- includeAttribute,
1078
1119
  inlineStylesheet,
1079
1120
  maskInputOptions,
1080
1121
  maskInputFn,
@@ -1083,8 +1124,7 @@ function serializeNode(n, options) {
1083
1124
  recordCanvas,
1084
1125
  keepIframeSrcFn,
1085
1126
  newlyAddedElement,
1086
- rootId,
1087
- xPath
1127
+ rootId
1088
1128
  });
1089
1129
  case n.TEXT_NODE:
1090
1130
  return serializeTextNode(n, {
@@ -1092,22 +1132,19 @@ function serializeNode(n, options) {
1092
1132
  needsMask,
1093
1133
  maskTextFn,
1094
1134
  rootId,
1095
- cssCaptured,
1096
- xPath
1135
+ cssCaptured
1097
1136
  });
1098
1137
  case n.CDATA_SECTION_NODE:
1099
1138
  return {
1100
1139
  type: NodeType.CDATA,
1101
1140
  textContent: "",
1102
- rootId,
1103
- xPath
1141
+ rootId
1104
1142
  };
1105
1143
  case n.COMMENT_NODE:
1106
1144
  return {
1107
1145
  type: NodeType.Comment,
1108
1146
  textContent: index.textContent(n) || "",
1109
- rootId,
1110
- xPath
1147
+ rootId
1111
1148
  };
1112
1149
  default:
1113
1150
  return false;
@@ -1119,7 +1156,7 @@ function getRootId(doc, mirror) {
1119
1156
  return docId === 1 ? void 0 : docId;
1120
1157
  }
1121
1158
  function serializeTextNode(n, options) {
1122
- const { needsMask, maskTextFn, rootId, cssCaptured, xPath } = options;
1159
+ const { needsMask, maskTextFn, rootId, cssCaptured } = options;
1123
1160
  const parent = index.parentNode(n);
1124
1161
  const parentTagName = parent && parent.tagName;
1125
1162
  let textContent2 = "";
@@ -1136,15 +1173,10 @@ function serializeTextNode(n, options) {
1136
1173
  if (!isStyle && !isScript && textContent2 && needsMask) {
1137
1174
  textContent2 = maskTextFn ? maskTextFn(textContent2, index.parentElement(n)) : textContent2.replace(/[\S]/g, "*");
1138
1175
  }
1139
- const isVisible = isTextVisible(n);
1140
- const isInteractive = isElementInteractive(n);
1141
1176
  return {
1142
1177
  type: NodeType.Text,
1143
1178
  textContent: textContent2 || "",
1144
- rootId,
1145
- isVisible,
1146
- isInteractive,
1147
- xPath
1179
+ rootId
1148
1180
  };
1149
1181
  }
1150
1182
  function serializeElementNode(n, options) {
@@ -1153,7 +1185,6 @@ function serializeElementNode(n, options) {
1153
1185
  blockClass,
1154
1186
  blockSelector,
1155
1187
  excludeAttribute,
1156
- includeAttribute,
1157
1188
  inlineStylesheet,
1158
1189
  maskInputOptions = {},
1159
1190
  maskInputFn,
@@ -1162,8 +1193,7 @@ function serializeElementNode(n, options) {
1162
1193
  recordCanvas,
1163
1194
  keepIframeSrcFn,
1164
1195
  newlyAddedElement = false,
1165
- rootId,
1166
- xPath
1196
+ rootId
1167
1197
  } = options;
1168
1198
  const needBlock = _isBlockedElement(n, blockClass, blockSelector);
1169
1199
  const tagName = getValidTagName(n);
@@ -1171,7 +1201,7 @@ function serializeElementNode(n, options) {
1171
1201
  const len = n.attributes.length;
1172
1202
  for (let i = 0; i < len; i++) {
1173
1203
  const attr = n.attributes[i];
1174
- if (isExcludeAttribute(attr.name, excludeAttribute) && !isIncludeAttribute(attr.name, includeAttribute)) {
1204
+ if (isExcludeAttribute(attr.name, excludeAttribute)) {
1175
1205
  continue;
1176
1206
  }
1177
1207
  if (!ignoreAttribute(tagName, attr.name, attr.value)) {
@@ -1333,8 +1363,6 @@ function serializeElementNode(n, options) {
1333
1363
  if (customElements.get(tagName)) isCustomElement = true;
1334
1364
  } catch (e) {
1335
1365
  }
1336
- const isVisible = isElementVisible(n);
1337
- const isInteractive = isElementInteractive(n);
1338
1366
  return {
1339
1367
  type: NodeType.Element,
1340
1368
  tagName,
@@ -1343,10 +1371,7 @@ function serializeElementNode(n, options) {
1343
1371
  isSVG: isSVGElement(n) || void 0,
1344
1372
  needBlock,
1345
1373
  rootId,
1346
- isCustom: isCustomElement,
1347
- isVisible,
1348
- isInteractive,
1349
- xPath
1374
+ isCustom: isCustomElement
1350
1375
  };
1351
1376
  }
1352
1377
  function lowerIfExists(maybeAttr) {
@@ -1397,7 +1422,6 @@ function serializeNodeWithId(n, options) {
1397
1422
  maskTextClass,
1398
1423
  maskTextSelector,
1399
1424
  excludeAttribute,
1400
- includeAttribute,
1401
1425
  skipChild = false,
1402
1426
  inlineStylesheet = true,
1403
1427
  maskInputOptions = {},
@@ -1433,7 +1457,6 @@ function serializeNodeWithId(n, options) {
1433
1457
  blockClass,
1434
1458
  blockSelector,
1435
1459
  excludeAttribute,
1436
- includeAttribute,
1437
1460
  needsMask,
1438
1461
  inlineStylesheet,
1439
1462
  maskInputOptions,
@@ -1459,6 +1482,22 @@ function serializeNodeWithId(n, options) {
1459
1482
  id = genId();
1460
1483
  }
1461
1484
  const serializedNode = Object.assign(_serializedNode, { id });
1485
+ if (isElement(n) || n.nodeType === Node.TEXT_NODE) {
1486
+ serializedNode.xpath = buildXPath(n);
1487
+ if (isElement(n)) {
1488
+ const selector = buildSelector(n);
1489
+ if (selector) {
1490
+ serializedNode.selector = selector;
1491
+ }
1492
+ }
1493
+ if (n.nodeType === Node.TEXT_NODE) {
1494
+ serializedNode.isVisible = isTextVisible(n);
1495
+ }
1496
+ if (n.nodeType === Node.ELEMENT_NODE) {
1497
+ serializedNode.isVisible = isElementVisible(n);
1498
+ serializedNode.isInteractive = isElementInteractive(n);
1499
+ }
1500
+ }
1462
1501
  mirror.add(n, serializedNode);
1463
1502
  if (id === IGNORED_NODE) {
1464
1503
  return null;
@@ -1487,7 +1526,6 @@ function serializeNodeWithId(n, options) {
1487
1526
  maskTextClass,
1488
1527
  maskTextSelector,
1489
1528
  excludeAttribute,
1490
- includeAttribute,
1491
1529
  skipChild,
1492
1530
  inlineStylesheet,
1493
1531
  maskInputOptions,
@@ -1548,7 +1586,6 @@ function serializeNodeWithId(n, options) {
1548
1586
  maskTextClass,
1549
1587
  maskTextSelector,
1550
1588
  excludeAttribute,
1551
- includeAttribute,
1552
1589
  skipChild: false,
1553
1590
  inlineStylesheet,
1554
1591
  maskInputOptions,
@@ -1591,7 +1628,6 @@ function serializeNodeWithId(n, options) {
1591
1628
  maskTextClass,
1592
1629
  maskTextSelector,
1593
1630
  excludeAttribute,
1594
- includeAttribute,
1595
1631
  skipChild: false,
1596
1632
  inlineStylesheet,
1597
1633
  maskInputOptions,
@@ -1629,8 +1665,7 @@ function snapshot(n, options) {
1629
1665
  blockSelector = null,
1630
1666
  maskTextClass = "rr-mask",
1631
1667
  maskTextSelector = null,
1632
- excludeAttribute = /^$a/,
1633
- includeAttribute = /.+/i,
1668
+ excludeAttribute = /.^/,
1634
1669
  inlineStylesheet = true,
1635
1670
  inlineImages = false,
1636
1671
  recordCanvas = false,
@@ -1691,7 +1726,6 @@ function snapshot(n, options) {
1691
1726
  maskTextClass,
1692
1727
  maskTextSelector,
1693
1728
  excludeAttribute,
1694
- includeAttribute,
1695
1729
  skipChild: false,
1696
1730
  inlineStylesheet,
1697
1731
  maskInputOptions,
@@ -5728,6 +5762,8 @@ exports.Mirror = Mirror;
5728
5762
  exports.absolutifyURLs = absolutifyURLs;
5729
5763
  exports.adaptCssForReplay = adaptCssForReplay;
5730
5764
  exports.buildNodeWithSN = buildNodeWithSN;
5765
+ exports.buildSelector = buildSelector;
5766
+ exports.buildXPath = buildXPath;
5731
5767
  exports.classMatchesRegex = classMatchesRegex;
5732
5768
  exports.cleanupSnapshot = cleanupSnapshot;
5733
5769
  exports.createCache = createCache;
@@ -5737,7 +5773,6 @@ exports.extractFileExtension = extractFileExtension;
5737
5773
  exports.fixSafariColons = fixSafariColons;
5738
5774
  exports.genId = genId;
5739
5775
  exports.getInputType = getInputType;
5740
- exports.getXPath = getXPath;
5741
5776
  exports.ignoreAttribute = ignoreAttribute;
5742
5777
  exports.interactiveEvents = interactiveEvents;
5743
5778
  exports.interactiveTags = interactiveTags;
@@ -5748,7 +5783,6 @@ exports.isElement = isElement;
5748
5783
  exports.isElementInteractive = isElementInteractive;
5749
5784
  exports.isElementVisible = isElementVisible;
5750
5785
  exports.isExcludeAttribute = isExcludeAttribute;
5751
- exports.isIncludeAttribute = isIncludeAttribute;
5752
5786
  exports.isNativeShadowDom = isNativeShadowDom;
5753
5787
  exports.isNodeMetaEqual = isNodeMetaEqual;
5754
5788
  exports.isShadowRoot = isShadowRoot;