stylelint-order 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -1
- package/README.md +9 -1
- package/index.js +1 -1
- package/package.json +23 -7
- package/rules/checkAlphabeticalOrder.js +4 -1
- package/rules/index.js +1 -1
- package/rules/order/calcAtRulePatternPriority.js +11 -2
- package/rules/order/checkOrder.js +12 -4
- package/rules/order/createExpectedOrder.js +4 -17
- package/rules/order/getDescription.js +1 -1
- package/rules/order/getOrderData.js +3 -7
- package/rules/order/index.js +1 -1
- package/rules/order/validatePrimaryOption.js +46 -30
- package/rules/properties-alphabetical-order/index.js +1 -1
- package/rules/properties-order/README.md +10 -12
- package/rules/properties-order/addEmptyLineBefore.js +3 -3
- package/rules/properties-order/checkEmptyLineBefore.js +3 -6
- package/rules/properties-order/checkNode.js +10 -16
- package/rules/properties-order/checkOrder.js +13 -15
- package/rules/properties-order/createExpectedOrder.js +2 -2
- package/rules/properties-order/createFlatOrder.js +1 -1
- package/rules/properties-order/index.js +5 -10
- package/rules/properties-order/validatePrimaryOption.js +27 -21
- package/utils/isCustomProperty.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
4
|
|
|
5
|
+
## 0.7.0
|
|
6
|
+
|
|
7
|
+
* Specified `stylelint` in `peerDependencies` rather in `dependencies`. Following [stylelint's plugin guide](https://github.com/stylelint/stylelint/blob/master/docs/developer-guide/plugins.md#peer-dependencies).
|
|
8
|
+
|
|
5
9
|
## 0.6.0
|
|
6
10
|
|
|
7
|
-
*
|
|
11
|
+
* Migrated to `stylelint@8.0.0`.
|
|
8
12
|
|
|
9
13
|
## 0.5.0
|
|
10
14
|
* Added autofixing for every rule! Please read docs before using this feature, because each rule has some caveats. stylelint 7.11+ is required for this feature.
|
package/README.md
CHANGED
|
@@ -4,8 +4,16 @@ A plugin pack of order related linting rules for [stylelint]. Every rule support
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
+
First, install [stylelint]:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npm install stylelint --save-dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then install plugin:
|
|
14
|
+
|
|
7
15
|
```
|
|
8
|
-
npm install stylelint-order
|
|
16
|
+
npm install stylelint-order --save-dev
|
|
9
17
|
```
|
|
10
18
|
|
|
11
19
|
## Usage
|
package/index.js
CHANGED
|
@@ -4,7 +4,7 @@ const createPlugin = require('stylelint').createPlugin;
|
|
|
4
4
|
const namespace = require('./utils').namespace;
|
|
5
5
|
const rules = require('./rules');
|
|
6
6
|
|
|
7
|
-
const rulesPlugins = Object.keys(rules).map(
|
|
7
|
+
const rulesPlugins = Object.keys(rules).map(ruleName => {
|
|
8
8
|
return createPlugin(namespace(ruleName), rules[ruleName]);
|
|
9
9
|
});
|
|
10
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stylelint-order",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "A collection of order related linting rules for stylelint.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"stylelint-plugin",
|
|
@@ -28,21 +28,37 @@
|
|
|
28
28
|
"main": "index.js",
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"lodash": "^4.17.4",
|
|
31
|
-
"postcss": "^6.0.
|
|
32
|
-
"postcss-sorting": "^3.0.
|
|
31
|
+
"postcss": "^6.0.11",
|
|
32
|
+
"postcss-sorting": "^3.0.2"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
33
35
|
"stylelint": "^8.0.0"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
36
|
-
"eslint": "
|
|
37
|
-
"eslint-config-hudochenkov": "
|
|
38
|
-
"
|
|
38
|
+
"eslint": "~4.7.2",
|
|
39
|
+
"eslint-config-hudochenkov": "~2.0.0",
|
|
40
|
+
"eslint-config-prettier": "^2.6.0",
|
|
41
|
+
"eslint-plugin-prettier": "^2.3.1",
|
|
42
|
+
"husky": "^0.14.3",
|
|
43
|
+
"jest": "^21.1.0",
|
|
44
|
+
"lint-staged": "^4.2.2",
|
|
45
|
+
"prettier": "^1.7.0",
|
|
46
|
+
"stylelint": "^8.1.1"
|
|
39
47
|
},
|
|
40
48
|
"scripts": {
|
|
49
|
+
"precommit": "lint-staged",
|
|
41
50
|
"pretest": "eslint .",
|
|
42
51
|
"test": "jest",
|
|
43
52
|
"jest": "jest",
|
|
44
53
|
"watch": "jest --watch",
|
|
45
|
-
"coverage": "jest --coverage"
|
|
54
|
+
"coverage": "jest --coverage",
|
|
55
|
+
"fix": "npm run pretest -- --fix"
|
|
56
|
+
},
|
|
57
|
+
"lint-staged": {
|
|
58
|
+
"*.js": [
|
|
59
|
+
"npm run fix",
|
|
60
|
+
"git add"
|
|
61
|
+
]
|
|
46
62
|
},
|
|
47
63
|
"jest": {
|
|
48
64
|
"setupFiles": [
|
|
@@ -4,7 +4,10 @@ module.exports = function checkAlphabeticalOrder(firstPropData, secondPropData)
|
|
|
4
4
|
// If unprefixed prop names are the same, compare the prefixed versions
|
|
5
5
|
if (firstPropData.unprefixedName === secondPropData.unprefixedName) {
|
|
6
6
|
// If first property has no prefix and second property has prefix
|
|
7
|
-
if (
|
|
7
|
+
if (
|
|
8
|
+
!postcss.vendor.prefix(firstPropData.name).length &&
|
|
9
|
+
postcss.vendor.prefix(secondPropData.name).length
|
|
10
|
+
) {
|
|
8
11
|
return false;
|
|
9
12
|
}
|
|
10
13
|
|
package/rules/index.js
CHANGED
|
@@ -30,7 +30,11 @@ module.exports = function calcAtRulePatternPriority(pattern, node) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// doesn't have `name` and `hasBlock`
|
|
33
|
-
if (
|
|
33
|
+
if (
|
|
34
|
+
!pattern.hasOwnProperty('hasBlock') &&
|
|
35
|
+
!pattern.hasOwnProperty('name') &&
|
|
36
|
+
!pattern.hasOwnProperty('paremeter')
|
|
37
|
+
) {
|
|
34
38
|
priority = 1;
|
|
35
39
|
}
|
|
36
40
|
|
|
@@ -45,7 +49,12 @@ module.exports = function calcAtRulePatternPriority(pattern, node) {
|
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
// patter has `name`, `parameter`, and `hasBlock`, but it doesn't match all properties
|
|
48
|
-
if (
|
|
52
|
+
if (
|
|
53
|
+
pattern.hasOwnProperty('name') &&
|
|
54
|
+
pattern.hasOwnProperty('parameter') &&
|
|
55
|
+
pattern.hasOwnProperty('hasBlock') &&
|
|
56
|
+
priority < 30000
|
|
57
|
+
) {
|
|
49
58
|
priority = 0;
|
|
50
59
|
}
|
|
51
60
|
|
|
@@ -15,14 +15,20 @@ module.exports = function checkOrder(firstNodeData, secondNodeData, allNodesData
|
|
|
15
15
|
if (firstNodeIsUnspecified && !secondNodeIsUnspecified) {
|
|
16
16
|
// If first node is unspecified, look for a specified node before it to
|
|
17
17
|
// compare to the current node
|
|
18
|
-
const priorSpecifiedNodeData = _.findLast(allNodesData.slice(0, -1),
|
|
18
|
+
const priorSpecifiedNodeData = _.findLast(allNodesData.slice(0, -1), d =>
|
|
19
|
+
Boolean(d.expectedPosition)
|
|
20
|
+
);
|
|
19
21
|
|
|
20
22
|
if (
|
|
21
|
-
priorSpecifiedNodeData &&
|
|
22
|
-
|
|
23
|
+
priorSpecifiedNodeData &&
|
|
24
|
+
priorSpecifiedNodeData.expectedPosition &&
|
|
25
|
+
priorSpecifiedNodeData.expectedPosition > secondNodeData.expectedPosition
|
|
23
26
|
) {
|
|
24
27
|
stylelint.utils.report({
|
|
25
|
-
message: sharedInfo.messages.expected(
|
|
28
|
+
message: sharedInfo.messages.expected(
|
|
29
|
+
secondNodeData.description,
|
|
30
|
+
priorSpecifiedNodeData.description
|
|
31
|
+
),
|
|
26
32
|
node: secondNodeData.node,
|
|
27
33
|
result: sharedInfo.result,
|
|
28
34
|
ruleName: sharedInfo.ruleName,
|
|
@@ -45,6 +51,7 @@ module.exports = function checkOrder(firstNodeData, secondNodeData, allNodesData
|
|
|
45
51
|
if (unspecified === 'top' && firstNodeIsUnspecified) {
|
|
46
52
|
return true;
|
|
47
53
|
}
|
|
54
|
+
|
|
48
55
|
if (unspecified === 'top' && secondNodeIsUnspecified) {
|
|
49
56
|
return false;
|
|
50
57
|
}
|
|
@@ -52,6 +59,7 @@ module.exports = function checkOrder(firstNodeData, secondNodeData, allNodesData
|
|
|
52
59
|
if (unspecified === 'bottom' && secondNodeIsUnspecified) {
|
|
53
60
|
return true;
|
|
54
61
|
}
|
|
62
|
+
|
|
55
63
|
if (unspecified === 'bottom' && firstNodeIsUnspecified) {
|
|
56
64
|
return false;
|
|
57
65
|
}
|
|
@@ -7,27 +7,17 @@ module.exports = function createExpectedOrder(input) {
|
|
|
7
7
|
const order = {};
|
|
8
8
|
let expectedPosition = 0;
|
|
9
9
|
|
|
10
|
-
input.forEach(
|
|
10
|
+
input.forEach(item => {
|
|
11
11
|
expectedPosition += 1;
|
|
12
12
|
|
|
13
|
-
if (
|
|
14
|
-
(
|
|
15
|
-
_.isString(item)
|
|
16
|
-
&& item !== 'at-rules'
|
|
17
|
-
&& item !== 'rules'
|
|
18
|
-
)
|
|
19
|
-
|| item === 'less-mixins'
|
|
20
|
-
) {
|
|
13
|
+
if ((_.isString(item) && item !== 'at-rules' && item !== 'rules') || item === 'less-mixins') {
|
|
21
14
|
order[item] = {
|
|
22
15
|
expectedPosition,
|
|
23
16
|
description: getDescription(item),
|
|
24
17
|
};
|
|
25
18
|
}
|
|
26
19
|
|
|
27
|
-
if (
|
|
28
|
-
item === 'rules'
|
|
29
|
-
|| item.type === 'rule'
|
|
30
|
-
) {
|
|
20
|
+
if (item === 'rules' || item.type === 'rule') {
|
|
31
21
|
// Convert 'rules' into extended pattern
|
|
32
22
|
if (item === 'rules') {
|
|
33
23
|
item = {
|
|
@@ -56,10 +46,7 @@ module.exports = function createExpectedOrder(input) {
|
|
|
56
46
|
order[item.type].push(nodeData);
|
|
57
47
|
}
|
|
58
48
|
|
|
59
|
-
if (
|
|
60
|
-
item === 'at-rules'
|
|
61
|
-
|| item.type === 'at-rule'
|
|
62
|
-
) {
|
|
49
|
+
if (item === 'at-rules' || item.type === 'at-rule') {
|
|
63
50
|
// Convert 'at-rules' into extended pattern
|
|
64
51
|
if (item === 'at-rules') {
|
|
65
52
|
item = {
|
|
@@ -18,11 +18,7 @@ module.exports = function getOrderData(expectedOrder, node) {
|
|
|
18
18
|
} else if (utils.isStandardSyntaxProperty(node.prop)) {
|
|
19
19
|
nodeType = 'declarations';
|
|
20
20
|
}
|
|
21
|
-
} else if (
|
|
22
|
-
node.type === 'rule'
|
|
23
|
-
&& node.empty
|
|
24
|
-
&& !node.extend
|
|
25
|
-
) {
|
|
21
|
+
} else if (node.type === 'rule' && node.empty && !node.extend) {
|
|
26
22
|
nodeType = 'less-mixins';
|
|
27
23
|
} else if (node.type === 'rule') {
|
|
28
24
|
nodeType = {
|
|
@@ -37,7 +33,7 @@ module.exports = function getOrderData(expectedOrder, node) {
|
|
|
37
33
|
let prioritizedPattern;
|
|
38
34
|
let max = 0;
|
|
39
35
|
|
|
40
|
-
rules.forEach(function
|
|
36
|
+
rules.forEach(function(pattern) {
|
|
41
37
|
const priority = calcRulePatternPriority(pattern, nodeType);
|
|
42
38
|
|
|
43
39
|
if (priority > max) {
|
|
@@ -72,7 +68,7 @@ module.exports = function getOrderData(expectedOrder, node) {
|
|
|
72
68
|
let prioritizedPattern;
|
|
73
69
|
let max = 0;
|
|
74
70
|
|
|
75
|
-
atRules.forEach(function
|
|
71
|
+
atRules.forEach(function(pattern) {
|
|
76
72
|
const priority = calcAtRulePatternPriority(pattern, nodeType);
|
|
77
73
|
|
|
78
74
|
if (priority > max) {
|
package/rules/order/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
|
17
17
|
function rule(expectation, options, context) {
|
|
18
18
|
context = context || {};
|
|
19
19
|
|
|
20
|
-
return function
|
|
20
|
+
return function(root, result) {
|
|
21
21
|
const validOptions = stylelint.utils.validateOptions(
|
|
22
22
|
result,
|
|
23
23
|
ruleName,
|
|
@@ -10,52 +10,68 @@ module.exports = function validatePrimaryOption(actualOptions) {
|
|
|
10
10
|
|
|
11
11
|
// Every item in the array must be a certain string or an object
|
|
12
12
|
// with a "type" property
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
if (
|
|
14
|
+
!actualOptions.every(item => {
|
|
15
|
+
if (_.isString(item)) {
|
|
16
|
+
return _.includes(
|
|
17
|
+
[
|
|
18
|
+
'custom-properties',
|
|
19
|
+
'dollar-variables',
|
|
20
|
+
'at-variables',
|
|
21
|
+
'declarations',
|
|
22
|
+
'rules',
|
|
23
|
+
'at-rules',
|
|
24
|
+
'less-mixins',
|
|
25
|
+
],
|
|
26
|
+
item
|
|
27
|
+
);
|
|
28
|
+
}
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
return _.isPlainObject(item) && !_.isUndefined(item.type);
|
|
31
|
+
})
|
|
32
|
+
) {
|
|
20
33
|
return false;
|
|
21
34
|
}
|
|
22
35
|
|
|
23
36
|
const objectItems = actualOptions.filter(_.isPlainObject);
|
|
24
37
|
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (item.type !== 'at-rule' && item.type !== 'rule') {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
38
|
+
if (
|
|
39
|
+
!objectItems.every(item => {
|
|
40
|
+
let result = true;
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
// if parameter is specified, name should be specified also
|
|
34
|
-
if (!_.isUndefined(item.parameter) && _.isUndefined(item.name)) {
|
|
42
|
+
if (item.type !== 'at-rule' && item.type !== 'rule') {
|
|
35
43
|
return false;
|
|
36
44
|
}
|
|
37
45
|
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
if (item.type === 'at-rule') {
|
|
47
|
+
// if parameter is specified, name should be specified also
|
|
48
|
+
if (!_.isUndefined(item.parameter) && _.isUndefined(item.name)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
41
51
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
if (!_.isUndefined(item.hasBlock)) {
|
|
53
|
+
result = item.hasBlock === true || item.hasBlock === false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!_.isUndefined(item.name)) {
|
|
57
|
+
result = _.isString(item.name) && item.name.length;
|
|
58
|
+
}
|
|
45
59
|
|
|
46
|
-
|
|
47
|
-
|
|
60
|
+
if (!_.isUndefined(item.parameter)) {
|
|
61
|
+
result =
|
|
62
|
+
(_.isString(item.parameter) && item.parameter.length) || _.isRegExp(item.parameter);
|
|
63
|
+
}
|
|
48
64
|
}
|
|
49
|
-
}
|
|
50
65
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
if (item.type === 'rule') {
|
|
67
|
+
if (!_.isUndefined(item.selector)) {
|
|
68
|
+
result = (_.isString(item.selector) && item.selector.length) || _.isRegExp(item.selector);
|
|
69
|
+
}
|
|
54
70
|
}
|
|
55
|
-
}
|
|
56
71
|
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
return result;
|
|
73
|
+
})
|
|
74
|
+
) {
|
|
59
75
|
return false;
|
|
60
76
|
}
|
|
61
77
|
|
|
@@ -16,7 +16,7 @@ const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
|
16
16
|
function rule(actual, options, context) {
|
|
17
17
|
context = context || {};
|
|
18
18
|
|
|
19
|
-
return function
|
|
19
|
+
return function(root, result) {
|
|
20
20
|
const validOptions = stylelint.utils.validateOptions(
|
|
21
21
|
result,
|
|
22
22
|
ruleName,
|
|
@@ -574,18 +574,16 @@ If `order: "flexible"` is using, for sorting it will be treated as `strict`. It
|
|
|
574
574
|
Given:
|
|
575
575
|
|
|
576
576
|
```json
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
"
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
]
|
|
588
|
-
}
|
|
577
|
+
[
|
|
578
|
+
{
|
|
579
|
+
"order": "flexible",
|
|
580
|
+
"properties": [
|
|
581
|
+
"color",
|
|
582
|
+
"font-size",
|
|
583
|
+
"font-weight"
|
|
584
|
+
]
|
|
585
|
+
}
|
|
586
|
+
]
|
|
589
587
|
```
|
|
590
588
|
|
|
591
589
|
Before:
|
|
@@ -4,11 +4,11 @@ const _ = require('lodash');
|
|
|
4
4
|
|
|
5
5
|
// Add an empty line before a node. Mutates the node.
|
|
6
6
|
module.exports = function addEmptyLineBefore(node, newline) {
|
|
7
|
-
if (
|
|
7
|
+
if (!/\r?\n/.test(node.raws.before)) {
|
|
8
8
|
node.raws.before = _.repeat(newline, 2) + node.raws.before;
|
|
9
|
-
} else if (
|
|
9
|
+
} else if (/^\r?\n/.test(node.raws.before)) {
|
|
10
10
|
node.raws.before = newline + node.raws.before;
|
|
11
|
-
} else if (
|
|
11
|
+
} else if (/\r?\n$/.test(node.raws.before)) {
|
|
12
12
|
node.raws.before = node.raws.before + newline;
|
|
13
13
|
} else {
|
|
14
14
|
node.raws.before = node.raws.before.replace(/(\r?\n)/, `${newline}$1`);
|
|
@@ -11,17 +11,14 @@ module.exports = function checkEmptyLineBefore(firstPropData, secondPropData, sh
|
|
|
11
11
|
const secondPropIsUnspecified = !secondPropData.orderData;
|
|
12
12
|
|
|
13
13
|
// Now check newlines between ...
|
|
14
|
-
const firstPropSeparatedGroup =
|
|
14
|
+
const firstPropSeparatedGroup = !firstPropIsUnspecified
|
|
15
15
|
? firstPropData.orderData.separatedGroup
|
|
16
16
|
: sharedInfo.lastKnownSeparatedGroup;
|
|
17
|
-
const secondPropSeparatedGroup =
|
|
17
|
+
const secondPropSeparatedGroup = !secondPropIsUnspecified
|
|
18
18
|
? secondPropData.orderData.separatedGroup
|
|
19
19
|
: sharedInfo.lastKnownSeparatedGroup;
|
|
20
20
|
|
|
21
|
-
if (
|
|
22
|
-
firstPropSeparatedGroup !== secondPropSeparatedGroup
|
|
23
|
-
&& !secondPropIsUnspecified
|
|
24
|
-
) {
|
|
21
|
+
if (firstPropSeparatedGroup !== secondPropSeparatedGroup && !secondPropIsUnspecified) {
|
|
25
22
|
// Get an array of just the property groups, remove any solo properties
|
|
26
23
|
const groups = _.reject(sharedInfo.expectation, _.isString);
|
|
27
24
|
|
|
@@ -26,10 +26,7 @@ module.exports = function checkNode(node, sharedInfo) {
|
|
|
26
26
|
if (child.type === 'decl') {
|
|
27
27
|
const prop = child.prop;
|
|
28
28
|
|
|
29
|
-
if (
|
|
30
|
-
utils.isStandardSyntaxProperty(prop)
|
|
31
|
-
&& !utils.isCustomProperty(prop)
|
|
32
|
-
) {
|
|
29
|
+
if (utils.isStandardSyntaxProperty(prop) && !utils.isCustomProperty(prop)) {
|
|
33
30
|
let unprefixedPropName = postcss.vendor.unprefixed(prop);
|
|
34
31
|
|
|
35
32
|
// Hack to allow -moz-osx-font-smoothing to be understood
|
|
@@ -53,9 +50,9 @@ module.exports = function checkNode(node, sharedInfo) {
|
|
|
53
50
|
|
|
54
51
|
// current node should be a standard declaration
|
|
55
52
|
if (
|
|
56
|
-
child.type !== 'decl'
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
child.type !== 'decl' ||
|
|
54
|
+
!utils.isStandardSyntaxProperty(nodeData.node.prop) ||
|
|
55
|
+
utils.isCustomProperty(nodeData.node.prop)
|
|
59
56
|
) {
|
|
60
57
|
return;
|
|
61
58
|
}
|
|
@@ -64,10 +61,7 @@ module.exports = function checkNode(node, sharedInfo) {
|
|
|
64
61
|
const previousPropData = _.nth(allPropData, -2);
|
|
65
62
|
|
|
66
63
|
// Skip first decl
|
|
67
|
-
if (
|
|
68
|
-
previousPropData
|
|
69
|
-
&& (!sharedInfo.context.fix || sharedInfo.disableFix)
|
|
70
|
-
) {
|
|
64
|
+
if (previousPropData && (!sharedInfo.context.fix || sharedInfo.disableFix)) {
|
|
71
65
|
const isCorrectOrder = checkOrder(previousPropData, nodeData, allPropData, sharedInfo);
|
|
72
66
|
|
|
73
67
|
if (!isCorrectOrder) {
|
|
@@ -85,9 +79,9 @@ module.exports = function checkNode(node, sharedInfo) {
|
|
|
85
79
|
|
|
86
80
|
// if previous node is shared-line comment, use second previous node
|
|
87
81
|
if (
|
|
88
|
-
previousNodeData
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
previousNodeData &&
|
|
83
|
+
previousNodeData.node.type === 'comment' &&
|
|
84
|
+
previousNodeData.node.raw('before').indexOf('\n') === -1
|
|
91
85
|
) {
|
|
92
86
|
previousNodeData = _.nth(allNodesData, -3);
|
|
93
87
|
}
|
|
@@ -103,8 +97,8 @@ module.exports = function checkNode(node, sharedInfo) {
|
|
|
103
97
|
|
|
104
98
|
// previous node should be a standard declaration
|
|
105
99
|
if (
|
|
106
|
-
!utils.isStandardSyntaxProperty(previousNodeData.node.prop)
|
|
107
|
-
|
|
100
|
+
!utils.isStandardSyntaxProperty(previousNodeData.node.prop) ||
|
|
101
|
+
utils.isCustomProperty(previousNodeData.node.prop)
|
|
108
102
|
) {
|
|
109
103
|
return;
|
|
110
104
|
}
|
|
@@ -8,7 +8,10 @@ const checkAlphabeticalOrder = require('../checkAlphabeticalOrder');
|
|
|
8
8
|
module.exports = function checkOrder(firstPropData, secondPropData, allPropData, sharedInfo) {
|
|
9
9
|
if (firstPropData.unprefixedName === secondPropData.unprefixedName) {
|
|
10
10
|
// If first property has no prefix and second property has prefix
|
|
11
|
-
if (
|
|
11
|
+
if (
|
|
12
|
+
!postcss.vendor.prefix(firstPropData.name).length &&
|
|
13
|
+
postcss.vendor.prefix(secondPropData.name).length
|
|
14
|
+
) {
|
|
12
15
|
return false;
|
|
13
16
|
}
|
|
14
17
|
|
|
@@ -26,12 +29,12 @@ module.exports = function checkOrder(firstPropData, secondPropData, allPropData,
|
|
|
26
29
|
if (firstPropIsUnspecified && !secondPropIsUnspecified) {
|
|
27
30
|
// If first prop is unspecified, look for a specified prop before it to
|
|
28
31
|
// compare to the current prop
|
|
29
|
-
const priorSpecifiedPropData = _.findLast(allPropData.slice(0, -1),
|
|
32
|
+
const priorSpecifiedPropData = _.findLast(allPropData.slice(0, -1), d => Boolean(d.orderData));
|
|
30
33
|
|
|
31
34
|
if (
|
|
32
|
-
priorSpecifiedPropData
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
priorSpecifiedPropData &&
|
|
36
|
+
priorSpecifiedPropData.orderData &&
|
|
37
|
+
priorSpecifiedPropData.orderData.expectedPosition > secondPropData.orderData.expectedPosition
|
|
35
38
|
) {
|
|
36
39
|
stylelint.utils.report({
|
|
37
40
|
message: sharedInfo.messages.expected(secondPropData.name, priorSpecifiedPropData.name),
|
|
@@ -48,25 +51,18 @@ module.exports = function checkOrder(firstPropData, secondPropData, allPropData,
|
|
|
48
51
|
|
|
49
52
|
// Now deal with unspecified props
|
|
50
53
|
// Starting with bottomAlphabetical as it requires more specific conditionals
|
|
51
|
-
if (
|
|
52
|
-
unspecified === 'bottomAlphabetical'
|
|
53
|
-
&& !firstPropIsUnspecified
|
|
54
|
-
&& secondPropIsUnspecified
|
|
55
|
-
) {
|
|
54
|
+
if (unspecified === 'bottomAlphabetical' && !firstPropIsUnspecified && secondPropIsUnspecified) {
|
|
56
55
|
return true;
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
if (
|
|
60
|
-
unspecified === 'bottomAlphabetical'
|
|
61
|
-
&& secondPropIsUnspecified
|
|
62
|
-
&& firstPropIsUnspecified
|
|
63
|
-
) {
|
|
58
|
+
if (unspecified === 'bottomAlphabetical' && secondPropIsUnspecified && firstPropIsUnspecified) {
|
|
64
59
|
if (checkAlphabeticalOrder(firstPropData, secondPropData)) {
|
|
65
60
|
return true;
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
return false;
|
|
69
64
|
}
|
|
65
|
+
|
|
70
66
|
if (unspecified === 'bottomAlphabetical' && firstPropIsUnspecified) {
|
|
71
67
|
return false;
|
|
72
68
|
}
|
|
@@ -82,6 +78,7 @@ module.exports = function checkOrder(firstPropData, secondPropData, allPropData,
|
|
|
82
78
|
if (unspecified === 'top' && firstPropIsUnspecified) {
|
|
83
79
|
return true;
|
|
84
80
|
}
|
|
81
|
+
|
|
85
82
|
if (unspecified === 'top' && secondPropIsUnspecified) {
|
|
86
83
|
return false;
|
|
87
84
|
}
|
|
@@ -89,6 +86,7 @@ module.exports = function checkOrder(firstPropData, secondPropData, allPropData,
|
|
|
89
86
|
if (unspecified === 'bottom' && secondPropIsUnspecified) {
|
|
90
87
|
return true;
|
|
91
88
|
}
|
|
89
|
+
|
|
92
90
|
if (unspecified === 'bottom' && firstPropIsUnspecified) {
|
|
93
91
|
return false;
|
|
94
92
|
}
|
|
@@ -10,7 +10,7 @@ module.exports = function createExpectedOrder(input) {
|
|
|
10
10
|
appendGroup(input);
|
|
11
11
|
|
|
12
12
|
function appendGroup(items) {
|
|
13
|
-
items.forEach(
|
|
13
|
+
items.forEach(item => appendItem(item, false));
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function appendItem(item, inFlexibleGroup) {
|
|
@@ -35,7 +35,7 @@ module.exports = function createExpectedOrder(input) {
|
|
|
35
35
|
if (item.order && item.order === 'flexible') {
|
|
36
36
|
expectedPosition += 1;
|
|
37
37
|
|
|
38
|
-
item.properties.forEach(
|
|
38
|
+
item.properties.forEach(property => {
|
|
39
39
|
appendItem(property, true);
|
|
40
40
|
});
|
|
41
41
|
} else {
|
|
@@ -13,14 +13,14 @@ const ruleName = utils.namespace('properties-order');
|
|
|
13
13
|
|
|
14
14
|
const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
15
15
|
expected: (first, second) => `Expected "${first}" to come before "${second}"`,
|
|
16
|
-
expectedEmptyLineBefore:
|
|
17
|
-
rejectedEmptyLineBefore:
|
|
16
|
+
expectedEmptyLineBefore: property => `Expected an empty line before property "${property}"`,
|
|
17
|
+
rejectedEmptyLineBefore: property => `Unexpected an empty line before property "${property}"`,
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
const rule = function
|
|
20
|
+
const rule = function(expectation, options, context) {
|
|
21
21
|
context = context || {};
|
|
22
22
|
|
|
23
|
-
return function
|
|
23
|
+
return function(root, result) {
|
|
24
24
|
const validOptions = stylelint.utils.validateOptions(
|
|
25
25
|
result,
|
|
26
26
|
ruleName,
|
|
@@ -31,12 +31,7 @@ const rule = function (expectation, options, context) {
|
|
|
31
31
|
{
|
|
32
32
|
actual: options,
|
|
33
33
|
possible: {
|
|
34
|
-
unspecified: [
|
|
35
|
-
'top',
|
|
36
|
-
'bottom',
|
|
37
|
-
'ignore',
|
|
38
|
-
'bottomAlphabetical',
|
|
39
|
-
],
|
|
34
|
+
unspecified: ['top', 'bottom', 'ignore', 'bottomAlphabetical'],
|
|
40
35
|
disableFix: _.isBoolean,
|
|
41
36
|
},
|
|
42
37
|
optional: true,
|
|
@@ -10,37 +10,43 @@ module.exports = function validatePrimaryOption(actualOptions) {
|
|
|
10
10
|
|
|
11
11
|
// Every item in the array must be a string or an object
|
|
12
12
|
// with a "properties" property
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
if (
|
|
14
|
+
!actualOptions.every(item => {
|
|
15
|
+
if (_.isString(item)) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return _.isPlainObject(item) && !_.isUndefined(item.properties);
|
|
20
|
+
})
|
|
21
|
+
) {
|
|
20
22
|
return false;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
const objectItems = actualOptions.filter(_.isPlainObject);
|
|
24
26
|
|
|
25
27
|
// Every object-item's "properties" should be an array with no items, or with strings
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
if (
|
|
29
|
+
!objectItems.every(item => {
|
|
30
|
+
if (!Array.isArray(item.properties)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return item.properties.every(property => _.isString(property));
|
|
35
|
+
})
|
|
36
|
+
) {
|
|
33
37
|
return false;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
// Every object-item's "emptyLineBefore" must be "always" or "never"
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
if (
|
|
42
|
+
!objectItems.every(item => {
|
|
43
|
+
if (_.isUndefined(item.emptyLineBefore)) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return _.includes(['always', 'never'], item.emptyLineBefore);
|
|
48
|
+
})
|
|
49
|
+
) {
|
|
44
50
|
return false;
|
|
45
51
|
}
|
|
46
52
|
|