Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

postcss-sorting

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss-sorting - npm Package Compare versions

Comparing version 1.6.1 to 1.7.0

configs/alphabetical.json

4

CHANGELOG.md

@@ -5,2 +5,6 @@ # Change Log

## 1.7.0
* Added `smacss` and `alphabetical` predefined configs.
* Under the hood refactoring.
## 1.6.1

@@ -7,0 +11,0 @@ * Fixed a regression in 1.6.0. Sort order with item like `@include media` didn't found rules like `@include media(">=desk") {}`.

347

index.js
var postcss = require('postcss');
var objectAssign = require('object-assign');
var path = require('path');
var fs = require('fs');
module.exports = postcss.plugin('postcss-sorting', function (opts) {
return function (css) {
plugin(css, opts);
};
});
function plugin(css, opts) {
// Verify options and use defaults if not specified
opts = verifyOptions(opts);
var enableSorting = true;
css.walk(function (node) {
if (node.type === 'comment' && node.parent.type === 'root') {
if (node.text === 'postcss-sorting: on') {
enableSorting = true;
} else if (node.text === 'postcss-sorting: off') {
enableSorting = false;
}
}
if (!enableSorting) {
return;
}
// Process only rules and atrules with nodes
if ((node.type === 'rule' || node.type === 'atrule') && node.nodes && node.nodes.length) {
// Nodes for sorting
var processed = [];
// Add indexes to nodes
node.each(function (childNode, index) {
processed = processMostNodes(childNode, index, opts, processed);
});
// Add last comments in the rule. Need this because last comments are not belonging to anything
node.each(function (childNode, index) {
processed = processLastComments(childNode, index, processed);
});
// Sort declarations saved for sorting
processed.sort(sortByIndexes);
// Replace rule content with sorted one
if (processed.length) {
node.removeAll();
node.append(processed);
}
// Taking care of empty lines
node.each(function (childNode) {
formatNodes(childNode, opts);
});
}
});
}
function verifyOptions(options) {

@@ -10,10 +68,12 @@ if (options === null || typeof options !== 'object') {

options['sort-order'] = options['sort-order'] || 'default';
options['empty-lines-between-children-rules'] = options['empty-lines-between-children-rules'] || 0;
options['empty-lines-between-media-rules'] = options['empty-lines-between-media-rules'] || 0;
options['preserve-empty-lines-between-children-rules'] = options['preserve-empty-lines-between-children-rules'] || false;
options['empty-lines-before-comment'] = options['empty-lines-before-comment'] || 0;
options['empty-lines-after-comment'] = options['empty-lines-after-comment'] || 0;
var defaultOptions = {
'sort-order': 'default',
'empty-lines-between-children-rules': 0,
'empty-lines-between-media-rules': 0,
'preserve-empty-lines-between-children-rules': false,
'empty-lines-before-comment': 0,
'empty-lines-after-comment': 0,
};
return options;
return objectAssign({}, defaultOptions, options);
}

@@ -116,13 +176,13 @@

switch (node.type) {
case 'decl':
return (/^(\$|--)[\w-]+/).test(node.prop) ? '$variable' : node.prop;
case 'decl':
return (/^(\$|--)[\w-]+/).test(node.prop) ? '$variable' : node.prop;
case 'atrule':
return getAtruleSortName(node, order);
case 'atrule':
return getAtruleSortName(node, order);
case 'rule':
return '>child';
case 'rule':
return '>child';
default:
return null;
default:
return null;
}

@@ -228,170 +288,137 @@ }

