diff --git a/README.md b/README.md index 206a56c..1f73f3b 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ yarn add --dev stylelint stylelint-order stylelint-config-rational-order ``` This shareable config contains the following: -```javascript +```json { "plugins": [ "stylelint-order", @@ -86,6 +86,7 @@ This shareable config contains the following: "plugin/rational-order": [true, { "border-in-box-model": false, "empty-line-between-groups": false, + "empty-line-minimum-property-threshold": 0 }] } } @@ -108,6 +109,16 @@ The default value is `false` (**border** property belongs to the **visual sectio If `true` adds an empty line between groups. The default value is `false`. +A third option `'threshold'` is available and described under [empty-line-minimum-property-threshold](#empty-line-minimum-property-threshold) + +#### empty-line-minimum-property-threshold + +If `empty-line-between-groups: 'threshold'`, the empty line behaviour toggles based on the number of properties in the rule. + +When the configured minimum property threshold is reached, empty lines are **inserted**. When the number of properties is less than the minimum property threshold, empty lines are **removed**. + +_e.g. threshold set to **3**, and there are **5** properties in total, then groups will have an empty line inserted._ + ## FAQ
diff --git a/__tests__/index.js b/__tests__/index.js index 81b2fd4..95a5a6c 100644 --- a/__tests__/index.js +++ b/__tests__/index.js @@ -191,6 +191,101 @@ describe('stylelint-config-rational-order/plugin', () => { expect(warnings).toHaveLength(0); }); }); + + it('with "empty-line-between-groups" = "threshold" AND with "empty-line-minimum-property-threshold" = ', () => { + const rules = { + [ruleName]: [ + true, + { + 'empty-line-between-groups': 'threshold', + }, + ], + }; + const correct = ` + a { + position: relative; + z-index: 10; + + display: block; + width: auto; + height: auto; + margin: 10px; + padding: 10px; + + color: red; + + background: white; + border: 1px solid blue; + } + `; + return stylelint.lint(getPluginOptions(correct, rules)).then(output => { + const { errored } = output; + const { warnings } = output.results[0]; + expect(errored).toBeFalsy(); + expect(warnings).toHaveLength(0); + }); + }); + + it('with "empty-line-between-groups" = "threshold" AND with "empty-line-minimum-property-threshold" = 5 (above threshold)', () => { + const rules = { + [ruleName]: [ + true, + { + 'empty-line-between-groups': 'threshold', + 'empty-line-minimum-property-threshold': 5, + }, + ], + }; + const correct = ` + a { + position: relative; + z-index: 10; + + display: block; + width: auto; + height: auto; + margin: 10px; + padding: 10px; + + color: red; + + background: white; + border: 1px solid blue; + } + `; + return stylelint.lint(getPluginOptions(correct, rules)).then(output => { + const { errored } = output; + const { warnings } = output.results[0]; + expect(errored).toBeFalsy(); + expect(warnings).toHaveLength(0); + }); + }); + + it('with "empty-line-between-groups" = "threshold" AND with "empty-line-minimum-property-threshold" = 5 (below threshold)', () => { + const rules = { + [ruleName]: [ + true, + { + 'empty-line-between-groups': 'threshold', + 'empty-line-minimum-property-threshold': 5, + }, + ], + }; + const correct = ` + a { + position: relative; + z-index: 10; + display: block; + background: white; + } + `; + return stylelint.lint(getPluginOptions(correct, rules)).then(output => { + const { errored } = output; + const { warnings } = output.results[0]; + expect(errored).toBeFalsy(); + expect(warnings).toHaveLength(0); + }); + }); }); describe('wrong order with disabled plugin', () => { diff --git a/config/configCreator.js b/config/configCreator.js index d7fddea..4cd55e2 100644 --- a/config/configCreator.js +++ b/config/configCreator.js @@ -1,3 +1,4 @@ +const emptyLineBeforeOption = require('./emptyLineBeforeOption'); const special = require('../groups/special'); const positioning = require('../groups/positioning'); const boxModel = require('../groups/boxModel'); @@ -19,7 +20,7 @@ module.exports = ({ ['Animation', animation], ['Misc', misc], ].map(([groupName, properties]) => ({ - emptyLineBefore: emptyLineBetweenGroups ? 'always' : 'never', + emptyLineBefore: emptyLineBeforeOption(emptyLineBetweenGroups), properties, groupName, })); diff --git a/config/emptyLineBeforeOption.js b/config/emptyLineBeforeOption.js new file mode 100644 index 0000000..1784195 --- /dev/null +++ b/config/emptyLineBeforeOption.js @@ -0,0 +1,4 @@ +module.exports = emptyLineBetweenGroups => { + if (emptyLineBetweenGroups === 'threshold') return 'threshold'; + return emptyLineBetweenGroups ? 'always' : 'never'; +}; diff --git a/config/extendedStylelintOrderConfig.js b/config/extendedStylelintOrderConfig.js index 42afa4e..eba55bc 100644 --- a/config/extendedStylelintOrderConfig.js +++ b/config/extendedStylelintOrderConfig.js @@ -4,6 +4,7 @@ const specialProps = require('../groups/special'); module.exports = ({ 'border-in-box-model': borderInBoxModel = false, 'empty-line-between-groups': emptyLineBetweenGroups = false, + 'empty-line-minimum-property-threshold': emptyLineMinimumPropertyThreshold = 0, } = {}) => ({ plugins: ['stylelint-order', path.join(__dirname, '../plugin')], rules: { @@ -19,6 +20,7 @@ module.exports = ({ { 'border-in-box-model': borderInBoxModel, 'empty-line-between-groups': emptyLineBetweenGroups, + 'empty-line-minimum-property-threshold': emptyLineMinimumPropertyThreshold, }, ], }, diff --git a/config/propertiesOrderOptionsCreator.js b/config/propertiesOrderOptionsCreator.js new file mode 100644 index 0000000..820e328 --- /dev/null +++ b/config/propertiesOrderOptionsCreator.js @@ -0,0 +1,9 @@ +const emptyLineBeforeOption = require('./emptyLineBeforeOption'); + +module.exports = ({ + 'empty-line-between-groups': emptyLineBetweenGroups = false, + 'empty-line-minimum-property-threshold': emptyLineMinimumPropertyThreshold = 0, +} = {}) => ({ + emptyLineBeforeUnspecified: emptyLineBeforeOption(emptyLineBetweenGroups), + emptyLineMinimumPropertyThreshold, +}); diff --git a/package.json b/package.json index a2047a8..7f33148 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ ], "dependencies": { "stylelint": "^9.10.1", - "stylelint-order": "^2.2.1" + "stylelint-order": "^3.1.0" }, "devDependencies": { "eslint": "^5.16.0", diff --git a/plugin/index.js b/plugin/index.js index 24412eb..85103ce 100644 --- a/plugin/index.js +++ b/plugin/index.js @@ -1,5 +1,6 @@ const stylelint = require('stylelint'); const propertiesOrderRule = require('stylelint-order/rules/properties-order'); +const propertiesOrderOptionsCreator = require('../config/propertiesOrderOptionsCreator'); const configCreator = require('../config/configCreator'); const ruleName = 'plugin/rational-order'; @@ -19,15 +20,20 @@ module.exports = stylelint.createPlugin( optional: true, possible: { 'border-in-box-model': [true, false], - 'empty-line-between-groups': [true, false], + 'empty-line-between-groups': [true, false, 'threshold'], + 'empty-line-minimum-property-threshold': Number.isInteger, }, }, ); + if (!enabled || !validOptions) { return; } + const expectation = configCreator(options); - propertiesOrderRule(expectation, undefined, context)(postcssRoot, postcssResult); + const propertiesOrderOptions = propertiesOrderOptionsCreator(options); + + propertiesOrderRule(expectation, propertiesOrderOptions, context)(postcssRoot, postcssResult); }, ); diff --git a/yarn.lock b/yarn.lock index ba6a492..843ef51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2976,11 +2976,16 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4: +lodash@^4.17.11: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + log-symbols@^2.0.0, log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -3811,13 +3816,13 @@ postcss-selector-parser@^3.1.0: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-sorting@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-sorting/-/postcss-sorting-4.1.0.tgz#a107f0bf3852977fa64e4442bc340c88d5aacdb3" - integrity sha512-r4T2oQd1giURJdHQ/RMb72dKZCuLOdWx2B/XhXN1Y1ZdnwXsKH896Qz6vD4tFy9xSjpKNYhlZoJmWyhH/7JUQw== +postcss-sorting@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-sorting/-/postcss-sorting-5.0.1.tgz#10d5d0059eea8334dacc820c0121864035bc3f11" + integrity sha512-Y9fUFkIhfrm6i0Ta3n+89j56EFqaNRdUKqXyRp6kvTcSXnmgEjaVowCXH+JBe9+YKWqd4nc28r2sgwnzJalccA== dependencies: - lodash "^4.17.4" - postcss "^7.0.0" + lodash "^4.17.14" + postcss "^7.0.17" postcss-syntax@^0.36.2: version "0.36.2" @@ -3829,7 +3834,16 @@ postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.2, postcss@^7.0.7: +postcss@^7.0.0, postcss@^7.0.17, postcss@^7.0.2: + version "7.0.17" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f" + integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@^7.0.1, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.7: version "7.0.14" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5" integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg== @@ -4575,14 +4589,14 @@ style-search@^0.1.0: resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= -stylelint-order@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-2.2.1.tgz#cd2d4a0d81d91c705f1d275a58487e5ad5aa5828" - integrity sha512-019KBV9j8qp1MfBjJuotse6MgaZqGVtXMc91GU9MsS9Feb+jYUvUU3Z8XiClqPdqJZQ0ryXQJGg3U3PcEjXwfg== +stylelint-order@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-3.1.0.tgz#e35fce453ae9ed71a2185af36b2bb45e62a9ce75" + integrity sha512-0BGQhRWOcdPi4oDVuInOHiXWzgCB9vEwJt5fvBre/I/brXLIumC9uiiAc3E6xUiUdWEmU2OLzAop8LK8UY0X0A== dependencies: - lodash "^4.17.10" - postcss "^7.0.2" - postcss-sorting "^4.1.0" + lodash "^4.17.15" + postcss "^7.0.17" + postcss-sorting "^5.0.1" stylelint@^9.10.1: version "9.10.1"