Skip to content

Commit 54806f0

Browse files
committed
Initial commit
1 parent 4168024 commit 54806f0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1047
-0
lines changed

.editorconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 4
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true
10+
11+
[*.{json,yml}]
12+
indent_size = 2
13+
14+
[*.pcss]
15+
indent_style = tab
16+
end_of_line = lf
17+
charset = utf-8
18+
trim_trailing_whitespace = true
19+
insert_final_newline = true

.eslintrc

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
{
2+
"rules": {
3+
"space-before-function-paren": [2, { "named": "never" }],
4+
"no-shadow-restricted-names": [2],
5+
"computed-property-spacing": [2],
6+
"no-empty-character-class": [2],
7+
"no-irregular-whitespace": [2],
8+
"no-unexpected-multiline": [2],
9+
"no-multiple-empty-lines": [2],
10+
"space-return-throw-case": [2],
11+
"no-constant-condition": [2],
12+
"no-extra-boolean-cast": [2],
13+
"no-inner-declarations": [2],
14+
"no-this-before-super": [2],
15+
"no-use-before-define": [2],
16+
"no-array-constructor": [2],
17+
"object-curly-spacing": [2, "always"],
18+
"no-floating-decimal": [2],
19+
"no-warning-comments": [2],
20+
"handle-callback-err": [2],
21+
"no-unneeded-ternary": [2],
22+
"operator-assignment": [2],
23+
"space-before-blocks": [2],
24+
"no-native-reassign": [2],
25+
"no-trailing-spaces": [2],
26+
"operator-linebreak": [2, "after"],
27+
"consistent-return": [2],
28+
"no-duplicate-case": [2],
29+
"no-invalid-regexp": [2],
30+
"no-negated-in-lhs": [2],
31+
"constructor-super": [2],
32+
"no-nested-ternary": [2],
33+
"no-extend-native": [2],
34+
"block-scoped-var": [2],
35+
"no-control-regex": [2],
36+
"no-sparse-arrays": [2],
37+
"no-throw-literal": [2],
38+
"no-return-assign": [2],
39+
"no-const-assign": [2],
40+
"no-class-assign": [2],
41+
"no-extra-parens": [2],
42+
"no-regex-spaces": [2],
43+
"no-implied-eval": [2],
44+
"no-useless-call": [2],
45+
"no-self-compare": [2],
46+
"no-octal-escape": [2],
47+
"no-new-wrappers": [2],
48+
"no-process-exit": [2],
49+
"no-catch-shadow": [2],
50+
"linebreak-style": [2],
51+
"space-infix-ops": [2],
52+
"space-unary-ops": [2],
53+
"no-cond-assign": [2],
54+
"no-func-assign": [2],
55+
"no-unreachable": [2],
56+
"accessor-pairs": [2],
57+
"no-empty-label": [2],
58+
"no-fallthrough": [2],
59+
"no-path-concat": [2],
60+
"no-new-require": [2],
61+
"no-spaced-func": [2],
62+
"no-unused-vars": [2],
63+
"spaced-comment": [2],
64+
"no-delete-var": [2],
65+
"comma-spacing": [2],
66+
"no-extra-semi": [2],
67+
"no-extra-bind": [2],
68+
"arrow-spacing": [2],
69+
"prefer-spread": [2],
70+
"no-new-object": [2],
71+
"no-multi-str": [2],
72+
"semi-spacing": [2],
73+
"no-lonely-if": [2],
74+
"dot-notation": [2],
75+
"dot-location": [2, "property"],
76+
"comma-dangle": [2, "never"],
77+
"no-dupe-args": [2],
78+
"no-dupe-keys": [2],
79+
"no-ex-assign": [2],
80+
"no-obj-calls": [2],
81+
"valid-typeof": [2],
82+
"default-case": [2],
83+
"no-redeclare": [2],
84+
"no-div-regex": [2],
85+
"no-sequences": [2],
86+
"no-label-var": [2],
87+
"comma-style": [2],
88+
"brace-style": [2],
89+
"no-debugger": [2],
90+
"quote-props": [2, "consistent-as-needed"],
91+
"no-iterator": [2],
92+
"no-new-func": [2],
93+
"key-spacing": [2],
94+
"complexity": [2],
95+
"new-parens": [2],
96+
"no-eq-null": [2],
97+
"no-bitwise": [2],
98+
"wrap-iife": [2],
99+
"no-caller": [2],
100+
"use-isnan": [2],
101+
"no-labels": [2],
102+
"no-shadow": [2],
103+
"camelcase": [2],
104+
"eol-last": [2],
105+
"no-octal": [2],
106+
"no-empty": [2],
107+
"no-alert": [2],
108+
"no-proto": [2],
109+
"no-undef": [2],
110+
"no-eval": [2],
111+
"no-with": [2],
112+
"no-void": [2],
113+
"new-cap": [2],
114+
"eqeqeq": [2],
115+
"no-new": [2],
116+
"quotes": [2, "single"],
117+
"indent": [2, 4],
118+
"semi": [2, "always"],
119+
"yoda": [2, "never"]
120+
},
121+
"ecmaFeatures": {
122+
"modules": true
123+
},
124+
"env": {
125+
"node": true,
126+
"es6": true
127+
}
128+
}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
npm-debug.log
3+
test/**/*.actual.css
4+
dev/

.npmignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.gitignore
2+
3+
node_modules/
4+
npm-debug.log
5+
6+
test/
7+
.travis.yml

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
sudo: false
2+
language: node_js
3+
node_js:
4+
- stable
5+
- "4"
6+
- "0.12"

LICENSE.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License (MIT)
2+
3+
Copyright 2015 Aleks Hudochenkov <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# PostCSS Sort [![Build Status][ci-img]][ci]
2+
3+
[PostCSS] plugin to sort rules content with specified order.
4+
5+
[PostCSS]: https://github.com/postcss/postcss
6+
[ci-img]: https://travis-ci.org/hudochenkov/postcss-sort.svg
7+
[ci]: https://travis-ci.org/hudochenkov/postcss-sort
8+
9+
```css
10+
.foo {
11+
/* Input example */
12+
}
13+
```
14+
15+
```css
16+
.foo {
17+
/* Output example */
18+
}
19+
```
20+
21+
## Usage
22+
23+
```js
24+
postcss([ require('postcss-sort') ])
25+
```
26+
27+
See [PostCSS] docs for examples for your environment.

index.js

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
var postcss = require('postcss');
2+
3+
function getSortOrder(options) {
4+
if (options.hasOwnProperty('sort-order') && Array.isArray(options['sort-order'])) {
5+
var sortOrder = options['sort-order'];
6+
var order = {};
7+
8+
if (typeof sortOrder[0] === 'string') {
9+
sortOrder.forEach(function (prop, propIndex) {
10+
order[prop] = {
11+
group: 0,
12+
prop: propIndex
13+
};
14+
});
15+
} else {
16+
sortOrder.forEach(function (group, groupIndex) {
17+
group.forEach(function (prop, propIndex) {
18+
order[prop] = {
19+
group: groupIndex,
20+
prop: propIndex
21+
};
22+
});
23+
});
24+
}
25+
26+
return order;
27+
}
28+
29+
return false;
30+
}
31+
32+
function cloneWithStyle(node) {
33+
var nodeClone = node.clone();
34+
nodeClone.raws = node.raws;
35+
36+
if (nodeClone.raws.before) {
37+
nodeClone.raws.before = nodeClone.raws.before.replace(/\n\s*\n/g, '\n').replace(/\r\n\s*\r\n/g, '\r\n');
38+
}
39+
40+
return nodeClone;
41+
}
42+
43+
function cleanLineBreaks(node) {
44+
if (node.raws.before) {
45+
node.raws.before = node.raws.before.replace(/\r\n\s*\r\n/g, '\r\n').replace(/\n\s*\n/g, '\n');
46+
}
47+
48+
return node;
49+
}
50+
51+
module.exports = postcss.plugin('postcss-sort', function (opts) {
52+
opts = opts || {};
53+
54+
return function (css) {
55+
var order = getSortOrder(opts);
56+
57+
// Index to place the nodes that shouldn't be sorted
58+
var lastGroupIndex = order['...'] ? order['...'].group : Infinity;
59+
var lastPropertyIndex = order['...'] ? order['...'].prop : Infinity;
60+
61+
css.walk(function (rule) {
62+
if ((rule.type === 'rule' || rule.type === 'atrule') && rule.nodes && rule.nodes.length) {
63+
64+
var processed = [];
65+
66+
rule.each(function (node, index) {
67+
var sortName = null;
68+
69+
if (node.type === 'comment') {
70+
return;
71+
} else if (node.type === 'decl') {
72+
sortName = node.prop;
73+
74+
// if property start with $ and letters it's a variable
75+
if (/^\$[\w-]+/.test(node.prop)) {
76+
sortName = '$variable';
77+
}
78+
} else if (node.type === 'atrule') {
79+
sortName = '@atrule';
80+
81+
var atruleName = '@' + node.name;
82+
83+
if (order[atruleName]) {
84+
sortName = atruleName;
85+
}
86+
87+
// if atRule has a name like @mixin name or @include name, we can sort by this name too
88+
var atruleParameter = /^[\w-]+/.exec(node.params);
89+
90+
if (atruleParameter && atruleParameter.length) {
91+
var sortNameExtended = sortName + ' ' + atruleParameter[0];
92+
93+
if (order[sortNameExtended]) {
94+
sortName = sortNameExtended;
95+
}
96+
}
97+
} else if (node.type === 'rule') {
98+
sortName = '>child';
99+
}
100+
101+
// If the declaration's property is in order's list, save its
102+
// group and property indices. Otherwise set them to 10000, so
103+
// declaration appears at the bottom of a sorted list:
104+
var orderProperty = order[sortName];
105+
106+
node.groupIndex = orderProperty && orderProperty.group > -1 ? orderProperty.group : lastGroupIndex;
107+
node.propertyIndex = orderProperty && orderProperty.prop > -1 ? orderProperty.prop : lastPropertyIndex;
108+
node.initialIndex = index;
109+
110+
if (node.prev() && node.prev().type === 'comment') {
111+
var previousNode = node.prev();
112+
113+
if (previousNode.raws.before && previousNode.raws.before.indexOf('\n') > -1) {
114+
previousNode.groupIndex = node.groupIndex;
115+
previousNode.propertyIndex = node.propertyIndex;
116+
previousNode.initialIndex = index - 1;
117+
118+
var previousNodeClone = cloneWithStyle(previousNode);
119+
120+
processed.push(previousNodeClone);
121+
}
122+
}
123+
124+
processed.push(node);
125+
126+
if (node.next() && node.next().type === 'comment') {
127+
var nextNode = node.next();
128+
129+
if (nextNode.raws.before && nextNode.raws.before.indexOf('\n') < 0) {
130+
nextNode.groupIndex = node.groupIndex;
131+
nextNode.propertyIndex = node.propertyIndex;
132+
nextNode.initialIndex = index + 1;
133+
processed.push(nextNode);
134+
}
135+
}
136+
});
137+
138+
// Sort declarations saved for sorting:
139+
processed.sort(function (a, b) {
140+
// If a's group index is higher than b's group index, in a sorted
141+
// list a appears after b:
142+
if (a.groupIndex !== b.groupIndex) return a.groupIndex - b.groupIndex;
143+
144+
// If a and b have the same group index, and a's property index is
145+
// higher than b's property index, in a sorted list a appears after
146+
// b:
147+
if (a.propertyIndex !== b.propertyIndex) return a.propertyIndex - b.propertyIndex;
148+
149+
// If a and b have the same group index and the same property index,
150+
// in a sorted list they appear in the same order they were in
151+
// original array:
152+
return a.initialIndex - b.initialIndex;
153+
});
154+
155+
rule.removeAll();
156+
rule.append(processed);
157+
158+
rule.each(function (node) {
159+
node = cleanLineBreaks(node);
160+
161+
var prevNode = node.prev();
162+
163+
if (prevNode && node.groupIndex > prevNode.groupIndex) {
164+
if (node.raws.before) {
165+
node.raws.before = '\n' + node.raws.before;
166+
}
167+
}
168+
});
169+
170+
}
171+
});
172+
};
173+
});

0 commit comments

Comments
 (0)