diff --git a/build/postcss-combine-selectors.cjs b/build/postcss-combine-selectors.cjs new file mode 100644 index 00000000..497504db --- /dev/null +++ b/build/postcss-combine-selectors.cjs @@ -0,0 +1,88 @@ +const creator = () => { + return { + postcssPlugin: 'postcss-combine-selectors', + OnceExit(root) { + const rulesToCombine = new Map() + + root.walkRules(rule => { + if (isKeyframesRule(rule)) { + return + } + + const key = ruleKey(rule) + const existing = rulesToCombine.get(key) + + // Existing group: + // - add rule to the group + if (existing) { + existing.rules.push(rule) + return + } + + // New group: + // - first rule is the one we're going to combine into + // - create an empty slice for other rules to be added to + rulesToCombine.set(key, { + first: rule, + rules: [] + }) + }) + + // Iterate over all groups + for (const { first, rules } of rulesToCombine.values()) { + // If there was only one rule for a given group, there's nothing to combine + if (rules.length === 0) { + continue + } + + // Append all contents of all subsequent rules to the first rule + for (const rule of rules) { + rule.each((child) => { + child.remove() + first.append(child) + }) + + // Remove the now-empty rule + rule.remove() + } + } + }, + } +} + +/** +* Construct a key that is specific to the AST ancestry of the rule. +* Only rules with the same key can be combined. +* +* @param {import('postcss').Rule} rule +* @returns {string} +*/ +function ruleKey(rule) { + let key = `[rule ${rule.selector}]` + + let ancestor = rule.parent + while (ancestor) { + if (ancestor.type === 'atrule') { + key = `[${ancestor.name} ${ancestor.params}]${key}` + } else if (ancestor.type === 'rule') { + key = `[rule ${ancestor.selector}]${key}` + } else if (ancestor.type === 'root') { + break + } + + ancestor = ancestor.parent + } + + return key +} + +function isKeyframesRule(rule) { + if (rule.parent?.type === 'atrule' && rule.parent.name === 'keyframes') { + return true + } + + return false +} + +module.exports = creator +module.exports.postcss = true diff --git a/package-lock.json b/package-lock.json index c985b577..4e0659ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-props", - "version": "1.5.10", + "version": "1.5.16", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "open-props", - "version": "1.5.10", + "version": "1.5.16", "license": "MIT", "devDependencies": { "ava": "^3.15.0", @@ -17,7 +17,6 @@ "open-color": "^1.9.1", "postcss": "^8.3.9", "postcss-cli": "^8.3.1", - "postcss-combine-duplicated-selectors": "^10.0.3", "postcss-import": "^14.0.2", "postcss-preset-env": "6.7.x", "typescript": "^4.9.4" @@ -3894,46 +3893,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-combine-duplicated-selectors": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/postcss-combine-duplicated-selectors/-/postcss-combine-duplicated-selectors-10.0.3.tgz", - "integrity": "sha512-IP0BmwFloCskv7DV7xqvzDXqMHpwdczJa6ZvIW8abgHdcIHs9mCJX2ltFhu3EwA51ozp13DByng30+Ke+eIExA==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-combine-duplicated-selectors/node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-combine-duplicated-selectors/node_modules/postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/postcss-convert-values": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.2.tgz", @@ -9197,33 +9156,6 @@ "postcss-value-parser": "^4.2.0" } }, - "postcss-combine-duplicated-selectors": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/postcss-combine-duplicated-selectors/-/postcss-combine-duplicated-selectors-10.0.3.tgz", - "integrity": "sha512-IP0BmwFloCskv7DV7xqvzDXqMHpwdczJa6ZvIW8abgHdcIHs9mCJX2ltFhu3EwA51ozp13DByng30+Ke+eIExA==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.4" - }, - "dependencies": { - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } - } - }, "postcss-convert-values": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.2.tgz", diff --git a/package.json b/package.json index e969dd07..8e084174 100644 --- a/package.json +++ b/package.json @@ -317,7 +317,6 @@ "open-color": "^1.9.1", "postcss": "^8.3.9", "postcss-cli": "^8.3.1", - "postcss-combine-duplicated-selectors": "^10.0.3", "postcss-import": "^14.0.2", "postcss-preset-env": "6.7.x", "typescript": "^4.9.4" diff --git a/postcss.config.cjs b/postcss.config.cjs index 7ac657c9..5a74ce6d 100644 --- a/postcss.config.cjs +++ b/postcss.config.cjs @@ -1,7 +1,7 @@ const postcssPresetEnv = require('postcss-preset-env') const postcssImport = require('postcss-import') const cssnano = require('cssnano') -const combineSelectors = require('postcss-combine-duplicated-selectors') +const combineSelectors = require('./build/postcss-combine-selectors.cjs') const lib = process.env.npm_lifecycle_event