module.exports = postcss.plugin('postcss-sorting', function (opts) {
// Verify options and use defaults if not specified
opts = verifyOptions(opts);
function processMostNodes(node, index, opts, processedNodes) {
if (node.type === 'comment') {
if (index === 0 && node.raws.before.indexOf('\n') === -1) {
node.ruleComment = true; // need this flag to not append this comment twice
return function (css) {
var order = getSortOrderFromOptions(opts);
var linesBetweenChildrenRules = getLinesBetweenRulesFromOptions('children', opts);
var linesBetweenMediaRules = getLinesBetweenRulesFromOptions('media', opts);
var preserveLinesBetweenChildren = opts['preserve-empty-lines-between-children-rules'];
var linesBeforeComment = opts['empty-lines-before-comment'];
var linesAfterComment = opts['empty-lines-after-comment'];
var enableSorting = true;
return processedNodes.concat(node);
}
css.walk(function (rule) {
if (rule.type === 'comment' && rule.parent.type === 'root') {
if (rule.text === 'postcss-sorting: on') {
enableSorting = true;
} else if (rule.text === 'postcss-sorting: off') {
enableSorting = false;
}
}
return processedNodes;
}
if (!enableSorting) {
return;
}
var order = getSortOrderFromOptions(opts);
// Process only rules and atrules with nodes
if ((rule.type === 'rule' || rule.type === 'atrule') && rule.nodes && rule.nodes.length) {
// Nodes for sorting
var processed = [];
node = addIndexesToNode(node, index, order);
rule.each(function (node, index) {
if (node.type === 'comment') {
if (index === 0 && node.raws.before.indexOf('\n') === -1) {
node.ruleComment = true; // need this flag to not append this comment twice
// If comment on separate line before node, use node's indexes for comment
var commentsBefore = fetchAllCommentsBeforeNode([], node.prev(), node);
processed.push(node);
}
// If comment on same line with the node and node, use node's indexes for comment
var commentsAfter = fetchAllCommentsAfterNode([], node.next(), node);
return;
}
return processedNodes.concat(commentsBefore, node, commentsAfter);
}
node = addIndexesToNode(node, index, order);
function processLastComments(node, index, processedNodes) {
if (node.type === 'comment' && !node.hasOwnProperty('groupIndex') && !node.ruleComment) {
node.groupIndex = Infinity;
node.propertyIndex = Infinity;
node.initialIndex = index;
// If comment on separate line before node, use node's indexes for comment
var commentsBefore = fetchAllCommentsBeforeNode([], node.prev(), node);
return processedNodes.concat(node);
}
// If comment on same line with the node and node, use node's indexes for comment
var commentsAfter = fetchAllCommentsAfterNode([], node.next(), node);
return processedNodes;
}
processed = processed.concat(commentsBefore, node, commentsAfter);
});
function sortByIndexes(a, b) {
// If a's group index is higher than b's group index, in a sorted
// list a appears after b:
if (a.groupIndex !== b.groupIndex) {
return a.groupIndex - b.groupIndex;
}
// Add last comments in the rule. Need this because last comments are not belonging to anything
rule.each(function (node, index) {
if (node.type === 'comment' && !node.hasOwnProperty('groupIndex') && !node.ruleComment) {
node.groupIndex = Infinity;
node.propertyIndex = Infinity;
node.initialIndex = index;
// If a and b have the same group index, and a's property index is
// higher than b's property index, in a sorted list a appears after
// b:
if (a.propertyIndex !== b.propertyIndex) {
return a.propertyIndex - b.propertyIndex;
}
processed.push(node);
}
});
// If a and b have the same group index and the same property index,
// in a sorted list they appear in the same order they were in
// original array:
return a.initialIndex - b.initialIndex;
}
// Sort declarations saved for sorting:
processed.sort(function (a, b) {
// If a's group index is higher than b's group index, in a sorted
// list a appears after b:
if (a.groupIndex !== b.groupIndex) {
return a.groupIndex - b.groupIndex;
}
function formatNodes(node, opts) {
var linesBetweenChildrenRules = getLinesBetweenRulesFromOptions('children', opts);
var linesBetweenMediaRules = getLinesBetweenRulesFromOptions('media', opts);
var preserveLinesBetweenChildren = opts['preserve-empty-lines-between-children-rules'];
var linesBeforeComment = opts['empty-lines-before-comment'];
var linesAfterComment = opts['empty-lines-after-comment'];
// If a and b have the same group index, and a's property index is
// higher than b's property index, in a sorted list a appears after
// b:
if (a.propertyIndex !== b.propertyIndex) {
return a.propertyIndex - b.propertyIndex;
}
// don't remove empty lines if they are should be preserved
if (
!(
preserveLinesBetweenChildren &&
(node.type === 'rule' || node.type === 'comment') &&
node.prev() &&
getApplicableNode('rule', node)
)
) {
node = cleanLineBreaks(node);
}
// If a and b have the same group index and the same property index,
// in a sorted list they appear in the same order they were in
// original array:
return a.initialIndex - b.initialIndex;
});
var prevNode = node.prev();
if (processed.length) {
rule.removeAll();
rule.append(processed);
}
if (prevNode && node.raws.before) {
if (node.groupIndex > prevNode.groupIndex) {
node.raws.before = createLineBreaks(1) + node.raws.before;
}
// Remove all empty lines and add empty lines between groups
rule.each(function (node) {
// don't remove empty lines if they are should be preserved
if (
!(
preserveLinesBetweenChildren &&
(node.type === 'rule' || node.type === 'comment') &&
node.prev() &&
getApplicableNode('rule', node)
)
) {
node = cleanLineBreaks(node);
}
var applicableNode;
var prevNode = node.prev();
// Insert empty lines between children classes
if (node.type === 'rule' && linesBetweenChildrenRules > 0) {
// between rules can be comments, so empty lines should be added to first comment between rules, rather than to rule
applicableNode = getApplicableNode('rule', node);
if (prevNode && node.raws.before) {
if (node.groupIndex > prevNode.groupIndex) {
node.raws.before = createLineBreaks(1) + node.raws.before;
}
if (applicableNode) {
// add lines only if source empty lines not preserved, or if there are less empty lines then should be
if (
!preserveLinesBetweenChildren ||
(
preserveLinesBetweenChildren &&
countEmptyLines(applicableNode.raws.before) < linesBetweenChildrenRules
)
) {
applicableNode.raws.before = createLineBreaks(linesBetweenChildrenRules - countEmptyLines(applicableNode.raws.before)) + applicableNode.raws.before;
}
}
}
var applicableNode;
// Insert empty lines between media rules
if (node.type === 'atrule' && node.name === 'media' && linesBetweenMediaRules > 0) {
// between rules can be comments, so empty lines should be added to first comment between rules, rather than to rule
applicableNode = getApplicableNode('atrule', node);
// Insert empty lines between children classes
if (node.type === 'rule' && linesBetweenChildrenRules > 0) {
// between rules can be comments, so empty lines should be added to first comment between rules, rather than to rule
applicableNode = getApplicableNode('rule', node);
if (applicableNode) {
applicableNode.raws.before = createLineBreaks(linesBetweenMediaRules - countEmptyLines(applicableNode.raws.before)) + applicableNode.raws.before;
}
}
if (applicableNode) {
// add lines only if source empty lines not preserved, or if there are less empty lines then should be
if (
!preserveLinesBetweenChildren ||
(
preserveLinesBetweenChildren &&
countEmptyLines(applicableNode.raws.before) < linesBetweenChildrenRules
)
) {
applicableNode.raws.before = createLineBreaks(linesBetweenChildrenRules - countEmptyLines(applicableNode.raws.before)) + applicableNode.raws.before;
}
}
}
// Insert empty lines before comment
if (
linesBeforeComment &&
node.type === 'comment' &&
(prevNode.type !== 'comment' || prevNode.raws.before.indexOf('\n') === -1) && // prevNode it's not a comment or it's an inline comment
node.raws.before.indexOf('\n') >= 0 && // this isn't an inline comment
countEmptyLines(node.raws.before) < linesBeforeComment
) {
node.raws.before = createLineBreaks(linesBeforeComment - countEmptyLines(node.raws.before)) + node.raws.before;
}
// Insert empty lines between media rules
if (node.type === 'atrule' && node.name === 'media' && linesBetweenMediaRules > 0) {
// between rules can be comments, so empty lines should be added to first comment between rules, rather than to rule
applicableNode = getApplicableNode('atrule', node);
if (applicableNode) {
applicableNode.raws.before = createLineBreaks(linesBetweenMediaRules - countEmptyLines(applicableNode.raws.before)) + applicableNode.raws.before;
}
}
// Insert empty lines before comment
if (
linesBeforeComment &&
node.type === 'comment' &&
(prevNode.type !== 'comment' || prevNode.raws.before.indexOf('\n') === -1) && // prevNode it's not a comment or it's an inline comment
node.raws.before.indexOf('\n') >= 0 && // this isn't an inline comment
countEmptyLines(node.raws.before) < linesBeforeComment
) {
node.raws.before = createLineBreaks(linesBeforeComment - countEmptyLines(node.raws.before)) + node.raws.before;
}
// Insert empty lines after comment
if (
linesAfterComment &&
node.type !== 'comment' &&
prevNode.type === 'comment' &&
prevNode.raws.before.indexOf('\n') >= 0 && // this isn't an inline comment
countEmptyLines(node.raws.before) < linesAfterComment
) {
node.raws.before = createLineBreaks(linesAfterComment - countEmptyLines(node.raws.before)) + node.raws.before;
}
}
});
}
});
};
});
// Insert empty lines after comment
if (
linesAfterComment &&
node.type !== 'comment' &&
prevNode.type === 'comment' &&
prevNode.raws.before.indexOf('\n') >= 0 && // this isn't an inline comment
countEmptyLines(node.raws.before) < linesAfterComment
) {
node.raws.before = createLineBreaks(linesAfterComment - countEmptyLines(node.raws.before)) + node.raws.before;
}
}
}
{
"name": "postcss-sorting",
"version": "1.6.1",
"version": "1.7.0",
"description": "PostCSS plugin to sort rules content with specified order.",

@@ -24,9 +24,9 @@ "keywords": [

"dependencies": {
"postcss": "^5.0.16"
"object-assign": "^4.1.0",
"postcss": "^5.1.2"
},
"devDependencies": {
"ava": "^0.13.0",
"eslint": "^2.8.0",
"postcss-less": "^0.8.0",
"postcss-scss": "^0.1.7"
"ava": "^0.16.0",
"eslint": "^3.4.0",
"postcss-scss": "^0.2.1"
},

@@ -33,0 +33,0 @@ "scripts": {

@@ -272,5 +272,7 @@ # PostCSS Sorting [![Build Status][ci-img]][ci]

* `default`
* `alphabetical`
* `zen`
* `csscomb`
* `yandex`
* `smacss`

@@ -277,0 +279,0 @@ Example: `{ "sort-order": "zen" }`

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc