Skip to content

Commit

Permalink
Allow order to be a function for custom ordering
Browse files Browse the repository at this point in the history
Breaking changes:
No custom order JSON file can be provided anymore instead a function is 
expected.
The default sorting order is renamed to 'alphabetical'.

Closes #64
  • Loading branch information
Siilwyn committed Dec 16, 2019
1 parent 6c05241 commit a3cb4b3
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 36 deletions.
69 changes: 40 additions & 29 deletions src/index.js
@@ -1,36 +1,41 @@
'use strict';

const { readFile } = require('fs');
const { readFile } = require('fs').promises;
const path = require('path');
const { promisify } = require('util');

const postcss = require('postcss');
const timsort = require('timsort').sort;

const builtInOrders = [
'alphabetical',
'concentric-css',
'smacss',
];

module.exports = postcss.plugin(
'css-declaration-sorter',
(options = {}) => css => {
let sortOrderPath;

// Use included sorting order if order is passed and not alphabetically
if (options.order && options.order !== 'alphabetically') {
sortOrderPath =
path.join(__dirname, '../orders/', options.order) + '.json';
} else if (options.customOrder) {
sortOrderPath = options.customOrder;
} else {
// Fallback to the default sorting order
return processCss(css, 'alphabetically');
}
({ order = 'alphabetical' } = {}) => css => {
if (typeof order === 'function')
return processCss({ css, comparator: order });

if (!builtInOrders.includes(order))
return Promise.reject(
Error([
`Invalid built-in order '${order}' provided.`,
`Available built-in orders are: ${builtInOrders}`,
].join('\n'))
);

if (order === 'alphabetical')
return Promise.resolve(processCss({ css, order }));

// Load in the array containing the order from a JSON file
return promisify(readFile)(sortOrderPath).then(data =>
processCss(css, JSON.parse(data))
);
return readFile(path.join(__dirname, '..', 'orders', order) + '.json')
.then(data => processCss({ css, order: JSON.parse(data) }));
}
);

function processCss (css, sortOrder) {
function processCss ({ css, order, comparator }) {
const comments = [];
const rulesCache = [];

Expand Down Expand Up @@ -82,7 +87,7 @@ function processCss (css, sortOrder) {

// Perform a sort once all comment nodes are removed
rulesCache.forEach(nodes => {
sortCssDecls(nodes, sortOrder);
sortCssDeclarations({ nodes, order, comparator });
});

// Add comments back to the nodes they are paired with
Expand All @@ -94,29 +99,35 @@ function processCss (css, sortOrder) {
}

// Sort CSS declarations alphabetically or using the set sorting order
function sortCssDecls (cssDecls, sortOrder) {
if (sortOrder === 'alphabetically') {
timsort(cssDecls, (a, b) => {
function sortCssDeclarations ({ nodes, order, comparator }) {
if (order === 'alphabetical') {
comparator = defaultComparator;
}

if (comparator) {
timsort(nodes, (a, b) => {
if (a.type === 'decl' && b.type === 'decl') {
return comparator(a.prop, b.prop);
} else {
return compareDifferentType(a, b);
}
});
} else {
timsort(cssDecls, (a, b) => {
}

else {
timsort(nodes, (a, b) => {
if (a.type === 'decl' && b.type === 'decl') {
const aIndex = sortOrder.indexOf(a.prop);
const bIndex = sortOrder.indexOf(b.prop);
return comparator(aIndex, bIndex);
const aIndex = order.indexOf(a.prop);
const bIndex = order.indexOf(b.prop);
return defaultComparator(aIndex, bIndex);
} else {
return compareDifferentType(a, b);
}
});
}
}

function comparator (a, b) {
function defaultComparator (a, b) {
return a === b ? 0 : a < b ? -1 : 1;
}

Expand Down
4 changes: 0 additions & 4 deletions tests/custom-order.json

This file was deleted.

12 changes: 9 additions & 3 deletions tests/test.js
Expand Up @@ -40,13 +40,19 @@ const sortOrderTests = [
message: 'Sort alphabetically with a defined order.',
fixture: 'a{flex: 0;border: 0;}',
expected: 'a{border: 0;flex: 0;}',
options: { order: 'alphabetically' },
options: { order: 'alphabetical' },
},
{
message: 'Sort according to custom order.',
message: 'Sort according to custom order, changed.',
fixture: 'a{border: 0;z-index: 0;}',
expected: 'a{z-index: 0;border: 0;}',
options: { customOrder: 'tests/custom-order.json' },
options: { order: () => -1 },
},
{
message: 'Sort according to custom order, retained.',
fixture: 'a{border: 0;z-index: 0;}',
expected: 'a{border: 0;z-index: 0;}',
options: { order: () => 1 },
},
{
message: 'Sort according to SMACSS.',
Expand Down

0 comments on commit a3cb4b3

Please sign in to comment.