diff --git a/.github/ISSUE_TEMPLATE/css-issue.yml b/.github/ISSUE_TEMPLATE/css-issue.yml
index 96dcbbab85..b6f4ba6c96 100644
--- a/.github/ISSUE_TEMPLATE/css-issue.yml
+++ b/.github/ISSUE_TEMPLATE/css-issue.yml
@@ -110,8 +110,8 @@ body:
- PostCSS Logical Overscroll Behavior
- PostCSS Logical Resize
- PostCSS Logical Viewport Units
- - PostCSS Media Queries Aspect-Ratio Number Values
- PostCSS Media MinMax
+ - PostCSS Media Queries Aspect-Ratio Number Values
- PostCSS Minify
- PostCSS Nested Calc
- PostCSS Nesting
@@ -121,18 +121,20 @@ body:
- PostCSS Place
- PostCSS Position Area Property
- PostCSS Progressive Custom Properties
+ - PostCSS Property Rule Prelude List
- PostCSS Pseudo Class Any Link
- PostCSS Random Function
- PostCSS Rebase URL
- - PostCSS Rewrite URL
- PostCSS Rebeccapurple
- PostCSS Relative Color Syntax
- PostCSS Replace Overflow Wrap
+ - PostCSS Rewrite URL
- PostCSS Scope Pseudo Class
- PostCSS Selector Not
- PostCSS Sign Functions
- PostCSS Slow Plugins
- PostCSS Stepped Value Functions
+ - PostCSS Syntax Descriptor Syntax Production
- PostCSS System Ui Font Family
- PostCSS Text Decoration Shorthand
- PostCSS Trigonometric Functions
diff --git a/.github/ISSUE_TEMPLATE/plugin-issue.yml b/.github/ISSUE_TEMPLATE/plugin-issue.yml
index fdb488208d..70d7be639d 100644
--- a/.github/ISSUE_TEMPLATE/plugin-issue.yml
+++ b/.github/ISSUE_TEMPLATE/plugin-issue.yml
@@ -107,8 +107,8 @@ body:
- PostCSS Logical Overscroll Behavior
- PostCSS Logical Resize
- PostCSS Logical Viewport Units
- - PostCSS Media Queries Aspect-Ratio Number Values
- PostCSS Media MinMax
+ - PostCSS Media Queries Aspect-Ratio Number Values
- PostCSS Minify
- PostCSS Nested Calc
- PostCSS Nesting
@@ -118,18 +118,20 @@ body:
- PostCSS Place
- PostCSS Position Area Property
- PostCSS Progressive Custom Properties
+ - PostCSS Property Rule Prelude List
- PostCSS Pseudo Class Any Link
- PostCSS Random Function
- PostCSS Rebase URL
- - PostCSS Rewrite URL
- PostCSS Rebeccapurple
- PostCSS Relative Color Syntax
- PostCSS Replace Overflow Wrap
+ - PostCSS Rewrite URL
- PostCSS Scope Pseudo Class
- PostCSS Selector Not
- PostCSS Sign Functions
- PostCSS Slow Plugins
- PostCSS Stepped Value Functions
+ - PostCSS Syntax Descriptor Syntax Production
- PostCSS System Ui Font Family
- PostCSS Text Decoration Shorthand
- PostCSS Trigonometric Functions
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 98cb932c46..7219806efb 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -407,6 +407,12 @@
- plugins/postcss-progressive-custom-properties/**
- experimental/postcss-progressive-custom-properties/**
+"plugins/postcss-property-rule-prelude-list":
+ - changed-files:
+ - any-glob-to-any-file:
+ - plugins/postcss-property-rule-prelude-list/**
+ - experimental/postcss-property-rule-prelude-list/**
+
"plugins/postcss-pseudo-class-any-link":
- changed-files:
- any-glob-to-any-file:
@@ -479,6 +485,12 @@
- plugins/postcss-stepped-value-functions/**
- experimental/postcss-stepped-value-functions/**
+"plugins/syntax-descriptor-syntax-production":
+ - changed-files:
+ - any-glob-to-any-file:
+ - plugins/postcss-syntax-descriptor-syntax-production/**
+ - experimental/postcss-syntax-descriptor-syntax-production/**
+
"plugins/postcss-text-decoration-shorthand":
- changed-files:
- any-glob-to-any-file:
diff --git a/package-lock.json b/package-lock.json
index 21f11804ef..abcc53f4df 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2096,6 +2096,10 @@
"resolved": "plugins/postcss-progressive-custom-properties",
"link": true
},
+ "node_modules/@csstools/postcss-property-rule-prelude-list": {
+ "resolved": "plugins/postcss-property-rule-prelude-list",
+ "link": true
+ },
"node_modules/@csstools/postcss-random-function": {
"resolved": "plugins/postcss-random-function",
"link": true
@@ -2128,6 +2132,10 @@
"resolved": "plugins/postcss-stepped-value-functions",
"link": true
},
+ "node_modules/@csstools/postcss-syntax-descriptor-syntax-production": {
+ "resolved": "plugins/postcss-syntax-descriptor-syntax-production",
+ "link": true
+ },
"node_modules/@csstools/postcss-system-ui-font-family": {
"resolved": "plugins/postcss-system-ui-font-family",
"link": true
@@ -11769,6 +11777,34 @@
"postcss": "^8.4"
}
},
+ "plugins/postcss-property-rule-prelude-list": {
+ "name": "@csstools/postcss-property-rule-prelude-list",
+ "version": "0.0.0",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT-0",
+ "dependencies": {
+ "@csstools/css-parser-algorithms": "^3.0.5",
+ "@csstools/css-tokenizer": "^3.0.4"
+ },
+ "devDependencies": {
+ "@csstools/postcss-tape": "*"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4"
+ }
+ },
"plugins/postcss-pseudo-class-any-link": {
"version": "10.0.1",
"funding": [
@@ -12047,6 +12083,33 @@
"postcss": "^8.4"
}
},
+ "plugins/postcss-syntax-descriptor-syntax-production": {
+ "name": "@csstools/postcss-syntax-descriptor-syntax-production",
+ "version": "0.0.0",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT-0",
+ "dependencies": {
+ "@csstools/css-tokenizer": "^3.0.4"
+ },
+ "devDependencies": {
+ "@csstools/postcss-tape": "*"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4"
+ }
+ },
"plugins/postcss-system-ui-font-family": {
"name": "@csstools/postcss-system-ui-font-family",
"version": "1.0.0",
diff --git a/plugins/postcss-property-rule-prelude-list/.gitignore b/plugins/postcss-property-rule-prelude-list/.gitignore
new file mode 100644
index 0000000000..e5b28db4ad
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/.gitignore
@@ -0,0 +1,6 @@
+node_modules
+package-lock.json
+yarn.lock
+*.result.css
+*.result.css.map
+*.result.html
diff --git a/plugins/postcss-property-rule-prelude-list/.nvmrc b/plugins/postcss-property-rule-prelude-list/.nvmrc
new file mode 100644
index 0000000000..28d6ff1c82
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/.nvmrc
@@ -0,0 +1 @@
+v25.1.0
diff --git a/plugins/postcss-property-rule-prelude-list/CHANGELOG.md b/plugins/postcss-property-rule-prelude-list/CHANGELOG.md
new file mode 100644
index 0000000000..ff38c3b481
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changes to PostCSS Property Rule Prelude List
+
+### Unreleased (major)
+
+- Initial version
diff --git a/plugins/postcss-property-rule-prelude-list/INSTALL.md b/plugins/postcss-property-rule-prelude-list/INSTALL.md
new file mode 100644
index 0000000000..2bd343587a
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/INSTALL.md
@@ -0,0 +1,235 @@
+# Installing PostCSS Property Rule Prelude List
+
+[PostCSS Property Rule Prelude List] runs in all Node environments, with special instructions for:
+
+- [Node](#node)
+- [PostCSS CLI](#postcss-cli)
+- [PostCSS Load Config](#postcss-load-config)
+- [Webpack](#webpack)
+- [Next.js](#nextjs)
+- [Gulp](#gulp)
+- [Grunt](#grunt)
+
+
+
+## Node
+
+Add [PostCSS Property Rule Prelude List] to your project:
+
+```bash
+npm install postcss @csstools/postcss-property-rule-prelude-list --save-dev
+```
+
+Use it as a [PostCSS] plugin:
+
+```js
+// commonjs
+const postcss = require('postcss');
+const postcssPropertyRulePreludeList = require('@csstools/postcss-property-rule-prelude-list');
+
+postcss([
+ postcssPropertyRulePreludeList(/* pluginOptions */)
+]).process(YOUR_CSS /*, processOptions */);
+```
+
+```js
+// esm
+import postcss from 'postcss';
+import postcssPropertyRulePreludeList from '@csstools/postcss-property-rule-prelude-list';
+
+postcss([
+ postcssPropertyRulePreludeList(/* pluginOptions */)
+]).process(YOUR_CSS /*, processOptions */);
+```
+
+## PostCSS CLI
+
+Add [PostCSS CLI] to your project:
+
+```bash
+npm install postcss-cli @csstools/postcss-property-rule-prelude-list --save-dev
+```
+
+Use [PostCSS Property Rule Prelude List] in your `postcss.config.js` configuration file:
+
+```js
+const postcssPropertyRulePreludeList = require('@csstools/postcss-property-rule-prelude-list');
+
+module.exports = {
+ plugins: [
+ postcssPropertyRulePreludeList(/* pluginOptions */)
+ ]
+}
+```
+
+## PostCSS Load Config
+
+If your framework/CLI supports [`postcss-load-config`](https://github.com/postcss/postcss-load-config).
+
+```bash
+npm install @csstools/postcss-property-rule-prelude-list --save-dev
+```
+
+`package.json`:
+
+```json
+{
+ "postcss": {
+ "plugins": {
+ "@csstools/postcss-property-rule-prelude-list": {}
+ }
+ }
+}
+```
+
+`.postcssrc.json`:
+
+```json
+{
+ "plugins": {
+ "@csstools/postcss-property-rule-prelude-list": {}
+ }
+}
+```
+
+_See the [README of `postcss-load-config`](https://github.com/postcss/postcss-load-config#usage) for more usage options._
+
+## Webpack
+
+_Webpack version 5_
+
+Add [PostCSS Loader] to your project:
+
+```bash
+npm install postcss-loader @csstools/postcss-property-rule-prelude-list --save-dev
+```
+
+Use [PostCSS Property Rule Prelude List] in your Webpack configuration:
+
+```js
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: [
+ "style-loader",
+ {
+ loader: "css-loader",
+ options: { importLoaders: 1 },
+ },
+ {
+ loader: "postcss-loader",
+ options: {
+ postcssOptions: {
+ plugins: [
+ // Other plugins,
+ [
+ "@csstools/postcss-property-rule-prelude-list",
+ {
+ // Options
+ },
+ ],
+ ],
+ },
+ },
+ },
+ ],
+ },
+ ],
+ },
+};
+```
+
+## Next.js
+
+Read the instructions on how to [customize the PostCSS configuration in Next.js](https://nextjs.org/docs/advanced-features/customizing-postcss-config)
+
+```bash
+npm install @csstools/postcss-property-rule-prelude-list --save-dev
+```
+
+Use [PostCSS Property Rule Prelude List] in your `postcss.config.json` file:
+
+```json
+{
+ "plugins": [
+ "@csstools/postcss-property-rule-prelude-list"
+ ]
+}
+```
+
+```json5
+{
+ "plugins": [
+ [
+ "@csstools/postcss-property-rule-prelude-list",
+ {
+ // Optionally add plugin options
+ }
+ ]
+ ]
+}
+```
+
+## Gulp
+
+Add [Gulp PostCSS] to your project:
+
+```bash
+npm install gulp-postcss @csstools/postcss-property-rule-prelude-list --save-dev
+```
+
+Use [PostCSS Property Rule Prelude List] in your Gulpfile:
+
+```js
+const postcss = require('gulp-postcss');
+const postcssPropertyRulePreludeList = require('@csstools/postcss-property-rule-prelude-list');
+
+gulp.task('css', function () {
+ var plugins = [
+ postcssPropertyRulePreludeList(/* pluginOptions */)
+ ];
+
+ return gulp.src('./src/*.css')
+ .pipe(postcss(plugins))
+ .pipe(gulp.dest('.'));
+});
+```
+
+## Grunt
+
+Add [Grunt PostCSS] to your project:
+
+```bash
+npm install grunt-postcss @csstools/postcss-property-rule-prelude-list --save-dev
+```
+
+Use [PostCSS Property Rule Prelude List] in your Gruntfile:
+
+```js
+const postcssPropertyRulePreludeList = require('@csstools/postcss-property-rule-prelude-list');
+
+grunt.loadNpmTasks('grunt-postcss');
+
+grunt.initConfig({
+ postcss: {
+ options: {
+ processors: [
+ postcssPropertyRulePreludeList(/* pluginOptions */)
+ ]
+ },
+ dist: {
+ src: '*.css'
+ }
+ }
+});
+```
+
+[Gulp PostCSS]: https://github.com/postcss/gulp-postcss
+[Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss
+[PostCSS]: https://github.com/postcss/postcss
+[PostCSS CLI]: https://github.com/postcss/postcss-cli
+[PostCSS Loader]: https://github.com/postcss/postcss-loader
+[PostCSS Property Rule Prelude List]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-property-rule-prelude-list
+[Next.js]: https://nextjs.org
diff --git a/plugins/postcss-property-rule-prelude-list/LICENSE.md b/plugins/postcss-property-rule-prelude-list/LICENSE.md
new file mode 100644
index 0000000000..e8ae93b9f9
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/LICENSE.md
@@ -0,0 +1,18 @@
+MIT No Attribution (MIT-0)
+
+Copyright © CSSTools Contributors
+
+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.
+
+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.
diff --git a/plugins/postcss-property-rule-prelude-list/README.md b/plugins/postcss-property-rule-prelude-list/README.md
new file mode 100644
index 0000000000..36614d645c
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/README.md
@@ -0,0 +1,69 @@
+# PostCSS Property Rule Prelude List [
][PostCSS]
+
+[
][npm-url] [
][cli-url] [
][discord]
[
][css-url] [
][css-url]
+
+```bash
+npm install @csstools/postcss-property-rule-prelude-list --save-dev
+```
+
+[PostCSS Property Rule Prelude List] lets you declare a list of custom properties in a single `@property` rule following the [CSS Specification].
+
+```css
+@property --color-a, --color-b {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+/* becomes */
+
+@property --color-a {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+@property --color-b {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+```
+
+## Usage
+
+Add [PostCSS Property Rule Prelude List] to your project:
+
+```bash
+npm install postcss @csstools/postcss-property-rule-prelude-list --save-dev
+```
+
+Use it as a [PostCSS] plugin:
+
+```js
+const postcss = require('postcss');
+const postcssPropertyRulePreludeList = require('@csstools/postcss-property-rule-prelude-list');
+
+postcss([
+ postcssPropertyRulePreludeList(/* pluginOptions */)
+]).process(YOUR_CSS /*, processOptions */);
+```
+
+[PostCSS Property Rule Prelude List] runs in all Node environments, with special
+instructions for:
+
+- [Node](INSTALL.md#node)
+- [PostCSS CLI](INSTALL.md#postcss-cli)
+- [PostCSS Load Config](INSTALL.md#postcss-load-config)
+- [Webpack](INSTALL.md#webpack)
+- [Next.js](INSTALL.md#nextjs)
+- [Gulp](INSTALL.md#gulp)
+- [Grunt](INSTALL.md#grunt)
+
+[cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test
+[css-url]: https://cssdb.org/#property-rule-prelude-list
+[discord]: https://discord.gg/bUadyRwkJS
+[npm-url]: https://www.npmjs.com/package/@csstools/postcss-property-rule-prelude-list
+
+[PostCSS]: https://github.com/postcss/postcss
+[PostCSS Property Rule Prelude List]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-property-rule-prelude-list
+[CSS Specification]: https://github.com/w3c/csswg-drafts/issues/7523#issuecomment-3683970305
diff --git a/plugins/postcss-property-rule-prelude-list/api-extractor.json b/plugins/postcss-property-rule-prelude-list/api-extractor.json
new file mode 100644
index 0000000000..42058be517
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/api-extractor.json
@@ -0,0 +1,4 @@
+{
+ "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
+ "extends": "../../api-extractor.json"
+}
diff --git a/plugins/postcss-property-rule-prelude-list/dist/index.cjs b/plugins/postcss-property-rule-prelude-list/dist/index.cjs
new file mode 100644
index 0000000000..64a2db2d78
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/dist/index.cjs
@@ -0,0 +1 @@
+"use strict";var s=require("@csstools/css-parser-algorithms"),e=require("@csstools/css-tokenizer");const r=/^property$/i,creator=()=>({postcssPlugin:"postcss-property-rule-prelude-list",AtRule(t){if(!r.test(t.name))return;if(!t.params.includes(","))return;const o=s.parseCommaSeparatedListOfComponentValues(e.tokenize({css:t.params}));o.length<2||(o.forEach(e=>{t.cloneBefore({params:s.stringify([e]).trim()})}),t.remove())}});creator.postcss=!0,module.exports=creator;
diff --git a/plugins/postcss-property-rule-prelude-list/dist/index.d.ts b/plugins/postcss-property-rule-prelude-list/dist/index.d.ts
new file mode 100644
index 0000000000..27d0f244b6
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/dist/index.d.ts
@@ -0,0 +1,9 @@
+import type { PluginCreator } from 'postcss';
+
+declare const creator: PluginCreator;
+export default creator;
+
+/** postcss-property-rule-prelude-list plugin options */
+export declare type pluginOptions = never;
+
+export { }
diff --git a/plugins/postcss-property-rule-prelude-list/dist/index.mjs b/plugins/postcss-property-rule-prelude-list/dist/index.mjs
new file mode 100644
index 0000000000..26a8de6c15
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/dist/index.mjs
@@ -0,0 +1 @@
+import{parseCommaSeparatedListOfComponentValues as s,stringify as r}from"@csstools/css-parser-algorithms";import{tokenize as t}from"@csstools/css-tokenizer";const e=/^property$/i,creator=()=>({postcssPlugin:"postcss-property-rule-prelude-list",AtRule(o){if(!e.test(o.name))return;if(!o.params.includes(","))return;const p=s(t({css:o.params}));p.length<2||(p.forEach(s=>{o.cloneBefore({params:r([s]).trim()})}),o.remove())}});creator.postcss=!0;export{creator as default};
diff --git a/plugins/postcss-property-rule-prelude-list/docs/README.md b/plugins/postcss-property-rule-prelude-list/docs/README.md
new file mode 100644
index 0000000000..eb262e2c2b
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/docs/README.md
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[] lets you declare a list of custom properties in a single `@property` rule following the [CSS Specification].
+
+```css
+
+
+/* becomes */
+
+
+```
+
+
+
+
+
+
+[CSS Specification]:
diff --git a/plugins/postcss-property-rule-prelude-list/package.json b/plugins/postcss-property-rule-prelude-list/package.json
new file mode 100644
index 0000000000..6aed94a503
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/package.json
@@ -0,0 +1,87 @@
+{
+ "name": "@csstools/postcss-property-rule-prelude-list",
+ "description": "Declare a list of custom properties in a single at-property rule",
+ "version": "0.0.0",
+ "contributors": [
+ {
+ "name": "Antonio Laguna",
+ "email": "antonio@laguna.es",
+ "url": "https://antonio.laguna.es"
+ },
+ {
+ "name": "Romain Menke",
+ "email": "romainmenke@gmail.com"
+ }
+ ],
+ "license": "MIT-0",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "engines": {
+ "node": ">=18"
+ },
+ "type": "module",
+ "main": "dist/index.cjs",
+ "module": "dist/index.mjs",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/index.mjs"
+ },
+ "require": {
+ "default": "./dist/index.cjs"
+ }
+ }
+ },
+ "files": [
+ "CHANGELOG.md",
+ "LICENSE.md",
+ "README.md",
+ "dist"
+ ],
+ "dependencies": {
+ "@csstools/css-parser-algorithms": "^3.0.5",
+ "@csstools/css-tokenizer": "^3.0.4"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4"
+ },
+ "devDependencies": {
+ "@csstools/postcss-tape": "*"
+ },
+ "scripts": {
+ "build": "rollup -c ../../rollup/default.mjs",
+ "docs": "node ../../.github/bin/generate-docs/install.mjs && node ../../.github/bin/generate-docs/readme.mjs",
+ "lint": "node ../../.github/bin/format-package-json.mjs",
+ "prepublishOnly": "npm run build && npm run test",
+ "test": "node --test",
+ "test:rewrite-expects": "REWRITE_EXPECTS=true node --test"
+ },
+ "homepage": "https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-property-rule-prelude-list#readme",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/csstools/postcss-plugins.git",
+ "directory": "plugins/postcss-property-rule-prelude-list"
+ },
+ "bugs": "https://github.com/csstools/postcss-plugins/issues",
+ "keywords": [
+ "postcss-plugin"
+ ],
+ "csstools": {
+ "cssdbId": "property-rule-prelude-list",
+ "exportName": "postcssPropertyRulePreludeList",
+ "humanReadableName": "PostCSS Property Rule Prelude List",
+ "specUrl": "https://github.com/w3c/csswg-drafts/issues/7523#issuecomment-3683970305"
+ },
+ "volta": {
+ "extends": "../../package.json"
+ }
+}
diff --git a/plugins/postcss-property-rule-prelude-list/src/index.ts b/plugins/postcss-property-rule-prelude-list/src/index.ts
new file mode 100644
index 0000000000..4ce1a3b87f
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/src/index.ts
@@ -0,0 +1,41 @@
+import { parseCommaSeparatedListOfComponentValues, stringify } from '@csstools/css-parser-algorithms';
+import { tokenize } from '@csstools/css-tokenizer';
+import type { PluginCreator } from 'postcss';
+
+/** postcss-property-rule-prelude-list plugin options */
+export type pluginOptions = never;
+
+const IS_AT_PROPERTY_REGEX = /^property$/i;
+
+const creator: PluginCreator = () => {
+
+ return {
+ postcssPlugin: 'postcss-property-rule-prelude-list',
+ AtRule(atRule): void {
+ if (!IS_AT_PROPERTY_REGEX.test(atRule.name)) {
+ return;
+ }
+
+ if (!atRule.params.includes(',')) {
+ return;
+ }
+
+ const list = parseCommaSeparatedListOfComponentValues(tokenize({ css: atRule.params }));
+ if (list.length < 2) {
+ return;
+ }
+
+ list.forEach((params) => {
+ atRule.cloneBefore({
+ params: stringify([params]).trim(),
+ });
+ })
+
+ atRule.remove();
+ },
+ };
+};
+
+creator.postcss = true;
+
+export default creator;
diff --git a/plugins/postcss-property-rule-prelude-list/test/_import.mjs b/plugins/postcss-property-rule-prelude-list/test/_import.mjs
new file mode 100644
index 0000000000..454b80a4d4
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/test/_import.mjs
@@ -0,0 +1,10 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+import plugin from '@csstools/postcss-property-rule-prelude-list';
+
+test('import', () => {
+ plugin();
+ assert.ok(plugin.postcss, 'should have "postcss flag"');
+ assert.equal(typeof plugin, 'function', 'should return a function');
+});
+
diff --git a/plugins/postcss-property-rule-prelude-list/test/_require.cjs b/plugins/postcss-property-rule-prelude-list/test/_require.cjs
new file mode 100644
index 0000000000..2af37a9006
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/test/_require.cjs
@@ -0,0 +1,9 @@
+const assert = require('node:assert/strict');
+const test = require('node:test');
+const plugin = require('@csstools/postcss-property-rule-prelude-list');
+
+test('require', () => {
+ plugin();
+ assert.ok(plugin.postcss, 'should have "postcss flag"');
+ assert.equal(typeof plugin, 'function', 'should return a function');
+});
diff --git a/plugins/postcss-property-rule-prelude-list/test/_tape.mjs b/plugins/postcss-property-rule-prelude-list/test/_tape.mjs
new file mode 100644
index 0000000000..60eb29bfee
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/test/_tape.mjs
@@ -0,0 +1,11 @@
+import { postcssTape } from '@csstools/postcss-tape';
+import plugin from '@csstools/postcss-property-rule-prelude-list';
+
+postcssTape(plugin)({
+ basic: {
+ message: 'supports basic usage',
+ },
+ 'examples/example': {
+ message: 'minimal example',
+ },
+});
diff --git a/plugins/postcss-property-rule-prelude-list/test/basic.css b/plugins/postcss-property-rule-prelude-list/test/basic.css
new file mode 100644
index 0000000000..37174ad9e9
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/test/basic.css
@@ -0,0 +1,23 @@
+@property --color-a, --color-b {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-c something, --color-d {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-e, --color-f, --color-g, --color-h {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-i something(a, b) {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
diff --git a/plugins/postcss-property-rule-prelude-list/test/basic.expect.css b/plugins/postcss-property-rule-prelude-list/test/basic.expect.css
new file mode 100644
index 0000000000..64f03c799d
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/test/basic.expect.css
@@ -0,0 +1,53 @@
+@property --color-a {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-b {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-c something {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-d {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-e {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-f {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-g {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-h {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+
+@property --color-i something(a, b) {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
diff --git a/plugins/postcss-property-rule-prelude-list/test/examples/example.css b/plugins/postcss-property-rule-prelude-list/test/examples/example.css
new file mode 100644
index 0000000000..92a6bb4491
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/test/examples/example.css
@@ -0,0 +1,5 @@
+@property --color-a, --color-b {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
diff --git a/plugins/postcss-property-rule-prelude-list/test/examples/example.expect.css b/plugins/postcss-property-rule-prelude-list/test/examples/example.expect.css
new file mode 100644
index 0000000000..492cd8616d
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/test/examples/example.expect.css
@@ -0,0 +1,10 @@
+@property --color-a {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
+@property --color-b {
+ inherits: true;
+ initial-value: black;
+ syntax: "";
+}
diff --git a/plugins/postcss-property-rule-prelude-list/tsconfig.json b/plugins/postcss-property-rule-prelude-list/tsconfig.json
new file mode 100644
index 0000000000..500af6d266
--- /dev/null
+++ b/plugins/postcss-property-rule-prelude-list/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "declarationDir": ".",
+ "strict": true
+ },
+ "include": ["./src/**/*"],
+ "exclude": ["dist"]
+}
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/.gitignore b/plugins/postcss-syntax-descriptor-syntax-production/.gitignore
new file mode 100644
index 0000000000..e5b28db4ad
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/.gitignore
@@ -0,0 +1,6 @@
+node_modules
+package-lock.json
+yarn.lock
+*.result.css
+*.result.css.map
+*.result.html
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/.nvmrc b/plugins/postcss-syntax-descriptor-syntax-production/.nvmrc
new file mode 100644
index 0000000000..28d6ff1c82
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/.nvmrc
@@ -0,0 +1 @@
+v25.1.0
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/CHANGELOG.md b/plugins/postcss-syntax-descriptor-syntax-production/CHANGELOG.md
new file mode 100644
index 0000000000..6e8575a65f
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changes to PostCSS Syntax Descriptor Syntax Production
+
+### Unreleased (major)
+
+- Initial version
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/INSTALL.md b/plugins/postcss-syntax-descriptor-syntax-production/INSTALL.md
new file mode 100644
index 0000000000..c490220326
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/INSTALL.md
@@ -0,0 +1,235 @@
+# Installing PostCSS Syntax Descriptor Syntax Production
+
+[PostCSS Syntax Descriptor Syntax Production] runs in all Node environments, with special instructions for:
+
+- [Node](#node)
+- [PostCSS CLI](#postcss-cli)
+- [PostCSS Load Config](#postcss-load-config)
+- [Webpack](#webpack)
+- [Next.js](#nextjs)
+- [Gulp](#gulp)
+- [Grunt](#grunt)
+
+
+
+## Node
+
+Add [PostCSS Syntax Descriptor Syntax Production] to your project:
+
+```bash
+npm install postcss @csstools/postcss-syntax-descriptor-syntax-production --save-dev
+```
+
+Use it as a [PostCSS] plugin:
+
+```js
+// commonjs
+const postcss = require('postcss');
+const postcssSyntaxDescriptorSyntaxProduction = require('@csstools/postcss-syntax-descriptor-syntax-production');
+
+postcss([
+ postcssSyntaxDescriptorSyntaxProduction(/* pluginOptions */)
+]).process(YOUR_CSS /*, processOptions */);
+```
+
+```js
+// esm
+import postcss from 'postcss';
+import postcssSyntaxDescriptorSyntaxProduction from '@csstools/postcss-syntax-descriptor-syntax-production';
+
+postcss([
+ postcssSyntaxDescriptorSyntaxProduction(/* pluginOptions */)
+]).process(YOUR_CSS /*, processOptions */);
+```
+
+## PostCSS CLI
+
+Add [PostCSS CLI] to your project:
+
+```bash
+npm install postcss-cli @csstools/postcss-syntax-descriptor-syntax-production --save-dev
+```
+
+Use [PostCSS Syntax Descriptor Syntax Production] in your `postcss.config.js` configuration file:
+
+```js
+const postcssSyntaxDescriptorSyntaxProduction = require('@csstools/postcss-syntax-descriptor-syntax-production');
+
+module.exports = {
+ plugins: [
+ postcssSyntaxDescriptorSyntaxProduction(/* pluginOptions */)
+ ]
+}
+```
+
+## PostCSS Load Config
+
+If your framework/CLI supports [`postcss-load-config`](https://github.com/postcss/postcss-load-config).
+
+```bash
+npm install @csstools/postcss-syntax-descriptor-syntax-production --save-dev
+```
+
+`package.json`:
+
+```json
+{
+ "postcss": {
+ "plugins": {
+ "@csstools/postcss-syntax-descriptor-syntax-production": {}
+ }
+ }
+}
+```
+
+`.postcssrc.json`:
+
+```json
+{
+ "plugins": {
+ "@csstools/postcss-syntax-descriptor-syntax-production": {}
+ }
+}
+```
+
+_See the [README of `postcss-load-config`](https://github.com/postcss/postcss-load-config#usage) for more usage options._
+
+## Webpack
+
+_Webpack version 5_
+
+Add [PostCSS Loader] to your project:
+
+```bash
+npm install postcss-loader @csstools/postcss-syntax-descriptor-syntax-production --save-dev
+```
+
+Use [PostCSS Syntax Descriptor Syntax Production] in your Webpack configuration:
+
+```js
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: [
+ "style-loader",
+ {
+ loader: "css-loader",
+ options: { importLoaders: 1 },
+ },
+ {
+ loader: "postcss-loader",
+ options: {
+ postcssOptions: {
+ plugins: [
+ // Other plugins,
+ [
+ "@csstools/postcss-syntax-descriptor-syntax-production",
+ {
+ // Options
+ },
+ ],
+ ],
+ },
+ },
+ },
+ ],
+ },
+ ],
+ },
+};
+```
+
+## Next.js
+
+Read the instructions on how to [customize the PostCSS configuration in Next.js](https://nextjs.org/docs/advanced-features/customizing-postcss-config)
+
+```bash
+npm install @csstools/postcss-syntax-descriptor-syntax-production --save-dev
+```
+
+Use [PostCSS Syntax Descriptor Syntax Production] in your `postcss.config.json` file:
+
+```json
+{
+ "plugins": [
+ "@csstools/postcss-syntax-descriptor-syntax-production"
+ ]
+}
+```
+
+```json5
+{
+ "plugins": [
+ [
+ "@csstools/postcss-syntax-descriptor-syntax-production",
+ {
+ // Optionally add plugin options
+ }
+ ]
+ ]
+}
+```
+
+## Gulp
+
+Add [Gulp PostCSS] to your project:
+
+```bash
+npm install gulp-postcss @csstools/postcss-syntax-descriptor-syntax-production --save-dev
+```
+
+Use [PostCSS Syntax Descriptor Syntax Production] in your Gulpfile:
+
+```js
+const postcss = require('gulp-postcss');
+const postcssSyntaxDescriptorSyntaxProduction = require('@csstools/postcss-syntax-descriptor-syntax-production');
+
+gulp.task('css', function () {
+ var plugins = [
+ postcssSyntaxDescriptorSyntaxProduction(/* pluginOptions */)
+ ];
+
+ return gulp.src('./src/*.css')
+ .pipe(postcss(plugins))
+ .pipe(gulp.dest('.'));
+});
+```
+
+## Grunt
+
+Add [Grunt PostCSS] to your project:
+
+```bash
+npm install grunt-postcss @csstools/postcss-syntax-descriptor-syntax-production --save-dev
+```
+
+Use [PostCSS Syntax Descriptor Syntax Production] in your Gruntfile:
+
+```js
+const postcssSyntaxDescriptorSyntaxProduction = require('@csstools/postcss-syntax-descriptor-syntax-production');
+
+grunt.loadNpmTasks('grunt-postcss');
+
+grunt.initConfig({
+ postcss: {
+ options: {
+ processors: [
+ postcssSyntaxDescriptorSyntaxProduction(/* pluginOptions */)
+ ]
+ },
+ dist: {
+ src: '*.css'
+ }
+ }
+});
+```
+
+[Gulp PostCSS]: https://github.com/postcss/gulp-postcss
+[Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss
+[PostCSS]: https://github.com/postcss/postcss
+[PostCSS CLI]: https://github.com/postcss/postcss-cli
+[PostCSS Loader]: https://github.com/postcss/postcss-loader
+[PostCSS Syntax Descriptor Syntax Production]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-syntax-descriptor-syntax-production
+[Next.js]: https://nextjs.org
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/LICENSE.md b/plugins/postcss-syntax-descriptor-syntax-production/LICENSE.md
new file mode 100644
index 0000000000..e8ae93b9f9
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/LICENSE.md
@@ -0,0 +1,18 @@
+MIT No Attribution (MIT-0)
+
+Copyright © CSSTools Contributors
+
+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.
+
+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.
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/README.md b/plugins/postcss-syntax-descriptor-syntax-production/README.md
new file mode 100644
index 0000000000..587018faee
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/README.md
@@ -0,0 +1,92 @@
+# PostCSS Syntax Descriptor Syntax Production [
][PostCSS]
+
+[
][npm-url] [
][cli-url] [
][discord]
[
][css-url] [
][css-url]
+
+```bash
+npm install @csstools/postcss-syntax-descriptor-syntax-production --save-dev
+```
+
+[PostCSS Syntax Descriptor Syntax Production] lets you use the `` production in `syntax` descriptors following the [CSS Specification].
+
+```css
+@property --color {
+ inherits: true;
+ initial-value: black;
+ syntax: ;
+}
+
+/* becomes */
+
+@property --color {
+ inherits: true;
+ initial-value: black;
+ color: "";
+}
+```
+
+## Usage
+
+Add [PostCSS Syntax Descriptor Syntax Production] to your project:
+
+```bash
+npm install postcss @csstools/postcss-syntax-descriptor-syntax-production --save-dev
+```
+
+Use it as a [PostCSS] plugin:
+
+```js
+const postcss = require('postcss');
+const postcssSyntaxDescriptorSyntaxProduction = require('@csstools/postcss-syntax-descriptor-syntax-production');
+
+postcss([
+ postcssSyntaxDescriptorSyntaxProduction(/* pluginOptions */)
+]).process(YOUR_CSS /*, processOptions */);
+```
+
+[PostCSS Syntax Descriptor Syntax Production] runs in all Node environments, with special
+instructions for:
+
+- [Node](INSTALL.md#node)
+- [PostCSS CLI](INSTALL.md#postcss-cli)
+- [PostCSS Load Config](INSTALL.md#postcss-load-config)
+- [Webpack](INSTALL.md#webpack)
+- [Next.js](INSTALL.md#nextjs)
+- [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
+postcssSyntaxDescriptorSyntaxProduction({ preserve: true })
+```
+
+```css
+@property --color {
+ inherits: true;
+ initial-value: black;
+ syntax: ;
+}
+
+/* becomes */
+
+@property --color {
+ inherits: true;
+ initial-value: black;
+ color: "";
+ syntax: ;
+}
+```
+
+[cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test
+[css-url]: https://cssdb.org/#syntax-descriptor-syntax-production
+[discord]: https://discord.gg/bUadyRwkJS
+[npm-url]: https://www.npmjs.com/package/@csstools/postcss-syntax-descriptor-syntax-production
+
+[PostCSS]: https://github.com/postcss/postcss
+[PostCSS Syntax Descriptor Syntax Production]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-syntax-descriptor-syntax-production
+[CSS Specification]: https://github.com/w3c/csswg-drafts/issues/11426#issuecomment-3657538113
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/api-extractor.json b/plugins/postcss-syntax-descriptor-syntax-production/api-extractor.json
new file mode 100644
index 0000000000..42058be517
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/api-extractor.json
@@ -0,0 +1,4 @@
+{
+ "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
+ "extends": "../../api-extractor.json"
+}
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/dist/index.cjs b/plugins/postcss-syntax-descriptor-syntax-production/dist/index.cjs
new file mode 100644
index 0000000000..b898a58372
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/dist/index.cjs
@@ -0,0 +1 @@
+"use strict";var e=require("@csstools/css-tokenizer");const s=/^property$/i,c=/^syntax$/i,creator=a=>{const t=Object.assign({preserve:!1},a);return{postcssPlugin:"postcss-syntax-descriptor-syntax-production",Declaration(a){if(!c.test(a.prop))return;if(!a.parent||"atrule"!==a.parent.type)return;if(!s.test(a.parent.name))return;const o=a.value,r=e.tokenize({css:a.value});let n="";r.forEach(s=>{e.isTokenComment(s)||(e.isTokenWhitespace(s)?n+=" ":n+=s[1])});let i='"';for(const e of n){const s=e.codePointAt(0);if(void 0!==s)switch(s){case 0:i+=String.fromCodePoint(65533);break;case 34:case 92:i+="\\"+String.fromCodePoint(s);break;case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9:case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19:case 20:case 21:case 22:case 23:case 24:case 25:case 26:case 27:case 28:case 29:case 30:case 31:case 127:i+="\\"+s.toString(16)+" ";break;default:i+=String.fromCodePoint(s)}}i+='"',o!==i&&(a.cloneBefore({prop:"color",value:i}),t.preserve||a.remove())}}};creator.postcss=!0,module.exports=creator;
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/dist/index.d.ts b/plugins/postcss-syntax-descriptor-syntax-production/dist/index.d.ts
new file mode 100644
index 0000000000..9e6a372973
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/dist/index.d.ts
@@ -0,0 +1,12 @@
+import type { PluginCreator } from 'postcss';
+
+declare const creator: PluginCreator;
+export default creator;
+
+/** postcss-syntax-descriptor-syntax-production plugin options */
+export declare type pluginOptions = {
+ /** Preserve the original notation. default: false */
+ preserve?: boolean;
+};
+
+export { }
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/dist/index.mjs b/plugins/postcss-syntax-descriptor-syntax-production/dist/index.mjs
new file mode 100644
index 0000000000..a532e96084
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/dist/index.mjs
@@ -0,0 +1 @@
+import{tokenize as e,isTokenComment as s,isTokenWhitespace as a}from"@csstools/css-tokenizer";const c=/^property$/i,t=/^syntax$/i,creator=r=>{const o=Object.assign({preserve:!1},r);return{postcssPlugin:"postcss-syntax-descriptor-syntax-production",Declaration(r){if(!t.test(r.prop))return;if(!r.parent||"atrule"!==r.parent.type)return;if(!c.test(r.parent.name))return;const n=r.value,i=e({css:r.value});let p="";i.forEach(e=>{s(e)||(a(e)?p+=" ":p+=e[1])});let f='"';for(const e of p){const s=e.codePointAt(0);if(void 0!==s)switch(s){case 0:f+=String.fromCodePoint(65533);break;case 34:case 92:f+="\\"+String.fromCodePoint(s);break;case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9:case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19:case 20:case 21:case 22:case 23:case 24:case 25:case 26:case 27:case 28:case 29:case 30:case 31:case 127:f+="\\"+s.toString(16)+" ";break;default:f+=String.fromCodePoint(s)}}f+='"',n!==f&&(r.cloneBefore({prop:"color",value:f}),o.preserve||r.remove())}}};creator.postcss=!0;export{creator as default};
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/docs/README.md b/plugins/postcss-syntax-descriptor-syntax-production/docs/README.md
new file mode 100644
index 0000000000..bb1ef292d7
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/docs/README.md
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[] lets you use the `` production in `syntax` descriptors following the [CSS Specification].
+
+```css
+
+
+/* becomes */
+
+
+```
+
+
+
+
+
+## Options
+
+### preserve
+
+The `preserve` option determines whether the original notation
+is preserved. By default, it is not preserved.
+
+```js
+({ preserve: true })
+```
+
+```css
+
+
+/* becomes */
+
+
+```
+
+
+[CSS Specification]:
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/package.json b/plugins/postcss-syntax-descriptor-syntax-production/package.json
new file mode 100644
index 0000000000..903428fa1c
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/package.json
@@ -0,0 +1,86 @@
+{
+ "name": "@csstools/postcss-syntax-descriptor-syntax-production",
+ "description": "Use the syntax production in syntax descriptors",
+ "version": "0.0.0",
+ "contributors": [
+ {
+ "name": "Antonio Laguna",
+ "email": "antonio@laguna.es",
+ "url": "https://antonio.laguna.es"
+ },
+ {
+ "name": "Romain Menke",
+ "email": "romainmenke@gmail.com"
+ }
+ ],
+ "license": "MIT-0",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "engines": {
+ "node": ">=18"
+ },
+ "type": "module",
+ "main": "dist/index.cjs",
+ "module": "dist/index.mjs",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/index.mjs"
+ },
+ "require": {
+ "default": "./dist/index.cjs"
+ }
+ }
+ },
+ "files": [
+ "CHANGELOG.md",
+ "LICENSE.md",
+ "README.md",
+ "dist"
+ ],
+ "dependencies": {
+ "@csstools/css-tokenizer": "^3.0.4"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4"
+ },
+ "devDependencies": {
+ "@csstools/postcss-tape": "*"
+ },
+ "scripts": {
+ "build": "rollup -c ../../rollup/default.mjs",
+ "docs": "node ../../.github/bin/generate-docs/install.mjs && node ../../.github/bin/generate-docs/readme.mjs",
+ "lint": "node ../../.github/bin/format-package-json.mjs",
+ "prepublishOnly": "npm run build && npm run test",
+ "test": "node --test",
+ "test:rewrite-expects": "REWRITE_EXPECTS=true node --test"
+ },
+ "homepage": "https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-syntax-descriptor-syntax-production#readme",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/csstools/postcss-plugins.git",
+ "directory": "plugins/postcss-syntax-descriptor-syntax-production"
+ },
+ "bugs": "https://github.com/csstools/postcss-plugins/issues",
+ "keywords": [
+ "postcss-plugin"
+ ],
+ "csstools": {
+ "cssdbId": "syntax-descriptor-syntax-production",
+ "exportName": "postcssSyntaxDescriptorSyntaxProduction",
+ "humanReadableName": "PostCSS Syntax Descriptor Syntax Production",
+ "specUrl": "https://github.com/w3c/csswg-drafts/issues/11426#issuecomment-3657538113"
+ },
+ "volta": {
+ "extends": "../../package.json"
+ }
+}
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/src/index.ts b/plugins/postcss-syntax-descriptor-syntax-production/src/index.ts
new file mode 100644
index 0000000000..3d78391434
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/src/index.ts
@@ -0,0 +1,132 @@
+import { isTokenComment, isTokenWhitespace, tokenize } from '@csstools/css-tokenizer';
+import type { PluginCreator } from 'postcss';
+
+/** postcss-syntax-descriptor-syntax-production plugin options */
+export type pluginOptions = {
+ /** Preserve the original notation. default: false */
+ preserve?: boolean,
+};
+
+const IS_AT_PROPERTY_REGEX = /^property$/i;
+const IS_SYNTAX_REGEX = /^syntax$/i;
+
+const creator: PluginCreator = (opts?: pluginOptions) => {
+ const options: pluginOptions = Object.assign(
+ // Default options
+ {
+ preserve: false,
+ },
+ // Provided options
+ opts,
+ );
+
+ return {
+ postcssPlugin: 'postcss-syntax-descriptor-syntax-production',
+ Declaration(decl): void {
+ if (!IS_SYNTAX_REGEX.test(decl.prop)) {
+ return;
+ }
+
+ if (!decl.parent || decl.parent.type !== 'atrule') {
+ return;
+ }
+
+ if (!IS_AT_PROPERTY_REGEX.test(decl.parent.name)) {
+ return;
+ }
+
+ const originalValue = decl.value;
+ const tokens = tokenize({ css: decl.value });
+
+ let stringValue = '';
+ tokens.forEach((token) => {
+ if (isTokenComment(token)) return;
+
+ if (isTokenWhitespace(token)) {
+ stringValue += " ";
+ return;
+ }
+
+ stringValue += token[1];
+ });
+
+ let serialized = '"';
+
+ for (const part of stringValue) {
+ const codePoint = part.codePointAt(0);
+ if (typeof codePoint === "undefined") {
+ continue;
+ }
+
+ switch (codePoint) {
+ case 0x0000:
+ serialized += String.fromCodePoint(0xFFFD);
+ break;
+ case 0x0022:
+ case 0x005C:
+ serialized += ("\\" + String.fromCodePoint(codePoint));
+ break;
+ case 0x0001:
+ case 0x0002:
+ case 0x0003:
+ case 0x0004:
+ case 0x0005:
+ case 0x0006:
+ case 0x0007:
+ case 0x0008:
+ case 0x0009:
+ case 0x000A:
+ case 0x000B:
+ case 0x000C:
+ case 0x000D:
+ case 0x000E:
+ case 0x000F:
+ case 0x0010:
+ case 0x0011:
+ case 0x0012:
+ case 0x0013:
+ case 0x0014:
+ case 0x0015:
+ case 0x0016:
+ case 0x0017:
+ case 0x0018:
+ case 0x0019:
+ case 0x001A:
+ case 0x001B:
+ case 0x001C:
+ case 0x001D:
+ case 0x001E:
+ case 0x001F:
+ case 0x007F:
+ serialized += ("\\" + codePoint.toString(16) + " ");
+ break;
+
+ default:
+ serialized += String.fromCodePoint(codePoint);
+ break;
+ }
+ }
+
+ serialized += '"';
+
+ if (originalValue === serialized) {
+ return;
+ }
+
+ decl.cloneBefore({
+ prop: 'color',
+ value: serialized,
+ });
+
+ if (options.preserve) {
+ return;
+ }
+
+ decl.remove();
+ },
+ };
+};
+
+creator.postcss = true;
+
+export default creator;
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/test/_import.mjs b/plugins/postcss-syntax-descriptor-syntax-production/test/_import.mjs
new file mode 100644
index 0000000000..02b22158cd
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/test/_import.mjs
@@ -0,0 +1,10 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+import plugin from '@csstools/postcss-syntax-descriptor-syntax-production';
+
+test('import', () => {
+ plugin();
+ assert.ok(plugin.postcss, 'should have "postcss flag"');
+ assert.equal(typeof plugin, 'function', 'should return a function');
+});
+
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/test/_require.cjs b/plugins/postcss-syntax-descriptor-syntax-production/test/_require.cjs
new file mode 100644
index 0000000000..8f98620a89
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/test/_require.cjs
@@ -0,0 +1,9 @@
+const assert = require('node:assert/strict');
+const test = require('node:test');
+const plugin = require('@csstools/postcss-syntax-descriptor-syntax-production');
+
+test('require', () => {
+ plugin();
+ assert.ok(plugin.postcss, 'should have "postcss flag"');
+ assert.equal(typeof plugin, 'function', 'should return a function');
+});
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/test/_tape.mjs b/plugins/postcss-syntax-descriptor-syntax-production/test/_tape.mjs
new file mode 100644
index 0000000000..a498b2836f
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/test/_tape.mjs
@@ -0,0 +1,23 @@
+import { postcssTape } from '@csstools/postcss-tape';
+import plugin from '@csstools/postcss-syntax-descriptor-syntax-production';
+
+postcssTape(plugin)({
+ basic: {
+ message: 'supports basic usage',
+ },
+ 'basic:preserve-true': {
+ message: 'supports basic usage',
+ options: {
+ preserve: true,
+ },
+ },
+ 'examples/example': {
+ message: 'minimal example',
+ },
+ 'examples/example:preserve-true': {
+ message: 'minimal example',
+ options: {
+ preserve: true,
+ },
+ },
+});
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/test/basic.css b/plugins/postcss-syntax-descriptor-syntax-production/test/basic.css
new file mode 100644
index 0000000000..6657ff29f2
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/test/basic.css
@@ -0,0 +1,37 @@
+@property --color {
+ inherits: true;
+ initial-value: black;
+ syntax: ;
+}
+
+@property --multi-line {
+ inherits: true;
+ initial-value: black;
+ syntax: |
+ |
+ ;
+}
+
+@property --box-shadow {
+ inherits: true;
+ initial-value: black;
+ syntax: [ inset? && {2,4} && ? ]# | none;
+}
+
+@property --quoted {
+ inherits: true;
+ initial-value: black;
+ syntax: '"' '"';
+}
+
+@property --function {
+ inherits: true;
+ initial-value: black;
+ syntax: example(first?, second?, third?);
+}
+
+@property --comments {
+ inherits: true;
+ initial-value: black;
+ syntax: /* a comment */ | * a comment */string> | ;
+}
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/test/basic.expect.css b/plugins/postcss-syntax-descriptor-syntax-production/test/basic.expect.css
new file mode 100644
index 0000000000..2dcd62c5ef
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/test/basic.expect.css
@@ -0,0 +1,35 @@
+@property --color {
+ inherits: true;
+ initial-value: black;
+ color: "";
+}
+
+@property --multi-line {
+ inherits: true;
+ initial-value: black;
+ color: " | | ";
+}
+
+@property --box-shadow {
+ inherits: true;
+ initial-value: black;
+ color: "[ inset? && {2,4} && ? ]# | none";
+}
+
+@property --quoted {
+ inherits: true;
+ initial-value: black;
+ color: "'\"' '\"'";
+}
+
+@property --function {
+ inherits: true;
+ initial-value: black;
+ color: "example(first?, second?, third?)";
+}
+
+@property --comments {
+ inherits: true;
+ initial-value: black;
+ color: " | | ";
+}
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/test/basic.preserve-true.expect.css b/plugins/postcss-syntax-descriptor-syntax-production/test/basic.preserve-true.expect.css
new file mode 100644
index 0000000000..a13c76cdfc
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/test/basic.preserve-true.expect.css
@@ -0,0 +1,43 @@
+@property --color {
+ inherits: true;
+ initial-value: black;
+ color: "";
+ syntax: ;
+}
+
+@property --multi-line {
+ inherits: true;
+ initial-value: black;
+ color: " | | ";
+ syntax: |
+ |
+ ;
+}
+
+@property --box-shadow {
+ inherits: true;
+ initial-value: black;
+ color: "[ inset? && {2,4} && ? ]# | none";
+ syntax: [ inset? && {2,4} && ? ]# | none;
+}
+
+@property --quoted {
+ inherits: true;
+ initial-value: black;
+ color: "'\"' '\"'";
+ syntax: '"' '"';
+}
+
+@property --function {
+ inherits: true;
+ initial-value: black;
+ color: "example(first?, second?, third?)";
+ syntax: example(first?, second?, third?);
+}
+
+@property --comments {
+ inherits: true;
+ initial-value: black;
+ color: " | | ";
+ syntax: /* a comment */ | * a comment */string> | ;
+}
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/test/examples/example.css b/plugins/postcss-syntax-descriptor-syntax-production/test/examples/example.css
new file mode 100644
index 0000000000..4c6ca81d4a
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/test/examples/example.css
@@ -0,0 +1,5 @@
+@property --color {
+ inherits: true;
+ initial-value: black;
+ syntax: ;
+}
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/test/examples/example.expect.css b/plugins/postcss-syntax-descriptor-syntax-production/test/examples/example.expect.css
new file mode 100644
index 0000000000..6710a1730a
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/test/examples/example.expect.css
@@ -0,0 +1,5 @@
+@property --color {
+ inherits: true;
+ initial-value: black;
+ color: "";
+}
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/test/examples/example.preserve-true.expect.css b/plugins/postcss-syntax-descriptor-syntax-production/test/examples/example.preserve-true.expect.css
new file mode 100644
index 0000000000..abc051ccb6
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/test/examples/example.preserve-true.expect.css
@@ -0,0 +1,6 @@
+@property --color {
+ inherits: true;
+ initial-value: black;
+ color: "";
+ syntax: ;
+}
diff --git a/plugins/postcss-syntax-descriptor-syntax-production/tsconfig.json b/plugins/postcss-syntax-descriptor-syntax-production/tsconfig.json
new file mode 100644
index 0000000000..500af6d266
--- /dev/null
+++ b/plugins/postcss-syntax-descriptor-syntax-production/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "declarationDir": ".",
+ "strict": true
+ },
+ "include": ["./src/**/*"],
+ "exclude": ["dist"]
+}
diff --git a/rollup/configs/externals.mjs b/rollup/configs/externals.mjs
index 352c46f99e..c2d58b8de7 100644
--- a/rollup/configs/externals.mjs
+++ b/rollup/configs/externals.mjs
@@ -55,12 +55,14 @@ export const externalsForCLI = [
'@csstools/postcss-oklab-function',
'@csstools/postcss-position-area-property',
'@csstools/postcss-progressive-custom-properties',
+ '@csstools/postcss-property-rule-prelude-list',
'@csstools/postcss-random-function',
'@csstools/postcss-rebase-url',
'@csstools/postcss-relative-color-syntax',
'@csstools/postcss-scope-pseudo-class',
'@csstools/postcss-sign-functions',
'@csstools/postcss-stepped-value-functions',
+ '@csstools/postcss-syntax-descriptor-syntax-production',
'@csstools/postcss-system-ui-font-family',
'@csstools/postcss-text-decoration-shorthand',
'@csstools/postcss-trigonometric-functions',
@@ -164,12 +166,14 @@ export const externalsForPlugin = [
'@csstools/postcss-oklab-function',
'@csstools/postcss-position-area-property',
'@csstools/postcss-progressive-custom-properties',
+ '@csstools/postcss-property-rule-prelude-list',
'@csstools/postcss-random-function',
'@csstools/postcss-rebase-url',
'@csstools/postcss-relative-color-syntax',
'@csstools/postcss-scope-pseudo-class',
'@csstools/postcss-sign-functions',
'@csstools/postcss-stepped-value-functions',
+ '@csstools/postcss-syntax-descriptor-syntax-production',
'@csstools/postcss-system-ui-font-family',
'@csstools/postcss-text-decoration-shorthand',
'@csstools/postcss-trigonometric-functions',