@whenessel/seql-js 1.0.0 → 1.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/dist/seql-js.js +2637 -1
- package/dist/seql-js.js.map +1 -1
- package/dist/seql-js.umd.cjs +1 -1
- package/dist/seql-js.umd.cjs.map +1 -1
- package/package.json +1 -1
package/dist/seql-js.js
CHANGED
|
@@ -1,2 +1,2638 @@
|
|
|
1
|
-
const t="1.0",e=10,s=.4,r=.3,n=.2,i=.1,a=.5,o=.3,c=.1,l=.1,h=.05,u=5,d=.05,g=.3,f=.7,m=["form","main","nav","section","article","footer","header"],p=["form","navigation","main","region","contentinfo","complementary","banner","search"],b=["article","aside","details","figcaption","figure","footer","header","main","mark","nav","section","summary","time","button","datalist","fieldset","form","input","label","legend","meter","optgroup","option","output","progress","select","textarea","a","audio","video","canvas","dialog","menu","blockquote","dd","dl","dt","hr","li","ol","ul","p","pre","h1","h2","h3","h4","h5","h6","caption","col","colgroup","table","tbody","td","tfoot","th","thead","tr","svg","path","circle","rect","line","polyline","polygon","ellipse","g","text","use"],y=["rect","path","circle","line","polyline","polygon","ellipse","g","text","use","defs","clipPath","mask"],x=["aria-label","aria-labelledby","aria-describedby","name","type","data-testid","data-qa","data-test","href","title","placeholder","alt"],S={"data-testid":100,"data-qa":99,"data-cy":98,"data-test":97,"data-test-id":96,"aria-label":90,"aria-labelledby":85,"aria-describedby":80,name:75,href:70,src:70,type:65,role:60,alt:55,title:50,for:45,placeholder:40,"data-*":30,"aria-*":25},A=/* @__PURE__ */new Set(["id","class","style","xmlns","tabindex","contenteditable"]),C={maxPathDepth:10,enableSvgFingerprint:!0,confidenceThreshold:.1,fallbackToBody:!0,includeUtilityClasses:!1,source:"dom-dsl"},w={strictMode:!1,enableFallback:!0,maxCandidates:20};function $(t){return!!/^[a-z]+-\d+$/i.test(t)||(!!/^\d+$/.test(t)||(!!/^:[a-z0-9]+:$/i.test(t)||(!!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(t)||(!(!/^[a-z]{1,3}[A-Za-z0-9]{8,}$/.test(t)||!/\d/.test(t)&&!/[A-Z]/.test(t))||(!!/^radix-/.test(t)||!!/^mui-\d+$/.test(t))))))}class v{constructor(t,e){this.maxDepth=t.maxPathDepth??10,this.cache=e}findAnchor(t){if(this.cache){const e=this.cache.getAnchor(t);if(void 0!==e)return e}let e=t.parentElement,s=0,r=null;for(;e&&s<this.maxDepth;){if("body"===e.tagName.toLowerCase())return r||{element:e,score:g,tier:"C",depth:s};const t=this.scoreAnchor(e);if(t>0){const n=this.applyDepthPenalty(t,s),i=this.getTier(e),a={element:e,score:n,tier:i,depth:s};if("A"===i)return a;(!r||n>r.score)&&(r=a)}e=e.parentElement,s++}const n=r;return this.cache&&this.cache.setAnchor(t,n),n}scoreAnchor(t){let e=0;const s=t.tagName.toLowerCase();m.includes(s)&&(e+=a);const r=t.getAttribute("role");r&&p.includes(r)&&(e+=o),(t.hasAttribute("aria-label")||t.hasAttribute("aria-labelledby"))&&(e+=c);const n=t.id;return n&&!$(n)&&(e+=l),(t.hasAttribute("data-testid")||t.hasAttribute("data-qa")||t.hasAttribute("data-test"))&&(e+=h),Math.min(e,1)}applyDepthPenalty(t,e){if(e<=u)return t;const s=(e-u)*d;return Math.max(0,t-s)}getTier(t){const e=t.tagName.toLowerCase();if(m.includes(e))return"A";const s=t.getAttribute("role");return s&&p.includes(s)?"B":"C"}}const M=[/^css-[a-z0-9]+$/i,/^sc-[a-z0-9]+-\d+$/i,/^[a-z]{5,8}$/i,/^Mui[A-Z]\w+-\w+-\w+/,/^makeStyles-\w+-\d+$/,/^jss\d+$/,/^(emotion|linaria)-[a-z0-9]+/i,/^(chakra|tw-|ant-)[a-z0-9]+-\w+/i,/-[a-f0-9]{6,}$/i,/^_[a-z0-9]{5,}$/i,/\d{5,}/],q=[/^\[/,/^(first|last|odd|even|only|first-of-type|last-of-type|only-of-type):/,/^(hover|focus|active|disabled|enabled|checked|indeterminate|default|required|valid|invalid|in-range|out-of-range|placeholder-shown|autofill|read-only):/,/^(focus-within|focus-visible|visited|target|open):/,/^(sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl):/,/^dark:/,/^(rtl|ltr):/,/^(group|peer)(-hover|-focus|-active)?:/,/\/([\d.]+|full|auto|screen)$/,/^(inset|top|right|bottom|left)(-|$)/,/^(flex|inline-flex|grid|block|inline|inline-block|hidden|visible)$/,/^(absolute|relative|fixed|sticky|static)$/,/^(items|justify|content|self|place)-/,/^flex-(row|col|wrap|nowrap|1|auto|initial|none)/,/^grid-(cols|rows|flow)/,/^(gap|space)-/,/^[mp][trblxy]?-(\d+|auto|px)$/,/^(w|h|min-w|min-h|max-w|max-h|size)-/,/^text-(center|left|right|justify|start|end|xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)$/,/^text-(uppercase|lowercase|capitalize|normal-case|underline|line-through|no-underline)$/,/^text-(truncate|ellipsis|clip)$/,/^(bg|border|ring|shadow|outline)-/,/^rounded(-|$)/,/^(font|leading|tracking|whitespace|break|truncate)-/,/^(uppercase|lowercase|capitalize|normal-case)$/,/^(transform|transition|duration|delay|ease|animate)-/,/^(scale|rotate|translate|skew)-/,/^transform$/,/^backdrop-blur-/,/^motion-/,/^(fade|slide|zoom|bounce|pulse|spin|ping)-/,/^(overflow|overscroll|scroll)-/,/^(cursor|pointer-events|select|resize)-/,/^(opacity|z)-/,/^(visible|invisible|collapse)$/,/^d-(none|inline|inline-block|block|grid|table|flex)$/,/^(float|clearfix|text)-(left|right|center|justify|start|end)$/,/^(m|p)[trblxy]?-[0-5]$/,/^(w|h)-(25|50|75|100|auto)$/,/^btn-(sm|lg|block)$/,/^text-(muted|primary|success|danger|warning|info|light|dark|white)$/,/^bg-(primary|secondary|success|danger|warning|info|light|dark|white|transparent)$/,/^border(-top|-bottom|-left|-right)?(-0)?$/,/^rounded(-top|-bottom|-left|-right|-circle|-pill|-0)?$/,/^shadow(-sm|-lg|-none)?$/,/^(align|justify|order|flex)-(start|end|center|between|around|fill|grow|shrink)$/,/^col(-sm|-md|-lg|-xl)?(-\d+|-auto)?$/,/^row(-cols)?(-\d+)?$/,/^g[xy]?-[0-5]$/,/^(show|hide|invisible|visible)$/,/^(position|top|bottom|start|end)-(static|relative|absolute|fixed|sticky|-\d+)$/,/^(row|col)$/,/^clearfix$/,/^pull-(left|right)$/,/^float-(left|right|none)$/],T=[/^(nav|menu|header|footer|sidebar|topbar|navbar|breadcrumb)/,/(navigation|dropdown|megamenu)$/,/^(btn|button|link|card|modal|dialog|popup|tooltip|alert|badge|chip)/,/^(form|input|select|checkbox|radio|textarea|label|fieldset)/,/^(table|list|item|row|cell|column)/,/^(accordion|tab|carousel|slider|gallery)/,/^(content|main|article|post|comment|title|subtitle|description|caption)/,/^(hero|banner|jumbotron|section|wrapper|box)/,/^(user|profile|avatar|account|auth)/,/^(product|item|price|cart|checkout|order)/,/^(page|layout|panel|widget|block)/,/-(primary|secondary|tertiary|success|error|warning|info|danger)$/,/-(active|inactive|disabled|enabled|selected|highlighted|focused)$/,/-(open|closed|expanded|collapsed|visible|hidden)$/,/-(large|medium|small|tiny|xs|sm|md|lg|xl)$/,/^(submit|cancel|close|delete|edit|save|back|next|prev|search)/,/^(loading|pending|complete|failed|draft|published)/];function N(t){return M.some(e=>e.test(t))}function k(t){return t.length<=2||(!!/^\d/.test(t)||q.some(e=>e.test(t)))}function E(t){return t.filter(t=>{return!N(e=t)&&!k(e);var e})}function H(t){if(N(t)||k(t))return 0;let e=.5;return function(t){return!N(t)&&!k(t)&&T.some(e=>e.test(t))}(t)&&(e=.8),t.length<3?e*=.3:t.length<5&&(e*=.6),/\d/.test(t)&&(e*=.7),Math.min(e,1)}function z(t){const e=[],s=[];for(const r of t)k(r)||N(r)?s.push(r):e.push(r);return{semantic:e,utility:s}}function j(t){return k(t)||N(t)}function D(t){return H(t)}const F=t=>t.replace(/([#:.[\]@])/g,"\\$1");class L{constructor(t,e){this.maxDepth=t.maxPathDepth??10,this.cache=e}buildPath(t,e,s){const r=[];let n=e.parentElement;for(;n&&n!==t&&r.length<this.maxDepth;)r.unshift(n),n=n.parentElement;const i=r.length>=this.maxDepth&&n!==t;let a=this.filterNoise(r);a=this.ensureUniqueness(r,a,t,e,s);return{path:a.map(t=>{const e=t.parentElement;let r;if(e){const s=Array.from(e.children).indexOf(t);-1!==s&&(r=s+1)}return{tag:t.tagName.toLowerCase(),semantics:s.extract(t),score:s.scoreElement(t),nthChild:r}}),degraded:i,degradationReason:i?"path-depth-overflow":void 0}}buildPathNodes(t,e,s){return this.buildPath(t,e,s).path}ensureUniqueness(t,e,s,r,n){const i=this.buildTestSelector(s,e,r);try{const a=r.ownerDocument;if(!a)return e;let o;if(this.cache){const t=this.cache.getSelectorResults(i);void 0!==t?o=t:(o=Array.from(a.querySelectorAll(i)),this.cache.setSelectorResults(i,o))}else o=a.querySelectorAll(i);if(o.length<=1)return e;const c=t.filter(t=>!e.includes(t));for(const i of c){if(n.scoreElement(i)<f)continue;const c=this.insertNodeInOrder(e,i,t),l=this.buildTestSelector(s,c,r);try{let t;if(this.cache){const e=this.cache.getSelectorResults(l);void 0!==e?t=e:(t=Array.from(a.querySelectorAll(l)),this.cache.setSelectorResults(l,t))}else t=a.querySelectorAll(l);if(1===t.length)return c;t.length<o.length&&(e=c)}catch{}}return e}catch{return e}}insertNodeInOrder(t,e,s){const r=s.indexOf(e),n=[...t];let i=0;for(let a=0;a<n.length;a++){if(s.indexOf(n[a])>r)break;i=a+1}return n.splice(i,0,e),n}buildTestSelector(t,e,s){const r=[];r.push(this.elementToSelector(t));for(const n of e)r.push(this.elementToSelector(n));return r.push(this.elementToSelector(s)),r.join(" ")}elementToSelector(t){let e=t.tagName.toLowerCase();t.id&&!$(t.id)&&(e+=`#${F(t.id)}`);for(const s of Array.from(t.classList))j(s)||(e+=`.${F(s)}`);return e}filterNoise(t){return t.filter(t=>this.shouldInclude(t))}shouldInclude(t){const e=t.tagName.toLowerCase();return!!b.includes(e)||("div"===e||"span"===e)&&this.hasSemanticFeatures(t)}hasSemanticFeatures(t){if(t.hasAttribute("role"))return!0;for(const s of Array.from(t.attributes))if(s.name.startsWith("aria-"))return!0;if(t.classList.length>0)for(const s of Array.from(t.classList))if(!j(s))return!0;if(t.hasAttribute("data-testid")||t.hasAttribute("data-qa")||t.hasAttribute("data-test"))return!0;const e=t.id;return!(!e||$(e))}}function U(t){return t?t.trim().replace(/[\n\t\r]/g," ").replace(/\s+/g," "):""}const R={preserveQueryForAbsolute:!0,removeDynamicHashes:!0};function P(t,e,s={}){if(!e)return e;const r={...R,...s};return"href"===t||"src"===t?function(t,e){if(!t)return t;const s=t.startsWith("http://")||t.startsWith("https://");let[r,n]=t.split("#");const[i,a]=r.split("?");let o=i;return s&&e.preserveQueryForAbsolute&&a&&(o+=`?${a}`),n&&(e.removeDynamicHashes&&function(t){return!!t&&[/\d{5,}/,/[a-f0-9]{8,}/i,/(session|token|temp|random|timestamp|nonce|cache)/i,/^\d+$/,/^[a-f0-9-]{32,}$/i].some(e=>e.test(t))}(n)||(o+=`#${n}`)),o}(e,r):e}class O{constructor(t,e){this.includeUtilityClasses=t.includeUtilityClasses??!1,this.cache=e}extract(t){if(this.cache){const e=this.cache.getSemantics(t);if(void 0!==e)return e}const e={},s=t.id;if(s&&!$(s)&&(e.id=s),t.classList.length>0){const s=Array.from(t.classList);if(this.includeUtilityClasses)e.classes=s;else{const{semantic:t}=z(s);t.length>0&&(e.classes=t)}}const r=this.extractAttributes(t);Object.keys(r).length>0&&(e.attributes=r);const n=t.getAttribute("role");if(n&&(e.role=n),this.shouldExtractText(t)){const s=this.extractText(t);s&&(e.text=s)}return this.cache&&this.cache.setSemantics(t,e),e}scoreElement(t){let e=.5;const s=this.extract(t);return s.id&&(e+=.15),s.classes&&s.classes.length>0&&(e+=.1),s.attributes&&Object.keys(s.attributes).length>0&&(e+=.1),s.role&&(e+=.1),s.text&&(e+=.05),Math.min(e,1)}shouldIgnoreAttribute(t){return!!A.has(t)||(!!t.startsWith("on")||(!(!t.startsWith("ng-")&&!t.startsWith("_ng"))||(!(!t.startsWith("data-reactid")&&!t.startsWith("data-react"))||!!t.startsWith("data-v-"))))}getAttributePriority(t){return void 0!==S[t]?S[t]:t.startsWith("data-")?S["data-*"]:t.startsWith("aria-")?S["aria-*"]:0}isDynamicValue(t){return[/^[a-f0-9]{32,}$/i,/^\d{10,}$/,/^(undefined|null|\[object)/,/^{{.*}}$/].some(e=>e.test(t))}extractAttributes(t){const e={};for(const s of Array.from(t.attributes)){const t=s.name;if(this.shouldIgnoreAttribute(t))continue;if(0===this.getAttributePriority(t))continue;const r="href"===t||"src"===t?P(t,s.value):s.value;r&&""!==r.trim()&&(this.isDynamicValue(r)||(e[t]=r))}return e}extractText(t){const e=this.getDirectTextContent(t);if(!e)return null;const s=U(e);if(!s)return null;const r=100;return{raw:e.length>r?e.slice(0,r)+"...":e,normalized:s.length>r?s.slice(0,r)+"...":s}}getDirectTextContent(t){const e=[];for(const s of Array.from(t.childNodes))if(s.nodeType===Node.TEXT_NODE&&s.textContent){const t=s.textContent.trim();t&&e.push(t)}return e.length>0?e.join(" "):t.textContent??null}shouldExtractText(t){const e=t.tagName.toLowerCase();return["button","a","label","h1","h2","h3","h4","h5","h6","p","span","li","th","td","dt","dd","legend","figcaption","summary"].includes(e)}}class I{fingerprint(t){const e=t.tagName.toLowerCase(),s=this.getShape(e),r={shape:s,hasAnimation:this.hasAnimation(t)};if("path"===s){const e=t.getAttribute("d");e&&(r.dHash=this.computePathHash(e))}else["circle","rect","ellipse","line"].includes(s)&&(r.geomHash=this.computeGeomHash(t,s));const n=t.getAttribute("role");n&&(r.role=n);const i=t.querySelector("title");return i?.textContent&&(r.titleText=i.textContent.trim()),r}computePathHash(t){const e=this.normalizePathData(t);return this.simpleHash(e)}getShape(t){return["path","circle","rect","line","polyline","polygon","ellipse","g","text","use","svg"].find(e=>e===t)??"path"}normalizePathData(t){return(t.match(/[MLHVCSQTAZ][^MLHVCSQTAZ]*/gi)??[]).slice(0,5).map(t=>t.trim().replace(/(-?\d+\.?\d*)/g,t=>parseFloat(t).toFixed(1))).join(" ")}computeGeomHash(t,e){const s=[];switch(e){case"circle":s.push(`r=${t.getAttribute("r")??"0"}`);break;case"rect":{const e=parseFloat(t.getAttribute("width")??"0"),r=parseFloat(t.getAttribute("height")??"0");e>0&&r>0&&s.push(`ratio=${(e/r).toFixed(2)}`)}break;case"ellipse":{const e=parseFloat(t.getAttribute("rx")??"0"),r=parseFloat(t.getAttribute("ry")??"0");e>0&&r>0&&s.push(`ratio=${(e/r).toFixed(2)}`)}break;case"line":{const e=parseFloat(t.getAttribute("x1")??"0"),r=parseFloat(t.getAttribute("y1")??"0"),n=parseFloat(t.getAttribute("x2")??"0"),i=parseFloat(t.getAttribute("y2")??"0"),a=Math.atan2(i-r,n-e);s.push(`angle=${a.toFixed(2)}`)}}return this.simpleHash(s.join(";"))}hasAnimation(t){if(t.querySelector("animate, animateTransform, animateMotion"))return!0;const e=t.ownerDocument;if(e?.defaultView)try{const s=e.defaultView.getComputedStyle(t);if("none"!==s.animationName||"all"!==s.transitionProperty&&"none"!==s.transitionProperty)return!0}catch{}return!1}simpleHash(t){let e=0;for(let s=0;s<t.length;s++){e=(e<<5)-e+t.charCodeAt(s),e&=e}return Math.abs(e).toString(16).padStart(8,"0")}}function W(t,e=0){const a=t.anchor.score,o=t.path.length>0?t.path.reduce((t,e)=>t+e.score,0)/t.path.length:.5,c=t.target.score,l=a*s+o*r+c*n+e*i,h=t.anchor.degraded?.2:0;return Math.max(0,Math.min(1,l-h))}function B(t,e,s){let r=.5;return e&&(r+=.2),s&&(r+=.15),r+=Math.min(.05*t,.15),Math.min(r,1)}class Q{constructor(t){this.cache=/* @__PURE__ */new Map,this.maxSize=t}get(t){if(!this.cache.has(t))return;const e=this.cache.get(t);return this.cache.delete(t),this.cache.set(t,e),e}set(t,e){if(this.cache.has(t))this.cache.delete(t);else if(this.cache.size>=this.maxSize){const t=this.cache.keys().next().value;void 0!==t&&this.cache.delete(t)}this.cache.set(t,e)}has(t){return this.cache.has(t)}delete(t){this.cache.delete(t)}clear(){this.cache.clear()}get size(){return this.cache.size}}class Z{constructor(t={}){this.eidCache=/* @__PURE__ */new WeakMap,this.selectorResultCache=new Q(t.maxSelectorCacheSize??1e3),this.anchorCache=/* @__PURE__ */new WeakMap,this.semanticsCache=/* @__PURE__ */new WeakMap,this.stats={eidHits:0,eidMisses:0,selectorHits:0,selectorMisses:0,anchorHits:0,anchorMisses:0,semanticsHits:0,semanticsMisses:0,selectorCacheSize:0,maxSelectorCacheSize:t.maxSelectorCacheSize??1e3}}getEID(t){const e=this.eidCache.get(t);if(void 0!==e)return this.stats.eidHits++,e;this.stats.eidMisses++}setEID(t,e){this.eidCache.set(t,e)}getSelectorResults(t){const e=this.selectorResultCache.get(t);if(void 0!==e)return this.stats.selectorHits++,this.stats.selectorCacheSize=this.selectorResultCache.size,e;this.stats.selectorMisses++,this.stats.selectorCacheSize=this.selectorResultCache.size}setSelectorResults(t,e){this.selectorResultCache.set(t,e),this.stats.selectorCacheSize=this.selectorResultCache.size}getAnchor(t){if(this.anchorCache.has(t))return this.stats.anchorHits++,this.anchorCache.get(t);this.stats.anchorMisses++}setAnchor(t,e){this.anchorCache.set(t,e)}getSemantics(t){const e=this.semanticsCache.get(t);if(void 0!==e)return this.stats.semanticsHits++,e;this.stats.semanticsMisses++}setSemantics(t,e){this.semanticsCache.set(t,e)}clear(){this.selectorResultCache.clear(),this.stats.selectorCacheSize=0,this.stats={eidHits:0,eidMisses:0,selectorHits:0,selectorMisses:0,anchorHits:0,anchorMisses:0,semanticsHits:0,semanticsMisses:0,selectorCacheSize:0,maxSelectorCacheSize:this.stats.maxSelectorCacheSize}}invalidateElement(t){}invalidateSelector(t){this.selectorResultCache.delete(t),this.stats.selectorCacheSize=this.selectorResultCache.size}getStats(){return{...this.stats,selectorCacheSize:this.selectorResultCache.size}}getEIDHitRate(){const t=this.stats.eidHits+this.stats.eidMisses;return t>0?this.stats.eidHits/t:0}getSelectorHitRate(){const t=this.stats.selectorHits+this.stats.selectorMisses;return t>0?this.stats.selectorHits/t:0}getAnchorHitRate(){const t=this.stats.anchorHits+this.stats.anchorMisses;return t>0?this.stats.anchorHits/t:0}getSemanticsHitRate(){const t=this.stats.semanticsHits+this.stats.semanticsMisses;return t>0?this.stats.semanticsHits/t:0}getOverallHitRate(){const t=this.stats.eidHits+this.stats.selectorHits+this.stats.anchorHits+this.stats.semanticsHits,e=t+(this.stats.eidMisses+this.stats.selectorMisses+this.stats.anchorMisses+this.stats.semanticsMisses);return e>0?t/e:0}}function V(t){return new Z(t)}let G=null;function _(){return G||(G=V()),G}function J(){G=null}function X(e,s={}){if(!e||!e.ownerDocument)return null;if(!e.isConnected)return null;const r={...C,...s},n=r.cache??_(),i=n.getEID(e);if(void 0!==i)return i;const a=new v(r,n),o=new L(r,n),c=new O(r,n),l=new I,h=a.findAnchor(e);if(!h&&!r.fallbackToBody)return null;const u=h?.element??e.ownerDocument?.body??null;if(!u)return null;const d=!h||"C"===h.tier,f=c.extract(u),m={tag:u.tagName.toLowerCase(),semantics:f,score:h?.score??g,degraded:d},p=o.buildPath(u,e,c),b=c.extract(e);var y;r.enableSvgFingerprint&&("http://www.w3.org/2000/svg"===(y=e).namespaceURI||"svg"===y.tagName.toLowerCase()||y instanceof SVGElement)&&(b.svg=l.fingerprint(e));const x=e.parentElement;let S;if(x){const t=Array.from(x.children).indexOf(e);-1!==t&&(S=t+1)}const A={tag:e.tagName.toLowerCase(),semantics:b,score:c.scoreElement(e),nthChild:S},w=m.degraded||p.degraded,$=function(t,e){if(t&&e.degraded)return"anchor-and-path-degraded";if(t)return"no-semantic-anchor";if(e.degraded)return e.degradationReason;return}(m.degraded,p),M={version:t,anchor:m,path:p.path,target:A,constraints:[],fallback:{onMultiple:"best-score",onMissing:"anchor-only",maxDepth:3},meta:{confidence:0,generatedAt:/* @__PURE__ */(new Date).toISOString(),generator:`dom-eid@${t}`,source:r.source,degraded:w,degradationReason:$}};return M.meta.confidence=W(M),M.meta.confidence<r.confidenceThreshold?null:(n.setEID(e,M),M)}class K{buildSelector(t,e){if(0===t.path.length&&t.anchor.tag===t.target.tag&&JSON.stringify(t.anchor.semantics)===JSON.stringify(t.target.semantics)){const s=this.buildNodeSelector(t.target.tag,t.target.semantics,{excludeClasses:!1});return e?.ensureUnique?this.ensureUniqueSelector(s,t,e):s}const s=[],r=e?.ensureUnique?this.ensureUniqueAnchor(t,e.root??document):this.buildNodeSelector(t.anchor.tag,t.anchor.semantics);s.push(r);for(const l of t.path){let t=this.buildNodeSelector(l.tag,l.semantics);if(void 0!==l.nthChild){["tr","td","th","thead","tbody","tfoot"].includes(l.tag);t+=`:nth-child(${l.nthChild})`}s.push(t)}let n=this.buildNodeSelector(t.target.tag,t.target.semantics,{excludeClasses:e?.ensureUnique});if(void 0!==t.target.nthChild){["tr","td","th","thead","tbody","tfoot"].includes(t.target.tag);n+=`:nth-child(${t.target.nthChild})`}s.push(n);const i=this.isSvgChildElement(t.target.tag),a=t.path.some(t=>"svg"===t.tag);let o;if(i&&a){const e=t.path.findIndex(t=>"svg"===t.tag);if(-1!==e){const t=e+1,r=s.slice(0,t+1),n=s.slice(t+1,-1),i=s[s.length-1];o=n.length>0?r.join(" ")+" > "+n.join(" > ")+" > "+i:r.join(" ")+" > "+i}else o=s.join(" ")}else o=s.join(" ");if(!e?.ensureUnique)return o;const c=this.querySelectorSafe(o,e.root??document);if(1===c.length)return{selector:o,isUnique:!0,usedNthOfType:o.includes(":nth-"),extraClassesAdded:0};if(0===c.length||c.length>1){const s=this.buildFullDomPathSelector(t,t.target.semantics,e.root??document);if(s&&this.isUnique(s,e.root??document))return{selector:s,isUnique:!0,usedNthOfType:s.includes(":nth-"),extraClassesAdded:0}}return this.ensureUniqueSelector(o,t,e)}buildAnchorSelector(t){return this.buildNodeSelector(t.anchor.tag,t.anchor.semantics)}ensureUniqueSelector(t,e,s){const r=s.root??document,n=s.maxClasses??4,i=e.target.tag,a=e.target.semantics;let o=t,c=0,l=!1;if(0===this.querySelectorSafe(o,r).length){const t=this.buildFullDomPathSelector(e,a,r);if(t&&(o=t,this.isUnique(o,r)))return{selector:o,isUnique:!0,usedNthOfType:!1,extraClassesAdded:0}}if(this.isUnique(o,r))return{selector:o,isUnique:!0,usedNthOfType:!1,extraClassesAdded:0};const h=E(a.classes??[]);for(let d=0;d<Math.min(h.length,n);d++){const t=h[d];if(o+=`.${this.escapeCSS(t)}`,c++,this.isUnique(o,r))return{selector:o,isUnique:!0,usedNthOfType:!1,extraClassesAdded:c}}if(!this.isUnique(o,r)){const t=this.buildFullDomPathSelector(e,a,r);if(t&&this.isUnique(t,r))return{selector:t,isUnique:!0,usedNthOfType:t.includes(":nth-of-type("),extraClassesAdded:c}}const u=this.findNthElementByText(o,a,r);return u&&(o+=this.getNthSelector(u,i),l=!0),{selector:o,isUnique:this.isUnique(o,r),usedNthOfType:l,extraClassesAdded:c}}buildFullDomPathSelector(t,e,s){const r=this.buildNodeSelector(t.anchor.tag,t.anchor.semantics),n=this.querySelectorSafe(r,s);if(0===n.length)return null;for(const i of n){const r=this.findTargetWithinAnchor(i,t.target.tag,e);if(0===r.length)continue;const n=r.map(e=>({element:e,score:this.scorePathMatch(e,i,t.path)}));n.sort((t,e)=>e.score-t.score);for(const{element:e}of n){const r=this.buildPathFromAnchorToTarget(i,e,t,s);if(r&&this.isUnique(r,s))return r}}return null}scorePathMatch(t,e,s){const r=[];let n=t.parentElement;for(;n&&n!==e;)r.unshift(n),n=n.parentElement;let i=0;const a=Math.min(r.length,s.length);for(let o=0;o<a;o++){const t=r[o],e=s[o];if(t.tagName.toLowerCase()===e.tag){if(i+=10,void 0!==e.nthChild){const s=t.parentElement;if(s){Array.from(s.children).indexOf(t)+1===e.nthChild?i+=20:i-=10}}}else i-=5;if(e.semantics.classes&&e.semantics.classes.length>0){i+=2*e.semantics.classes.filter(e=>t.classList.contains(e)).length}if(e.semantics.attributes){i+=3*Object.entries(e.semantics.attributes).filter(([e,s])=>t.getAttribute(e)===s).length}}return i-=2*Math.abs(r.length-s.length),i}findTargetWithinAnchor(t,e,s){return Array.from(t.querySelectorAll(e)).filter(t=>{if(s.text){const e=t.textContent?.trim()||"",r=s.text.normalized;if(!e.includes(r)&&!r.includes(e))return!1}if(s.classes&&s.classes.length>0){if(s.classes.every(e=>t.classList.contains(e)))return!0}if(s.attributes){if(Object.entries(s.attributes).every(([e,s])=>{const r=t.getAttribute(e);return"href"===e||"src"===e?P(e,r||"")===P(e,s):r===s}))return!0}return!!s.text})}disambiguateParent(t,e,s,r,n){if(s?.semantics?.attributes){const t=this.buildNodeSelector(e,s.semantics,{excludeClasses:!0}),i=[...r,e].join(" > "),a=this.querySelectorSafe(i,n),o=[...r,t].join(" > "),c=this.querySelectorSafe(o,n);if(c.length>0&&c.length<a.length)return t}if(s?.semantics?.classes){const t=E(s.semantics.classes);if(t.length>0){const s=`${e}.${this.escapeCSS(t[0])}`,i=[...r,e].join(" > "),a=this.querySelectorSafe(i,n),o=[...r,s].join(" > "),c=this.querySelectorSafe(o,n);if(c.length>0&&c.length<a.length)return s}}const i=t.parentElement;if(i){if(Array.from(i.children).filter(t=>t.tagName.toLowerCase()===e).length>1)return`${e}${this.getNthSelector(t,e)}`}return e}buildPathFromAnchorToTarget(t,e,s,r){const n=[];let i=e;for(;i&&i!==t;)n.unshift(i),i=i.parentElement;if(i!==t)return null;const a=[()=>{const t=this.buildNodeSelector(s.anchor.tag,s.anchor.semantics),e=s.target.tag,n=s.target.semantics,i=[];for(const r of s.path)i.push(r.tag);const a=[t,...i,e].filter(Boolean).join(" ");if(this.isUnique(a,r))return a;const o=this.buildNodeSelector(e,n,{excludeClasses:!0}),c=[t,...i.slice(0,-1),o].join(" ");return this.isUnique(c,r)?c:null},()=>{const t=[this.buildNodeSelector(s.anchor.tag,s.anchor.semantics)],e=/* @__PURE__ */new Map;let i=0;for(let r=0;r<n.length-1;r++){const t=n[r],a=t.tagName.toLowerCase();i<s.path.length&&s.path[i].tag===a?(e.set(t,s.path[i]),i++):e.set(t,null)}for(let o=0;o<n.length;o++){const i=n[o],a=i.tagName.toLowerCase();if(o<n.length-1){const s=e.get(i)||null,n=this.disambiguateParent(i,a,s,t,r);t.push(n);continue}const c=this.buildNodeSelector(s.target.tag,s.target.semantics,{excludeClasses:!0}),l=i.parentElement;if(l&&["td","th","tr","thead","tbody","tfoot"].includes(a)){Array.from(l.children).filter(t=>t.tagName.toLowerCase()===a).length>1?t.push(`${c}${this.getNthSelector(i,a)}`):t.push(c)}else t.push(c)}const a=t.join(" > ");return this.isUnique(a,r)?a:null},()=>{const t=[this.buildNodeSelector(s.anchor.tag,s.anchor.semantics)];for(let a=0;a<n.length-1;a++){const e=n[a].tagName.toLowerCase(),i=s.path[a]||null,o=t.join(" ")+" "+e;if(this.querySelectorSafe(o,r).length>1){if(i?.semantics?.attributes){const n=this.buildNodeSelector(e,i.semantics,{excludeClasses:!0}),a=t.join(" ")+" "+n;if(1===this.querySelectorSafe(a,r).length||1===this.querySelectorSafe(a+" "+s.target.tag,r).length){t.push(n);continue}}if(i?.semantics?.classes){const n=E(i.semantics.classes);if(n.length>0){const i=`${e}.${this.escapeCSS(n[0])}`,a=t.join(" ")+" "+i;if(1===this.querySelectorSafe(a,r).length||1===this.querySelectorSafe(a+" "+s.target.tag,r).length){t.push(i);continue}}}const o=n[a],c=o.parentElement;if(c){if(Array.from(c.children).filter(t=>t.tagName.toLowerCase()===e).length>1){t.push(`${e}${this.getNthSelector(o,e)}`);continue}}}t.push(e)}const e=this.buildNodeSelector(s.target.tag,s.target.semantics,{excludeClasses:!0});t.push(e);const i=t.join(" ");return this.isUnique(i,r)?i:null},()=>{const t=this.buildNodeSelector(s.anchor.tag,s.anchor.semantics),e=[];for(const r of s.path)e.push(r.tag);if(0===E(s.target.semantics.classes??[]).length)return null;const n=this.buildNodeSelector(s.target.tag,s.target.semantics,{maxClasses:1}),i=[t,...e.slice(0,-1),n].join(" ");return this.isUnique(i,r)?i:null},()=>{const t=this.buildNodeSelector(s.anchor.tag,s.anchor.semantics),e=[];for(const r of s.path)e.push(r.tag);const i=n[n.length-1],a=i.parentElement;if(!a)return null;if(Array.from(a.children).filter(t=>t.tagName.toLowerCase()===s.target.tag).length<=1)return null;const o=this.buildNodeSelector(s.target.tag,s.target.semantics,{excludeClasses:!0})+this.getNthSelector(i,s.target.tag),c=[t,...e.slice(0,-1),o].join(" ");return this.isUnique(c,r)?c:null}];for(const o of a){const t=o();if(t)return t}return null}buildElementSelector(t){const e=t.tagName.toLowerCase();let s=e;if(t.id&&!this.isDynamicId(t.id))return`${e}#${this.escapeCSS(t.id)}`;const r=E(Array.from(t.classList));r.length>0&&(s+=r.slice(0,2).map(t=>`.${this.escapeCSS(t)}`).join(""));const n=t.getAttribute("role");return n&&(s+=`[role="${this.escapeAttr(n)}"]`),s}isDynamicId(t){return[/^[a-f0-9]{8,}$/i,/^\d{5,}$/,/^(r|react|ember|vue)[\d_]/i,/:r\d+:$/].some(e=>e.test(t))}querySelectorSafe(t,e){try{return Array.from(e.querySelectorAll(t))}catch{return[]}}findNthElementByText(t,e,s){const r=this.querySelectorSafe(t,s);if(r.length<=1)return null;if(e.text){const t=e.text.normalized;for(const e of r){const s=e.textContent?.trim()||"";if(s===t||s.includes(t)||t.includes(s))return e}}return null}isUnique(t,e){try{return 1===e.querySelectorAll(t).length}catch{return!1}}getNthOfTypeIndex(t,e){const s=t.parentElement;if(!s)return null;const r=Array.from(s.children).filter(t=>t.tagName.toLowerCase()===e).indexOf(t);return-1!==r?r+1:null}ensureUniqueAnchor(t,e){const s=t.anchor.tag,r=t.anchor.semantics;if(this.isUnique(s,e))return s;if(r.classes&&r.classes.length>0){const t=E(r.classes);if(t.length>0){const r=`${s}.${this.escapeCSS(t[0])}`;if(this.isUnique(r,e))return r}}if(r.attributes){const t=this.getSortedAttributes(r.attributes);for(const{name:r,value:n}of t){const t="href"===r||"src"===r?P(r,n):n;if(t){const n=`${s}[${r}="${this.escapeAttr(t)}"]`;if(this.isUnique(n,e))return n}}}const n=Array.from(e.querySelectorAll(s));if(n.length>1){const t=this.findElementBySemantics(n,r);if(t){const e=this.getNthOfTypeIndex(t,s);if(e)return`${s}:nth-of-type(${e})`}}return s}findElementBySemantics(t,e){return e.classes&&e.classes.length>0||e.attributes&&Object.keys(e.attributes).length>0||e.text?t.find(t=>{if(e.classes&&e.classes.length>0){if(e.classes.every(e=>t.classList.contains(e)))return!0}if(e.attributes){if(Object.entries(e.attributes).every(([e,s])=>t.getAttribute(e)===s))return!0}if(e.text){const s=t.textContent?.trim()||"",r=e.text.normalized;if(s.includes(r)||r.includes(s))return!0}return!1})||null:t.length>0?t[0]:null}getNthSelector(t,e){const s=t.parentElement;if(!s)return"";const r=Array.from(s.children),n=r.indexOf(t)+1;if(["tr","td","th","thead","tbody","tfoot"].includes(e))return`:nth-child(${n})`;return`:nth-of-type(${r.filter(t=>t.tagName.toLowerCase()===e).indexOf(t)+1})`}getAttributePriority(t){return void 0!==S[t]?S[t]:t.startsWith("data-")?S["data-*"]:t.startsWith("aria-")?S["aria-*"]:0}shouldIgnoreAttribute(t){return!!A.has(t)||(!!t.startsWith("on")||(!(!t.startsWith("ng-")&&!t.startsWith("_ng"))||(!(!t.startsWith("data-reactid")&&!t.startsWith("data-react"))||!!t.startsWith("data-v-"))))}getSortedAttributes(t){return Object.entries(t).filter(([t])=>!this.shouldIgnoreAttribute(t)).map(([t,e])=>({name:t,value:e,priority:this.getAttributePriority(t)})).filter(t=>t.priority>0).sort((t,e)=>e.priority-t.priority)}buildNodeSelector(t,e,s){let r=t;if(e.id)return r+=`#${this.escapeCSS(e.id)}`,r;if(e.attributes){const t=this.getSortedAttributes(e.attributes);for(const{name:e,value:s}of t){const t="href"===e||"src"===e?P(e,s):s;t&&(r+=`[${e}="${this.escapeAttr(t)}"]`)}}if(e.role&&!e.attributes?.role&&(r+=`[role="${this.escapeAttr(e.role)}"]`),!s?.excludeClasses&&e.classes&&e.classes.length>0){const t=E(e.classes);r+=(void 0!==s?.maxClasses?t.slice(0,s.maxClasses):t).map(t=>`.${this.escapeCSS(t)}`).join("")}return r}escapeCSS(t){return t.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g,"\\$1")}escapeAttr(t){return t.replace(/"/g,'\\"').replace(/\\/g,"\\\\")}isSvgChildElement(t){return y.includes(t)}}class Y{match(t,e){return t.filter(t=>this.matchElement(t,e))}matchElement(t,e){return!(e.text&&!this.matchText(t,e.text))&&(!(e.attributes&&!this.matchAttributes(t,e.attributes))&&!(e.svg&&!this.matchSvgFingerprint(t,e.svg)))}matchText(t,e){const s=Array.from(t.childNodes).filter(t=>t.nodeType===Node.TEXT_NODE).map(t=>t.textContent?.trim()??"").join(" ")||(t.textContent?.trim()??"");if(!s)return!1;const r=U(s);return"partial"===e.matchMode?r.includes(e.normalized):r===e.normalized}matchAttributes(t,e){for(const[s,r]of Object.entries(e)){if(t.getAttribute(s)!==r)return!1}return!0}matchSvgFingerprint(t,e){if(t.tagName.toLowerCase()!==e.shape)return!1;if(e.dHash&&"path"===e.shape){const s=t.getAttribute("d");if(s){if(this.computePathHash(s)!==e.dHash)return!1}}if(e.geomHash&&["circle","rect","ellipse","line"].includes(e.shape)){if(this.computeGeomHash(t,e.shape)!==e.geomHash)return!1}if(e.titleText){const s=t.querySelector("title");if(s?.textContent?.trim()!==e.titleText)return!1}return!0}computePathHash(t){const e=(t.match(/[MLHVCSQTAZ][^MLHVCSQTAZ]*/gi)??[]).slice(0,5).map(t=>t.trim().replace(/(-?\d+\.?\d*)/g,t=>parseFloat(t).toFixed(1))).join(" ");return this.simpleHash(e)}computeGeomHash(t,e){const s=[];switch(e){case"circle":s.push(`r=${t.getAttribute("r")??"0"}`);break;case"rect":{const e=parseFloat(t.getAttribute("width")??"0"),r=parseFloat(t.getAttribute("height")??"0");e>0&&r>0&&s.push(`ratio=${(e/r).toFixed(2)}`);break}case"ellipse":{const e=parseFloat(t.getAttribute("rx")??"0"),r=parseFloat(t.getAttribute("ry")??"0");e>0&&r>0&&s.push(`ratio=${(e/r).toFixed(2)}`);break}case"line":{const e=parseFloat(t.getAttribute("x1")??"0"),r=parseFloat(t.getAttribute("y1")??"0"),n=parseFloat(t.getAttribute("x2")??"0"),i=parseFloat(t.getAttribute("y2")??"0"),a=Math.atan2(i-r,n-e);s.push(`angle=${a.toFixed(2)}`);break}}return this.simpleHash(s.join(";"))}simpleHash(t){let e=0;for(let s=0;s<t.length;s++){e=(e<<5)-e+t.charCodeAt(s),e&=e}return Math.abs(e).toString(16).padStart(8,"0")}}class tt{applyConstraint(t,e){switch(e.type){case"text-proximity":return this.applyTextProximity(t,e.params);case"position":return this.applyPosition(t,e.params);default:return t}}applyTextProximity(t,e){return t.filter(t=>{const s=t.textContent?.trim()??"";return this.levenshteinDistance(s,e.reference)<=e.maxDistance})}applyPosition(t,e){if(t.length<=1)return t;switch(e.strategy){case"first-in-dom":default:return[t[0]];case"top-most":return[this.getTopMost(t)];case"left-most":return[this.getLeftMost(t)]}}getTopMost(t){return t.reduce((t,e)=>{try{const s=t.getBoundingClientRect();return e.getBoundingClientRect().top<s.top?e:t}catch{return t}})}getLeftMost(t){return t.reduce((t,e)=>{try{const s=t.getBoundingClientRect();return e.getBoundingClientRect().left<s.left?e:t}catch{return t}})}levenshteinDistance(t,e){if(t===e)return 0;if(0===t.length)return e.length;if(0===e.length)return t.length;const s=Array.from({length:e.length+1},(t,e)=>e);for(let r=1;r<=t.length;r++){let n=r;for(let i=1;i<=e.length;i++){const a=t[r-1]===e[i-1]?s[i-1]:Math.min(s[i-1],n,s[i])+1;s[i-1]=n,n=a}s[e.length]=n}return s[e.length]}}class et{constructor(){this.cssGenerator=new K}handleFallback(t,e){const{onMissing:s}=t.fallback;switch(s){case"anchor-only":return this.fallbackToAnchor(t,e);case"strict":return{status:"error",elements:[],warnings:["Element not found (strict mode)"],confidence:0,meta:{degraded:!0,degradationReason:"strict-not-found"}};default:return{status:"error",elements:[],warnings:["Element not found"],confidence:0,meta:{degraded:!0,degradationReason:"not-found"}}}}fallbackToAnchor(t,e){const s=this.cssGenerator.buildAnchorSelector(t),r=e instanceof Document?e:e.ownerDocument??e;try{const e=r.querySelector(s);if(e)return{status:"degraded-fallback",elements:[e],warnings:["Target not found, returning anchor"],confidence:.3*t.meta.confidence,meta:{degraded:!0,degradationReason:"anchor-fallback"}}}catch(n){return{status:"error",elements:[],warnings:[`Invalid anchor selector: ${n instanceof Error?n.message:"Unknown selector error"}`],confidence:0,meta:{degraded:!0,degradationReason:"invalid-anchor-selector"}}}return{status:"error",elements:[],warnings:["Anchor also not found"],confidence:0,meta:{degraded:!0,degradationReason:"anchor-not-found"}}}handleAmbiguous(t,e){const{onMultiple:s}=e.fallback;switch(s){case"first":return{status:"success",elements:[t[0]],warnings:["Multiple matches, returning first"],confidence:.7*e.meta.confidence,meta:{degraded:!0,degradationReason:"first-of-multiple"}};case"best-score":return this.selectBestScoring(t,e);default:return{status:"ambiguous",elements:t,warnings:[`Multiple matches: ${t.length}`],confidence:.5*e.meta.confidence,meta:{degraded:!0,degradationReason:"multiple-matches"}}}}selectBestScoring(t,e){const s=e.target.semantics;let r=t[0],n=-1;for(const i of t){const t=this.scoreElementMatch(i,s);t>n&&(n=t,r=i)}return{status:"success",elements:[r],warnings:[`Multiple matches (${t.length}), selected best-scoring element`],confidence:e.meta.confidence*(.7+.2*n),meta:{degraded:!0,degradationReason:"best-of-multiple"}}}scoreElementMatch(t,e){let s=0,r=0;if(e.id&&(r+=.3,t.id===e.id&&(s+=.3)),e.classes&&e.classes.length>0){r+=.25;const n=Array.from(t.classList);s+=e.classes.filter(t=>n.includes(t)).length/e.classes.length*.25}if(e.attributes){const n=Object.entries(e.attributes);if(n.length>0){r+=.2;let e=0;for(const[s,r]of n)t.getAttribute(s)===r&&e++;s+=e/n.length*.2}}if(e.role&&(r+=.15,t.getAttribute("role")===e.role&&(s+=.15)),e.text){r+=.1;const n=U(t.textContent);n===e.text.normalized?s+=.1:n.includes(e.text.normalized)&&(s+=.05)}return r>0?s/r:0}}function st(t,e,s={}){const r={...w,...s},n=new K,i=new Y,a=new tt,o=new et,c=e instanceof Document?e:e.ownerDocument??e,l=n.buildSelector(t,{ensureUnique:!1,root:c});let h;try{h=Array.from(c.querySelectorAll(l))}catch(m){return{status:"error",elements:[],warnings:[`Invalid CSS selector: ${l}`,`Error: ${m instanceof Error?m.message:"Unknown selector error"}`],confidence:0,meta:{degraded:!0,degradationReason:"invalid-selector"}}}h.length>r.maxCandidates&&(h=h.slice(0,r.maxCandidates));const u=i.match(h,t.target.semantics);if(1===u.length)return{status:"success",elements:u,warnings:[],confidence:t.meta.confidence,meta:{degraded:!1}};if(0===u.length)return r.enableFallback?o.handleFallback(t,c):{status:"error",elements:[],warnings:["No matching elements found"],confidence:0,meta:{degraded:!0,degradationReason:"not-found"}};let d=u;const g=(f=t.constraints,[...f].sort((t,e)=>e.priority-t.priority));var f;for(const p of g){if(d=a.applyConstraint(d,p),1===d.length)return{status:"success",elements:d,warnings:[],confidence:.9*t.meta.confidence,meta:{degraded:!1}};if(0===d.length)return r.enableFallback?o.handleFallback(t,c):{status:"error",elements:[],warnings:["Constraints eliminated all candidates"],confidence:0,meta:{degraded:!0,degradationReason:"over-constrained"}}}return r.strictMode?{status:"ambiguous",elements:d,warnings:[`Non-unique resolution: ${d.length} matches`],confidence:.7*t.meta.confidence,meta:{degraded:!0,degradationReason:"ambiguous"}}:o.handleAmbiguous(d,t)}function rt(t){const e=[],s=[];if(t.version?"1.0"!==t.version&&s.push(`Unknown version: ${t.version}`):e.push("Missing version field"),t.anchor?(t.anchor.tag||e.push("Anchor missing tag"),"number"!=typeof t.anchor.score&&e.push("Anchor missing score"),t.anchor.semantics||e.push("Anchor missing semantics")):e.push("Missing anchor field"),t.target?(t.target.tag||e.push("Target missing tag"),"number"!=typeof t.target.score&&e.push("Target missing score"),t.target.semantics||e.push("Target missing semantics")):e.push("Missing target field"),Array.isArray(t.path))for(let r=0;r<t.path.length;r++){const s=t.path[r];s.tag||e.push(`Path node ${r} missing tag`),s.semantics||e.push(`Path node ${r} missing semantics`)}else e.push("Path must be an array");return t.meta?("number"!=typeof t.meta.confidence&&s.push("Missing confidence score"),t.meta.generatedAt||s.push("Missing generatedAt timestamp")):e.push("Missing meta field"),Array.isArray(t.constraints)||s.push("Constraints should be an array"),t.fallback||s.push("Missing fallback rules"),{valid:0===e.length,errors:e,warnings:s}}function nt(t){if(!t||"object"!=typeof t)return!1;const e=t;return"string"==typeof e.version&&"object"==typeof e.anchor&&Array.isArray(e.path)&&"object"==typeof e.target}const it={maxClasses:2,maxAttributes:5,includeText:!0,maxTextLength:50,simplifyTarget:!0,includeConstraints:!0};function at(t){return"id"===t?101:void 0!==S[t]?S[t]:t.startsWith("data-")?S["data-*"]:t.startsWith("aria-")?S["aria-*"]:0}function ot(t){return["id","data-testid","data-qa","data-cy","href","text","role"].includes(t)}function ct(t,e){const s={...it,...e},r=`v${t.version}`,n=ht(t.anchor,!1,s),i=t.path.length>0?t.path.map(t=>ht(t,!1,s)).join(" > ")+" > ":"",a=ht(t.target,!0,s),o=s.includeConstraints?function(t){if(!t.constraints||0===t.constraints.length)return"";const e=[];for(const s of t.constraints)switch(s.type){case"uniqueness":e.push("unique=true");break;case"position":s.params&&s.params.strategy&&e.push(`pos=${s.params.strategy}`);break;case"text-proximity":if(s.params&&s.params.reference){const t=dt(String(s.params.reference));e.push(`text="${t}"`)}}if(0===e.length)return"";return` {${e.join(",")}}`}(t):"";return`${r}: ${n} :: ${i}${a}${o}`}function lt(t){const e=(t=t.trim()).match(/^v(\d+(?:\.\d+)?)\s*:\s*/);if(!e)throw new Error('Invalid SEQL Selector: missing version prefix (expected "v1:")');const s=e[1];if("1.0"!==s&&"1"!==s)throw new Error(`Unsupported SEQL Selector version: v${s} (only v1.0 is supported)`);let r=t.slice(e[0].length);const n=r.match(/^(.+?)\s*::\s*/);if(!n)throw new Error('Invalid SEQL Selector: missing anchor separator "::"');const i=n[1].trim();r=r.slice(n[0].length);const a=r.match(/\s*\{([^}]+)\}\s*$/);let o="";a&&(o=a[1],r=r.slice(0,a.index));const c=r.split(/\s*>\s*/).map(t=>t.trim()).filter(t=>t);if(0===c.length)throw new Error("Invalid SEQL Selector: missing target node");const l=c[c.length-1],h=c.slice(0,-1),u=ut(i,!0),d=h.map(t=>ut(t,!1)),g=ut(l,!1),f=function(t){if(!t.trim())return[];const e=[],s=t.split(",").map(t=>t.trim());for(const r of s){const[t,s]=r.split("=").map(t=>t.trim());switch(t){case"unique":"true"===s&&e.push({type:"uniqueness",params:{mode:"strict"},priority:90});break;case"pos":e.push({type:"position",params:{strategy:s},priority:70});break;case"text":const t=s.replace(/^"(.*)"$/,"$1");e.push({type:"text-proximity",params:{reference:gt(t),maxDistance:5},priority:60})}}return e}(o);return{version:"1.0",anchor:u,path:d,target:g,constraints:f,fallback:{onMultiple:"best-score",onMissing:"anchor-only",maxDepth:10},meta:{confidence:.7,generatedAt:/* @__PURE__ */(new Date).toISOString(),generator:"seql-parser@1.0",source:"seql-string",degraded:!1}}}function ht(t,e=!1,s=it){const{tag:r,semantics:n}=t;let i=r;const a=[],o={...n.attributes};n.id&&(o.id=n.id),n.role&&!o.role&&(o.role=n.role);const c=Object.entries(o).map(([t,e])=>{const s=at(t);return{name:t,value:"href"===t||"src"===t?P(t,e):e,priority:s}}).filter(t=>!["style","xmlns","tabindex","contenteditable"].includes(t.name)&&(t.priority>0||"role"===t.name||"id"===t.name));c.sort((t,e)=>e.priority-t.priority);const l=c.slice(0,s.maxAttributes);l.sort((t,e)=>t.name.localeCompare(e.name));for(const{name:u,value:d}of l)a.push(`${u}="${dt(d)}"`);if(s.includeText&&n.text&&(h=n.text.normalized,!(/@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/.test(h)||/(\+?\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/.test(h)||/\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}/.test(h)))){const t=n.text.normalized;t.length>0&&t.length<=s.maxTextLength&&a.push(`text="${dt(t)}"`)}var h;if(a.length>0){let t=a;e&&s.simplifyTarget&&n.id&&(t=a.filter(t=>{const e=t.split("=")[0];return at(e)>=60||"text"===e||"id"===e||"role"===e})),t.length>0&&(t.sort((t,e)=>t.localeCompare(e)),i+=`[${t.join(",")}]`)}if(n.classes&&n.classes.length>0){const t=E(n.classes),r=!!n.id||a.some(t=>t.startsWith("href=")||t.startsWith("data-testid=")||t.startsWith("text=")||t.startsWith("role="));if(!(e&&s.simplifyTarget&&r)&&t.length>0){i+=t.sort().slice(0,s.maxClasses).map(t=>`.${t}`).join("")}}if("nthChild"in t&&t.nthChild){const r=!!n.id||n.attributes&&Object.keys(n.attributes).some(ot);e&&s.simplifyTarget&&r||(i+=`#${t.nthChild}`)}return i}function ut(t,e){let s=t;const r={},n=s.match(/^([a-z][a-z0-9-]*)/);if(!n)throw new Error(`Invalid node: missing tag name in "${t}"`);const i=n[1];s=s.slice(i.length);const a=[];let o;for(;o=s.match(/^\.([a-zA-Z][a-zA-Z0-9-_]*)/);)a.push(o[1]),s=s.slice(o[0].length);a.length>0&&(r.classes=a);const c=s.match(/^\[([^\]]+)\]/);if(c){const t={},e=function(t){const e=[];let s="",r=!1;for(let n=0;n<t.length;n++){const i=t[n];'"'!==i||0!==n&&"\\"===t[n-1]?","!==i||r?s+=i:(s.trim()&&e.push(s.trim()),s=""):(r=!r,s+=i)}s.trim()&&e.push(s.trim());return e}(c[1]);for(const s of e){const e=s.match(/^([a-z][a-z0-9-]*)(?:=|~=)"((?:[^"\\]|\\.)*)"/);if(e){const[,s,r]=e;t[s]=gt(r)}}Object.keys(t).length>0&&(t.text&&(r.text={raw:t.text,normalized:t.text},delete t.text),t.id&&(r.id=t.id,delete t.id),t.role&&(r.role=t.role,delete t.role),Object.keys(t).length>0&&(r.attributes=t)),s=s.slice(c[0].length)}let l;const h=s.match(/^#(\d+)/);if(h&&(l=parseInt(h[1],10),s=s.slice(h[0].length)),s.trim())throw new Error(`Invalid node: unexpected content "${s}" in "${t}"`);return e?{tag:i,semantics:r,score:.7,degraded:!1}:{tag:i,semantics:r,score:.7,nthChild:l}}function dt(t){return t.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/>/g,"\\>").replace(/:/g,"\\:")}function gt(t){return t.replace(/\\\\/g,"\0").replace(/\\"/g,'"').replace(/\\>/g,">").replace(/\\:/g,":").replace(/\x00/g,"\\")}function ft(t,e,s){const r=X(t,e);return r?ct(r,s):null}function mt(t,e,s){try{const r=lt(t);return st(r,e,s).elements||[]}catch(r){return console.error("Failed to resolve SEQL Selector:",r),[]}}const pt=/* @__PURE__ */new Set(["script","style","noscript","meta","link","head","title"]);function bt(t){return t.id&&!$(t.id)?3:t.hasAttribute("role")||t.hasAttribute("aria-label")||t.hasAttribute("aria-labelledby")||t.hasAttribute("data-testid")||t.hasAttribute("data-qa")||t.hasAttribute("data-test")?2:1}function yt(t,e){const s=t.tagName.toLowerCase();if(pt.has(s))return!0;if(e){if(1===bt(t)){if(!["form","main","nav","section","article","footer","header","button","a","input","label","select","textarea"].includes(s))return!0}}return!1}function xt(t){return[...t].sort((t,e)=>{const s=bt(t);return bt(e)-s})}function St(t={}){const e=performance.now(),{root:s=("undefined"!=typeof document?document.body:void 0),filter:r="*",limit:n=1/0,onProgress:i,progressInterval:a=100,skipNonSemantic:o=!0,generatorOptions:c={},cache:l,signal:h}=t;if(!s)throw new Error("Root element or document is required");const u=l??_(),d={...c,cache:u};let g;try{g=(Document,Array.from(s.querySelectorAll(r)))}catch(v){return{results:[],failed:[],stats:{totalElements:0,successful:0,failed:0,skipped:0,totalTimeMs:0,avgTimePerElementMs:0,cacheHitRate:0}}}const f=xt(g.filter(t=>!yt(t,o))).slice(0,n),m=[],p=[];let b=0;const y=f.length;let x=0;for(let M=0;M<f.length&&!h?.aborted;M++){const t=f[M],e=u.getEID(t);if(e)m.push({element:t,eid:e,generationTimeMs:0});else{const e=performance.now();try{const s=X(t,d),r=performance.now()-e;s?m.push({element:t,eid:s,generationTimeMs:r}):b++}catch(v){p.push({element:t,error:v instanceof Error?v.message:String(v)})}}i&&M-x>=a&&(i(M+1,y),x=M)}i&&i(y,y);const S=performance.now()-e,A=u.getStats(),C=A.eidHits+A.eidMisses+A.selectorHits+A.selectorMisses,w=A.eidHits+A.selectorHits,$=C>0?w/C:0;return{results:m,failed:p,stats:{totalElements:y,successful:m.length,failed:p.length,skipped:b,totalTimeMs:S,avgTimePerElementMs:m.length>0?S/m.length:0,cacheHitRate:$}}}function At(t,e={}){const s=performance.now(),{limit:r=1/0,onProgress:n,progressInterval:i=100,skipNonSemantic:a=!0,generatorOptions:o={},cache:c,signal:l}=e,h=c??_(),u={...o,cache:h},d=xt(t.filter(t=>!yt(t,a))).slice(0,r),g=[],f=[];let m=0;const p=d.length;let b=0;for(let $=0;$<d.length&&!l?.aborted;$++){const t=d[$],e=h.getEID(t);if(e)g.push({element:t,eid:e,generationTimeMs:0});else{const e=performance.now();try{const s=X(t,u),r=performance.now()-e;s?g.push({element:t,eid:s,generationTimeMs:r}):m++}catch(w){f.push({element:t,error:w instanceof Error?w.message:String(w)})}}n&&$-b>=i&&(n($+1,p),b=$)}n&&n(p,p);const y=performance.now()-s,x=h.getStats(),S=x.eidHits+x.eidMisses+x.selectorHits+x.selectorMisses,A=x.eidHits+x.selectorHits,C=S>0?A/S:0;return{results:g,failed:f,stats:{totalElements:p,successful:g.length,failed:f.length,skipped:m,totalTimeMs:y,avgTimePerElementMs:g.length>0?y/g.length:0,cacheHitRate:C}}}export{v as AnchorFinder,tt as ConstraintsEvaluator,K as CssGenerator,C as DEFAULT_GENERATOR_OPTIONS,w as DEFAULT_RESOLVER_OPTIONS,Z as EIDCache,t as EID_VERSION,et as FallbackHandler,e as MAX_PATH_DEPTH,L as PathBuilder,p as ROLE_ANCHOR_VALUES,m as SEMANTIC_ANCHOR_TAGS,x as SEMANTIC_ATTRIBUTES,b as SEMANTIC_TAGS,O as SemanticExtractor,Y as SemanticsMatcher,I as SvgFingerprinter,W as calculateConfidence,B as calculateElementScore,V as createEIDCache,z as filterClasses,X as generateEID,St as generateEIDBatch,At as generateEIDForElements,ft as generateSEQL,D as getClassScore,_ as getGlobalCache,nt as isEID,j as isUtilityClass,U as normalizeText,lt as parseSEQL,J as resetGlobalCache,st as resolve,mt as resolveSEQL,ct as stringifySEQL,rt as validateEID};
|
|
1
|
+
const Wt = "1.0", Bt = 10, L = {
|
|
2
|
+
ANCHOR: 0.4,
|
|
3
|
+
PATH: 0.3,
|
|
4
|
+
TARGET: 0.2,
|
|
5
|
+
UNIQUENESS: 0.1
|
|
6
|
+
}, $ = {
|
|
7
|
+
SEMANTIC_TAG: 0.5,
|
|
8
|
+
ROLE: 0.3,
|
|
9
|
+
ARIA_LABEL: 0.1,
|
|
10
|
+
STABLE_ID: 0.1,
|
|
11
|
+
TEST_MARKER: 0.05,
|
|
12
|
+
DEPTH_PENALTY_THRESHOLD: 5,
|
|
13
|
+
DEPTH_PENALTY_FACTOR: 0.05,
|
|
14
|
+
DEGRADED_SCORE: 0.3
|
|
15
|
+
}, at = {
|
|
16
|
+
MIN_CONFIDENCE_FOR_SKIP: 0.7
|
|
17
|
+
}, Q = [
|
|
18
|
+
"form",
|
|
19
|
+
"main",
|
|
20
|
+
"nav",
|
|
21
|
+
"section",
|
|
22
|
+
"article",
|
|
23
|
+
"footer",
|
|
24
|
+
"header"
|
|
25
|
+
], Z = [
|
|
26
|
+
"form",
|
|
27
|
+
"navigation",
|
|
28
|
+
"main",
|
|
29
|
+
"region",
|
|
30
|
+
"contentinfo",
|
|
31
|
+
"complementary",
|
|
32
|
+
"banner",
|
|
33
|
+
"search"
|
|
34
|
+
], ot = [
|
|
35
|
+
// HTML5 Semantic
|
|
36
|
+
"article",
|
|
37
|
+
"aside",
|
|
38
|
+
"details",
|
|
39
|
+
"figcaption",
|
|
40
|
+
"figure",
|
|
41
|
+
"footer",
|
|
42
|
+
"header",
|
|
43
|
+
"main",
|
|
44
|
+
"mark",
|
|
45
|
+
"nav",
|
|
46
|
+
"section",
|
|
47
|
+
"summary",
|
|
48
|
+
"time",
|
|
49
|
+
// Form elements
|
|
50
|
+
"button",
|
|
51
|
+
"datalist",
|
|
52
|
+
"fieldset",
|
|
53
|
+
"form",
|
|
54
|
+
"input",
|
|
55
|
+
"label",
|
|
56
|
+
"legend",
|
|
57
|
+
"meter",
|
|
58
|
+
"optgroup",
|
|
59
|
+
"option",
|
|
60
|
+
"output",
|
|
61
|
+
"progress",
|
|
62
|
+
"select",
|
|
63
|
+
"textarea",
|
|
64
|
+
// Interactive
|
|
65
|
+
"a",
|
|
66
|
+
"audio",
|
|
67
|
+
"video",
|
|
68
|
+
"canvas",
|
|
69
|
+
"dialog",
|
|
70
|
+
"menu",
|
|
71
|
+
// Text content
|
|
72
|
+
"blockquote",
|
|
73
|
+
"dd",
|
|
74
|
+
"dl",
|
|
75
|
+
"dt",
|
|
76
|
+
"hr",
|
|
77
|
+
"li",
|
|
78
|
+
"ol",
|
|
79
|
+
"ul",
|
|
80
|
+
"p",
|
|
81
|
+
"pre",
|
|
82
|
+
"h1",
|
|
83
|
+
"h2",
|
|
84
|
+
"h3",
|
|
85
|
+
"h4",
|
|
86
|
+
"h5",
|
|
87
|
+
"h6",
|
|
88
|
+
// Table
|
|
89
|
+
"caption",
|
|
90
|
+
"col",
|
|
91
|
+
"colgroup",
|
|
92
|
+
"table",
|
|
93
|
+
"tbody",
|
|
94
|
+
"td",
|
|
95
|
+
"tfoot",
|
|
96
|
+
"th",
|
|
97
|
+
"thead",
|
|
98
|
+
"tr",
|
|
99
|
+
// SVG
|
|
100
|
+
"svg",
|
|
101
|
+
"path",
|
|
102
|
+
"circle",
|
|
103
|
+
"rect",
|
|
104
|
+
"line",
|
|
105
|
+
"polyline",
|
|
106
|
+
"polygon",
|
|
107
|
+
"ellipse",
|
|
108
|
+
"g",
|
|
109
|
+
"text",
|
|
110
|
+
"use"
|
|
111
|
+
], ct = [
|
|
112
|
+
"rect",
|
|
113
|
+
"path",
|
|
114
|
+
"circle",
|
|
115
|
+
"line",
|
|
116
|
+
"polyline",
|
|
117
|
+
"polygon",
|
|
118
|
+
"ellipse",
|
|
119
|
+
"g",
|
|
120
|
+
"text",
|
|
121
|
+
"use",
|
|
122
|
+
"defs",
|
|
123
|
+
"clipPath",
|
|
124
|
+
"mask"
|
|
125
|
+
], Gt = [
|
|
126
|
+
"aria-label",
|
|
127
|
+
"aria-labelledby",
|
|
128
|
+
"aria-describedby",
|
|
129
|
+
"name",
|
|
130
|
+
"type",
|
|
131
|
+
"data-testid",
|
|
132
|
+
"data-qa",
|
|
133
|
+
"data-test",
|
|
134
|
+
"href",
|
|
135
|
+
"title",
|
|
136
|
+
"placeholder",
|
|
137
|
+
"alt"
|
|
138
|
+
], T = {
|
|
139
|
+
// Test attributes (highest priority)
|
|
140
|
+
"data-testid": 100,
|
|
141
|
+
"data-qa": 99,
|
|
142
|
+
"data-cy": 98,
|
|
143
|
+
"data-test": 97,
|
|
144
|
+
"data-test-id": 96,
|
|
145
|
+
// ARIA (accessibility semantics)
|
|
146
|
+
"aria-label": 90,
|
|
147
|
+
"aria-labelledby": 85,
|
|
148
|
+
"aria-describedby": 80,
|
|
149
|
+
// Semantic HTML attributes
|
|
150
|
+
name: 75,
|
|
151
|
+
href: 70,
|
|
152
|
+
// for <a>
|
|
153
|
+
src: 70,
|
|
154
|
+
// for <img>, <script>, etc.
|
|
155
|
+
type: 65,
|
|
156
|
+
role: 60,
|
|
157
|
+
alt: 55,
|
|
158
|
+
title: 50,
|
|
159
|
+
for: 45,
|
|
160
|
+
placeholder: 40,
|
|
161
|
+
// Any data-* attribute (if not above)
|
|
162
|
+
"data-*": 30,
|
|
163
|
+
// Any aria-* attribute (if not above)
|
|
164
|
+
"aria-*": 25
|
|
165
|
+
}, J = /* @__PURE__ */ new Set([
|
|
166
|
+
"id",
|
|
167
|
+
// handled separately
|
|
168
|
+
"class",
|
|
169
|
+
// handled separately
|
|
170
|
+
"style",
|
|
171
|
+
// unstable
|
|
172
|
+
"xmlns",
|
|
173
|
+
// service attribute for SVG
|
|
174
|
+
"tabindex",
|
|
175
|
+
// can change
|
|
176
|
+
"contenteditable"
|
|
177
|
+
]), lt = {
|
|
178
|
+
maxPathDepth: 10,
|
|
179
|
+
enableSvgFingerprint: !0,
|
|
180
|
+
confidenceThreshold: 0.1,
|
|
181
|
+
fallbackToBody: !0,
|
|
182
|
+
includeUtilityClasses: !1,
|
|
183
|
+
source: "dom-dsl"
|
|
184
|
+
}, ht = {
|
|
185
|
+
strictMode: !1,
|
|
186
|
+
enableFallback: !0,
|
|
187
|
+
maxCandidates: 20
|
|
188
|
+
};
|
|
189
|
+
function k(n) {
|
|
190
|
+
return !!(/^[a-z]+-\d+$/i.test(n) || /^\d+$/.test(n) || /^:[a-z0-9]+:$/i.test(n) || /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(n) || /^[a-z]{1,3}[A-Za-z0-9]{8,}$/.test(n) && (/\d/.test(n) || /[A-Z]/.test(n)) || /^radix-/.test(n) || /^mui-\d+$/.test(n));
|
|
191
|
+
}
|
|
192
|
+
class ut {
|
|
193
|
+
constructor(t, e) {
|
|
194
|
+
this.maxDepth = t.maxPathDepth ?? 10, this.cache = e;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Finds the best anchor element for the target
|
|
198
|
+
* @param target - Target element to find anchor for
|
|
199
|
+
* @returns Anchor result or null if not found
|
|
200
|
+
*/
|
|
201
|
+
findAnchor(t) {
|
|
202
|
+
if (this.cache) {
|
|
203
|
+
const a = this.cache.getAnchor(t);
|
|
204
|
+
if (a !== void 0)
|
|
205
|
+
return a;
|
|
206
|
+
}
|
|
207
|
+
let e = t.parentElement, s = 0, r = null;
|
|
208
|
+
for (; e && s < this.maxDepth; ) {
|
|
209
|
+
if (e.tagName.toLowerCase() === "body")
|
|
210
|
+
return r || {
|
|
211
|
+
element: e,
|
|
212
|
+
score: $.DEGRADED_SCORE,
|
|
213
|
+
tier: "C",
|
|
214
|
+
depth: s
|
|
215
|
+
};
|
|
216
|
+
const a = this.scoreAnchor(e);
|
|
217
|
+
if (a > 0) {
|
|
218
|
+
const o = this.applyDepthPenalty(a, s), l = this.getTier(e), h = { element: e, score: o, tier: l, depth: s };
|
|
219
|
+
if (l === "A")
|
|
220
|
+
return h;
|
|
221
|
+
(!r || o > r.score) && (r = h);
|
|
222
|
+
}
|
|
223
|
+
e = e.parentElement, s++;
|
|
224
|
+
}
|
|
225
|
+
const i = r;
|
|
226
|
+
return this.cache && this.cache.setAnchor(t, i), i;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Scores an element as anchor candidate (without depth penalty)
|
|
230
|
+
* @param element - Element to score
|
|
231
|
+
* @returns Raw score from 0 to 1
|
|
232
|
+
*/
|
|
233
|
+
scoreAnchor(t) {
|
|
234
|
+
let e = 0;
|
|
235
|
+
const s = t.tagName.toLowerCase();
|
|
236
|
+
Q.includes(s) && (e += $.SEMANTIC_TAG);
|
|
237
|
+
const r = t.getAttribute("role");
|
|
238
|
+
r && Z.includes(r) && (e += $.ROLE), (t.hasAttribute("aria-label") || t.hasAttribute("aria-labelledby")) && (e += $.ARIA_LABEL);
|
|
239
|
+
const i = t.id;
|
|
240
|
+
return i && !k(i) && (e += $.STABLE_ID), (t.hasAttribute("data-testid") || t.hasAttribute("data-qa") || t.hasAttribute("data-test")) && (e += $.TEST_MARKER), Math.min(e, 1);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Applies depth penalty to score
|
|
244
|
+
* Following SPECIFICATION.md §7: depthPenalty = (depth - threshold) * factor
|
|
245
|
+
*/
|
|
246
|
+
applyDepthPenalty(t, e) {
|
|
247
|
+
if (e <= $.DEPTH_PENALTY_THRESHOLD)
|
|
248
|
+
return t;
|
|
249
|
+
const s = (e - $.DEPTH_PENALTY_THRESHOLD) * $.DEPTH_PENALTY_FACTOR;
|
|
250
|
+
return Math.max(0, t - s);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Determines the tier of an anchor element
|
|
254
|
+
*/
|
|
255
|
+
getTier(t) {
|
|
256
|
+
const e = t.tagName.toLowerCase();
|
|
257
|
+
if (Q.includes(e))
|
|
258
|
+
return "A";
|
|
259
|
+
const s = t.getAttribute("role");
|
|
260
|
+
return s && Z.includes(s) ? "B" : "C";
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const ft = [
|
|
264
|
+
// CSS-in-JS
|
|
265
|
+
/^css-[a-z0-9]+$/i,
|
|
266
|
+
/^sc-[a-z0-9]+-\d+$/i,
|
|
267
|
+
/^[a-z]{5,8}$/i,
|
|
268
|
+
// Short generated classes (abcdef)
|
|
269
|
+
// Material-UI / MUI
|
|
270
|
+
/^Mui[A-Z]\w+-\w+-\w+/,
|
|
271
|
+
/^makeStyles-\w+-\d+$/,
|
|
272
|
+
// JSS
|
|
273
|
+
/^jss\d+$/,
|
|
274
|
+
// Emotion / Linaria
|
|
275
|
+
/^(emotion|linaria)-[a-z0-9]+/i,
|
|
276
|
+
// Component libraries with hashes
|
|
277
|
+
/^(chakra|tw-|ant-)[a-z0-9]+-\w+/i,
|
|
278
|
+
// Hash-based (hashes in classes)
|
|
279
|
+
/-[a-f0-9]{6,}$/i,
|
|
280
|
+
/^_[a-z0-9]{5,}$/i,
|
|
281
|
+
/\d{5,}/
|
|
282
|
+
// 5+ digits in a row
|
|
283
|
+
], dt = [
|
|
284
|
+
// === FIX 4: Tailwind arbitrary values and variants (highest priority) ===
|
|
285
|
+
/^\[/,
|
|
286
|
+
// Any arbitrary value or variant starting with [ (e.g., [&_svg]:..., [mask-type:luminance])
|
|
287
|
+
// === FIX 4: Pseudo-class variants (must be before specific patterns) ===
|
|
288
|
+
/^(first|last|odd|even|only|first-of-type|last-of-type|only-of-type):/,
|
|
289
|
+
// first:, last:, etc.
|
|
290
|
+
/^(hover|focus|active|disabled|enabled|checked|indeterminate|default|required|valid|invalid|in-range|out-of-range|placeholder-shown|autofill|read-only):/,
|
|
291
|
+
// State pseudo-classes
|
|
292
|
+
/^(focus-within|focus-visible|visited|target|open):/,
|
|
293
|
+
// Advanced pseudo-classes
|
|
294
|
+
// === FIX 4: Responsive variants (must be before specific patterns) ===
|
|
295
|
+
/^(sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl):/,
|
|
296
|
+
// === FIX 4: Dark mode and directional variants ===
|
|
297
|
+
/^dark:/,
|
|
298
|
+
/^(rtl|ltr):/,
|
|
299
|
+
// === FIX 4: Group and peer variants ===
|
|
300
|
+
/^(group|peer)(-hover|-focus|-active)?:/,
|
|
301
|
+
// === FIX 4: Tailwind utilities with fraction values ===
|
|
302
|
+
/\/([\d.]+|full|auto|screen)$/,
|
|
303
|
+
// /50, /100, /full, /auto, /screen
|
|
304
|
+
// === FIX 4: Positioning utilities ===
|
|
305
|
+
/^(inset|top|right|bottom|left)(-|$)/,
|
|
306
|
+
// inset-0, top-0, left-0
|
|
307
|
+
// === Layout & Display ===
|
|
308
|
+
/^(flex|inline-flex|grid|block|inline|inline-block|hidden|visible)$/,
|
|
309
|
+
/^(absolute|relative|fixed|sticky|static)$/,
|
|
310
|
+
// === Flexbox & Grid ===
|
|
311
|
+
/^(items|justify|content|self|place)-/,
|
|
312
|
+
/^flex-(row|col|wrap|nowrap|1|auto|initial|none)/,
|
|
313
|
+
/^grid-(cols|rows|flow)/,
|
|
314
|
+
// === Spacing (Tailwind) ===
|
|
315
|
+
/^(gap|space)-/,
|
|
316
|
+
/^[mp][trblxy]?-(\d+|auto|px)$/,
|
|
317
|
+
// === Sizing ===
|
|
318
|
+
/^(w|h|min-w|min-h|max-w|max-h|size)-/,
|
|
319
|
+
// === Colors & Styling ===
|
|
320
|
+
// Note: text-* can be semantic (text-muted, text-primary) or utility (text-center, text-lg)
|
|
321
|
+
// More specific patterns for utility text-* classes
|
|
322
|
+
/^text-(center|left|right|justify|start|end|xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)$/,
|
|
323
|
+
/^text-(uppercase|lowercase|capitalize|normal-case|underline|line-through|no-underline)$/,
|
|
324
|
+
/^text-(truncate|ellipsis|clip)$/,
|
|
325
|
+
/^(bg|border|ring|shadow|outline)-/,
|
|
326
|
+
/^rounded(-|$)/,
|
|
327
|
+
// === Typography ===
|
|
328
|
+
/^(font|leading|tracking|whitespace|break|truncate)-/,
|
|
329
|
+
/^(uppercase|lowercase|capitalize|normal-case)$/,
|
|
330
|
+
// === Transform & Animation (IMPORTANT!) ===
|
|
331
|
+
/^(transform|transition|duration|delay|ease|animate)-/,
|
|
332
|
+
/^(scale|rotate|translate|skew)-/,
|
|
333
|
+
/^transform$/,
|
|
334
|
+
/^backdrop-blur-/,
|
|
335
|
+
/^motion-/,
|
|
336
|
+
// Framer Motion
|
|
337
|
+
/^(fade|slide|zoom|bounce|pulse|spin|ping)-/,
|
|
338
|
+
// animations
|
|
339
|
+
// === Overflow & Scrolling ===
|
|
340
|
+
/^(overflow|overscroll|scroll)-/,
|
|
341
|
+
// === Interactivity ===
|
|
342
|
+
/^(cursor|pointer-events|select|resize)-/,
|
|
343
|
+
// === Visibility & Opacity ===
|
|
344
|
+
/^(opacity|z)-/,
|
|
345
|
+
/^(visible|invisible|collapse)$/,
|
|
346
|
+
// === Bootstrap utilities ===
|
|
347
|
+
/^d-(none|inline|inline-block|block|grid|table|flex)$/,
|
|
348
|
+
/^(float|clearfix|text)-(left|right|center|justify|start|end)$/,
|
|
349
|
+
/^(m|p)[trblxy]?-[0-5]$/,
|
|
350
|
+
/^(w|h)-(25|50|75|100|auto)$/,
|
|
351
|
+
// Note: btn-* classes are semantic (component classes), not utility
|
|
352
|
+
// /^btn-(primary|secondary|success|danger|warning|info|light|dark|link)$/,
|
|
353
|
+
/^btn-(sm|lg|block)$/,
|
|
354
|
+
// Only size modifiers are utility
|
|
355
|
+
/^text-(muted|primary|success|danger|warning|info|light|dark|white)$/,
|
|
356
|
+
/^bg-(primary|secondary|success|danger|warning|info|light|dark|white|transparent)$/,
|
|
357
|
+
/^border(-top|-bottom|-left|-right)?(-0)?$/,
|
|
358
|
+
/^rounded(-top|-bottom|-left|-right|-circle|-pill|-0)?$/,
|
|
359
|
+
/^shadow(-sm|-lg|-none)?$/,
|
|
360
|
+
/^(align|justify|order|flex)-(start|end|center|between|around|fill|grow|shrink)$/,
|
|
361
|
+
/^col(-sm|-md|-lg|-xl)?(-\d+|-auto)?$/,
|
|
362
|
+
/^row(-cols)?(-\d+)?$/,
|
|
363
|
+
/^g[xy]?-[0-5]$/,
|
|
364
|
+
/^(show|hide|invisible|visible)$/,
|
|
365
|
+
/^(position|top|bottom|start|end)-(static|relative|absolute|fixed|sticky|-\d+)$/,
|
|
366
|
+
// === Common utility patterns ===
|
|
367
|
+
/^(row|col)$/,
|
|
368
|
+
/^clearfix$/,
|
|
369
|
+
/^pull-(left|right)$/,
|
|
370
|
+
/^float-(left|right|none)$/
|
|
371
|
+
], gt = [
|
|
372
|
+
// === Navigation ===
|
|
373
|
+
/^(nav|menu|header|footer|sidebar|topbar|navbar|breadcrumb)/,
|
|
374
|
+
/(navigation|dropdown|megamenu)$/,
|
|
375
|
+
// === Components ===
|
|
376
|
+
/^(btn|button|link|card|modal|dialog|popup|tooltip|alert|badge|chip)/,
|
|
377
|
+
/^(form|input|select|checkbox|radio|textarea|label|fieldset)/,
|
|
378
|
+
/^(table|list|item|row|cell|column)/,
|
|
379
|
+
/^(accordion|tab|carousel|slider|gallery)/,
|
|
380
|
+
// === Content ===
|
|
381
|
+
/^(content|main|article|post|comment|title|subtitle|description|caption)/,
|
|
382
|
+
/^(hero|banner|jumbotron|section|wrapper|box)/,
|
|
383
|
+
// === User/Data ===
|
|
384
|
+
/^(user|profile|avatar|account|auth)/,
|
|
385
|
+
/^(product|item|price|cart|checkout|order)/,
|
|
386
|
+
// === Layout sections ===
|
|
387
|
+
/^(page|layout|panel|widget|block)/,
|
|
388
|
+
// === States (semantic naming) ===
|
|
389
|
+
/-(primary|secondary|tertiary|success|error|warning|info|danger)$/,
|
|
390
|
+
/-(active|inactive|disabled|enabled|selected|highlighted|focused)$/,
|
|
391
|
+
/-(open|closed|expanded|collapsed|visible|hidden)$/,
|
|
392
|
+
/-(large|medium|small|tiny|xs|sm|md|lg|xl)$/,
|
|
393
|
+
// === Action buttons ===
|
|
394
|
+
/^(submit|cancel|close|delete|edit|save|back|next|prev|search)/,
|
|
395
|
+
// === Status ===
|
|
396
|
+
/^(loading|pending|complete|failed|draft|published)/
|
|
397
|
+
];
|
|
398
|
+
function q(n) {
|
|
399
|
+
return ft.some((t) => t.test(n));
|
|
400
|
+
}
|
|
401
|
+
function O(n) {
|
|
402
|
+
return n.length <= 2 || /^\d/.test(n) ? !0 : dt.some((t) => t.test(n));
|
|
403
|
+
}
|
|
404
|
+
function mt(n) {
|
|
405
|
+
return q(n) || O(n) ? !1 : gt.some((t) => t.test(n));
|
|
406
|
+
}
|
|
407
|
+
function pt(n) {
|
|
408
|
+
return !q(n) && !O(n);
|
|
409
|
+
}
|
|
410
|
+
function I(n) {
|
|
411
|
+
return n.filter((t) => pt(t));
|
|
412
|
+
}
|
|
413
|
+
function bt(n) {
|
|
414
|
+
if (q(n) || O(n))
|
|
415
|
+
return 0;
|
|
416
|
+
let t = 0.5;
|
|
417
|
+
return mt(n) && (t = 0.8), n.length < 3 ? t *= 0.3 : n.length < 5 && (t *= 0.6), /\d/.test(n) && (t *= 0.7), Math.min(t, 1);
|
|
418
|
+
}
|
|
419
|
+
function St(n) {
|
|
420
|
+
const t = [], e = [];
|
|
421
|
+
for (const s of n)
|
|
422
|
+
O(s) || q(s) ? e.push(s) : t.push(s);
|
|
423
|
+
return { semantic: t, utility: e };
|
|
424
|
+
}
|
|
425
|
+
function Y(n) {
|
|
426
|
+
return O(n) || q(n);
|
|
427
|
+
}
|
|
428
|
+
function Vt(n) {
|
|
429
|
+
return bt(n);
|
|
430
|
+
}
|
|
431
|
+
const K = (n) => n.replace(/([#:.[\]@])/g, "\\$1");
|
|
432
|
+
class yt {
|
|
433
|
+
constructor(t, e) {
|
|
434
|
+
this.maxDepth = t.maxPathDepth ?? 10, this.cache = e;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Builds path from anchor to target (excluding both)
|
|
438
|
+
* @param anchor - Anchor element (start)
|
|
439
|
+
* @param target - Target element (end)
|
|
440
|
+
* @param extractor - Semantic extractor instance
|
|
441
|
+
* @returns Path build result with nodes and degradation info
|
|
442
|
+
*/
|
|
443
|
+
buildPath(t, e, s) {
|
|
444
|
+
const r = [];
|
|
445
|
+
let i = e.parentElement;
|
|
446
|
+
for (; i && i !== t && r.length < this.maxDepth; )
|
|
447
|
+
r.unshift(i), i = i.parentElement;
|
|
448
|
+
const a = r.length >= this.maxDepth && i !== t;
|
|
449
|
+
let o = this.filterNoise(r);
|
|
450
|
+
return o = this.ensureUniqueness(
|
|
451
|
+
r,
|
|
452
|
+
o,
|
|
453
|
+
t,
|
|
454
|
+
e,
|
|
455
|
+
s
|
|
456
|
+
), {
|
|
457
|
+
path: o.map((h) => {
|
|
458
|
+
const c = h.parentElement;
|
|
459
|
+
let u;
|
|
460
|
+
if (c) {
|
|
461
|
+
const g = Array.from(c.children).indexOf(h);
|
|
462
|
+
g !== -1 && (u = g + 1);
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
tag: h.tagName.toLowerCase(),
|
|
466
|
+
semantics: s.extract(h),
|
|
467
|
+
score: s.scoreElement(h),
|
|
468
|
+
nthChild: u
|
|
469
|
+
};
|
|
470
|
+
}),
|
|
471
|
+
degraded: a,
|
|
472
|
+
degradationReason: a ? "path-depth-overflow" : void 0
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Legacy method for backward compatibility
|
|
477
|
+
*/
|
|
478
|
+
buildPathNodes(t, e, s) {
|
|
479
|
+
return this.buildPath(t, e, s).path;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Ensures path uniqueness by adding nodes if needed
|
|
483
|
+
* Following SPECIFICATION.md §8 Disambiguation Algorithm
|
|
484
|
+
*/
|
|
485
|
+
ensureUniqueness(t, e, s, r, i) {
|
|
486
|
+
const a = this.buildTestSelector(s, e, r);
|
|
487
|
+
try {
|
|
488
|
+
const o = r.ownerDocument;
|
|
489
|
+
if (!o) return e;
|
|
490
|
+
let l;
|
|
491
|
+
if (this.cache) {
|
|
492
|
+
const c = this.cache.getSelectorResults(a);
|
|
493
|
+
c !== void 0 ? l = c : (l = Array.from(o.querySelectorAll(a)), this.cache.setSelectorResults(a, l));
|
|
494
|
+
} else
|
|
495
|
+
l = o.querySelectorAll(a);
|
|
496
|
+
if (l.length <= 1)
|
|
497
|
+
return e;
|
|
498
|
+
const h = t.filter((c) => !e.includes(c));
|
|
499
|
+
for (const c of h) {
|
|
500
|
+
if (i.scoreElement(c) < at.MIN_CONFIDENCE_FOR_SKIP)
|
|
501
|
+
continue;
|
|
502
|
+
const f = this.insertNodeInOrder(e, c, t), g = this.buildTestSelector(s, f, r);
|
|
503
|
+
try {
|
|
504
|
+
let d;
|
|
505
|
+
if (this.cache) {
|
|
506
|
+
const m = this.cache.getSelectorResults(g);
|
|
507
|
+
m !== void 0 ? d = m : (d = Array.from(o.querySelectorAll(g)), this.cache.setSelectorResults(g, d));
|
|
508
|
+
} else
|
|
509
|
+
d = o.querySelectorAll(g);
|
|
510
|
+
if (d.length === 1)
|
|
511
|
+
return f;
|
|
512
|
+
d.length < l.length && (e = f);
|
|
513
|
+
} catch {
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return e;
|
|
517
|
+
} catch {
|
|
518
|
+
return e;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Inserts node into path maintaining original order
|
|
523
|
+
*/
|
|
524
|
+
insertNodeInOrder(t, e, s) {
|
|
525
|
+
const r = s.indexOf(e), i = [...t];
|
|
526
|
+
let a = 0;
|
|
527
|
+
for (let o = 0; o < i.length && !(s.indexOf(i[o]) > r); o++)
|
|
528
|
+
a = o + 1;
|
|
529
|
+
return i.splice(a, 0, e), i;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Builds a test CSS selector from path
|
|
533
|
+
*/
|
|
534
|
+
buildTestSelector(t, e, s) {
|
|
535
|
+
const r = [];
|
|
536
|
+
r.push(this.elementToSelector(t));
|
|
537
|
+
for (const i of e)
|
|
538
|
+
r.push(this.elementToSelector(i));
|
|
539
|
+
return r.push(this.elementToSelector(s)), r.join(" ");
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Converts element to basic CSS selector
|
|
543
|
+
*/
|
|
544
|
+
elementToSelector(t) {
|
|
545
|
+
let e = t.tagName.toLowerCase();
|
|
546
|
+
t.id && !k(t.id) && (e += `#${K(t.id)}`);
|
|
547
|
+
for (const s of Array.from(t.classList))
|
|
548
|
+
Y(s) || (e += `.${K(s)}`);
|
|
549
|
+
return e;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Filters out noise/layout elements
|
|
553
|
+
*/
|
|
554
|
+
filterNoise(t) {
|
|
555
|
+
return t.filter((e) => this.shouldInclude(e));
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Determines if element should be included in path
|
|
559
|
+
*/
|
|
560
|
+
shouldInclude(t) {
|
|
561
|
+
const e = t.tagName.toLowerCase();
|
|
562
|
+
return ot.includes(e) ? !0 : e === "div" || e === "span" ? this.hasSemanticFeatures(t) : !1;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Checks if element has meaningful semantic features
|
|
566
|
+
*/
|
|
567
|
+
hasSemanticFeatures(t) {
|
|
568
|
+
if (t.hasAttribute("role")) return !0;
|
|
569
|
+
for (const s of Array.from(t.attributes))
|
|
570
|
+
if (s.name.startsWith("aria-")) return !0;
|
|
571
|
+
if (t.classList.length > 0) {
|
|
572
|
+
for (const s of Array.from(t.classList))
|
|
573
|
+
if (!Y(s)) return !0;
|
|
574
|
+
}
|
|
575
|
+
if (t.hasAttribute("data-testid") || t.hasAttribute("data-qa") || t.hasAttribute("data-test"))
|
|
576
|
+
return !0;
|
|
577
|
+
const e = t.id;
|
|
578
|
+
return !!(e && !k(e));
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
function B(n) {
|
|
582
|
+
return n ? n.trim().replace(/[\n\t\r]/g, " ").replace(/\s+/g, " ") : "";
|
|
583
|
+
}
|
|
584
|
+
const At = {
|
|
585
|
+
preserveQueryForAbsolute: !0,
|
|
586
|
+
removeDynamicHashes: !0
|
|
587
|
+
};
|
|
588
|
+
function xt(n) {
|
|
589
|
+
return n ? [
|
|
590
|
+
/\d{5,}/,
|
|
591
|
+
// 5+ digits
|
|
592
|
+
/[a-f0-9]{8,}/i,
|
|
593
|
+
// hex hash 8+ characters
|
|
594
|
+
/(session|token|temp|random|timestamp|nonce|cache)/i,
|
|
595
|
+
// dynamic words
|
|
596
|
+
/^\d+$/,
|
|
597
|
+
// only digits
|
|
598
|
+
/^[a-f0-9-]{32,}$/i
|
|
599
|
+
// UUID-like
|
|
600
|
+
].some((e) => e.test(n)) : !1;
|
|
601
|
+
}
|
|
602
|
+
function Ct(n, t) {
|
|
603
|
+
if (!n) return n;
|
|
604
|
+
const e = n.startsWith("http://") || n.startsWith("https://");
|
|
605
|
+
let [s, r] = n.split("#");
|
|
606
|
+
const [i, a] = s.split("?");
|
|
607
|
+
let o = i;
|
|
608
|
+
return e && t.preserveQueryForAbsolute && a && (o += `?${a}`), r && (t.removeDynamicHashes && xt(r) || (o += `#${r}`)), o;
|
|
609
|
+
}
|
|
610
|
+
function H(n, t, e = {}) {
|
|
611
|
+
if (!t) return t;
|
|
612
|
+
const s = { ...At, ...e };
|
|
613
|
+
return n === "href" || n === "src" ? Ct(t, s) : t;
|
|
614
|
+
}
|
|
615
|
+
class Et {
|
|
616
|
+
constructor(t, e) {
|
|
617
|
+
this.includeUtilityClasses = t.includeUtilityClasses ?? !1, this.cache = e;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Extracts semantic features from element
|
|
621
|
+
* @param element - DOM element to extract from
|
|
622
|
+
* @returns Semantic features object
|
|
623
|
+
*/
|
|
624
|
+
extract(t) {
|
|
625
|
+
if (this.cache) {
|
|
626
|
+
const a = this.cache.getSemantics(t);
|
|
627
|
+
if (a !== void 0)
|
|
628
|
+
return a;
|
|
629
|
+
}
|
|
630
|
+
const e = {}, s = t.id;
|
|
631
|
+
if (s && !k(s) && (e.id = s), t.classList.length > 0) {
|
|
632
|
+
const a = Array.from(t.classList);
|
|
633
|
+
if (this.includeUtilityClasses)
|
|
634
|
+
e.classes = a;
|
|
635
|
+
else {
|
|
636
|
+
const { semantic: o } = St(a);
|
|
637
|
+
o.length > 0 && (e.classes = o);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
const r = this.extractAttributes(t);
|
|
641
|
+
Object.keys(r).length > 0 && (e.attributes = r);
|
|
642
|
+
const i = t.getAttribute("role");
|
|
643
|
+
if (i && (e.role = i), this.shouldExtractText(t)) {
|
|
644
|
+
const a = this.extractText(t);
|
|
645
|
+
a && (e.text = a);
|
|
646
|
+
}
|
|
647
|
+
return this.cache && this.cache.setSemantics(t, e), e;
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Scores element based on semantic richness
|
|
651
|
+
* @param element - Element to score
|
|
652
|
+
* @returns Score from 0 to 1
|
|
653
|
+
*/
|
|
654
|
+
scoreElement(t) {
|
|
655
|
+
let e = 0.5;
|
|
656
|
+
const s = this.extract(t);
|
|
657
|
+
return s.id && (e += 0.15), s.classes && s.classes.length > 0 && (e += 0.1), s.attributes && Object.keys(s.attributes).length > 0 && (e += 0.1), s.role && (e += 0.1), s.text && (e += 0.05), Math.min(e, 1);
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Checks if attribute should be ignored
|
|
661
|
+
* @param attrName - Attribute name
|
|
662
|
+
* @returns True if should be ignored
|
|
663
|
+
*/
|
|
664
|
+
shouldIgnoreAttribute(t) {
|
|
665
|
+
return !!(J.has(t) || t.startsWith("on") || t.startsWith("ng-") || t.startsWith("_ng") || t.startsWith("data-reactid") || t.startsWith("data-react") || t.startsWith("data-v-"));
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Gets attribute priority
|
|
669
|
+
* @param attrName - Attribute name
|
|
670
|
+
* @returns Priority number (higher = more priority)
|
|
671
|
+
*/
|
|
672
|
+
getAttributePriority(t) {
|
|
673
|
+
return T[t] !== void 0 ? T[t] : t.startsWith("data-") ? T["data-*"] : t.startsWith("aria-") ? T["aria-*"] : 0;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Checks if attribute value is dynamic (should be ignored)
|
|
677
|
+
* @param value - Attribute value
|
|
678
|
+
* @returns True if value is dynamic
|
|
679
|
+
*/
|
|
680
|
+
isDynamicValue(t) {
|
|
681
|
+
return [
|
|
682
|
+
/^[a-f0-9]{32,}$/i,
|
|
683
|
+
// Long hashes
|
|
684
|
+
/^\d{10,}$/,
|
|
685
|
+
// Timestamp
|
|
686
|
+
/^(undefined|null|\[object)/,
|
|
687
|
+
// JS artifacts
|
|
688
|
+
/^{{.*}}$/
|
|
689
|
+
// Template literals
|
|
690
|
+
].some((s) => s.test(t));
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Extracts relevant semantic attributes from element
|
|
694
|
+
* Iterates through all attributes and filters by priority
|
|
695
|
+
*/
|
|
696
|
+
extractAttributes(t) {
|
|
697
|
+
const e = {};
|
|
698
|
+
for (const s of Array.from(t.attributes)) {
|
|
699
|
+
const r = s.name;
|
|
700
|
+
if (this.shouldIgnoreAttribute(r) || this.getAttributePriority(r) === 0) continue;
|
|
701
|
+
const a = r === "href" || r === "src" ? H(r, s.value) : s.value;
|
|
702
|
+
!a || a.trim() === "" || this.isDynamicValue(a) || (e[r] = a);
|
|
703
|
+
}
|
|
704
|
+
return e;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Extracts and normalizes text content
|
|
708
|
+
*/
|
|
709
|
+
extractText(t) {
|
|
710
|
+
const e = this.getDirectTextContent(t);
|
|
711
|
+
if (!e) return null;
|
|
712
|
+
const s = B(e);
|
|
713
|
+
if (!s) return null;
|
|
714
|
+
const r = 100, i = e.length > r ? e.slice(0, r) + "..." : e, a = s.length > r ? s.slice(0, r) + "..." : s;
|
|
715
|
+
return {
|
|
716
|
+
raw: i,
|
|
717
|
+
normalized: a
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Gets direct text content excluding child elements
|
|
722
|
+
*/
|
|
723
|
+
getDirectTextContent(t) {
|
|
724
|
+
const e = [];
|
|
725
|
+
for (const s of Array.from(t.childNodes))
|
|
726
|
+
if (s.nodeType === Node.TEXT_NODE && s.textContent) {
|
|
727
|
+
const r = s.textContent.trim();
|
|
728
|
+
r && e.push(r);
|
|
729
|
+
}
|
|
730
|
+
return e.length > 0 ? e.join(" ") : t.textContent ?? null;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Determines if text should be extracted for this element
|
|
734
|
+
*/
|
|
735
|
+
shouldExtractText(t) {
|
|
736
|
+
const e = t.tagName.toLowerCase();
|
|
737
|
+
return [
|
|
738
|
+
"button",
|
|
739
|
+
"a",
|
|
740
|
+
"label",
|
|
741
|
+
"h1",
|
|
742
|
+
"h2",
|
|
743
|
+
"h3",
|
|
744
|
+
"h4",
|
|
745
|
+
"h5",
|
|
746
|
+
"h6",
|
|
747
|
+
"p",
|
|
748
|
+
"span",
|
|
749
|
+
"li",
|
|
750
|
+
"th",
|
|
751
|
+
"td",
|
|
752
|
+
"dt",
|
|
753
|
+
"dd",
|
|
754
|
+
"legend",
|
|
755
|
+
"figcaption",
|
|
756
|
+
"summary"
|
|
757
|
+
].includes(e);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
class Tt {
|
|
761
|
+
/**
|
|
762
|
+
* Generates fingerprint for SVG element
|
|
763
|
+
* @param element - SVG element to fingerprint
|
|
764
|
+
* @returns SVG fingerprint object
|
|
765
|
+
*/
|
|
766
|
+
fingerprint(t) {
|
|
767
|
+
const e = t.tagName.toLowerCase(), s = this.getShape(e), r = {
|
|
768
|
+
shape: s,
|
|
769
|
+
hasAnimation: this.hasAnimation(t)
|
|
770
|
+
};
|
|
771
|
+
if (s === "path") {
|
|
772
|
+
const o = t.getAttribute("d");
|
|
773
|
+
o && (r.dHash = this.computePathHash(o));
|
|
774
|
+
} else ["circle", "rect", "ellipse", "line"].includes(s) && (r.geomHash = this.computeGeomHash(t, s));
|
|
775
|
+
const i = t.getAttribute("role");
|
|
776
|
+
i && (r.role = i);
|
|
777
|
+
const a = t.querySelector("title");
|
|
778
|
+
return a?.textContent && (r.titleText = a.textContent.trim()), r;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Computes hash from path data (first N commands)
|
|
782
|
+
* @param d - SVG path d attribute value
|
|
783
|
+
* @returns Hash string
|
|
784
|
+
*/
|
|
785
|
+
computePathHash(t) {
|
|
786
|
+
const e = this.normalizePathData(t);
|
|
787
|
+
return this.simpleHash(e);
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Gets the shape type from tag name
|
|
791
|
+
*/
|
|
792
|
+
getShape(t) {
|
|
793
|
+
return [
|
|
794
|
+
"path",
|
|
795
|
+
"circle",
|
|
796
|
+
"rect",
|
|
797
|
+
"line",
|
|
798
|
+
"polyline",
|
|
799
|
+
"polygon",
|
|
800
|
+
"ellipse",
|
|
801
|
+
"g",
|
|
802
|
+
"text",
|
|
803
|
+
"use",
|
|
804
|
+
"svg"
|
|
805
|
+
].find((s) => s === t) ?? "path";
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Normalizes path data for consistent hashing
|
|
809
|
+
*/
|
|
810
|
+
normalizePathData(t) {
|
|
811
|
+
return (t.match(/[MLHVCSQTAZ][^MLHVCSQTAZ]*/gi) ?? []).slice(0, 5).map((r) => r.trim().replace(/(-?\d+\.?\d*)/g, (i) => parseFloat(i).toFixed(1))).join(" ");
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Computes geometry hash for non-path shapes
|
|
815
|
+
*/
|
|
816
|
+
computeGeomHash(t, e) {
|
|
817
|
+
const s = [];
|
|
818
|
+
switch (e) {
|
|
819
|
+
case "circle":
|
|
820
|
+
s.push(`r=${t.getAttribute("r") ?? "0"}`);
|
|
821
|
+
break;
|
|
822
|
+
case "rect":
|
|
823
|
+
{
|
|
824
|
+
const r = parseFloat(t.getAttribute("width") ?? "0"), i = parseFloat(t.getAttribute("height") ?? "0");
|
|
825
|
+
r > 0 && i > 0 && s.push(`ratio=${(r / i).toFixed(2)}`);
|
|
826
|
+
}
|
|
827
|
+
break;
|
|
828
|
+
case "ellipse":
|
|
829
|
+
{
|
|
830
|
+
const r = parseFloat(t.getAttribute("rx") ?? "0"), i = parseFloat(t.getAttribute("ry") ?? "0");
|
|
831
|
+
r > 0 && i > 0 && s.push(`ratio=${(r / i).toFixed(2)}`);
|
|
832
|
+
}
|
|
833
|
+
break;
|
|
834
|
+
case "line":
|
|
835
|
+
{
|
|
836
|
+
const r = parseFloat(t.getAttribute("x1") ?? "0"), i = parseFloat(t.getAttribute("y1") ?? "0"), a = parseFloat(t.getAttribute("x2") ?? "0"), o = parseFloat(t.getAttribute("y2") ?? "0"), l = Math.atan2(o - i, a - r);
|
|
837
|
+
s.push(`angle=${l.toFixed(2)}`);
|
|
838
|
+
}
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
return this.simpleHash(s.join(";"));
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Detects animations on SVG element
|
|
845
|
+
*/
|
|
846
|
+
hasAnimation(t) {
|
|
847
|
+
if (t.querySelector("animate, animateTransform, animateMotion"))
|
|
848
|
+
return !0;
|
|
849
|
+
const e = t.ownerDocument;
|
|
850
|
+
if (e?.defaultView)
|
|
851
|
+
try {
|
|
852
|
+
const s = e.defaultView.getComputedStyle(t);
|
|
853
|
+
if (s.animationName !== "none" || s.transitionProperty !== "all" && s.transitionProperty !== "none")
|
|
854
|
+
return !0;
|
|
855
|
+
} catch {
|
|
856
|
+
}
|
|
857
|
+
return !1;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Simple hash function for fingerprinting (not cryptographic)
|
|
861
|
+
*/
|
|
862
|
+
simpleHash(t) {
|
|
863
|
+
let e = 0;
|
|
864
|
+
for (let s = 0; s < t.length; s++) {
|
|
865
|
+
const r = t.charCodeAt(s);
|
|
866
|
+
e = (e << 5) - e + r, e = e & e;
|
|
867
|
+
}
|
|
868
|
+
return Math.abs(e).toString(16).padStart(8, "0");
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
function wt(n, t = 0) {
|
|
872
|
+
const e = n.anchor.score, s = n.path.length > 0 ? n.path.reduce((o, l) => o + l.score, 0) / n.path.length : 0.5, r = n.target.score, i = e * L.ANCHOR + s * L.PATH + r * L.TARGET + t * L.UNIQUENESS, a = n.anchor.degraded ? 0.2 : 0;
|
|
873
|
+
return Math.max(0, Math.min(1, i - a));
|
|
874
|
+
}
|
|
875
|
+
function Qt(n, t, e) {
|
|
876
|
+
let s = 0.5;
|
|
877
|
+
return t && (s += 0.2), e && (s += 0.15), s += Math.min(n * 0.05, 0.15), Math.min(s, 1);
|
|
878
|
+
}
|
|
879
|
+
class vt {
|
|
880
|
+
constructor(t) {
|
|
881
|
+
this.cache = /* @__PURE__ */ new Map(), this.maxSize = t;
|
|
882
|
+
}
|
|
883
|
+
get(t) {
|
|
884
|
+
if (!this.cache.has(t)) return;
|
|
885
|
+
const e = this.cache.get(t);
|
|
886
|
+
return this.cache.delete(t), this.cache.set(t, e), e;
|
|
887
|
+
}
|
|
888
|
+
set(t, e) {
|
|
889
|
+
if (this.cache.has(t))
|
|
890
|
+
this.cache.delete(t);
|
|
891
|
+
else if (this.cache.size >= this.maxSize) {
|
|
892
|
+
const s = this.cache.keys().next().value;
|
|
893
|
+
s !== void 0 && this.cache.delete(s);
|
|
894
|
+
}
|
|
895
|
+
this.cache.set(t, e);
|
|
896
|
+
}
|
|
897
|
+
has(t) {
|
|
898
|
+
return this.cache.has(t);
|
|
899
|
+
}
|
|
900
|
+
delete(t) {
|
|
901
|
+
this.cache.delete(t);
|
|
902
|
+
}
|
|
903
|
+
clear() {
|
|
904
|
+
this.cache.clear();
|
|
905
|
+
}
|
|
906
|
+
get size() {
|
|
907
|
+
return this.cache.size;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
class $t {
|
|
911
|
+
constructor(t = {}) {
|
|
912
|
+
this.eidCache = /* @__PURE__ */ new WeakMap(), this.selectorResultCache = new vt(
|
|
913
|
+
t.maxSelectorCacheSize ?? 1e3
|
|
914
|
+
), this.anchorCache = /* @__PURE__ */ new WeakMap(), this.semanticsCache = /* @__PURE__ */ new WeakMap(), this.stats = {
|
|
915
|
+
eidHits: 0,
|
|
916
|
+
eidMisses: 0,
|
|
917
|
+
selectorHits: 0,
|
|
918
|
+
selectorMisses: 0,
|
|
919
|
+
anchorHits: 0,
|
|
920
|
+
anchorMisses: 0,
|
|
921
|
+
semanticsHits: 0,
|
|
922
|
+
semanticsMisses: 0,
|
|
923
|
+
selectorCacheSize: 0,
|
|
924
|
+
maxSelectorCacheSize: t.maxSelectorCacheSize ?? 1e3
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Get cached EID for element
|
|
929
|
+
*/
|
|
930
|
+
getEID(t) {
|
|
931
|
+
const e = this.eidCache.get(t);
|
|
932
|
+
if (e !== void 0)
|
|
933
|
+
return this.stats.eidHits++, e;
|
|
934
|
+
this.stats.eidMisses++;
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Cache EID for element
|
|
938
|
+
*/
|
|
939
|
+
setEID(t, e) {
|
|
940
|
+
this.eidCache.set(t, e);
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Get cached selector results
|
|
944
|
+
*/
|
|
945
|
+
getSelectorResults(t) {
|
|
946
|
+
const e = this.selectorResultCache.get(t);
|
|
947
|
+
if (e !== void 0)
|
|
948
|
+
return this.stats.selectorHits++, this.stats.selectorCacheSize = this.selectorResultCache.size, e;
|
|
949
|
+
this.stats.selectorMisses++, this.stats.selectorCacheSize = this.selectorResultCache.size;
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Cache selector results
|
|
953
|
+
*/
|
|
954
|
+
setSelectorResults(t, e) {
|
|
955
|
+
this.selectorResultCache.set(t, e), this.stats.selectorCacheSize = this.selectorResultCache.size;
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Get cached anchor result
|
|
959
|
+
*/
|
|
960
|
+
getAnchor(t) {
|
|
961
|
+
if (this.anchorCache.has(t))
|
|
962
|
+
return this.stats.anchorHits++, this.anchorCache.get(t);
|
|
963
|
+
this.stats.anchorMisses++;
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* Cache anchor result
|
|
967
|
+
*/
|
|
968
|
+
setAnchor(t, e) {
|
|
969
|
+
this.anchorCache.set(t, e);
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Get cached semantics
|
|
973
|
+
*/
|
|
974
|
+
getSemantics(t) {
|
|
975
|
+
const e = this.semanticsCache.get(t);
|
|
976
|
+
if (e !== void 0)
|
|
977
|
+
return this.stats.semanticsHits++, e;
|
|
978
|
+
this.stats.semanticsMisses++;
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Cache semantics
|
|
982
|
+
*/
|
|
983
|
+
setSemantics(t, e) {
|
|
984
|
+
this.semanticsCache.set(t, e);
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Clear all caches
|
|
988
|
+
*/
|
|
989
|
+
clear() {
|
|
990
|
+
this.selectorResultCache.clear(), this.stats.selectorCacheSize = 0, this.stats = {
|
|
991
|
+
eidHits: 0,
|
|
992
|
+
eidMisses: 0,
|
|
993
|
+
selectorHits: 0,
|
|
994
|
+
selectorMisses: 0,
|
|
995
|
+
anchorHits: 0,
|
|
996
|
+
anchorMisses: 0,
|
|
997
|
+
semanticsHits: 0,
|
|
998
|
+
semanticsMisses: 0,
|
|
999
|
+
selectorCacheSize: 0,
|
|
1000
|
+
maxSelectorCacheSize: this.stats.maxSelectorCacheSize
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Invalidate cache for a specific element
|
|
1005
|
+
* Note: WeakMaps don't support deletion, but we can clear selector cache
|
|
1006
|
+
* if needed. This method is mainly for future extensibility.
|
|
1007
|
+
*/
|
|
1008
|
+
invalidateElement(t) {
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Invalidate a specific selector from cache
|
|
1012
|
+
*/
|
|
1013
|
+
invalidateSelector(t) {
|
|
1014
|
+
this.selectorResultCache.delete(t), this.stats.selectorCacheSize = this.selectorResultCache.size;
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Get cache statistics
|
|
1018
|
+
*/
|
|
1019
|
+
getStats() {
|
|
1020
|
+
return {
|
|
1021
|
+
...this.stats,
|
|
1022
|
+
selectorCacheSize: this.selectorResultCache.size
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Get cache hit rate for EID cache
|
|
1027
|
+
*/
|
|
1028
|
+
getEIDHitRate() {
|
|
1029
|
+
const t = this.stats.eidHits + this.stats.eidMisses;
|
|
1030
|
+
return t > 0 ? this.stats.eidHits / t : 0;
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Get cache hit rate for selector cache
|
|
1034
|
+
*/
|
|
1035
|
+
getSelectorHitRate() {
|
|
1036
|
+
const t = this.stats.selectorHits + this.stats.selectorMisses;
|
|
1037
|
+
return t > 0 ? this.stats.selectorHits / t : 0;
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Get cache hit rate for anchor cache
|
|
1041
|
+
*/
|
|
1042
|
+
getAnchorHitRate() {
|
|
1043
|
+
const t = this.stats.anchorHits + this.stats.anchorMisses;
|
|
1044
|
+
return t > 0 ? this.stats.anchorHits / t : 0;
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Get cache hit rate for semantics cache
|
|
1048
|
+
*/
|
|
1049
|
+
getSemanticsHitRate() {
|
|
1050
|
+
const t = this.stats.semanticsHits + this.stats.semanticsMisses;
|
|
1051
|
+
return t > 0 ? this.stats.semanticsHits / t : 0;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Get overall cache hit rate
|
|
1055
|
+
*/
|
|
1056
|
+
getOverallHitRate() {
|
|
1057
|
+
const t = this.stats.eidHits + this.stats.selectorHits + this.stats.anchorHits + this.stats.semanticsHits, e = this.stats.eidMisses + this.stats.selectorMisses + this.stats.anchorMisses + this.stats.semanticsMisses, s = t + e;
|
|
1058
|
+
return s > 0 ? t / s : 0;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
function Mt(n) {
|
|
1062
|
+
return new $t(n);
|
|
1063
|
+
}
|
|
1064
|
+
let _ = null;
|
|
1065
|
+
function G() {
|
|
1066
|
+
return _ || (_ = Mt()), _;
|
|
1067
|
+
}
|
|
1068
|
+
function Zt() {
|
|
1069
|
+
_ = null;
|
|
1070
|
+
}
|
|
1071
|
+
function V(n, t = {}) {
|
|
1072
|
+
if (!n || !n.ownerDocument || !n.isConnected)
|
|
1073
|
+
return null;
|
|
1074
|
+
const e = { ...lt, ...t }, s = e.cache ?? G(), r = s.getEID(n);
|
|
1075
|
+
if (r !== void 0)
|
|
1076
|
+
return r;
|
|
1077
|
+
const i = new ut(e, s), a = new yt(e, s), o = new Et(e, s), l = new Tt(), h = i.findAnchor(n);
|
|
1078
|
+
if (!h && !e.fallbackToBody)
|
|
1079
|
+
return null;
|
|
1080
|
+
const c = h?.element ?? n.ownerDocument?.body ?? null;
|
|
1081
|
+
if (!c) return null;
|
|
1082
|
+
const u = !h || h.tier === "C", f = o.extract(c), g = {
|
|
1083
|
+
tag: c.tagName.toLowerCase(),
|
|
1084
|
+
semantics: f,
|
|
1085
|
+
score: h?.score ?? $.DEGRADED_SCORE,
|
|
1086
|
+
degraded: u
|
|
1087
|
+
}, d = a.buildPath(
|
|
1088
|
+
c,
|
|
1089
|
+
n,
|
|
1090
|
+
o
|
|
1091
|
+
), m = o.extract(n);
|
|
1092
|
+
e.enableSvgFingerprint && It(n) && (m.svg = l.fingerprint(n));
|
|
1093
|
+
const p = n.parentElement;
|
|
1094
|
+
let S;
|
|
1095
|
+
if (p) {
|
|
1096
|
+
const C = Array.from(p.children).indexOf(n);
|
|
1097
|
+
C !== -1 && (S = C + 1);
|
|
1098
|
+
}
|
|
1099
|
+
const y = {
|
|
1100
|
+
tag: n.tagName.toLowerCase(),
|
|
1101
|
+
semantics: m,
|
|
1102
|
+
score: o.scoreElement(n),
|
|
1103
|
+
nthChild: S
|
|
1104
|
+
}, w = [], A = {
|
|
1105
|
+
onMultiple: "best-score",
|
|
1106
|
+
onMissing: "anchor-only",
|
|
1107
|
+
maxDepth: 3
|
|
1108
|
+
}, b = g.degraded || d.degraded, v = Nt(g.degraded, d), x = {
|
|
1109
|
+
version: "1.0",
|
|
1110
|
+
anchor: g,
|
|
1111
|
+
path: d.path,
|
|
1112
|
+
target: y,
|
|
1113
|
+
constraints: w,
|
|
1114
|
+
fallback: A,
|
|
1115
|
+
meta: {
|
|
1116
|
+
confidence: 0,
|
|
1117
|
+
// Calculated below
|
|
1118
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1119
|
+
generator: "dom-eid@1.0",
|
|
1120
|
+
source: e.source,
|
|
1121
|
+
degraded: b,
|
|
1122
|
+
degradationReason: v
|
|
1123
|
+
}
|
|
1124
|
+
};
|
|
1125
|
+
return x.meta.confidence = wt(x), x.meta.confidence < e.confidenceThreshold ? null : (s.setEID(n, x), x);
|
|
1126
|
+
}
|
|
1127
|
+
function It(n) {
|
|
1128
|
+
return n.namespaceURI === "http://www.w3.org/2000/svg" || n.tagName.toLowerCase() === "svg" || n instanceof SVGElement;
|
|
1129
|
+
}
|
|
1130
|
+
function Nt(n, t) {
|
|
1131
|
+
if (n && t.degraded)
|
|
1132
|
+
return "anchor-and-path-degraded";
|
|
1133
|
+
if (n)
|
|
1134
|
+
return "no-semantic-anchor";
|
|
1135
|
+
if (t.degraded)
|
|
1136
|
+
return t.degradationReason;
|
|
1137
|
+
}
|
|
1138
|
+
class tt {
|
|
1139
|
+
buildSelector(t, e) {
|
|
1140
|
+
if (t.path.length === 0 && t.anchor.tag === t.target.tag && JSON.stringify(t.anchor.semantics) === JSON.stringify(t.target.semantics)) {
|
|
1141
|
+
const u = this.buildNodeSelector(
|
|
1142
|
+
t.target.tag,
|
|
1143
|
+
t.target.semantics,
|
|
1144
|
+
{ excludeClasses: !1 }
|
|
1145
|
+
// Include classes for same-element case
|
|
1146
|
+
);
|
|
1147
|
+
return e?.ensureUnique ? this.ensureUniqueSelector(u, t, e) : u;
|
|
1148
|
+
}
|
|
1149
|
+
const r = [], i = e?.ensureUnique ? this.ensureUniqueAnchor(t, e.root ?? document) : this.buildNodeSelector(t.anchor.tag, t.anchor.semantics);
|
|
1150
|
+
r.push(i);
|
|
1151
|
+
for (const u of t.path) {
|
|
1152
|
+
let f = this.buildNodeSelector(u.tag, u.semantics);
|
|
1153
|
+
u.nthChild !== void 0 && (["tr", "td", "th", "thead", "tbody", "tfoot"].includes(u.tag) ? f += `:nth-child(${u.nthChild})` : f += `:nth-child(${u.nthChild})`), r.push(f);
|
|
1154
|
+
}
|
|
1155
|
+
let a = this.buildNodeSelector(
|
|
1156
|
+
t.target.tag,
|
|
1157
|
+
t.target.semantics,
|
|
1158
|
+
{ excludeClasses: e?.ensureUnique }
|
|
1159
|
+
// Exclude classes initially if we need unique
|
|
1160
|
+
);
|
|
1161
|
+
t.target.nthChild !== void 0 && (["tr", "td", "th", "thead", "tbody", "tfoot"].includes(t.target.tag) ? a += `:nth-child(${t.target.nthChild})` : a += `:nth-child(${t.target.nthChild})`), r.push(a);
|
|
1162
|
+
const o = this.isSvgChildElement(t.target.tag), l = t.path.some((u) => u.tag === "svg");
|
|
1163
|
+
let h;
|
|
1164
|
+
if (o && l) {
|
|
1165
|
+
const u = t.path.findIndex((f) => f.tag === "svg");
|
|
1166
|
+
if (u !== -1) {
|
|
1167
|
+
const f = u + 1, g = r.slice(0, f + 1), d = r.slice(f + 1, -1), m = r[r.length - 1];
|
|
1168
|
+
d.length > 0 ? h = g.join(" ") + " > " + d.join(" > ") + " > " + m : h = g.join(" ") + " > " + m;
|
|
1169
|
+
} else
|
|
1170
|
+
h = r.join(" ");
|
|
1171
|
+
} else
|
|
1172
|
+
h = r.join(" ");
|
|
1173
|
+
if (!e?.ensureUnique)
|
|
1174
|
+
return h;
|
|
1175
|
+
const c = this.querySelectorSafe(h, e.root ?? document);
|
|
1176
|
+
if (c.length === 1)
|
|
1177
|
+
return {
|
|
1178
|
+
selector: h,
|
|
1179
|
+
isUnique: !0,
|
|
1180
|
+
usedNthOfType: h.includes(":nth-"),
|
|
1181
|
+
extraClassesAdded: 0
|
|
1182
|
+
};
|
|
1183
|
+
if (c.length === 0 || c.length > 1) {
|
|
1184
|
+
const u = this.buildFullDomPathSelector(
|
|
1185
|
+
t,
|
|
1186
|
+
t.target.semantics,
|
|
1187
|
+
e.root ?? document
|
|
1188
|
+
);
|
|
1189
|
+
if (u && this.isUnique(u, e.root ?? document))
|
|
1190
|
+
return {
|
|
1191
|
+
selector: u,
|
|
1192
|
+
isUnique: !0,
|
|
1193
|
+
usedNthOfType: u.includes(":nth-"),
|
|
1194
|
+
extraClassesAdded: 0
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
return this.ensureUniqueSelector(
|
|
1198
|
+
h,
|
|
1199
|
+
t,
|
|
1200
|
+
e
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Builds selector for anchor only (used in fallback)
|
|
1205
|
+
* @param eid - Element Identity
|
|
1206
|
+
* @returns CSS selector for anchor
|
|
1207
|
+
*/
|
|
1208
|
+
buildAnchorSelector(t) {
|
|
1209
|
+
return this.buildNodeSelector(t.anchor.tag, t.anchor.semantics);
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Ensures selector uniqueness by progressively adding classes and nth-of-type
|
|
1213
|
+
*/
|
|
1214
|
+
ensureUniqueSelector(t, e, s) {
|
|
1215
|
+
const r = s.root ?? document, i = s.maxClasses ?? 4, a = e.target.tag, o = e.target.semantics;
|
|
1216
|
+
let l = t, h = 0, c = !1;
|
|
1217
|
+
if (this.querySelectorSafe(l, r).length === 0) {
|
|
1218
|
+
const d = this.buildFullDomPathSelector(e, o, r);
|
|
1219
|
+
if (d && (l = d, this.isUnique(l, r)))
|
|
1220
|
+
return {
|
|
1221
|
+
selector: l,
|
|
1222
|
+
isUnique: !0,
|
|
1223
|
+
usedNthOfType: !1,
|
|
1224
|
+
extraClassesAdded: 0
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
if (this.isUnique(l, r))
|
|
1228
|
+
return {
|
|
1229
|
+
selector: l,
|
|
1230
|
+
isUnique: !0,
|
|
1231
|
+
usedNthOfType: !1,
|
|
1232
|
+
extraClassesAdded: 0
|
|
1233
|
+
};
|
|
1234
|
+
const f = I(o.classes ?? []);
|
|
1235
|
+
for (let d = 0; d < Math.min(f.length, i); d++) {
|
|
1236
|
+
const m = f[d];
|
|
1237
|
+
if (l += `.${this.escapeCSS(m)}`, h++, this.isUnique(l, r))
|
|
1238
|
+
return {
|
|
1239
|
+
selector: l,
|
|
1240
|
+
isUnique: !0,
|
|
1241
|
+
usedNthOfType: !1,
|
|
1242
|
+
extraClassesAdded: h
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
if (!this.isUnique(l, r)) {
|
|
1246
|
+
const d = this.buildFullDomPathSelector(e, o, r);
|
|
1247
|
+
if (d && this.isUnique(d, r))
|
|
1248
|
+
return {
|
|
1249
|
+
selector: d,
|
|
1250
|
+
isUnique: !0,
|
|
1251
|
+
usedNthOfType: d.includes(":nth-of-type("),
|
|
1252
|
+
extraClassesAdded: h
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
const g = this.findNthElementByText(l, o, r);
|
|
1256
|
+
return g && (l += this.getNthSelector(g, a), c = !0), {
|
|
1257
|
+
selector: l,
|
|
1258
|
+
isUnique: this.isUnique(l, r),
|
|
1259
|
+
usedNthOfType: c,
|
|
1260
|
+
extraClassesAdded: h
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Builds full DOM path selector by traversing actual DOM from anchor
|
|
1265
|
+
* This handles cases where intermediate div/span elements were filtered out
|
|
1266
|
+
*/
|
|
1267
|
+
buildFullDomPathSelector(t, e, s) {
|
|
1268
|
+
const r = this.buildNodeSelector(t.anchor.tag, t.anchor.semantics), i = this.querySelectorSafe(r, s);
|
|
1269
|
+
if (i.length === 0) return null;
|
|
1270
|
+
for (const a of i) {
|
|
1271
|
+
const o = this.findTargetWithinAnchor(
|
|
1272
|
+
a,
|
|
1273
|
+
t.target.tag,
|
|
1274
|
+
e
|
|
1275
|
+
);
|
|
1276
|
+
if (o.length === 0) continue;
|
|
1277
|
+
const l = o.map((h) => {
|
|
1278
|
+
const c = this.scorePathMatch(h, a, t.path);
|
|
1279
|
+
return { element: h, score: c };
|
|
1280
|
+
});
|
|
1281
|
+
l.sort((h, c) => c.score - h.score);
|
|
1282
|
+
for (const { element: h } of l) {
|
|
1283
|
+
const c = this.buildPathFromAnchorToTarget(
|
|
1284
|
+
a,
|
|
1285
|
+
h,
|
|
1286
|
+
t,
|
|
1287
|
+
s
|
|
1288
|
+
);
|
|
1289
|
+
if (c && this.isUnique(c, s))
|
|
1290
|
+
return c;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
return null;
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Scores how well a candidate's DOM path matches the EID path
|
|
1297
|
+
* Compares tags, classes, attributes, and nthChild positions
|
|
1298
|
+
* @param candidate - Target element candidate
|
|
1299
|
+
* @param anchor - Anchor element
|
|
1300
|
+
* @param eidPath - EID path nodes
|
|
1301
|
+
* @returns Score (higher = better match)
|
|
1302
|
+
*/
|
|
1303
|
+
scorePathMatch(t, e, s) {
|
|
1304
|
+
const r = [];
|
|
1305
|
+
let i = t.parentElement;
|
|
1306
|
+
for (; i && i !== e; )
|
|
1307
|
+
r.unshift(i), i = i.parentElement;
|
|
1308
|
+
let a = 0;
|
|
1309
|
+
const o = Math.min(r.length, s.length);
|
|
1310
|
+
for (let h = 0; h < o; h++) {
|
|
1311
|
+
const c = r[h], u = s[h];
|
|
1312
|
+
if (c.tagName.toLowerCase() === u.tag) {
|
|
1313
|
+
if (a += 10, u.nthChild !== void 0) {
|
|
1314
|
+
const f = c.parentElement;
|
|
1315
|
+
f && (Array.from(f.children).indexOf(c) + 1 === u.nthChild ? a += 20 : a -= 10);
|
|
1316
|
+
}
|
|
1317
|
+
} else
|
|
1318
|
+
a -= 5;
|
|
1319
|
+
if (u.semantics.classes && u.semantics.classes.length > 0) {
|
|
1320
|
+
const f = u.semantics.classes.filter(
|
|
1321
|
+
(g) => c.classList.contains(g)
|
|
1322
|
+
);
|
|
1323
|
+
a += f.length * 2;
|
|
1324
|
+
}
|
|
1325
|
+
if (u.semantics.attributes) {
|
|
1326
|
+
const f = Object.entries(u.semantics.attributes).filter(
|
|
1327
|
+
([g, d]) => c.getAttribute(g) === d
|
|
1328
|
+
);
|
|
1329
|
+
a += f.length * 3;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
const l = Math.abs(r.length - s.length);
|
|
1333
|
+
return a -= l * 2, a;
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Finds target elements within an anchor by matching semantics
|
|
1337
|
+
*/
|
|
1338
|
+
findTargetWithinAnchor(t, e, s) {
|
|
1339
|
+
return Array.from(t.querySelectorAll(e)).filter((i) => {
|
|
1340
|
+
if (s.text) {
|
|
1341
|
+
const a = i.textContent?.trim() || "", o = s.text.normalized;
|
|
1342
|
+
if (!a.includes(o) && !o.includes(a))
|
|
1343
|
+
return !1;
|
|
1344
|
+
}
|
|
1345
|
+
return !!(s.classes && s.classes.length > 0 && s.classes.every(
|
|
1346
|
+
(o) => i.classList.contains(o)
|
|
1347
|
+
) || s.attributes && Object.entries(s.attributes).every(
|
|
1348
|
+
([o, l]) => {
|
|
1349
|
+
const h = i.getAttribute(o);
|
|
1350
|
+
return o === "href" || o === "src" ? H(o, h || "") === H(o, l) : h === l;
|
|
1351
|
+
}
|
|
1352
|
+
) || s.text);
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Disambiguates a parent element by trying attributes, classes, then nth-of-type
|
|
1357
|
+
* Priority: stable attributes > one stable class > nth-of-type
|
|
1358
|
+
* @param element The DOM element to disambiguate
|
|
1359
|
+
* @param tag The tag name
|
|
1360
|
+
* @param pathNode EID path node with semantics (if available)
|
|
1361
|
+
* @param fullPath Current selector path (for uniqueness testing)
|
|
1362
|
+
* @param root Root element for queries
|
|
1363
|
+
* @returns Disambiguated selector part (e.g., "div[role='main']" or "div.sidebar" or "div:nth-of-type(3)")
|
|
1364
|
+
*/
|
|
1365
|
+
disambiguateParent(t, e, s, r, i) {
|
|
1366
|
+
if (s?.semantics?.attributes) {
|
|
1367
|
+
const o = this.buildNodeSelector(e, s.semantics, {
|
|
1368
|
+
excludeClasses: !0
|
|
1369
|
+
}), l = [...r, e].join(" > "), h = this.querySelectorSafe(l, i), c = [...r, o].join(" > "), u = this.querySelectorSafe(c, i);
|
|
1370
|
+
if (u.length > 0 && u.length < h.length)
|
|
1371
|
+
return o;
|
|
1372
|
+
}
|
|
1373
|
+
if (s?.semantics?.classes) {
|
|
1374
|
+
const o = I(s.semantics.classes);
|
|
1375
|
+
if (o.length > 0) {
|
|
1376
|
+
const l = `${e}.${this.escapeCSS(o[0])}`, h = [...r, e].join(" > "), c = this.querySelectorSafe(h, i), u = [...r, l].join(" > "), f = this.querySelectorSafe(u, i);
|
|
1377
|
+
if (f.length > 0 && f.length < c.length)
|
|
1378
|
+
return l;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
const a = t.parentElement;
|
|
1382
|
+
return a && Array.from(a.children).filter(
|
|
1383
|
+
(l) => l.tagName.toLowerCase() === e
|
|
1384
|
+
).length > 1 ? `${e}${this.getNthSelector(t, e)}` : e;
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Builds CSS selector path from anchor to target by traversing actual DOM
|
|
1388
|
+
*/
|
|
1389
|
+
buildPathFromAnchorToTarget(t, e, s, r) {
|
|
1390
|
+
const i = [];
|
|
1391
|
+
let a = e;
|
|
1392
|
+
for (; a && a !== t; )
|
|
1393
|
+
i.unshift(a), a = a.parentElement;
|
|
1394
|
+
if (a !== t)
|
|
1395
|
+
return null;
|
|
1396
|
+
const o = [
|
|
1397
|
+
// ============================================================
|
|
1398
|
+
// Strategy 0: anchor path target[attrs_only]
|
|
1399
|
+
// Most flexible - no classes on target, only semantic attributes
|
|
1400
|
+
// ============================================================
|
|
1401
|
+
() => {
|
|
1402
|
+
const l = this.buildNodeSelector(s.anchor.tag, s.anchor.semantics), h = s.target.tag, c = s.target.semantics, u = [];
|
|
1403
|
+
for (const p of s.path)
|
|
1404
|
+
u.push(p.tag);
|
|
1405
|
+
const g = [l, ...u, h].filter(Boolean).join(" ");
|
|
1406
|
+
if (this.isUnique(g, r))
|
|
1407
|
+
return g;
|
|
1408
|
+
const d = this.buildNodeSelector(h, c, {
|
|
1409
|
+
excludeClasses: !0
|
|
1410
|
+
// KEY: no classes on target in Strategy 0
|
|
1411
|
+
}), m = [l, ...u.slice(0, -1), d].join(" ");
|
|
1412
|
+
return this.isUnique(m, r) ? m : null;
|
|
1413
|
+
},
|
|
1414
|
+
// ============================================================
|
|
1415
|
+
// Strategy 1: anchor > parent[attrs|class|nth] > target[attrs_only]
|
|
1416
|
+
// Full path with '>' combinator
|
|
1417
|
+
// Parents: disambiguated using attrs > stable class > nth-of-type
|
|
1418
|
+
// Target: ONLY attributes, NO classes
|
|
1419
|
+
// ============================================================
|
|
1420
|
+
() => {
|
|
1421
|
+
const l = [this.buildNodeSelector(s.anchor.tag, s.anchor.semantics)], h = /* @__PURE__ */ new Map();
|
|
1422
|
+
let c = 0;
|
|
1423
|
+
for (let f = 0; f < i.length - 1; f++) {
|
|
1424
|
+
const g = i[f], d = g.tagName.toLowerCase();
|
|
1425
|
+
c < s.path.length && s.path[c].tag === d ? (h.set(g, s.path[c]), c++) : h.set(g, null);
|
|
1426
|
+
}
|
|
1427
|
+
for (let f = 0; f < i.length; f++) {
|
|
1428
|
+
const g = i[f], d = g.tagName.toLowerCase();
|
|
1429
|
+
if (f < i.length - 1) {
|
|
1430
|
+
const S = h.get(g) || null, y = this.disambiguateParent(g, d, S, l, r);
|
|
1431
|
+
l.push(y);
|
|
1432
|
+
continue;
|
|
1433
|
+
}
|
|
1434
|
+
const m = this.buildNodeSelector(
|
|
1435
|
+
s.target.tag,
|
|
1436
|
+
s.target.semantics,
|
|
1437
|
+
{ excludeClasses: !0 }
|
|
1438
|
+
// KEY: no classes on target
|
|
1439
|
+
), p = g.parentElement;
|
|
1440
|
+
p && ["td", "th", "tr", "thead", "tbody", "tfoot"].includes(d) && Array.from(p.children).filter(
|
|
1441
|
+
(y) => y.tagName.toLowerCase() === d
|
|
1442
|
+
).length > 1 ? l.push(`${m}${this.getNthSelector(g, d)}`) : l.push(m);
|
|
1443
|
+
}
|
|
1444
|
+
const u = l.join(" > ");
|
|
1445
|
+
return this.isUnique(u, r) ? u : null;
|
|
1446
|
+
},
|
|
1447
|
+
// ============================================================
|
|
1448
|
+
// Strategy 2: anchor parent[attrs|class|nth] target[attrs_only]
|
|
1449
|
+
// Descendant combinator (space) - more flexible
|
|
1450
|
+
// Parents: disambiguated using attrs > stable class > nth-of-type
|
|
1451
|
+
// Target: ONLY attributes, NO classes
|
|
1452
|
+
// ============================================================
|
|
1453
|
+
() => {
|
|
1454
|
+
const h = [this.buildNodeSelector(s.anchor.tag, s.anchor.semantics)];
|
|
1455
|
+
for (let f = 0; f < i.length - 1; f++) {
|
|
1456
|
+
const d = i[f].tagName.toLowerCase(), m = s.path[f] || null, p = h.join(" ") + " " + d;
|
|
1457
|
+
if (this.querySelectorSafe(p, r).length > 1) {
|
|
1458
|
+
if (m?.semantics?.attributes) {
|
|
1459
|
+
const A = this.buildNodeSelector(d, m.semantics, {
|
|
1460
|
+
excludeClasses: !0
|
|
1461
|
+
}), b = h.join(" ") + " " + A;
|
|
1462
|
+
if (this.querySelectorSafe(b, r).length === 1 || this.querySelectorSafe(b + " " + s.target.tag, r).length === 1) {
|
|
1463
|
+
h.push(A);
|
|
1464
|
+
continue;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
if (m?.semantics?.classes) {
|
|
1468
|
+
const A = I(m.semantics.classes);
|
|
1469
|
+
if (A.length > 0) {
|
|
1470
|
+
const b = `${d}.${this.escapeCSS(A[0])}`, v = h.join(" ") + " " + b;
|
|
1471
|
+
if (this.querySelectorSafe(v, r).length === 1 || this.querySelectorSafe(v + " " + s.target.tag, r).length === 1) {
|
|
1472
|
+
h.push(b);
|
|
1473
|
+
continue;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
const y = i[f], w = y.parentElement;
|
|
1478
|
+
if (w && Array.from(w.children).filter(
|
|
1479
|
+
(b) => b.tagName.toLowerCase() === d
|
|
1480
|
+
).length > 1) {
|
|
1481
|
+
h.push(`${d}${this.getNthSelector(y, d)}`);
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
h.push(d);
|
|
1486
|
+
}
|
|
1487
|
+
const c = this.buildNodeSelector(
|
|
1488
|
+
s.target.tag,
|
|
1489
|
+
s.target.semantics,
|
|
1490
|
+
{ excludeClasses: !0 }
|
|
1491
|
+
// KEY: no classes on target
|
|
1492
|
+
);
|
|
1493
|
+
h.push(c);
|
|
1494
|
+
const u = h.join(" ");
|
|
1495
|
+
return this.isUnique(u, r) ? u : null;
|
|
1496
|
+
},
|
|
1497
|
+
// ============================================================
|
|
1498
|
+
// Strategy 3: anchor path target[attrs + 1_stable_class]
|
|
1499
|
+
// Add ONE stable class to target (must be semantic, NOT utility)
|
|
1500
|
+
// Only use this if attrs alone are not sufficient
|
|
1501
|
+
// ============================================================
|
|
1502
|
+
() => {
|
|
1503
|
+
const l = this.buildNodeSelector(s.anchor.tag, s.anchor.semantics), h = [];
|
|
1504
|
+
for (const g of s.path)
|
|
1505
|
+
h.push(g.tag);
|
|
1506
|
+
if (I(s.target.semantics.classes ?? []).length === 0)
|
|
1507
|
+
return null;
|
|
1508
|
+
const u = this.buildNodeSelector(
|
|
1509
|
+
s.target.tag,
|
|
1510
|
+
s.target.semantics,
|
|
1511
|
+
{ maxClasses: 1 }
|
|
1512
|
+
// KEY: ONE stable class only
|
|
1513
|
+
), f = [l, ...h.slice(0, -1), u].join(" ");
|
|
1514
|
+
return this.isUnique(f, r) ? f : null;
|
|
1515
|
+
},
|
|
1516
|
+
// ============================================================
|
|
1517
|
+
// Strategy 4: anchor path target[attrs]:nth-of-type(N)
|
|
1518
|
+
// Last resort - add nth-of-type to target
|
|
1519
|
+
// Only use when all other strategies fail
|
|
1520
|
+
// ============================================================
|
|
1521
|
+
() => {
|
|
1522
|
+
const l = this.buildNodeSelector(s.anchor.tag, s.anchor.semantics), h = [];
|
|
1523
|
+
for (const m of s.path)
|
|
1524
|
+
h.push(m.tag);
|
|
1525
|
+
const c = i[i.length - 1], u = c.parentElement;
|
|
1526
|
+
if (!u || Array.from(u.children).filter(
|
|
1527
|
+
(m) => m.tagName.toLowerCase() === s.target.tag
|
|
1528
|
+
).length <= 1) return null;
|
|
1529
|
+
const g = this.buildNodeSelector(
|
|
1530
|
+
s.target.tag,
|
|
1531
|
+
s.target.semantics,
|
|
1532
|
+
{ excludeClasses: !0 }
|
|
1533
|
+
// No classes, just attrs + nth
|
|
1534
|
+
) + this.getNthSelector(c, s.target.tag), d = [l, ...h.slice(0, -1), g].join(" ");
|
|
1535
|
+
return this.isUnique(d, r) ? d : null;
|
|
1536
|
+
}
|
|
1537
|
+
];
|
|
1538
|
+
for (const l of o) {
|
|
1539
|
+
const h = l();
|
|
1540
|
+
if (h) return h;
|
|
1541
|
+
}
|
|
1542
|
+
return null;
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* Builds a minimal selector for a DOM element
|
|
1546
|
+
* @param element The DOM element to create a selector for
|
|
1547
|
+
* @returns A minimal CSS selector for the element
|
|
1548
|
+
*/
|
|
1549
|
+
// @ts-ignore: Method is used dynamically in buildPathFromAnchorToTarget
|
|
1550
|
+
buildElementSelector(t) {
|
|
1551
|
+
const e = t.tagName.toLowerCase();
|
|
1552
|
+
let s = e;
|
|
1553
|
+
if (t.id && !this.isDynamicId(t.id))
|
|
1554
|
+
return `${e}#${this.escapeCSS(t.id)}`;
|
|
1555
|
+
const r = Array.from(t.classList), i = I(r);
|
|
1556
|
+
i.length > 0 && (s += i.slice(0, 2).map((o) => `.${this.escapeCSS(o)}`).join(""));
|
|
1557
|
+
const a = t.getAttribute("role");
|
|
1558
|
+
return a && (s += `[role="${this.escapeAttr(a)}"]`), s;
|
|
1559
|
+
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Checks if ID is dynamic (generated)
|
|
1562
|
+
*/
|
|
1563
|
+
isDynamicId(t) {
|
|
1564
|
+
return [
|
|
1565
|
+
/^[a-f0-9]{8,}$/i,
|
|
1566
|
+
// hex hash
|
|
1567
|
+
/^\d{5,}$/,
|
|
1568
|
+
// numeric
|
|
1569
|
+
/^(r|react|ember|vue)[\d_]/i,
|
|
1570
|
+
// framework prefixes
|
|
1571
|
+
/:r\d+:$/
|
|
1572
|
+
// React 18 ID pattern
|
|
1573
|
+
].some((s) => s.test(t));
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Safe querySelectorAll that doesn't throw
|
|
1577
|
+
*/
|
|
1578
|
+
querySelectorSafe(t, e) {
|
|
1579
|
+
try {
|
|
1580
|
+
return Array.from(e.querySelectorAll(t));
|
|
1581
|
+
} catch {
|
|
1582
|
+
return [];
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
/**
|
|
1586
|
+
* Finds element by matching text content
|
|
1587
|
+
* Returns the matching element (used with getNthSelector for table-aware positioning)
|
|
1588
|
+
*/
|
|
1589
|
+
findNthElementByText(t, e, s) {
|
|
1590
|
+
const r = this.querySelectorSafe(t, s);
|
|
1591
|
+
if (r.length <= 1) return null;
|
|
1592
|
+
if (e.text) {
|
|
1593
|
+
const i = e.text.normalized;
|
|
1594
|
+
for (const a of r) {
|
|
1595
|
+
const o = a.textContent?.trim() || "";
|
|
1596
|
+
if (o === i || o.includes(i) || i.includes(o))
|
|
1597
|
+
return a;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
return null;
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Checks if selector matches exactly one element
|
|
1604
|
+
*/
|
|
1605
|
+
isUnique(t, e) {
|
|
1606
|
+
try {
|
|
1607
|
+
return e.querySelectorAll(t).length === 1;
|
|
1608
|
+
} catch {
|
|
1609
|
+
return !1;
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
/**
|
|
1613
|
+
* Gets nth-of-type index for an element
|
|
1614
|
+
*/
|
|
1615
|
+
getNthOfTypeIndex(t, e) {
|
|
1616
|
+
const s = t.parentElement;
|
|
1617
|
+
if (!s) return null;
|
|
1618
|
+
const i = Array.from(s.children).filter(
|
|
1619
|
+
(a) => a.tagName.toLowerCase() === e
|
|
1620
|
+
).indexOf(t);
|
|
1621
|
+
return i !== -1 ? i + 1 : null;
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* FIX 2: Ensures anchor selector is unique in the document
|
|
1625
|
+
* Priority order: tag → tag.class → tag[attr] → tag:nth-of-type(N)
|
|
1626
|
+
* @param eid - Element Identity with anchor information
|
|
1627
|
+
* @param root - Root element for uniqueness check
|
|
1628
|
+
* @returns Unique selector for anchor
|
|
1629
|
+
*/
|
|
1630
|
+
ensureUniqueAnchor(t, e) {
|
|
1631
|
+
const s = t.anchor.tag, r = t.anchor.semantics;
|
|
1632
|
+
if (this.isUnique(s, e))
|
|
1633
|
+
return s;
|
|
1634
|
+
if (r.classes && r.classes.length > 0) {
|
|
1635
|
+
const a = I(r.classes);
|
|
1636
|
+
if (a.length > 0) {
|
|
1637
|
+
const o = `${s}.${this.escapeCSS(a[0])}`;
|
|
1638
|
+
if (this.isUnique(o, e))
|
|
1639
|
+
return o;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
if (r.attributes) {
|
|
1643
|
+
const a = this.getSortedAttributes(r.attributes);
|
|
1644
|
+
for (const { name: o, value: l } of a) {
|
|
1645
|
+
const h = o === "href" || o === "src" ? H(o, l) : l;
|
|
1646
|
+
if (h) {
|
|
1647
|
+
const c = `${s}[${o}="${this.escapeAttr(h)}"]`;
|
|
1648
|
+
if (this.isUnique(c, e))
|
|
1649
|
+
return c;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
const i = Array.from(e.querySelectorAll(s));
|
|
1654
|
+
if (i.length > 1) {
|
|
1655
|
+
const a = this.findElementBySemantics(i, r);
|
|
1656
|
+
if (a) {
|
|
1657
|
+
const o = this.getNthOfTypeIndex(a, s);
|
|
1658
|
+
if (o)
|
|
1659
|
+
return `${s}:nth-of-type(${o})`;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
return s;
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* FIX 2: Finds element by matching semantics
|
|
1666
|
+
* @param elements - Array of candidate elements
|
|
1667
|
+
* @param semantics - Semantics to match against
|
|
1668
|
+
* @returns Matching element or null
|
|
1669
|
+
*/
|
|
1670
|
+
findElementBySemantics(t, e) {
|
|
1671
|
+
return e.classes && e.classes.length > 0 || e.attributes && Object.keys(e.attributes).length > 0 || e.text ? t.find((r) => {
|
|
1672
|
+
if (e.classes && e.classes.length > 0 && e.classes.every(
|
|
1673
|
+
(a) => r.classList.contains(a)
|
|
1674
|
+
) || e.attributes && Object.entries(e.attributes).every(
|
|
1675
|
+
([a, o]) => r.getAttribute(a) === o
|
|
1676
|
+
))
|
|
1677
|
+
return !0;
|
|
1678
|
+
if (e.text) {
|
|
1679
|
+
const i = r.textContent?.trim() || "", a = e.text.normalized;
|
|
1680
|
+
if (i.includes(a) || a.includes(i))
|
|
1681
|
+
return !0;
|
|
1682
|
+
}
|
|
1683
|
+
return !1;
|
|
1684
|
+
}) || null : t.length > 0 ? t[0] : null;
|
|
1685
|
+
}
|
|
1686
|
+
/**
|
|
1687
|
+
* FIX 3: Gets nth selector - nth-child for tables, nth-of-type for others
|
|
1688
|
+
* This method is now ACTIVELY INTEGRATED in selector generation logic
|
|
1689
|
+
* to ensure table elements use position-specific nth-child selectors
|
|
1690
|
+
* @param element - Element to get selector for
|
|
1691
|
+
* @param tag - Tag name
|
|
1692
|
+
* @returns nth selector string (e.g., ":nth-child(2)" or ":nth-of-type(2)")
|
|
1693
|
+
*/
|
|
1694
|
+
getNthSelector(t, e) {
|
|
1695
|
+
const s = t.parentElement;
|
|
1696
|
+
if (!s) return "";
|
|
1697
|
+
const r = Array.from(s.children), i = r.indexOf(t) + 1;
|
|
1698
|
+
return ["tr", "td", "th", "thead", "tbody", "tfoot"].includes(e) ? `:nth-child(${i})` : `:nth-of-type(${r.filter((l) => l.tagName.toLowerCase() === e).indexOf(t) + 1})`;
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
* Gets attribute priority for sorting
|
|
1702
|
+
* @param attrName - Attribute name
|
|
1703
|
+
* @returns Priority number (higher = more priority)
|
|
1704
|
+
*/
|
|
1705
|
+
getAttributePriority(t) {
|
|
1706
|
+
return T[t] !== void 0 ? T[t] : t.startsWith("data-") ? T["data-*"] : t.startsWith("aria-") ? T["aria-*"] : 0;
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Checks if attribute should be ignored
|
|
1710
|
+
* @param attrName - Attribute name
|
|
1711
|
+
* @returns True if should be ignored
|
|
1712
|
+
*/
|
|
1713
|
+
shouldIgnoreAttribute(t) {
|
|
1714
|
+
return !!(J.has(t) || t.startsWith("on") || t.startsWith("ng-") || t.startsWith("_ng") || t.startsWith("data-reactid") || t.startsWith("data-react") || t.startsWith("data-v-"));
|
|
1715
|
+
}
|
|
1716
|
+
/**
|
|
1717
|
+
* Gets attributes sorted by priority
|
|
1718
|
+
* @param attributes - Attributes object
|
|
1719
|
+
* @returns Sorted array of attributes with priority
|
|
1720
|
+
*/
|
|
1721
|
+
getSortedAttributes(t) {
|
|
1722
|
+
return Object.entries(t).filter(([e]) => !this.shouldIgnoreAttribute(e)).map(([e, s]) => ({
|
|
1723
|
+
name: e,
|
|
1724
|
+
value: s,
|
|
1725
|
+
priority: this.getAttributePriority(e)
|
|
1726
|
+
})).filter((e) => e.priority > 0).sort((e, s) => s.priority - e.priority);
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* Builds selector for a single node
|
|
1730
|
+
* Priority: ID → semantic attributes → role → classes
|
|
1731
|
+
*/
|
|
1732
|
+
buildNodeSelector(t, e, s) {
|
|
1733
|
+
let r = t;
|
|
1734
|
+
if (e.id)
|
|
1735
|
+
return r += `#${this.escapeCSS(e.id)}`, r;
|
|
1736
|
+
if (e.attributes) {
|
|
1737
|
+
const i = this.getSortedAttributes(e.attributes);
|
|
1738
|
+
for (const { name: a, value: o } of i) {
|
|
1739
|
+
const l = a === "href" || a === "src" ? H(a, o) : o;
|
|
1740
|
+
l && (r += `[${a}="${this.escapeAttr(l)}"]`);
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
if (e.role && !e.attributes?.role && (r += `[role="${this.escapeAttr(e.role)}"]`), !s?.excludeClasses && e.classes && e.classes.length > 0) {
|
|
1744
|
+
const i = I(e.classes), a = s?.maxClasses !== void 0 ? i.slice(0, s.maxClasses) : i;
|
|
1745
|
+
r += a.map((o) => `.${this.escapeCSS(o)}`).join("");
|
|
1746
|
+
}
|
|
1747
|
+
return r;
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Escapes special characters for CSS selector
|
|
1751
|
+
*/
|
|
1752
|
+
escapeCSS(t) {
|
|
1753
|
+
return t.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1");
|
|
1754
|
+
}
|
|
1755
|
+
/**
|
|
1756
|
+
* Escapes quotes for attribute values
|
|
1757
|
+
*/
|
|
1758
|
+
escapeAttr(t) {
|
|
1759
|
+
return t.replace(/"/g, '\\"').replace(/\\/g, "\\\\");
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Checks if element tag is an SVG child element
|
|
1763
|
+
* @param tag - Element tag name
|
|
1764
|
+
* @returns True if element is an SVG child
|
|
1765
|
+
*/
|
|
1766
|
+
isSvgChildElement(t) {
|
|
1767
|
+
return ct.includes(t);
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
class Dt {
|
|
1771
|
+
/**
|
|
1772
|
+
* Filters elements that match the semantics
|
|
1773
|
+
* @param elements - Candidate elements
|
|
1774
|
+
* @param semantics - Target semantics to match
|
|
1775
|
+
* @returns Filtered elements that match
|
|
1776
|
+
*/
|
|
1777
|
+
match(t, e) {
|
|
1778
|
+
return t.filter((s) => this.matchElement(s, e));
|
|
1779
|
+
}
|
|
1780
|
+
/**
|
|
1781
|
+
* Checks if a single element matches the semantics
|
|
1782
|
+
*/
|
|
1783
|
+
matchElement(t, e) {
|
|
1784
|
+
return !(e.text && !this.matchText(t, e.text) || e.attributes && !this.matchAttributes(t, e.attributes) || e.svg && !this.matchSvgFingerprint(t, e.svg));
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Matches text content
|
|
1788
|
+
* Prioritizes direct text nodes, but falls back to full textContent if no direct text
|
|
1789
|
+
*/
|
|
1790
|
+
matchText(t, e) {
|
|
1791
|
+
const i = Array.from(t.childNodes).filter((o) => o.nodeType === Node.TEXT_NODE).map((o) => o.textContent?.trim() ?? "").join(" ") || (t.textContent?.trim() ?? "");
|
|
1792
|
+
if (!i) return !1;
|
|
1793
|
+
const a = B(i);
|
|
1794
|
+
return e.matchMode === "partial" ? a.includes(e.normalized) : a === e.normalized;
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1797
|
+
* Matches attributes
|
|
1798
|
+
*/
|
|
1799
|
+
matchAttributes(t, e) {
|
|
1800
|
+
for (const [s, r] of Object.entries(e))
|
|
1801
|
+
if (t.getAttribute(s) !== r)
|
|
1802
|
+
return !1;
|
|
1803
|
+
return !0;
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Matches SVG fingerprint
|
|
1807
|
+
*/
|
|
1808
|
+
matchSvgFingerprint(t, e) {
|
|
1809
|
+
if (t.tagName.toLowerCase() !== e.shape)
|
|
1810
|
+
return !1;
|
|
1811
|
+
if (e.dHash && e.shape === "path") {
|
|
1812
|
+
const s = t.getAttribute("d");
|
|
1813
|
+
if (s && this.computePathHash(s) !== e.dHash)
|
|
1814
|
+
return !1;
|
|
1815
|
+
}
|
|
1816
|
+
return !(e.geomHash && ["circle", "rect", "ellipse", "line"].includes(e.shape) && this.computeGeomHash(t, e.shape) !== e.geomHash || e.titleText && t.querySelector("title")?.textContent?.trim() !== e.titleText);
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Computes simple path hash (matching SvgFingerprinter)
|
|
1820
|
+
*/
|
|
1821
|
+
computePathHash(t) {
|
|
1822
|
+
const r = (t.match(/[MLHVCSQTAZ][^MLHVCSQTAZ]*/gi) ?? []).slice(0, 5).map((i) => i.trim().replace(/(-?\d+\.?\d*)/g, (a) => parseFloat(a).toFixed(1))).join(" ");
|
|
1823
|
+
return this.simpleHash(r);
|
|
1824
|
+
}
|
|
1825
|
+
/**
|
|
1826
|
+
* Computes geometry hash for non-path shapes (matching SvgFingerprinter)
|
|
1827
|
+
*/
|
|
1828
|
+
computeGeomHash(t, e) {
|
|
1829
|
+
const s = [];
|
|
1830
|
+
switch (e) {
|
|
1831
|
+
case "circle":
|
|
1832
|
+
s.push(`r=${t.getAttribute("r") ?? "0"}`);
|
|
1833
|
+
break;
|
|
1834
|
+
case "rect": {
|
|
1835
|
+
const r = parseFloat(t.getAttribute("width") ?? "0"), i = parseFloat(t.getAttribute("height") ?? "0");
|
|
1836
|
+
r > 0 && i > 0 && s.push(`ratio=${(r / i).toFixed(2)}`);
|
|
1837
|
+
break;
|
|
1838
|
+
}
|
|
1839
|
+
case "ellipse": {
|
|
1840
|
+
const r = parseFloat(t.getAttribute("rx") ?? "0"), i = parseFloat(t.getAttribute("ry") ?? "0");
|
|
1841
|
+
r > 0 && i > 0 && s.push(`ratio=${(r / i).toFixed(2)}`);
|
|
1842
|
+
break;
|
|
1843
|
+
}
|
|
1844
|
+
case "line": {
|
|
1845
|
+
const r = parseFloat(t.getAttribute("x1") ?? "0"), i = parseFloat(t.getAttribute("y1") ?? "0"), a = parseFloat(t.getAttribute("x2") ?? "0"), o = parseFloat(t.getAttribute("y2") ?? "0"), l = Math.atan2(o - i, a - r);
|
|
1846
|
+
s.push(`angle=${l.toFixed(2)}`);
|
|
1847
|
+
break;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
return this.simpleHash(s.join(";"));
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* Simple hash function (matching SvgFingerprinter)
|
|
1854
|
+
*/
|
|
1855
|
+
simpleHash(t) {
|
|
1856
|
+
let e = 0;
|
|
1857
|
+
for (let s = 0; s < t.length; s++) {
|
|
1858
|
+
const r = t.charCodeAt(s);
|
|
1859
|
+
e = (e << 5) - e + r, e = e & e;
|
|
1860
|
+
}
|
|
1861
|
+
return Math.abs(e).toString(16).padStart(8, "0");
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
class Rt {
|
|
1865
|
+
/**
|
|
1866
|
+
* Applies a single constraint to candidates
|
|
1867
|
+
* @param candidates - Current candidate elements
|
|
1868
|
+
* @param constraint - Constraint to apply
|
|
1869
|
+
* @returns Filtered candidates
|
|
1870
|
+
*/
|
|
1871
|
+
applyConstraint(t, e) {
|
|
1872
|
+
switch (e.type) {
|
|
1873
|
+
case "text-proximity":
|
|
1874
|
+
return this.applyTextProximity(
|
|
1875
|
+
t,
|
|
1876
|
+
e.params
|
|
1877
|
+
);
|
|
1878
|
+
case "position":
|
|
1879
|
+
return this.applyPosition(
|
|
1880
|
+
t,
|
|
1881
|
+
e.params
|
|
1882
|
+
);
|
|
1883
|
+
default:
|
|
1884
|
+
return t;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* Applies text proximity constraint using Levenshtein distance
|
|
1889
|
+
*/
|
|
1890
|
+
applyTextProximity(t, e) {
|
|
1891
|
+
return t.filter((s) => {
|
|
1892
|
+
const r = s.textContent?.trim() ?? "";
|
|
1893
|
+
return this.levenshteinDistance(r, e.reference) <= e.maxDistance;
|
|
1894
|
+
});
|
|
1895
|
+
}
|
|
1896
|
+
/**
|
|
1897
|
+
* Applies position constraint
|
|
1898
|
+
*/
|
|
1899
|
+
applyPosition(t, e) {
|
|
1900
|
+
if (t.length <= 1) return t;
|
|
1901
|
+
switch (e.strategy) {
|
|
1902
|
+
case "first-in-dom":
|
|
1903
|
+
return [t[0]];
|
|
1904
|
+
case "top-most":
|
|
1905
|
+
return [this.getTopMost(t)];
|
|
1906
|
+
case "left-most":
|
|
1907
|
+
return [this.getLeftMost(t)];
|
|
1908
|
+
default:
|
|
1909
|
+
return [t[0]];
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
/**
|
|
1913
|
+
* Gets the top-most element by bounding rect
|
|
1914
|
+
*/
|
|
1915
|
+
getTopMost(t) {
|
|
1916
|
+
return t.reduce((e, s) => {
|
|
1917
|
+
try {
|
|
1918
|
+
const r = e.getBoundingClientRect();
|
|
1919
|
+
return s.getBoundingClientRect().top < r.top ? s : e;
|
|
1920
|
+
} catch {
|
|
1921
|
+
return e;
|
|
1922
|
+
}
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
/**
|
|
1926
|
+
* Gets the left-most element by bounding rect
|
|
1927
|
+
*/
|
|
1928
|
+
getLeftMost(t) {
|
|
1929
|
+
return t.reduce((e, s) => {
|
|
1930
|
+
try {
|
|
1931
|
+
const r = e.getBoundingClientRect();
|
|
1932
|
+
return s.getBoundingClientRect().left < r.left ? s : e;
|
|
1933
|
+
} catch {
|
|
1934
|
+
return e;
|
|
1935
|
+
}
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
/**
|
|
1939
|
+
* Calculates Levenshtein distance between two strings
|
|
1940
|
+
*/
|
|
1941
|
+
levenshteinDistance(t, e) {
|
|
1942
|
+
if (t === e) return 0;
|
|
1943
|
+
if (t.length === 0) return e.length;
|
|
1944
|
+
if (e.length === 0) return t.length;
|
|
1945
|
+
const s = Array.from({ length: e.length + 1 }, (r, i) => i);
|
|
1946
|
+
for (let r = 1; r <= t.length; r++) {
|
|
1947
|
+
let i = r;
|
|
1948
|
+
for (let a = 1; a <= e.length; a++) {
|
|
1949
|
+
const o = t[r - 1] === e[a - 1] ? s[a - 1] : Math.min(s[a - 1], i, s[a]) + 1;
|
|
1950
|
+
s[a - 1] = i, i = o;
|
|
1951
|
+
}
|
|
1952
|
+
s[e.length] = i;
|
|
1953
|
+
}
|
|
1954
|
+
return s[e.length];
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
class Ht {
|
|
1958
|
+
constructor() {
|
|
1959
|
+
this.cssGenerator = new tt();
|
|
1960
|
+
}
|
|
1961
|
+
/**
|
|
1962
|
+
* Handles fallback when resolution fails
|
|
1963
|
+
* @param eid - Element Identity being resolved
|
|
1964
|
+
* @param dom - Document or element to search in
|
|
1965
|
+
* @returns Fallback resolution result
|
|
1966
|
+
*/
|
|
1967
|
+
handleFallback(t, e) {
|
|
1968
|
+
const { onMissing: s } = t.fallback;
|
|
1969
|
+
switch (s) {
|
|
1970
|
+
case "anchor-only":
|
|
1971
|
+
return this.fallbackToAnchor(t, e);
|
|
1972
|
+
case "strict":
|
|
1973
|
+
return {
|
|
1974
|
+
status: "error",
|
|
1975
|
+
elements: [],
|
|
1976
|
+
warnings: ["Element not found (strict mode)"],
|
|
1977
|
+
confidence: 0,
|
|
1978
|
+
meta: { degraded: !0, degradationReason: "strict-not-found" }
|
|
1979
|
+
};
|
|
1980
|
+
default:
|
|
1981
|
+
return {
|
|
1982
|
+
status: "error",
|
|
1983
|
+
elements: [],
|
|
1984
|
+
warnings: ["Element not found"],
|
|
1985
|
+
confidence: 0,
|
|
1986
|
+
meta: { degraded: !0, degradationReason: "not-found" }
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
/**
|
|
1991
|
+
* Attempts to find and return the anchor element as fallback
|
|
1992
|
+
*/
|
|
1993
|
+
fallbackToAnchor(t, e) {
|
|
1994
|
+
const s = this.cssGenerator.buildAnchorSelector(t), r = e instanceof Document ? e : e.ownerDocument ?? e;
|
|
1995
|
+
try {
|
|
1996
|
+
const i = r.querySelector(s);
|
|
1997
|
+
if (i)
|
|
1998
|
+
return {
|
|
1999
|
+
status: "degraded-fallback",
|
|
2000
|
+
elements: [i],
|
|
2001
|
+
warnings: ["Target not found, returning anchor"],
|
|
2002
|
+
confidence: t.meta.confidence * 0.3,
|
|
2003
|
+
meta: { degraded: !0, degradationReason: "anchor-fallback" }
|
|
2004
|
+
};
|
|
2005
|
+
} catch (i) {
|
|
2006
|
+
const a = i instanceof Error ? i.message : "Unknown selector error";
|
|
2007
|
+
return {
|
|
2008
|
+
status: "error",
|
|
2009
|
+
elements: [],
|
|
2010
|
+
warnings: [`Invalid anchor selector: ${a}`],
|
|
2011
|
+
confidence: 0,
|
|
2012
|
+
meta: { degraded: !0, degradationReason: "invalid-anchor-selector" }
|
|
2013
|
+
};
|
|
2014
|
+
}
|
|
2015
|
+
return {
|
|
2016
|
+
status: "error",
|
|
2017
|
+
elements: [],
|
|
2018
|
+
warnings: ["Anchor also not found"],
|
|
2019
|
+
confidence: 0,
|
|
2020
|
+
meta: { degraded: !0, degradationReason: "anchor-not-found" }
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
/**
|
|
2024
|
+
* Handles ambiguous results (multiple matches)
|
|
2025
|
+
* @param elements - All matching elements
|
|
2026
|
+
* @param eid - Original Element Identity
|
|
2027
|
+
* @returns Resolution result based on fallback rules
|
|
2028
|
+
*/
|
|
2029
|
+
handleAmbiguous(t, e) {
|
|
2030
|
+
const { onMultiple: s } = e.fallback;
|
|
2031
|
+
switch (s) {
|
|
2032
|
+
case "first":
|
|
2033
|
+
return {
|
|
2034
|
+
status: "success",
|
|
2035
|
+
elements: [t[0]],
|
|
2036
|
+
warnings: ["Multiple matches, returning first"],
|
|
2037
|
+
confidence: e.meta.confidence * 0.7,
|
|
2038
|
+
meta: { degraded: !0, degradationReason: "first-of-multiple" }
|
|
2039
|
+
};
|
|
2040
|
+
case "best-score":
|
|
2041
|
+
return this.selectBestScoring(t, e);
|
|
2042
|
+
default:
|
|
2043
|
+
return {
|
|
2044
|
+
status: "ambiguous",
|
|
2045
|
+
elements: t,
|
|
2046
|
+
warnings: [`Multiple matches: ${t.length}`],
|
|
2047
|
+
confidence: e.meta.confidence * 0.5,
|
|
2048
|
+
meta: { degraded: !0, degradationReason: "multiple-matches" }
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
/**
|
|
2053
|
+
* Selects the best-scoring element from candidates
|
|
2054
|
+
* Re-scores each element based on semantic match quality
|
|
2055
|
+
*/
|
|
2056
|
+
selectBestScoring(t, e) {
|
|
2057
|
+
const s = e.target.semantics;
|
|
2058
|
+
let r = t[0], i = -1;
|
|
2059
|
+
for (const a of t) {
|
|
2060
|
+
const o = this.scoreElementMatch(a, s);
|
|
2061
|
+
o > i && (i = o, r = a);
|
|
2062
|
+
}
|
|
2063
|
+
return {
|
|
2064
|
+
status: "success",
|
|
2065
|
+
elements: [r],
|
|
2066
|
+
warnings: [
|
|
2067
|
+
`Multiple matches (${t.length}), selected best-scoring element`
|
|
2068
|
+
],
|
|
2069
|
+
confidence: e.meta.confidence * (0.7 + i * 0.2),
|
|
2070
|
+
meta: { degraded: !0, degradationReason: "best-of-multiple" }
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* Scores how well an element matches the target semantics
|
|
2075
|
+
* @returns Score from 0 to 1
|
|
2076
|
+
*/
|
|
2077
|
+
scoreElementMatch(t, e) {
|
|
2078
|
+
let s = 0, r = 0;
|
|
2079
|
+
if (e.id && (r += 0.3, t.id === e.id && (s += 0.3)), e.classes && e.classes.length > 0) {
|
|
2080
|
+
r += 0.25;
|
|
2081
|
+
const i = Array.from(t.classList), a = e.classes.filter(
|
|
2082
|
+
(o) => i.includes(o)
|
|
2083
|
+
).length;
|
|
2084
|
+
s += a / e.classes.length * 0.25;
|
|
2085
|
+
}
|
|
2086
|
+
if (e.attributes) {
|
|
2087
|
+
const i = Object.entries(e.attributes);
|
|
2088
|
+
if (i.length > 0) {
|
|
2089
|
+
r += 0.2;
|
|
2090
|
+
let a = 0;
|
|
2091
|
+
for (const [o, l] of i)
|
|
2092
|
+
t.getAttribute(o) === l && a++;
|
|
2093
|
+
s += a / i.length * 0.2;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
if (e.role && (r += 0.15, t.getAttribute("role") === e.role && (s += 0.15)), e.text) {
|
|
2097
|
+
r += 0.1;
|
|
2098
|
+
const i = B(t.textContent);
|
|
2099
|
+
i === e.text.normalized ? s += 0.1 : i.includes(e.text.normalized) && (s += 0.05);
|
|
2100
|
+
}
|
|
2101
|
+
return r > 0 ? s / r : 0;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
function Pt(n, t, e = {}) {
|
|
2105
|
+
const s = { ...ht, ...e }, r = new tt(), i = new Dt(), a = new Rt(), o = new Ht(), l = t instanceof Document ? t : t.ownerDocument ?? t, h = r.buildSelector(n, {
|
|
2106
|
+
ensureUnique: !1,
|
|
2107
|
+
root: l
|
|
2108
|
+
});
|
|
2109
|
+
let c;
|
|
2110
|
+
try {
|
|
2111
|
+
c = Array.from(l.querySelectorAll(h));
|
|
2112
|
+
} catch (d) {
|
|
2113
|
+
const m = d instanceof Error ? d.message : "Unknown selector error";
|
|
2114
|
+
return {
|
|
2115
|
+
status: "error",
|
|
2116
|
+
elements: [],
|
|
2117
|
+
warnings: [
|
|
2118
|
+
`Invalid CSS selector: ${h}`,
|
|
2119
|
+
`Error: ${m}`
|
|
2120
|
+
],
|
|
2121
|
+
confidence: 0,
|
|
2122
|
+
meta: { degraded: !0, degradationReason: "invalid-selector" }
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
c.length > s.maxCandidates && (c = c.slice(0, s.maxCandidates));
|
|
2126
|
+
const u = i.match(c, n.target.semantics);
|
|
2127
|
+
if (u.length === 1)
|
|
2128
|
+
return {
|
|
2129
|
+
status: "success",
|
|
2130
|
+
elements: u,
|
|
2131
|
+
warnings: [],
|
|
2132
|
+
confidence: n.meta.confidence,
|
|
2133
|
+
meta: { degraded: !1 }
|
|
2134
|
+
};
|
|
2135
|
+
if (u.length === 0)
|
|
2136
|
+
return s.enableFallback ? o.handleFallback(n, l) : {
|
|
2137
|
+
status: "error",
|
|
2138
|
+
elements: [],
|
|
2139
|
+
warnings: ["No matching elements found"],
|
|
2140
|
+
confidence: 0,
|
|
2141
|
+
meta: { degraded: !0, degradationReason: "not-found" }
|
|
2142
|
+
};
|
|
2143
|
+
let f = u;
|
|
2144
|
+
const g = kt(n.constraints);
|
|
2145
|
+
for (const d of g) {
|
|
2146
|
+
if (f = a.applyConstraint(f, d), f.length === 1)
|
|
2147
|
+
return {
|
|
2148
|
+
status: "success",
|
|
2149
|
+
elements: f,
|
|
2150
|
+
warnings: [],
|
|
2151
|
+
confidence: n.meta.confidence * 0.9,
|
|
2152
|
+
meta: { degraded: !1 }
|
|
2153
|
+
};
|
|
2154
|
+
if (f.length === 0)
|
|
2155
|
+
return s.enableFallback ? o.handleFallback(n, l) : {
|
|
2156
|
+
status: "error",
|
|
2157
|
+
elements: [],
|
|
2158
|
+
warnings: ["Constraints eliminated all candidates"],
|
|
2159
|
+
confidence: 0,
|
|
2160
|
+
meta: { degraded: !0, degradationReason: "over-constrained" }
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
return s.strictMode ? {
|
|
2164
|
+
status: "ambiguous",
|
|
2165
|
+
elements: f,
|
|
2166
|
+
warnings: [`Non-unique resolution: ${f.length} matches`],
|
|
2167
|
+
confidence: n.meta.confidence * 0.7,
|
|
2168
|
+
meta: { degraded: !0, degradationReason: "ambiguous" }
|
|
2169
|
+
} : o.handleAmbiguous(f, n);
|
|
2170
|
+
}
|
|
2171
|
+
function kt(n) {
|
|
2172
|
+
return [...n].sort((t, e) => e.priority - t.priority);
|
|
2173
|
+
}
|
|
2174
|
+
function Yt(n) {
|
|
2175
|
+
const t = [], e = [];
|
|
2176
|
+
if (n.version ? n.version !== "1.0" && e.push(`Unknown version: ${n.version}`) : t.push("Missing version field"), n.anchor ? (n.anchor.tag || t.push("Anchor missing tag"), typeof n.anchor.score != "number" && t.push("Anchor missing score"), n.anchor.semantics || t.push("Anchor missing semantics")) : t.push("Missing anchor field"), n.target ? (n.target.tag || t.push("Target missing tag"), typeof n.target.score != "number" && t.push("Target missing score"), n.target.semantics || t.push("Target missing semantics")) : t.push("Missing target field"), !Array.isArray(n.path))
|
|
2177
|
+
t.push("Path must be an array");
|
|
2178
|
+
else
|
|
2179
|
+
for (let s = 0; s < n.path.length; s++) {
|
|
2180
|
+
const r = n.path[s];
|
|
2181
|
+
r.tag || t.push(`Path node ${s} missing tag`), r.semantics || t.push(`Path node ${s} missing semantics`);
|
|
2182
|
+
}
|
|
2183
|
+
return n.meta ? (typeof n.meta.confidence != "number" && e.push("Missing confidence score"), n.meta.generatedAt || e.push("Missing generatedAt timestamp")) : t.push("Missing meta field"), Array.isArray(n.constraints) || e.push("Constraints should be an array"), n.fallback || e.push("Missing fallback rules"), {
|
|
2184
|
+
valid: t.length === 0,
|
|
2185
|
+
errors: t,
|
|
2186
|
+
warnings: e
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
function Kt(n) {
|
|
2190
|
+
if (!n || typeof n != "object") return !1;
|
|
2191
|
+
const t = n;
|
|
2192
|
+
return typeof t.version == "string" && typeof t.anchor == "object" && Array.isArray(t.path) && typeof t.target == "object";
|
|
2193
|
+
}
|
|
2194
|
+
const et = {
|
|
2195
|
+
maxClasses: 2,
|
|
2196
|
+
maxAttributes: 5,
|
|
2197
|
+
includeText: !0,
|
|
2198
|
+
maxTextLength: 50,
|
|
2199
|
+
simplifyTarget: !0,
|
|
2200
|
+
includeConstraints: !0
|
|
2201
|
+
};
|
|
2202
|
+
function X(n) {
|
|
2203
|
+
return n === "id" ? 101 : T[n] !== void 0 ? T[n] : n.startsWith("data-") ? T["data-*"] : n.startsWith("aria-") ? T["aria-*"] : 0;
|
|
2204
|
+
}
|
|
2205
|
+
function qt(n) {
|
|
2206
|
+
return ["id", "data-testid", "data-qa", "data-cy", "href", "text", "role"].includes(n);
|
|
2207
|
+
}
|
|
2208
|
+
function Ot(n) {
|
|
2209
|
+
return !!(/@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/.test(n) || /(\+?\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/.test(n) || /\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}/.test(n));
|
|
2210
|
+
}
|
|
2211
|
+
function Lt(n, t) {
|
|
2212
|
+
const e = { ...et, ...t }, s = `v${n.version}`, r = F(n.anchor, !1, e), i = n.path.length > 0 ? n.path.map((l) => F(l, !1, e)).join(" > ") + " > " : "", a = F(n.target, !0, e), o = e.includeConstraints ? zt(n) : "";
|
|
2213
|
+
return `${s}: ${r} :: ${i}${a}${o}`;
|
|
2214
|
+
}
|
|
2215
|
+
function _t(n) {
|
|
2216
|
+
n = n.trim();
|
|
2217
|
+
const t = n.match(/^v(\d+(?:\.\d+)?)\s*:\s*/);
|
|
2218
|
+
if (!t)
|
|
2219
|
+
throw new Error('Invalid SEQL Selector: missing version prefix (expected "v1:")');
|
|
2220
|
+
const e = t[1];
|
|
2221
|
+
if (e !== "1.0" && e !== "1")
|
|
2222
|
+
throw new Error(`Unsupported SEQL Selector version: v${e} (only v1.0 is supported)`);
|
|
2223
|
+
let s = n.slice(t[0].length);
|
|
2224
|
+
const r = s.match(/^(.+?)\s*::\s*/);
|
|
2225
|
+
if (!r)
|
|
2226
|
+
throw new Error('Invalid SEQL Selector: missing anchor separator "::"');
|
|
2227
|
+
const i = r[1].trim();
|
|
2228
|
+
s = s.slice(r[0].length);
|
|
2229
|
+
const a = s.match(/\s*\{([^}]+)\}\s*$/);
|
|
2230
|
+
let o = "";
|
|
2231
|
+
a && (o = a[1], s = s.slice(0, a.index));
|
|
2232
|
+
const l = s.split(/\s*>\s*/).map((p) => p.trim()).filter((p) => p);
|
|
2233
|
+
if (l.length === 0)
|
|
2234
|
+
throw new Error("Invalid SEQL Selector: missing target node");
|
|
2235
|
+
const h = l[l.length - 1], c = l.slice(0, -1), u = U(i, !0), f = c.map((p) => U(p, !1)), g = U(h, !1), d = Ft(o);
|
|
2236
|
+
return {
|
|
2237
|
+
version: "1.0",
|
|
2238
|
+
anchor: u,
|
|
2239
|
+
path: f,
|
|
2240
|
+
target: g,
|
|
2241
|
+
constraints: d,
|
|
2242
|
+
fallback: {
|
|
2243
|
+
onMultiple: "best-score",
|
|
2244
|
+
onMissing: "anchor-only",
|
|
2245
|
+
maxDepth: 10
|
|
2246
|
+
},
|
|
2247
|
+
meta: {
|
|
2248
|
+
confidence: 0.7,
|
|
2249
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2250
|
+
generator: "seql-parser@1.0",
|
|
2251
|
+
source: "seql-string",
|
|
2252
|
+
degraded: !1
|
|
2253
|
+
}
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
function F(n, t = !1, e = et) {
|
|
2257
|
+
const { tag: s, semantics: r } = n;
|
|
2258
|
+
let i = s;
|
|
2259
|
+
const a = [], o = { ...r.attributes };
|
|
2260
|
+
r.id && (o.id = r.id), r.role && !o.role && (o.role = r.role);
|
|
2261
|
+
const l = Object.entries(o).map(([c, u]) => {
|
|
2262
|
+
const f = X(c), g = c === "href" || c === "src" ? H(c, u) : u;
|
|
2263
|
+
return { name: c, value: g, priority: f };
|
|
2264
|
+
}).filter((c) => ["style", "xmlns", "tabindex", "contenteditable"].includes(c.name) ? !1 : c.priority > 0 || c.name === "role" || c.name === "id");
|
|
2265
|
+
l.sort((c, u) => u.priority - c.priority);
|
|
2266
|
+
const h = l.slice(0, e.maxAttributes);
|
|
2267
|
+
h.sort((c, u) => c.name.localeCompare(u.name));
|
|
2268
|
+
for (const { name: c, value: u } of h)
|
|
2269
|
+
a.push(`${c}="${j(u)}"`);
|
|
2270
|
+
if (e.includeText && r.text && !Ot(r.text.normalized)) {
|
|
2271
|
+
const c = r.text.normalized;
|
|
2272
|
+
c.length > 0 && c.length <= e.maxTextLength && a.push(`text="${j(c)}"`);
|
|
2273
|
+
}
|
|
2274
|
+
if (a.length > 0) {
|
|
2275
|
+
let c = a;
|
|
2276
|
+
t && e.simplifyTarget && r.id && (c = a.filter((u) => {
|
|
2277
|
+
const f = u.split("=")[0];
|
|
2278
|
+
return X(f) >= 60 || f === "text" || f === "id" || f === "role";
|
|
2279
|
+
})), c.length > 0 && (c.sort((u, f) => u.localeCompare(f)), i += `[${c.join(",")}]`);
|
|
2280
|
+
}
|
|
2281
|
+
if (r.classes && r.classes.length > 0) {
|
|
2282
|
+
const c = I(r.classes), u = !!r.id || a.some((g) => g.startsWith("href=") || g.startsWith("data-testid=") || g.startsWith("text=") || g.startsWith("role="));
|
|
2283
|
+
if (!(t && e.simplifyTarget && u) && c.length > 0) {
|
|
2284
|
+
const g = c.sort().slice(0, e.maxClasses);
|
|
2285
|
+
i += g.map((d) => `.${d}`).join("");
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
if ("nthChild" in n && n.nthChild) {
|
|
2289
|
+
const c = !!r.id || r.attributes && Object.keys(r.attributes).some(qt);
|
|
2290
|
+
t && e.simplifyTarget && c || (i += `#${n.nthChild}`);
|
|
2291
|
+
}
|
|
2292
|
+
return i;
|
|
2293
|
+
}
|
|
2294
|
+
function zt(n) {
|
|
2295
|
+
if (!n.constraints || n.constraints.length === 0)
|
|
2296
|
+
return "";
|
|
2297
|
+
const t = [];
|
|
2298
|
+
for (const e of n.constraints)
|
|
2299
|
+
switch (e.type) {
|
|
2300
|
+
case "uniqueness":
|
|
2301
|
+
t.push("unique=true");
|
|
2302
|
+
break;
|
|
2303
|
+
case "position":
|
|
2304
|
+
e.params && e.params.strategy && t.push(`pos=${e.params.strategy}`);
|
|
2305
|
+
break;
|
|
2306
|
+
case "text-proximity":
|
|
2307
|
+
if (e.params && e.params.reference) {
|
|
2308
|
+
const s = j(String(e.params.reference));
|
|
2309
|
+
t.push(`text="${s}"`);
|
|
2310
|
+
}
|
|
2311
|
+
break;
|
|
2312
|
+
}
|
|
2313
|
+
return t.length === 0 ? "" : ` {${t.join(",")}}`;
|
|
2314
|
+
}
|
|
2315
|
+
function U(n, t) {
|
|
2316
|
+
let e = n;
|
|
2317
|
+
const s = {}, r = e.match(/^([a-z][a-z0-9-]*)/);
|
|
2318
|
+
if (!r)
|
|
2319
|
+
throw new Error(`Invalid node: missing tag name in "${n}"`);
|
|
2320
|
+
const i = r[1];
|
|
2321
|
+
e = e.slice(i.length);
|
|
2322
|
+
const a = [];
|
|
2323
|
+
let o;
|
|
2324
|
+
for (; o = e.match(/^\.([a-zA-Z][a-zA-Z0-9-_]*)/); )
|
|
2325
|
+
a.push(o[1]), e = e.slice(o[0].length);
|
|
2326
|
+
a.length > 0 && (s.classes = a);
|
|
2327
|
+
const l = e.match(/^\[([^\]]+)\]/);
|
|
2328
|
+
if (l) {
|
|
2329
|
+
const u = l[1], f = {}, g = Ut(u);
|
|
2330
|
+
for (const d of g) {
|
|
2331
|
+
const m = d.match(/^([a-z][a-z0-9-]*)(?:=|~=)"((?:[^"\\]|\\.)*)"/);
|
|
2332
|
+
if (m) {
|
|
2333
|
+
const [, p, S] = m;
|
|
2334
|
+
f[p] = st(S);
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
Object.keys(f).length > 0 && (f.text && (s.text = {
|
|
2338
|
+
raw: f.text,
|
|
2339
|
+
normalized: f.text
|
|
2340
|
+
}, delete f.text), f.id && (s.id = f.id, delete f.id), f.role && (s.role = f.role, delete f.role), Object.keys(f).length > 0 && (s.attributes = f)), e = e.slice(l[0].length);
|
|
2341
|
+
}
|
|
2342
|
+
let h;
|
|
2343
|
+
const c = e.match(/^#(\d+)/);
|
|
2344
|
+
if (c && (h = parseInt(c[1], 10), e = e.slice(c[0].length)), e.trim())
|
|
2345
|
+
throw new Error(`Invalid node: unexpected content "${e}" in "${n}"`);
|
|
2346
|
+
return t ? {
|
|
2347
|
+
tag: i,
|
|
2348
|
+
semantics: s,
|
|
2349
|
+
score: 0.7,
|
|
2350
|
+
degraded: !1
|
|
2351
|
+
} : {
|
|
2352
|
+
tag: i,
|
|
2353
|
+
semantics: s,
|
|
2354
|
+
score: 0.7,
|
|
2355
|
+
nthChild: h
|
|
2356
|
+
};
|
|
2357
|
+
}
|
|
2358
|
+
function Ft(n) {
|
|
2359
|
+
if (!n.trim())
|
|
2360
|
+
return [];
|
|
2361
|
+
const t = [], e = n.split(",").map((s) => s.trim());
|
|
2362
|
+
for (const s of e) {
|
|
2363
|
+
const [r, i] = s.split("=").map((a) => a.trim());
|
|
2364
|
+
switch (r) {
|
|
2365
|
+
case "unique":
|
|
2366
|
+
i === "true" && t.push({
|
|
2367
|
+
type: "uniqueness",
|
|
2368
|
+
params: {
|
|
2369
|
+
mode: "strict"
|
|
2370
|
+
},
|
|
2371
|
+
priority: 90
|
|
2372
|
+
});
|
|
2373
|
+
break;
|
|
2374
|
+
case "pos":
|
|
2375
|
+
t.push({
|
|
2376
|
+
type: "position",
|
|
2377
|
+
params: {
|
|
2378
|
+
strategy: i
|
|
2379
|
+
},
|
|
2380
|
+
priority: 70
|
|
2381
|
+
});
|
|
2382
|
+
break;
|
|
2383
|
+
case "text":
|
|
2384
|
+
const a = i.replace(/^"(.*)"$/, "$1");
|
|
2385
|
+
t.push({
|
|
2386
|
+
type: "text-proximity",
|
|
2387
|
+
params: {
|
|
2388
|
+
reference: st(a),
|
|
2389
|
+
maxDistance: 5
|
|
2390
|
+
},
|
|
2391
|
+
priority: 60
|
|
2392
|
+
});
|
|
2393
|
+
break;
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
return t;
|
|
2397
|
+
}
|
|
2398
|
+
function Ut(n) {
|
|
2399
|
+
const t = [];
|
|
2400
|
+
let e = "", s = !1;
|
|
2401
|
+
for (let r = 0; r < n.length; r++) {
|
|
2402
|
+
const i = n[r];
|
|
2403
|
+
i === '"' && (r === 0 || n[r - 1] !== "\\") ? (s = !s, e += i) : i === "," && !s ? (e.trim() && t.push(e.trim()), e = "") : e += i;
|
|
2404
|
+
}
|
|
2405
|
+
return e.trim() && t.push(e.trim()), t;
|
|
2406
|
+
}
|
|
2407
|
+
function j(n) {
|
|
2408
|
+
return n.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/>/g, "\\>").replace(/:/g, "\\:");
|
|
2409
|
+
}
|
|
2410
|
+
function st(n) {
|
|
2411
|
+
return n.replace(/\\\\/g, "\0").replace(/\\"/g, '"').replace(/\\>/g, ">").replace(/\\:/g, ":").replace(/\x00/g, "\\");
|
|
2412
|
+
}
|
|
2413
|
+
function Xt(n, t, e) {
|
|
2414
|
+
const s = V(n, t);
|
|
2415
|
+
return s ? Lt(s, e) : null;
|
|
2416
|
+
}
|
|
2417
|
+
function Jt(n, t, e) {
|
|
2418
|
+
try {
|
|
2419
|
+
const s = _t(n);
|
|
2420
|
+
return Pt(s, t, e).elements || [];
|
|
2421
|
+
} catch (s) {
|
|
2422
|
+
return console.error("Failed to resolve SEQL Selector:", s), [];
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
const jt = /* @__PURE__ */ new Set([
|
|
2426
|
+
"script",
|
|
2427
|
+
"style",
|
|
2428
|
+
"noscript",
|
|
2429
|
+
"meta",
|
|
2430
|
+
"link",
|
|
2431
|
+
"head",
|
|
2432
|
+
"title"
|
|
2433
|
+
]);
|
|
2434
|
+
function W(n) {
|
|
2435
|
+
return n.id && !k(n.id) ? 3 : n.hasAttribute("role") || n.hasAttribute("aria-label") || n.hasAttribute("aria-labelledby") || n.hasAttribute("data-testid") || n.hasAttribute("data-qa") || n.hasAttribute("data-test") ? 2 : 1;
|
|
2436
|
+
}
|
|
2437
|
+
function rt(n, t) {
|
|
2438
|
+
const e = n.tagName.toLowerCase();
|
|
2439
|
+
return !!(jt.has(e) || t && W(n) === 1 && ![
|
|
2440
|
+
"form",
|
|
2441
|
+
"main",
|
|
2442
|
+
"nav",
|
|
2443
|
+
"section",
|
|
2444
|
+
"article",
|
|
2445
|
+
"footer",
|
|
2446
|
+
"header",
|
|
2447
|
+
"button",
|
|
2448
|
+
"a",
|
|
2449
|
+
"input",
|
|
2450
|
+
"label",
|
|
2451
|
+
"select",
|
|
2452
|
+
"textarea"
|
|
2453
|
+
].includes(e));
|
|
2454
|
+
}
|
|
2455
|
+
function nt(n) {
|
|
2456
|
+
return [...n].sort((t, e) => {
|
|
2457
|
+
const s = W(t);
|
|
2458
|
+
return W(e) - s;
|
|
2459
|
+
});
|
|
2460
|
+
}
|
|
2461
|
+
function te(n = {}) {
|
|
2462
|
+
const t = performance.now(), {
|
|
2463
|
+
root: e = typeof document < "u" ? document.body : void 0,
|
|
2464
|
+
filter: s = "*",
|
|
2465
|
+
limit: r = 1 / 0,
|
|
2466
|
+
onProgress: i,
|
|
2467
|
+
progressInterval: a = 100,
|
|
2468
|
+
skipNonSemantic: o = !0,
|
|
2469
|
+
generatorOptions: l = {},
|
|
2470
|
+
cache: h,
|
|
2471
|
+
signal: c
|
|
2472
|
+
} = n;
|
|
2473
|
+
if (!e)
|
|
2474
|
+
throw new Error("Root element or document is required");
|
|
2475
|
+
const u = h ?? G(), f = { ...l, cache: u };
|
|
2476
|
+
let g;
|
|
2477
|
+
try {
|
|
2478
|
+
e instanceof Document, g = Array.from(e.querySelectorAll(s));
|
|
2479
|
+
} catch {
|
|
2480
|
+
return {
|
|
2481
|
+
results: [],
|
|
2482
|
+
failed: [],
|
|
2483
|
+
stats: {
|
|
2484
|
+
totalElements: 0,
|
|
2485
|
+
successful: 0,
|
|
2486
|
+
failed: 0,
|
|
2487
|
+
skipped: 0,
|
|
2488
|
+
totalTimeMs: 0,
|
|
2489
|
+
avgTimePerElementMs: 0,
|
|
2490
|
+
cacheHitRate: 0
|
|
2491
|
+
}
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2494
|
+
const d = g.filter(
|
|
2495
|
+
(E) => !rt(E, o)
|
|
2496
|
+
), p = nt(d).slice(0, r), S = [], y = [];
|
|
2497
|
+
let w = 0;
|
|
2498
|
+
const A = p.length;
|
|
2499
|
+
let b = 0;
|
|
2500
|
+
for (let E = 0; E < p.length && !c?.aborted; E++) {
|
|
2501
|
+
const D = p[E], M = u.getEID(D);
|
|
2502
|
+
if (M)
|
|
2503
|
+
S.push({
|
|
2504
|
+
element: D,
|
|
2505
|
+
eid: M,
|
|
2506
|
+
generationTimeMs: 0
|
|
2507
|
+
// Cached, no generation time
|
|
2508
|
+
});
|
|
2509
|
+
else {
|
|
2510
|
+
const z = performance.now();
|
|
2511
|
+
try {
|
|
2512
|
+
const R = V(D, f), it = performance.now() - z;
|
|
2513
|
+
R ? S.push({
|
|
2514
|
+
element: D,
|
|
2515
|
+
eid: R,
|
|
2516
|
+
generationTimeMs: it
|
|
2517
|
+
}) : w++;
|
|
2518
|
+
} catch (R) {
|
|
2519
|
+
y.push({
|
|
2520
|
+
element: D,
|
|
2521
|
+
error: R instanceof Error ? R.message : String(R)
|
|
2522
|
+
});
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
i && E - b >= a && (i(E + 1, A), b = E);
|
|
2526
|
+
}
|
|
2527
|
+
i && i(A, A);
|
|
2528
|
+
const v = performance.now() - t, x = u.getStats(), P = x.eidHits + x.eidMisses + x.selectorHits + x.selectorMisses, C = x.eidHits + x.selectorHits, N = P > 0 ? C / P : 0;
|
|
2529
|
+
return {
|
|
2530
|
+
results: S,
|
|
2531
|
+
failed: y,
|
|
2532
|
+
stats: {
|
|
2533
|
+
totalElements: A,
|
|
2534
|
+
successful: S.length,
|
|
2535
|
+
failed: y.length,
|
|
2536
|
+
skipped: w,
|
|
2537
|
+
totalTimeMs: v,
|
|
2538
|
+
avgTimePerElementMs: S.length > 0 ? v / S.length : 0,
|
|
2539
|
+
cacheHitRate: N
|
|
2540
|
+
}
|
|
2541
|
+
};
|
|
2542
|
+
}
|
|
2543
|
+
function ee(n, t = {}) {
|
|
2544
|
+
const e = performance.now(), {
|
|
2545
|
+
limit: s = 1 / 0,
|
|
2546
|
+
onProgress: r,
|
|
2547
|
+
progressInterval: i = 100,
|
|
2548
|
+
skipNonSemantic: a = !0,
|
|
2549
|
+
generatorOptions: o = {},
|
|
2550
|
+
cache: l,
|
|
2551
|
+
signal: h
|
|
2552
|
+
} = t, c = l ?? G(), u = { ...o, cache: c }, f = n.filter(
|
|
2553
|
+
(C) => !rt(C, a)
|
|
2554
|
+
), d = nt(f).slice(0, s), m = [], p = [];
|
|
2555
|
+
let S = 0;
|
|
2556
|
+
const y = d.length;
|
|
2557
|
+
let w = 0;
|
|
2558
|
+
for (let C = 0; C < d.length && !h?.aborted; C++) {
|
|
2559
|
+
const N = d[C], E = c.getEID(N);
|
|
2560
|
+
if (E)
|
|
2561
|
+
m.push({
|
|
2562
|
+
element: N,
|
|
2563
|
+
eid: E,
|
|
2564
|
+
generationTimeMs: 0
|
|
2565
|
+
});
|
|
2566
|
+
else {
|
|
2567
|
+
const D = performance.now();
|
|
2568
|
+
try {
|
|
2569
|
+
const M = V(N, u), z = performance.now() - D;
|
|
2570
|
+
M ? m.push({
|
|
2571
|
+
element: N,
|
|
2572
|
+
eid: M,
|
|
2573
|
+
generationTimeMs: z
|
|
2574
|
+
}) : S++;
|
|
2575
|
+
} catch (M) {
|
|
2576
|
+
p.push({
|
|
2577
|
+
element: N,
|
|
2578
|
+
error: M instanceof Error ? M.message : String(M)
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
r && C - w >= i && (r(C + 1, y), w = C);
|
|
2583
|
+
}
|
|
2584
|
+
r && r(y, y);
|
|
2585
|
+
const A = performance.now() - e, b = c.getStats(), v = b.eidHits + b.eidMisses + b.selectorHits + b.selectorMisses, x = b.eidHits + b.selectorHits, P = v > 0 ? x / v : 0;
|
|
2586
|
+
return {
|
|
2587
|
+
results: m,
|
|
2588
|
+
failed: p,
|
|
2589
|
+
stats: {
|
|
2590
|
+
totalElements: y,
|
|
2591
|
+
successful: m.length,
|
|
2592
|
+
failed: p.length,
|
|
2593
|
+
skipped: S,
|
|
2594
|
+
totalTimeMs: A,
|
|
2595
|
+
avgTimePerElementMs: m.length > 0 ? A / m.length : 0,
|
|
2596
|
+
cacheHitRate: P
|
|
2597
|
+
}
|
|
2598
|
+
};
|
|
2599
|
+
}
|
|
2600
|
+
export {
|
|
2601
|
+
ut as AnchorFinder,
|
|
2602
|
+
Rt as ConstraintsEvaluator,
|
|
2603
|
+
tt as CssGenerator,
|
|
2604
|
+
lt as DEFAULT_GENERATOR_OPTIONS,
|
|
2605
|
+
ht as DEFAULT_RESOLVER_OPTIONS,
|
|
2606
|
+
$t as EIDCache,
|
|
2607
|
+
Wt as EID_VERSION,
|
|
2608
|
+
Ht as FallbackHandler,
|
|
2609
|
+
Bt as MAX_PATH_DEPTH,
|
|
2610
|
+
yt as PathBuilder,
|
|
2611
|
+
Z as ROLE_ANCHOR_VALUES,
|
|
2612
|
+
Q as SEMANTIC_ANCHOR_TAGS,
|
|
2613
|
+
Gt as SEMANTIC_ATTRIBUTES,
|
|
2614
|
+
ot as SEMANTIC_TAGS,
|
|
2615
|
+
Et as SemanticExtractor,
|
|
2616
|
+
Dt as SemanticsMatcher,
|
|
2617
|
+
Tt as SvgFingerprinter,
|
|
2618
|
+
wt as calculateConfidence,
|
|
2619
|
+
Qt as calculateElementScore,
|
|
2620
|
+
Mt as createEIDCache,
|
|
2621
|
+
St as filterClasses,
|
|
2622
|
+
V as generateEID,
|
|
2623
|
+
te as generateEIDBatch,
|
|
2624
|
+
ee as generateEIDForElements,
|
|
2625
|
+
Xt as generateSEQL,
|
|
2626
|
+
Vt as getClassScore,
|
|
2627
|
+
G as getGlobalCache,
|
|
2628
|
+
Kt as isEID,
|
|
2629
|
+
Y as isUtilityClass,
|
|
2630
|
+
B as normalizeText,
|
|
2631
|
+
_t as parseSEQL,
|
|
2632
|
+
Zt as resetGlobalCache,
|
|
2633
|
+
Pt as resolve,
|
|
2634
|
+
Jt as resolveSEQL,
|
|
2635
|
+
Lt as stringifySEQL,
|
|
2636
|
+
Yt as validateEID
|
|
2637
|
+
};
|
|
2
2638
|
//# sourceMappingURL=seql-js.js.map
|