stylelint-order 0.5.0 → 0.8.1

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE.md +1 -1
  3. package/README.md +9 -1
  4. package/index.js +3 -5
  5. package/package.json +25 -9
  6. package/rules/.DS_Store +0 -0
  7. package/rules/checkAlphabeticalOrder.js +4 -1
  8. package/rules/index.js +1 -1
  9. package/rules/order/.DS_Store +0 -0
  10. package/rules/order/calcAtRulePatternPriority.js +11 -4
  11. package/rules/order/calcRulePatternPriority.js +0 -2
  12. package/rules/order/checkNode.js +7 -2
  13. package/rules/order/checkOrder.js +20 -7
  14. package/rules/order/createExpectedOrder.js +4 -19
  15. package/rules/order/getDescription.js +1 -3
  16. package/rules/order/getOrderData.js +3 -9
  17. package/rules/order/index.js +15 -11
  18. package/rules/order/validatePrimaryOption.js +46 -32
  19. package/rules/properties-alphabetical-order/.DS_Store +0 -0
  20. package/rules/properties-alphabetical-order/index.js +2 -4
  21. package/rules/properties-order/.DS_Store +0 -0
  22. package/rules/properties-order/README.md +0 -39
  23. package/rules/properties-order/addEmptyLineBefore.js +3 -5
  24. package/rules/properties-order/checkEmptyLineBefore.js +7 -12
  25. package/rules/properties-order/checkNode.js +65 -74
  26. package/rules/properties-order/checkOrder.js +38 -42
  27. package/rules/properties-order/createExpectedOrder.js +2 -4
  28. package/rules/properties-order/createFlatOrder.js +1 -3
  29. package/rules/properties-order/getNodeData.js +25 -0
  30. package/rules/properties-order/hasEmptyLineBefore.js +0 -2
  31. package/rules/properties-order/index.js +10 -34
  32. package/rules/properties-order/removeEmptyLinesBefore.js +0 -2
  33. package/rules/properties-order/validatePrimaryOption.js +27 -23
  34. package/utils/index.js +2 -0
  35. package/utils/isCustomProperty.js +1 -1
  36. package/utils/isProperty.js +9 -0
  37. package/utils/isRuleWithNodes.js +3 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
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.8.1
6
+
7
+ * Add `stylelint@9.0.0` as a peer dependency.
8
+
9
+ ## 0.8.0
10
+
11
+ * Breaking change: Dropped Node.js 4 support. Use Node.js 6 or newer.
12
+ * Changed: `order` and `properties-order` will no longer autofix proactively. If there no violations would be reported with autofix disabled, then nothing will be changed with autofix enabled. Previously, there were changes to `flexible` properties order ([#49](https://github.com/hudochenkov/stylelint-order/issues/49)) or to the order of content within declaration blocks ([#51](https://github.com/hudochenkov/stylelint-order/issues/51)).
13
+
14
+ ## 0.7.0
15
+
16
+ * 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).
17
+
18
+ ## 0.6.0
19
+
20
+ * Migrated to `stylelint@8.0.0`.
21
+
5
22
  ## 0.5.0
6
23
  * 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.
7
24
  * Removed SCSS nested properties support.
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright 2016–2017 Aleks Hudochenkov <aleks@hudochenkov.com>
3
+ Copyright 2016–present Aleks Hudochenkov <aleks@hudochenkov.com>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
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
@@ -1,10 +1,8 @@
1
- 'use strict';
2
-
3
- const createPlugin = require('stylelint').createPlugin;
4
- const namespace = require('./utils').namespace;
1
+ const { createPlugin } = require('stylelint');
2
+ const { namespace } = require('./utils');
5
3
  const rules = require('./rules');
6
4
 
7
- const rulesPlugins = Object.keys(rules).map((ruleName) => {
5
+ const rulesPlugins = Object.keys(rules).map(ruleName => {
8
6
  return createPlugin(namespace(ruleName), rules[ruleName]);
9
7
  });
10
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stylelint-order",
3
- "version": "0.5.0",
3
+ "version": "0.8.1",
4
4
  "description": "A collection of order related linting rules for stylelint.",
5
5
  "keywords": [
6
6
  "stylelint-plugin",
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "homepage": "https://github.com/hudochenkov/stylelint-order",
19
19
  "engines": {
20
- "node": ">=4"
20
+ "node": ">=6"
21
21
  },
22
22
  "files": [
23
23
  "rules",
@@ -28,21 +28,37 @@
28
28
  "main": "index.js",
29
29
  "dependencies": {
30
30
  "lodash": "^4.17.4",
31
- "postcss": "^6.0.1",
32
- "postcss-sorting": "^3.0.0",
33
- "stylelint": "^7.11.0"
31
+ "postcss": "^6.0.14",
32
+ "postcss-sorting": "^3.1.0"
33
+ },
34
+ "peerDependencies": {
35
+ "stylelint": "^8.0.0 || ^9.0.0"
34
36
  },
35
37
  "devDependencies": {
36
- "eslint": "^3.19.0",
37
- "eslint-config-hudochenkov": "^1.3.0",
38
- "jest": "^20.0.4"
38
+ "eslint": "~4.12.1",
39
+ "eslint-config-hudochenkov": "~2.0.0",
40
+ "eslint-config-prettier": "~2.9.0",
41
+ "eslint-plugin-prettier": "~2.3.1",
42
+ "husky": "^0.14.3",
43
+ "jest": "^21.2.1",
44
+ "lint-staged": "^6.0.0",
45
+ "prettier": "~1.8.2",
46
+ "stylelint": "^8.3.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": [
Binary file
@@ -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 (!postcss.vendor.prefix(firstPropData.name).length && postcss.vendor.prefix(secondPropData.name).length) {
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
@@ -1,5 +1,5 @@
1
1
  module.exports = {
2
- 'order': require('./order'),
2
+ order: require('./order'),
3
3
  'properties-order': require('./properties-order'),
4
4
  'properties-alphabetical-order': require('./properties-alphabetical-order'),
5
5
  };
Binary file
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  module.exports = function calcAtRulePatternPriority(pattern, node) {
4
2
  // 0 — it pattern doesn't match
5
3
  // 1 — pattern without `name` and `hasBlock`
@@ -30,7 +28,11 @@ module.exports = function calcAtRulePatternPriority(pattern, node) {
30
28
  }
31
29
 
32
30
  // doesn't have `name` and `hasBlock`
33
- if (!pattern.hasOwnProperty('hasBlock') && !pattern.hasOwnProperty('name') && !pattern.hasOwnProperty('paremeter')) {
31
+ if (
32
+ !pattern.hasOwnProperty('hasBlock') &&
33
+ !pattern.hasOwnProperty('name') &&
34
+ !pattern.hasOwnProperty('paremeter')
35
+ ) {
34
36
  priority = 1;
35
37
  }
36
38
 
@@ -45,7 +47,12 @@ module.exports = function calcAtRulePatternPriority(pattern, node) {
45
47
  }
46
48
 
47
49
  // patter has `name`, `parameter`, and `hasBlock`, but it doesn't match all properties
48
- if (pattern.hasOwnProperty('name') && pattern.hasOwnProperty('parameter') && pattern.hasOwnProperty('hasBlock') && priority < 30000) {
50
+ if (
51
+ pattern.hasOwnProperty('name') &&
52
+ pattern.hasOwnProperty('parameter') &&
53
+ pattern.hasOwnProperty('hasBlock') &&
54
+ priority < 30000
55
+ ) {
49
56
  priority = 0;
50
57
  }
51
58
 
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  module.exports = function calcRulePatternPriority(pattern, node) {
4
2
  // 0 — it pattern doesn't match
5
3
  // 1 — pattern without `selector`
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const stylelint = require('stylelint');
4
2
  const _ = require('lodash');
5
3
  const checkOrder = require('./checkOrder');
@@ -46,6 +44,13 @@ module.exports = function checkNode(node, sharedInfo) {
46
44
  return;
47
45
  }
48
46
 
47
+ if (sharedInfo.isFixEnabled) {
48
+ sharedInfo.shouldFix = true;
49
+
50
+ // Don't go further, fix will be applied
51
+ return;
52
+ }
53
+
49
54
  stylelint.utils.report({
50
55
  message: sharedInfo.messages.expected(nodeData.description, previousNodeData.description),
51
56
  node: child,
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const stylelint = require('stylelint');
4
2
  const _ = require('lodash');
5
3
 
@@ -15,14 +13,27 @@ module.exports = function checkOrder(firstNodeData, secondNodeData, allNodesData
15
13
  if (firstNodeIsUnspecified && !secondNodeIsUnspecified) {
16
14
  // If first node is unspecified, look for a specified node before it to
17
15
  // compare to the current node
18
- const priorSpecifiedNodeData = _.findLast(allNodesData.slice(0, -1), (d) => Boolean(d.expectedPosition));
16
+ const priorSpecifiedNodeData = _.findLast(allNodesData.slice(0, -1), d =>
17
+ Boolean(d.expectedPosition)
18
+ );
19
19
 
20
20
  if (
21
- priorSpecifiedNodeData && priorSpecifiedNodeData.expectedPosition
22
- && priorSpecifiedNodeData.expectedPosition > secondNodeData.expectedPosition
21
+ priorSpecifiedNodeData &&
22
+ priorSpecifiedNodeData.expectedPosition &&
23
+ priorSpecifiedNodeData.expectedPosition > secondNodeData.expectedPosition
23
24
  ) {
25
+ if (sharedInfo.isFixEnabled) {
26
+ sharedInfo.shouldFix = true;
27
+
28
+ // Don't go further, fix will be applied
29
+ return;
30
+ }
31
+
24
32
  stylelint.utils.report({
25
- message: sharedInfo.messages.expected(secondNodeData.description, priorSpecifiedNodeData.description),
33
+ message: sharedInfo.messages.expected(
34
+ secondNodeData.description,
35
+ priorSpecifiedNodeData.description
36
+ ),
26
37
  node: secondNodeData.node,
27
38
  result: sharedInfo.result,
28
39
  ruleName: sharedInfo.ruleName,
@@ -36,7 +47,7 @@ module.exports = function checkOrder(firstNodeData, secondNodeData, allNodesData
36
47
  return true;
37
48
  }
38
49
 
39
- const unspecified = sharedInfo.unspecified;
50
+ const { unspecified } = sharedInfo;
40
51
 
41
52
  if (unspecified === 'ignore' && (firstNodeIsUnspecified || secondNodeIsUnspecified)) {
42
53
  return true;
@@ -45,6 +56,7 @@ module.exports = function checkOrder(firstNodeData, secondNodeData, allNodesData
45
56
  if (unspecified === 'top' && firstNodeIsUnspecified) {
46
57
  return true;
47
58
  }
59
+
48
60
  if (unspecified === 'top' && secondNodeIsUnspecified) {
49
61
  return false;
50
62
  }
@@ -52,6 +64,7 @@ module.exports = function checkOrder(firstNodeData, secondNodeData, allNodesData
52
64
  if (unspecified === 'bottom' && secondNodeIsUnspecified) {
53
65
  return true;
54
66
  }
67
+
55
68
  if (unspecified === 'bottom' && firstNodeIsUnspecified) {
56
69
  return false;
57
70
  }
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const _ = require('lodash');
4
2
  const getDescription = require('./getDescription');
5
3
 
@@ -7,27 +5,17 @@ module.exports = function createExpectedOrder(input) {
7
5
  const order = {};
8
6
  let expectedPosition = 0;
9
7
 
10
- input.forEach((item) => {
8
+ input.forEach(item => {
11
9
  expectedPosition += 1;
12
10
 
13
- if (
14
- (
15
- _.isString(item)
16
- && item !== 'at-rules'
17
- && item !== 'rules'
18
- )
19
- || item === 'less-mixins'
20
- ) {
11
+ if ((_.isString(item) && item !== 'at-rules' && item !== 'rules') || item === 'less-mixins') {
21
12
  order[item] = {
22
13
  expectedPosition,
23
14
  description: getDescription(item),
24
15
  };
25
16
  }
26
17
 
27
- if (
28
- item === 'rules'
29
- || item.type === 'rule'
30
- ) {
18
+ if (item === 'rules' || item.type === 'rule') {
31
19
  // Convert 'rules' into extended pattern
32
20
  if (item === 'rules') {
33
21
  item = {
@@ -56,10 +44,7 @@ module.exports = function createExpectedOrder(input) {
56
44
  order[item.type].push(nodeData);
57
45
  }
58
46
 
59
- if (
60
- item === 'at-rules'
61
- || item.type === 'at-rule'
62
- ) {
47
+ if (item === 'at-rules' || item.type === 'at-rule') {
63
48
  // Convert 'at-rules' into extended pattern
64
49
  if (item === 'at-rules') {
65
50
  item = {
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const _ = require('lodash');
4
2
 
5
3
  module.exports = function getDescription(item) {
@@ -8,7 +6,7 @@ module.exports = function getDescription(item) {
8
6
  'dollar-variables': '$-variable',
9
7
  'at-variables': '@-variable',
10
8
  'less-mixins': 'Less mixin',
11
- 'declarations': 'declaration',
9
+ declarations: 'declaration',
12
10
  };
13
11
 
14
12
  if (_.isPlainObject(item)) {
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const utils = require('../../utils');
4
2
  const calcAtRulePatternPriority = require('./calcAtRulePatternPriority');
5
3
  const calcRulePatternPriority = require('./calcRulePatternPriority');
@@ -18,11 +16,7 @@ module.exports = function getOrderData(expectedOrder, node) {
18
16
  } else if (utils.isStandardSyntaxProperty(node.prop)) {
19
17
  nodeType = 'declarations';
20
18
  }
21
- } else if (
22
- node.type === 'rule'
23
- && node.ruleWithoutBody
24
- && !node.extendRule
25
- ) {
19
+ } else if (node.type === 'rule' && node.empty && !node.extend) {
26
20
  nodeType = 'less-mixins';
27
21
  } else if (node.type === 'rule') {
28
22
  nodeType = {
@@ -37,7 +31,7 @@ module.exports = function getOrderData(expectedOrder, node) {
37
31
  let prioritizedPattern;
38
32
  let max = 0;
39
33
 
40
- rules.forEach(function (pattern) {
34
+ rules.forEach(function(pattern) {
41
35
  const priority = calcRulePatternPriority(pattern, nodeType);
42
36
 
43
37
  if (priority > max) {
@@ -72,7 +66,7 @@ module.exports = function getOrderData(expectedOrder, node) {
72
66
  let prioritizedPattern;
73
67
  let max = 0;
74
68
 
75
- atRules.forEach(function (pattern) {
69
+ atRules.forEach(function(pattern) {
76
70
  const priority = calcAtRulePatternPriority(pattern, nodeType);
77
71
 
78
72
  if (priority > max) {
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const stylelint = require('stylelint');
4
2
  const _ = require('lodash');
5
3
  const postcssSorting = require('postcss-sorting');
@@ -17,7 +15,7 @@ const messages = stylelint.utils.ruleMessages(ruleName, {
17
15
  function rule(expectation, options, context) {
18
16
  context = context || {};
19
17
 
20
- return function (root, result) {
18
+ return function(root, result) {
21
19
  const validOptions = stylelint.utils.validateOptions(
22
20
  result,
23
21
  ruleName,
@@ -39,18 +37,13 @@ function rule(expectation, options, context) {
39
37
  return;
40
38
  }
41
39
 
42
- const disableFix = _.get(options, ['disableFix'], false);
43
-
44
- if (context.fix && !disableFix) {
45
- postcssSorting({ order: expectation })(root);
46
-
47
- return;
48
- }
40
+ const disableFix = _.get(options, 'disableFix', false);
41
+ const isFixEnabled = context.fix && !disableFix;
49
42
 
50
43
  const expectedOrder = createExpectedOrder(expectation);
51
44
 
52
45
  // By default, ignore unspecified properties
53
- const unspecified = _.get(options, ['unspecified'], 'ignore');
46
+ const unspecified = _.get(options, 'unspecified', 'ignore');
54
47
 
55
48
  const sharedInfo = {
56
49
  expectedOrder,
@@ -58,14 +51,25 @@ function rule(expectation, options, context) {
58
51
  messages,
59
52
  ruleName,
60
53
  result,
54
+ isFixEnabled,
55
+ shouldFix: false,
61
56
  };
62
57
 
63
58
  // Check all rules and at-rules recursively
64
59
  root.walk(function processRulesAndAtrules(node) {
60
+ // return early if we know there is a violation and auto fix should be applied
61
+ if (isFixEnabled && sharedInfo.shouldFix) {
62
+ return;
63
+ }
64
+
65
65
  if (node.type === 'rule' || node.type === 'atrule') {
66
66
  checkNode(node, sharedInfo);
67
67
  }
68
68
  });
69
+
70
+ if (sharedInfo.shouldFix) {
71
+ postcssSorting({ order: expectation })(root);
72
+ }
69
73
  };
70
74
  }
71
75
 
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const _ = require('lodash');
4
2
 
5
3
  module.exports = function validatePrimaryOption(actualOptions) {
@@ -10,52 +8,68 @@ module.exports = function validatePrimaryOption(actualOptions) {
10
8
 
11
9
  // Every item in the array must be a certain string or an object
12
10
  // with a "type" property
13
- if (!actualOptions.every((item) => {
14
- if (_.isString(item)) {
15
- return _.includes(['custom-properties', 'dollar-variables', 'at-variables', 'declarations', 'rules', 'at-rules', 'less-mixins'], item);
16
- }
11
+ if (
12
+ !actualOptions.every(item => {
13
+ if (_.isString(item)) {
14
+ return _.includes(
15
+ [
16
+ 'custom-properties',
17
+ 'dollar-variables',
18
+ 'at-variables',
19
+ 'declarations',
20
+ 'rules',
21
+ 'at-rules',
22
+ 'less-mixins',
23
+ ],
24
+ item
25
+ );
26
+ }
17
27
 
18
- return _.isPlainObject(item) && !_.isUndefined(item.type);
19
- })) {
28
+ return _.isPlainObject(item) && !_.isUndefined(item.type);
29
+ })
30
+ ) {
20
31
  return false;
21
32
  }
22
33
 
23
34
  const objectItems = actualOptions.filter(_.isPlainObject);
24
35
 
25
- if (!objectItems.every((item) => {
26
- let result = true;
27
-
28
- if (item.type !== 'at-rule' && item.type !== 'rule') {
29
- return false;
30
- }
36
+ if (
37
+ !objectItems.every(item => {
38
+ let result = true;
31
39
 
32
- if (item.type === 'at-rule') {
33
- // if parameter is specified, name should be specified also
34
- if (!_.isUndefined(item.parameter) && _.isUndefined(item.name)) {
40
+ if (item.type !== 'at-rule' && item.type !== 'rule') {
35
41
  return false;
36
42
  }
37
43
 
38
- if (!_.isUndefined(item.hasBlock)) {
39
- result = item.hasBlock === true || item.hasBlock === false;
40
- }
44
+ if (item.type === 'at-rule') {
45
+ // if parameter is specified, name should be specified also
46
+ if (!_.isUndefined(item.parameter) && _.isUndefined(item.name)) {
47
+ return false;
48
+ }
41
49
 
42
- if (!_.isUndefined(item.name)) {
43
- result = _.isString(item.name) && item.name.length;
44
- }
50
+ if (!_.isUndefined(item.hasBlock)) {
51
+ result = item.hasBlock === true || item.hasBlock === false;
52
+ }
53
+
54
+ if (!_.isUndefined(item.name)) {
55
+ result = _.isString(item.name) && item.name.length;
56
+ }
45
57
 
46
- if (!_.isUndefined(item.parameter)) {
47
- result = (_.isString(item.parameter) && item.parameter.length) || _.isRegExp(item.parameter);
58
+ if (!_.isUndefined(item.parameter)) {
59
+ result =
60
+ (_.isString(item.parameter) && item.parameter.length) || _.isRegExp(item.parameter);
61
+ }
48
62
  }
49
- }
50
63
 
51
- if (item.type === 'rule') {
52
- if (!_.isUndefined(item.selector)) {
53
- result = (_.isString(item.selector) && item.selector.length) || _.isRegExp(item.selector);
64
+ if (item.type === 'rule') {
65
+ if (!_.isUndefined(item.selector)) {
66
+ result = (_.isString(item.selector) && item.selector.length) || _.isRegExp(item.selector);
67
+ }
54
68
  }
55
- }
56
69
 
57
- return result;
58
- })) {
70
+ return result;
71
+ })
72
+ ) {
59
73
  return false;
60
74
  }
61
75
 
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const stylelint = require('stylelint');
4
2
  const _ = require('lodash');
5
3
  const postcss = require('postcss');
@@ -16,7 +14,7 @@ const messages = stylelint.utils.ruleMessages(ruleName, {
16
14
  function rule(actual, options, context) {
17
15
  context = context || {};
18
16
 
19
- return function (root, result) {
17
+ return function(root, result) {
20
18
  const validOptions = stylelint.utils.validateOptions(
21
19
  result,
22
20
  ruleName,
@@ -71,7 +69,7 @@ function checkNode(node, result) {
71
69
  return;
72
70
  }
73
71
 
74
- const prop = child.prop;
72
+ const { prop } = child;
75
73
 
76
74
  if (!utils.isStandardSyntaxProperty(prop)) {
77
75
  return;
Binary file
@@ -568,42 +568,3 @@ a {
568
568
  ```
569
569
 
570
570
  If `unspecified` secondary option was set to `ignore`, it will be re-set to `bottom`.
571
-
572
- If `order: "flexible"` is using, for sorting it will be treated as `strict`. It might change properties order, but linting will not be broken.
573
-
574
- Given:
575
-
576
- ```json
577
- {
578
- "properties-order": [
579
- {
580
- "order": "flexible",
581
- "properties": [
582
- "color",
583
- "font-size",
584
- "font-weight"
585
- ]
586
- }
587
- ]
588
- }
589
- ```
590
-
591
- Before:
592
-
593
- ```css
594
- a {
595
- font-size: 1em;
596
- color: pink;
597
- font-weight: normal;
598
- }
599
- ```
600
-
601
- After:
602
-
603
- ```css
604
- a {
605
- color: pink;
606
- font-size: 1em;
607
- font-weight: normal;
608
- }
609
- ```
@@ -1,14 +1,12 @@
1
- 'use strict';
2
-
3
1
  const _ = require('lodash');
4
2
 
5
3
  // Add an empty line before a node. Mutates the node.
6
4
  module.exports = function addEmptyLineBefore(node, newline) {
7
- if (!(/\r?\n/).test(node.raws.before)) {
5
+ if (!/\r?\n/.test(node.raws.before)) {
8
6
  node.raws.before = _.repeat(newline, 2) + node.raws.before;
9
- } else if ((/^\r?\n/).test(node.raws.before)) {
7
+ } else if (/^\r?\n/.test(node.raws.before)) {
10
8
  node.raws.before = newline + node.raws.before;
11
- } else if ((/\r?\n$/).test(node.raws.before)) {
9
+ } else if (/\r?\n$/.test(node.raws.before)) {
12
10
  node.raws.before = node.raws.before + newline;
13
11
  } else {
14
12
  node.raws.before = node.raws.before.replace(/(\r?\n)/, `${newline}$1`);
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const stylelint = require('stylelint');
4
2
  const _ = require('lodash');
5
3
  const addEmptyLineBefore = require('./addEmptyLineBefore');
@@ -11,17 +9,16 @@ module.exports = function checkEmptyLineBefore(firstPropData, secondPropData, sh
11
9
  const secondPropIsUnspecified = !secondPropData.orderData;
12
10
 
13
11
  // Now check newlines between ...
14
- const firstPropSeparatedGroup = (!firstPropIsUnspecified)
12
+ const firstPropSeparatedGroup = !firstPropIsUnspecified
15
13
  ? firstPropData.orderData.separatedGroup
16
14
  : sharedInfo.lastKnownSeparatedGroup;
17
- const secondPropSeparatedGroup = (!secondPropIsUnspecified)
15
+ const secondPropSeparatedGroup = !secondPropIsUnspecified
18
16
  ? secondPropData.orderData.separatedGroup
19
17
  : sharedInfo.lastKnownSeparatedGroup;
20
18
 
21
- if (
22
- firstPropSeparatedGroup !== secondPropSeparatedGroup
23
- && !secondPropIsUnspecified
24
- ) {
19
+ sharedInfo.lastKnownSeparatedGroup = secondPropSeparatedGroup;
20
+
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
 
@@ -30,7 +27,7 @@ module.exports = function checkEmptyLineBefore(firstPropData, secondPropData, sh
30
27
  const emptyLineBefore = _.get(groups[secondPropSeparatedGroup - 2], 'emptyLineBefore');
31
28
 
32
29
  if (!hasEmptyLineBefore(secondPropData.node) && emptyLineBefore === 'always') {
33
- if (sharedInfo.context.fix && !sharedInfo.disableFix) {
30
+ if (sharedInfo.isFixEnabled) {
34
31
  addEmptyLineBefore(secondPropData.node, sharedInfo.context.newline);
35
32
  } else {
36
33
  stylelint.utils.report({
@@ -41,7 +38,7 @@ module.exports = function checkEmptyLineBefore(firstPropData, secondPropData, sh
41
38
  });
42
39
  }
43
40
  } else if (hasEmptyLineBefore(secondPropData.node) && emptyLineBefore === 'never') {
44
- if (sharedInfo.context.fix && !sharedInfo.disableFix) {
41
+ if (sharedInfo.isFixEnabled) {
45
42
  removeEmptyLinesBefore(secondPropData.node, sharedInfo.context.newline);
46
43
  } else {
47
44
  stylelint.utils.report({
@@ -53,6 +50,4 @@ module.exports = function checkEmptyLineBefore(firstPropData, secondPropData, sh
53
50
  }
54
51
  }
55
52
  }
56
-
57
- sharedInfo.lastKnownSeparatedGroup = secondPropSeparatedGroup;
58
53
  };
@@ -1,95 +1,93 @@
1
- 'use strict';
2
-
3
1
  const stylelint = require('stylelint');
4
2
  const postcss = require('postcss');
5
- const _ = require('lodash');
3
+ const postcssSorting = require('postcss-sorting');
6
4
  const utils = require('../../utils');
7
5
  const checkEmptyLineBefore = require('./checkEmptyLineBefore');
8
6
  const checkOrder = require('./checkOrder');
7
+ const getNodeData = require('./getNodeData');
8
+ const createFlatOrder = require('./createFlatOrder');
9
9
 
10
10
  module.exports = function checkNode(node, sharedInfo) {
11
- // Skip if it's an empty rule
12
- if (!node.nodes || !node.nodes.length) {
13
- return;
14
- }
15
-
16
- const allPropData = [];
17
11
  const allNodesData = [];
18
12
 
19
- sharedInfo.lastKnownSeparatedGroup = 1;
13
+ // Collect order data for all nodes
14
+ node.each(function collectDataForEveryNode(child) {
15
+ const nodeData = getNodeData(child, sharedInfo.expectedOrder);
20
16
 
21
- node.each(function processEveryNode(child) {
22
- let nodeData = {
23
- node: child,
24
- };
25
-
26
- if (child.type === 'decl') {
27
- const prop = child.prop;
28
-
29
- if (
30
- utils.isStandardSyntaxProperty(prop)
31
- && !utils.isCustomProperty(prop)
32
- ) {
33
- let unprefixedPropName = postcss.vendor.unprefixed(prop);
34
-
35
- // Hack to allow -moz-osx-font-smoothing to be understood
36
- // just like -webkit-font-smoothing
37
- if (unprefixedPropName.indexOf('osx-') === 0) {
38
- unprefixedPropName = unprefixedPropName.slice(4);
39
- }
17
+ allNodesData.push(nodeData);
18
+ });
40
19
 
41
- nodeData = {
42
- name: prop,
43
- unprefixedName: unprefixedPropName,
44
- orderData: sharedInfo.expectedOrder[unprefixedPropName],
45
- node: child,
46
- };
20
+ const allPropData = allNodesData.filter(item => item.name);
21
+ let shouldFixOrder = false;
47
22
 
48
- allPropData.push(nodeData);
49
- }
23
+ // First, check order
24
+ allPropData.forEach(function checkEveryPropForOrder(propData, index) {
25
+ // return early if we know there is a violation and auto fix should be applied
26
+ if (shouldFixOrder && sharedInfo.isFixEnabled) {
27
+ return;
50
28
  }
51
29
 
52
- allNodesData.push(nodeData);
53
-
54
30
  // current node should be a standard declaration
55
- if (
56
- child.type !== 'decl'
57
- || !utils.isStandardSyntaxProperty(nodeData.node.prop)
58
- || utils.isCustomProperty(nodeData.node.prop)
59
- ) {
31
+ if (!utils.isProperty(propData.node)) {
60
32
  return;
61
33
  }
62
34
 
63
- // First, check order
64
- const previousPropData = _.nth(allPropData, -2);
35
+ const previousPropData = allPropData[index - 1];
65
36
 
66
37
  // Skip first decl
67
- if (
68
- previousPropData
69
- && (!sharedInfo.context.fix || sharedInfo.disableFix)
70
- ) {
71
- const isCorrectOrder = checkOrder(previousPropData, nodeData, allPropData, sharedInfo);
72
-
73
- if (!isCorrectOrder) {
74
- stylelint.utils.report({
75
- message: sharedInfo.messages.expected(nodeData.name, previousPropData.name),
76
- node: child,
77
- result: sharedInfo.result,
78
- ruleName: sharedInfo.ruleName,
79
- });
38
+ if (previousPropData) {
39
+ const checkedOrder = checkOrder({
40
+ firstPropData: previousPropData,
41
+ secondPropData: propData,
42
+ unspecified: sharedInfo.unspecified,
43
+ allPropData: allPropData.slice(0, index),
44
+ });
45
+
46
+ if (!checkedOrder.result) {
47
+ if (sharedInfo.isFixEnabled) {
48
+ shouldFixOrder = true;
49
+ } else {
50
+ stylelint.utils.report({
51
+ message: sharedInfo.messages.expected(
52
+ checkedOrder.secondNode.name,
53
+ checkedOrder.firstNode.name
54
+ ),
55
+ node: checkedOrder.secondNode.node,
56
+ result: sharedInfo.result,
57
+ ruleName: sharedInfo.ruleName,
58
+ });
59
+ }
80
60
  }
81
61
  }
62
+ });
63
+
64
+ if (shouldFixOrder && sharedInfo.isFixEnabled) {
65
+ const sortingOptions = {
66
+ 'properties-order': createFlatOrder(sharedInfo.expectation),
67
+ 'unspecified-properties-position':
68
+ sharedInfo.unspecified === 'ignore' ? 'bottom' : sharedInfo.unspecified,
69
+ };
70
+
71
+ // creating PostCSS Root node with current node as a child,
72
+ // so PostCSS Sorting can process it
73
+ const tempRoot = postcss.root({ nodes: [node] });
74
+
75
+ postcssSorting(sortingOptions)(tempRoot);
76
+ }
77
+
78
+ sharedInfo.lastKnownSeparatedGroup = 1;
82
79
 
83
- // Second, check emptyLineBefore
84
- let previousNodeData = _.nth(allNodesData, -2);
80
+ // Second, check emptyLineBefore
81
+ allNodesData.forEach(function checkEveryPropForEmptyLine(nodeData, index) {
82
+ let previousNodeData = allNodesData[index - 1];
85
83
 
86
84
  // if previous node is shared-line comment, use second previous node
87
85
  if (
88
- previousNodeData
89
- && previousNodeData.node.type === 'comment'
90
- && previousNodeData.node.raw('before').indexOf('\n') === -1
86
+ previousNodeData &&
87
+ previousNodeData.node.type === 'comment' &&
88
+ previousNodeData.node.raw('before').indexOf('\n') === -1
91
89
  ) {
92
- previousNodeData = _.nth(allNodesData, -3);
90
+ previousNodeData = allNodesData[index - 2];
93
91
  }
94
92
 
95
93
  // skip first decl
@@ -97,18 +95,11 @@ module.exports = function checkNode(node, sharedInfo) {
97
95
  return;
98
96
  }
99
97
 
100
- if (previousNodeData.node.type !== 'decl') {
101
- return;
102
- }
103
-
104
98
  // previous node should be a standard declaration
105
- if (
106
- !utils.isStandardSyntaxProperty(previousNodeData.node.prop)
107
- || utils.isCustomProperty(previousNodeData.node.prop)
108
- ) {
99
+ if (!utils.isProperty(previousNodeData.node)) {
109
100
  return;
110
101
  }
111
102
 
112
- checkEmptyLineBefore(previousPropData, nodeData, sharedInfo);
103
+ checkEmptyLineBefore(previousNodeData, nodeData, sharedInfo);
113
104
  });
114
105
  };
@@ -1,18 +1,26 @@
1
- 'use strict';
2
-
3
- const stylelint = require('stylelint');
4
1
  const postcss = require('postcss');
5
2
  const _ = require('lodash');
6
3
  const checkAlphabeticalOrder = require('../checkAlphabeticalOrder');
7
4
 
8
- module.exports = function checkOrder(firstPropData, secondPropData, allPropData, sharedInfo) {
5
+ module.exports = function checkOrder({ firstPropData, secondPropData, allPropData, unspecified }) {
6
+ function report(result, firstNode = firstPropData, secondNode = secondPropData) {
7
+ return {
8
+ result,
9
+ firstNode,
10
+ secondNode,
11
+ };
12
+ }
13
+
9
14
  if (firstPropData.unprefixedName === secondPropData.unprefixedName) {
10
15
  // If first property has no prefix and second property has prefix
11
- if (!postcss.vendor.prefix(firstPropData.name).length && postcss.vendor.prefix(secondPropData.name).length) {
12
- return false;
16
+ if (
17
+ !postcss.vendor.prefix(firstPropData.name).length &&
18
+ postcss.vendor.prefix(secondPropData.name).length
19
+ ) {
20
+ return report(false);
13
21
  }
14
22
 
15
- return true;
23
+ return report(true);
16
24
  }
17
25
 
18
26
  const firstPropIsUnspecified = !firstPropData.orderData;
@@ -20,76 +28,64 @@ module.exports = function checkOrder(firstPropData, secondPropData, allPropData,
20
28
 
21
29
  // Check actual known properties
22
30
  if (!firstPropIsUnspecified && !secondPropIsUnspecified) {
23
- return firstPropData.orderData.expectedPosition <= secondPropData.orderData.expectedPosition;
31
+ return report(
32
+ firstPropData.orderData.expectedPosition <= secondPropData.orderData.expectedPosition
33
+ );
24
34
  }
25
35
 
26
36
  if (firstPropIsUnspecified && !secondPropIsUnspecified) {
27
37
  // If first prop is unspecified, look for a specified prop before it to
28
38
  // compare to the current prop
29
- const priorSpecifiedPropData = _.findLast(allPropData.slice(0, -1), (d) => Boolean(d.orderData));
39
+ const priorSpecifiedPropData = _.findLast(allPropData.slice(0, -1), d => Boolean(d.orderData));
30
40
 
31
41
  if (
32
- priorSpecifiedPropData
33
- && priorSpecifiedPropData.orderData
34
- && priorSpecifiedPropData.orderData.expectedPosition > secondPropData.orderData.expectedPosition
42
+ priorSpecifiedPropData &&
43
+ priorSpecifiedPropData.orderData &&
44
+ priorSpecifiedPropData.orderData.expectedPosition > secondPropData.orderData.expectedPosition
35
45
  ) {
36
- stylelint.utils.report({
37
- message: sharedInfo.messages.expected(secondPropData.name, priorSpecifiedPropData.name),
38
- node: secondPropData.node,
39
- result: sharedInfo.result,
40
- ruleName: sharedInfo.ruleName,
41
- });
42
-
43
- return true; // avoid logging another warning
46
+ return report(false, priorSpecifiedPropData, secondPropData);
44
47
  }
45
48
  }
46
49
 
47
- const unspecified = sharedInfo.unspecified;
48
-
49
50
  // Now deal with unspecified props
50
51
  // Starting with bottomAlphabetical as it requires more specific conditionals
51
- if (
52
- unspecified === 'bottomAlphabetical'
53
- && !firstPropIsUnspecified
54
- && secondPropIsUnspecified
55
- ) {
56
- return true;
52
+ if (unspecified === 'bottomAlphabetical' && !firstPropIsUnspecified && secondPropIsUnspecified) {
53
+ return report(true);
57
54
  }
58
55
 
59
- if (
60
- unspecified === 'bottomAlphabetical'
61
- && secondPropIsUnspecified
62
- && firstPropIsUnspecified
63
- ) {
56
+ if (unspecified === 'bottomAlphabetical' && firstPropIsUnspecified && secondPropIsUnspecified) {
64
57
  if (checkAlphabeticalOrder(firstPropData, secondPropData)) {
65
- return true;
58
+ return report(true);
66
59
  }
67
60
 
68
- return false;
61
+ return report(false);
69
62
  }
63
+
70
64
  if (unspecified === 'bottomAlphabetical' && firstPropIsUnspecified) {
71
- return false;
65
+ return report(false);
72
66
  }
73
67
 
74
68
  if (firstPropIsUnspecified && secondPropIsUnspecified) {
75
- return true;
69
+ return report(true);
76
70
  }
77
71
 
78
72
  if (unspecified === 'ignore' && (firstPropIsUnspecified || secondPropIsUnspecified)) {
79
- return true;
73
+ return report(true);
80
74
  }
81
75
 
82
76
  if (unspecified === 'top' && firstPropIsUnspecified) {
83
- return true;
77
+ return report(true);
84
78
  }
79
+
85
80
  if (unspecified === 'top' && secondPropIsUnspecified) {
86
- return false;
81
+ return report(false);
87
82
  }
88
83
 
89
84
  if (unspecified === 'bottom' && secondPropIsUnspecified) {
90
- return true;
85
+ return report(true);
91
86
  }
87
+
92
88
  if (unspecified === 'bottom' && firstPropIsUnspecified) {
93
- return false;
89
+ return report(false);
94
90
  }
95
91
  };
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const _ = require('lodash');
4
2
 
5
3
  module.exports = function createExpectedOrder(input) {
@@ -10,7 +8,7 @@ module.exports = function createExpectedOrder(input) {
10
8
  appendGroup(input);
11
9
 
12
10
  function appendGroup(items) {
13
- items.forEach((item) => appendItem(item, false));
11
+ items.forEach(item => appendItem(item, false));
14
12
  }
15
13
 
16
14
  function appendItem(item, inFlexibleGroup) {
@@ -35,7 +33,7 @@ module.exports = function createExpectedOrder(input) {
35
33
  if (item.order && item.order === 'flexible') {
36
34
  expectedPosition += 1;
37
35
 
38
- item.properties.forEach((property) => {
36
+ item.properties.forEach(property => {
39
37
  appendItem(property, true);
40
38
  });
41
39
  } else {
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const _ = require('lodash');
4
2
 
5
3
  module.exports = function createFlatOrder(order) {
@@ -8,7 +6,7 @@ module.exports = function createFlatOrder(order) {
8
6
  appendGroup(order);
9
7
 
10
8
  function appendGroup(items) {
11
- items.forEach((item) => appendItem(item));
9
+ items.forEach(item => appendItem(item));
12
10
  }
13
11
 
14
12
  function appendItem(item) {
@@ -0,0 +1,25 @@
1
+ const postcss = require('postcss');
2
+ const utils = require('../../utils');
3
+
4
+ module.exports = function getNodeData(node, expectedOrder) {
5
+ const nodeData = {
6
+ node,
7
+ };
8
+
9
+ if (utils.isProperty(node)) {
10
+ const { prop } = node;
11
+ let unprefixedPropName = postcss.vendor.unprefixed(prop);
12
+
13
+ // Hack to allow -moz-osx-font-smoothing to be understood
14
+ // just like -webkit-font-smoothing
15
+ if (unprefixedPropName.indexOf('osx-') === 0) {
16
+ unprefixedPropName = unprefixedPropName.slice(4);
17
+ }
18
+
19
+ nodeData.name = prop;
20
+ nodeData.unprefixedName = unprefixedPropName;
21
+ nodeData.orderData = expectedOrder[unprefixedPropName];
22
+ }
23
+
24
+ return nodeData;
25
+ };
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  module.exports = function hasEmptyLineBefore(decl) {
4
2
  if (/\r?\n\s*\r?\n/.test(decl.raw('before'))) {
5
3
  return true;
@@ -1,26 +1,20 @@
1
- 'use strict';
2
-
3
1
  const stylelint = require('stylelint');
4
2
  const _ = require('lodash');
5
- const postcssSorting = require('postcss-sorting');
6
3
  const utils = require('../../utils');
7
4
  const checkNode = require('./checkNode');
8
5
  const createExpectedOrder = require('./createExpectedOrder');
9
- const createFlatOrder = require('./createFlatOrder');
10
6
  const validatePrimaryOption = require('./validatePrimaryOption');
11
7
 
12
8
  const ruleName = utils.namespace('properties-order');
13
9
 
14
10
  const messages = stylelint.utils.ruleMessages(ruleName, {
15
11
  expected: (first, second) => `Expected "${first}" to come before "${second}"`,
16
- expectedEmptyLineBefore: (property) => `Expected an empty line before property "${property}"`,
17
- rejectedEmptyLineBefore: (property) => `Unexpected an empty line before property "${property}"`,
12
+ expectedEmptyLineBefore: property => `Expected an empty line before property "${property}"`,
13
+ rejectedEmptyLineBefore: property => `Unexpected an empty line before property "${property}"`,
18
14
  });
19
15
 
20
- const rule = function (expectation, options, context) {
21
- context = context || {};
22
-
23
- return function (root, result) {
16
+ const rule = function(expectation, options, context = {}) {
17
+ return function(root, result) {
24
18
  const validOptions = stylelint.utils.validateOptions(
25
19
  result,
26
20
  ruleName,
@@ -31,12 +25,7 @@ const rule = function (expectation, options, context) {
31
25
  {
32
26
  actual: options,
33
27
  possible: {
34
- unspecified: [
35
- 'top',
36
- 'bottom',
37
- 'ignore',
38
- 'bottomAlphabetical',
39
- ],
28
+ unspecified: ['top', 'bottom', 'ignore', 'bottomAlphabetical'],
40
29
  disableFix: _.isBoolean,
41
30
  },
42
31
  optional: true,
@@ -48,22 +37,9 @@ const rule = function (expectation, options, context) {
48
37
  }
49
38
 
50
39
  // By default, ignore unspecified properties
51
- let unspecified = _.get(options, ['unspecified'], 'ignore');
52
-
53
- const disableFix = _.get(options, ['disableFix'], false);
54
-
55
- if (context.fix && !disableFix) {
56
- if (unspecified === 'ignore') {
57
- unspecified = 'bottom';
58
- }
59
-
60
- const sortingOptions = {
61
- 'properties-order': createFlatOrder(expectation),
62
- 'unspecified-properties-position': unspecified,
63
- };
64
-
65
- postcssSorting(sortingOptions)(root);
66
- }
40
+ const unspecified = _.get(options, 'unspecified', 'ignore');
41
+ const disableFix = _.get(options, 'disableFix', false);
42
+ const isFixEnabled = context.fix && !disableFix;
67
43
 
68
44
  const expectedOrder = createExpectedOrder(expectation);
69
45
 
@@ -75,12 +51,12 @@ const rule = function (expectation, options, context) {
75
51
  ruleName,
76
52
  result,
77
53
  context,
78
- disableFix,
54
+ isFixEnabled,
79
55
  };
80
56
 
81
57
  // Check all rules and at-rules recursively
82
58
  root.walk(function processRulesAndAtrules(node) {
83
- if (node.type === 'rule' || node.type === 'atrule') {
59
+ if (utils.isRuleWithNodes(node)) {
84
60
  checkNode(node, sharedInfo);
85
61
  }
86
62
  });
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  // Remove empty lines before a node. Mutates the node.
4
2
  module.exports = function removeEmptyLinesBefore(node, newline) {
5
3
  node.raws.before = node.raws.before.replace(/(\r?\n\s*\r?\n)+/g, newline);
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  const _ = require('lodash');
4
2
 
5
3
  module.exports = function validatePrimaryOption(actualOptions) {
@@ -10,37 +8,43 @@ module.exports = function validatePrimaryOption(actualOptions) {
10
8
 
11
9
  // Every item in the array must be a string or an object
12
10
  // with a "properties" property
13
- if (!actualOptions.every((item) => {
14
- if (_.isString(item)) {
15
- return true;
16
- }
17
-
18
- return _.isPlainObject(item) && !_.isUndefined(item.properties);
19
- })) {
11
+ if (
12
+ !actualOptions.every(item => {
13
+ if (_.isString(item)) {
14
+ return true;
15
+ }
16
+
17
+ return _.isPlainObject(item) && !_.isUndefined(item.properties);
18
+ })
19
+ ) {
20
20
  return false;
21
21
  }
22
22
 
23
23
  const objectItems = actualOptions.filter(_.isPlainObject);
24
24
 
25
25
  // Every object-item's "properties" should be an array with no items, or with strings
26
- if (!objectItems.every((item) => {
27
- if (!Array.isArray(item.properties)) {
28
- return false;
29
- }
30
-
31
- return item.properties.every((property) => _.isString(property));
32
- })) {
26
+ if (
27
+ !objectItems.every(item => {
28
+ if (!Array.isArray(item.properties)) {
29
+ return false;
30
+ }
31
+
32
+ return item.properties.every(property => _.isString(property));
33
+ })
34
+ ) {
33
35
  return false;
34
36
  }
35
37
 
36
38
  // Every object-item's "emptyLineBefore" must be "always" or "never"
37
- if (!objectItems.every((item) => {
38
- if (_.isUndefined(item.emptyLineBefore)) {
39
- return true;
40
- }
41
-
42
- return _.includes(['always', 'never'], item.emptyLineBefore);
43
- })) {
39
+ if (
40
+ !objectItems.every(item => {
41
+ if (_.isUndefined(item.emptyLineBefore)) {
42
+ return true;
43
+ }
44
+
45
+ return _.includes(['always', 'never'], item.emptyLineBefore);
46
+ })
47
+ ) {
44
48
  return false;
45
49
  }
46
50
 
package/utils/index.js CHANGED
@@ -2,6 +2,8 @@ module.exports = {
2
2
  namespace: require('./namespace'),
3
3
  isCustomProperty: require('./isCustomProperty'),
4
4
  isStandardSyntaxProperty: require('./isStandardSyntaxProperty'),
5
+ isProperty: require('./isProperty'),
5
6
  isDollarVariable: require('./isDollarVariable'),
6
7
  isAtVariable: require('./isAtVariable'),
8
+ isRuleWithNodes: require('./isRuleWithNodes'),
7
9
  };
@@ -6,5 +6,5 @@
6
6
  */
7
7
 
8
8
  module.exports = function isCustomProperty(property) {
9
- return (property.slice(0, 2) === '--');
9
+ return property.slice(0, 2) === '--';
10
10
  };
@@ -0,0 +1,9 @@
1
+ // Check whether a property is a CSS property
2
+ const isCustomProperty = require('./isCustomProperty');
3
+ const isStandardSyntaxProperty = require('./isStandardSyntaxProperty');
4
+
5
+ module.exports = function isProperty(node) {
6
+ return (
7
+ node.type === 'decl' && isStandardSyntaxProperty(node.prop) && !isCustomProperty(node.prop)
8
+ );
9
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = function isRuleWithNodes(node) {
2
+ return (node.type === 'rule' || node.type === 'atrule') && node.nodes && node.nodes.length;
3
+ };