This commit is contained in:
Iliyan Angelov
2025-09-14 23:24:25 +03:00
commit c67067a2a4
71311 changed files with 6800714 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
# Changes to PostCSS Custom Selectors
### 6.0.3 (June 4, 2022)
- Fixed: allow any valid ident in custom media (`@custom-selector :--🧑🏾‍🎤 .singer`)
### 6.0.2 (June 3, 2022)
- Fixed: prevent duplicate rules when custom selectors are not defined
- Fixed: selectors not resolving when using with other features like nesting
### 6.0.1 (June 3, 2022)
- Fixed: invalid whitespace (https://github.com/csstools/postcss-custom-selectors/pull/55)
### 6.0.0 (January 12, 2021)
- Added: Support for PostCSS v8
- Added: Support for Node v10+
- Fixed: importing from multiple sources (https://github.com/postcss/postcss-custom-selectors/pull/42)
### 5.1.2 (September 20, 2018)
- Fixed: Do not break on an empty `importFrom` object
### 5.1.1 (September 18, 2018)
- Fixed: Selectors like `.foo:--h1` become `h1.foo` instead of `.fooh1`
### 5.1.0 (September 12, 2018)
- Added: New `exportTo` function to specify where to export custom selectors
- Updated: `importFrom` option to support passing it a function
### 5.0.0 (September 7, 2018)
- Added: New `preserve` option to preserve custom selectors and rules using them
- Added: New `importFrom` option to specify where to import custom selectors
- Added: Support for PostCSS v7
- Added: Support for Node v6+
### 4.0.1 (May 15, 2017)
- Fixed: incorrect export
### 4.0.0 (May 12, 2017)
- Added: compatibility with postcss v6.x
### 3.0.0 (August 25, 2015)
- Removed: compatibility with postcss v4.x
- Added: compatibility with postcss v5.x
### 2.3.0 (July 14, 2015)
* Fixed: Nested/mixed selectors now works correctly
(https://github.com/postcss/postcss-custom-selectors/issues/19)
* Added: `transformMatches` option to limit transformation to :matches()
replacements.
### 2.2.0 (June 30, 2015)
* Fixed: No more useless warnings for undefined non custom selectors
(https://github.com/postcss/postcss-custom-selectors/issues/22)
* Changed: warnings now use PostCSS message API
### 2.1.1 (June 30, 2015)
* Fixed: the lineBreak option keeping the selectors indent
(https://github.com/postcss/postcss-custom-selectors/issues/18)
* Fixed: the tip of an undefined selector
(https://github.com/postcss/postcss-custom-selectors/issues/20)
### 2.1.0 (June 4, 2015)
* Changed: use PostCSS 4.1 plugin API
(https://github.com/postcss/postcss-custom-selectors/issues/13)
### 2.0.1 (June 3, 2015)
* Fixed: `(foo, bar)` conversion error exists in the selector
### 2.0.0 (May 29, 2015)
* Removed: no longer support `::` or `--` to defined a custom selectors,
you must use the syntax `:--` to define it.
(https://github.com/postcss/postcss-custom-selectors/issues/6)
* Fixed: two or more consecutive hyphens in selector don't output `undefined`
(https://github.com/postcss/postcss-custom-selectors/issues/14)
### 1.1.1 (April 6, 2015)
* Fixed: add support for multilines definition
### 1.1.0 (December 6, 2014)
* Added: "lineBreak" option
### 1.0.0 (December 6, 2014)
* First release

View File

@@ -0,0 +1,21 @@
# The MIT License (MIT)
Copyright © PostCSS
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,166 @@
# PostCSS Custom Selectors [<img src="https://postcss.github.io/postcss/logo.svg" alt="PostCSS Logo" width="90" height="90" align="right">][postcss]
[<img alt="npm version" src="https://img.shields.io/npm/v/postcss-custom-selectors.svg" height="20">][npm-url] [<img alt="CSS Standard Status" src="https://cssdb.org/images/badges/custom-selectors.svg" height="20">][css-url] [<img alt="Build Status" src="https://github.com/csstools/postcss-plugins/workflows/test/badge.svg" height="20">][cli-url] [<img alt="Discord" src="https://shields.io/badge/Discord-5865F2?logo=discord&logoColor=white">][discord]
[PostCSS Custom Selectors] lets you define `@custom-selector` in CSS following the [Custom Selectors Specification].
```pcss
@custom-selector :--heading h1, h2, h3;
article :--heading + p {
margin-top: 0;
}
/* becomes */
article h1 + p,article h2 + p,article h3 + p {
margin-top: 0;
}
```
## Usage
Add [PostCSS Custom Selectors] to your project:
```bash
npm install postcss postcss-custom-selectors --save-dev
```
Use it as a [PostCSS] plugin:
```js
const postcss = require('postcss');
const postcssCustomSelectors = require('postcss-custom-selectors');
postcss([
postcssCustomSelectors(/* pluginOptions */)
]).process(YOUR_CSS /*, processOptions */);
```
[PostCSS Custom Selectors] runs in all Node environments, with special
instructions for:
| [Node](INSTALL.md#node) | [PostCSS CLI](INSTALL.md#postcss-cli) | [Webpack](INSTALL.md#webpack) | [Create React App](INSTALL.md#create-react-app) | [Gulp](INSTALL.md#gulp) | [Grunt](INSTALL.md#grunt) |
| --- | --- | --- | --- | --- | --- |
## Options
### preserve
The `preserve` option determines whether the original notation
is preserved. By default, it is not preserved.
```js
postcssCustomSelectors({ preserve: true })
```
```pcss
@custom-selector :--heading h1, h2, h3;
article :--heading + p {
margin-top: 0;
}
/* becomes */
@custom-selector :--heading h1, h2, h3;
article h1 + p,article h2 + p,article h3 + p {
margin-top: 0;
}
article :--heading + p {
margin-top: 0;
}
```
### importFrom
The `importFrom` option specifies sources where custom selectors can be
imported from, which might be CSS, JS, and JSON files, functions, and directly
passed objects.
```js
postcssCustomSelectors({
importFrom: 'path/to/file.css' // => @custom-selector :--heading h1, h2, h3;
});
```
```pcss
article :--heading + p {
margin-top: 0;
}
/* becomes */
article h1 + p, article h2 + p, article h3 + p {}
```
Multiple sources can be passed into this option, and they will be parsed in the
order they are received. JavaScript files, JSON files, functions, and objects
will need to namespace custom selectors using the `customProperties` or
`custom-properties` key.
```js
postcssCustomSelectors({
importFrom: [
'path/to/file.css',
'and/then/this.js',
'and/then/that.json',
{
customSelectors: { ':--heading': 'h1, h2, h3' }
},
() => {
const customProperties = { ':--heading': 'h1, h2, h3' };
return { customProperties };
}
]
});
```
### exportTo
The `exportTo` option specifies destinations where custom selectors can be
exported to, which might be CSS, JS, and JSON files, functions, and directly
passed objects.
```js
postcssCustomSelectors({
exportTo: 'path/to/file.css' // @custom-selector :--heading h1, h2, h3;
});
```
Multiple destinations can be passed into this option, and they will be parsed
in the order they are received. JavaScript files, JSON files, and objects will
need to namespace custom selectors using the `customProperties` or
`custom-properties` key.
```js
const cachedObject = { customSelectors: {} };
postcssCustomSelectors({
exportTo: [
'path/to/file.css', // @custom-selector :--heading h1, h2, h3;
'and/then/this.js', // module.exports = { customSelectors: { ':--heading': 'h1, h2, h3' } }
'and/then/this.mjs', // export const customSelectors = { ':--heading': 'h1, h2, h3' } }
'and/then/that.json', // { "custom-selectors": { ":--heading": "h1, h2, h3" } }
cachedObject,
customProperties => {
customProperties // { ':--heading': 'h1, h2, h3' }
}
]
});
```
[cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test
[css-url]: https://cssdb.org/#custom-selectors
[discord]: https://discord.gg/bUadyRwkJS
[npm-url]: https://www.npmjs.com/package/postcss-custom-selectors
[Gulp PostCSS]: https://github.com/postcss/gulp-postcss
[Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss
[PostCSS]: https://github.com/postcss/postcss
[PostCSS Loader]: https://github.com/postcss/postcss-loader
[PostCSS Custom Selectors]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-custom-selectors
[Custom Selectors Specification]: https://drafts.csswg.org/css-extensions/#custom-selectors

View File

@@ -0,0 +1 @@
"use strict";var e=require("postcss-selector-parser"),t=require("fs"),s=require("path"),n=require("postcss");function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function c(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(s){if("default"!==s){var n=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,n.get?n:{enumerable:!0,get:function(){return e[s]}})}})),t.default=e,Object.freeze(t)}var o=r(e),a=r(t),i=r(s),u=r(n),l=(e,t)=>{const s={};return e.nodes.slice().forEach((e=>{var n,r,c;if("atrule"!==e.type||"custom-selector"!==e.name)return;if(!e.params||!e.params.includes(":--"))return;const a=e.params.trim(),i=o.default().astSync(a),u=null==i||null==(n=i.nodes)||null==(r=n[0])||null==(c=r.nodes)?void 0:c[0];if(!u||"pseudo"!==u.type||!u.value.startsWith(":--"))return;const l=u.toString();s[l]=o.default().astSync(a.slice(l.length).trim()),Object(t).preserve||e.remove()})),s};function f(e,t){let s=e.nodes.length-1;for(;s>=0;){const n=p(e.nodes[s],t);n.length&&e.nodes.splice(s,1,...n),--s}return e}function p(e,t){const s=[];for(const n in e.nodes){const{value:r,nodes:c}=e.nodes[n];if(r in t){for(const c of t[r].nodes){const r=e.clone(),o=c.clone().nodes;r.nodes.splice(n,1,...o.map(((t,s)=>("selector"===t.type&&(t.spaces={...e.nodes[s].spaces}),0===s&&t.spaces&&(t.spaces.before=""),s===o.length-1&&t.spaces&&(t.spaces.after=""),t))));const a=p(r,t);b(r.nodes,Number(n)),a.length?s.push(...a):s.push(r)}return s}c&&c.length&&f(e.nodes[n],t)}return s}const d=/^(tag|universal)$/,m=/^(class|id|pseudo|tag|universal)$/,j=e=>m.test(Object(e).type),b=(e,t)=>{if(t&&(s=e[t],d.test(Object(s).type))&&j(e[t-1])){let s=t-1;for(;s&&j(e[s]);)--s;if(s<t){const n=e.splice(t,1)[0];e.splice(s,0,n),e[s].spaces.before=e[s+1].spaces.before,e[s+1].spaces.before="",e[t]&&(e[t].spaces.after=e[s].spaces.after,e[s].spaces.after="")}}var s};function y(e){return l(e)}function O(e){const t=Object.assign({},Object(e).customSelectors||Object(e)["custom-selectors"]);for(const e in t)t[e]=o.default().astSync(t[e]);return t}function g(e){return e.map((e=>{if(e instanceof Promise)return e;if(e instanceof Function)return e();const t=e===Object(e)?e:{from:String(e)};if(Object(t).customSelectors||Object(t)["custom-selectors"])return t;const s=String(t.from||"");return{type:(t.type||i.default.extname(s).slice(1)).toLowerCase(),from:s}})).reduce((async(e,t)=>{const s=await e,{type:n,from:r}=await t;return"ast"===n?Object.assign(s,y(r)):"css"===n?Object.assign(s,await async function(e){const t=await w(i.default.resolve(e));return y(u.default.parse(t,{from:i.default.resolve(e)}))}(r)):"js"===n?Object.assign(s,await async function(e){var t;return O(await(t=i.default.resolve(e),Promise.resolve().then((function(){return c(require(t))}))))}(r)):"json"===n?Object.assign(s,await async function(e){return O(await v(i.default.resolve(e)))}(r)):Object.assign(s,O(await t))}),Promise.resolve({}))}const w=e=>new Promise(((t,s)=>{a.default.readFile(e,"utf8",((e,n)=>{e?s(e):t(n)}))})),v=async e=>JSON.parse(await w(e));function S(e,t){return Promise.all(t.map((async t=>{if(t instanceof Function)await t(h(e));else{const s=t===Object(t)?t:{to:String(t)},n=s.toJSON||h;if("customSelectors"in s)s.customSelectors=n(e);else if("custom-selectors"in s)s["custom-selectors"]=n(e);else{const t=String(s.to||""),r=(s.type||i.default.extname(s.to).slice(1)).toLowerCase(),c=n(e);"css"===r&&await async function(e,t){const s=`${Object.keys(t).reduce(((e,s)=>(e.push(`@custom-selector ${s} ${t[s]};`),e)),[]).join("\n")}\n`;await $(e,s)}(t,c),"js"===r&&await async function(e,t){const s=`module.exports = {\n\tcustomSelectors: {\n${Object.keys(t).reduce(((e,s)=>(e.push(`\t\t'${P(s)}': '${P(t[s])}'`),e)),[]).join(",\n")}\n\t}\n};\n`;await $(e,s)}(t,c),"json"===r&&await async function(e,t){const s=`${JSON.stringify({"custom-selectors":t},null,"\t")}\n`;await $(e,s)}(t,c),"mjs"===r&&await async function(e,t){const s=`export const customSelectors = {\n${Object.keys(t).reduce(((e,s)=>(e.push(`\t'${P(s)}': '${P(t[s])}'`),e)),[]).join(",\n")}\n};\n`;await $(e,s)}(t,c)}}})))}const h=e=>Object.keys(e).reduce(((t,s)=>(t[s]=String(e[s]),t)),{}),$=(e,t)=>new Promise(((s,n)=>{a.default.writeFile(e,t,(e=>{e?n(e):s()}))})),P=e=>e.replace(/\\([\s\S])|(')/g,"\\$1$2").replace(/\n/g,"\\n").replace(/\r/g,"\\r"),x=e=>{const t=Boolean(Object(e).preserve),s=[].concat(Object(e).importFrom||[]),n=[].concat(Object(e).exportTo||[]),r=g(s),c=Symbol("customSelectorHelper");return{postcssPlugin:"postcss-custom-selectors",Once:async(e,s)=>{s[c]=Object.assign(await r,l(e,{preserve:t})),await S(s[c],n)},Rule:(e,s)=>{e.selector.includes(":--")&&((e,t,s)=>{const n=o.default((e=>{f(e,t)})).processSync(e.selector);n!==e.selector&&(e.cloneBefore({selector:n}),s.preserve||e.remove())})(e,s[c],{preserve:t})}}};x.postcss=!0,module.exports=x;

View File

@@ -0,0 +1 @@
import e from"postcss-selector-parser";import s from"fs";import t from"path";import n from"postcss";var o=(s,t)=>{const n={};return s.nodes.slice().forEach((s=>{var o,c,r;if("atrule"!==s.type||"custom-selector"!==s.name)return;if(!s.params||!s.params.includes(":--"))return;const a=s.params.trim(),i=e().astSync(a),l=null==i||null==(o=i.nodes)||null==(c=o[0])||null==(r=c.nodes)?void 0:r[0];if(!l||"pseudo"!==l.type||!l.value.startsWith(":--"))return;const u=l.toString();n[u]=e().astSync(a.slice(u.length).trim()),Object(t).preserve||s.remove()})),n};function c(e,s){let t=e.nodes.length-1;for(;t>=0;){const n=r(e.nodes[t],s);n.length&&e.nodes.splice(t,1,...n),--t}return e}function r(e,s){const t=[];for(const n in e.nodes){const{value:o,nodes:a}=e.nodes[n];if(o in s){for(const c of s[o].nodes){const o=e.clone(),a=c.clone().nodes;o.nodes.splice(n,1,...a.map(((s,t)=>("selector"===s.type&&(s.spaces={...e.nodes[t].spaces}),0===t&&s.spaces&&(s.spaces.before=""),t===a.length-1&&s.spaces&&(s.spaces.after=""),s))));const i=r(o,s);u(o.nodes,Number(n)),i.length?t.push(...i):t.push(o)}return t}a&&a.length&&c(e.nodes[n],s)}return t}const a=/^(tag|universal)$/,i=/^(class|id|pseudo|tag|universal)$/,l=e=>i.test(Object(e).type),u=(e,s)=>{if(s&&(t=e[s],a.test(Object(t).type))&&l(e[s-1])){let t=s-1;for(;t&&l(e[t]);)--t;if(t<s){const n=e.splice(s,1)[0];e.splice(t,0,n),e[t].spaces.before=e[t+1].spaces.before,e[t+1].spaces.before="",e[s]&&(e[s].spaces.after=e[t].spaces.after,e[t].spaces.after="")}}var t};function p(e){return o(e)}function f(s){const t=Object.assign({},Object(s).customSelectors||Object(s)["custom-selectors"]);for(const s in t)t[s]=e().astSync(t[s]);return t}function m(e){return e.map((e=>{if(e instanceof Promise)return e;if(e instanceof Function)return e();const s=e===Object(e)?e:{from:String(e)};if(Object(s).customSelectors||Object(s)["custom-selectors"])return s;const n=String(s.from||"");return{type:(s.type||t.extname(n).slice(1)).toLowerCase(),from:n}})).reduce((async(e,s)=>{const o=await e,{type:c,from:r}=await s;return"ast"===c?Object.assign(o,p(r)):"css"===c?Object.assign(o,await async function(e){const s=await j(t.resolve(e));return p(n.parse(s,{from:t.resolve(e)}))}(r)):"js"===c?Object.assign(o,await async function(e){return f(await import(t.resolve(e)))}(r)):"json"===c?Object.assign(o,await async function(e){return f(await y(t.resolve(e)))}(r)):Object.assign(o,f(await s))}),Promise.resolve({}))}const j=e=>new Promise(((t,n)=>{s.readFile(e,"utf8",((e,s)=>{e?n(e):t(s)}))})),y=async e=>JSON.parse(await j(e));function b(e,s){return Promise.all(s.map((async s=>{if(s instanceof Function)await s(d(e));else{const n=s===Object(s)?s:{to:String(s)},o=n.toJSON||d;if("customSelectors"in n)n.customSelectors=o(e);else if("custom-selectors"in n)n["custom-selectors"]=o(e);else{const s=String(n.to||""),c=(n.type||t.extname(n.to).slice(1)).toLowerCase(),r=o(e);"css"===c&&await async function(e,s){const t=`${Object.keys(s).reduce(((e,t)=>(e.push(`@custom-selector ${t} ${s[t]};`),e)),[]).join("\n")}\n`;await O(e,t)}(s,r),"js"===c&&await async function(e,s){const t=`module.exports = {\n\tcustomSelectors: {\n${Object.keys(s).reduce(((e,t)=>(e.push(`\t\t'${g(t)}': '${g(s[t])}'`),e)),[]).join(",\n")}\n\t}\n};\n`;await O(e,t)}(s,r),"json"===c&&await async function(e,s){const t=`${JSON.stringify({"custom-selectors":s},null,"\t")}\n`;await O(e,t)}(s,r),"mjs"===c&&await async function(e,s){const t=`export const customSelectors = {\n${Object.keys(s).reduce(((e,t)=>(e.push(`\t'${g(t)}': '${g(s[t])}'`),e)),[]).join(",\n")}\n};\n`;await O(e,t)}(s,r)}}})))}const d=e=>Object.keys(e).reduce(((s,t)=>(s[t]=String(e[t]),s)),{}),O=(e,t)=>new Promise(((n,o)=>{s.writeFile(e,t,(e=>{e?o(e):n()}))})),g=e=>e.replace(/\\([\s\S])|(')/g,"\\$1$2").replace(/\n/g,"\\n").replace(/\r/g,"\\r"),w=s=>{const t=Boolean(Object(s).preserve),n=[].concat(Object(s).importFrom||[]),r=[].concat(Object(s).exportTo||[]),a=m(n),i=Symbol("customSelectorHelper");return{postcssPlugin:"postcss-custom-selectors",Once:async(e,s)=>{s[i]=Object.assign(await a,o(e,{preserve:t})),await b(s[i],r)},Rule:(s,n)=>{s.selector.includes(":--")&&((s,t,n)=>{const o=e((e=>{c(e,t)})).processSync(s.selector);o!==s.selector&&(s.cloneBefore({selector:o}),n.preserve||s.remove())})(s,n[i],{preserve:t})}}};w.postcss=!0;export{w as default};

View File

@@ -0,0 +1,98 @@
{
"name": "postcss-custom-selectors",
"description": "Use Custom Selectors in CSS",
"version": "6.0.3",
"contributors": [
{
"name": "Antonio Laguna",
"email": "antonio@laguna.es",
"url": "https://antonio.laguna.es"
},
{
"name": "Romain Menke",
"email": "romainmenke@gmail.com"
},
{
"name": "Jonathan Neal",
"email": "jonathantneal@hotmail.com"
},
{
"name": "Maxime Thirouin"
},
{
"name": "yisi"
}
],
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/csstools"
},
"engines": {
"node": "^12 || ^14 || >=16"
},
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"default": "./dist/index.mjs"
}
},
"files": [
"CHANGELOG.md",
"LICENSE.md",
"README.md",
"dist"
],
"dependencies": {
"postcss-selector-parser": "^6.0.4"
},
"peerDependencies": {
"postcss": "^8.3"
},
"scripts": {
"build": "rollup -c ../../rollup/default.js",
"clean": "node -e \"fs.rmSync('./dist', { recursive: true, force: true });\"",
"docs": "node ../../.github/bin/generate-docs/install.mjs && node ../../.github/bin/generate-docs/readme.mjs",
"lint": "npm run lint:eslint && npm run lint:package-json",
"lint:eslint": "eslint ./src --ext .js --ext .ts --ext .mjs --no-error-on-unmatched-pattern",
"lint:package-json": "node ../../.github/bin/format-package-json.mjs",
"prepublishOnly": "npm run clean && npm run build && npm run test",
"test": "node .tape.cjs && node .tape.mjs && npm run test:exports",
"test:exports": "node ./test/_import.mjs && node ./test/_require.cjs",
"test:rewrite-expects": "REWRITE_EXPECTS=true node .tape.mjs && REWRITE_EXPECTS=true node .tape.cjs"
},
"homepage": "https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-custom-selectors#readme",
"repository": {
"type": "git",
"url": "https://github.com/csstools/postcss-plugins.git",
"directory": "plugins/postcss-custom-selectors"
},
"bugs": "https://github.com/csstools/postcss-plugins/issues",
"keywords": [
"at-rule",
"atrule",
"css",
"csswg",
"custom",
"declarative",
"extensions",
"postcss",
"postcss-plugin",
"rule",
"selectors",
"specification",
"w3c"
],
"csstools": {
"cssdbId": "custom-selectors",
"exportName": "postcssCustomSelectors",
"humanReadableName": "PostCSS Custom Selectors",
"specUrl": "https://drafts.csswg.org/css-extensions/#custom-selectors"
},
"volta": {
"extends": "../../package.json"
}
}