About rules
The built-in rules:
- apply to standard CSS syntax only
- are generally useful; not tied to idiosyncratic patterns
- have a clear and unambiguous finished state
- have a singular purpose
- are standalone, and don't rely on another rule
- do not contain functionality that overlaps with another rule
In contrast, a plugin is a community rule that doesn't adhere to all these criteria. It might support a particular methodology or toolset, or apply to non-standard constructs and features, or be for specific use cases.
#
OptionsEach rule accepts a primary and an optional secondary option.
#
PrimaryEvery rule must have a primary option. For example, in:
"color-hex-case": "upper"
, the primary option is"upper"
"indentation": [2, { "except": ["block"] }]
, the primary option is2
#
SecondarySome rules require extra flexibility to address edge cases. These can use an optional secondary options object. For example, in:
"color-hex-case": "upper"
there is no secondary options object"indentation": [2, { "except": ["block"] }]
, the secondary options object is{ "except": ["block"] }
The most typical secondary options are "ignore": []
and "except": []
.
"ignore"
and "except"
#
Keyword The "ignore"
and "except"
options accept an array of predefined keyword options, e.g. ["relative", "first-nested", "descendant"]
:
"ignore"
skips-over a particular pattern"except"
inverts the primary option for a particular pattern
"ignore*"
#
User-defined Some rules accept a user-defined list of things to ignore. This takes the form of "ignore<Things>": []
, e.g. "ignoreAtRules": []
.
The ignore*
options let users ignore non-standard syntax at the configuration level. For example, the:
:global
and:local
pseudo-classes introduced in CSS Modules@debug
and@extend
at-rules introduced in SCSS
Methodologies and language extensions come and go quickly, and this approach ensures our codebase does not become littered with code for obsolete things.
#
NamesRule are consistently named, they are:
- made up of lowercase words separated by hyphens
- split into two parts
The first part describes what thing the rule applies to. The second part describes what the rule is checking.
For example:
"number-leading-zero"// โ โ// the thing what the rule is checking
There is no first part when the rule applies to the whole stylesheet.
For example:
"no-eol-whitespace""indentation"// โ// what the rules are checking
Rules are named to encourage explicit, rather than implicit, options. For example, color-hex-case: "upper"|"lower"
rather than color-hex-uppercase: "always"|"never"
. As color-hex-uppercase: "never"
implies always lowercase, whereas color-hex-case: "lower"
makes it explicit.
#
No rulesMost rules require or disallow something.
For example, whether numbers must or must not have a leading zero:
number-leading-zero
:string - "always"|"never"
"always"
- there must always be a leading zero"never"
- there must never be a leading zero
a { line-height: 0.5; }/** โ * This leading zero */
However, some rules just disallow something. These rules include *-no-*
in their name.
For example, to disallow empty blocks:
block-no-empty
- blocks must not be empty
a { }/** โ * Blocks like this */
Notice how it does not make sense to have an option to enforce the opposite, i.e. that every block must be empty.
#
Max and min rules*-max-*
and *-min-*
rules set a limit to something.
For example, specifying the maximum number of digits after the "." in a number:
number-max-precision
:int
a { font-size: 1.333em; }/** โ * The maximum number of digits after this "." */
#
Whitespace rulesWhitespace rules allow you to enforce an empty line, a single space, a newline or no space in some specific part of the stylesheet.
The whitespace rules combine two sets of keywords:
before
,after
andinside
to specify where the whitespace (if any) is expectedempty-line
,space
andnewline
to specify whether a single empty line, a single space, a single newline or no space is expected there
For example, specifying if a single empty line or no space must come before all the comments in a stylesheet:
comment-empty-line-before
:string
-"always"|"never"
a {} โ/* comment */ โ โ/** โ * This empty line */
Additionally, some whitespace rules use an additional set of keywords:
comma
,colon
,semicolon
,opening-brace
,closing-brace
,opening-parenthesis
,closing-parenthesis
,operator
orrange-operator
are used if a specific piece of punctuation in the thing is being targeted
For example, specifying if a single space or no space must follow a comma in a function:
function-comma-space-after
:string
-"always"|"never"
a { transform: translate(1, 1) }/** โ * The space after this commas */
The plural of the punctuation is used for inside
rules. For example, specifying if a single space or no space must be inside the parentheses of a function:
function-parentheses-space-inside
:string
-"always"|"never"
a { transform: translate( 1, 1 ); }/** โ โ * The space inside these two parentheses */
#
READMEsEach rule is accompanied by a README in the following format:
- Rule name.
- Single-line description.
- Prototypical code example.
- Expanded description (if necessary).
- Options.
- Example patterns that are considered problems (for each option value).
- Example patterns that are not considered problems (for each option value).
- Optional options (if applicable).
The single-line description is in the form of:
- "Disallow ..." for
no
rules - "Limit ..." for
max
rules - "Require ..." for rules that accept
"always"
and"never"
options - "Specify ..." for everything else
#
Problem messagesEach rule produces problem messages in these forms:
- "Expected [something] [in some context]"
- "Unexpected [something] [in some context]"