css-has-pseudo 7.0.3 → 8.0.0

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/CHANGELOG.md CHANGED
@@ -1,9 +1,11 @@
1
1
  # Changes to CSS Has Pseudo
2
2
 
3
- ### 7.0.3
3
+ ### 8.0.0
4
4
 
5
- _August 27, 2025_
5
+ _January 14, 2026_
6
6
 
7
- - Fix order of removal of CSSOM rules when a browser supports `:has()` natively
7
+ - Updated: Support for Node `20.19.0` or later (major).
8
+ - Removed: `commonjs` API. In supported Node versions `require(esm)` will work without needing to make code changes.
9
+ - Updated [`@csstools/selector-specificity`](https://github.com/csstools/postcss-plugins/tree/main/packages/selector-specificity) to [`6.0.0`](https://github.com/csstools/postcss-plugins/tree/main/packages/selector-specificity/CHANGELOG.md#600) (major)
8
10
 
9
11
  [Full CHANGELOG](https://github.com/csstools/postcss-plugins/tree/main/plugins/css-has-pseudo/CHANGELOG.md)
package/README.md CHANGED
@@ -153,12 +153,12 @@ or
153
153
 
154
154
  ```html
155
155
  <!-- When using a CDN url you will have to manually update the version number -->
156
- <script src="https://unpkg.com/css-has-pseudo@7.0.3/dist/browser-global.js"></script>
156
+ <script src="https://unpkg.com/css-has-pseudo@8.0.0/dist/browser-global.js"></script>
157
157
  <script>cssHasPseudo(document)</script>
158
158
  ```
159
159
 
160
160
  > [!TIP]
161
- > Please use a versioned url, like this : `https://unpkg.com/css-has-pseudo@7.0.3/dist/browser-global.js`
161
+ > Please use a versioned url, like this : `https://unpkg.com/css-has-pseudo@8.0.0/dist/browser-global.js`
162
162
  > Without the version, you might unexpectedly get a new major version of the library with breaking changes.
163
163
 
164
164
  [PostCSS Has Pseudo] works in all major browsers, including
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { PluginCreator } from 'postcss';
2
2
 
3
3
  declare const creator: PluginCreator<pluginOptions>;
4
4
  export default creator;
5
+ export { creator as 'module.exports' }
5
6
 
6
7
  /** css-has-pseudo plugin options */
7
8
  export declare type pluginOptions = {
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import e from"postcss-selector-parser";import t from"postcss-value-parser";import{selectorSpecificity as s}from"@csstools/selector-specificity";function encodeCSS(e){if(""===e)return"";let t,s="";for(let o=0;o<e.length;o++)t=e.charCodeAt(o).toString(36),s+=0===o?t:"-"+t;return"csstools-has-"+s}function isGuardedByAtSupportsFromAtRuleParams(e){if(!e.toLowerCase().includes(":has("))return!1;let s=!1;try{const o=new Set;t(e).walk(e=>{if("function"===e.type&&"selector"===e.value.toLowerCase())return o.add(t.stringify(e.nodes)),!1}),o.forEach(e=>{selectorContainsHasPseudo(e)&&(s=!0)})}catch{}return s}function selectorContainsHasPseudo(t){if(!t.toLowerCase().includes(":has("))return!1;let s=!1;try{e().astSync(t).walk(e=>{if("pseudo"===e.type&&":has"===e.value.toLowerCase()&&e.nodes&&e.nodes.length>0)return s=!0,!1})}catch{}return s}const creator=t=>{const o={preserve:!0,specificityMatchingName:"does-not-exist",...t||{}},r=":not(#"+o.specificityMatchingName+")",n=":not(."+o.specificityMatchingName+")",a=":not("+o.specificityMatchingName+")";return{postcssPlugin:"css-has-pseudo",prepare(){const t=new WeakSet;return{postcssPlugin:"css-has-pseudo",RuleExit(c,{result:i}){if(t.has(c))return;if(!c.selector.toLowerCase().includes(":has(")||isWithinSupportCheck(c))return;const l=c.selectors.map(t=>{if(!t.toLowerCase().includes(":has("))return t;let l;try{l=e().astSync(t)}catch(e){return c.warn(i,`Failed to parse selector : "${t}" with message: "${e instanceof Error?e.message:e}"`),t}if(void 0===l)return t;l.walkPseudos(t=>{let s=t.parent,r=!1;for(;s;)e.isPseudoClass(s)&&":has"===s.value.toLowerCase()&&(r=!0),s=s.parent;r&&(":visited"===t.value.toLowerCase()&&t.replaceWith(e.className({value:o.specificityMatchingName})),":any-link"===t.value.toLowerCase()&&(t.value=":link"))}),l.walkPseudos(t=>{if(":has"!==t.value.toLowerCase()||!t.nodes)return;const o=t.parent;if(!o)return;const c=e.selector({value:"",nodes:[]});{let t=o.nodes.length;e:for(let s=0;s<o.nodes.length;s++){const r=o.nodes[s];if(e.isPseudoElement(r))for(let e=s-1;e>=0;e--)if("combinator"!==o.nodes[s].type&&"comment"!==o.nodes[s].type){t=e+1;break e}}o.nodes.slice(0,t).forEach(e=>{e.remove(),"selector"===e.type?e.nodes.forEach(e=>{delete e.parent,c.append(e)}):(delete e.parent,c.append(e))})}const i="["+encodeCSS(c.toString())+"]",l=s(c);let u=i;for(let e=0;e<l.a;e++)u+=r;const p=Math.max(1,l.b)-1;for(let e=0;e<p;e++)u+=n;for(let e=0;e<l.c;e++)u+=a;const d=e().astSync(u).nodes[0].nodes;for(let e=d.length-1;e>=0;e--)o.prepend(d[e])});const u=l.toString();return u!==t?".js-has-pseudo "+u:t});l.join(",")!==c.selectors.join(",")&&(t.add(c),c.cloneBefore({selectors:l}),o.preserve||c.remove())}}}}};function isWithinSupportCheck(e){let t=e.parent;for(;t;){if("atrule"===t.type&&isGuardedByAtSupportsFromAtRuleParams(t.params))return!0;t=t.parent}return!1}creator.postcss=!0;export{creator as default};
1
+ import e from"postcss-selector-parser";import t from"postcss-value-parser";import{selectorSpecificity as s}from"@csstools/selector-specificity";function encodeCSS(e){if(""===e)return"";let t,s="";for(let o=0;o<e.length;o++)t=e.charCodeAt(o).toString(36),s+=0===o?t:"-"+t;return"csstools-has-"+s}function isGuardedByAtSupportsFromAtRuleParams(e){if(!e.toLowerCase().includes(":has("))return!1;let s=!1;try{const o=new Set;t(e).walk(e=>{if("function"===e.type&&"selector"===e.value.toLowerCase())return o.add(t.stringify(e.nodes)),!1}),o.forEach(e=>{selectorContainsHasPseudo(e)&&(s=!0)})}catch{}return s}function selectorContainsHasPseudo(t){if(!t.toLowerCase().includes(":has("))return!1;let s=!1;try{e().astSync(t).walk(e=>{if("pseudo"===e.type&&":has"===e.value.toLowerCase()&&e.nodes&&e.nodes.length>0)return s=!0,!1})}catch{}return s}const creator=t=>{const o={preserve:!0,specificityMatchingName:"does-not-exist",...t||{}},r=":not(#"+o.specificityMatchingName+")",n=":not(."+o.specificityMatchingName+")",a=":not("+o.specificityMatchingName+")";return{postcssPlugin:"css-has-pseudo",prepare(){const t=new WeakSet;return{postcssPlugin:"css-has-pseudo",RuleExit(c,{result:i}){if(t.has(c))return;if(!c.selector.toLowerCase().includes(":has(")||isWithinSupportCheck(c))return;const l=c.selectors.map(t=>{if(!t.toLowerCase().includes(":has("))return t;let l;try{l=e().astSync(t)}catch(e){return c.warn(i,`Failed to parse selector : "${t}" with message: "${e instanceof Error?e.message:e}"`),t}if(void 0===l)return t;l.walkPseudos(t=>{let s=t.parent,r=!1;for(;s;)e.isPseudoClass(s)&&":has"===s.value.toLowerCase()&&(r=!0),s=s.parent;r&&(":visited"===t.value.toLowerCase()&&t.replaceWith(e.className({value:o.specificityMatchingName})),":any-link"===t.value.toLowerCase()&&(t.value=":link"))}),l.walkPseudos(t=>{if(":has"!==t.value.toLowerCase()||!t.nodes)return;const o=t.parent;if(!o)return;const c=e.selector({value:"",nodes:[]});{let t=o.nodes.length;e:for(let s=0;s<o.nodes.length;s++){const r=o.nodes[s];if(e.isPseudoElement(r))for(let e=s-1;e>=0;e--)if("combinator"!==o.nodes[s].type&&"comment"!==o.nodes[s].type){t=e+1;break e}}o.nodes.slice(0,t).forEach(e=>{e.remove(),"selector"===e.type?e.nodes.forEach(e=>{delete e.parent,c.append(e)}):(delete e.parent,c.append(e))})}const i="["+encodeCSS(c.toString())+"]",l=s(c);let u=i;for(let e=0;e<l.a;e++)u+=r;const p=Math.max(1,l.b)-1;for(let e=0;e<p;e++)u+=n;for(let e=0;e<l.c;e++)u+=a;const d=e().astSync(u).nodes[0].nodes;for(let e=d.length-1;e>=0;e--)o.prepend(d[e])});const u=l.toString();return u!==t?".js-has-pseudo "+u:t});l.join(",")!==c.selectors.join(",")&&(t.add(c),c.cloneBefore({selectors:l}),o.preserve||c.remove())}}}}};function isWithinSupportCheck(e){let t=e.parent;for(;t;){if("atrule"===t.type&&isGuardedByAtSupportsFromAtRuleParams(t.params))return!0;t=t.parent}return!1}creator.postcss=!0;export{creator as default,creator as"module.exports"};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "css-has-pseudo",
3
3
  "description": "Style elements relative to other elements in CSS",
4
- "version": "7.0.3",
4
+ "version": "8.0.0",
5
5
  "contributors": [
6
6
  {
7
7
  "name": "Antonio Laguna",
@@ -29,20 +29,13 @@
29
29
  }
30
30
  ],
31
31
  "engines": {
32
- "node": ">=18"
32
+ "node": ">=20.19.0"
33
33
  },
34
34
  "type": "module",
35
- "main": "dist/index.cjs",
36
- "module": "dist/index.mjs",
37
35
  "exports": {
38
36
  ".": {
39
- "import": {
40
- "types": "./dist/index.d.ts",
41
- "default": "./dist/index.mjs"
42
- },
43
- "require": {
44
- "default": "./dist/index.cjs"
45
- }
37
+ "types": "./dist/index.d.ts",
38
+ "default": "./dist/index.mjs"
46
39
  },
47
40
  "./browser": {
48
41
  "import": "./dist/browser.mjs",
@@ -60,8 +53,8 @@
60
53
  "dist"
61
54
  ],
62
55
  "dependencies": {
63
- "@csstools/selector-specificity": "^5.0.0",
64
- "postcss-selector-parser": "^7.0.0",
56
+ "@csstools/selector-specificity": "^6.0.0",
57
+ "postcss-selector-parser": "^7.1.1",
65
58
  "postcss-value-parser": "^4.2.0"
66
59
  },
67
60
  "peerDependencies": {
package/dist/index.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";var e=require("postcss-selector-parser"),t=require("postcss-value-parser"),s=require("@csstools/selector-specificity");function encodeCSS(e){if(""===e)return"";let t,s="";for(let r=0;r<e.length;r++)t=e.charCodeAt(r).toString(36),s+=0===r?t:"-"+t;return"csstools-has-"+s}function isGuardedByAtSupportsFromAtRuleParams(e){if(!e.toLowerCase().includes(":has("))return!1;let s=!1;try{const r=new Set;t(e).walk(e=>{if("function"===e.type&&"selector"===e.value.toLowerCase())return r.add(t.stringify(e.nodes)),!1}),r.forEach(e=>{selectorContainsHasPseudo(e)&&(s=!0)})}catch{}return s}function selectorContainsHasPseudo(t){if(!t.toLowerCase().includes(":has("))return!1;let s=!1;try{e().astSync(t).walk(e=>{if("pseudo"===e.type&&":has"===e.value.toLowerCase()&&e.nodes&&e.nodes.length>0)return s=!0,!1})}catch{}return s}const creator=t=>{const r={preserve:!0,specificityMatchingName:"does-not-exist",...t||{}},o=":not(#"+r.specificityMatchingName+")",n=":not(."+r.specificityMatchingName+")",a=":not("+r.specificityMatchingName+")";return{postcssPlugin:"css-has-pseudo",prepare(){const t=new WeakSet;return{postcssPlugin:"css-has-pseudo",RuleExit(c,{result:i}){if(t.has(c))return;if(!c.selector.toLowerCase().includes(":has(")||isWithinSupportCheck(c))return;const l=c.selectors.map(t=>{if(!t.toLowerCase().includes(":has("))return t;let l;try{l=e().astSync(t)}catch(e){return c.warn(i,`Failed to parse selector : "${t}" with message: "${e instanceof Error?e.message:e}"`),t}if(void 0===l)return t;l.walkPseudos(t=>{let s=t.parent,o=!1;for(;s;)e.isPseudoClass(s)&&":has"===s.value.toLowerCase()&&(o=!0),s=s.parent;o&&(":visited"===t.value.toLowerCase()&&t.replaceWith(e.className({value:r.specificityMatchingName})),":any-link"===t.value.toLowerCase()&&(t.value=":link"))}),l.walkPseudos(t=>{if(":has"!==t.value.toLowerCase()||!t.nodes)return;const r=t.parent;if(!r)return;const c=e.selector({value:"",nodes:[]});{let t=r.nodes.length;e:for(let s=0;s<r.nodes.length;s++){const o=r.nodes[s];if(e.isPseudoElement(o))for(let e=s-1;e>=0;e--)if("combinator"!==r.nodes[s].type&&"comment"!==r.nodes[s].type){t=e+1;break e}}r.nodes.slice(0,t).forEach(e=>{e.remove(),"selector"===e.type?e.nodes.forEach(e=>{delete e.parent,c.append(e)}):(delete e.parent,c.append(e))})}const i="["+encodeCSS(c.toString())+"]",l=s.selectorSpecificity(c);let u=i;for(let e=0;e<l.a;e++)u+=o;const p=Math.max(1,l.b)-1;for(let e=0;e<p;e++)u+=n;for(let e=0;e<l.c;e++)u+=a;const d=e().astSync(u).nodes[0].nodes;for(let e=d.length-1;e>=0;e--)r.prepend(d[e])});const u=l.toString();return u!==t?".js-has-pseudo "+u:t});l.join(",")!==c.selectors.join(",")&&(t.add(c),c.cloneBefore({selectors:l}),r.preserve||c.remove())}}}}};function isWithinSupportCheck(e){let t=e.parent;for(;t;){if("atrule"===t.type&&isGuardedByAtSupportsFromAtRuleParams(t.params))return!0;t=t.parent}return!1}creator.postcss=!0,module.exports=creator;