Skip to content

Commit 59eb4bf

Browse files
committed
simplify the algorithm and test cases
1 parent deecc42 commit 59eb4bf

17 files changed

+62
-103
lines changed

plugins/postcss-nesting/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
### Unreleased (patch)
44

5-
- Fix reorder of declarations inside nested `@mixin` rules
5+
- Fix order of final CSS with complex usage of both nesting and mixins, by @pciarach
66

77
### 12.0.3
88

plugins/postcss-nesting/dist/index.cjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

plugins/postcss-nesting/dist/index.mjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { ChildNode, Container } from 'postcss';
2-
import { isAtRule, isMixinRule, isRule } from "./is-type-of-rule";
32

43
export default function groupDeclarations(node: Container<ChildNode>) {
54
// https://drafts.csswg.org/css-nesting/#mixing
@@ -10,60 +9,54 @@ export default function groupDeclarations(node: Container<ChildNode>) {
109
// For the purpose of determining the Order Of Appearance,
1110
// nested style rules and nested conditional group rules are considered to come after their parent rule.
1211

13-
let indexOfLastDeclarationInFirstDeclarationList = -1;
12+
const declarationLikeThings: Array<ChildNode> = [];
13+
const ruleLikeThings: Array<ChildNode> = [];
1414

15-
node.each((child, index) => {
16-
if (child.type === 'decl') {
17-
if (indexOfLastDeclarationInFirstDeclarationList === index - 1) {
18-
indexOfLastDeclarationInFirstDeclarationList = index;
19-
return;
20-
}
21-
22-
child.remove();
23-
node.insertAfter(indexOfLastDeclarationInFirstDeclarationList, child);
24-
indexOfLastDeclarationInFirstDeclarationList = node.index(child);
15+
node.each((child) => {
16+
if (isDeclarationLike(child, ruleLikeThings.length > 0)) {
17+
declarationLikeThings.push(child);
2518
return;
2619
}
2720

28-
if (isMixinRule(child)) {
29-
let prev = child.prev();
30-
// We assume that
31-
// - a mixin after declarations will resolve to more declarations
32-
// - a mixin after rules or at-rules will resolve to more rules or at-rules (except after another mixin)
33-
while (prev) {
34-
if ((prev.type === 'rule' || (isAtRule(prev) && !isMixinRule(prev)))) {
35-
return;
36-
}
37-
38-
prev = prev.prev();
21+
if (child.type === 'comment') {
22+
let next = child.next();
23+
while (next && next.type === 'comment') {
24+
next = next.next();
3925
}
4026

41-
if (indexOfLastDeclarationInFirstDeclarationList === index - 1) {
42-
indexOfLastDeclarationInFirstDeclarationList = index;
27+
if (isDeclarationLike(next, ruleLikeThings.length > 0)) {
28+
declarationLikeThings.push(child);
4329
return;
4430
}
45-
46-
child.remove();
47-
node.insertAfter(indexOfLastDeclarationInFirstDeclarationList, child);
48-
indexOfLastDeclarationInFirstDeclarationList = node.index(child);
49-
return;
5031
}
5132

52-
if (child.type === 'comment') {
53-
const next = child.next();
54-
if (next && (next.type === 'comment' || isRule(next) || (isAtRule(next) && !isMixinRule(next)))) {
55-
return;
56-
}
33+
ruleLikeThings.push(child);
34+
});
5735

58-
if (indexOfLastDeclarationInFirstDeclarationList === index - 1) {
59-
indexOfLastDeclarationInFirstDeclarationList = index;
60-
return;
61-
}
36+
node.removeAll();
6237

63-
child.remove();
64-
node.insertAfter(indexOfLastDeclarationInFirstDeclarationList, child);
65-
indexOfLastDeclarationInFirstDeclarationList = node.index(child);
66-
return;
67-
}
38+
declarationLikeThings.forEach((child) => {
39+
node.append(child);
6840
});
41+
42+
ruleLikeThings.forEach((child) => {
43+
node.append(child);
44+
});
45+
}
46+
47+
function isDeclarationLike(node: ChildNode | undefined, didSeeRuleLikeThings: boolean): boolean {
48+
if (!node) {
49+
return false;
50+
}
51+
52+
if (node.type === 'decl') {
53+
return true;
54+
}
55+
56+
// We assume that
57+
// - a mixin after declarations will resolve to declarations
58+
// - a mixin after rules or at-rules will resolve to rules or at-rules
59+
return node.type === 'atrule' &&
60+
node.name.toLowerCase() === 'mixin' &&
61+
!didSeeRuleLikeThings;
6962
}

plugins/postcss-nesting/src/lib/is-type-of-rule.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ export function isNestRule(node?: Node): node is AtRule {
88
return node && isAtRule(node) && node.name === 'nest';
99
}
1010

11-
export function isMixinRule(node?: Node): node is AtRule {
12-
return node && isAtRule(node) && node.name.toLowerCase() === 'mixin';
13-
}
14-
1511
export function isRule(node?: Node): node is Rule {
1612
return node && node.type === 'rule';
1713
}

plugins/postcss-nesting/test/_tape.mjs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ const mixinPluginNestedRules = () => {
3232
postcssPlugin: 'mixin',
3333
AtRule: {
3434
mixin(node, { postcss }) {
35-
if (node.params === 'nestedMixins') {
36-
node.replaceWith(postcss.parse('@mixin mixinWithDecl; @mixin mixinToOverride; &:disabled { color: white; }', {from : 'mixin.css'}));
37-
} else if (node.params === 'mixinWithDecl') {
35+
if (node.params === 'alpha') {
36+
node.replaceWith(postcss.parse('@mixin alpha-1; @mixin alpha-2; & { color: white; }', {from : 'mixin.css'}));
37+
} else if (node.params === 'alpha-1') {
3838
node.replaceWith(postcss.parse('color: blue;', {from : 'mixin.css'}));
39-
} else if (node.params === 'mixinToOverride') {
39+
} else if (node.params === 'alpha-2') {
4040
node.replaceWith(postcss.parse('display: flex;', {from : 'mixin.css'}));
4141
}
4242
},
@@ -191,10 +191,6 @@ postcssTape(plugin)({
191191
message: 'supports mixin with nested rules',
192192
plugins: [mixinPluginNestedRules(), plugin()],
193193
},
194-
'mixin-nested-rules-after-media': {
195-
message: 'supports mixin with nested rules',
196-
plugins: [mixinPluginNestedRules(), plugin()],
197-
},
198194
'spec-examples': {
199195
message: 'supports all spec examples',
200196
},

plugins/postcss-nesting/test/at-nest.expect.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,8 +1019,6 @@ article {
10191019
This declaration is preserved
10201020
*/
10211021
color: red;
1022-
1023-
/* valid! */
10241022
}
10251023

10261024
article {
@@ -1030,3 +1028,5 @@ article {
10301028
article.foo {
10311029
color: yellow;
10321030
}
1031+
1032+
/* valid! */

plugins/postcss-nesting/test/at-nest.no-is-pseudo-selector.expect.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,8 +1019,6 @@ article {
10191019
This declaration is preserved
10201020
*/
10211021
color: red;
1022-
1023-
/* valid! */
10241022
}
10251023

10261024
article {
@@ -1030,3 +1028,5 @@ article {
10301028
article.foo {
10311029
color: yellow;
10321030
}
1031+
1032+
/* valid! */

plugins/postcss-nesting/test/at-nest.silent.expect.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,8 +1019,6 @@ article {
10191019
This declaration is preserved
10201020
*/
10211021
color: red;
1022-
1023-
/* valid! */
10241022
}
10251023

10261024
article {
@@ -1030,3 +1028,5 @@ article {
10301028
article.foo {
10311029
color: yellow;
10321030
}
1031+
1032+
/* valid! */

plugins/postcss-nesting/test/mixin-nested-rules-after-media.css

Lines changed: 0 additions & 10 deletions
This file was deleted.

plugins/postcss-nesting/test/mixin-nested-rules-after-media.expect.css

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
a {
2-
color: yellow;
3-
42
& b {
5-
@mixin nestedMixins;
3+
@mixin alpha;
64
display: inline-flex;
75
}
86
}
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
a {
2-
color: yellow;
3-
}
4-
a b {color: blue;display: flex;
1+
2+
a b {color: blue;display: flex;
53
display: inline-flex;
64
}
7-
a b:disabled { color: white; }
5+
a b { color: white; }

plugins/postcss-nesting/test/mixin-rule.expect.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
a .in.deep { color: blue; }
77

8-
/* a comment */
9-
108
f g {
119
color: red;
1210
}
1311

12+
/* a comment */
13+
1414
f .in.deep { color: blue; }

plugins/postcss-nesting/test/mixin-rule.no-is-pseudo-selector.expect.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
a .in.deep { color: blue; }
77

8-
/* a comment */
9-
108
f g {
119
color: red;
1210
}
1311

12+
/* a comment */
13+
1414
f .in.deep { color: blue; }

plugins/postcss-nesting/test/spec-examples.expect.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,6 @@ article {
376376
This declaration is preserved
377377
*/
378378
color: red;
379-
380-
/* valid! */
381379
}
382380

383381
article {
@@ -387,3 +385,5 @@ article {
387385
article.foo {
388386
color: yellow;
389387
}
388+
389+
/* valid! */

plugins/postcss-nesting/test/spec-examples.no-is-pseudo-selector.expect.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,6 @@ article {
376376
This declaration is preserved
377377
*/
378378
color: red;
379-
380-
/* valid! */
381379
}
382380

383381
article {
@@ -387,3 +385,5 @@ article {
387385
article.foo {
388386
color: yellow;
389387
}
388+
389+
/* valid! */

0 commit comments

Comments
 (0)