Please help us create, enhance, and debug our rules!
You should:
When writing the rule, you should:
ignore
options to make the rule more permissiveYou should make use of the:
Use the PostCSS API to navigate and analyze the CSS syntax tree. We recommend using the walk
iterators (e.g. walkDecls
), rather than using forEach
to loop through the nodes.
When using array methods on nodes, e.g. find
, some
, filter
etc, you should explicitly check the type
property of the node before attempting to access other properties. For example:
const hasProperty = nodes.find(
({ type, prop }) => type === "decl" && prop === propertyName
);
Use node.raws
instead of node.raw()
when accessing raw strings from the PostCSS AST.
Depending on the rule, we also recommend using:
There are significant benefits to using these parsers instead of regular expressions or indexOf
searches (even if they aren’t always the most performant method).
stylelint has utility functions that are used in existing rules and might prove useful to you, as well. Please look through those so that you know what’s available. (And if you have a new function that you think might prove generally helpful, let’s add it to the list!).
Use the:
validateOptions()
utility to warn users about invalid optionsisStandardSyntax*
utilities to ignore non-standard syntaxOnly add an option to a rule if it addresses a requested use case to avoid polluting the tool with unused features.
If your rule can accept an array as its primary option, you must designate this by setting the property primaryOptionArray = true
on your rule function. For example:
function rule(primary, secondary) {
return (root, result) => {
/* .. */
};
}
rule.primaryOptionArray = true;
module.exports = rule;
There is one caveat here: If your rule accepts a primary option array, it cannot also accept a primary option object. Whenever possible, if you want your rule to accept a primary option array, you should make an array the only possibility, instead of allowing for various data structures.
Depending on the rule, it might be possible to automatically fix the rule’s violations by mutating the PostCSS AST (Abstract Syntax Tree) using the PostCSS API.
Add context
variable to rule parameters:
function rule(primary, secondary, context) {
return (root, result) => {
/* .. */
};
}
context
is an object which could have two properties:
fix
(boolean): If true
, your rule can apply autofixes.newline
(string): Line-ending used in current linted file.If context.fix
is true
, then change root
using PostCSS API and return early before report()
is called.
if (context.fix) {
// Apply fixes using PostCSS API
return; // Return and don't report a problem
}
report(/* .. */);
Each rule must have tests that cover all patterns that:
Write as many as you can stand to.
You should:
You should ask yourself how does your rule handle:
$sass
, @less
or var(--custom-property)
)?content: "anything goes";
)?/* anything goes */
)?url()
functions, including data URIs (e.g. url(anything/goes.jpg)
)?@-webkit-keyframes name {}
)?@KEYFRAMES name {}
)?a:hover::before
)?& a {}
, or check it as is?)?rgb(0,0,0)
with rgb(0, 0, 0)
)?You should:
<!-- prettier-ignore -->
before css
code fencesFor example:
@media screen and (min-width: 768px) {}
/** ↑ ↑
* These names and values */
When writing examples, you should use:
...
){}
{}
, rather than { }
for empty rulesa
type selector by default@media
at-rules by defaultcolor
property by default.foo
, #bar
, --baz
Look at the READMEs of other rules to glean more conventional patterns.
The final step is to add references to the new rule in the following places:
You should:
You should:
Deprecating rules doesn’t happen very often. When you do, you must:
stylelintReference
link to the specific version of the rule README on the GitHub website, so that it is always accessible.You can run a benchmarks on any given rule with any valid config using:
npm run benchmark-rule -- ruleName ruleOptions [ruleContext]
If the ruleOptions
argument is anything other than a string or a boolean, it must be valid JSON wrapped in quotation marks.
npm run benchmark-rule -- selector-combinator-space-after never
npm run benchmark-rule -- selector-combinator-space-after always
npm run benchmark-rule -- block-opening-brace-space-before "[\"always\", {\"ignoreAtRules\": [\"else\"]}]"
If the ruleContext
argument is specified, the sames procedure would apply:
npm run benchmark-rule -- block-opening-brace-space-before "[\"always\", {\"ignoreAtRules\": [\"else\"]}]" "{\"fix\": \"true\"}"
The script loads Bootstrap’s CSS (from its CDN) and runs it through the configured rule.
It will end up printing some simple stats like this:
Warnings: 1441
Mean: 74.17598357142856 ms
Deviation: 16.63969674310928 ms
When writing new rules or refactoring existing rules, use these measurements to determine the efficiency of your code.
A stylelint rule can repeat its core logic many, many times (e.g. checking every value node of every declaration in a vast CSS codebase). So it’s worth paying attention to performance and doing what we can to improve it!
Improving the performance of a rule is a great way to contribute if you want a quick little project. Try picking a rule and seeing if there’s anything you can do to speed it up.
Make sure you include benchmark measurements in your pull request!