Skip to content

Commit

Permalink
Added option to preserve at-rule order
Browse files Browse the repository at this point in the history
Fix #30
  • Loading branch information
erikthalen authored and MadLittleMods committed Jun 17, 2019
1 parent fe5c821 commit a205e5a
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 8 deletions.
7 changes: 7 additions & 0 deletions README.md
Expand Up @@ -394,6 +394,13 @@ postcss([
```


### `preserveAtRulesOrder` (default: `false`)

Keeps your at-rules like media queries in the order to defined them.

Ideally, this would be defaulted to `true` and it will be in the next major version. All of the tests expecations need to be updated and probably just drop support for `preserveAtRulesOrder: false`


# Quick Reference/Notes

- This plugin was spawned out of a [discussion on the `cssnext` repo](https://github.com/cssnext/cssnext/issues/99).
Expand Down
7 changes: 5 additions & 2 deletions index.js
Expand Up @@ -65,7 +65,10 @@ var defaults = {
variables: {},
// Preserve variables injected via JS with the `variables` option above
// before serializing to CSS (`false` will remove these variables from output)
preserveInjectedVariables: true
preserveInjectedVariables: true,
// Will write media queries in the same order as in the original file.
// Currently defaulted to false for legacy behavior. We can update to `true` in a major version
preserveAtRulesOrder: false
};

module.exports = postcss.plugin('postcss-css-variables', function(options) {
Expand Down Expand Up @@ -249,7 +252,7 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
ruleToWorkOn.nodes.slice(0).forEach(function(node) {
if(node.type === 'decl') {
var decl = node;
resolveDecl(decl, map, opts.preserve, logResolveValueResult);
resolveDecl(decl, map, opts.preserve, opts.preserveAtRulesOrder, logResolveValueResult);
}
});
});
Expand Down
17 changes: 12 additions & 5 deletions lib/resolve-decl.js
Expand Up @@ -71,8 +71,9 @@ function eachMapItemDependencyOfDecl(variablesUsedList, map, decl, cb) {

// Resolve the decl with the computed value
// Also add in any media queries that change the value as necessary
function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/logResolveValueResult) {
function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/preserveAtRulesOrder, /*optional*/logResolveValueResult) {
shouldPreserve = shouldPreserve || false;
preserveAtRulesOrder = preserveAtRulesOrder || false;

// Make it chainable
var _logResolveValueResult = function(valueResults) {
Expand All @@ -93,6 +94,7 @@ function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/logResol
// Resolve the cascade dependencies
// Now find any at-rule declarations that need to be added below each rule
//console.log('resolveDecl 2');
var previousAtRuleNode;
eachMapItemDependencyOfDecl(valueResults.variablesUsed, map, decl, function(mimicDecl, mapItem) {
var ruleClone = shallowCloneNode(decl.parent);
var declClone = decl.clone();
Expand Down Expand Up @@ -129,14 +131,19 @@ function resolveDecl(decl, map, /*optional*/shouldPreserve, /*optional*/logResol
currentAtRuleNode = currentAtRuleNode.parent;
}

// Put the atRuleStructure after the declaration's rule
decl.parent.parent.insertAfter(decl.parent, parentAtRuleNode);
// Put the first atRuleStructure after the declaration's rule,
// and after that, put them right after the previous one
decl.parent.parent.insertAfter(preserveAtRulesOrder && previousAtRuleNode || decl.parent, parentAtRuleNode);

// Save referance of previous atRuleStructure
previousAtRuleNode = parentAtRuleNode
}
else {
ruleClone.selector = mimicDecl.parent.selector;

// Put the atRuleStructure after the declaration's rule
decl.parent.parent.insertAfter(decl.parent, ruleClone);
// Put the first atRuleStructure after the declaration's rule,
// and after that, put them right after the previous one
decl.parent.parent.insertAfter(preserveAtRulesOrder && previousAtRuleNode || decl.parent, ruleClone);
}
});

Expand Down
21 changes: 21 additions & 0 deletions test/fixtures/media-query-nested-preserver-rule-order.css
@@ -0,0 +1,21 @@
:root {
--width: 150px;
}

@media print {
@media (min-width: 1000px) {
:root {
--width: 300px;
}

@media (min-width: 1250px) {
:root {
--width: 450px;
}
}
}
}

.box {
width: var(--width);
}
26 changes: 26 additions & 0 deletions test/fixtures/media-query-nested-preserver-rule-order.expected.css
@@ -0,0 +1,26 @@
.box {
width: 150px;
}

@media print {

@media (min-width: 1000px) {

.box{
width: 300px;
}
}
}

@media print {

@media (min-width: 1000px) {

@media (min-width: 1250px) {

.box {
width: 450px;
}
}
}
}
20 changes: 20 additions & 0 deletions test/fixtures/media-query-preserve-rule-order.css
@@ -0,0 +1,20 @@
:root {
--width: 150px;
}

@media (min-width: 1000px) {
:root {
--width: 300px;
}
}

@media (min-width: 1250px) {
:root {
--width: 450px;
}
}

.box {
width: var(--width);

}
15 changes: 15 additions & 0 deletions test/fixtures/media-query-preserve-rule-order.expected.css
@@ -0,0 +1,15 @@
.box {
width: 150px;
}

@media (min-width: 1000px) {
.box {
width: 300px;
}
}

@media (min-width: 1250px) {
.box {
width: 450px;
}
}
6 changes: 5 additions & 1 deletion test/test.js
Expand Up @@ -135,7 +135,11 @@ describe('postcss-css-variables', function() {
test('should add rule declaration of property in @media', 'media-query');
test('should add rule declaration of property in @support', 'support-directive');

test('should work with nested @media', 'media-query-nested');
test('should work with @media, preserving rule order', 'media-query-preserve-rule-order', { preserveAtRulesOrder: true });

test('should work with nested @media', 'media-query-nested', { preserveAtRulesOrder: false });
test('should work with nested @media, preserving rule order', 'media-query-nested-preserver-rule-order', { preserveAtRulesOrder: true });


test('should cascade to nested rules', 'cascade-on-nested-rules');

Expand Down

0 comments on commit a205e5a

Please sign in to comment.