1 | # About rules
|
2 |
|
3 | The built-in rules:
|
4 |
|
5 | - apply to standard CSS syntax only
|
6 | - are generally useful; not tied to idiosyncratic patterns
|
7 | - have a clear and unambiguous finished state
|
8 | - have a singular purpose
|
9 | - are standalone, and don't rely on another rule
|
10 | - do not contain functionality that overlaps with another rule
|
11 |
|
12 | 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.
|
13 |
|
14 | ## Options
|
15 |
|
16 | Each rule accepts a primary and an optional secondary option.
|
17 |
|
18 | ### Primary
|
19 |
|
20 | Every rule _must have_ a primary option. For example, in:
|
21 |
|
22 | - `"color-hex-case": "upper"`, the primary option is `"upper"`
|
23 | - `"indentation": [2, { "except": ["block"] }]`, the primary option is `2`
|
24 |
|
25 | ### Secondary
|
26 |
|
27 | Some rules require extra flexibility to address edge cases. These can use an optional secondary options object. For example, in:
|
28 |
|
29 | - `"color-hex-case": "upper"` there is no secondary options object
|
30 | - `"indentation": [2, { "except": ["block"] }]`, the secondary options object is `{ "except": ["block"] }`
|
31 |
|
32 | The most typical secondary options are `"ignore": []` and `"except": []`.
|
33 |
|
34 | #### Keyword `"ignore"` and `"except"`
|
35 |
|
36 | The `"ignore"` and `"except"` options accept an array of predefined keyword options, e.g. `["relative", "first-nested", "descendant"]`:
|
37 |
|
38 | - `"ignore"` skips-over a particular pattern
|
39 | - `"except"` inverts the primary option for a particular pattern
|
40 |
|
41 | #### User-defined `"ignore*"`
|
42 |
|
43 | Some rules accept a _user-defined_ list of things to ignore. This takes the form of `"ignore<Things>": []`, e.g. `"ignoreAtRules": []`.
|
44 |
|
45 | The `ignore*` options let users ignore non-standard syntax at the _configuration level_. For example, the:
|
46 |
|
47 | - `:global` and `:local` pseudo-classes introduced in CSS Modules
|
48 | - `@debug` and `@extend` at-rules introduced in SCSS
|
49 |
|
50 | Methodologies and language extensions come and go quickly, and this approach ensures our codebase does not become littered with code for obsolete things.
|
51 |
|
52 | ## Names
|
53 |
|
54 | Rule are consistently named, they are:
|
55 |
|
56 | - made up of lowercase words separated by hyphens
|
57 | - split into two parts
|
58 |
|
59 | The first part describes what [_thing_](http://apps.workflower.fi/vocabs/css/en) the rule applies to. The second part describes what the rule is checking.
|
60 |
|
61 | For example:
|
62 |
|
63 | ```
|
64 | "number-leading-zero"
|
65 | // ↑ ↑
|
66 | // the thing what the rule is checking
|
67 | ```
|
68 |
|
69 | There is no first part when the rule applies to the whole stylesheet.
|
70 |
|
71 | For example:
|
72 |
|
73 | ```
|
74 | "no-eol-whitespace"
|
75 | "indentation"
|
76 | // ↑
|
77 | // what the rules are checking
|
78 | ```
|
79 |
|
80 | _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_.
|
81 |
|
82 | ### No rules
|
83 |
|
84 | Most rules require _or_ disallow something.
|
85 |
|
86 | For example, whether numbers _must_ or _must not_ have a leading zero:
|
87 |
|
88 | - `number-leading-zero`: `string - "always"|"never"`
|
89 | - `"always"` - there _must always_ be a leading zero
|
90 | - `"never"` - there _must never_ be a leading zero
|
91 |
|
92 |
|
93 | ```css
|
94 | a { line-height: 0.5; }
|
95 | /** ↑
|
96 | * This leading zero */
|
97 | ```
|
98 |
|
99 | However, some rules _just disallow_ something. These rules include `*-no-*` in their name.
|
100 |
|
101 | For example, to disallow empty blocks:
|
102 |
|
103 | - `block-no-empty` - blocks _must not_ be empty
|
104 |
|
105 |
|
106 | ```css
|
107 | a { }
|
108 | /** ↑
|
109 | * Blocks like this */
|
110 | ```
|
111 |
|
112 | Notice how it does not make sense to have an option to enforce the opposite, i.e. that every block _must_ be empty.
|
113 |
|
114 | ### Max and min rules
|
115 |
|
116 | `*-max-*` and `*-min-*` rules _set a limit_ to something.
|
117 |
|
118 | For example, specifying the maximum number of digits after the "." in a number:
|
119 |
|
120 | - `number-max-precision`: `int`
|
121 |
|
122 |
|
123 | ```css
|
124 | a { font-size: 1.333em; }
|
125 | /** ↑
|
126 | * The maximum number of digits after this "." */
|
127 | ```
|
128 |
|
129 | ### Whitespace rules
|
130 |
|
131 | Whitespace rules allow you to enforce an empty line, a single space, a newline or no space in some specific part of the stylesheet.
|
132 |
|
133 | The whitespace rules combine two sets of keywords:
|
134 |
|
135 | - `before`, `after` and `inside` to specify where the whitespace (if any) is expected
|
136 | - `empty-line`, `space` and `newline` to specify whether a single empty line, a single space, a single newline or no space is expected there
|
137 |
|
138 | For example, specifying if a single empty line or no space must come before all the comments in a stylesheet:
|
139 |
|
140 | - `comment-empty-line-before`: `string` - `"always"|"never"`
|
141 |
|
142 |
|
143 | ```css
|
144 | a {}
|
145 | ←
|
146 | /* comment */ ↑
|
147 | ↑
|
148 | /** ↑
|
149 | * This empty line */
|
150 | ```
|
151 |
|
152 | Additionally, some whitespace rules use an additional set of keywords:
|
153 |
|
154 | - `comma`, `colon`, `semicolon`, `opening-brace`, `closing-brace`, `opening-parenthesis`, `closing-parenthesis`, `operator` or `range-operator` are used if a specific piece of punctuation in the _thing_ is being targeted
|
155 |
|
156 | For example, specifying if a single space or no space must follow a comma in a function:
|
157 |
|
158 | - `function-comma-space-after`: `string` - `"always"|"never"`
|
159 |
|
160 |
|
161 | ```css
|
162 | a { transform: translate(1, 1) }
|
163 | /** ↑
|
164 | * The space after this commas */
|
165 | ```
|
166 |
|
167 | 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:
|
168 |
|
169 | - `function-parentheses-space-inside`: `string` - `"always"|"never"`
|
170 |
|
171 |
|
172 | ```css
|
173 | a { transform: translate( 1, 1 ); }
|
174 | /** ↑ ↑
|
175 | * The space inside these two parentheses */
|
176 | ```
|
177 |
|
178 | ## READMEs
|
179 |
|
180 | Each rule is accompanied by a README in the following format:
|
181 |
|
182 | 1. Rule name.
|
183 | 2. Single-line description.
|
184 | 3. Prototypical code example.
|
185 | 4. Expanded description (if necessary).
|
186 | 5. Options.
|
187 | 6. Example patterns that are considered violations (for each option value).
|
188 | 7. Example patterns that are _not_ considered violations (for each option value).
|
189 | 8. Optional options (if applicable).
|
190 |
|
191 | The single-line description is in the form of:
|
192 |
|
193 | - "Disallow ..." for `no` rules
|
194 | - "Limit ..." for `max` rules
|
195 | - "Require ..." for rules that accept `"always"` and `"never"` options
|
196 | - "Specify ..." for everything else
|
197 |
|
198 | ## Violation messages
|
199 |
|
200 | Each rule produces violation messages in these forms:
|
201 |
|
202 | - "Expected \[something\] \[in some context\]"
|
203 | - "Unexpected \[something\] \[in some context\]"
|