├── .npmrc ├── .gitattributes ├── .gitignore ├── example.css ├── .editorconfig ├── .github └── workflows │ └── main.yml ├── readme.md ├── test └── test.js ├── license ├── package.json ├── properties-order.js └── index.js /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | -------------------------------------------------------------------------------- /example.css: -------------------------------------------------------------------------------- 1 | div { 2 | padding-top: 1px; 3 | margin: 5px; 4 | color: #FFF; 5 | } 6 | 7 | /* 8 | 9 | Run: 10 | $ stylelint --config=index.js example.css 11 | 12 | */ 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | - push 4 | - pull_request 5 | jobs: 6 | test: 7 | name: Node.js ${{ matrix.node-version }} 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | node-version: 13 | - 20 14 | - 18 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: actions/setup-node@v4 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | - run: npm install 21 | - run: npm test 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # stylelint-config-xo 2 | 3 | > [Stylelint](https://stylelint.io) shareable config for [XO](https://github.com/xojs/xo) 4 | 5 | ## Install 6 | 7 | ```sh 8 | npm install --save-dev stylelint-config-xo 9 | ``` 10 | 11 | ## Usage 12 | 13 | Add the following to your [Stylelint config](https://stylelint.io/user-guide/configure): 14 | 15 | ```json 16 | { 17 | "extends": "stylelint-config-xo" 18 | } 19 | ``` 20 | 21 | ## Related 22 | 23 | - [stylelint-config-xo-space](https://github.com/xojs/stylelint-config-xo-space) - Stylelint shareable config for XO with 2-space indent 24 | - [stylelint-config-xo-scss](https://github.com/xojs/stylelint-config-xo-scss) - Stylelint shareable config for XO with Sass support 25 | - [xo](https://github.com/xojs/xo) - JavaScript linter 26 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import stylelint from 'stylelint'; 3 | import config from '../index.js'; 4 | 5 | const hasRule = (errors, ruleId) => errors.some(x => x.rule === ruleId); 6 | 7 | const runStylelint = async code => { 8 | const {results} = await stylelint.lint({ 9 | code, 10 | config, 11 | }); 12 | 13 | for (const result of results) { 14 | if (result.deprecations.length > 0) { 15 | throw new Error(`Deprecations:\n${result.deprecations.join('\n')}`); 16 | } 17 | 18 | if (result.invalidOptionWarnings.length > 0) { 19 | const warnings = result.invalidOptionWarnings.map(x => x.text).join('\n'); 20 | throw new Error(`Invalid options:\n${warnings}`); 21 | } 22 | } 23 | 24 | return results; 25 | }; 26 | 27 | test('main', async t => { 28 | const results = await runStylelint( 29 | `div { 30 | left: .2em; 31 | } 32 | `, 33 | ); 34 | 35 | t.true(hasRule(results[0].warnings, '@stylistic/number-leading-zero')); 36 | }); 37 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Sindre Sorhus (https://sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stylelint-config-xo", 3 | "version": "1.0.2", 4 | "description": "Stylelint shareable config for XO", 5 | "license": "MIT", 6 | "repository": "sindresorhus/stylelint-config-xo", 7 | "funding": "https://github.com/sponsors/sindresorhus", 8 | "author": { 9 | "name": "Sindre Sorhus", 10 | "email": "sindresorhus@gmail.com", 11 | "url": "https://sindresorhus.com" 12 | }, 13 | "type": "module", 14 | "exports": "./index.js", 15 | "sideEffects": false, 16 | "engines": { 17 | "node": ">=18" 18 | }, 19 | "scripts": { 20 | "test": "xo && ava" 21 | }, 22 | "files": [ 23 | "index.js", 24 | "properties-order.js" 25 | ], 26 | "keywords": [ 27 | "stylelint", 28 | "stylelint-config", 29 | "xo", 30 | "code", 31 | "quality", 32 | "style", 33 | "css", 34 | "lint", 35 | "linter", 36 | "jscs", 37 | "jshint", 38 | "jslint", 39 | "eslint", 40 | "validate", 41 | "code style", 42 | "standard", 43 | "strict", 44 | "check", 45 | "checker", 46 | "verify", 47 | "enforce", 48 | "hint", 49 | "simple" 50 | ], 51 | "dependencies": { 52 | "@stylistic/stylelint-plugin": "^2.1.2", 53 | "stylelint-declaration-block-no-ignored-properties": "^2.8.0", 54 | "stylelint-order": "^6.0.4" 55 | }, 56 | "devDependencies": { 57 | "ava": "^6.1.2", 58 | "stylelint": "^16.4.0", 59 | "xo": "^0.58.0" 60 | }, 61 | "peerDependencies": { 62 | "stylelint": ">=16" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /properties-order.js: -------------------------------------------------------------------------------- 1 | const config = [ 2 | { 3 | // Must be first 4 | properties: [ 5 | 'all', 6 | ], 7 | }, 8 | { 9 | // Content 10 | properties: [ 11 | 'content', 12 | 'quotes', 13 | ], 14 | }, 15 | { 16 | // Display and box model 17 | properties: [ 18 | 'display', 19 | 'box-sizing', 20 | 'overflow', 21 | 'width', 22 | 'height', 23 | 'min-width', 24 | 'min-height', 25 | 'max-width', 26 | 'max-height', 27 | 'padding', 28 | 'padding-top', 29 | 'padding-right', 30 | 'padding-bottom', 31 | 'padding-left', 32 | 'padding-block-start', 33 | 'padding-block-end', 34 | 'padding-inline-start', 35 | 'padding-inline-end', 36 | 'border', 37 | 'border-top', 38 | 'border-right', 39 | 'border-bottom', 40 | 'border-left', 41 | 'border-width', 42 | 'border-top-width', 43 | 'border-right-width', 44 | 'border-bottom-width', 45 | 'border-left-width', 46 | 'border-color', 47 | 'border-top-color', 48 | 'border-right-color', 49 | 'border-bottom-color', 50 | 'border-left-color', 51 | 'border-style', 52 | 'border-top-style', 53 | 'border-right-style', 54 | 'border-bottom-style', 55 | 'border-left-style', 56 | 'border-image', 57 | 'border-image-source', 58 | 'border-image-width', 59 | 'border-image-outset', 60 | 'border-image-repeat', 61 | 'border-image-slice', 62 | // TODO: Add the rest of the `border` properties 63 | 'border-radius', 64 | 'border-top-left-radius', 65 | 'border-top-right-radius', 66 | 'border-bottom-left-radius', 67 | 'border-bottom-right-radius', 68 | 'margin', 69 | 'margin-top', 70 | 'margin-right', 71 | 'margin-bottom', 72 | 'margin-left', 73 | 'margin-block-start', 74 | 'margin-block-end', 75 | 'margin-inline-start', 76 | 'margin-inline-end', 77 | ], 78 | }, 79 | { 80 | // Positioning 81 | properties: [ 82 | 'position', 83 | 'top', 84 | 'right', 85 | 'bottom', 86 | 'left', 87 | 'vertical-align', 88 | ], 89 | }, 90 | { 91 | // Float 92 | properties: [ 93 | 'float', 94 | 'clear', 95 | ], 96 | }, 97 | { 98 | // Flexbox 99 | properties: [ 100 | 'flex', 101 | 'flex-basis', 102 | 'flex-direction', 103 | 'flex-flow', 104 | 'flex-grow', 105 | 'flex-shrink', 106 | 'flex-wrap', 107 | ], 108 | }, 109 | { 110 | // Grid 111 | properties: [ 112 | 'grid', 113 | 'grid-area', 114 | 'grid-template', 115 | 'grid-template-areas', 116 | 'grid-template-rows', 117 | 'grid-template-columns', 118 | 'grid-row', 119 | 'grid-row-start', 120 | 'grid-row-end', 121 | 'grid-column', 122 | 'grid-column-start', 123 | 'grid-column-end', 124 | 'grid-auto-rows', 125 | 'grid-auto-columns', 126 | 'grid-auto-flow', 127 | 'grid-gap', 128 | 'grid-row-gap', 129 | 'grid-column-gap', 130 | ], 131 | }, 132 | { 133 | // Align 134 | properties: [ 135 | 'align-content', 136 | 'align-items', 137 | 'align-self', 138 | ], 139 | }, 140 | { 141 | // Justify 142 | properties: [ 143 | 'justify-content', 144 | 'justify-items', 145 | 'justify-self', 146 | ], 147 | }, 148 | { 149 | // Order 150 | properties: [ 151 | 'order', 152 | ], 153 | }, 154 | { 155 | // Columns 156 | properties: [ 157 | 'columns', 158 | 'column-gap', 159 | 'column-fill', 160 | 'column-rule', 161 | 'column-rule-width', 162 | 'column-rule-style', 163 | 'column-rule-color', 164 | 'column-span', 165 | 'column-count', 166 | 'column-width', 167 | ], 168 | }, 169 | { 170 | // Transform 171 | properties: [ 172 | 'transform', 173 | 'transform-origin', 174 | 'transform-box', 175 | 'transform-style', 176 | 'transform-function', 177 | 'backface-visibility', 178 | 'perspective', 179 | 'perspective-origin', 180 | ], 181 | }, 182 | { 183 | // Visibility 184 | properties: [ 185 | 'visibility', 186 | 'opacity', 187 | 'z-index', 188 | ], 189 | }, 190 | { 191 | // Style 192 | properties: [ 193 | 'color', 194 | 'background', 195 | 'background-color', 196 | 'background-image', 197 | 'background-repeat', 198 | 'background-position', 199 | 'background-size', 200 | 'background-attachment', 201 | 'background-clip', 202 | 'background-origin', 203 | 'background-blend-mode', 204 | 'outline', 205 | 'outline-width', 206 | 'outline-color', 207 | 'outline-style', 208 | 'outline-offset', 209 | 'box-shadow', 210 | ], 211 | }, 212 | { 213 | // Lists 214 | properties: [ 215 | 'list-style', 216 | 'list-style-type', 217 | 'list-style-position', 218 | 'list-style-image', 219 | 'caption-side', 220 | ], 221 | }, 222 | { 223 | // Tables 224 | properties: [ 225 | 'table-layout', 226 | 'border-collapse', 227 | 'border-spacing', 228 | 'empty-cells', 229 | ], 230 | }, 231 | { 232 | // Font 233 | properties: [ 234 | 'font', 235 | 'font-family', 236 | 'font-size', 237 | 'font-size-adjust', 238 | 'font-style', 239 | 'font-weight', 240 | 'font-smoothing', 241 | 'font-synthesis', 242 | 'font-kerning', 243 | 'font-stretch', 244 | 'font-variant', 245 | 'font-variant-caps', 246 | 'font-variant-numeric', 247 | 'font-variant-position', 248 | 'font-variant-ligatures', 249 | 'font-variant-alternates', 250 | 'font-variant-east-asian', 251 | 'font-language-override', 252 | 'font-feature-settings', 253 | ], 254 | }, 255 | { 256 | // Text alignment and decoration 257 | properties: [ 258 | 'direction', 259 | 'tab-size', 260 | 'text-align', 261 | 'text-align-last', 262 | 'text-justify', 263 | 'text-indent', 264 | 'text-transform', 265 | 'text-decoration', 266 | 'text-decoration-line', 267 | 'text-decoration-color', 268 | 'text-decoration-style', 269 | 'text-rendering', 270 | 'text-emphasis', 271 | 'text-emphasis-color', 272 | 'text-emphasis-style', 273 | 'text-emphasis-position', 274 | 'text-combine-upright', 275 | 'text-underline-position', 276 | 'text-orientation', 277 | 'text-shadow', 278 | 'text-overflow', 279 | ], 280 | }, 281 | { 282 | // Text spacing 283 | properties: [ 284 | 'line-height', 285 | 'word-spacing', 286 | 'letter-spacing', 287 | 'white-space', 288 | 'word-break', 289 | 'word-wrap', 290 | ], 291 | }, 292 | { 293 | // Interactivity 294 | properties: [ 295 | 'transition', 296 | 'transition-property', 297 | 'transition-duration', 298 | 'transition-timing-function', 299 | 'transition-delay', 300 | 'animation', 301 | 'animation-name', 302 | 'animation-duration', 303 | 'animation-timing-function', 304 | 'animation-direction', 305 | 'animation-delay', 306 | 'animation-iteration-count', 307 | 'animation-fill-mode', 308 | 'animation-play-state', 309 | 'pointer-events', 310 | 'cursor', 311 | ], 312 | }, 313 | { 314 | // Counters 315 | properties: [ 316 | 'counter-reset', 317 | 'counter-increment', 318 | ], 319 | }, 320 | ]; 321 | 322 | export default config; 323 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // - import propertiesOrder from './properties-order.js'; 2 | 3 | // Allows: 4 | // foo-bar 5 | // FooBar 6 | // foo-bar--foo-bar 7 | // foo-bar__foo-bar 8 | // FooBar--FooBar 9 | // FooBar__FooBar 10 | // FooBar--foo-bar 11 | // foo-bar--FooBar 12 | // Foo-bar 13 | // … 14 | const reLowerCaseFirstUpper = /([A-Z][a-z\d]*(-[a-z\d]+)*)/; 15 | const reLowerCase = /([a-z][a-z\d]*(-[a-z\d]+)*)/; 16 | const rePascalCase = /(([A-Z][a-zA-Z\d]+)*)/; 17 | const reName = new RegExp(`^(${reLowerCaseFirstUpper.source}|${reLowerCase.source}|${rePascalCase.source})((--|__)(${reLowerCase.source}|${rePascalCase.source}))*$`); 18 | 19 | const config = { 20 | plugins: [ 21 | 'stylelint-order', 22 | 'stylelint-declaration-block-no-ignored-properties', 23 | '@stylistic/stylelint-plugin', 24 | ], 25 | rules: { 26 | 'color-no-invalid-hex': true, 27 | 'font-family-no-duplicate-names': true, 28 | 'font-family-no-missing-generic-family-keyword': true, 29 | 'function-calc-no-unspaced-operator': true, 30 | 'function-linear-gradient-no-nonstandard-direction': true, 31 | 'function-no-unknown': true, 32 | 'string-no-newline': true, 33 | 'unit-no-unknown': true, 34 | 'shorthand-property-no-redundant-values': true, 35 | 'property-no-unknown': true, 36 | 'keyframe-declaration-no-important': true, 37 | 'declaration-block-no-duplicate-properties': true, 38 | 'declaration-block-no-redundant-longhand-properties': [ 39 | true, 40 | { 41 | ignoreShorthands: [ 42 | 'grid-template', 43 | ], 44 | }, 45 | ], 46 | 'declaration-block-no-shorthand-property-overrides': true, 47 | 'block-no-empty': [ 48 | true, 49 | { 50 | ignore: [ 51 | 'comments', 52 | ], 53 | }, 54 | ], 55 | 'selector-pseudo-class-no-unknown': true, 56 | 'selector-pseudo-element-no-unknown': true, 57 | 'selector-type-no-unknown': true, 58 | 'media-feature-name-no-unknown': true, 59 | 'at-rule-no-unknown': true, 60 | 'declaration-property-value-no-unknown': true, 61 | 'comment-no-empty': true, 62 | 'no-descending-specificity': [ 63 | true, 64 | { 65 | ignore: [ 66 | 'selectors-within-list', 67 | ], 68 | }, 69 | ], 70 | 'no-duplicate-at-import-rules': true, 71 | 'no-duplicate-selectors': true, 72 | 'no-empty-source': true, 73 | '@stylistic/no-extra-semicolons': true, 74 | 'no-invalid-double-slash-comments': true, 75 | 'alpha-value-notation': 'percentage', 76 | 'hue-degree-notation': 'angle', 77 | 'color-function-notation': 'modern', 78 | 'color-named': 'never', 79 | 'function-url-no-scheme-relative': true, 80 | 'keyframes-name-pattern': reLowerCase, 81 | 'number-max-precision': 3, 82 | 'time-min-milliseconds': 100, 83 | 'value-no-vendor-prefix': [ 84 | true, 85 | { 86 | ignoreValues: [ 87 | 'grab', 88 | 'grabbing', 89 | ], 90 | }, 91 | ], 92 | 'property-no-vendor-prefix': [ 93 | true, 94 | { 95 | ignoreProperties: [ 96 | 'app-region', // For Electron 97 | 'appearance', 98 | 'mask', 99 | 'tab-size', // It's still only prefixed in Firefox 100 | ], 101 | }, 102 | ], 103 | 'declaration-no-important': true, 104 | 'declaration-property-value-disallowed-list': { 105 | '/^border(?!-(width|spacing|radius|(top|bottom)-(left|right)-radius))/': [ 106 | /thin/, 107 | /medium/, 108 | /thick/, 109 | '0', // Prefer `none` 110 | ], 111 | '/^transition/': [ 112 | /all/, 113 | ], 114 | }, 115 | 'selector-class-pattern': reName, 116 | 'selector-id-pattern': reName, 117 | 'selector-max-attribute': 8, 118 | 'selector-max-class': 8, 119 | 'selector-max-compound-selectors': 8, 120 | '@stylistic/selector-max-empty-lines': 0, 121 | 'selector-max-universal': 1, 122 | 'selector-no-vendor-prefix': [ 123 | true, 124 | { 125 | ignoreSelectors: [ 126 | '::-webkit-input-placeholder', 127 | ], 128 | }, 129 | ], 130 | 'media-feature-name-no-vendor-prefix': true, 131 | 'at-rule-no-vendor-prefix': true, 132 | 'at-rule-property-required-list': { 133 | 'font-face': [ 134 | 'font-display', 135 | 'font-family', 136 | 'font-style', 137 | ], 138 | }, 139 | 'comment-word-disallowed-list': [ 140 | [ 141 | /^TODO:/, 142 | /^FIXME:/, 143 | 'fuck', 144 | 'shit', 145 | 'damn', 146 | 'twerk', 147 | 'egg yolk', 148 | ], 149 | { 150 | severity: 'warning', 151 | }, 152 | ], 153 | 'max-nesting-depth': [ 154 | 8, 155 | { 156 | ignore: [ 157 | 'pseudo-classes', 158 | ], 159 | }, 160 | ], 161 | '@stylistic/color-hex-case': 'lower', 162 | 'color-hex-length': 'short', 163 | 'font-family-name-quotes': 'always-where-recommended', 164 | 'font-weight-notation': 'named-where-possible', 165 | '@stylistic/function-comma-newline-after': 'always-multi-line', 166 | '@stylistic/function-comma-newline-before': 'never-multi-line', 167 | '@stylistic/function-comma-space-after': 'always-single-line', 168 | '@stylistic/function-max-empty-lines': 0, 169 | 'function-name-case': 'lower', 170 | '@stylistic/function-parentheses-newline-inside': 'always-multi-line', 171 | '@stylistic/function-parentheses-space-inside': 'never-single-line', 172 | 'function-url-quotes': 'always', 173 | '@stylistic/function-whitespace-after': 'always', 174 | '@stylistic/number-leading-zero': 'always', 175 | '@stylistic/number-no-trailing-zeros': true, 176 | '@stylistic/string-quotes': [ 177 | 'single', 178 | { 179 | avoidEscape: false, 180 | }, 181 | ], 182 | 'length-zero-no-unit': true, 183 | '@stylistic/unit-case': 'lower', 184 | 'value-keyword-case': 'lower', 185 | '@stylistic/value-list-comma-newline-after': 'always-multi-line', 186 | '@stylistic/value-list-comma-newline-before': 'never-multi-line', 187 | '@stylistic/value-list-comma-space-after': 'always-single-line', 188 | '@stylistic/value-list-comma-space-before': 'never', 189 | '@stylistic/value-list-max-empty-lines': 0, 190 | '@stylistic/property-case': 'lower', 191 | '@stylistic/declaration-bang-space-after': 'never', 192 | '@stylistic/declaration-bang-space-before': 'always', 193 | '@stylistic/declaration-colon-newline-after': 'always-multi-line', 194 | '@stylistic/declaration-colon-space-after': 'always-single-line', 195 | '@stylistic/declaration-colon-space-before': 'never', 196 | 'declaration-empty-line-before': 'never', 197 | '@stylistic/declaration-block-semicolon-newline-after': 'always', 198 | '@stylistic/declaration-block-semicolon-newline-before': 'never-multi-line', 199 | '@stylistic/declaration-block-semicolon-space-after': 'always-single-line', 200 | '@stylistic/declaration-block-semicolon-space-before': 'never', 201 | '@stylistic/declaration-block-trailing-semicolon': 'always', 202 | '@stylistic/block-closing-brace-empty-line-before': 'never', 203 | '@stylistic/block-closing-brace-newline-after': 'always', 204 | '@stylistic/block-closing-brace-newline-before': 'always', 205 | '@stylistic/block-opening-brace-newline-after': 'always', 206 | '@stylistic/block-opening-brace-space-before': 'always', 207 | '@stylistic/selector-attribute-brackets-space-inside': 'never', 208 | '@stylistic/selector-attribute-operator-space-after': 'never', 209 | '@stylistic/selector-attribute-operator-space-before': 'never', 210 | 'selector-attribute-quotes': 'always', 211 | '@stylistic/selector-combinator-space-after': 'always', 212 | '@stylistic/selector-combinator-space-before': 'always', 213 | '@stylistic/selector-descendant-combinator-no-non-space': true, 214 | '@stylistic/selector-pseudo-class-case': 'lower', 215 | '@stylistic/selector-pseudo-class-parentheses-space-inside': 'never', 216 | '@stylistic/selector-pseudo-element-case': 'lower', 217 | 'selector-pseudo-element-colon-notation': 'double', 218 | 'selector-type-case': 'lower', 219 | '@stylistic/selector-list-comma-newline-after': 'always', 220 | '@stylistic/selector-list-comma-newline-before': 'never-multi-line', 221 | '@stylistic/selector-list-comma-space-after': 'always-single-line', 222 | '@stylistic/selector-list-comma-space-before': 'never', 223 | 'rule-empty-line-before': [ 224 | 'always', 225 | { 226 | except: [ 227 | 'after-single-line-comment', 228 | 'first-nested', 229 | ], 230 | ignore: [ 231 | 'after-comment', 232 | ], 233 | }, 234 | ], 235 | '@stylistic/media-feature-colon-space-after': 'always', 236 | '@stylistic/media-feature-colon-space-before': 'never', 237 | '@stylistic/media-feature-name-case': 'lower', 238 | '@stylistic/media-feature-parentheses-space-inside': 'never', 239 | '@stylistic/media-feature-range-operator-space-after': 'always', 240 | '@stylistic/media-feature-range-operator-space-before': 'always', 241 | '@stylistic/media-query-list-comma-newline-after': 'always', 242 | '@stylistic/media-query-list-comma-newline-before': 'never-multi-line', 243 | '@stylistic/media-query-list-comma-space-before': 'never', 244 | 'at-rule-empty-line-before': [ 245 | 'always', 246 | { 247 | except: [ 248 | 'inside-block', 249 | 'blockless-after-blockless', 250 | ], 251 | ignore: [ 252 | 'after-comment', 253 | ], 254 | }, 255 | ], 256 | '@stylistic/at-rule-name-case': 'lower', 257 | '@stylistic/at-rule-name-newline-after': 'always-multi-line', 258 | '@stylistic/at-rule-name-space-after': 'always-single-line', 259 | '@stylistic/at-rule-semicolon-newline-after': 'always', 260 | '@stylistic/at-rule-semicolon-space-before': 'never', 261 | 'comment-whitespace-inside': 'always', 262 | '@stylistic/indentation': [ 263 | 'tab', 264 | { 265 | baseIndentLevel: 1, 266 | }, 267 | ], 268 | '@stylistic/linebreaks': 'unix', 269 | '@stylistic/max-empty-lines': 2, 270 | '@stylistic/no-eol-whitespace': true, 271 | '@stylistic/no-missing-end-of-source-newline': true, 272 | '@stylistic/no-empty-first-line': true, 273 | '@stylistic/unicode-bom': 'never', 274 | 275 | // `stylelint-order` 276 | 'order/order': [ 277 | 'dollar-variables', 278 | 'custom-properties', 279 | 'declarations', 280 | 'rules', 281 | ], 282 | // Disabled for now: https://github.com/sindresorhus/stylelint-config-xo/pull/2#issuecomment-363438756 283 | // 'order/properties-order': propertiesOrder, 284 | 285 | // `stylelint-declaration-block-no-ignored-properties` 286 | 'plugin/declaration-block-no-ignored-properties': true, 287 | }, 288 | }; 289 | 290 | export default config; 291 | --------------------------------------------------------------------------------