diff --git a/.agents/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.agents/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.agents/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.agents/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.agents/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.agents/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.agents/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.agents/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.claude/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.claude/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.claude/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.claude/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.claude/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.claude/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.claude/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.claude/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.cursor/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.cursor/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.cursor/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.cursor/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.cursor/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.cursor/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.cursor/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.cursor/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.gemini/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.gemini/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.gemini/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.gemini/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.gemini/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.gemini/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.gemini/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.gemini/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.github/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.github/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.github/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.github/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.github/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.github/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.github/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.github/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.grok/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.grok/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.grok/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.grok/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.grok/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.grok/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.grok/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.grok/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.hermes/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.hermes/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.hermes/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.hermes/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.hermes/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.hermes/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.hermes/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.hermes/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.kiro/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.kiro/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.kiro/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.kiro/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.kiro/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.kiro/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.kiro/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.kiro/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.opencode/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.opencode/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.opencode/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.opencode/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.opencode/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.opencode/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.opencode/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.opencode/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.pi/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.pi/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.pi/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.pi/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.pi/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.pi/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.pi/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.pi/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.qoder/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.qoder/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.qoder/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.qoder/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.qoder/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.qoder/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.qoder/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.qoder/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.rovodev/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.rovodev/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.rovodev/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.rovodev/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.rovodev/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.rovodev/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.rovodev/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.rovodev/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.trae-cn/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.trae-cn/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.trae-cn/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.trae-cn/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.trae-cn/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.trae-cn/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.trae-cn/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.trae-cn/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.trae/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.trae/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.trae/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.trae/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.trae/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.trae/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.trae/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.trae/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/.vibe/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/.vibe/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/.vibe/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/.vibe/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/.vibe/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/.vibe/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/.vibe/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/.vibe/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, }; diff --git a/plugin/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs b/plugin/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs index caf4aff44..e5f53b69a 100644 --- a/plugin/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +++ b/plugin/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs @@ -835,10 +835,11 @@ class StaticElement { } } closest(selector) { + const matcher = this._doc.matcherFor(selector); let cur = this.node; while (cur && cur.type === 'tag') { try { - if (this._doc.is(cur, selector)) return this._doc.wrap(cur); + if (matcher(cur)) return this._doc.wrap(cur); } catch { return null; } @@ -862,9 +863,10 @@ class StaticDocument { this.root = root; this.selectAll = modules.selectAll; this.selectOne = modules.selectOne; - this.is = modules.is; + this.compile = modules.compile; this.domutils = modules.domutils; this._wrappers = new WeakMap(); + this._compiledSelectors = new Map(); this._styleMap = new WeakMap(); this._hoverStyleMap = new WeakMap(); this._accentDashPseudo = new WeakSet(); @@ -882,6 +884,20 @@ class StaticDocument { } return wrapped; } + matcherFor(selector) { + let matcher = this._compiledSelectors.get(selector); + if (!matcher) { + try { + matcher = this.compile(selector); + } catch (err) { + // Cache the failure as a rethrower so a bad selector still reaches + // closest()'s catch on every call, first and repeat alike. + matcher = () => { throw err; }; + } + this._compiledSelectors.set(selector, matcher); + } + return matcher; + } querySelectorAll(selector) { try { return this.selectAll(selector, this.root.children || []).map(node => this.wrap(node)); diff --git a/plugin/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs b/plugin/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs index 9e7a429a2..b4efa84ac 100644 --- a/plugin/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +++ b/plugin/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs @@ -134,7 +134,7 @@ async function detectHtml(filePath, options = {}) { parseDocument: htmlparser2.parseDocument, selectAll: cssSelect.selectAll, selectOne: cssSelect.selectOne, - is: cssSelect.is, + compile: cssSelect.compile, csstree, domutils, };