stylelint: stylelint-declaration-block-order
Stylelint doesn’t support linting rules structure. I want to add this feature using PostCSS Sorting. It will require adding linting functionality in PostCSS Sorting, which I’ll add when things got clearer 😃 Also when stylelint can check rule structure, it can be great to integrate PostCSS Sorting in stylefmt.
- Should I add this functionality as a rule or plugin? If it will be as a plugin, can it be used in stylefmt? Stylefmt support only stylelint’s config. /cc @morishitter
- What name rule or plugin should have? As a plugin name @jeddy3 suggested
stylelint-block-structure. - What to do with tests? PostCSS Sorting has a lot of tests. Should all they be copied to rule/plugin?
- What to do with options description? Options description is a long document. Should I maintain it in both places (postcss-sorting repository and stylelint/plugin repository)?
- I have no idea what primary option should be for this rule.
P. S. Nice issue number 😃
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 2
- Comments: 52 (52 by maintainers)
Fantastic. I’m glad we’re on the same page now.
Scratch that property. I misunderstood @bjankord’s requirements. I don’t use SCSS and so I hadn’t fully grokked some of the terms used in “specifically checking the order of
@includedeclarations without inner@content, properties,@includedeclarations with inner@content”. I now think that theatRuleHasBlockproperty is all that’s needed to achieve this e.g.Will allow this:
But warn for this:
This is why every stylelint rule is scoped to the smallest and most specific thing possible e.g. number (
number-max-precision) / unit (unit-blacklist) →<length>type (length-zero-no-unit) → value (value-keyword-case) / property (property-no-vendor-prefix) → declaration (declaration-no-important) → rule (rule-nested-empty-line-before). It keeps things flexible and future proof.I finally started to work on this plugin 😃 I have a problem with development, though. I want to use Chrome Dev Tools to debug my plugin (
node --inspect run.jsin Node 6.3.0+), becauseconsole.log()isn’t enough. But I don’t know how to teach stylelint that current folder is a plugin and use it. I have thisrun.js:P. S. Developing stylelint plugin is not a straightforward task 😥
I summed up config with all options plugin will have. Do I miss something?
While this plugin is on my mind, I’ll answer my own question and throw a suggestion out there.
I like to order my nested rules and nested media queries in a specific order. I believe this helps to keep things findable and scannable for larger teams, especially when there are many nested rules within a block. We use the following order:
&:hover, and&:not()&::beforeand&::after& .a {}@nest .a & {}@media (width < 100px) {}For example:
The object within the config array could be expanded to accommodate this, as so: (I’ve kept the
extendsandincludeat-rules in for illustrative purposes only, as they are not something I would normally use)Incidentally, this is a great illustration of why this will be community plugin rather than a core rule i.e. it doesn’t have a “clear and unambiguous finished state”.
One of the advantages of being a plugin is that you can iterate often and release breaking changes to the config syntax. So, it’s probably best to release something that works for at-rules first and maybe tackle the above, more involved, use-case at a later date.
Do you feel that you now have enough information to make a start on this plugin? I’m keen to see how you get on, and so would you mind posting a link to your repo once you’ve something to show? There is a “Writing plugins” section of the developer guide that you might find useful. In terms of reference material, the stylelint-scss team is doing a great job and any of their plugins would make a great blueprint. In particular, there is their
at-mixin-patternplugin, which has a great set of tests that use various configurations and syntax options. And, of course, there is also the7.0.0version ofdeclaration-block-properties-orderfor reference.Does anyone else have any feedback on the proposal or shall we get the ball rolling?
My broader proposal above hinges upon the assumption that this isn’t the case. There are already individual and laser-focused rules for linting empty lines before things. The addition of the
emptyLineBeforeoption todeclaration-block-properties-orderwas a mistake, and why it is being removed in7.0.0. This is to ensure that thedeclaration-block-properties-orderrule, like all the other rules, has a singular purpose (whether that’s linting for an empty line, or checking the order of things). This is one of the core design philosophies of stylelint, and one of the main reasons why there are no overlaps between the rules, despite there being over 140 of them.In my original proposal, I showed an example config that illustrated how all these individual whitespace and empty line rules work together. For clarity, I’ll focus on just the empty lines rules below:
I believe these laser-focused rules, with the help of their secondary options, already work well together to lint empty lines within blocks. In my original proposal I mentioned that there are a couple of holes to fill, and I’ve created separate issues for those:
declaration-no-empty-line-before: https://github.com/stylelint/stylelint/issues/1573custom-property-no-empty-line-before: https://github.com/stylelint/stylelint/issues/1578block-closing-brace-empty-line-before: https://github.com/stylelint/stylelint/issues/1574dollar-variable-no-empty-line-before: https://github.com/kristerkari/stylelint-scss/issues/53Hopefully the above explanation has made it a little clearer why I believe this new plugin should only be focused on the order of non-properties within a block, and not concerned with whitespace or empty lines?
I think you’re on to something with accepting objects though, but for a different reason than controlling whitespace. I think you’re right that objects are more extensible, which will be especially useful for the user-defined at-rules. For example:
I like this approach as:
"at-rules","nested-rules","declarations","custom-properties","dollar-variables"etc.) and user-defined at-rules.Off hand, I can think of the following ways to extend that object:
I believe this makes achieving @bjankord’s requirements viable.
Can you think of any other useful ways that this object could be extended?
In the example above I’ve used two separate keywords,
"custom-properties"and"dollar-variables", as this is in-keeping with how we categorise things. I believe this fine-grain categorisation is more future proof e.g. it’s possible to use custom properties and dollar variables side-by-side i.e. dollar variables for build-time variables, and custom properties for computed-time variables.Don’t worry, I have no intention of writing or maintaining this plugin 😃 My interest here is to ensure that the plugin works together with the other rules and that overlapping functionality is avoided.
The gist of
stylelint-block-non-properties-orderis outlined in my comment above. However, it’s interwoven into a larger proposal about how rules work together. For everyone’s sanity, including my own, I’ll pull out and extend on thestylelint-block-non-properties-orderstuff below 😃The first thing to keep in mind is that we still need to finalise the name and exact options. What is decided on is the scope of the plugin and how the plugin will work together with the existing rules and with these two new rules: https://github.com/stylelint/stylelint/issues/1574 & https://github.com/stylelint/stylelint/issues/1573. How and why this works is covered in my comment above and by examples I gave.
OK, so my suggestion for the general outline of this plugin is:
stylelint-block-non-properties-order["array", "of", "predefined-keywords", "and", "userdefined-at-rule-names"]Expected "${first}" to come before "${second}"Its singular purpose is to lint the order of non-properties (excluding comments) within a block. It is not concerned with any whitespace nor the order of properties.
The inspiration (and internals) for the keywords within the primary object array could be taken from PostCSS sorting’s at-rule, nested rule and variable options.
An example rule config using all of these keywords could be:
*To reiterate this plugin isn’t concerned with the order of properties/declarations. Only that the declarations appear at the right place within the block.
And again, the keywords within the primary option array are just suggestions. We need to ask ourselves whether they allow people enough control to specify exactly the order of non-properties they want? e.g. does it allow for this?
Some examples, given the config above…
Would yield:
And:
Would yield:
@bjankord Thank you for your input. I especially appreciate that you looked through the spider’s web of historical issues to get a grip on this 😃
As you can see there are a number of use-cases to consider and fair few competing interests. I think I have a proposal that might be satisfactory to all parties, and I’ll try to outline that below.
I believe this to be the crux of the issue. We’ve been very careful in the past to create very focused rules who’s functionality does not overlap. Currently we already have one sorting rule (for properties), a number of non-overlapping empty line rules and number of non-overlapping newline rules in core. My new proposal is that, where possible, any new plugin complements these existing rules, rather than overlaps them.
I think the following example and config will help us all understand what can be linted with the existing rules, and where there are holes to fill:
And with the following abbreviated config:
As you can see, we can already lint the vast majority of newlines and empty lines, including:
And we can lint the order of properties.
So, I think we are only lacking three features:
I think we can simply address the first one with a new
block-closing-brace-empty-line-before: "always"|"never"rule. This rule would only check multi-line blocks and check whether the closing brace is preceded by an empty line.I think the second feature is the responsibility of plugin called
stylelint-block-non-properties-order: [](and the focus of this issue). The inspiration (and internals) for which could be taken from PostCSS sorting’s at-rule, nested rule and variable options. This plugin would not be concerned with any whitespace nor the order of properties. An example rule config for the above CSS example could be:The above example shows the use of pre-defined keywords (like
"declarations"and"nested-rules") as well as user-defined at-rule names (like"@apply","@nest"and"@media").Lastly, I think we can address the simpler use-case of the third feature in core with a new
declaration-empty-line-before": [ "always"|"never", { "except": ["first-nested"], "ignore": ["after-comment"] } ]rule (ref).Whereas, I think linting empty lines before property groups should be a plugin as there are all sorts of edge-cases in and around this feature. One option could be a plugin (perhaps called
stylelint-property-groups-structure) that builds on top ofdeclaration-block-properties-order. This kind of mixes the concerns of empty lines with ordering, but I can’t see away around this in this very specific situation. I’m OK with the mixing of concerns in community-land, but only if it’s absolutely necessary.I realise that this proposal is quite a radical departure from my original suggestion of a
stylelint-block-structureplugin, but having taken a step back from the problem these last few days I feel confident that this proposal is the way forward. If we’re happy to go down the route I proposed above, then I’ll create separate issues for theblock-closing-brace-empty-line-beforeanddeclaration-empty-line-beforerules, and we can keep this issue focused on the ordering of non-properties within a block.@hudochenkov Thanks for kickstarting the discussion about this! I’ll try to answer each of your questions.
Definitely a plugin. We had some recent discussions about the sustainability of development. These accumulated into the decision to remove some features in
7.0, including from the existingdeclaration-block-properties-orderrule, and push a number of proposed rules and options to plugins.Each rule/plugin follows these naming conventions.
blockis the thing that this rule is scoped to. I chosestructurebecause it’s unique in stylelint as no other plugin/rule deals with both whitespace and the order of things. Perhaps there’s a better word for it though?We can look to the existing plugin
stylelint-selector-bem-patternfor precedence here i.e. “just a couple of quick tests to ensurepostcss-bem-linteris getting the hard work done”, docs that say look at thepostcss-bem-linterdocs for options, and a primary option that is a object containing what optionspostcss-bem-linterexpects.Right, I think that’s probably enough to keep the ball rolling. Anyone else have anything to add?
Agreed 😃
@hudochenkov What do you think about the name
declaration-block-order? I now thinknon-propertiesis an odd thing to include in the name as other things might also be excluded if specific rules are written in the future e.g.declaration-block-custom-properties-orderorscss/declaration-block-dollar-variables-order.