Skip to content

Commit 0cdf35f

Browse files
committed
Add preserve-empty-lines-between-children-rules option #20
1 parent 6a961c9 commit 0cdf35f

9 files changed

+198
-6
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## 1.4.0
6+
* Added `preserve-empty-lines-between-children-rules`, which preserve empty lines between children rules and preserve empty lines for comments between children rules. #20
7+
58
## 1.3.1
69
* Fix adding additional empty line if both `empty-lines-between-children-rules` and `empty-lines-between-media-rules` are not 0. #19
710

README.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Also available as [Sublime Text plugin], [Atom plugin], and [VS Code plugin].
2929
* [Predefined configs](#predefined-configs)
3030
* [`empty-lines-between-children-rules`](#empty-lines-between-children-rules)
3131
* [`empty-lines-between-media-rules`](#empty-lines-between-media-rules)
32+
* [`preserve-empty-lines-between-children-rules`](#preserve-empty-lines-between-children-rules)
3233
* [Migration from CSSComb](#migration-from-csscomb)
3334
* [Usage](#usage)
3435
* [Text editor](#text-editor)
@@ -50,7 +51,8 @@ $ npm install postcss-sorting
5051
{
5152
"sort-order": "default",
5253
"empty-lines-between-children-rules": 0,
53-
"empty-lines-between-media-rules": 0
54+
"empty-lines-between-media-rules": 0,
55+
"preserve-empty-lines-between-children-rules": false
5456
}
5557
```
5658

@@ -342,6 +344,40 @@ Example: `{ "empty-lines-between-media-rules": 1, "sort-order": ["@media"] }`
342344
}
343345
```
344346

347+
### `preserve-empty-lines-between-children-rules`
348+
349+
Preserve empty lines between children rules and preserve empty lines for comments between children rules.
350+
351+
Acceptable value: `true`
352+
353+
Example: `{ "preserve-empty-lines-between-children-rules": true }`
354+
355+
```scss
356+
/* before */
357+
.block {
358+
&:before {}
359+
&:after {}
360+
361+
.element {}
362+
363+
/* comment */
364+
365+
.child {}
366+
}
367+
368+
/* after (nothing changed) */
369+
.block {
370+
&:before {}
371+
&:after {}
372+
373+
.element {}
374+
375+
/* comment */
376+
377+
.child {}
378+
}
379+
```
380+
345381
### Migration from CSSComb
346382

347383
If you used to use custom sorting order in [CSSComb] you can easily use this sorting order in PostCSS Sorting. `sort-order` option in this plugin is compatible with `sort-order` in CSSComb. Just copy `sort-order` value from CSSComb config to PostCSS Sorting config.

index.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ function verifyOptions(options) {
1010
options['sort-order'] = options['sort-order'] || 'default';
1111
options['empty-lines-between-children-rules'] = options['empty-lines-between-children-rules'] || 0;
1212
options['empty-lines-between-media-rules'] = options['empty-lines-between-media-rules'] || 0;
13+
options['preserve-empty-lines-between-children-rules'] = options['preserve-empty-lines-between-children-rules'] || false;
1314

1415
return options;
1516
}
@@ -157,8 +158,7 @@ function fetchAllCommentsBeforeNode(comments, previousNode, node, currentInitial
157158
previousNode.propertyIndex = node.propertyIndex;
158159
previousNode.initialIndex = currentInitialIndex - 0.0001;
159160

160-
var previousNodeClone = cleanLineBreaks(previousNode);
161-
var newComments = [previousNodeClone].concat(comments);
161+
var newComments = [previousNode].concat(comments);
162162

163163
return fetchAllCommentsBeforeNode(newComments, previousNode.prev(), node, previousNode.initialIndex);
164164
}
@@ -196,6 +196,16 @@ function getApplicableNode(lookFor, node) {
196196
return false;
197197
}
198198

199+
function countEmptyLines(str) {
200+
var lineBreaks = (str.match(/\n/g) || []).length;
201+
202+
if (lineBreaks > 0) {
203+
lineBreaks -= 1;
204+
}
205+
206+
return lineBreaks;
207+
}
208+
199209
module.exports = postcss.plugin('postcss-sorting', function (opts) {
200210
// Verify options and use defaults if not specified
201211
opts = verifyOptions(opts);
@@ -204,6 +214,7 @@ module.exports = postcss.plugin('postcss-sorting', function (opts) {
204214
var order = getSortOrderFromOptions(opts);
205215
var linesBetweenChildrenRules = getLinesBetweenRulesFromOptions('children', opts);
206216
var linesBetweenMediaRules = getLinesBetweenRulesFromOptions('media', opts);
217+
var preserveLinesBetweenChildren = opts['preserve-empty-lines-between-children-rules'];
207218

208219
css.walk(function (rule) {
209220
// Process only rules and atrules with nodes
@@ -268,7 +279,17 @@ module.exports = postcss.plugin('postcss-sorting', function (opts) {
268279

269280
// Remove all empty lines and add empty lines between groups
270281
rule.each(function (node) {
271-
node = cleanLineBreaks(node);
282+
// don't remove empty lines if they are should be preserved
283+
if (
284+
!(
285+
preserveLinesBetweenChildren &&
286+
(node.type === 'rule' || node.type === 'comment') &&
287+
node.prev() &&
288+
getApplicableNode('rule', node)
289+
)
290+
) {
291+
node = cleanLineBreaks(node);
292+
}
272293

273294
var prevNode = node.prev();
274295

@@ -285,7 +306,16 @@ module.exports = postcss.plugin('postcss-sorting', function (opts) {
285306
applicableNode = getApplicableNode('rule', node);
286307

287308
if (applicableNode) {
288-
applicableNode.raws.before = createLineBreaks(linesBetweenChildrenRules) + applicableNode.raws.before;
309+
// add lines only if source empty lines not preserved, or if there are less empty lines then should be
310+
if (
311+
!preserveLinesBetweenChildren ||
312+
(
313+
preserveLinesBetweenChildren &&
314+
countEmptyLines(applicableNode.raws.before) < linesBetweenChildrenRules
315+
)
316+
) {
317+
applicableNode.raws.before = createLineBreaks(linesBetweenChildrenRules) + applicableNode.raws.before;
318+
}
289319
}
290320
}
291321

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "postcss-sorting",
3-
"version": "1.3.1",
3+
"version": "1.4.0",
44
"description": "PostCSS plugin to sort rules content with specified order.",
55
"keywords": [
66
"postcss",
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.block {
2+
div {}
3+
/* comment 1 */
4+
section {}
5+
6+
7+
8+
9+
article {}
10+
11+
12+
/* comment 2 */
13+
14+
.child {}
15+
}
16+
.block {
17+
div {}
18+
/* comment 1 */
19+
section {}
20+
21+
22+
23+
24+
/* comment 2 */
25+
/* comment 3 */
26+
.child {}
27+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
.block {
2+
div {}
3+
4+
/* comment 1 */
5+
section {}
6+
7+
8+
9+
10+
article {}
11+
12+
13+
/* comment 2 */
14+
15+
.child {}
16+
}
17+
.block {
18+
div {}
19+
20+
/* comment 1 */
21+
section {}
22+
23+
24+
25+
26+
/* comment 2 */
27+
/* comment 3 */
28+
.child {}
29+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.block {
2+
div {}
3+
/* comment 1 */
4+
section {}
5+
6+
7+
8+
9+
article {}
10+
11+
12+
/* comment 2 */
13+
14+
.child {}
15+
}
16+
.block {
17+
div {}
18+
/* comment 1 */
19+
section {}
20+
21+
22+
23+
24+
/* comment 2 */
25+
/* comment 3 */
26+
.child {}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.block {
2+
div {}
3+
/* comment 1 */
4+
section {}
5+
6+
7+
8+
9+
article {}
10+
11+
12+
/* comment 2 */
13+
14+
.child {}
15+
}
16+
.block {
17+
div {}
18+
/* comment 1 */
19+
section {}
20+
21+
22+
23+
24+
/* comment 2 */
25+
/* comment 3 */
26+
.child {}
27+
}

test/test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,19 @@ test('Should not insert additional line between @media and children rules if the
239239
});
240240
});
241241

242+
test('Should preserve empty lines between children rules', t => {
243+
return run(t, 'preserve-empty-lines-between-children', {
244+
'preserve-empty-lines-between-children-rules': true
245+
});
246+
});
247+
248+
test('Should preserve empty lines between children rules and don\'t create unneeded empty lines if \'empty-lines-between-children-rules\' enabled', t => {
249+
return run(t, 'preserve-empty-lines-between-children-2', {
250+
'empty-lines-between-children-rules': 1,
251+
'preserve-empty-lines-between-children-rules': true
252+
});
253+
});
254+
242255
// test('Should sort LESS files', t => {
243256
// return run(t, 'less.less', {}, 'less');
244257
// });

0 commit comments

Comments
 (0)