# `replaceTimeUnits` controls replacing time units with shorter values; defaults to `on
# `replaceZeroUnits` controls replacing zero values with units; defaults to `on`
# `roundingPrecision` rounds pixel values to `N` decimal places; `off` disables rounding; defaults to `off`
+# `selectorsSortingMethod` denotes selector sorting method; can be `natural` or `standard`; defaults to `standard`
# `specialComments` denotes a number of /*! ... */ comments preserved; defaults to `all`
# `tidyAtRules` controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `on`
# `tidyBlockScopes` controls block scopes (e.g. `@media`) optimizing; defaults to `on`
replaceTimeUnits: true, // controls replacing time units with shorter values; defaults to `true`
replaceZeroUnits: true, // controls replacing zero values with units; defaults to `true`
roundingPrecision: false, // rounds pixel values to `N` decimal places; `false` disables rounding; defaults to `false`
+ selectorsSortingMethod: 'standard', // denotes selector sorting method; can be `natural` or `standard`; defaults to `standard`
specialComments: 'all', // denotes a number of /*! ... */ comments preserved; defaults to `all`
tidyAtRules: true, // controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `true`
tidyBlockScopes: true, // controls block scopes (e.g. `@media`) optimizing; defaults to `true`
console.log(' %> # `replaceTimeUnits` controls replacing time units with shorter values; defaults to `on');
console.log(' %> # `replaceZeroUnits` controls replacing zero values with units; defaults to `on`');
console.log(' %> # `roundingPrecision` rounds pixel values to `N` decimal places; `off` disables rounding; defaults to `off`');
+ console.log(' %> # `selectorsSortingMethod` denotes selector sorting method; can be `natural` or `standard`; defaults to `standard`');
console.log(' %> # `specialComments` denotes a number of /*! ... */ comments preserved; defaults to `all`');
console.log(' %> # `tidyAtRules` controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `on`');
console.log(' %> # `tidyBlockScopes` controls block scopes (e.g. `@media`) optimizing; defaults to `on`');
var shortenHex = require('./shorten-hex');
var shortenHsl = require('./shorten-hsl');
var shortenRgb = require('./shorten-rgb');
+var sortSelectors = require('./sort-selectors');
var tidyRules = require('./tidy-rules');
var tidyBlock = require('./tidy-block');
var tidyAtRule = require('./tidy-at-rule');
break;
case Token.RULE:
token[1] = levelOptions.tidySelectors ? tidyRules(token[1], !ie7Hack, adjacentSpace, beautify, context.warnings) : token[1];
+ token[1] = token[1].length > 1 ? sortSelectors(token[1], levelOptions.selectorsSortingMethod) : token[1];
optimizeBody(token[2], context);
afterRules = true;
break;
--- /dev/null
+var naturalCompare = require('../../utils/natural-compare');
+
+function naturalSorter(scope1, scope2) {
+ return naturalCompare(scope1[1], scope2[1]);
+}
+
+function standardSorter(scope1, scope2) {
+ return scope1[1] > scope2[1] ? 1 : -1;
+}
+
+function sortSelectors(selectors, method) {
+ var sorter;
+
+ switch (method) {
+ case 'natural':
+ sorter = naturalSorter;
+ break;
+ case 'standard':
+ sorter = standardSorter;
+ }
+
+ return selectors.sort(sorter);
+}
+
+module.exports = sortSelectors;
.replace(/="([a-zA-Z][a-zA-Z\d\-_]+)"/g, '=$1');
}
-function ruleSorter(s1, s2) {
- return s1[1] > s2[1] ? 1 : -1;
-}
-
function tidyRules(rules, removeUnsupported, adjacentSpace, beautify, warnings) {
var list = [];
var repeated = [];
list = [];
}
- return list.sort(ruleSorter);
+ return list;
}
module.exports = tidyRules;
var compactorOptimize = require('./compacting/optimize');
+var sortSelectors = require('../level-1/sort-selectors');
var tidyRules = require('../level-1/tidy-rules');
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+
var serializeBody = require('../../writer/one-time').body;
var serializeRules = require('../../writer/one-time').rules;
var lastToken = [null, [], []];
var options = context.options;
var adjacentSpace = options.compatibility.selectors.adjacentSpace;
+ var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod;
var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements) &&
isMergeable(serializeRules(lastToken[1]), mergeablePseudoClasses, mergeablePseudoElements)) {
lastToken[1] = tidyRules(lastToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings);
+ lastToken[1] = lastToken.length > 1 ? sortSelectors(lastToken[1], selectorsSortingMethod) : lastToken[1];
token[2] = [];
} else {
lastToken = token;
var isMergeable = require('./is-mergeable');
+var sortSelectors = require('../level-1/sort-selectors');
var tidyRules = require('../level-1/tidy-rules');
var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
var options = context.options;
var mergeSemantically = options.level[OptimizationLevel.Two].mergeSemantically;
var adjacentSpace = options.compatibility.selectors.adjacentSpace;
+ var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod;
var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
var candidates = {};
if (oldToken &&
isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements) &&
isMergeable(serializeRules(oldToken[1]), mergeablePseudoClasses, mergeablePseudoElements)) {
- token[1] = token[2].length > 0 ?
- tidyRules(oldToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings) :
- oldToken[1].concat(token[1]);
+
+ if (token[2].length > 0) {
+ token[1] = tidyRules(oldToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings);
+ token[1] = token[1].length > 1 ? sortSelectors(token[1], selectorsSortingMethod) : token[1];
+ } else {
+ token[1] = oldToken[1].concat(token[1]);
+ }
oldToken[2] = [];
candidates[candidateBody] = null;
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
]
}, { level: 1 })
)
+ .addBatch(
+ optimizerContext('selectors - sorting when tidySelectors is off', {
+ 'no numbers': [
+ '.block,.another-block,.one-more-block{color:red}',
+ '.another-block,.block,.one-more-block{color:red}'
+ ]
+ }, { level: { 1: { tidySelectors: false } } })
+ )
+ .addBatch(
+ optimizerContext('selectors - natural order', {
+ 'no numbers': [
+ '.block,.another-block,.one-more-block{color:red}',
+ '.another-block,.block,.one-more-block{color:red}'
+ ],
+ 'some numbers': [
+ '.block-3,.block-11,.block{color:red}',
+ '.block,.block-3,.block-11{color:red}'
+ ],
+ 'all numbers': [
+ '.block-3,.block-11,.block-1{color:red}',
+ '.block-1,.block-3,.block-11{color:red}'
+ ],
+ 'complex numbers': [
+ '.block-1__element-11,.block-1__element-2,.block-12__element-1,.block-3__element-1{color:red}',
+ '.block-1__element-2,.block-1__element-11,.block-3__element-1,.block-12__element-1{color:red}'
+ ],
+ }, { level: { 1: { selectorsSortingMethod: 'natural' } } })
+ )
.addBatch(
optimizerContext('selectors - ie8', {
'+html': [
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 0,
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: false,
replaceZeroUnits: false,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: false,
tidyBlockScopes: false,
replaceTimeUnits: false,
replaceZeroUnits: false,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: false,
tidyBlockScopes: false,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 0,
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 0,
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(3),
+ selectorsSortingMethod: 'standard',
specialComments: 0,
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
replaceTimeUnits: true,
replaceZeroUnits: true,
roundingPrecision: roundingPrecisionFrom(undefined),
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
'vw': 4,
'%': 4
},
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,
'vw': 5,
'%': 1
},
+ selectorsSortingMethod: 'standard',
specialComments: 'all',
tidyAtRules: true,
tidyBlockScopes: true,