Skip to content

Commit 752fcb1

Browse files
committed
optimization
1 parent 26f1d78 commit 752fcb1

File tree

1 file changed

+68
-17
lines changed

1 file changed

+68
-17
lines changed

lib/core/utils/dq-element.js

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import getSelector from './get-selector';
21
import getAncestry from './get-ancestry';
32
import getXpath from './get-xpath';
43
import getNodeFromTree from './get-node-from-tree';
@@ -7,30 +6,80 @@ import cache from '../base/cache';
76

87
const CACHE_KEY = 'DqElm.RunOptions';
98

10-
function truncate(str, maxLength) {
11-
maxLength = maxLength || 300;
9+
function getFullPathSelector(elm) {
10+
if (elm.nodeName === 'BODY') {
11+
return 'BODY';
12+
}
13+
14+
if (cache.get('getFullPathSelector') === undefined) {
15+
cache.set('getFullPathSelector', new WeakMap());
16+
}
1217

13-
if (str.length > maxLength) {
14-
var index = str.indexOf('>');
15-
str = str.substring(0, index + 1);
18+
// Check cache first
19+
const sourceCache = cache.get('getFullPathSelector');
20+
if (sourceCache.has(elm)) {
21+
return sourceCache.get(elm);
1622
}
1723

18-
return str;
24+
const element = elm;
25+
const names = [];
26+
while (elm.parentElement && elm.nodeName !== 'BODY') {
27+
if (elm.id) {
28+
names.unshift('#' + elm.getAttribute('id'));
29+
break;
30+
} else {
31+
let c = 1,
32+
e = elm;
33+
for (; e.previousElementSibling; e = e.previousElementSibling, c++) {}
34+
names.unshift(elm.nodeName + ':nth-child(' + c + ')');
35+
}
36+
elm = elm.parentElement;
37+
}
38+
39+
const selector = names.join('>');
40+
sourceCache.set(element, selector);
41+
return selector;
1942
}
2043

2144
function getSource(element) {
22-
if (!element?.outerHTML) {
45+
if (!element) {
2346
return '';
2447
}
25-
var source = element.outerHTML;
26-
if (!source && typeof window.XMLSerializer === 'function') {
27-
source = new window.XMLSerializer().serializeToString(element);
48+
49+
// Initialize cache if needed
50+
if (cache.get('getSourceEfficient') === undefined) {
51+
cache.set('getSourceEfficient', new WeakMap());
52+
}
53+
54+
// Check cache first
55+
const sourceCache = cache.get('getSourceEfficient');
56+
if (sourceCache.has(element)) {
57+
return sourceCache.get(element);
2858
}
29-
let htmlString = truncate(source || '');
30-
// Remove unwanted attributes
31-
const regex = /\s*data-percy-[^=]+="[^"]*"/g;
32-
htmlString = htmlString.replace(regex, '');
33-
return htmlString;
59+
60+
// Compute value if not cached
61+
const tagName = element.nodeName?.toLowerCase();
62+
if (!tagName) {
63+
return '';
64+
}
65+
66+
let result;
67+
try {
68+
const attributes = Array.from(element.attributes || [])
69+
.filter(attr => !attr.name.startsWith('data-percy-'))
70+
.map(attr => `${attr.name}="${attr.value}"`)
71+
.join(' ');
72+
73+
result = attributes ? `<${tagName} ${attributes}>` : `<${tagName}>`;
74+
75+
// Store in cache
76+
sourceCache.set(element, result);
77+
} catch (e) {
78+
// Handle potential errors (like accessing attributes on non-element nodes)
79+
result = `<${tagName || 'unknown'}>`;
80+
}
81+
82+
return result;
3483
}
3584

3685
/**
@@ -94,7 +143,9 @@ DqElement.prototype = {
94143
* @return {String}
95144
*/
96145
get selector() {
97-
return this.spec.selector || [getSelector(this.element, this._options)];
146+
return (
147+
this.spec.selector || [getFullPathSelector(this.element, this._options)]
148+
);
98149
},
99150

100151
/**

0 commit comments

Comments
 (0)