diff --git a/plugins/postcss-nesting/CHANGELOG.md b/plugins/postcss-nesting/CHANGELOG.md index 59e21f686..da262df9b 100644 --- a/plugins/postcss-nesting/CHANGELOG.md +++ b/plugins/postcss-nesting/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Nesting +### Unreleased (patch) + +- Fix order of final CSS with complex usage of both nesting and mixins, by @pciarach + ### 12.0.3 _February 19, 2024_ diff --git a/plugins/postcss-nesting/dist/index.cjs b/plugins/postcss-nesting/dist/index.cjs index 2990b02ab..30af5d92e 100644 --- a/plugins/postcss-nesting/dist/index.cjs +++ b/plugins/postcss-nesting/dist/index.cjs @@ -1 +1 @@ -"use strict";var e=require("postcss-selector-parser"),t=require("@csstools/selector-specificity");const n=e.pseudo({value:":is"});function sortCompoundSelectorsInsideComplexSelector(t){if(!t||!t.nodes)return;const r=[];let o=[];for(let s=0;s"tag"===e.type))){const r=n.clone({}),o=t.nodes[s];o.replaceWith(r),r.append(e.selector({nodes:[o],value:void 0}))}o.push(t.nodes[s])}else r.push(o),r.push([t.nodes[s]]),o=[];r.push(o);const s=[];for(let e=0;e"selector"===e.type&&"selector"===t.type&&e.nodes.length&&t.nodes.length?selectorTypeOrder(e.nodes[0])-selectorTypeOrder(t.nodes[0]):"selector"===e.type&&e.nodes.length?selectorTypeOrder(e.nodes[0])-selectorTypeOrder(t):"selector"===t.type&&t.nodes.length?selectorTypeOrder(e)-selectorTypeOrder(t.nodes[0]):selectorTypeOrder(e)-selectorTypeOrder(t)));for(let e=0;e=0;e--)s[e].remove(),t.prepend(s[e])}function selectorTypeOrder(t){return e.isPseudoElement(t)?r.pseudoElement:r[t.type]}const r={universal:0,tag:1,pseudoElement:2,id:3,class:4,attribute:5,pseudo:6,selector:7,string:8,root:9,comment:10};function ampersandToScope(t,n){let r,o=t.parent;for(;o;){if("rule"===o.type)return;o=o.parent}try{r=e().astSync(t.selector)}catch(e){return void t.warn(n,`Failed to parse selector : "${t.selector}" with message: "${e instanceof Error?e.message:e}"`)}r&&(r.walkNesting((t=>{const n=t.parent;t.replaceWith(e.pseudo({value:":scope"})),n&&sortCompoundSelectorsInsideComplexSelector(n)})),t.selector=r.toString())}function cleanupParent(e){if(!e.nodes.length)return void e.remove();const t=e.nodes.filter((e=>"comment"===e.type));t.length===e.nodes.length&&e.replaceWith(...t)}function shiftNodesBeforeParent(e,t){const n=t.index(e);if(n){const e=t.cloneBefore().removeAll().append(t.nodes.slice(0,n));e.raws.semicolon=!0,cleanupParent(e)}t.before(e),t.raws.semicolon=!0}function combinationsWithSizeN(e,t){if(t<2)throw new Error("n must be greater than 1");if(e.length<2)throw new Error("s must be greater than 1");if(Math.pow(e.length,t)>1e4)throw new Error("Too many combinations when trying to resolve a nested selector with lists, reduce the complexity of your selectors");const n=[];for(let e=0;e=0;s--){let t=n[s];if(t>=e.length){if(t=0,n[s]=0,0===s)return r;n[s-1]+=1}o[s]=e[t]}r.push(o),n[n.length-1]++}}function nodesAreEquallySpecific(n){const r=n.map((t=>e().astSync(t))).map((e=>t.selectorSpecificity(e))),o=r[0];for(let e=1;ee().astSync(t))):[e().astSync(`:is(${t.join(",")})`)];const s=[];for(let t=0;t{"nesting"===e.type&&(n=!0)}));const r=t.nodes[0];let o=!1;r.each((e=>"combinator"===e.type&&(o=!0,!1))),n?o&&r.insertBefore(r.at(0),e.nesting({})):(r.insertBefore(r.at(0),e.combinator({value:" "})),r.insertBefore(r.at(0),e.nesting({}))),l=t.toString()}let c=[],a=0;if(e().astSync(l).walkNesting((()=>{a++})),a>1&&o.length>1)c=combinationsWithSizeN(o,a),i=c.length;else{i=o.length;for(let e=0;e{if("nesting"!==o.type)return;let s=c[t][n];n++,"root"===s.type&&1===s.nodes.length&&(s=s.nodes[0]);const i=e().astSync(`:is(${s.toString()})`),l=isSimpleSelector(s.nodes[0]),a=isCompoundSelector(s.nodes[0]),u=isSimpleSelector(o),p=isCompoundSelector(o);if(l&&u)return void o.replaceWith(s.clone());if((l||a)&&(u||p)){const e=o.parent;return l&&"selector"===s.type?o.replaceWith(s.clone().nodes[0]):o.replaceWith(...s.clone().nodes),void(e&&e.nodes.length>1&&sortCompoundSelectorsInsideComplexSelector(e))}if(l){const e=o.parent;return o.replaceWith(s.clone().nodes[0]),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(a){const e=o.parent;return o.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(nestingIsFirstAndOnlyInSelectorWithEitherSpaceOrChildCombinator(o)){const e=o.parent;return o.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(nestingIsNotInsideCompoundSelector(o)){const e=o.parent;return o.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}const d=o.parent;r.noIsPseudoSelector?o.replaceWith(...s.clone().nodes):o.replaceWith(...i.clone({}).nodes),d&&sortCompoundSelectorsInsideComplexSelector(d)})),s.push(o.toString())}}return s}function isSimpleSelector(e){return"combinator"!==e.type&&!(e.parent&&e.parent.nodes.length>1)}function isCompoundSelector(e,t=null){if(isSimpleSelector(e))return!1;if(!e.parent)return!1;if(!!e.parent.nodes.find((e=>"combinator"===e.type)))return!1;return!(!!e.parent.nodes.find((e=>"nesting"===e.type))&&t&&!isCompoundSelector(t))}function nestingIsFirstAndOnlyInSelectorWithEitherSpaceOrChildCombinator(e){if(!e.parent)return!1;if(0!==e.parent.nodes.indexOf(e))return!1;for(let t=1;t"!==e.parent.nodes[t].value)return!1;return!0}function nestingIsNotInsideCompoundSelector(e){if(isSimpleSelector(e))return!0;if(!e.parent)return!1;for(let t=0;t{if("decl"===n.type)return t===r-1?void(t=r):(n.remove(),e.insertAfter(t,n),void(t=e.index(n)));if("atrule"===n.type&&"mixin"===n.name.toLowerCase()){let o=n.prev();for(;o;){if("rule"===o.type||"atrule"===o.type)return;o=o.prev()}return t===r-1?void(t=r):(n.remove(),e.insertAfter(t,n),void(t=e.index(n)))}if("comment"===n.type){const o=n.next();if(o&&("comment"===o.type||"rule"===o.type||"atrule"===o.type&&"mixin"!==o.name.toLowerCase()))return;return t===r-1?void(t=r):(n.remove(),e.insertAfter(t,n),void(t=e.index(n)))}}))}function transformRuleWithinRule(e,t,n,r){let o=[];try{o=mergeSelectors(t.selectors,e.selectors,r)}catch(r){return void e.warn(n,`Failed to parse selectors : "${t.selector}" / "${e.selector}" with message: "${r instanceof Error?r.message:r}"`)}if(!o.length)return;groupDeclarations(t),shiftNodesBeforeParent(e,t),e.selectors=o;"rule"===e.type&&"rule"===t.type&&e.selector===t.selector&&e.append(...t.nodes),cleanupParent(t)}function isValidRuleWithinRule(e){return e.selectors.every((e=>-1===e.indexOf("|")))}function comma(e){const t=[];let n="",r=!1,o=0,s=!1,i=!1;for(const l of e)i?i=!1:"\\"===l?i=!0:s?l===s&&(s=!1):'"'===l||"'"===l?s=l:"("===l?o+=1:")"===l?o>0&&(o-=1):0===o&&","===l&&(r=!0),r?(""!==n&&t.push(n.trim()),n="",r=!1):n+=l;return t.push(n.trim()),t}function transformNestRuleWithinRule(e,t,n,r,o){let s=[];try{s=mergeSelectors(t.selectors,comma(e.params),o)}catch(r){return void e.warn(n,`Failed to parse selectors : "${t.selector}" / "${e.params}" with message: "${r instanceof Error?r.message:r}"`)}if(!s.length)return;shiftNodesBeforeParent(e,t);const i=t.clone().removeAll().append(e.nodes);i.raws.semicolon=!0,i.selectors=s,e.replaceWith(i),cleanupParent(t),r(i,n,o)}function isValidNestRuleWithinRule(e){return comma(e.params).every((e=>e.split("&").length>=2&&-1===e.indexOf("|")))}var o=["container","document","media","supports","layer","starting-style"];function atruleWithinRule(e,t,n,r,o){if(groupDeclarations(t),shiftNodesBeforeParent(e,t),e.nodes){const s=t.clone().removeAll().append(e.nodes);e.append(s),cleanupParent(t),r(s,n,o)}else cleanupParent(t)}function isAtruleWithinRule(e){return o.includes(e.name)}function transformAtruleWithinAtrule(e,t){var n,r;groupDeclarations(t),shiftNodesBeforeParent(e,t),e.params=(n=t.params,r=e.params,comma(n).map((e=>comma(r).map((t=>`${e} and ${t}`)).join(", "))).join(", ")),cleanupParent(t)}function isAtruleWithinAtrule(e,t){return o.includes(e.name)&&e.name===t.name}function isAtRule(e){return e&&"atrule"===e.type}function isNestRule(e){return e&&isAtRule(e)&&"nest"===e.name}function isRule(e){return e&&"rule"===e.type}function walk(e,t,n){e.each((r=>{const o=r.parent;isNestRule(r)&&!n.silenceAtNestWarning&&e.warn(t,`\`@nest\` was removed from the CSS Nesting specification and will be removed from PostCSS Nesting in the next major version.\nChange \`@nest ${r.params} {}\` to \`${r.params} {}\` to migrate to the latest standard.`),isRule(r)&&isRule(o)&&isValidRuleWithinRule(r)?transformRuleWithinRule(r,o,t,n):isNestRule(r)&&isRule(o)&&isValidNestRuleWithinRule(r)?transformNestRuleWithinRule(r,o,t,walk,n):isAtRule(r)&&isRule(o)&&isAtruleWithinRule(r)?atruleWithinRule(r,o,t,walk,n):isAtRule(r)&&isAtRule(o)&&isAtruleWithinAtrule(r,o)&&transformAtruleWithinAtrule(r,o),"nodes"in r&&r.nodes.length&&walk(r,t,n)}))}const creator=e=>{const t=Object.assign({noIsPseudoSelector:!1,silenceAtNestWarning:!1},e);return{postcssPlugin:"postcss-nesting",Rule(e,{result:n}){walk(e,n,t),e.selector.includes("&")&&ersandToScope(e,n)}}};creator.postcss=!0,module.exports=creator; +"use strict";var e=require("postcss-selector-parser"),t=require("@csstools/selector-specificity");const n=e.pseudo({value:":is"});function sortCompoundSelectorsInsideComplexSelector(t){if(!t||!t.nodes)return;const r=[];let o=[];for(let s=0;s"tag"===e.type))){const r=n.clone({}),o=t.nodes[s];o.replaceWith(r),r.append(e.selector({nodes:[o],value:void 0}))}o.push(t.nodes[s])}else r.push(o),r.push([t.nodes[s]]),o=[];r.push(o);const s=[];for(let e=0;e"selector"===e.type&&"selector"===t.type&&e.nodes.length&&t.nodes.length?selectorTypeOrder(e.nodes[0])-selectorTypeOrder(t.nodes[0]):"selector"===e.type&&e.nodes.length?selectorTypeOrder(e.nodes[0])-selectorTypeOrder(t):"selector"===t.type&&t.nodes.length?selectorTypeOrder(e)-selectorTypeOrder(t.nodes[0]):selectorTypeOrder(e)-selectorTypeOrder(t)));for(let e=0;e=0;e--)s[e].remove(),t.prepend(s[e])}function selectorTypeOrder(t){return e.isPseudoElement(t)?r.pseudoElement:r[t.type]}const r={universal:0,tag:1,pseudoElement:2,id:3,class:4,attribute:5,pseudo:6,selector:7,string:8,root:9,comment:10};function ampersandToScope(t,n){let r,o=t.parent;for(;o;){if("rule"===o.type)return;o=o.parent}try{r=e().astSync(t.selector)}catch(e){return void t.warn(n,`Failed to parse selector : "${t.selector}" with message: "${e instanceof Error?e.message:e}"`)}r&&(r.walkNesting((t=>{const n=t.parent;t.replaceWith(e.pseudo({value:":scope"})),n&&sortCompoundSelectorsInsideComplexSelector(n)})),t.selector=r.toString())}function cleanupParent(e){if(!e.nodes.length)return void e.remove();const t=e.nodes.filter((e=>"comment"===e.type));t.length===e.nodes.length&&e.replaceWith(...t)}function shiftNodesBeforeParent(e,t){const n=t.index(e);if(n){const e=t.cloneBefore().removeAll().append(t.nodes.slice(0,n));e.raws.semicolon=!0,cleanupParent(e)}t.before(e),t.raws.semicolon=!0}function combinationsWithSizeN(e,t){if(t<2)throw new Error("n must be greater than 1");if(e.length<2)throw new Error("s must be greater than 1");if(Math.pow(e.length,t)>1e4)throw new Error("Too many combinations when trying to resolve a nested selector with lists, reduce the complexity of your selectors");const n=[];for(let e=0;e=0;s--){let t=n[s];if(t>=e.length){if(t=0,n[s]=0,0===s)return r;n[s-1]+=1}o[s]=e[t]}r.push(o),n[n.length-1]++}}function nodesAreEquallySpecific(n){const r=n.map((t=>e().astSync(t))).map((e=>t.selectorSpecificity(e))),o=r[0];for(let e=1;ee().astSync(t))):[e().astSync(`:is(${t.join(",")})`)];const s=[];for(let t=0;t{"nesting"===e.type&&(n=!0)}));const r=t.nodes[0];let o=!1;r.each((e=>"combinator"===e.type&&(o=!0,!1))),n?o&&r.insertBefore(r.at(0),e.nesting({})):(r.insertBefore(r.at(0),e.combinator({value:" "})),r.insertBefore(r.at(0),e.nesting({}))),l=t.toString()}let c=[],a=0;if(e().astSync(l).walkNesting((()=>{a++})),a>1&&o.length>1)c=combinationsWithSizeN(o,a),i=c.length;else{i=o.length;for(let e=0;e{if("nesting"!==o.type)return;let s=c[t][n];n++,"root"===s.type&&1===s.nodes.length&&(s=s.nodes[0]);const i=e().astSync(`:is(${s.toString()})`),l=isSimpleSelector(s.nodes[0]),a=isCompoundSelector(s.nodes[0]),p=isSimpleSelector(o),u=isCompoundSelector(o);if(l&&p)return void o.replaceWith(s.clone());if((l||a)&&(p||u)){const e=o.parent;return l&&"selector"===s.type?o.replaceWith(s.clone().nodes[0]):o.replaceWith(...s.clone().nodes),void(e&&e.nodes.length>1&&sortCompoundSelectorsInsideComplexSelector(e))}if(l){const e=o.parent;return o.replaceWith(s.clone().nodes[0]),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(a){const e=o.parent;return o.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(nestingIsFirstAndOnlyInSelectorWithEitherSpaceOrChildCombinator(o)){const e=o.parent;return o.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(nestingIsNotInsideCompoundSelector(o)){const e=o.parent;return o.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}const d=o.parent;r.noIsPseudoSelector?o.replaceWith(...s.clone().nodes):o.replaceWith(...i.clone({}).nodes),d&&sortCompoundSelectorsInsideComplexSelector(d)})),s.push(o.toString())}}return s}function isSimpleSelector(e){return"combinator"!==e.type&&!(e.parent&&e.parent.nodes.length>1)}function isCompoundSelector(e,t=null){if(isSimpleSelector(e))return!1;if(!e.parent)return!1;if(!!e.parent.nodes.find((e=>"combinator"===e.type)))return!1;return!(!!e.parent.nodes.find((e=>"nesting"===e.type))&&t&&!isCompoundSelector(t))}function nestingIsFirstAndOnlyInSelectorWithEitherSpaceOrChildCombinator(e){if(!e.parent)return!1;if(0!==e.parent.nodes.indexOf(e))return!1;for(let t=1;t"!==e.parent.nodes[t].value)return!1;return!0}function nestingIsNotInsideCompoundSelector(e){if(isSimpleSelector(e))return!0;if(!e.parent)return!1;for(let t=0;t{if(isDeclarationLike(e,n.length>0))t.push(e);else{if("comment"===e.type){let r=e.next();for(;r&&"comment"===r.type;)r=r.next();if(isDeclarationLike(r,n.length>0))return void t.push(e)}n.push(e)}})),e.removeAll(),t.forEach((t=>{e.append(t)})),n.forEach((t=>{e.append(t)}))}function isDeclarationLike(e,t){return!!e&&("decl"===e.type||"atrule"===e.type&&"mixin"===e.name.toLowerCase()&&!t)}function transformRuleWithinRule(e,t,n,r){let o=[];try{o=mergeSelectors(t.selectors,e.selectors,r)}catch(r){return void e.warn(n,`Failed to parse selectors : "${t.selector}" / "${e.selector}" with message: "${r instanceof Error?r.message:r}"`)}if(!o.length)return;groupDeclarations(t),shiftNodesBeforeParent(e,t),e.selectors=o;"rule"===e.type&&"rule"===t.type&&e.selector===t.selector&&e.append(...t.nodes),cleanupParent(t)}function isValidRuleWithinRule(e){return e.selectors.every((e=>-1===e.indexOf("|")))}function comma(e){const t=[];let n="",r=!1,o=0,s=!1,i=!1;for(const l of e)i?i=!1:"\\"===l?i=!0:s?l===s&&(s=!1):'"'===l||"'"===l?s=l:"("===l?o+=1:")"===l?o>0&&(o-=1):0===o&&","===l&&(r=!0),r?(""!==n&&t.push(n.trim()),n="",r=!1):n+=l;return t.push(n.trim()),t}function transformNestRuleWithinRule(e,t,n,r,o){let s=[];try{s=mergeSelectors(t.selectors,comma(e.params),o)}catch(r){return void e.warn(n,`Failed to parse selectors : "${t.selector}" / "${e.params}" with message: "${r instanceof Error?r.message:r}"`)}if(!s.length)return;shiftNodesBeforeParent(e,t);const i=t.clone().removeAll().append(e.nodes);i.raws.semicolon=!0,i.selectors=s,e.replaceWith(i),cleanupParent(t),r(i,n,o)}function isValidNestRuleWithinRule(e){return comma(e.params).every((e=>e.split("&").length>=2&&-1===e.indexOf("|")))}var o=["container","document","media","supports","layer","starting-style"];function atruleWithinRule(e,t,n,r,o){if(groupDeclarations(t),shiftNodesBeforeParent(e,t),e.nodes){const s=t.clone().removeAll().append(e.nodes);e.append(s),cleanupParent(t),r(s,n,o)}else cleanupParent(t)}function isAtruleWithinRule(e){return o.includes(e.name)}function transformAtruleWithinAtrule(e,t){var n,r;groupDeclarations(t),shiftNodesBeforeParent(e,t),e.params=(n=t.params,r=e.params,comma(n).map((e=>comma(r).map((t=>`${e} and ${t}`)).join(", "))).join(", ")),cleanupParent(t)}function isAtruleWithinAtrule(e,t){return o.includes(e.name)&&e.name===t.name}function isAtRule(e){return e&&"atrule"===e.type}function isNestRule(e){return e&&isAtRule(e)&&"nest"===e.name}function isRule(e){return e&&"rule"===e.type}function walk(e,t,n){e.each((r=>{const o=r.parent;isNestRule(r)&&!n.silenceAtNestWarning&&e.warn(t,`\`@nest\` was removed from the CSS Nesting specification and will be removed from PostCSS Nesting in the next major version.\nChange \`@nest ${r.params} {}\` to \`${r.params} {}\` to migrate to the latest standard.`),isRule(r)&&isRule(o)&&isValidRuleWithinRule(r)?transformRuleWithinRule(r,o,t,n):isNestRule(r)&&isRule(o)&&isValidNestRuleWithinRule(r)?transformNestRuleWithinRule(r,o,t,walk,n):isAtRule(r)&&isRule(o)&&isAtruleWithinRule(r)?atruleWithinRule(r,o,t,walk,n):isAtRule(r)&&isAtRule(o)&&isAtruleWithinAtrule(r,o)&&transformAtruleWithinAtrule(r,o),"nodes"in r&&r.nodes.length&&walk(r,t,n)}))}const creator=e=>{const t=Object.assign({noIsPseudoSelector:!1,silenceAtNestWarning:!1},e);return{postcssPlugin:"postcss-nesting",Rule(e,{result:n}){walk(e,n,t),e.selector.includes("&")&&ersandToScope(e,n)}}};creator.postcss=!0,module.exports=creator; diff --git a/plugins/postcss-nesting/dist/index.mjs b/plugins/postcss-nesting/dist/index.mjs index 593ade047..9db68b45c 100644 --- a/plugins/postcss-nesting/dist/index.mjs +++ b/plugins/postcss-nesting/dist/index.mjs @@ -1 +1 @@ -import e from"postcss-selector-parser";import{selectorSpecificity as t}from"@csstools/selector-specificity";const n=e.pseudo({value:":is"});function sortCompoundSelectorsInsideComplexSelector(t){if(!t||!t.nodes)return;const r=[];let o=[];for(let s=0;s"tag"===e.type))){const r=n.clone({}),o=t.nodes[s];o.replaceWith(r),r.append(e.selector({nodes:[o],value:void 0}))}o.push(t.nodes[s])}else r.push(o),r.push([t.nodes[s]]),o=[];r.push(o);const s=[];for(let e=0;e"selector"===e.type&&"selector"===t.type&&e.nodes.length&&t.nodes.length?selectorTypeOrder(e.nodes[0])-selectorTypeOrder(t.nodes[0]):"selector"===e.type&&e.nodes.length?selectorTypeOrder(e.nodes[0])-selectorTypeOrder(t):"selector"===t.type&&t.nodes.length?selectorTypeOrder(e)-selectorTypeOrder(t.nodes[0]):selectorTypeOrder(e)-selectorTypeOrder(t)));for(let e=0;e=0;e--)s[e].remove(),t.prepend(s[e])}function selectorTypeOrder(t){return e.isPseudoElement(t)?r.pseudoElement:r[t.type]}const r={universal:0,tag:1,pseudoElement:2,id:3,class:4,attribute:5,pseudo:6,selector:7,string:8,root:9,comment:10};function ampersandToScope(t,n){let r,o=t.parent;for(;o;){if("rule"===o.type)return;o=o.parent}try{r=e().astSync(t.selector)}catch(e){return void t.warn(n,`Failed to parse selector : "${t.selector}" with message: "${e instanceof Error?e.message:e}"`)}r&&(r.walkNesting((t=>{const n=t.parent;t.replaceWith(e.pseudo({value:":scope"})),n&&sortCompoundSelectorsInsideComplexSelector(n)})),t.selector=r.toString())}function cleanupParent(e){if(!e.nodes.length)return void e.remove();const t=e.nodes.filter((e=>"comment"===e.type));t.length===e.nodes.length&&e.replaceWith(...t)}function shiftNodesBeforeParent(e,t){const n=t.index(e);if(n){const e=t.cloneBefore().removeAll().append(t.nodes.slice(0,n));e.raws.semicolon=!0,cleanupParent(e)}t.before(e),t.raws.semicolon=!0}function combinationsWithSizeN(e,t){if(t<2)throw new Error("n must be greater than 1");if(e.length<2)throw new Error("s must be greater than 1");if(Math.pow(e.length,t)>1e4)throw new Error("Too many combinations when trying to resolve a nested selector with lists, reduce the complexity of your selectors");const n=[];for(let e=0;e=0;s--){let t=n[s];if(t>=e.length){if(t=0,n[s]=0,0===s)return r;n[s-1]+=1}o[s]=e[t]}r.push(o),n[n.length-1]++}}function nodesAreEquallySpecific(n){const r=n.map((t=>e().astSync(t))).map((e=>t(e))),o=r[0];for(let e=1;ee().astSync(t))):[e().astSync(`:is(${t.join(",")})`)];const s=[];for(let t=0;t{"nesting"===e.type&&(n=!0)}));const r=t.nodes[0];let o=!1;r.each((e=>"combinator"===e.type&&(o=!0,!1))),n?o&&r.insertBefore(r.at(0),e.nesting({})):(r.insertBefore(r.at(0),e.combinator({value:" "})),r.insertBefore(r.at(0),e.nesting({}))),l=t.toString()}let c=[],a=0;if(e().astSync(l).walkNesting((()=>{a++})),a>1&&o.length>1)c=combinationsWithSizeN(o,a),i=c.length;else{i=o.length;for(let e=0;e{if("nesting"!==o.type)return;let s=c[t][n];n++,"root"===s.type&&1===s.nodes.length&&(s=s.nodes[0]);const i=e().astSync(`:is(${s.toString()})`),l=isSimpleSelector(s.nodes[0]),a=isCompoundSelector(s.nodes[0]),p=isSimpleSelector(o),u=isCompoundSelector(o);if(l&&p)return void o.replaceWith(s.clone());if((l||a)&&(p||u)){const e=o.parent;return l&&"selector"===s.type?o.replaceWith(s.clone().nodes[0]):o.replaceWith(...s.clone().nodes),void(e&&e.nodes.length>1&&sortCompoundSelectorsInsideComplexSelector(e))}if(l){const e=o.parent;return o.replaceWith(s.clone().nodes[0]),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(a){const e=o.parent;return o.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(nestingIsFirstAndOnlyInSelectorWithEitherSpaceOrChildCombinator(o)){const e=o.parent;return o.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(nestingIsNotInsideCompoundSelector(o)){const e=o.parent;return o.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}const d=o.parent;r.noIsPseudoSelector?o.replaceWith(...s.clone().nodes):o.replaceWith(...i.clone({}).nodes),d&&sortCompoundSelectorsInsideComplexSelector(d)})),s.push(o.toString())}}return s}function isSimpleSelector(e){return"combinator"!==e.type&&!(e.parent&&e.parent.nodes.length>1)}function isCompoundSelector(e,t=null){if(isSimpleSelector(e))return!1;if(!e.parent)return!1;if(!!e.parent.nodes.find((e=>"combinator"===e.type)))return!1;return!(!!e.parent.nodes.find((e=>"nesting"===e.type))&&t&&!isCompoundSelector(t))}function nestingIsFirstAndOnlyInSelectorWithEitherSpaceOrChildCombinator(e){if(!e.parent)return!1;if(0!==e.parent.nodes.indexOf(e))return!1;for(let t=1;t"!==e.parent.nodes[t].value)return!1;return!0}function nestingIsNotInsideCompoundSelector(e){if(isSimpleSelector(e))return!0;if(!e.parent)return!1;for(let t=0;t{if("decl"===n.type)return t===r-1?void(t=r):(n.remove(),e.insertAfter(t,n),void(t=e.index(n)));if("atrule"===n.type&&"mixin"===n.name.toLowerCase()){let o=n.prev();for(;o;){if("rule"===o.type||"atrule"===o.type)return;o=o.prev()}return t===r-1?void(t=r):(n.remove(),e.insertAfter(t,n),void(t=e.index(n)))}if("comment"===n.type){const o=n.next();if(o&&("comment"===o.type||"rule"===o.type||"atrule"===o.type&&"mixin"!==o.name.toLowerCase()))return;return t===r-1?void(t=r):(n.remove(),e.insertAfter(t,n),void(t=e.index(n)))}}))}function transformRuleWithinRule(e,t,n,r){let o=[];try{o=mergeSelectors(t.selectors,e.selectors,r)}catch(r){return void e.warn(n,`Failed to parse selectors : "${t.selector}" / "${e.selector}" with message: "${r instanceof Error?r.message:r}"`)}if(!o.length)return;groupDeclarations(t),shiftNodesBeforeParent(e,t),e.selectors=o;"rule"===e.type&&"rule"===t.type&&e.selector===t.selector&&e.append(...t.nodes),cleanupParent(t)}function isValidRuleWithinRule(e){return e.selectors.every((e=>-1===e.indexOf("|")))}function comma(e){const t=[];let n="",r=!1,o=0,s=!1,i=!1;for(const l of e)i?i=!1:"\\"===l?i=!0:s?l===s&&(s=!1):'"'===l||"'"===l?s=l:"("===l?o+=1:")"===l?o>0&&(o-=1):0===o&&","===l&&(r=!0),r?(""!==n&&t.push(n.trim()),n="",r=!1):n+=l;return t.push(n.trim()),t}function transformNestRuleWithinRule(e,t,n,r,o){let s=[];try{s=mergeSelectors(t.selectors,comma(e.params),o)}catch(r){return void e.warn(n,`Failed to parse selectors : "${t.selector}" / "${e.params}" with message: "${r instanceof Error?r.message:r}"`)}if(!s.length)return;shiftNodesBeforeParent(e,t);const i=t.clone().removeAll().append(e.nodes);i.raws.semicolon=!0,i.selectors=s,e.replaceWith(i),cleanupParent(t),r(i,n,o)}function isValidNestRuleWithinRule(e){return comma(e.params).every((e=>e.split("&").length>=2&&-1===e.indexOf("|")))}var o=["container","document","media","supports","layer","starting-style"];function atruleWithinRule(e,t,n,r,o){if(groupDeclarations(t),shiftNodesBeforeParent(e,t),e.nodes){const s=t.clone().removeAll().append(e.nodes);e.append(s),cleanupParent(t),r(s,n,o)}else cleanupParent(t)}function isAtruleWithinRule(e){return o.includes(e.name)}function transformAtruleWithinAtrule(e,t){var n,r;groupDeclarations(t),shiftNodesBeforeParent(e,t),e.params=(n=t.params,r=e.params,comma(n).map((e=>comma(r).map((t=>`${e} and ${t}`)).join(", "))).join(", ")),cleanupParent(t)}function isAtruleWithinAtrule(e,t){return o.includes(e.name)&&e.name===t.name}function isAtRule(e){return e&&"atrule"===e.type}function isNestRule(e){return e&&isAtRule(e)&&"nest"===e.name}function isRule(e){return e&&"rule"===e.type}function walk(e,t,n){e.each((r=>{const o=r.parent;isNestRule(r)&&!n.silenceAtNestWarning&&e.warn(t,`\`@nest\` was removed from the CSS Nesting specification and will be removed from PostCSS Nesting in the next major version.\nChange \`@nest ${r.params} {}\` to \`${r.params} {}\` to migrate to the latest standard.`),isRule(r)&&isRule(o)&&isValidRuleWithinRule(r)?transformRuleWithinRule(r,o,t,n):isNestRule(r)&&isRule(o)&&isValidNestRuleWithinRule(r)?transformNestRuleWithinRule(r,o,t,walk,n):isAtRule(r)&&isRule(o)&&isAtruleWithinRule(r)?atruleWithinRule(r,o,t,walk,n):isAtRule(r)&&isAtRule(o)&&isAtruleWithinAtrule(r,o)&&transformAtruleWithinAtrule(r,o),"nodes"in r&&r.nodes.length&&walk(r,t,n)}))}const creator=e=>{const t=Object.assign({noIsPseudoSelector:!1,silenceAtNestWarning:!1},e);return{postcssPlugin:"postcss-nesting",Rule(e,{result:n}){walk(e,n,t),e.selector.includes("&")&&ersandToScope(e,n)}}};creator.postcss=!0;export{creator as default}; +import e from"postcss-selector-parser";import{selectorSpecificity as t}from"@csstools/selector-specificity";const n=e.pseudo({value:":is"});function sortCompoundSelectorsInsideComplexSelector(t){if(!t||!t.nodes)return;const o=[];let r=[];for(let s=0;s"tag"===e.type))){const o=n.clone({}),r=t.nodes[s];r.replaceWith(o),o.append(e.selector({nodes:[r],value:void 0}))}r.push(t.nodes[s])}else o.push(r),o.push([t.nodes[s]]),r=[];o.push(r);const s=[];for(let e=0;e"selector"===e.type&&"selector"===t.type&&e.nodes.length&&t.nodes.length?selectorTypeOrder(e.nodes[0])-selectorTypeOrder(t.nodes[0]):"selector"===e.type&&e.nodes.length?selectorTypeOrder(e.nodes[0])-selectorTypeOrder(t):"selector"===t.type&&t.nodes.length?selectorTypeOrder(e)-selectorTypeOrder(t.nodes[0]):selectorTypeOrder(e)-selectorTypeOrder(t)));for(let e=0;e=0;e--)s[e].remove(),t.prepend(s[e])}function selectorTypeOrder(t){return e.isPseudoElement(t)?o.pseudoElement:o[t.type]}const o={universal:0,tag:1,pseudoElement:2,id:3,class:4,attribute:5,pseudo:6,selector:7,string:8,root:9,comment:10};function ampersandToScope(t,n){let o,r=t.parent;for(;r;){if("rule"===r.type)return;r=r.parent}try{o=e().astSync(t.selector)}catch(e){return void t.warn(n,`Failed to parse selector : "${t.selector}" with message: "${e instanceof Error?e.message:e}"`)}o&&(o.walkNesting((t=>{const n=t.parent;t.replaceWith(e.pseudo({value:":scope"})),n&&sortCompoundSelectorsInsideComplexSelector(n)})),t.selector=o.toString())}function cleanupParent(e){if(!e.nodes.length)return void e.remove();const t=e.nodes.filter((e=>"comment"===e.type));t.length===e.nodes.length&&e.replaceWith(...t)}function shiftNodesBeforeParent(e,t){const n=t.index(e);if(n){const e=t.cloneBefore().removeAll().append(t.nodes.slice(0,n));e.raws.semicolon=!0,cleanupParent(e)}t.before(e),t.raws.semicolon=!0}function combinationsWithSizeN(e,t){if(t<2)throw new Error("n must be greater than 1");if(e.length<2)throw new Error("s must be greater than 1");if(Math.pow(e.length,t)>1e4)throw new Error("Too many combinations when trying to resolve a nested selector with lists, reduce the complexity of your selectors");const n=[];for(let e=0;e=0;s--){let t=n[s];if(t>=e.length){if(t=0,n[s]=0,0===s)return o;n[s-1]+=1}r[s]=e[t]}o.push(r),n[n.length-1]++}}function nodesAreEquallySpecific(n){const o=n.map((t=>e().astSync(t))).map((e=>t(e))),r=o[0];for(let e=1;ee().astSync(t))):[e().astSync(`:is(${t.join(",")})`)];const s=[];for(let t=0;t{"nesting"===e.type&&(n=!0)}));const o=t.nodes[0];let r=!1;o.each((e=>"combinator"===e.type&&(r=!0,!1))),n?r&&o.insertBefore(o.at(0),e.nesting({})):(o.insertBefore(o.at(0),e.combinator({value:" "})),o.insertBefore(o.at(0),e.nesting({}))),i=t.toString()}let c=[],a=0;if(e().astSync(i).walkNesting((()=>{a++})),a>1&&r.length>1)c=combinationsWithSizeN(r,a),l=c.length;else{l=r.length;for(let e=0;e{if("nesting"!==r.type)return;let s=c[t][n];n++,"root"===s.type&&1===s.nodes.length&&(s=s.nodes[0]);const l=e().astSync(`:is(${s.toString()})`),i=isSimpleSelector(s.nodes[0]),a=isCompoundSelector(s.nodes[0]),p=isSimpleSelector(r),u=isCompoundSelector(r);if(i&&p)return void r.replaceWith(s.clone());if((i||a)&&(p||u)){const e=r.parent;return i&&"selector"===s.type?r.replaceWith(s.clone().nodes[0]):r.replaceWith(...s.clone().nodes),void(e&&e.nodes.length>1&&sortCompoundSelectorsInsideComplexSelector(e))}if(i){const e=r.parent;return r.replaceWith(s.clone().nodes[0]),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(a){const e=r.parent;return r.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(nestingIsFirstAndOnlyInSelectorWithEitherSpaceOrChildCombinator(r)){const e=r.parent;return r.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}if(nestingIsNotInsideCompoundSelector(r)){const e=r.parent;return r.replaceWith(...s.clone().nodes),void(e&&sortCompoundSelectorsInsideComplexSelector(e))}const d=r.parent;o.noIsPseudoSelector?r.replaceWith(...s.clone().nodes):r.replaceWith(...l.clone({}).nodes),d&&sortCompoundSelectorsInsideComplexSelector(d)})),s.push(r.toString())}}return s}function isSimpleSelector(e){return"combinator"!==e.type&&!(e.parent&&e.parent.nodes.length>1)}function isCompoundSelector(e,t=null){if(isSimpleSelector(e))return!1;if(!e.parent)return!1;if(!!e.parent.nodes.find((e=>"combinator"===e.type)))return!1;return!(!!e.parent.nodes.find((e=>"nesting"===e.type))&&t&&!isCompoundSelector(t))}function nestingIsFirstAndOnlyInSelectorWithEitherSpaceOrChildCombinator(e){if(!e.parent)return!1;if(0!==e.parent.nodes.indexOf(e))return!1;for(let t=1;t"!==e.parent.nodes[t].value)return!1;return!0}function nestingIsNotInsideCompoundSelector(e){if(isSimpleSelector(e))return!0;if(!e.parent)return!1;for(let t=0;t{if(isDeclarationLike(e,n.length>0))t.push(e);else{if("comment"===e.type){let o=e.next();for(;o&&"comment"===o.type;)o=o.next();if(isDeclarationLike(o,n.length>0))return void t.push(e)}n.push(e)}})),e.removeAll(),t.forEach((t=>{e.append(t)})),n.forEach((t=>{e.append(t)}))}function isDeclarationLike(e,t){return!!e&&("decl"===e.type||"atrule"===e.type&&"mixin"===e.name.toLowerCase()&&!t)}function transformRuleWithinRule(e,t,n,o){let r=[];try{r=mergeSelectors(t.selectors,e.selectors,o)}catch(o){return void e.warn(n,`Failed to parse selectors : "${t.selector}" / "${e.selector}" with message: "${o instanceof Error?o.message:o}"`)}if(!r.length)return;groupDeclarations(t),shiftNodesBeforeParent(e,t),e.selectors=r;"rule"===e.type&&"rule"===t.type&&e.selector===t.selector&&e.append(...t.nodes),cleanupParent(t)}function isValidRuleWithinRule(e){return e.selectors.every((e=>-1===e.indexOf("|")))}function comma(e){const t=[];let n="",o=!1,r=0,s=!1,l=!1;for(const i of e)l?l=!1:"\\"===i?l=!0:s?i===s&&(s=!1):'"'===i||"'"===i?s=i:"("===i?r+=1:")"===i?r>0&&(r-=1):0===r&&","===i&&(o=!0),o?(""!==n&&t.push(n.trim()),n="",o=!1):n+=i;return t.push(n.trim()),t}function transformNestRuleWithinRule(e,t,n,o,r){let s=[];try{s=mergeSelectors(t.selectors,comma(e.params),r)}catch(o){return void e.warn(n,`Failed to parse selectors : "${t.selector}" / "${e.params}" with message: "${o instanceof Error?o.message:o}"`)}if(!s.length)return;shiftNodesBeforeParent(e,t);const l=t.clone().removeAll().append(e.nodes);l.raws.semicolon=!0,l.selectors=s,e.replaceWith(l),cleanupParent(t),o(l,n,r)}function isValidNestRuleWithinRule(e){return comma(e.params).every((e=>e.split("&").length>=2&&-1===e.indexOf("|")))}var r=["container","document","media","supports","layer","starting-style"];function atruleWithinRule(e,t,n,o,r){if(groupDeclarations(t),shiftNodesBeforeParent(e,t),e.nodes){const s=t.clone().removeAll().append(e.nodes);e.append(s),cleanupParent(t),o(s,n,r)}else cleanupParent(t)}function isAtruleWithinRule(e){return r.includes(e.name)}function transformAtruleWithinAtrule(e,t){var n,o;groupDeclarations(t),shiftNodesBeforeParent(e,t),e.params=(n=t.params,o=e.params,comma(n).map((e=>comma(o).map((t=>`${e} and ${t}`)).join(", "))).join(", ")),cleanupParent(t)}function isAtruleWithinAtrule(e,t){return r.includes(e.name)&&e.name===t.name}function isAtRule(e){return e&&"atrule"===e.type}function isNestRule(e){return e&&isAtRule(e)&&"nest"===e.name}function isRule(e){return e&&"rule"===e.type}function walk(e,t,n){e.each((o=>{const r=o.parent;isNestRule(o)&&!n.silenceAtNestWarning&&e.warn(t,`\`@nest\` was removed from the CSS Nesting specification and will be removed from PostCSS Nesting in the next major version.\nChange \`@nest ${o.params} {}\` to \`${o.params} {}\` to migrate to the latest standard.`),isRule(o)&&isRule(r)&&isValidRuleWithinRule(o)?transformRuleWithinRule(o,r,t,n):isNestRule(o)&&isRule(r)&&isValidNestRuleWithinRule(o)?transformNestRuleWithinRule(o,r,t,walk,n):isAtRule(o)&&isRule(r)&&isAtruleWithinRule(o)?atruleWithinRule(o,r,t,walk,n):isAtRule(o)&&isAtRule(r)&&isAtruleWithinAtrule(o,r)&&transformAtruleWithinAtrule(o,r),"nodes"in o&&o.nodes.length&&walk(o,t,n)}))}const creator=e=>{const t=Object.assign({noIsPseudoSelector:!1,silenceAtNestWarning:!1},e);return{postcssPlugin:"postcss-nesting",Rule(e,{result:n}){walk(e,n,t),e.selector.includes("&")&&ersandToScope(e,n)}}};creator.postcss=!0;export{creator as default}; diff --git a/plugins/postcss-nesting/src/lib/group-declarations.ts b/plugins/postcss-nesting/src/lib/group-declarations.ts index f1e91d8bb..1b881e756 100644 --- a/plugins/postcss-nesting/src/lib/group-declarations.ts +++ b/plugins/postcss-nesting/src/lib/group-declarations.ts @@ -9,60 +9,54 @@ export default function groupDeclarations(node: Container) { // For the purpose of determining the Order Of Appearance, // nested style rules and nested conditional group rules are considered to come after their parent rule. - let indexOfLastDeclarationInFirstDeclarationList = -1; + const declarationLikeThings: Array = []; + const ruleLikeThings: Array = []; - node.each((child, index) => { - if (child.type === 'decl') { - if (indexOfLastDeclarationInFirstDeclarationList === index - 1) { - indexOfLastDeclarationInFirstDeclarationList = index; - return; - } - - child.remove(); - node.insertAfter(indexOfLastDeclarationInFirstDeclarationList, child); - indexOfLastDeclarationInFirstDeclarationList = node.index(child); + node.each((child) => { + if (isDeclarationLike(child, ruleLikeThings.length > 0)) { + declarationLikeThings.push(child); return; } - if (child.type === 'atrule' && child.name.toLowerCase() === 'mixin') { - let prev = child.prev(); - // We assume that - // - a mixin after declarations will resolve to more declarations - // - a mixin after rules or at-rules will resolve to more rules or at-rules - while (prev) { - if ((prev.type === 'rule' || prev.type === 'atrule')) { - return; - } - - prev = prev.prev(); + if (child.type === 'comment') { + let next = child.next(); + while (next && next.type === 'comment') { + next = next.next(); } - if (indexOfLastDeclarationInFirstDeclarationList === index - 1) { - indexOfLastDeclarationInFirstDeclarationList = index; + if (isDeclarationLike(next, ruleLikeThings.length > 0)) { + declarationLikeThings.push(child); return; } - - child.remove(); - node.insertAfter(indexOfLastDeclarationInFirstDeclarationList, child); - indexOfLastDeclarationInFirstDeclarationList = node.index(child); - return; } - if (child.type === 'comment') { - const next = child.next(); - if (next && (next.type === 'comment' || next.type === 'rule' || (next.type === 'atrule' && next.name.toLowerCase() !== 'mixin'))) { - return; - } + ruleLikeThings.push(child); + }); - if (indexOfLastDeclarationInFirstDeclarationList === index - 1) { - indexOfLastDeclarationInFirstDeclarationList = index; - return; - } + node.removeAll(); - child.remove(); - node.insertAfter(indexOfLastDeclarationInFirstDeclarationList, child); - indexOfLastDeclarationInFirstDeclarationList = node.index(child); - return; - } + declarationLikeThings.forEach((child) => { + node.append(child); }); + + ruleLikeThings.forEach((child) => { + node.append(child); + }); +} + +function isDeclarationLike(node: ChildNode | undefined, didSeeRuleLikeThings: boolean): boolean { + if (!node) { + return false; + } + + if (node.type === 'decl') { + return true; + } + + // We assume that + // - a mixin after declarations will resolve to declarations + // - a mixin after rules or at-rules will resolve to rules or at-rules + return node.type === 'atrule' && + node.name.toLowerCase() === 'mixin' && + !didSeeRuleLikeThings; } diff --git a/plugins/postcss-nesting/test/_tape.mjs b/plugins/postcss-nesting/test/_tape.mjs index e8c7d4e8a..cdf523256 100644 --- a/plugins/postcss-nesting/test/_tape.mjs +++ b/plugins/postcss-nesting/test/_tape.mjs @@ -27,6 +27,25 @@ const mixinPluginDeclaration = () => { mixinPluginDeclaration.postcss = true; +const mixinPluginNestedRules = () => { + return { + postcssPlugin: 'mixin', + AtRule: { + mixin(node, { postcss }) { + if (node.params === 'alpha') { + node.replaceWith(postcss.parse('@mixin alpha-1; @mixin alpha-2; & { color: white; }', {from : 'mixin.css'})); + } else if (node.params === 'alpha-1') { + node.replaceWith(postcss.parse('color: blue;', {from : 'mixin.css'})); + } else if (node.params === 'alpha-2') { + node.replaceWith(postcss.parse('display: flex;', {from : 'mixin.css'})); + } + }, + }, + }; +}; + +mixinPluginNestedRules.postcss = true; + postcssTape(plugin)({ 'basic': { message: 'supports basic usage', @@ -168,6 +187,10 @@ postcssTape(plugin)({ noIsPseudoSelector: true, }, }, + 'mixin-nested-rules': { + message: 'supports mixin with nested rules', + plugins: [mixinPluginNestedRules(), plugin()], + }, 'spec-examples': { message: 'supports all spec examples', }, diff --git a/plugins/postcss-nesting/test/at-nest.expect.css b/plugins/postcss-nesting/test/at-nest.expect.css index a56ab074d..79f9ee615 100644 --- a/plugins/postcss-nesting/test/at-nest.expect.css +++ b/plugins/postcss-nesting/test/at-nest.expect.css @@ -1019,8 +1019,6 @@ article { This declaration is preserved */ color: red; - - /* valid! */ } article { @@ -1030,3 +1028,5 @@ article { article.foo { color: yellow; } + +/* valid! */ diff --git a/plugins/postcss-nesting/test/at-nest.no-is-pseudo-selector.expect.css b/plugins/postcss-nesting/test/at-nest.no-is-pseudo-selector.expect.css index bd1d54208..7cbe80b1e 100644 --- a/plugins/postcss-nesting/test/at-nest.no-is-pseudo-selector.expect.css +++ b/plugins/postcss-nesting/test/at-nest.no-is-pseudo-selector.expect.css @@ -1019,8 +1019,6 @@ article { This declaration is preserved */ color: red; - - /* valid! */ } article { @@ -1030,3 +1028,5 @@ article { article.foo { color: yellow; } + +/* valid! */ diff --git a/plugins/postcss-nesting/test/at-nest.silent.expect.css b/plugins/postcss-nesting/test/at-nest.silent.expect.css index a56ab074d..79f9ee615 100644 --- a/plugins/postcss-nesting/test/at-nest.silent.expect.css +++ b/plugins/postcss-nesting/test/at-nest.silent.expect.css @@ -1019,8 +1019,6 @@ article { This declaration is preserved */ color: red; - - /* valid! */ } article { @@ -1030,3 +1028,5 @@ article { article.foo { color: yellow; } + +/* valid! */ diff --git a/plugins/postcss-nesting/test/mixin-nested-rules.css b/plugins/postcss-nesting/test/mixin-nested-rules.css new file mode 100644 index 000000000..8e4693d49 --- /dev/null +++ b/plugins/postcss-nesting/test/mixin-nested-rules.css @@ -0,0 +1,6 @@ +a { + & b { + @mixin alpha; + display: inline-flex; + } +} diff --git a/plugins/postcss-nesting/test/mixin-nested-rules.expect.css b/plugins/postcss-nesting/test/mixin-nested-rules.expect.css new file mode 100644 index 000000000..792d1cabc --- /dev/null +++ b/plugins/postcss-nesting/test/mixin-nested-rules.expect.css @@ -0,0 +1,5 @@ + + a b {color: blue;display: flex; + display: inline-flex; + } +a b { color: white; } diff --git a/plugins/postcss-nesting/test/mixin-rule.expect.css b/plugins/postcss-nesting/test/mixin-rule.expect.css index a00c7325e..9e3451130 100644 --- a/plugins/postcss-nesting/test/mixin-rule.expect.css +++ b/plugins/postcss-nesting/test/mixin-rule.expect.css @@ -5,10 +5,10 @@ a .in.deep { color: blue; } -/* a comment */ - f g { color: red; } +/* a comment */ + f .in.deep { color: blue; } diff --git a/plugins/postcss-nesting/test/mixin-rule.no-is-pseudo-selector.expect.css b/plugins/postcss-nesting/test/mixin-rule.no-is-pseudo-selector.expect.css index a00c7325e..9e3451130 100644 --- a/plugins/postcss-nesting/test/mixin-rule.no-is-pseudo-selector.expect.css +++ b/plugins/postcss-nesting/test/mixin-rule.no-is-pseudo-selector.expect.css @@ -5,10 +5,10 @@ a .in.deep { color: blue; } -/* a comment */ - f g { color: red; } +/* a comment */ + f .in.deep { color: blue; } diff --git a/plugins/postcss-nesting/test/spec-examples.expect.css b/plugins/postcss-nesting/test/spec-examples.expect.css index 76a6bff88..d9a7a4f4f 100644 --- a/plugins/postcss-nesting/test/spec-examples.expect.css +++ b/plugins/postcss-nesting/test/spec-examples.expect.css @@ -376,8 +376,6 @@ article { This declaration is preserved */ color: red; - - /* valid! */ } article { @@ -387,3 +385,5 @@ article { article.foo { color: yellow; } + +/* valid! */ diff --git a/plugins/postcss-nesting/test/spec-examples.no-is-pseudo-selector.expect.css b/plugins/postcss-nesting/test/spec-examples.no-is-pseudo-selector.expect.css index 0b937ab4a..7f4030cb2 100644 --- a/plugins/postcss-nesting/test/spec-examples.no-is-pseudo-selector.expect.css +++ b/plugins/postcss-nesting/test/spec-examples.no-is-pseudo-selector.expect.css @@ -376,8 +376,6 @@ article { This declaration is preserved */ color: red; - - /* valid! */ } article { @@ -387,3 +385,5 @@ article { article.foo { color: yellow; } + +/* valid! */